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