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 |