Rev 2071 | Rev 2089 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 2071 | Rev 2087 | ||
|---|---|---|---|
| Line 63... | Line 63... | ||
| 63 | /** Spinlock protecting the tasks_btree B+tree. */ |
63 | /** Spinlock protecting the tasks_btree B+tree. */ |
| 64 | SPINLOCK_INITIALIZE(tasks_lock); |
64 | SPINLOCK_INITIALIZE(tasks_lock); |
| 65 | 65 | ||
| 66 | /** B+tree of active tasks. |
66 | /** B+tree of active tasks. |
| 67 | * |
67 | * |
| 68 | * The task is guaranteed to exist after it was found in the tasks_btree as long as: |
68 | * The task is guaranteed to exist after it was found in the tasks_btree as |
| - | 69 | * long as: |
|
| 69 | * @li the tasks_lock is held, |
70 | * @li the tasks_lock is held, |
| 70 | * @li the task's lock is held when task's lock is acquired before releasing tasks_lock or |
71 | * @li the task's lock is held when task's lock is acquired before releasing |
| - | 72 | * tasks_lock or |
|
| 71 | * @li the task's refcount is greater than 0 |
73 | * @li the task's refcount is greater than 0 |
| 72 | * |
74 | * |
| 73 | */ |
75 | */ |
| 74 | btree_t tasks_btree; |
76 | btree_t tasks_btree; |
| 75 | 77 | ||
| Line 123... | Line 125... | ||
| 123 | ta->cycles = 0; |
125 | ta->cycles = 0; |
| 124 | 126 | ||
| 125 | ipc_answerbox_init(&ta->answerbox); |
127 | ipc_answerbox_init(&ta->answerbox); |
| 126 | for (i = 0; i < IPC_MAX_PHONES; i++) |
128 | for (i = 0; i < IPC_MAX_PHONES; i++) |
| 127 | ipc_phone_init(&ta->phones[i]); |
129 | ipc_phone_init(&ta->phones[i]); |
| 128 | if ((ipc_phone_0) && (context_check(ipc_phone_0->task->context, ta->context))) |
130 | if ((ipc_phone_0) && (context_check(ipc_phone_0->task->context, |
| - | 131 | ta->context))) |
|
| 129 | ipc_phone_connect(&ta->phones[0], ipc_phone_0); |
132 | ipc_phone_connect(&ta->phones[0], ipc_phone_0); |
| 130 | atomic_set(&ta->active_calls, 0); |
133 | atomic_set(&ta->active_calls, 0); |
| 131 | 134 | ||
| 132 | mutex_initialize(&ta->futexes_lock); |
135 | mutex_initialize(&ta->futexes_lock); |
| 133 | btree_create(&ta->futexes); |
136 | btree_create(&ta->futexes); |
| Line 200... | Line 203... | ||
| 200 | as_destroy(as); |
203 | as_destroy(as); |
| 201 | return NULL; |
204 | return NULL; |
| 202 | } |
205 | } |
| 203 | 206 | ||
| 204 | kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0); |
207 | kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0); |
| - | 208 | kernel_uarg->uspace_entry = |
|
| 205 | kernel_uarg->uspace_entry = (void *) ((elf_header_t *) program_addr)->e_entry; |
209 | (void *) ((elf_header_t *) program_addr)->e_entry; |
| 206 | kernel_uarg->uspace_stack = (void *) USTACK_ADDRESS; |
210 | kernel_uarg->uspace_stack = (void *) USTACK_ADDRESS; |
| 207 | kernel_uarg->uspace_thread_function = NULL; |
211 | kernel_uarg->uspace_thread_function = NULL; |
| 208 | kernel_uarg->uspace_thread_arg = NULL; |
212 | kernel_uarg->uspace_thread_arg = NULL; |
| 209 | kernel_uarg->uspace_uarg = NULL; |
213 | kernel_uarg->uspace_uarg = NULL; |
| 210 | 214 | ||
| Line 212... | Line 216... | ||
| 212 | ASSERT(task); |
216 | ASSERT(task); |
| 213 | 217 | ||
| 214 | /* |
218 | /* |
| 215 | * Create the data as_area. |
219 | * Create the data as_area. |
| 216 | */ |
220 | */ |
| 217 | a = as_area_create(as, AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE, |
221 | a = as_area_create(as, AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE, |
| 218 | LOADED_PROG_STACK_PAGES_NO*PAGE_SIZE, |
222 | LOADED_PROG_STACK_PAGES_NO * PAGE_SIZE, USTACK_ADDRESS, |
| 219 | USTACK_ADDRESS, AS_AREA_ATTR_NONE, &anon_backend, NULL); |
223 | AS_AREA_ATTR_NONE, &anon_backend, NULL); |
| 220 | 224 | ||
| 221 | /* |
225 | /* |
| 222 | * Create the main thread. |
226 | * Create the main thread. |
| 223 | */ |
227 | */ |
| 224 | t1 = thread_create(uinit, kernel_uarg, task, THREAD_FLAG_USPACE, "uinit", false); |
228 | t1 = thread_create(uinit, kernel_uarg, task, THREAD_FLAG_USPACE, |
| - | 229 | "uinit", false); |
|
| 225 | ASSERT(t1); |
230 | ASSERT(t1); |
| 226 | 231 | ||
| 227 | /* |
232 | /* |
| 228 | * Create killer thread for the new task. |
233 | * Create killer thread for the new task. |
| 229 | */ |
234 | */ |
| Line 236... | Line 241... | ||
| 236 | return task; |
241 | return task; |
| 237 | } |
242 | } |
| 238 | 243 | ||
| 239 | /** Syscall for reading task ID from userspace. |
244 | /** Syscall for reading task ID from userspace. |
| 240 | * |
245 | * |
| 241 | * @param uspace_task_id Userspace address of 8-byte buffer where to store current task ID. |
246 | * @param uspace_task_id Userspace address of 8-byte buffer where to store |
| - | 247 | * current task ID. |
|
| 242 | * |
248 | * |
| 243 | * @return 0 on success or an error code from @ref errno.h. |
249 | * @return 0 on success or an error code from @ref errno.h. |
| 244 | */ |
250 | */ |
| 245 | unative_t sys_task_get_id(task_id_t *uspace_task_id) |
251 | unative_t sys_task_get_id(task_id_t *uspace_task_id) |
| 246 | { |
252 | { |
| 247 | /* |
253 | /* |
| 248 | * No need to acquire lock on TASK because taskid |
254 | * No need to acquire lock on TASK because taskid |
| 249 | * remains constant for the lifespan of the task. |
255 | * remains constant for the lifespan of the task. |
| 250 | */ |
256 | */ |
| 251 | return (unative_t) copy_to_uspace(uspace_task_id, &TASK->taskid, sizeof(TASK->taskid)); |
257 | return (unative_t) copy_to_uspace(uspace_task_id, &TASK->taskid, |
| - | 258 | sizeof(TASK->taskid)); |
|
| 252 | } |
259 | } |
| 253 | 260 | ||
| 254 | /** Find task structure corresponding to task ID. |
261 | /** Find task structure corresponding to task ID. |
| 255 | * |
262 | * |
| 256 | * The tasks_lock must be already held by the caller of this function |
263 | * The tasks_lock must be already held by the caller of this function |
| Line 286... | Line 293... | ||
| 286 | thread_t *thr = list_get_instance(cur, thread_t, th_link); |
293 | thread_t *thr = list_get_instance(cur, thread_t, th_link); |
| 287 | 294 | ||
| 288 | spinlock_lock(&thr->lock); |
295 | spinlock_lock(&thr->lock); |
| 289 | /* Process only counted threads */ |
296 | /* Process only counted threads */ |
| 290 | if (!thr->uncounted) { |
297 | if (!thr->uncounted) { |
| - | 298 | if (thr == THREAD) { |
|
| 291 | if (thr == THREAD) /* Update accounting of current thread */ |
299 | /* Update accounting of current thread */ |
| 292 | thread_update_accounting(); |
300 | thread_update_accounting(); |
| - | 301 | } |
|
| 293 | ret += thr->cycles; |
302 | ret += thr->cycles; |
| 294 | } |
303 | } |
| 295 | spinlock_unlock(&thr->lock); |
304 | spinlock_unlock(&thr->lock); |
| 296 | } |
305 | } |
| 297 | 306 | ||
| Line 374... | Line 383... | ||
| 374 | 383 | ||
| 375 | /* Messing with thread structures, avoid deadlock */ |
384 | /* Messing with thread structures, avoid deadlock */ |
| 376 | ipl = interrupts_disable(); |
385 | ipl = interrupts_disable(); |
| 377 | spinlock_lock(&tasks_lock); |
386 | spinlock_lock(&tasks_lock); |
| 378 | 387 | ||
| 379 | printf("taskid name ctx address as cycles threads calls callee\n"); |
388 | printf("taskid name ctx address as cycles threads " |
| - | 389 | "calls callee\n"); |
|
| 380 | printf("------ ---------- --- ---------- ---------- ---------- ------- ------ ------>\n"); |
390 | printf("------ ---------- --- ---------- ---------- ---------- ------- " "------ ------>\n"); |
| 381 | 391 | ||
| 382 | for (cur = tasks_btree.leaf_head.next; cur != &tasks_btree.leaf_head; cur = cur->next) { |
392 | for (cur = tasks_btree.leaf_head.next; cur != &tasks_btree.leaf_head; |
| - | 393 | cur = cur->next) { |
|
| 383 | btree_node_t *node; |
394 | btree_node_t *node; |
| 384 | int i; |
395 | int i; |
| 385 | 396 | ||
| 386 | node = list_get_instance(cur, btree_node_t, leaf_link); |
397 | node = list_get_instance(cur, btree_node_t, leaf_link); |
| 387 | for (i = 0; i < node->keys; i++) { |
398 | for (i = 0; i < node->keys; i++) { |
| Line 394... | Line 405... | ||
| 394 | 405 | ||
| 395 | uint64_t cycles; |
406 | uint64_t cycles; |
| 396 | char suffix; |
407 | char suffix; |
| 397 | order(task_get_accounting(t), &cycles, &suffix); |
408 | order(task_get_accounting(t), &cycles, &suffix); |
| 398 | 409 | ||
| 399 | printf("%-6lld %-10s %-3ld %#10zx %#10zx %9llu%c %7zd %6zd", t->taskid, t->name, t->context, t, t->as, cycles, suffix, t->refcount, atomic_get(&t->active_calls)); |
410 | printf("%-6lld %-10s %-3ld %#10zx %#10zx %9llu%c %7zd " |
| - | 411 | "%6zd", t->taskid, t->name, t->context, t, t->as, |
|
| - | 412 | cycles, suffix, t->refcount, |
|
| - | 413 | atomic_get(&t->active_calls)); |
|
| 400 | for (j = 0; j < IPC_MAX_PHONES; j++) { |
414 | for (j = 0; j < IPC_MAX_PHONES; j++) { |
| 401 | if (t->phones[j].callee) |
415 | if (t->phones[j].callee) |
| - | 416 | printf(" %zd:%#zx", j, |
|
| 402 | printf(" %zd:%#zx", j, t->phones[j].callee); |
417 | t->phones[j].callee); |
| 403 | } |
418 | } |
| 404 | printf("\n"); |
419 | printf("\n"); |
| 405 | 420 | ||
| 406 | spinlock_unlock(&t->lock); |
421 | spinlock_unlock(&t->lock); |
| 407 | } |
422 | } |
| Line 463... | Line 478... | ||
| 463 | scheduler(); |
478 | scheduler(); |
| 464 | goto loop; |
479 | goto loop; |
| 465 | } |
480 | } |
| 466 | 481 | ||
| 467 | if (t != THREAD) { |
482 | if (t != THREAD) { |
| 468 | ASSERT(t != main_thread); /* uninit is joined and detached in ktaskgc */ |
483 | ASSERT(t != main_thread); /* uninit is joined and detached |
| - | 484 | * in ktaskgc */ |
|
| 469 | thread_join(t); |
485 | thread_join(t); |
| 470 | thread_detach(t); |
486 | thread_detach(t); |
| 471 | goto loop; /* go for another thread */ |
487 | goto loop; /* go for another thread */ |
| 472 | } |
488 | } |
| 473 | 489 | ||
| 474 | /* |
490 | /* |
| 475 | * Now there are no other threads in this task |
491 | * Now there are no other threads in this task |
| 476 | * and no new threads can be created. |
492 | * and no new threads can be created. |
| Line 495... | Line 511... | ||
| 495 | loop: |
511 | loop: |
| 496 | /* |
512 | /* |
| 497 | * Userspace threads cannot detach themselves, |
513 | * Userspace threads cannot detach themselves, |
| 498 | * therefore the thread pointer is guaranteed to be valid. |
514 | * therefore the thread pointer is guaranteed to be valid. |
| 499 | */ |
515 | */ |
| 500 | if (thread_join_timeout(t, 1000000, SYNCH_FLAGS_NONE) == ESYNCH_TIMEOUT) { /* sleep uninterruptibly here! */ |
516 | if (thread_join_timeout(t, 1000000, SYNCH_FLAGS_NONE) == |
| - | 517 | ESYNCH_TIMEOUT) { /* sleep uninterruptibly here! */ |
|
| 501 | ipl_t ipl; |
518 | ipl_t ipl; |
| 502 | link_t *cur; |
519 | link_t *cur; |
| 503 | thread_t *thr = NULL; |
520 | thread_t *thr = NULL; |
| 504 | 521 | ||
| 505 | /* |
522 | /* |
| 506 | * The join timed out. Try to do some garbage collection of Undead threads. |
523 | * The join timed out. Try to do some garbage collection of |
| - | 524 | * Undead threads. |
|
| 507 | */ |
525 | */ |
| 508 | more_gc: |
526 | more_gc: |
| 509 | ipl = interrupts_disable(); |
527 | ipl = interrupts_disable(); |
| 510 | spinlock_lock(&TASK->lock); |
528 | spinlock_lock(&TASK->lock); |
| 511 | 529 | ||
| 512 | for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) { |
530 | for (cur = TASK->th_head.next; cur != &TASK->th_head; |
| - | 531 | cur = cur->next) { |
|
| 513 | thr = list_get_instance(cur, thread_t, th_link); |
532 | thr = list_get_instance(cur, thread_t, th_link); |
| 514 | spinlock_lock(&thr->lock); |
533 | spinlock_lock(&thr->lock); |
| 515 | if (thr != t && thr->state == Undead && thr->join_type == None) { |
534 | if (thr != t && thr->state == Undead && |
| - | 535 | thr->join_type == None) { |
|
| 516 | thr->join_type = TaskGC; |
536 | thr->join_type = TaskGC; |
| 517 | spinlock_unlock(&thr->lock); |
537 | spinlock_unlock(&thr->lock); |
| 518 | break; |
538 | break; |
| 519 | } |
539 | } |
| 520 | spinlock_unlock(&thr->lock); |
540 | spinlock_unlock(&thr->lock); |