13afb2937SSascha Wildner.\" 23afb2937SSascha Wildner.\" Copyright (c) 2010 The DragonFly Project. All rights reserved. 33afb2937SSascha Wildner.\" 43afb2937SSascha Wildner.\" This code is derived from software contributed to The DragonFly Project 53afb2937SSascha Wildner.\" by Venkatesh Srinivas <me@endeavour.zapto.org>. 63afb2937SSascha Wildner.\" 73afb2937SSascha Wildner.\" Redistribution and use in source and binary forms, with or without 83afb2937SSascha Wildner.\" modification, are permitted provided that the following conditions 93afb2937SSascha Wildner.\" are met: 103afb2937SSascha Wildner.\" 113afb2937SSascha Wildner.\" 1. Redistributions of source code must retain the above copyright 123afb2937SSascha Wildner.\" notice, this list of conditions and the following disclaimer. 133afb2937SSascha Wildner.\" 2. Redistributions in binary form must reproduce the above copyright 143afb2937SSascha Wildner.\" notice, this list of conditions and the following disclaimer in 153afb2937SSascha Wildner.\" the documentation and/or other materials provided with the 163afb2937SSascha Wildner.\" distribution. 173afb2937SSascha Wildner.\" 3. Neither the name of The DragonFly Project nor the names of its 183afb2937SSascha Wildner.\" contributors may be used to endorse or promote products derived 193afb2937SSascha Wildner.\" from this software without specific, prior written permission. 203afb2937SSascha Wildner.\" 213afb2937SSascha Wildner.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 223afb2937SSascha Wildner.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 233afb2937SSascha Wildner.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 243afb2937SSascha Wildner.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 253afb2937SSascha Wildner.\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 263afb2937SSascha Wildner.\" INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 273afb2937SSascha Wildner.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 283afb2937SSascha Wildner.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 293afb2937SSascha Wildner.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 303afb2937SSascha Wildner.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 313afb2937SSascha Wildner.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 323afb2937SSascha Wildner.\" SUCH DAMAGE. 333afb2937SSascha Wildner.\" 34abdf9ff7SSascha Wildner.Dd January 30, 2012 353afb2937SSascha Wildner.Dt TOKEN 9 36fb5b3747SSascha Wildner.Os 373afb2937SSascha Wildner.Sh NAME 383afb2937SSascha Wildner.Nm lwkt_token_init , 393afb2937SSascha Wildner.Nm lwkt_token_uninit , 403afb2937SSascha Wildner.Nm lwkt_gettoken , 413afb2937SSascha Wildner.Nm lwkt_trytoken , 423afb2937SSascha Wildner.Nm lwkt_reltoken , 433afb2937SSascha Wildner.Nm lwkt_token_pool_lookup , 44ccfda945SVenkatesh Srinivas.Nm lwkt_getpooltoken , 459254ffb1SSascha Wildner.\".Nm lwkt_relpooltoken , 468e9c3bf6SSascha Wildner.Nm lwkt_token_swap 473afb2937SSascha Wildner.Nd soft token locks 483afb2937SSascha Wildner.Sh SYNOPSIS 493afb2937SSascha Wildner.In sys/thread.h 503afb2937SSascha Wildner.Ft void 51*573f7837SSascha Wildner.Fn lwkt_token_init "struct lwkt_token *tok" "const char *desc" 523afb2937SSascha Wildner.Ft void 533afb2937SSascha Wildner.Fn lwkt_token_uninit "struct lwkt_token *tok" 543afb2937SSascha Wildner.Ft void 55a4212b42SNicolas Thery.Fn lwkt_gettoken "struct lwkt_token *tok" 563afb2937SSascha Wildner.Ft int 57a4212b42SNicolas Thery.Fn lwkt_trytoken "struct lwkt_token *tok" 583afb2937SSascha Wildner.Ft void 59a4212b42SNicolas Thery.Fn lwkt_reltoken "struct lwkt_token *tok" 603afb2937SSascha Wildner.Ft struct lwkt_token * 613afb2937SSascha Wildner.Fn lwkt_token_pool_lookup "void *ptr" 62a4212b42SNicolas Thery.Ft struct lwkt_token * 63a4212b42SNicolas Thery.Fn lwkt_getpooltoken "void *ptr" 64ccfda945SVenkatesh Srinivas.Ft void 6580921833SVenkatesh Srinivas.Fn lwkt_gettoken_shared "struct lwkt_token *tok" 6680921833SVenkatesh Srinivas.Ft void 678e9c3bf6SSascha Wildner.Fn lwkt_token_swap "void" 683afb2937SSascha Wildner.Sh DESCRIPTION 693afb2937SSascha WildnerA soft token is a lock which is only held while a thread is running. 703afb2937SSascha WildnerIf a thread explicitly blocks, all its tokens are released, and reacquired 713afb2937SSascha Wildnerwhen the thread resumes. 723afb2937SSascha WildnerWhile a thread blocks, the conditions protected by a soft token 733afb2937SSascha Wildnermay change and may need to be reevaluated on wakeup. 743afb2937SSascha Wildner.Pp 753afb2937SSascha WildnerTokens may be taken recursively. 763afb2937SSascha WildnerHowever, tokens must be released in the reverse order they were acquired. 773afb2937SSascha Wildner.Pp 7880921833SVenkatesh SrinivasTokens may be acquired in shared mode, allowing multiple concurrent holders, 7980921833SVenkatesh Srinivasvia 8080921833SVenkatesh Srinivas.Fn lwkt_gettoken_shared , 8180921833SVenkatesh Srinivasor in exclusive mode, allowing only one holder, via 8280921833SVenkatesh Srinivas.Fn lwkt_gettoken . 8380921833SVenkatesh SrinivasIt is safe to acquire a token shared while holding it exclusively. 8480921833SVenkatesh SrinivasA thread attempting to acquire a token exclusively after holding it shared 8580921833SVenkatesh Srinivaswill deadlock. 8680921833SVenkatesh Srinivas.Pp 873afb2937SSascha WildnerThe pool token interface exists to allow using tokens with data structures 883afb2937SSascha Wildnerwhich may be deallocated. 893afb2937SSascha WildnerIt allows getting a token reference from an address, which 903afb2937SSascha Wildneris implemented by a set of statically allocated tokens and a hash function. 913afb2937SSascha Wildner.Pp 92abdf9ff7SSascha WildnerIt is not recommended to take pool tokens in shared mode. 93abdf9ff7SSascha WildnerA hash collision 9480921833SVenkatesh Srinivasfrom a subsequent exclusive pool token request will hit the 9580921833SVenkatesh Srinivasexclusive-after-shared deadlock. 9680921833SVenkatesh Srinivas.Pp 973afb2937SSascha WildnerThe 983afb2937SSascha Wildner.Fn lwkt_token_init 998e9c3bf6SSascha Wildnerfunction is called to initialize a token. 1008e9c3bf6SSascha WildnerThe 101fffd28f3SVenkatesh Srinivas.Fa desc 102fffd28f3SVenkatesh Srinivasargument specifies the wait string displayed when waiting for the token. 1033afb2937SSascha WildnerThe 1043afb2937SSascha Wildner.Fn lwkt_token_uninit 1053afb2937SSascha Wildnerfunction is called to de-initialize one. 1063afb2937SSascha WildnerBefore using a token, it must be initialized. 1073afb2937SSascha Wildner.Pp 1083afb2937SSascha WildnerThe 1093afb2937SSascha Wildner.Fn lwkt_gettoken 110a4212b42SNicolas Theryfunction attempts to acquire a token. 1113afb2937SSascha WildnerIf it is unsuccessful, the calling thread blocks. 1123afb2937SSascha WildnerThe 1133afb2937SSascha Wildner.Fn lwkt_trytoken 114a4212b42SNicolas Therydoes the same thing; however, if it cannot acquire the token, it returns 0 115a4212b42SNicolas Theryinstead of blocking. 1163afb2937SSascha WildnerThe 1173afb2937SSascha Wildner.Fn lwkt_reltoken 118a4212b42SNicolas Theryfunction releases a previously acquired soft token. 1193afb2937SSascha Wildner.Pp 1203afb2937SSascha WildnerThe 1213afb2937SSascha Wildner.Fn lwkt_token_pool_lookup 1223afb2937SSascha Wildnerfunction takes an address and maps it to one of a number of statically 1233afb2937SSascha Wildnerallocated tokens. 1243afb2937SSascha WildnerThe 1253afb2937SSascha Wildner.Fn lwkt_getpooltoken 1263afb2937SSascha Wildnerfunction acquires a token associated with an address. 1273afb2937SSascha WildnerUse these two functions when tokens must protect a data structure, 1283afb2937SSascha Wildnerbut the structure can be deallocated. 1293afb2937SSascha WildnerPool tokens do not need to be initialized. 130ccfda945SVenkatesh Srinivas.Pp 131ccfda945SVenkatesh SrinivasThe 132ccfda945SVenkatesh Srinivas.Fn lwkt_token_swap 133ccfda945SVenkatesh Srinivasfunction swaps the two most recently acquired tokens; this allows release of 1348e9c3bf6SSascha Wildnertokens out-of-order. 1358e9c3bf6SSascha WildnerThis function should not be called when less than two tokens are held. 13618d6b65aSSascha Wildner.Sh FILES 13718d6b65aSSascha WildnerThe LWKT Token implementation is in 13818d6b65aSSascha Wildner.Pa /sys/kern/lwkt_token.c . 1393afb2937SSascha Wildner.Sh EXAMPLES 1403afb2937SSascha WildnerA simple example of using a token to protect access to a data structure: 1413afb2937SSascha Wildner.Bd -literal 1423afb2937SSascha Wildner/* Data structure to be protected */ 1433afb2937SSascha Wildnerstruct protected_data { 1443afb2937SSascha Wildner struct lwkt_token tok; 1453afb2937SSascha Wildner int data; 1463afb2937SSascha Wildner}; 1473afb2937SSascha Wildner 1483afb2937SSascha Wildnerstruct protected_data pdata; 1493afb2937SSascha Wildner 1503afb2937SSascha Wildner/* Called early in boot */ 1513afb2937SSascha Wildnervoid 1523afb2937SSascha Wildnerinit(void) 1533afb2937SSascha Wildner{ 154fffd28f3SVenkatesh Srinivas lwkt_token_init(&pdata.tok, "example"); 1553afb2937SSascha Wildner pdata.data = 0; 1563afb2937SSascha Wildner} 1573afb2937SSascha Wildner 1583afb2937SSascha Wildner/* 1593afb2937SSascha Wildner * A silly kthread; it uses a token to protect pdata.data. 1603afb2937SSascha Wildner */ 1613afb2937SSascha Wildnervoid 1623afb2937SSascha Wildnerkthread1(void) 1633afb2937SSascha Wildner{ 1643afb2937SSascha Wildner int local; 1653afb2937SSascha Wildner 1663afb2937SSascha Wildner /* 167a4212b42SNicolas Thery * Get the soft token. 1683afb2937SSascha Wildner */ 169a4212b42SNicolas Thery lwkt_gettoken(&pdata.tok); 1703afb2937SSascha Wildner for (;;) { 1713afb2937SSascha Wildner local = pdata.data++; 1723afb2937SSascha Wildner tsleep(pdata, 0, "sleep", 0); 1733afb2937SSascha Wildner /* 1743afb2937SSascha Wildner * While we are asleep, we do not hold the token. When we 1753afb2937SSascha Wildner * awake here, we will hold the token again, but we may not 1763afb2937SSascha Wildner * depend on local reflecting pdata.data. 1773afb2937SSascha Wildner */ 1783afb2937SSascha Wildner 1793afb2937SSascha Wildner local = pdata.data; 1803afb2937SSascha Wildner if (local == 4) 1813afb2937SSascha Wildner break; 1823afb2937SSascha Wildner } 1833afb2937SSascha Wildner /* 184a4212b42SNicolas Thery * Release the token. 1853afb2937SSascha Wildner */ 186a4212b42SNicolas Thery lwkt_reltoken(&pdata.tok); 1873afb2937SSascha Wildner} 1883afb2937SSascha Wildner.Ed 1893afb2937SSascha Wildner.Pp 1903afb2937SSascha WildnerAn example using pool tokens: 1913afb2937SSascha Wildner.Bd -literal 1923afb2937SSascha Wildnerstruct dynamic_data { 1933afb2937SSascha Wildner int ref; 1943afb2937SSascha Wildner}; 1953afb2937SSascha Wildner 1963afb2937SSascha Wildner/* 1973afb2937SSascha Wildner * Use a token to protect a reference count in a dynamic structure. 1983afb2937SSascha Wildner * Embedding a token in the structure would be inappropriate, since 1993afb2937SSascha Wildner * another thread may attempt to take the token after we have freed 2003afb2937SSascha Wildner * the object but before we have removed all external references to it. 2013afb2937SSascha Wildner */ 2023afb2937SSascha Wildnervoid 2033afb2937SSascha Wildnerkfunction(struct dynamic_data *dynptr) 2043afb2937SSascha Wildner{ 205a4212b42SNicolas Thery struct lwkt_token *tok; 2063afb2937SSascha Wildner 2073afb2937SSascha Wildner /* 2083afb2937SSascha Wildner * Get a token from the associated with the address of dynptr 2093afb2937SSascha Wildner */ 210a4212b42SNicolas Thery tok = lwkt_getpooltoken(dynptr); 2113afb2937SSascha Wildner dynptr->ref--; 2123afb2937SSascha Wildner if (dynptr->ref == 0) 2133afb2937SSascha Wildner free(dynptr); 2143afb2937SSascha Wildner 2153afb2937SSascha Wildner /* 2163afb2937SSascha Wildner * Release the token via its reference, as above 2173afb2937SSascha Wildner */ 218a4212b42SNicolas Thery lwkt_reltoken(tok); 2193afb2937SSascha Wildner} 2203afb2937SSascha Wildner.Ed 2213afb2937SSascha Wildner.Sh NOTES 2223afb2937SSascha WildnerSoft tokens are not released when a thread is preempted; they are only released 2233afb2937SSascha Wildnerwhen a thread explicitly blocks, such as via 2243afb2937SSascha Wildner.Fn tsleep 2253afb2937SSascha Wildneror 2263afb2937SSascha Wildner.Fn lwkt_switch . 2273afb2937SSascha Wildner.Pp 2283afb2937SSascha WildnerIf 2293afb2937SSascha Wildner.Fn lwkt_gettoken 2303afb2937SSascha Wildnerblocks while attempting to acquire a token, all currently-held tokens will 2313afb2937SSascha Wildnerbe released till a thread can acquire all of them again. 2323afb2937SSascha Wildner.Pp 2333afb2937SSascha WildnerWhen tokens are held and 2343afb2937SSascha Wildner.Fn tsleep_interlock 2353afb2937SSascha Wildneris used, tokens are not released until blocking happens - that is until the 2363afb2937SSascha Wildner.Fn tsleep 2373afb2937SSascha Wildnerpaired with the 2383afb2937SSascha Wildner.Fn tsleep_interlock 2393afb2937SSascha Wildneris called. 2403afb2937SSascha Wildner.Sh SEE ALSO 2413afb2937SSascha Wildner.Xr crit_enter 9 , 2423afb2937SSascha Wildner.Xr lockmgr 9 , 2433afb2937SSascha Wildner.Xr serializer 9 , 2443afb2937SSascha Wildner.Xr sleep 9 , 2453afb2937SSascha Wildner.Xr spinlock 9 2463afb2937SSascha Wildner.Sh HISTORY 2473afb2937SSascha WildnerLWKT tokens first appeared in 2483afb2937SSascha Wildner.Dx 1.0 . 24980921833SVenkatesh SrinivasShared tokens first appeared in 25080921833SVenkatesh Srinivas.Dx 2.11 . 2513afb2937SSascha Wildner.Sh AUTHORS 2523afb2937SSascha WildnerThe 2533afb2937SSascha Wildner.Nm token 2543afb2937SSascha Wildnerimplementation was written by 2553afb2937SSascha Wildner.An Matthew Dillon . 256