Rev 131 | Rev 140 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 131 | Rev 133 | ||
|---|---|---|---|
| Line 77... | Line 77... | ||
| 77 | 77 | ||
| 78 | <para>The scheduler, but also other pieces of the kernel, make heavy use |
78 | <para>The scheduler, but also other pieces of the kernel, make heavy use |
| 79 | of synchronous context switches, because it is a natural vehicle not |
79 | of synchronous context switches, because it is a natural vehicle not |
| 80 | only for changes in control flow, but also for switching between two |
80 | only for changes in control flow, but also for switching between two |
| 81 | kernel stacks. Two functions figure in a synchronous context switch |
81 | kernel stacks. Two functions figure in a synchronous context switch |
| 82 | implementation: <code>context_save</code> and |
82 | implementation: <code>context_save()</code> and |
| 83 | <code>context_restore</code>. Note that these two functions break the |
83 | <code>context_restore()</code>. Note that these two functions break the |
| 84 | natural perception of the linear C code execution flow starting at |
84 | natural perception of the linear C code execution flow starting at |
| 85 | function's entry point and ending on one of the function's exit |
85 | function's entry point and ending on one of the function's exit |
| 86 | points.</para> |
86 | points.</para> |
| 87 | 87 | ||
| 88 | <para>When the <code>context_save</code> function is called, the |
88 | <para>When the <code>context_save()</code> function is called, the |
| 89 | synchronous context is saved in a memory structure passed to it. After |
89 | synchronous context is saved in a memory structure passed to it. After |
| 90 | executing <code>context_save</code>, the caller is returned 1 as a |
90 | executing <code>context_save()</code>, the caller is returned 1 as a |
| 91 | return value. The execution of instructions continues as normally until |
91 | return value. The execution of instructions continues as normally until |
| 92 | <code>context_restore</code> is called. For the caller, it seems like |
92 | <code>context_restore()</code> is called. For the caller, it seems like |
| 93 | the call never returns<footnote> |
93 | the call never returns<footnote> |
| 94 | <para>Which might be a source of problems with variable liveliness |
94 | <para>Which might be a source of problems with variable liveliness |
| 95 | after <code>context_restore</code>.</para> |
95 | after <code>context_restore()</code>.</para> |
| 96 | </footnote>. Nevertheless, a synchronous register context, which is |
96 | </footnote>. Nevertheless, a synchronous register context, which is |
| 97 | saved in a memory structure passed to <code>context_restore,</code> is |
97 | saved in a memory structure passed to <code>context_restore()</code>, is |
| 98 | restored, thus transfering the control flow to the place of occurrence |
98 | restored, thus transfering the control flow to the place of occurrence |
| 99 | of the corresponding call to <code>context_save</code>. From the |
99 | of the corresponding call to <code>context_save()</code>. From the |
| 100 | perspective of the caller of the corresponding |
100 | perspective of the caller of the corresponding |
| 101 | <code>context_save</code>, it looks as though a return from |
101 | <code>context_save()</code>, it looks like a return from |
| 102 | <code>context_save</code>. However, this time a return value of 0 is |
102 | <code>context_save()</code>. However, this time a return value of 0 is |
| 103 | returned.</para> |
103 | returned.</para> |
| 104 | </section> |
104 | </section> |
| 105 | </section> |
105 | </section> |
| 106 | 106 | ||
| 107 | <section> |
107 | <section> |
| Line 134... | Line 134... | ||
| 134 | possibilities. It either runs until it is preemtped, in which case the |
134 | possibilities. It either runs until it is preemtped, in which case the |
| 135 | state changes to <constant>Ready</constant>, goes to the |
135 | state changes to <constant>Ready</constant>, goes to the |
| 136 | <constant>Sleeping</constant> state by going to sleep or enters the |
136 | <constant>Sleeping</constant> state by going to sleep or enters the |
| 137 | <constant>Exiting</constant> state when it reaches termination. When the |
137 | <constant>Exiting</constant> state when it reaches termination. When the |
| 138 | thread exits, its kernel structure usually stays in memory, until the |
138 | thread exits, its kernel structure usually stays in memory, until the |
| 139 | thread is detached by another thread using <code>thread_detach</code> |
139 | thread is detached by another thread using <code>thread_detach()</code> |
| 140 | function. Terminated but undetached threads are in the |
140 | function. Terminated but undetached threads are in the |
| 141 | <constant>Undead</constant> state. When the thread is detached or |
141 | <constant>Undead</constant> state. When the thread is detached or |
| 142 | detaches itself during its life, it is destroyed in the |
142 | detaches itself during its life, it is destroyed in the |
| 143 | <constant>Exiting</constant> state and the <constant>Undead</constant> |
143 | <constant>Exiting</constant> state and the <constant>Undead</constant> |
| 144 | state is not reached.<figure float="1"> |
144 | state is not reached.<figure float="1"> |
| Line 205... | Line 205... | ||
| 205 | 205 | ||
| 206 | <section> |
206 | <section> |
| 207 | <title>Scheduler Operation</title> |
207 | <title>Scheduler Operation</title> |
| 208 | 208 | ||
| 209 | <para>The scheduler is invoked either explicitly when a thread calls the |
209 | <para>The scheduler is invoked either explicitly when a thread calls the |
| 210 | <code>scheduler</code> function (e.g. goes to sleep or merely wants to |
210 | <code>scheduler()</code> function (e.g. goes to sleep or merely wants to |
| 211 | relinquish the processor for a while) or implicitly on a periodic basis |
211 | relinquish the processor for a while) or implicitly on a periodic basis |
| 212 | when the generic clock interrupt preempts the current thread. After its |
212 | when the generic clock interrupt preempts the current thread. After its |
| 213 | invocation, the scheduler saves the synchronous register context of the |
213 | invocation, the scheduler saves the synchronous register context of the |
| 214 | current thread and switches to its private stack. Afterwards, a new |
214 | current thread and switches to its private stack. Afterwards, a new |
| 215 | thread is selected according to the scheduling policy. If there is no |
215 | thread is selected according to the scheduling policy. If there is no |
| Line 223... | Line 223... | ||
| 223 | <para>The scheduling policy is implemented in function |
223 | <para>The scheduling policy is implemented in function |
| 224 | <code>find_best_thread</code>. This function walks the processor run |
224 | <code>find_best_thread</code>. This function walks the processor run |
| 225 | queues from lower towards higher indices and looks for a thread. If the |
225 | queues from lower towards higher indices and looks for a thread. If the |
| 226 | visited run queue is empty, it simply searches the next run queue. If it |
226 | visited run queue is empty, it simply searches the next run queue. If it |
| 227 | is known in advance that there are no ready threads waiting for |
227 | is known in advance that there are no ready threads waiting for |
| 228 | execution, <code>find_best_thread</code> interruptibly halts the |
228 | execution, <code>find_best_thread()</code> interruptibly halts the |
| 229 | processor or busy waits until some threads arrive. This process repeats |
229 | processor or busy waits until some threads arrive. This process repeats |
| 230 | until <code>find_best_thread</code> succeeds.</para> |
230 | until <code>find_best_thread()</code> succeeds.</para> |
| 231 | 231 | ||
| 232 | <para>After the best thread is chosen, the scheduler switches to the |
232 | <para>After the best thread is chosen, the scheduler switches to the |
| 233 | thread's task and memory management context. Finally, the saved |
233 | thread's task and memory management context. Finally, the saved |
| 234 | synchronous register context is restored and the thread runs. Each |
234 | synchronous register context is restored and the thread runs. Each |
| 235 | scheduled thread is given a time slice depending on its priority (i.e. |
235 | scheduled thread is given a time slice depending on its priority (i.e. |