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. |