Changeset ea7890e7 in mainline
- Timestamp:
- 2007-06-01T15:47:46Z (18 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 07be3c4
- Parents:
- ff3a34b
- Location:
- kernel/generic
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/include/adt/list.h
rff3a34b rea7890e7 181 181 } 182 182 183 #define list_get_instance(link, type,member) \183 #define list_get_instance(link, type, member) \ 184 184 ((type *)(((uint8_t *)(link)) - ((uint8_t *)&(((type *)NULL)->member)))) 185 185 -
kernel/generic/include/proc/task.h
rff3a34b rea7890e7 65 65 66 66 char *name; 67 /** Pointer to the main thread. */68 struct thread *main_thread;69 67 /** List of threads contained in this task. */ 70 68 link_t th_head; … … 76 74 context_id_t context; 77 75 78 /** If this is true, new threads can become part of the task. */79 bool accept_new_threads;80 76 /** Number of references (i.e. threads). */ 81 count_t refcount; 77 atomic_t refcount; 78 /** Number of threads that haven't exited yet. */ 79 atomic_t lifecount; 82 80 83 81 /** Task capabilities. */ … … 123 121 extern cap_t cap_get(task_t *t); 124 122 125 126 123 #ifndef task_create_arch 127 124 extern void task_create_arch(task_t *t); -
kernel/generic/include/proc/thread.h
rff3a34b rea7890e7 1 1 /* 2 * Copyright (c) 2001-200 4Jakub Jermar2 * Copyright (c) 2001-2007 Jakub Jermar 3 3 * All rights reserved. 4 4 * … … 41 41 #include <cpu.h> 42 42 #include <synch/rwlock.h> 43 #include <synch/spinlock.h> 43 44 #include <adt/btree.h> 44 45 #include <mm/slab.h> … … 81 82 /** After a thread calls thread_exit(), it is put into Exiting state. */ 82 83 Exiting, 83 /** Threads that were not detached but exited are in the Undeadstate. */84 Undead84 /** Threads that were not detached but exited are in the JoinMe state. */ 85 JoinMe 85 86 } state_t; 86 87 /** Join types. */88 typedef enum {89 None,90 TaskClnp, /**< The thread will be joined by ktaskclnp thread. */91 TaskGC /**< The thread will be joined by ktaskgc thread. */92 } thread_join_type_t;93 87 94 88 /** Thread structure. There is one per thread. */ … … 153 147 bool interrupted; 154 148 155 /** Who joinins the thread. */156 thread_join_type_t join_type;157 149 /** If true, thread_join_timeout() cannot be used on this thread. */ 158 150 bool detached; 159 151 /** Waitq for thread_join_timeout(). */ 160 152 waitq_t join_wq; 153 /** Link used in the joiner_head list. */ 154 link_t joiner_link; 161 155 162 156 fpu_context_t *saved_fpu_context; -
kernel/generic/src/main/uinit.c
rff3a34b rea7890e7 46 46 #include <userspace.h> 47 47 #include <mm/slab.h> 48 #include <arch.h> 48 49 49 50 /** Thread used to bring up userspace thread. … … 55 56 { 56 57 uspace_arg_t uarg; 58 59 /* 60 * So far, we don't have a use for joining userspace threads so we 61 * immediately detach each uinit thread. If joining of userspace threads 62 * is required, some userspace API based on the kernel mechanism will 63 * have to be implemented. Moreover, garbage collecting of threads that 64 * didn't detach themselves and nobody else joined them will have to be 65 * deployed for the event of forceful task termination. 66 */ 67 thread_detach(THREAD); 57 68 58 69 uarg.uspace_entry = ((uspace_arg_t *) arg)->uspace_entry; 59 70 uarg.uspace_stack = ((uspace_arg_t *) arg)->uspace_stack; 60 71 uarg.uspace_uarg = ((uspace_arg_t *) arg)->uspace_uarg; 61 uarg.uspace_thread_function = NULL; 62 uarg.uspace_thread_arg = NULL; 72 uarg.uspace_thread_function = NULL; uarg.uspace_thread_arg = NULL; 63 73 64 74 free((uspace_arg_t *) arg); -
kernel/generic/src/proc/scheduler.c
rff3a34b rea7890e7 406 406 */ 407 407 spinlock_unlock(&THREAD->lock); 408 delay( 10);408 delay(HZ); 409 409 spinlock_lock(&THREAD->lock); 410 410 DEADLOCK_PROBE(p_joinwq, … … 416 416 spinlock_unlock(&THREAD->join_wq.lock); 417 417 418 THREAD->state = Undead;418 THREAD->state = JoinMe; 419 419 spinlock_unlock(&THREAD->lock); 420 420 } -
kernel/generic/src/proc/task.c
rff3a34b rea7890e7 57 57 #include <func.h> 58 58 #include <syscall/copy.h> 59 #include <console/klog.h>60 59 61 60 #ifndef LOADED_PROG_STACK_PAGES_NO … … 79 78 80 79 static task_id_t task_counter = 0; 81 82 static void ktaskclnp(void *arg);83 static void ktaskgc(void *arg);84 80 85 81 /** Initialize tasks … … 165 161 ta->as = as; 166 162 ta->name = name; 167 ta->main_thread = NULL;168 ta->refcount = 0;163 atomic_set(&ta->refcount, 0); 164 atomic_set(&ta->lifecount, 0); 169 165 ta->context = CONTEXT; 170 166 171 167 ta->capabilities = 0; 172 ta->accept_new_threads = true;173 168 ta->cycles = 0; 174 169 … … 192 187 193 188 spinlock_lock(&tasks_lock); 194 195 189 ta->taskid = ++task_counter; 196 190 btree_insert(&tasks_btree, (btree_key_t) ta->taskid, (void *) ta, NULL); 197 198 191 spinlock_unlock(&tasks_lock); 199 192 interrupts_restore(ipl); … … 208 201 void task_destroy(task_t *t) 209 202 { 203 /* 204 * Remove the task from the task B+tree. 205 */ 206 spinlock_lock(&tasks_lock); 207 btree_remove(&tasks_btree, t->taskid, NULL); 208 spinlock_unlock(&tasks_lock); 209 210 /* 211 * Perform architecture specific task destruction. 212 */ 210 213 task_destroy_arch(t); 214 215 /* 216 * Free up dynamically allocated state. 217 */ 211 218 btree_destroy(&t->futexes); 212 219 220 /* 221 * Drop our reference to the address space. 222 */ 213 223 if (atomic_predec(&t->as->refcount) == 0) 214 224 as_destroy(t->as); … … 230 240 as_area_t *a; 231 241 int rc; 232 thread_t *t 1, *t2;242 thread_t *t; 233 243 task_t *task; 234 244 uspace_arg_t *kernel_uarg; … … 264 274 * Create the main thread. 265 275 */ 266 t 1= thread_create(uinit, kernel_uarg, task, THREAD_FLAG_USPACE,276 t = thread_create(uinit, kernel_uarg, task, THREAD_FLAG_USPACE, 267 277 "uinit", false); 268 ASSERT(t1); 269 270 /* 271 * Create killer thread for the new task. 272 */ 273 t2 = thread_create(ktaskgc, t1, task, 0, "ktaskgc", true); 274 ASSERT(t2); 275 thread_ready(t2); 276 277 thread_ready(t1); 278 ASSERT(t); 279 280 thread_ready(t); 278 281 279 282 return task; … … 348 351 /** Kill task. 349 352 * 353 * This function is idempotent. 354 * It signals all the task's threads to bail it out. 355 * 350 356 * @param id ID of the task to be killed. 351 357 * … … 356 362 ipl_t ipl; 357 363 task_t *ta; 358 thread_t *t;359 364 link_t *cur; 360 365 … … 364 369 ipl = interrupts_disable(); 365 370 spinlock_lock(&tasks_lock); 366 367 371 if (!(ta = task_find_by_id(id))) { 368 372 spinlock_unlock(&tasks_lock); … … 370 374 return ENOENT; 371 375 } 372 376 spinlock_unlock(&tasks_lock); 377 378 /* 379 * Interrupt all threads except ktaskclnp. 380 */ 373 381 spinlock_lock(&ta->lock); 374 ta->refcount++;375 spinlock_unlock(&ta->lock);376 377 btree_remove(&tasks_btree, ta->taskid, NULL);378 spinlock_unlock(&tasks_lock);379 380 t = thread_create(ktaskclnp, NULL, ta, 0, "ktaskclnp", true);381 382 spinlock_lock(&ta->lock);383 ta->accept_new_threads = false;384 ta->refcount--;385 386 /*387 * Interrupt all threads except ktaskclnp.388 */389 382 for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { 390 383 thread_t *thr; 391 bool 384 bool sleeping = false; 392 385 393 386 thr = list_get_instance(cur, thread_t, th_link); 394 if (thr == t)395 continue;396 387 397 388 spinlock_lock(&thr->lock); … … 404 395 waitq_interrupt_sleep(thr); 405 396 } 406 407 397 spinlock_unlock(&ta->lock); 408 398 interrupts_restore(ipl); 409 399 410 if (t)411 thread_ready(t);412 413 400 return 0; 414 401 } … … 426 413 printf("taskid name ctx address as cycles threads " 427 414 "calls callee\n"); 428 printf("------ ---------- --- ---------- ---------- ---------- ------- " "------ ------>\n"); 415 printf("------ ---------- --- ---------- ---------- ---------- ------- " 416 "------ ------>\n"); 429 417 430 418 for (cur = tasks_btree.leaf_head.next; cur != &tasks_btree.leaf_head; … … 465 453 } 466 454 467 /** Kernel thread used to cleanup the task after it is killed. */468 void ktaskclnp(void *arg)469 {470 ipl_t ipl;471 thread_t *t = NULL, *main_thread;472 link_t *cur;473 bool again;474 475 thread_detach(THREAD);476 477 loop:478 ipl = interrupts_disable();479 spinlock_lock(&TASK->lock);480 481 main_thread = TASK->main_thread;482 483 /*484 * Find a thread to join.485 */486 again = false;487 for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {488 t = list_get_instance(cur, thread_t, th_link);489 490 spinlock_lock(&t->lock);491 if (t == THREAD) {492 spinlock_unlock(&t->lock);493 continue;494 } else if (t == main_thread) {495 spinlock_unlock(&t->lock);496 continue;497 } else if (t->join_type != None) {498 spinlock_unlock(&t->lock);499 again = true;500 continue;501 } else {502 t->join_type = TaskClnp;503 spinlock_unlock(&t->lock);504 again = false;505 break;506 }507 }508 509 spinlock_unlock(&TASK->lock);510 interrupts_restore(ipl);511 512 if (again) {513 /*514 * Other cleanup (e.g. ktaskgc) is in progress.515 */516 scheduler();517 goto loop;518 }519 520 if (t != THREAD) {521 ASSERT(t != main_thread); /* uninit is joined and detached522 * in ktaskgc */523 thread_join(t);524 thread_detach(t);525 goto loop; /* go for another thread */526 }527 528 /*529 * Now there are no other threads in this task530 * and no new threads can be created.531 */532 533 ipc_cleanup();534 futex_cleanup();535 klog_printf("Cleanup of task %llu completed.", TASK->taskid);536 }537 538 /** Kernel thread used to kill the userspace task when its main thread exits.539 *540 * This thread waits until the main userspace thread (i.e. uninit) exits.541 * When this happens, the task is killed. In the meantime, exited threads542 * are garbage collected.543 *544 * @param arg Pointer to the thread structure of the task's main thread.545 */546 void ktaskgc(void *arg)547 {548 thread_t *t = (thread_t *) arg;549 loop:550 /*551 * Userspace threads cannot detach themselves,552 * therefore the thread pointer is guaranteed to be valid.553 */554 if (thread_join_timeout(t, 1000000, SYNCH_FLAGS_NONE) ==555 ESYNCH_TIMEOUT) { /* sleep uninterruptibly here! */556 ipl_t ipl;557 link_t *cur;558 thread_t *thr = NULL;559 560 /*561 * The join timed out. Try to do some garbage collection of562 * Undead threads.563 */564 more_gc:565 ipl = interrupts_disable();566 spinlock_lock(&TASK->lock);567 568 for (cur = TASK->th_head.next; cur != &TASK->th_head;569 cur = cur->next) {570 thr = list_get_instance(cur, thread_t, th_link);571 spinlock_lock(&thr->lock);572 if (thr != t && thr->state == Undead &&573 thr->join_type == None) {574 thr->join_type = TaskGC;575 spinlock_unlock(&thr->lock);576 break;577 }578 spinlock_unlock(&thr->lock);579 thr = NULL;580 }581 spinlock_unlock(&TASK->lock);582 interrupts_restore(ipl);583 584 if (thr) {585 thread_join(thr);586 thread_detach(thr);587 scheduler();588 goto more_gc;589 }590 591 goto loop;592 }593 thread_detach(t);594 task_kill(TASK->taskid);595 }596 597 455 /** @} 598 456 */ -
kernel/generic/src/proc/thread.c
rff3a34b rea7890e7 68 68 #include <syscall/copy.h> 69 69 #include <errno.h> 70 #include <console/klog.h> 70 71 71 72 … … 78 79 "Entering", 79 80 "Exiting", 80 " Undead"81 "JoinMe" 81 82 }; 82 83 … … 329 330 330 331 t->interrupted = false; 331 t->join_type = None;332 332 t->detached = false; 333 333 waitq_initialize(&t->join_wq); … … 343 343 thread_create_arch(t); 344 344 345 ipl = interrupts_disable();346 spinlock_lock(&task->lock);347 if (!task->accept_new_threads) {348 spinlock_unlock(&task->lock);349 slab_free(thread_slab, t);350 interrupts_restore(ipl);351 return NULL;352 } else {353 /*354 * Bump the reference count so that this task cannot be355 * destroyed while the new thread is being attached to it.356 */357 task->refcount++;358 }359 spinlock_unlock(&task->lock);360 interrupts_restore(ipl);361 362 345 if (!(flags & THREAD_FLAG_NOATTACH)) 363 346 thread_attach(t, task); … … 374 357 void thread_destroy(thread_t *t) 375 358 { 376 bool destroy_task = false; 377 378 ASSERT(t->state == Exiting || t->state == Undead); 359 ASSERT(t->state == Exiting || t->state == JoinMe); 379 360 ASSERT(t->task); 380 361 ASSERT(t->cpu); … … 396 377 spinlock_lock(&t->task->lock); 397 378 list_remove(&t->th_link); 398 if (--t->task->refcount == 0) {399 t->task->accept_new_threads = false;400 destroy_task = true;401 }402 379 spinlock_unlock(&t->task->lock); 403 404 if (destroy_task) 380 381 /* 382 * t is guaranteed to be the very last thread of its task. 383 * It is safe to destroy the task. 384 */ 385 if (atomic_predec(&t->task->refcount) == 0) 405 386 task_destroy(t->task); 406 387 … … 432 413 * Attach to the current task. 433 414 */ 434 ipl = interrupts_disable(); 415 ipl = interrupts_disable(); 435 416 spinlock_lock(&task->lock); 436 ASSERT(task->refcount); 417 atomic_inc(&task->refcount); 418 atomic_inc(&task->lifecount); 437 419 list_append(&t->th_link, &task->th_head); 438 if (task->refcount == 1)439 task->main_thread = t;440 420 spinlock_unlock(&task->lock); 441 421 … … 459 439 { 460 440 ipl_t ipl; 441 442 if (atomic_predec(&TASK->lifecount) == 0) { 443 /* 444 * We are the last thread in the task that still has not exited. 445 * With the exception of the moment the task was created, new 446 * threads can only be created by threads of the same task. 447 * We are safe to perform cleanup. 448 */ 449 if (THREAD->flags & THREAD_FLAG_USPACE) { 450 ipc_cleanup(); 451 futex_cleanup(); 452 klog_printf("Cleanup of task %llu completed.", 453 TASK->taskid); 454 } 455 } 461 456 462 457 restart: … … 469 464 goto restart; 470 465 } 466 471 467 THREAD->state = Exiting; 472 468 spinlock_unlock(&THREAD->lock); … … 525 521 /** Detach thread. 526 522 * 527 * Mark the thread as detached, if the thread is already in the Undeadstate,523 * Mark the thread as detached, if the thread is already in the JoinMe state, 528 524 * deallocate its resources. 529 525 * … … 541 537 spinlock_lock(&t->lock); 542 538 ASSERT(!t->detached); 543 if (t->state == Undead) {539 if (t->state == JoinMe) { 544 540 thread_destroy(t); /* unlocks &t->lock */ 545 541 interrupts_restore(ipl); … … 703 699 sizeof(t->tid)); 704 700 if (rc != 0) { 705 ipl_t ipl;706 707 701 /* 708 702 * We have encountered a failure, but the thread … … 712 706 713 707 /* 714 * The new thread structure is initialized, 715 * butis still not visible to the system.708 * The new thread structure is initialized, but 709 * is still not visible to the system. 716 710 * We can safely deallocate it. 717 711 */ 718 712 slab_free(thread_slab, t); 719 713 free(kernel_uarg); 720 721 /*722 * Now we need to decrement the task reference723 * counter. Because we are running within the724 * same task, thread t is not the last thread725 * in the task, so it is safe to merely726 * decrement the counter.727 */728 ipl = interrupts_disable();729 spinlock_lock(&TASK->lock);730 TASK->refcount--;731 spinlock_unlock(&TASK->lock);732 interrupts_restore(ipl);733 714 734 715 return (unative_t) rc;
Note:
See TracChangeset
for help on using the changeset viewer.