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