1.\" 2.\" Copyright (c) 2010 The DragonFly Project. All rights reserved. 3.\" 4.\" This code is derived from software contributed to The DragonFly Project 5.\" by Venkatesh Srinivas <me@endeavour.zapto.org>. 6.\" 7.\" Redistribution and use in source and binary forms, with or without 8.\" modification, are permitted provided that the following conditions 9.\" are met: 10.\" 11.\" 1. Redistributions of source code must retain the above copyright 12.\" notice, this list of conditions and the following disclaimer. 13.\" 2. Redistributions in binary form must reproduce the above copyright 14.\" notice, this list of conditions and the following disclaimer in 15.\" the documentation and/or other materials provided with the 16.\" distribution. 17.\" 3. Neither the name of The DragonFly Project nor the names of its 18.\" contributors may be used to endorse or promote products derived 19.\" from this software without specific, prior written permission. 20.\" 21.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25.\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26.\" INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32.\" SUCH DAMAGE. 33.\" 34.Dd January 30, 2012 35.Dt TOKEN 9 36.Os 37.Sh NAME 38.Nm lwkt_token_init , 39.Nm lwkt_token_uninit , 40.Nm lwkt_gettoken , 41.Nm lwkt_trytoken , 42.Nm lwkt_reltoken , 43.Nm lwkt_token_pool_lookup , 44.Nm lwkt_getpooltoken , 45.\".Nm lwkt_relpooltoken , 46.Nm lwkt_token_swap 47.Nd soft token locks 48.Sh SYNOPSIS 49.In sys/thread.h 50.Ft void 51.Fn lwkt_token_init "struct lwkt_token *tok" "char *desc" 52.Ft void 53.Fn lwkt_token_uninit "struct lwkt_token *tok" 54.Ft void 55.Fn lwkt_gettoken "struct lwkt_token *tok" 56.Ft int 57.Fn lwkt_trytoken "struct lwkt_token *tok" 58.Ft void 59.Fn lwkt_reltoken "struct lwkt_token *tok" 60.Ft struct lwkt_token * 61.Fn lwkt_token_pool_lookup "void *ptr" 62.Ft struct lwkt_token * 63.Fn lwkt_getpooltoken "void *ptr" 64.Ft void 65.Fn lwkt_gettoken_shared "struct lwkt_token *tok" 66.Ft void 67.Fn lwkt_token_swap "void" 68.Sh DESCRIPTION 69A soft token is a lock which is only held while a thread is running. 70If a thread explicitly blocks, all its tokens are released, and reacquired 71when the thread resumes. 72While a thread blocks, the conditions protected by a soft token 73may change and may need to be reevaluated on wakeup. 74.Pp 75Tokens may be taken recursively. 76However, tokens must be released in the reverse order they were acquired. 77.Pp 78Tokens may be acquired in shared mode, allowing multiple concurrent holders, 79via 80.Fn lwkt_gettoken_shared , 81or in exclusive mode, allowing only one holder, via 82.Fn lwkt_gettoken . 83It is safe to acquire a token shared while holding it exclusively. 84A thread attempting to acquire a token exclusively after holding it shared 85will deadlock. 86.Pp 87The pool token interface exists to allow using tokens with data structures 88which may be deallocated. 89It allows getting a token reference from an address, which 90is implemented by a set of statically allocated tokens and a hash function. 91.Pp 92It is not recommended to take pool tokens in shared mode. 93A hash collision 94from a subsequent exclusive pool token request will hit the 95exclusive-after-shared deadlock. 96.Pp 97The 98.Fn lwkt_token_init 99function is called to initialize a token. 100The 101.Fa desc 102argument specifies the wait string displayed when waiting for the token. 103The 104.Fn lwkt_token_uninit 105function is called to de-initialize one. 106Before using a token, it must be initialized. 107.Pp 108The 109.Fn lwkt_gettoken 110function attempts to acquire a token. 111If it is unsuccessful, the calling thread blocks. 112The 113.Fn lwkt_trytoken 114does the same thing; however, if it cannot acquire the token, it returns 0 115instead of blocking. 116The 117.Fn lwkt_reltoken 118function releases a previously acquired soft token. 119.Pp 120The 121.Fn lwkt_token_pool_lookup 122function takes an address and maps it to one of a number of statically 123allocated tokens. 124The 125.Fn lwkt_getpooltoken 126function acquires a token associated with an address. 127Use these two functions when tokens must protect a data structure, 128but the structure can be deallocated. 129Pool tokens do not need to be initialized. 130.Pp 131The 132.Fn lwkt_token_swap 133function swaps the two most recently acquired tokens; this allows release of 134tokens out-of-order. 135This function should not be called when less than two tokens are held. 136.Sh EXAMPLES 137A simple example of using a token to protect access to a data structure: 138.Bd -literal 139/* Data structure to be protected */ 140struct protected_data { 141 struct lwkt_token tok; 142 int data; 143}; 144 145struct protected_data pdata; 146 147/* Called early in boot */ 148void 149init(void) 150{ 151 lwkt_token_init(&pdata.tok, "example"); 152 pdata.data = 0; 153} 154 155/* 156 * A silly kthread; it uses a token to protect pdata.data. 157 */ 158void 159kthread1(void) 160{ 161 int local; 162 163 /* 164 * Get the soft token. 165 */ 166 lwkt_gettoken(&pdata.tok); 167 for (;;) { 168 local = pdata.data++; 169 tsleep(pdata, 0, "sleep", 0); 170 /* 171 * While we are asleep, we do not hold the token. When we 172 * awake here, we will hold the token again, but we may not 173 * depend on local reflecting pdata.data. 174 */ 175 176 local = pdata.data; 177 if (local == 4) 178 break; 179 } 180 /* 181 * Release the token. 182 */ 183 lwkt_reltoken(&pdata.tok); 184} 185.Ed 186.Pp 187An example using pool tokens: 188.Bd -literal 189struct dynamic_data { 190 int ref; 191}; 192 193/* 194 * Use a token to protect a reference count in a dynamic structure. 195 * Embedding a token in the structure would be inappropriate, since 196 * another thread may attempt to take the token after we have freed 197 * the object but before we have removed all external references to it. 198 */ 199void 200kfunction(struct dynamic_data *dynptr) 201{ 202 struct lwkt_token *tok; 203 204 /* 205 * Get a token from the associated with the address of dynptr 206 */ 207 tok = lwkt_getpooltoken(dynptr); 208 dynptr->ref--; 209 if (dynptr->ref == 0) 210 free(dynptr); 211 212 /* 213 * Release the token via its reference, as above 214 */ 215 lwkt_reltoken(tok); 216} 217.Ed 218.Sh NOTES 219Soft tokens are not released when a thread is preempted; they are only released 220when a thread explicitly blocks, such as via 221.Fn tsleep 222or 223.Fn lwkt_switch . 224.Pp 225If 226.Fn lwkt_gettoken 227blocks while attempting to acquire a token, all currently-held tokens will 228be released till a thread can acquire all of them again. 229.Pp 230When tokens are held and 231.Fn tsleep_interlock 232is used, tokens are not released until blocking happens - that is until the 233.Fn tsleep 234paired with the 235.Fn tsleep_interlock 236is called. 237.Sh FILES 238The LWKT Token implementation is in 239.Pa /sys/kern/lwkt_token.c . 240.Sh SEE ALSO 241.Xr crit_enter 9 , 242.Xr lockmgr 9 , 243.Xr serializer 9 , 244.Xr sleep 9 , 245.Xr spinlock 9 246.Sh HISTORY 247LWKT tokens first appeared in 248.Dx 1.0 . 249Shared tokens first appeared in 250.Dx 2.11 . 251.Sh AUTHORS 252The 253.Nm token 254implementation was written by 255.An Matthew Dillon . 256