Rev 3022 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3022 | Rev 4055 | ||
---|---|---|---|
Line 65... | Line 65... | ||
65 | #include <mm/slab.h> |
65 | #include <mm/slab.h> |
66 | #include <debug.h> |
66 | #include <debug.h> |
67 | #include <main/uinit.h> |
67 | #include <main/uinit.h> |
68 | #include <syscall/copy.h> |
68 | #include <syscall/copy.h> |
69 | #include <errno.h> |
69 | #include <errno.h> |
- | 70 | ||
- | 71 | ||
70 | #include <console/klog.h> |
72 | #ifndef LOADED_PROG_STACK_PAGES_NO |
- | 73 | #define LOADED_PROG_STACK_PAGES_NO 1 |
|
- | 74 | #endif |
|
71 | 75 | ||
72 | 76 | ||
73 | /** Thread states */ |
77 | /** Thread states */ |
74 | char *thread_states[] = { |
78 | char *thread_states[] = { |
75 | "Invalid", |
79 | "Invalid", |
Line 96... | Line 100... | ||
96 | 100 | ||
97 | SPINLOCK_INITIALIZE(tidlock); |
101 | SPINLOCK_INITIALIZE(tidlock); |
98 | thread_id_t last_tid = 0; |
102 | thread_id_t last_tid = 0; |
99 | 103 | ||
100 | static slab_cache_t *thread_slab; |
104 | static slab_cache_t *thread_slab; |
101 | #ifdef ARCH_HAS_FPU |
105 | #ifdef CONFIG_FPU |
102 | slab_cache_t *fpu_context_slab; |
106 | slab_cache_t *fpu_context_slab; |
103 | #endif |
107 | #endif |
104 | 108 | ||
105 | /** Thread wrapper. |
109 | /** Thread wrapper. |
106 | * |
110 | * |
Line 155... | Line 159... | ||
155 | link_initialize(&t->th_link); |
159 | link_initialize(&t->th_link); |
156 | 160 | ||
157 | /* call the architecture-specific part of the constructor */ |
161 | /* call the architecture-specific part of the constructor */ |
158 | thr_constructor_arch(t); |
162 | thr_constructor_arch(t); |
159 | 163 | ||
160 | #ifdef ARCH_HAS_FPU |
164 | #ifdef CONFIG_FPU |
161 | #ifdef CONFIG_FPU_LAZY |
165 | #ifdef CONFIG_FPU_LAZY |
162 | t->saved_fpu_context = NULL; |
166 | t->saved_fpu_context = NULL; |
163 | #else |
167 | #else |
164 | t->saved_fpu_context = slab_alloc(fpu_context_slab, kmflags); |
168 | t->saved_fpu_context = slab_alloc(fpu_context_slab, kmflags); |
165 | if (!t->saved_fpu_context) |
169 | if (!t->saved_fpu_context) |
166 | return -1; |
170 | return -1; |
167 | #endif |
171 | #endif |
168 | #endif |
172 | #endif |
169 | 173 | ||
170 | t->kstack = (uint8_t *) frame_alloc(STACK_FRAMES, FRAME_KA | kmflags); |
174 | t->kstack = (uint8_t *) frame_alloc(STACK_FRAMES, FRAME_KA | kmflags); |
171 | if (!t->kstack) { |
175 | if (!t->kstack) { |
172 | #ifdef ARCH_HAS_FPU |
176 | #ifdef CONFIG_FPU |
173 | if (t->saved_fpu_context) |
177 | if (t->saved_fpu_context) |
174 | slab_free(fpu_context_slab, t->saved_fpu_context); |
178 | slab_free(fpu_context_slab, t->saved_fpu_context); |
175 | #endif |
179 | #endif |
176 | return -1; |
180 | return -1; |
177 | } |
181 | } |
178 | 182 | ||
- | 183 | #ifdef CONFIG_UDEBUG |
|
- | 184 | mutex_initialize(&t->udebug.lock, MUTEX_PASSIVE); |
|
- | 185 | #endif |
|
- | 186 | ||
179 | return 0; |
187 | return 0; |
180 | } |
188 | } |
181 | 189 | ||
182 | /** Destruction of thread_t object */ |
190 | /** Destruction of thread_t object */ |
183 | static int thr_destructor(void *obj) |
191 | static int thr_destructor(void *obj) |
Line 186... | Line 194... | ||
186 | 194 | ||
187 | /* call the architecture-specific part of the destructor */ |
195 | /* call the architecture-specific part of the destructor */ |
188 | thr_destructor_arch(t); |
196 | thr_destructor_arch(t); |
189 | 197 | ||
190 | frame_free(KA2PA(t->kstack)); |
198 | frame_free(KA2PA(t->kstack)); |
191 | #ifdef ARCH_HAS_FPU |
199 | #ifdef CONFIG_FPU |
192 | if (t->saved_fpu_context) |
200 | if (t->saved_fpu_context) |
193 | slab_free(fpu_context_slab, t->saved_fpu_context); |
201 | slab_free(fpu_context_slab, t->saved_fpu_context); |
194 | #endif |
202 | #endif |
195 | return 1; /* One page freed */ |
203 | return 1; /* One page freed */ |
196 | } |
204 | } |
Line 201... | Line 209... | ||
201 | * |
209 | * |
202 | */ |
210 | */ |
203 | void thread_init(void) |
211 | void thread_init(void) |
204 | { |
212 | { |
205 | THREAD = NULL; |
213 | THREAD = NULL; |
206 | atomic_set(&nrdy,0); |
214 | atomic_set(&nrdy, 0); |
207 | thread_slab = slab_cache_create("thread_slab", sizeof(thread_t), 0, |
215 | thread_slab = slab_cache_create("thread_slab", sizeof(thread_t), 0, |
208 | thr_constructor, thr_destructor, 0); |
216 | thr_constructor, thr_destructor, 0); |
209 | 217 | ||
210 | #ifdef ARCH_HAS_FPU |
218 | #ifdef CONFIG_FPU |
211 | fpu_context_slab = slab_cache_create("fpu_slab", sizeof(fpu_context_t), |
219 | fpu_context_slab = slab_cache_create("fpu_slab", sizeof(fpu_context_t), |
212 | FPU_CONTEXT_ALIGN, NULL, NULL, 0); |
220 | FPU_CONTEXT_ALIGN, NULL, NULL, 0); |
213 | #endif |
221 | #endif |
214 | 222 | ||
215 | avltree_create(&threads_tree); |
223 | avltree_create(&threads_tree); |
Line 269... | Line 277... | ||
269 | * @param arg Thread's implementing function argument. |
277 | * @param arg Thread's implementing function argument. |
270 | * @param task Task to which the thread belongs. The caller must |
278 | * @param task Task to which the thread belongs. The caller must |
271 | * guarantee that the task won't cease to exist during the |
279 | * guarantee that the task won't cease to exist during the |
272 | * call. The task's lock may not be held. |
280 | * call. The task's lock may not be held. |
273 | * @param flags Thread flags. |
281 | * @param flags Thread flags. |
274 | * @param name Symbolic name. |
282 | * @param name Symbolic name (a copy is made). |
275 | * @param uncounted Thread's accounting doesn't affect accumulated task |
283 | * @param uncounted Thread's accounting doesn't affect accumulated task |
276 | * accounting. |
284 | * accounting. |
277 | * |
285 | * |
278 | * @return New thread's structure on success, NULL on failure. |
286 | * @return New thread's structure on success, NULL on failure. |
279 | * |
287 | * |
Line 287... | Line 295... | ||
287 | t = (thread_t *) slab_alloc(thread_slab, 0); |
295 | t = (thread_t *) slab_alloc(thread_slab, 0); |
288 | if (!t) |
296 | if (!t) |
289 | return NULL; |
297 | return NULL; |
290 | 298 | ||
291 | /* Not needed, but good for debugging */ |
299 | /* Not needed, but good for debugging */ |
292 | memsetb((uintptr_t) t->kstack, THREAD_STACK_SIZE * 1 << STACK_FRAMES, |
300 | memsetb(t->kstack, THREAD_STACK_SIZE * 1 << STACK_FRAMES, 0); |
293 | 0); |
- | |
294 | 301 | ||
295 | ipl = interrupts_disable(); |
302 | ipl = interrupts_disable(); |
296 | spinlock_lock(&tidlock); |
303 | spinlock_lock(&tidlock); |
297 | t->tid = ++last_tid; |
304 | t->tid = ++last_tid; |
298 | spinlock_unlock(&tidlock); |
305 | spinlock_unlock(&tidlock); |
Line 307... | Line 314... | ||
307 | ipl = interrupts_disable(); |
314 | ipl = interrupts_disable(); |
308 | t->saved_context.ipl = interrupts_read(); |
315 | t->saved_context.ipl = interrupts_read(); |
309 | interrupts_restore(ipl); |
316 | interrupts_restore(ipl); |
310 | 317 | ||
311 | memcpy(t->name, name, THREAD_NAME_BUFLEN); |
318 | memcpy(t->name, name, THREAD_NAME_BUFLEN); |
- | 319 | t->name[THREAD_NAME_BUFLEN - 1] = '\0'; |
|
312 | 320 | ||
313 | t->thread_code = func; |
321 | t->thread_code = func; |
314 | t->thread_arg = arg; |
322 | t->thread_arg = arg; |
315 | t->ticks = -1; |
323 | t->ticks = -1; |
316 | t->cycles = 0; |
324 | t->cycles = 0; |
Line 342... | Line 350... | ||
342 | t->fpu_context_engaged = 0; |
350 | t->fpu_context_engaged = 0; |
343 | 351 | ||
344 | avltree_node_initialize(&t->threads_tree_node); |
352 | avltree_node_initialize(&t->threads_tree_node); |
345 | t->threads_tree_node.key = (uintptr_t) t; |
353 | t->threads_tree_node.key = (uintptr_t) t; |
346 | 354 | ||
- | 355 | #ifdef CONFIG_UDEBUG |
|
- | 356 | /* Init debugging stuff */ |
|
- | 357 | udebug_thread_initialize(&t->udebug); |
|
- | 358 | #endif |
|
- | 359 | ||
347 | /* might depend on previous initialization */ |
360 | /* might depend on previous initialization */ |
348 | thread_create_arch(t); |
361 | thread_create_arch(t); |
349 | 362 | ||
350 | if (!(flags & THREAD_FLAG_NOATTACH)) |
363 | if (!(flags & THREAD_FLAG_NOATTACH)) |
351 | thread_attach(t, task); |
364 | thread_attach(t, task); |
Line 404... | Line 417... | ||
404 | void thread_attach(thread_t *t, task_t *task) |
417 | void thread_attach(thread_t *t, task_t *task) |
405 | { |
418 | { |
406 | ipl_t ipl; |
419 | ipl_t ipl; |
407 | 420 | ||
408 | /* |
421 | /* |
409 | * Attach to the current task. |
422 | * Attach to the specified task. |
410 | */ |
423 | */ |
411 | ipl = interrupts_disable(); |
424 | ipl = interrupts_disable(); |
412 | spinlock_lock(&task->lock); |
425 | spinlock_lock(&task->lock); |
- | 426 | ||
413 | atomic_inc(&task->refcount); |
427 | atomic_inc(&task->refcount); |
- | 428 | ||
- | 429 | /* Must not count kbox thread into lifecount */ |
|
- | 430 | if (t->flags & THREAD_FLAG_USPACE) |
|
414 | atomic_inc(&task->lifecount); |
431 | atomic_inc(&task->lifecount); |
- | 432 | ||
415 | list_append(&t->th_link, &task->th_head); |
433 | list_append(&t->th_link, &task->th_head); |
416 | spinlock_unlock(&task->lock); |
434 | spinlock_unlock(&task->lock); |
417 | 435 | ||
418 | /* |
436 | /* |
419 | * Register this thread in the system-wide list. |
437 | * Register this thread in the system-wide list. |
Line 432... | Line 450... | ||
432 | */ |
450 | */ |
433 | void thread_exit(void) |
451 | void thread_exit(void) |
434 | { |
452 | { |
435 | ipl_t ipl; |
453 | ipl_t ipl; |
436 | 454 | ||
- | 455 | if (THREAD->flags & THREAD_FLAG_USPACE) { |
|
- | 456 | #ifdef CONFIG_UDEBUG |
|
- | 457 | /* Generate udebug THREAD_E event */ |
|
- | 458 | udebug_thread_e_event(); |
|
- | 459 | #endif |
|
437 | if (atomic_predec(&TASK->lifecount) == 0) { |
460 | if (atomic_predec(&TASK->lifecount) == 0) { |
438 | /* |
461 | /* |
439 | * We are the last thread in the task that still has not exited. |
462 | * We are the last userspace thread in the task that |
- | 463 | * still has not exited. With the exception of the |
|
440 | * With the exception of the moment the task was created, new |
464 | * moment the task was created, new userspace threads |
441 | * threads can only be created by threads of the same task. |
465 | * can only be created by threads of the same task. |
442 | * We are safe to perform cleanup. |
466 | * We are safe to perform cleanup. |
443 | */ |
467 | */ |
444 | if (THREAD->flags & THREAD_FLAG_USPACE) { |
- | |
445 | ipc_cleanup(); |
468 | ipc_cleanup(); |
446 | futex_cleanup(); |
469 | futex_cleanup(); |
447 | klog_printf("Cleanup of task %llu completed.", |
470 | LOG("Cleanup of task %" PRIu64" completed.", TASK->taskid); |
448 | TASK->taskid); |
- | |
449 | } |
471 | } |
450 | } |
472 | } |
451 | 473 | ||
452 | restart: |
474 | restart: |
453 | ipl = interrupts_disable(); |
475 | ipl = interrupts_disable(); |
Line 579... | Line 601... | ||
579 | interrupts_restore(ipl); |
601 | interrupts_restore(ipl); |
580 | } |
602 | } |
581 | 603 | ||
582 | static bool thread_walker(avltree_node_t *node, void *arg) |
604 | static bool thread_walker(avltree_node_t *node, void *arg) |
583 | { |
605 | { |
584 | thread_t *t; |
- | |
585 | - | ||
586 | t = avltree_get_instance(node, thread_t, threads_tree_node); |
606 | thread_t *t = avltree_get_instance(node, thread_t, threads_tree_node); |
587 | 607 | ||
588 | uint64_t cycles; |
608 | uint64_t cycles; |
589 | char suffix; |
609 | char suffix; |
590 | order(t->cycles, &cycles, &suffix); |
610 | order(t->cycles, &cycles, &suffix); |
591 | 611 | ||
592 | if (sizeof(void *) == 4) |
612 | #ifdef __32_BITS__ |
593 | printf("%-6llu %-10s %#10zx %-8s %#10zx %-3ld %#10zx %#10zx %9llu%c ", |
613 | printf("%-6" PRIu64" %-10s %10p %-8s %10p %-3" PRIu32 " %10p %10p %9" PRIu64 "%c ", |
594 | t->tid, t->name, t, thread_states[t->state], t->task, |
614 | t->tid, t->name, t, thread_states[t->state], t->task, |
595 | t->task->context, t->thread_code, t->kstack, cycles, suffix); |
615 | t->task->context, t->thread_code, t->kstack, cycles, suffix); |
596 | else |
616 | #endif |
- | 617 | ||
- | 618 | #ifdef __64_BITS__ |
|
597 | printf("%-6llu %-10s %#18zx %-8s %#18zx %-3ld %#18zx %#18zx %9llu%c ", |
619 | printf("%-6" PRIu64" %-10s %18p %-8s %18p %-3" PRIu32 " %18p %18p %9" PRIu64 "%c ", |
598 | t->tid, t->name, t, thread_states[t->state], t->task, |
620 | t->tid, t->name, t, thread_states[t->state], t->task, |
599 | t->task->context, t->thread_code, t->kstack, cycles, suffix); |
621 | t->task->context, t->thread_code, t->kstack, cycles, suffix); |
- | 622 | #endif |
|
600 | 623 | ||
601 | if (t->cpu) |
624 | if (t->cpu) |
602 | printf("%-4zd", t->cpu->id); |
625 | printf("%-4u", t->cpu->id); |
603 | else |
626 | else |
604 | printf("none"); |
627 | printf("none"); |
605 | 628 | ||
606 | if (t->state == Sleeping) { |
629 | if (t->state == Sleeping) { |
607 | if (sizeof(uintptr_t) == 4) |
630 | #ifdef __32_BITS__ |
608 | printf(" %#10zx", t->sleep_queue); |
631 | printf(" %10p", t->sleep_queue); |
609 | else |
632 | #endif |
- | 633 | ||
- | 634 | #ifdef __64_BITS__ |
|
610 | printf(" %#18zx", t->sleep_queue); |
635 | printf(" %18p", t->sleep_queue); |
- | 636 | #endif |
|
611 | } |
637 | } |
612 | 638 | ||
613 | printf("\n"); |
639 | printf("\n"); |
614 | 640 | ||
615 | return true; |
641 | return true; |
Line 621... | Line 647... | ||
621 | ipl_t ipl; |
647 | ipl_t ipl; |
622 | 648 | ||
623 | /* Messing with thread structures, avoid deadlock */ |
649 | /* Messing with thread structures, avoid deadlock */ |
624 | ipl = interrupts_disable(); |
650 | ipl = interrupts_disable(); |
625 | spinlock_lock(&threads_lock); |
651 | spinlock_lock(&threads_lock); |
626 | 652 | ||
627 | if (sizeof(uintptr_t) == 4) { |
653 | #ifdef __32_BITS__ |
628 | printf("tid name address state task " |
654 | printf("tid name address state task " |
629 | "ctx code stack cycles cpu " |
655 | "ctx code stack cycles cpu " |
630 | "waitqueue\n"); |
656 | "waitqueue\n"); |
631 | printf("------ ---------- ---------- -------- ---------- " |
657 | printf("------ ---------- ---------- -------- ---------- " |
632 | "--- ---------- ---------- ---------- ---- " |
658 | "--- ---------- ---------- ---------- ---- " |
633 | "----------\n"); |
659 | "----------\n"); |
634 | } else { |
660 | #endif |
- | 661 | ||
- | 662 | #ifdef __64_BITS__ |
|
635 | printf("tid name address state task " |
663 | printf("tid name address state task " |
636 | "ctx code stack cycles cpu " |
664 | "ctx code stack cycles cpu " |
637 | "waitqueue\n"); |
665 | "waitqueue\n"); |
638 | printf("------ ---------- ------------------ -------- ------------------ " |
666 | printf("------ ---------- ------------------ -------- ------------------ " |
639 | "--- ------------------ ------------------ ---------- ---- " |
667 | "--- ------------------ ------------------ ---------- ---- " |
640 | "------------------\n"); |
668 | "------------------\n"); |
641 | } |
669 | #endif |
642 | 670 | ||
643 | avltree_walk(&threads_tree, thread_walker, NULL); |
671 | avltree_walk(&threads_tree, thread_walker, NULL); |
644 | 672 | ||
645 | spinlock_unlock(&threads_lock); |
673 | spinlock_unlock(&threads_lock); |
646 | interrupts_restore(ipl); |
674 | interrupts_restore(ipl); |
Line 662... | Line 690... | ||
662 | node = avltree_search(&threads_tree, (avltree_key_t) ((uintptr_t) t)); |
690 | node = avltree_search(&threads_tree, (avltree_key_t) ((uintptr_t) t)); |
663 | 691 | ||
664 | return node != NULL; |
692 | return node != NULL; |
665 | } |
693 | } |
666 | 694 | ||
667 | - | ||
668 | /** Update accounting of current thread. |
695 | /** Update accounting of current thread. |
669 | * |
696 | * |
670 | * Note that thread_lock on THREAD must be already held and |
697 | * Note that thread_lock on THREAD must be already held and |
671 | * interrupts must be already disabled. |
698 | * interrupts must be already disabled. |
672 | * |
699 | * |
Line 680... | Line 707... | ||
680 | 707 | ||
681 | /** Process syscall to create new thread. |
708 | /** Process syscall to create new thread. |
682 | * |
709 | * |
683 | */ |
710 | */ |
684 | unative_t sys_thread_create(uspace_arg_t *uspace_uarg, char *uspace_name, |
711 | unative_t sys_thread_create(uspace_arg_t *uspace_uarg, char *uspace_name, |
685 | thread_id_t *uspace_thread_id) |
712 | size_t name_len, thread_id_t *uspace_thread_id) |
686 | { |
713 | { |
687 | thread_t *t; |
714 | thread_t *t; |
688 | char namebuf[THREAD_NAME_BUFLEN]; |
715 | char namebuf[THREAD_NAME_BUFLEN]; |
689 | uspace_arg_t *kernel_uarg; |
716 | uspace_arg_t *kernel_uarg; |
690 | int rc; |
717 | int rc; |
691 | 718 | ||
- | 719 | if (name_len > THREAD_NAME_BUFLEN - 1) |
|
- | 720 | name_len = THREAD_NAME_BUFLEN - 1; |
|
- | 721 | ||
692 | rc = copy_from_uspace(namebuf, uspace_name, THREAD_NAME_BUFLEN); |
722 | rc = copy_from_uspace(namebuf, uspace_name, name_len); |
693 | if (rc != 0) |
723 | if (rc != 0) |
694 | return (unative_t) rc; |
724 | return (unative_t) rc; |
695 | 725 | ||
- | 726 | namebuf[name_len] = '\0'; |
|
- | 727 | ||
696 | /* |
728 | /* |
697 | * In case of failure, kernel_uarg will be deallocated in this function. |
729 | * In case of failure, kernel_uarg will be deallocated in this function. |
698 | * In case of success, kernel_uarg will be freed in uinit(). |
730 | * In case of success, kernel_uarg will be freed in uinit(). |
699 | */ |
731 | */ |
700 | kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0); |
732 | kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0); |
Line 729... | Line 761... | ||
729 | free(kernel_uarg); |
761 | free(kernel_uarg); |
730 | 762 | ||
731 | return (unative_t) rc; |
763 | return (unative_t) rc; |
732 | } |
764 | } |
733 | } |
765 | } |
- | 766 | #ifdef CONFIG_UDEBUG |
|
- | 767 | /* |
|
- | 768 | * Generate udebug THREAD_B event and attach the thread. |
|
- | 769 | * This must be done atomically (with the debug locks held), |
|
- | 770 | * otherwise we would either miss some thread or receive |
|
- | 771 | * THREAD_B events for threads that already existed |
|
- | 772 | * and could be detected with THREAD_READ before. |
|
- | 773 | */ |
|
- | 774 | udebug_thread_b_event_attach(t, TASK); |
|
- | 775 | #else |
|
734 | thread_attach(t, TASK); |
776 | thread_attach(t, TASK); |
- | 777 | #endif |
|
735 | thread_ready(t); |
778 | thread_ready(t); |
736 | 779 | ||
737 | return 0; |
780 | return 0; |
738 | } else |
781 | } else |
739 | free(kernel_uarg); |
782 | free(kernel_uarg); |