(no commit message)
[ikiwiki.git] / docs / developer / Locking_and_Synchronization / index.mdwn
1 ## Spinlocks
2 ### Internals
3 * they effectively spin until the lock becomes released. In each spin (while iteration) they check if the lock has been released yet; if not, they just spin further.
4 * optimization for UP: do nothing.
5 * new lock holder spins already, not sleeping, so no need to wakeup
6 ### Usage
7 * very lightweight, but should be held only for *very* short time (as other contenders spin and don't sleep!)
8 * read spinlocks (effectively shared) are also available, but not recommended for new implementations
9 * can not sleep while holding a spinlock; scheduler will panic about spinlocks being held by yielding thread XXX
10 * can never recurse!
11 * used to protect structures
12
13 ----
14
15 ## LWKT serializing tokens
16 ### Internals
17 * uses atomic_cmpset* internally
18 * UP optimization: only check to see if preemption is happening, in which case acquisition of token fails.
19 * deeply integrated with lwkt scheduler (lwkt_yield, ...)
20         * scheduler takes care of acquiring the token before rescheduling
21         * so a thread won't run unless the scheduler can acquire all the tokens for it.
22         * tokens are not owned by the thread but by the CPU. threads only get token references
23 * no explicit wakeup when yielding a token reference
24 ### Usage
25 * a same thread can acquire multiple token references, but if that's the case, all tokens have to be acquired before the lwkt is scheduled!
26 * if thread sleeps while holding token references, other threads can acquire a token reference and run; so not completely safe to sleep
27 * used to protect heavier processing than spinlocks; but mostly also to protect data structures. Often used for global lists (allproc, etc)
28 * when acquiring token, not available, go to sleep, lose tokens
29
30 ----
31
32 ## Lockmgr
33 ### Internals
34 * uses a spinlock inside
35 * sleeps while acquiring (at least if NO_WAIT is not specified) XXX
36 * heavyweight
37 * wakeup used to activate new lock holder
38 * no UP optimization
39 ### Usage
40 * supports shared locks or exclusive locks, shared locks can be upgraded, exclusive can be downgraded
41 * can be acquired recursively, if the thread is the same and LK_CANRECURSE is specified
42 * can sleep while holding the lock.
43 * used when there is a requirement or possibility of blocking/sleep/recursion/...
44
45 ----
46
47 ## MTX
48 ### Internals
49 * based around atomic_cmpset_int instead of spinlocks
50 * uses wakeup to activate new lock holder
51 * much more lightweight than lockmgr (faster, much less space)
52 * no UP optimization
53 ### Usage
54 * can always be recursive
55 * can be shared/exclusive, so upgradable
56 * can be held across blocking/sleeps
57 * can pass lock ownership directly to new owner, so no wakeup needed and is guaranteed to reach the intended destination
58
59 ----
60
61 ## MPLock
62 ### Internals
63 * internally uses atomic_cmpset
64 * logs when the mplock is contended to KTR
65 * clogs performance inmensely
66 ### Usage
67 * should be avoided at all cost
68 * must be held as little as possible
69 * one for the whole system (all CPUs!!)
70         
71 ----
72
73 ## LWKT Messages
74 ### Internals
75 * messages are passed by queueing them to the destination thread's message queue, then waking up the listener.
76 * messages have to be allocated/deallocated (typically using objcache_*)
77         * (usually use a drain to deallocate; set the replyport to be the drain and then just reply to the message)
78 * rather lightweight, except for inter-processor messages
79 ### Usage
80 * isn't a locking mechanism, rather serialization as everything can be processed in one thread if the others just send it to that one
81 * can be used to avoid races: just do all the processing in one single thread
82 * send all the work from other threads/entry points to that one thread using lwkt messages.
83 * requires no locking
84
85 ----
86         
87 ## Critical Sections
88 ### Internals
89 * Changes priority of current thread to TDPRIT_CRIT, effectively avoiding preemption of the thread
90 * are per-cpu
91 ### Usage
92 * avoid anything else happening on that CPU due to the disabled preemption
93 * are no synchronization/locking between different CPUs!
94 * should be used if some code has to run uninterruptedly
95
96 ----
97
98 ## Condvars
99 ### Internals
100 * uses spinlocks internally on the condvar
101 ### Usage
102 * can interlock sleep when given a lockmgr lock to avoid missing changes to it, or just regular tsleep
103 * used to wait for conditions to happen (threads doing this are waiters)
104 * can wakeup all waiters or just one, effectively notifying that a change has occured
105