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 May 31, 2010 35.Os 36.Dt TOKEN 9 37.Sh NAME 38.Nm lwkt_token_init , 39.Nm lwkt_token_uninit , 40.Nm lwkt_gettoken , 41.Nm lwkt_trytoken , 42.Nm lwkt_gettokref , 43.Nm lwkt_trytokref , 44.Nm lwkt_reltoken , 45.Nm lwkt_token_pool_lookup , 46.Nm lwkt_getpooltoken 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" 52.Ft void 53.Fn lwkt_token_uninit "struct lwkt_token *tok" 54.Ft void 55.Fn lwkt_gettoken "lwkt_tokref *ref" "struct lwkt_token *tok" 56.Ft int 57.Fn lwkt_trytoken "lwkt_tokref *ref" "struct lwkt_token *tok" 58.Ft void 59.Fn lwkt_gettokref "lwkt_tokref *ref" 60.Ft int 61.Fn lwkt_trytokref "lwkt_tokref *ref" 62.Ft void 63.Fn lwkt_reltoken "lwkt_tokref *ref" 64.Ft struct lwkt_token * 65.Fn lwkt_token_pool_lookup "void *ptr" 66.Ft void 67.Fn lwkt_getpooltoken "lwkt_tokref *ref" "void *ptr" 68.Sh DESCRIPTION 69.Pp 70A soft token is a lock which is only held while a thread is running. 71If a thread explicitly blocks, all its tokens are released, and reacquired 72when the thread resumes. 73While a thread blocks, the conditions protected by a soft token 74may change and may need to be reevaluated on wakeup. 75.Pp 76Tokens are manipulated via token references, 77.Vt lwkt_tokref . 78.Pp 79Tokens may be taken recursively. 80However, tokens must be released in the reverse order they were acquired. 81.Pp 82The pool token interface exists to allow using tokens with data structures 83which may be deallocated. 84It allows getting a token reference from an address, which 85is implemented by a set of statically allocated tokens and a hash function. 86.Pp 87The 88.Fn lwkt_token_init 89function is called to initialize a token. 90The 91.Fn lwkt_token_uninit 92function is called to de-initialize one. 93Before using a token, it must be initialized. 94.Pp 95The 96.Fn lwkt_gettoken 97function attemps to acquire a token; if it is successful, it initializes the 98token reference ref to reference the token. 99If it is unsuccessful, the calling thread blocks. 100The 101.Fn lwkt_trytoken 102does the same thing; however, if it cannot acquire the token, it returns a 103non-zero number instead of blocking. 104The 105.Fn lwkt_gettokref 106and 107.Fn lwkt_trytokref 108functions behave similarly, but they attempt to acquire a token referenced by 109ref rather than one passed by address; use when reacquiring a token. 110The 111.Fn lwkt_reltoken 112function releases a soft token and is called with a token reference. 113.Pp 114The 115.Fn lwkt_token_pool_lookup 116function takes an address and maps it to one of a number of statically 117allocated tokens. 118The 119.Fn lwkt_getpooltoken 120function acquires a token associated with an address. 121Use these two functions when tokens must protect a data structure, 122but the structure can be deallocated. 123Pool tokens do not need to be initialized. 124.Sh EXAMPLES 125A simple example of using a token to protect access to a data structure: 126.Bd -literal 127/* Data structure to be protected */ 128struct protected_data { 129 struct lwkt_token tok; 130 int data; 131}; 132 133struct protected_data pdata; 134 135/* Called early in boot */ 136void 137init(void) 138{ 139 lwkt_token_init(&pdata.tok); 140 pdata.data = 0; 141} 142 143/* 144 * A silly kthread; it uses a token to protect pdata.data. 145 */ 146void 147kthread1(void) 148{ 149 lwkt_tokref pdat_tref; 150 int local; 151 152 /* 153 * Get the soft token. pdat_tref will function as a handle 154 */ 155 lwkt_gettoken(&pdat_tref, &pdata.tok); 156 for (;;) { 157 local = pdata.data++; 158 tsleep(pdata, 0, "sleep", 0); 159 /* 160 * While we are asleep, we do not hold the token. When we 161 * awake here, we will hold the token again, but we may not 162 * depend on local reflecting pdata.data. 163 */ 164 165 local = pdata.data; 166 if (local == 4) 167 break; 168 } 169 /* 170 * Release the token. Release via the token reference. 171 */ 172 lwkt_reltoken(&pdat_tref); 173 174 /* 175 * Retake the token via the tokref; release afterwards 176 */ 177 lwkt_gettokref(&pdat_tref); 178 lwkt_reltoken(&pdat_tref); 179} 180.Ed 181.Pp 182An example using pool tokens: 183.Bd -literal 184struct dynamic_data { 185 int ref; 186}; 187 188/* 189 * Use a token to protect a reference count in a dynamic structure. 190 * Embedding a token in the structure would be inappropriate, since 191 * another thread may attempt to take the token after we have freed 192 * the object but before we have removed all external references to it. 193 */ 194void 195kfunction(struct dynamic_data *dynptr) 196{ 197 lwkt_tokref ddata_ref; 198 199 /* 200 * Get a token from the associated with the address of dynptr 201 */ 202 lwkt_getpooltoken(&ddata_ref, dynptr); 203 dynptr->ref--; 204 if (dynptr->ref == 0) 205 free(dynptr); 206 207 /* 208 * Release the token via its reference, as above 209 */ 210 lwkt_reltoken(dynptr); 211} 212.Ed 213.Sh NOTES 214Soft tokens are not released when a thread is preempted; they are only released 215when a thread explicitly blocks, such as via 216.Fn tsleep 217or 218.Fn lwkt_switch . 219.Pp 220If 221.Fn lwkt_gettoken 222blocks while attempting to acquire a token, all currently-held tokens will 223be released till a thread can acquire all of them again. 224.Pp 225When tokens are held and 226.Fn tsleep_interlock 227is used, tokens are not released until blocking happens - that is until the 228.Fn tsleep 229paired with the 230.Fn tsleep_interlock 231is called. 232.Sh FILES 233The LWKT Token implementation is in 234.Pa /sys/kern/lwkt_token.c . 235.Sh SEE ALSO 236.Xr crit_enter 9 , 237.Xr lockmgr 9 , 238.Xr serializer 9 , 239.Xr sleep 9 , 240.Xr spinlock 9 241.Sh HISTORY 242LWKT tokens first appeared in 243.Dx 1.0 . 244.Sh AUTHORS 245The 246.Nm token 247implementation was written by 248.An Matthew Dillon . 249