37 |
} \ |
} \ |
38 |
while (0) |
while (0) |
39 |
|
|
40 |
|
/* Reaper list for zombie threads. */ |
41 |
|
|
42 |
|
static struct queue_entry reaper_list = queue_ctor (reaper_list); |
43 |
|
static spin_lock_t reaper_lock = SPIN_LOCK_INITIALIZER; |
44 |
|
|
45 |
/* ???? */ |
/* ???? */ |
46 |
|
|
47 |
struct sched_policy sched_policies [4]; |
struct sched_policy sched_policies [4]; |
61 |
/* Cache for kernel stacks. */ |
/* Cache for kernel stacks. */ |
62 |
static struct kmem_cache *stack_cache; |
static struct kmem_cache *stack_cache; |
63 |
|
|
64 |
|
/* Thread list. Contains all threads in the system. */ |
65 |
|
static struct queue_entry thread_list = queue_ctor (thread_list); |
66 |
|
static spin_lock_t thread_list_lock; |
67 |
|
|
68 |
|
|
69 |
/* Wait semantics. |
/* Wait semantics. |
70 |
|
|
111 |
reaper_continuation (void) |
reaper_continuation (void) |
112 |
{ |
{ |
113 |
/* ??? dead code right now. */ |
/* ??? dead code right now. */ |
114 |
thread_sleep (0xdeadbeef, 0, reaper_continuation); |
thread_sleep ((int) &reaper_list, 0, reaper_continuation); |
115 |
} |
} |
116 |
|
|
117 |
/* Create a new thread in TASK. The thread is returned in THREADP. */ |
/* Create a new thread in TASK. The thread is returned in THREADP. */ |
121 |
{ |
{ |
122 |
struct thread *thread; |
struct thread *thread; |
123 |
kern_return_t kr; |
kern_return_t kr; |
124 |
|
SPL_T spl; |
125 |
|
|
126 |
thread = kmem_cache_alloc (thread_cache); |
thread = kmem_cache_alloc (thread_cache); |
127 |
if (! thread) |
if (! thread) |
162 |
if (kr != KERN_SUCCESS) |
if (kr != KERN_SUCCESS) |
163 |
return kr; |
return kr; |
164 |
|
|
165 |
|
/* Insert thread into thread list. */ |
166 |
|
|
167 |
|
spl = SPLOFF (); |
168 |
|
spin_lock (&thread_list_lock); |
169 |
|
queue_enter (&thread_list, thread, struct thread *, allq); |
170 |
|
spin_unlock (&thread_list_lock); |
171 |
|
SPLON (spl); |
172 |
|
|
173 |
|
trace_count (n_threads++); |
174 |
|
|
175 |
*threadp = thread; |
*threadp = thread; |
176 |
return KERN_SUCCESS; |
return KERN_SUCCESS; |
177 |
} |
} |
178 |
|
|
179 |
|
/* Terminate THREAD. */ |
180 |
|
|
181 |
|
kern_return_t |
182 |
|
thread_terminate (struct thread *thread) |
183 |
|
{ |
184 |
|
SPL_T spl; |
185 |
|
|
186 |
|
/* First check if we should zombify the current running thread. */ |
187 |
|
|
188 |
|
if (THREAD_CURRENT () == thread) |
189 |
|
thread_zombify_running (THREAD_CURRENT ()); |
190 |
|
|
191 |
|
spl = SPLOFF (); |
192 |
|
thread_lock (thread); |
193 |
|
|
194 |
|
#if 0 /* NCPUS > 1 */ |
195 |
|
/* Check if thread is running on some other processor. If it does, |
196 |
|
we send a interprocessor interrupt to that processor. */ |
197 |
|
|
198 |
|
if (thread->running_p) |
199 |
|
{ |
200 |
|
processor_send_terminate_ipi (thread->last_processor, thread); |
201 |
|
thread_sleep ((int) thread, &thread->lock, 0); |
202 |
|
|
203 |
|
SPLON (spl); |
204 |
|
return KERN_SUCCESS; |
205 |
|
} |
206 |
|
#endif |
207 |
|
|
208 |
|
/* Thread is not running on any processor -> it is either waiting or |
209 |
|
on some run queue. Remove thread from queue and kill it. */ |
210 |
|
|
211 |
|
if (thread->sched_state & THREAD_STATE_WAIT) |
212 |
|
{ |
213 |
|
int event; |
214 |
|
|
215 |
|
event = thread->wait_event; |
216 |
|
if (event) |
217 |
|
{ |
218 |
|
int hash_index = WAIT_HASH (event); |
219 |
|
|
220 |
|
thread_unlock (thread); |
221 |
|
spin_lock (&wait_locks [hash_index]); |
222 |
|
thread_lock (thread); |
223 |
|
|
224 |
|
if (thread->wait_event == event) |
225 |
|
{ |
226 |
|
queue_remove (&wait_queues [hash_index], thread, |
227 |
|
struct thread *, waitq); |
228 |
|
} |
229 |
|
|
230 |
|
thread_unlock (thread); |
231 |
|
spin_unlock (&wait_locks [hash_index]); |
232 |
|
thread_lock (thread); |
233 |
|
} |
234 |
|
} |
235 |
|
else /* on runq */ |
236 |
|
(*thread->sched_sp->ops->remove_fn) (thread->sched_sp, thread); |
237 |
|
|
238 |
|
/* Add thread to reaper daemon zombie list. Since we no longer will |
239 |
|
use the RUNQ chain in thread we use that as reaper chain link. */ |
240 |
|
|
241 |
|
thread_unlock (thread); |
242 |
|
spin_lock (&reaper_lock); |
243 |
|
thread_lock (thread); |
244 |
|
queue_enter (&reaper_list, thread, struct thread *, runq); |
245 |
|
thread_unlock (thread); |
246 |
|
spin_unlock (&reaper_lock); |
247 |
|
|
248 |
|
/* Wake up reaper daemon. */ |
249 |
|
|
250 |
|
thread_wakeup ((int) &reaper_list); |
251 |
|
|
252 |
|
SPLON (spl); |
253 |
|
return KERN_SUCCESS; |
254 |
|
} |
255 |
|
|
256 |
|
/* Halt running thread THREAD. This will signal to waiting threads that |
257 |
|
the thread have become a zombie. Will put thread on reaper queue. */ |
258 |
|
|
259 |
|
kern_return_t |
260 |
|
thread_zombify_running (struct thread *thread) |
261 |
|
{ |
262 |
|
SPL_T spl; |
263 |
|
|
264 |
|
spl = SPLOFF (); |
265 |
|
|
266 |
|
/* Set scheduling state to zombie state. */ |
267 |
|
|
268 |
|
thread_lock (thread); |
269 |
|
thread->sched_state |= THREAD_STATE_ZOMBIE; |
270 |
|
thread_unlock (thread); |
271 |
|
|
272 |
|
/* Add thread to reaper daemon zombie list. Since we no longer will |
273 |
|
use the RUNQ chain in thread we use that as reaper chain link. */ |
274 |
|
|
275 |
|
spin_lock (&reaper_lock); |
276 |
|
thread_lock (thread); |
277 |
|
queue_enter (&reaper_list, thread, struct thread *, runq); |
278 |
|
thread_unlock (thread); |
279 |
|
spin_unlock (&reaper_lock); |
280 |
|
|
281 |
|
/* Before waking up the reaper, we singal all threads waiting for this |
282 |
|
to finish. If we get preempted here, there's nothing to do, right? */ |
283 |
|
|
284 |
|
thread_wakeup ((int) thread); |
285 |
|
|
286 |
|
/* Wake up reaper daemon. */ |
287 |
|
|
288 |
|
thread_wakeup ((int) &reaper_list); |
289 |
|
|
290 |
|
/* Block here, we will never get any further. */ |
291 |
|
|
292 |
|
thread_block (0); |
293 |
|
panic ("??? after zombie state! should not be possible!"); |
294 |
|
|
295 |
|
return KERN_SUCCESS; |
296 |
|
} |
297 |
|
|
298 |
/* Return send right name to current thread. */ |
/* Return send right name to current thread. */ |
299 |
|
|
300 |
rtmk_port_t |
rtmk_port_t |
339 |
{ |
{ |
340 |
void (*continuation) () = THREAD_CURRENT()->swap_fn; |
void (*continuation) () = THREAD_CURRENT()->swap_fn; |
341 |
|
|
|
/* We must dispatch the old thread and then |
|
|
call the current thread's continuation. |
|
|
There might not be an old thread, if we are |
|
|
the first thread to run on this processor. */ |
|
|
|
|
|
#if 0 |
|
|
if (old_thread != 0) |
|
|
thread_dispatch (old_thread); |
|
|
#endif |
|
|
|
|
342 |
SPL0 (); |
SPL0 (); |
343 |
(*continuation) (); |
(*continuation) (); |
344 |
} |
} |
384 |
STACK_HANDOFF (old_thread, new_thread); |
STACK_HANDOFF (old_thread, new_thread); |
385 |
old_thread->sched_state |= THREAD_STATE_SWAPPED; |
old_thread->sched_state |= THREAD_STATE_SWAPPED; |
386 |
|
|
387 |
switch (old_thread->sched_state & ~THREAD_STATE_SWAPPED) |
if ((old_thread->sched_state & THREAD_SCHED_STATE) |
388 |
{ |
== THREAD_STATE_RUN) |
389 |
case THREAD_STATE_RUN: |
thread_setrun (old_thread, false); |
|
thread_setrun (old_thread, false); |
|
|
break; |
|
|
} |
|
390 |
} |
} |
391 |
else |
else |
392 |
{ |
{ |
393 |
switch (old_thread->sched_state & ~THREAD_STATE_SWAPPED) |
if ((old_thread->sched_state & THREAD_SCHED_STATE) |
394 |
{ |
== THREAD_STATE_RUN) |
395 |
case THREAD_STATE_RUN: |
thread_setrun (old_thread, false); |
|
thread_setrun (old_thread, false); |
|
|
break; |
|
|
} |
|
396 |
} |
} |
397 |
} |
} |
398 |
|
|
406 |
new_thread->sched_state &= ~THREAD_STATE_SWAPPED; |
new_thread->sched_state &= ~THREAD_STATE_SWAPPED; |
407 |
} |
} |
408 |
|
|
409 |
switch (old_thread->sched_state & ~THREAD_STATE_SWAPPED) |
if ((old_thread->sched_state & THREAD_SCHED_STATE) |
410 |
{ |
== THREAD_STATE_RUN) |
411 |
case THREAD_STATE_RUN: |
thread_setrun (old_thread, false); |
|
thread_setrun (old_thread, false); |
|
|
break; |
|
|
} |
|
412 |
} |
} |
413 |
|
|
414 |
trace_count (context_switches++); |
trace_count (context_switches++); |
670 |
|
|
671 |
spl = SPLOFF (); |
spl = SPLOFF (); |
672 |
|
|
673 |
while (! thread_invoke (thread, continuation, new_thread)); |
while (! thread_invoke (thread, continuation, new_thread)) |
674 |
new_thread = thread_select (PROCESSOR_CURRENT ()); |
new_thread = thread_select (PROCESSOR_CURRENT ()); |
675 |
|
|
676 |
SPLON (spl); |
SPLON (spl); |
884 |
processor = thread->last_processor; |
processor = thread->last_processor; |
885 |
if (processor) |
if (processor) |
886 |
{ |
{ |
887 |
|
/* If the last processor is the current one, check if we can preempt it. */ |
888 |
|
|
889 |
|
if (processor == PROCESSOR_CURRENT ()) |
890 |
|
{ |
891 |
|
if ((processor->state == PROCESSOR_STATE_RUNNING |
892 |
|
&& thread->sched_premul > processor->current_thread->sched_premul) |
893 |
|
|| processor->state == PROCESSOR_STATE_IDLE) |
894 |
|
{ |
895 |
|
trace_count (cpu_switch_hits++); |
896 |
|
thread_go (thread, 0); |
897 |
|
return; |
898 |
|
} |
899 |
|
} |
900 |
|
|
901 |
if (processor->state == PROCESSOR_STATE_IDLE) |
if (processor->state == PROCESSOR_STATE_IDLE) |
902 |
{ |
{ |
903 |
processor->state = PROCESSOR_STATE_DISPATCH; |
processor->state = PROCESSOR_STATE_DISPATCH; |
904 |
processor_send_dispatch_ipi (processor, thread); |
processor_send_dispatch_ipi (processor, thread); |
905 |
|
trace_count (cpu_switch_hits++); |
906 |
return; |
return; |
907 |
} |
} |
908 |
else if (processor->state == PROCESSOR_STATE_RUNNING && |
else if (processor->state == PROCESSOR_STATE_RUNNING && |
909 |
thread->sched_premul > processor->current_thread->sched_premul) |
thread->sched_premul > processor->current_thread->sched_premul) |
910 |
{ |
{ |
911 |
|
trace_printf ("last cpu %d current prio %x, new prio %x", |
912 |
|
processor->cpu_id, processor->current_thread->sched_premul, |
913 |
|
thread->sched_premul); |
914 |
|
|
915 |
processor->state = PROCESSOR_STATE_DISPATCH; |
processor->state = PROCESSOR_STATE_DISPATCH; |
916 |
processor_send_dispatch_ipi (processor, thread); |
processor_send_dispatch_ipi (processor, thread); |
917 |
|
trace_count (cpu_switch_hits++); |
918 |
|
return; |
919 |
} |
} |
920 |
} |
} |
921 |
|
|
937 |
{ |
{ |
938 |
processor->state = PROCESSOR_STATE_DISPATCH; |
processor->state = PROCESSOR_STATE_DISPATCH; |
939 |
processor_send_dispatch_ipi (processor, thread); |
processor_send_dispatch_ipi (processor, thread); |
940 |
|
return; |
941 |
|
} |
942 |
|
#if 0 |
943 |
|
else if (processor->state == PROCESSOR_STATE_RUNNING) |
944 |
|
{ |
945 |
|
trace_printf ("cpu %d current prio %x, new prio %x", |
946 |
|
i, processor->current_thread->sched_premul, |
947 |
|
thread->sched_premul); |
948 |
} |
} |
949 |
|
#endif |
950 |
} |
} |
951 |
#endif |
#endif |
952 |
|
|