xref: /dflybsd-src/share/man/man9/token.9 (revision abdf9ff7ecf1197b8e86f424661a8cf30d024863)
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