Rev 1636 | Rev 1676 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 1636 | Rev 1661 | ||
|---|---|---|---|
| Line 69... | Line 69... | ||
| 69 | btree_t tasks_btree; |
69 | btree_t tasks_btree; |
| 70 | 70 | ||
| 71 | static task_id_t task_counter = 0; |
71 | static task_id_t task_counter = 0; |
| 72 | 72 | ||
| 73 | static void ktaskclnp(void *arg); |
73 | static void ktaskclnp(void *arg); |
| 74 | static void ktaskkill(void *arg); |
74 | static void ktaskgc(void *arg); |
| 75 | 75 | ||
| 76 | /** Initialize tasks |
76 | /** Initialize tasks |
| 77 | * |
77 | * |
| 78 | * Initialize kernel tasks support. |
78 | * Initialize kernel tasks support. |
| 79 | * |
79 | * |
| Line 219... | Line 219... | ||
| 219 | ASSERT(t1); |
219 | ASSERT(t1); |
| 220 | 220 | ||
| 221 | /* |
221 | /* |
| 222 | * Create killer thread for the new task. |
222 | * Create killer thread for the new task. |
| 223 | */ |
223 | */ |
| 224 | t2 = thread_create(ktaskkill, t1, task, 0, "ktaskkill"); |
224 | t2 = thread_create(ktaskgc, t1, task, 0, "ktaskgc"); |
| 225 | ASSERT(t2); |
225 | ASSERT(t2); |
| 226 | thread_ready(t2); |
226 | thread_ready(t2); |
| 227 | 227 | ||
| 228 | thread_ready(t1); |
228 | thread_ready(t1); |
| 229 | 229 | ||
| Line 370... | Line 370... | ||
| 370 | void ktaskclnp(void *arg) |
370 | void ktaskclnp(void *arg) |
| 371 | { |
371 | { |
| 372 | ipl_t ipl; |
372 | ipl_t ipl; |
| 373 | thread_t *t = NULL, *main_thread; |
373 | thread_t *t = NULL, *main_thread; |
| 374 | link_t *cur; |
374 | link_t *cur; |
| - | 375 | bool again; |
|
| 375 | 376 | ||
| 376 | thread_detach(THREAD); |
377 | thread_detach(THREAD); |
| 377 | 378 | ||
| 378 | loop: |
379 | loop: |
| 379 | ipl = interrupts_disable(); |
380 | ipl = interrupts_disable(); |
| Line 382... | Line 383... | ||
| 382 | main_thread = TASK->main_thread; |
383 | main_thread = TASK->main_thread; |
| 383 | 384 | ||
| 384 | /* |
385 | /* |
| 385 | * Find a thread to join. |
386 | * Find a thread to join. |
| 386 | */ |
387 | */ |
| - | 388 | again = false; |
|
| 387 | for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) { |
389 | for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) { |
| 388 | t = list_get_instance(cur, thread_t, th_link); |
390 | t = list_get_instance(cur, thread_t, th_link); |
| - | 391 | ||
| - | 392 | spinlock_lock(&t->lock); |
|
| 389 | if (t == THREAD) |
393 | if (t == THREAD) { |
| - | 394 | spinlock_unlock(&t->lock); |
|
| - | 395 | continue; |
|
| - | 396 | } else if (t == main_thread) { |
|
| - | 397 | spinlock_unlock(&t->lock); |
|
| 390 | continue; |
398 | continue; |
| 391 | else if (t == main_thread) |
399 | } else if (t->join_type != None) { |
| - | 400 | spinlock_unlock(&t->lock); |
|
| - | 401 | again = true; |
|
| 392 | continue; |
402 | continue; |
| 393 | else |
403 | } else { |
| - | 404 | t->join_type = TaskClnp; |
|
| - | 405 | spinlock_unlock(&t->lock); |
|
| - | 406 | again = false; |
|
| 394 | break; |
407 | break; |
| - | 408 | } |
|
| 395 | } |
409 | } |
| 396 | 410 | ||
| 397 | spinlock_unlock(&TASK->lock); |
411 | spinlock_unlock(&TASK->lock); |
| 398 | interrupts_restore(ipl); |
412 | interrupts_restore(ipl); |
| 399 | 413 | ||
| - | 414 | if (again) { |
|
| - | 415 | /* |
|
| - | 416 | * Other cleanup (e.g. ktaskgc) is in progress. |
|
| - | 417 | */ |
|
| - | 418 | scheduler(); |
|
| - | 419 | goto loop; |
|
| - | 420 | } |
|
| - | 421 | ||
| 400 | if (t != THREAD) { |
422 | if (t != THREAD) { |
| 401 | ASSERT(t != main_thread); /* uninit is joined and detached in ktaskkill */ |
423 | ASSERT(t != main_thread); /* uninit is joined and detached in ktaskgc */ |
| 402 | thread_join(t); |
424 | thread_join(t); |
| 403 | thread_detach(t); |
425 | thread_detach(t); |
| 404 | goto loop; /* go for another thread */ |
426 | goto loop; /* go for another thread */ |
| 405 | } |
427 | } |
| 406 | 428 | ||
| Line 415... | Line 437... | ||
| 415 | } |
437 | } |
| 416 | 438 | ||
| 417 | /** Kernel task used to kill a userspace task when its main thread exits. |
439 | /** Kernel task used to kill a userspace task when its main thread exits. |
| 418 | * |
440 | * |
| 419 | * This thread waits until the main userspace thread (i.e. uninit) exits. |
441 | * This thread waits until the main userspace thread (i.e. uninit) exits. |
| 420 | * When this happens, the task is killed. |
442 | * When this happens, the task is killed. In the meantime, exited threads |
| - | 443 | * are garbage collected. |
|
| 421 | * |
444 | * |
| 422 | * @param arg Pointer to the thread structure of the task's main thread. |
445 | * @param arg Pointer to the thread structure of the task's main thread. |
| 423 | */ |
446 | */ |
| 424 | void ktaskkill(void *arg) |
447 | void ktaskgc(void *arg) |
| 425 | { |
448 | { |
| 426 | thread_t *t = (thread_t *) arg; |
449 | thread_t *t = (thread_t *) arg; |
| 427 | 450 | loop: |
|
| 428 | /* |
451 | /* |
| 429 | * Userspace threads cannot detach themselves, |
452 | * Userspace threads cannot detach themselves, |
| 430 | * therefore the thread pointer is guaranteed to be valid. |
453 | * therefore the thread pointer is guaranteed to be valid. |
| 431 | */ |
454 | */ |
| 432 | thread_join(t); /* sleep uninterruptibly here! */ |
455 | if (thread_join_timeout(t, 1000000, SYNCH_FLAGS_NONE) == ESYNCH_TIMEOUT) { /* sleep uninterruptibly here! */ |
| - | 456 | ipl_t ipl; |
|
| - | 457 | link_t *cur; |
|
| - | 458 | thread_t *thr = NULL; |
|
| - | 459 | ||
| - | 460 | /* |
|
| - | 461 | * The join timed out. Try to do some garbage collection of Undead threads. |
|
| - | 462 | */ |
|
| - | 463 | more_gc: |
|
| - | 464 | ipl = interrupts_disable(); |
|
| - | 465 | spinlock_lock(&TASK->lock); |
|
| - | 466 | ||
| - | 467 | for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) { |
|
| - | 468 | thr = list_get_instance(cur, thread_t, th_link); |
|
| - | 469 | spinlock_lock(&thr->lock); |
|
| - | 470 | if (thr->state == Undead && thr->join_type == None) { |
|
| - | 471 | thr->join_type = TaskGC; |
|
| - | 472 | spinlock_unlock(&thr->lock); |
|
| - | 473 | break; |
|
| - | 474 | } |
|
| - | 475 | spinlock_unlock(&thr->lock); |
|
| - | 476 | thr = NULL; |
|
| - | 477 | } |
|
| - | 478 | spinlock_unlock(&TASK->lock); |
|
| - | 479 | ||
| - | 480 | if (thr) { |
|
| - | 481 | thread_join(thr); |
|
| - | 482 | thread_detach(thr); |
|
| - | 483 | scheduler(); |
|
| - | 484 | goto more_gc; |
|
| - | 485 | } |
|
| - | 486 | ||
| - | 487 | goto loop; |
|
| - | 488 | } |
|
| 433 | thread_detach(t); |
489 | thread_detach(t); |
| 434 | task_kill(TASK->taskid); |
490 | task_kill(TASK->taskid); |
| 435 | } |
491 | } |