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); |