/** Copyright 2023 Haiku Inc. All rights reserved.* Distributed under the terms of the MIT License.** Authors:* Adrien Destugues*//*!\page synchronization_primitives Synchronization primitivesIn userspace code, there are many way to synchronize threads with each other. Pthreads providemutexes and condition variables. The Be API provides BLocker. There are also atomic functionsand a few other options, on which many solutions can be built.The kernel side is a bit more restricted, in particular when it comes to synchronizing betweeninterrupt handlers and other parts of the code. This is because of two reasons: first of all,interrupt are a low level mechanism of the CPU, and while interrupt handling code is running,the normal operations of the kernel are interrupted (as the name implies). So, normalscheduling will not take place. Secondly, interrupts are not allowed to be blocked to wait onanything. This rules out the use of critical sections in the traditional sense, where theinterrupt code may want to wait for an userspace thread to complete.As a result, the way synchronization is handled in the kernel is a bit different. The basicprimitives available are: spinlocks, atomic operations, semaphores, and condition variables.\section spinlocks SpinlocksA spinlock is a busy wait: it will run a loop, testing over and over for a condition to becometrue. On a single task system, that would not work, the CPU would be busy forever, and thecondition would never change. But, Haiku is a multitask system, and so the condition can bechanged, either because of code running on another CPU core, or code running in an interrupthandler (which can interrupt the thread that's running the spinlock).The downside of spinlocks is that they keep the CPU busy. Not only this increases power usage,it also prevents using the CPU for something else (maybe another thread would like to runwhile this one is waiting). As a result, they are used only for very short waits, and alwayswith a timeout to make sure they don't lock up a CPU core forever or even for an unreasonablylong time (that will result in a panic and a trip to the kernel debugger).\section atomic_ops Atomic operationsAtomic operations are defined in the \ref support. However, they are actually implementedusing only CPU instructions, and no operating system support. This means they are availablefor use in Kernel code as well.They are used as a building block for higher level primitives, but are also occasionally usefulfor simple synchronization needs or things like event counters. Since they are implementedat the CPU level, they are quite fast.Atomic operations are not blocking, but they guarantee that an operation will complete beforean interrupt happens or another CPU core accesses the same memory.\section semaphores SemaphoresSemaphores are the historical way to signal events in BeOS and Haiku. A semaphore has a counterthat can be incremented (\ref release_sem) and decremented (\ref acquire_sem). The counter isnot allowed to go below 0, if a thread attempts to acquire an empty semaphore, it will beblocked until someone else releases it.Seaphores can be used to implement mutexes: by creating a semaphore with a count of 1, threadscan enter the critical section by acquiring, and exit it by releasing the semaphore. Additionalchecks can be added to make sure that only threads in the critical section can release thesemaphore in this case.But semaphores are also useful in other cases. For example, they can be used for an interupthandler to wake up a thread. In that case, the interrupt handler always releases the semaphore(when an interrupt happens) and the thread always acquires it. Releasing a semaphore is nevera blocking operation, so there is no risk of blocking an interrupt handler. This setup makessure the thread is waken up exactly one time per event the interrupt needs to handle.Finally, semaphores are identified by an unique number, which can be shared between kerneland userspace. As a result, they can be used to sycnhronize directly between userspace andkernelspace threads, or even directly from interrupt handlers to userspace threads. Thedownside of this is that there is a limited number of semaphores, and if too much code usesthem, or if there is a leak in some code creating and never destroing semaphores, this mayend up blocking the system completely.\section condition_variables Condition VariablesA more recent addition to Haiku synchronization primitives is \ref ConditionVariable.Condition variables allow a thread to wait for a specific condition, which is notified byanother thread. This is similar to the use of semaphores outlined above, but provides an easierway to handle race conditions, spurious wakeups, and so on.In user-space programming, condition variables are used for thread synchronization inconjunction with a locking system. One thread will acquire a lock and verify (atomically) thatsome condition is not satisfied, it will then wait on the condition variable and unlock thelock. Another thread then notifies the condition variable - waking up the thread - when thecondition is satisfied.The kernel implementation in Haiku is a bit more flexible, which allows it to be used also frominterrupt handlers. An interrupt may notify a condition variable. Since interrupts usuallycannot be locked with mutexes, the synchronization is provided by other means. In some cases,no synchronization is needed at all: the driver main code can create a ConditionVariableEntyand add it to the condition variable before accessing the hardware in a way that will laterschedule an interrupt. In that case, the order of operations is guaranteed: the thread willbe watching the condition variable before the interrupt can be triggered, and the interruptwill wake up the thread. In cases where this is possible, condition variables provide a verysimple and efficient synchronization primitive and makes writing drivers much safer and simpler.*/