## Spinlocks ### Internals * 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. * optimization for UP: do nothing. * new lock holder spins already, not sleeping, so no need to wakeup ### Usage * very lightweight, but should be held only for *very* short time (as other contenders spin and don't sleep!) * read spinlocks (effectively shared) are also available, but not recommended for new implementations * can not sleep while holding a spinlock; scheduler will panic about spinlocks being held by yielding thread XXX * can never recurse! * used to protect structures ---- ## LWKT serializing tokens ### Internals * uses atomic_cmpset* internally * UP optimization: only check to see if preemption is happening, in which case acquisition of token fails. * deeply integrated with lwkt scheduler (lwkt_yield, ...) * scheduler takes care of acquiring the token before rescheduling * so a thread won't run unless the scheduler can acquire all the tokens for it. * tokens are not owned by the thread but by the CPU. threads only get token references * no explicit wakeup when yielding a token reference ### Usage * 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! * if thread sleeps while holding token references, other threads can acquire a token reference and run; so not completely safe to sleep * used to protect heavier processing than spinlocks; but mostly also to protect data structures. Often used for global lists (allproc, etc) * when acquiring token, not available, go to sleep, lose tokens ---- ## Lockmgr ### Internals * uses a spinlock inside * sleeps while acquiring (at least if NO_WAIT is not specified) XXX * heavyweight * wakeup used to activate new lock holder * no UP optimization ### Usage * supports shared locks or exclusive locks, shared locks can be upgraded, exclusive can be downgraded * can be acquired recursively, if the thread is the same and LK_CANRECURSE is specified * can sleep while holding the lock. * used when there is a requirement or possibility of blocking/sleep/recursion/... ---- ## MTX ### Internals * based around atomic_cmpset_int instead of spinlocks * uses wakeup to activate new lock holder * much more lightweight than lockmgr (faster, much less space) * no UP optimization ### Usage * can always be recursive * can be shared/exclusive, so upgradable * can be held across blocking/sleeps * can pass lock ownership directly to new owner, so no wakeup needed and is guaranteed to reach the intended destination ---- ## MPLock ### Internals * internally uses atomic_cmpset * logs when the mplock is contended to KTR * clogs performance inmensely ### Usage * should be avoided at all cost * must be held as little as possible * one for the whole system (all CPUs!!) ---- ## LWKT Messages ### Internals * messages are passed by queueing them to the destination thread's message queue, then waking up the listener. * messages have to be allocated/deallocated (typically using objcache_*) * (usually use a drain to deallocate; set the replyport to be the drain and then just reply to the message) * rather lightweight, except for inter-processor messages ### Usage * isn't a locking mechanism, rather serialization as everything can be processed in one thread if the others just send it to that one * can be used to avoid races: just do all the processing in one single thread * send all the work from other threads/entry points to that one thread using lwkt messages. * requires no locking ---- ## Critical Sections ### Internals * Changes priority of current thread to TDPRIT_CRIT, effectively avoiding preemption of the thread * are per-cpu ### Usage * avoid anything else happening on that CPU due to the disabled preemption * are no synchronization/locking between different CPUs! * should be used if some code has to run uninterruptedly ---- ## Condvars ### Internals * XXX: current implementation is incorrect, need to use lksleep!! * XXX: currently not yet in the main repository * uses spinlocks internally on the condvar ### Usage * can interlock sleep when given a lockmgr lock to avoid missing changes to it, or just regular tsleep * used to wait for conditions to happen (threads doing this are waiters) * can wakeup all waiters or just one, effectively notifying that a change has occured