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