Rev 11 | Rev 43 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 11 | Rev 41 | ||
|---|---|---|---|
| Line 1... | Line 1... | ||
| 1 | <?xml version="1.0" encoding="UTF-8"?> |
1 | <?xml version="1.0" encoding="UTF-8"?> |
| - | 2 | <chapter id="sync"> |
|
| - | 3 | <?dbhtml filename="sync.html"?> |
|
| 2 | 4 | ||
| - | 5 | <title>Mutual exclusion and synchronization</title> |
|
| 3 | 6 | ||
| 4 | <chapter id="sync"><?dbhtml filename="sync.html"?> |
7 | <section> |
| 5 | <title>Synchronization</title> |
8 | <title>Introduction</title> |
| 6 | 9 | ||
| - | 10 | <para>The HelenOS operating system is designed to make use of parallelism |
|
| - | 11 | offered by hardware and to exploit concurrency of both the kernel and |
|
| 7 | <section> |
12 | userspace tasks. This is achieved through multiprocessor support and |
| 8 | <title>Introduction. Concept.</title> |
13 | several levels of multiprogramming (i.e. multitasking, multithreading and |
| 9 | - | ||
| - | 14 | through userspace pseudo threads). However, such a highly concurrent |
|
| - | 15 | environment needs safe and efficient ways to handle mutual exclusion and |
|
| 10 | <para>Couple of words about global conception of sychronization</para> |
16 | synchronization of many execution flows.</para> |
| 11 | </section> |
17 | </section> |
| 12 | 18 | ||
| - | 19 | <section> |
|
| - | 20 | <title>Active kernel primitives</title> |
|
| 13 | 21 | ||
| 14 | <section> |
22 | <section> |
| 15 | <title>Active kernel synchronization. Spinlock.</title> |
23 | <title>Spinlocks</title> |
| 16 | <para>Spinlocks explanation. Arch specific notes.</para> |
- | |
| 17 | </section> |
- | |
| 18 | 24 | ||
| - | 25 | <para>The basic mutual exclusion primitive is the spinlock. Spinlock |
|
| - | 26 | implements busy waiting for an availability of a memory lock (i.e. |
|
| - | 27 | simple variable) in a multiprocessor-safe manner. This safety is |
|
| - | 28 | achieved through the use of a specialized, architecture-dependent, |
|
| - | 29 | atomic test-and-set operation which either locks the spinlock (i.e. sets |
|
| - | 30 | the variable) or, provided that it is already locked, leaves it |
|
| - | 31 | unaltered. In any case, the test-and-set operation returns a value, thus |
|
| - | 32 | signalling either success (i.e. zero return value) or failure (i.e. |
|
| - | 33 | non-zero value) in acquiring the lock. Note that this makes the |
|
| - | 34 | fundamental difference between the naive algorithm that doesn't use the |
|
| - | 35 | atomic operation and the spinlock algortihm. While the naive algorithm |
|
| - | 36 | is prone to race conditions on SMP configuratinos and thus is completely |
|
| - | 37 | SMP-unsafe, the spinlock algorithm eliminates the possibility of race |
|
| - | 38 | conditions and is suitable for mutual exclusion use.</para> |
|
| - | 39 | ||
| - | 40 | <para></para> |
|
| - | 41 | ||
| - | 42 | <para>The semantics of the test-and-set operation is that the spinlock |
|
| - | 43 | remains unavailable until this operation called on the respective |
|
| - | 44 | spinlock returns zero. HelenOS builds two functions on top of |
|
| - | 45 | test-and-set operation. The first is the unconditional attempt to |
|
| - | 46 | acquire the spinlock and is called <emphasis>spinlock_lock</emphasis>. |
|
| - | 47 | It simply loops until test-and-set returns zero. The other operation, |
|
| - | 48 | <emphasis>spinlock_trylock</emphasis>, is the conditional lock operation |
|
| - | 49 | and calls the test-and-set only once to find out wheter it managed to |
|
| - | 50 | acquire the spinlock or not. The conditional operation is useful in |
|
| - | 51 | situations in which an algorithm cannot acquire more spinlocks in the |
|
| - | 52 | proper order and a deadlock cannot be avoided. In such a case, the |
|
| - | 53 | algorithm would detect the danger and instead of possibly deadlocking |
|
| - | 54 | the system it would simply release some spinlocks it already holds and |
|
| - | 55 | retry the whole operation with the hope that it will succeed next time. |
|
| - | 56 | The unlock operation, <emphasis>spinlock_unlock</emphasis>, is quite |
|
| - | 57 | easy - it merely clears the spinlock variable.</para> |
|
| - | 58 | ||
| - | 59 | <para></para> |
|
| - | 60 | ||
| - | 61 | <para>Nevertheless, there is a special issue related to hardware |
|
| - | 62 | optimizations that modern processors implement. Particularily |
|
| - | 63 | problematic is the out-of-order execution of instructions within the |
|
| - | 64 | critical section protected by a spinlock. The processors are always |
|
| - | 65 | self-consistent so that they can carry out speculatively executed |
|
| - | 66 | instructions in the right order with regard to dependencies among those |
|
| - | 67 | instructions. However, the dependency between instructions inside the |
|
| - | 68 | critical section and those that implement locking and unlocking of the |
|
| - | 69 | respective spinlock is not implicit on some processor architectures and |
|
| - | 70 | the processor needs to be explicitly told about each occurrence of such |
|
| - | 71 | a dependency. Therefore, HelenOS adds architecture-specific hooks to all |
|
| - | 72 | <emphasis>spinlock_lock</emphasis>, |
|
| - | 73 | <emphasis>spinlock_trylock</emphasis> and |
|
| - | 74 | <emphasis>spinlock_unlock</emphasis> to prevent the instructions inside |
|
| - | 75 | the critical section from bleeding out. On some architectures, these |
|
| - | 76 | hooks can be a no-op because the dependencies are implicitly there |
|
| - | 77 | because of the special properties of locking and unlocking instructions. |
|
| - | 78 | However, other architectures need to instrument these hooks with |
|
| - | 79 | different memory barriers, depending on what operations can bleed |
|
| - | 80 | out.</para> |
|
| - | 81 | ||
| - | 82 | <para></para> |
|
| - | 83 | ||
| - | 84 | <para>Spinlocks have one significant drawback: when held for longer time |
|
| - | 85 | periods, they harm both parallelism and concurrency. Processor executing |
|
| - | 86 | <emphasis>spinlock_lock</emphasis> does not do any fruitful work and is |
|
| - | 87 | effectively halted until it can grab the lock and proceed. Similarily, |
|
| - | 88 | other threads cannot execute on the processor that holds the spinlock |
|
| - | 89 | because the kernel disables preemption on that processor when a spinlock |
|
| - | 90 | is held. The reason behind disabling preemption is priority inversion |
|
| - | 91 | problem avoidance. For the same reason, threads are strongly discouraged |
|
| - | 92 | from sleeping when they hold a spinlock.</para> |
|
| - | 93 | ||
| - | 94 | <para></para> |
|
| - | 95 | ||
| - | 96 | <para>To summarize, spinlocks represent very simple and essential mutual |
|
| - | 97 | exclusion primitive for SMP systems. On the other hand, spinlocks scale |
|
| - | 98 | poorly because of the active loop they are based on. Therefore, |
|
| - | 99 | spinlocks are used in HelenOS only for a short-time mutual exclusion and |
|
| - | 100 | in cases where the mutual exclusion is required out of thread context. |
|
| - | 101 | Lastly, spinlocks are used in the construction of passive |
|
| - | 102 | synchronization primitives.</para> |
|
| - | 103 | </section> |
|
| - | 104 | </section> |
|
| 19 | 105 | ||
| - | 106 | <section> |
|
| - | 107 | <title>Passive kernel synchronization</title> |
|
| 20 | 108 | ||
| 21 | <section> |
109 | <section> |
| 22 | <title>Passive kernel synchronization</title> |
110 | <title>Mutexes</title> |
| 23 | 111 | ||
| 24 | <section> |
- | |
| 25 | <title>Mutex</title> |
- | |
| 26 | - | ||
| 27 | <para>Mutex explanations</para> |
112 | <para>Mutex explanations</para> |
| 28 | </section> |
113 | </section> |
| 29 | - | ||
| 30 | <section> |
- | |
| 31 | <title>Semaphore</title> |
- | |
| 32 | 114 | ||
| 33 | <para>Semaphore explanations</para> |
115 | <section> |
| 34 | </section> |
116 | <title>Semaphores</title> |
| 35 | 117 | ||
| 36 | <section> |
118 | <para>Semaphore explanations</para> |
| 37 | <title>Read/Write Locks</title> |
119 | </section> |
| 38 | 120 | ||
| 39 | <para>RWLocks explanation</para> |
121 | <section> |
| 40 | </section> |
122 | <title>Read/Write Locks</title> |
| 41 | 123 | ||
| 42 | <section> |
124 | <para>RWLocks explanation</para> |
| 43 | <title>Wait queues</title> |
125 | </section> |
| 44 | 126 | ||
| 45 | <para>Wait queue explanation</para> |
127 | <section> |
| 46 | </section> |
128 | <title>Wait queues</title> |
| 47 | 129 | ||
| - | 130 | <para>Wait queue explanation</para> |
|
| - | 131 | </section> |
|
| 48 | 132 | ||
| 49 | <section> |
133 | <section> |
| 50 | <title>Conditional variables</title> |
134 | <title>Condition variables</title> |
| 51 | 135 | ||
| 52 | <para>Condvars explanation</para> |
136 | <para>Condvars explanation</para> |
| 53 | </section> |
137 | </section> |
| 54 | </section> |
138 | </section> |
| 55 | 139 | ||
| - | 140 | <section> |
|
| - | 141 | <title>Userspace synchronization</title> |
|
| 56 | 142 | ||
| 57 | <section> |
143 | <section> |
| 58 | <title>Userspace synchronization. Futex.</title> |
144 | <title>Futexes</title> |
| 59 | 145 | ||
| 60 | <para>Idea. Futex explanation.</para> |
146 | <para></para> |
| 61 | </section> |
147 | </section> |
| 62 | 148 | </section> |
|
| 63 | </chapter> |
149 | </chapter> |
| 64 | - | ||
| 65 | 150 | ||