NAME
lwkt_token_init
,
lwkt_token_uninit
,
lwkt_gettoken
,
lwkt_trytoken
,
lwkt_reltoken
,
lwkt_token_pool_lookup
,
lwkt_getpooltoken
,
lwkt_token_swap
—
soft token locks
SYNOPSIS
#include
<sys/thread.h>
void
lwkt_token_init
(struct
lwkt_token *tok, const
char *desc);
void
lwkt_token_uninit
(struct
lwkt_token *tok);
void
lwkt_gettoken
(struct
lwkt_token *tok);
int
lwkt_trytoken
(struct
lwkt_token *tok);
void
lwkt_reltoken
(struct
lwkt_token *tok);
struct lwkt_token *
lwkt_token_pool_lookup
(void
*ptr);
struct lwkt_token *
lwkt_getpooltoken
(void
*ptr);
void
lwkt_gettoken_shared
(struct
lwkt_token *tok);
void
lwkt_token_swap
(void);
DESCRIPTION
A soft token is a lock which is only held while a thread is running. If a thread explicitly blocks, all its tokens are released, and reacquired when the thread resumes. While a thread blocks, the conditions protected by a soft token may change and may need to be reevaluated on wakeup.Tokens may be taken recursively. However, tokens must be released in the reverse order they were acquired.
The pool token interface exists to allow using tokens with data structures which may be deallocated. It allows getting a token reference from an address, which is implemented by a set of statically allocated tokens and a hash function.
It is not recommended to take pool tokens in shared mode. A hash collision from a subsequent exclusive pool token request will hit the exclusive-after-shared deadlock.
The
lwkt_token_init
()
function is called to initialize a token. The desc
argument specifies the wait string displayed when waiting for the token. The
lwkt_token_uninit
()
function is called to de-initialize one. Before using a token, it must be
initialized.
The
lwkt_gettoken
()
function attempts to acquire a token. If it is unsuccessful, the calling
thread blocks. The
lwkt_trytoken
()
does the same thing; however, if it cannot acquire the token, it returns 0
instead of blocking. The
lwkt_reltoken
()
function releases a previously acquired soft token.
The
lwkt_token_pool_lookup
()
function takes an address and maps it to one of a number of statically
allocated tokens. The
lwkt_getpooltoken
()
function acquires a token associated with an address. Use these two
functions when tokens must protect a data structure, but the structure can
be deallocated. Pool tokens do not need to be initialized.
The
lwkt_token_swap
()
function swaps the two most recently acquired tokens; this allows release of
tokens out-of-order. This function should not be called when less than two
tokens are held.
FILES
The LWKT Token implementation is in /sys/kern/lwkt_token.c.
EXAMPLES
A simple example of using a token to protect access to a data structure:
/* Data structure to be protected */ struct protected_data { struct lwkt_token tok; int data; }; struct protected_data pdata; /* Called early in boot */ void init(void) { lwkt_token_init(&pdata.tok, "example"); pdata.data = 0; } /* * A silly kthread; it uses a token to protect pdata.data. */ void kthread1(void) { int local; /* * Get the soft token. */ lwkt_gettoken(&pdata.tok); for (;;) { local = pdata.data++; tsleep(pdata, 0, "sleep", 0); /* * While we are asleep, we do not hold the token. When we * awake here, we will hold the token again, but we may not * depend on local reflecting pdata.data. */ local = pdata.data; if (local == 4) break; } /* * Release the token. */ lwkt_reltoken(&pdata.tok); }
An example using pool tokens:
struct dynamic_data { int ref; }; /* * Use a token to protect a reference count in a dynamic structure. * Embedding a token in the structure would be inappropriate, since * another thread may attempt to take the token after we have freed * the object but before we have removed all external references to it. */ void kfunction(struct dynamic_data *dynptr) { struct lwkt_token *tok; /* * Get a token from the associated with the address of dynptr */ tok = lwkt_getpooltoken(dynptr); dynptr->ref--; if (dynptr->ref == 0) free(dynptr); /* * Release the token via its reference, as above */ lwkt_reltoken(tok); }
NOTES
Soft tokens are not released when a thread is preempted; they are
only released when a thread explicitly blocks, such as via
tsleep
()
or
lwkt_switch
().
If
lwkt_gettoken
()
blocks while attempting to acquire a token, all currently-held tokens will
be released till a thread can acquire all of them again.
When tokens are held and
tsleep_interlock
()
is used, tokens are not released until blocking happens - that is until the
tsleep
() paired with the
tsleep_interlock
() is called.
SEE ALSO
crit_enter(9), lockmgr(9), serializer(9), sleep(9), spinlock(9)
HISTORY
LWKT tokens first appeared in DragonFly 1.0. Shared tokens first appeared in DragonFly 2.11.
AUTHORS
The token
implementation was written by
Matthew Dillon.