Rev 3386 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3386 | Rev 4153 | ||
---|---|---|---|
Line 100... | Line 100... | ||
100 | 100 | ||
101 | SPINLOCK_INITIALIZE(tidlock); |
101 | SPINLOCK_INITIALIZE(tidlock); |
102 | thread_id_t last_tid = 0; |
102 | thread_id_t last_tid = 0; |
103 | 103 | ||
104 | static slab_cache_t *thread_slab; |
104 | static slab_cache_t *thread_slab; |
105 | #ifdef ARCH_HAS_FPU |
105 | #ifdef CONFIG_FPU |
106 | slab_cache_t *fpu_context_slab; |
106 | slab_cache_t *fpu_context_slab; |
107 | #endif |
107 | #endif |
108 | 108 | ||
109 | /** Thread wrapper. |
109 | /** Thread wrapper. |
110 | * |
110 | * |
Line 159... | Line 159... | ||
159 | link_initialize(&t->th_link); |
159 | link_initialize(&t->th_link); |
160 | 160 | ||
161 | /* call the architecture-specific part of the constructor */ |
161 | /* call the architecture-specific part of the constructor */ |
162 | thr_constructor_arch(t); |
162 | thr_constructor_arch(t); |
163 | 163 | ||
164 | #ifdef ARCH_HAS_FPU |
164 | #ifdef CONFIG_FPU |
165 | #ifdef CONFIG_FPU_LAZY |
165 | #ifdef CONFIG_FPU_LAZY |
166 | t->saved_fpu_context = NULL; |
166 | t->saved_fpu_context = NULL; |
167 | #else |
167 | #else |
168 | t->saved_fpu_context = slab_alloc(fpu_context_slab, kmflags); |
168 | t->saved_fpu_context = slab_alloc(fpu_context_slab, kmflags); |
169 | if (!t->saved_fpu_context) |
169 | if (!t->saved_fpu_context) |
170 | return -1; |
170 | return -1; |
171 | #endif |
171 | #endif |
172 | #endif |
172 | #endif |
173 | 173 | ||
174 | t->kstack = (uint8_t *) frame_alloc(STACK_FRAMES, FRAME_KA | kmflags); |
174 | t->kstack = (uint8_t *) frame_alloc(STACK_FRAMES, FRAME_KA | kmflags); |
175 | if (!t->kstack) { |
175 | if (!t->kstack) { |
176 | #ifdef ARCH_HAS_FPU |
176 | #ifdef CONFIG_FPU |
177 | if (t->saved_fpu_context) |
177 | if (t->saved_fpu_context) |
178 | slab_free(fpu_context_slab, t->saved_fpu_context); |
178 | slab_free(fpu_context_slab, t->saved_fpu_context); |
179 | #endif |
179 | #endif |
180 | return -1; |
180 | return -1; |
181 | } |
181 | } |
182 | 182 | ||
- | 183 | #ifdef CONFIG_UDEBUG |
|
- | 184 | mutex_initialize(&t->udebug.lock, MUTEX_PASSIVE); |
|
- | 185 | #endif |
|
- | 186 | ||
183 | return 0; |
187 | return 0; |
184 | } |
188 | } |
185 | 189 | ||
186 | /** Destruction of thread_t object */ |
190 | /** Destruction of thread_t object */ |
187 | static int thr_destructor(void *obj) |
191 | static int thr_destructor(void *obj) |
Line 190... | Line 194... | ||
190 | 194 | ||
191 | /* call the architecture-specific part of the destructor */ |
195 | /* call the architecture-specific part of the destructor */ |
192 | thr_destructor_arch(t); |
196 | thr_destructor_arch(t); |
193 | 197 | ||
194 | frame_free(KA2PA(t->kstack)); |
198 | frame_free(KA2PA(t->kstack)); |
195 | #ifdef ARCH_HAS_FPU |
199 | #ifdef CONFIG_FPU |
196 | if (t->saved_fpu_context) |
200 | if (t->saved_fpu_context) |
197 | slab_free(fpu_context_slab, t->saved_fpu_context); |
201 | slab_free(fpu_context_slab, t->saved_fpu_context); |
198 | #endif |
202 | #endif |
199 | return 1; /* One page freed */ |
203 | return 1; /* One page freed */ |
200 | } |
204 | } |
Line 205... | Line 209... | ||
205 | * |
209 | * |
206 | */ |
210 | */ |
207 | void thread_init(void) |
211 | void thread_init(void) |
208 | { |
212 | { |
209 | THREAD = NULL; |
213 | THREAD = NULL; |
210 | atomic_set(&nrdy,0); |
214 | atomic_set(&nrdy, 0); |
211 | thread_slab = slab_cache_create("thread_slab", sizeof(thread_t), 0, |
215 | thread_slab = slab_cache_create("thread_slab", sizeof(thread_t), 0, |
212 | thr_constructor, thr_destructor, 0); |
216 | thr_constructor, thr_destructor, 0); |
213 | 217 | ||
214 | #ifdef ARCH_HAS_FPU |
218 | #ifdef CONFIG_FPU |
215 | 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), |
216 | FPU_CONTEXT_ALIGN, NULL, NULL, 0); |
220 | FPU_CONTEXT_ALIGN, NULL, NULL, 0); |
217 | #endif |
221 | #endif |
218 | 222 | ||
219 | avltree_create(&threads_tree); |
223 | avltree_create(&threads_tree); |
Line 273... | Line 277... | ||
273 | * @param arg Thread's implementing function argument. |
277 | * @param arg Thread's implementing function argument. |
274 | * @param task Task to which the thread belongs. The caller must |
278 | * @param task Task to which the thread belongs. The caller must |
275 | * guarantee that the task won't cease to exist during the |
279 | * guarantee that the task won't cease to exist during the |
276 | * call. The task's lock may not be held. |
280 | * call. The task's lock may not be held. |
277 | * @param flags Thread flags. |
281 | * @param flags Thread flags. |
278 | * @param name Symbolic name. |
282 | * @param name Symbolic name (a copy is made). |
279 | * @param uncounted Thread's accounting doesn't affect accumulated task |
283 | * @param uncounted Thread's accounting doesn't affect accumulated task |
280 | * accounting. |
284 | * accounting. |
281 | * |
285 | * |
282 | * @return New thread's structure on success, NULL on failure. |
286 | * @return New thread's structure on success, NULL on failure. |
283 | * |
287 | * |
Line 310... | Line 314... | ||
310 | ipl = interrupts_disable(); |
314 | ipl = interrupts_disable(); |
311 | t->saved_context.ipl = interrupts_read(); |
315 | t->saved_context.ipl = interrupts_read(); |
312 | interrupts_restore(ipl); |
316 | interrupts_restore(ipl); |
313 | 317 | ||
314 | memcpy(t->name, name, THREAD_NAME_BUFLEN); |
318 | memcpy(t->name, name, THREAD_NAME_BUFLEN); |
- | 319 | t->name[THREAD_NAME_BUFLEN - 1] = '\0'; |
|
315 | 320 | ||
316 | t->thread_code = func; |
321 | t->thread_code = func; |
317 | t->thread_arg = arg; |
322 | t->thread_arg = arg; |
318 | t->ticks = -1; |
323 | t->ticks = -1; |
319 | t->cycles = 0; |
324 | t->cycles = 0; |
Line 345... | Line 350... | ||
345 | t->fpu_context_engaged = 0; |
350 | t->fpu_context_engaged = 0; |
346 | 351 | ||
347 | avltree_node_initialize(&t->threads_tree_node); |
352 | avltree_node_initialize(&t->threads_tree_node); |
348 | t->threads_tree_node.key = (uintptr_t) t; |
353 | t->threads_tree_node.key = (uintptr_t) t; |
349 | 354 | ||
- | 355 | #ifdef CONFIG_UDEBUG |
|
- | 356 | /* Init debugging stuff */ |
|
- | 357 | udebug_thread_initialize(&t->udebug); |
|
- | 358 | #endif |
|
- | 359 | ||
350 | /* might depend on previous initialization */ |
360 | /* might depend on previous initialization */ |
351 | thread_create_arch(t); |
361 | thread_create_arch(t); |
352 | 362 | ||
353 | if (!(flags & THREAD_FLAG_NOATTACH)) |
363 | if (!(flags & THREAD_FLAG_NOATTACH)) |
354 | thread_attach(t, task); |
364 | thread_attach(t, task); |
Line 407... | Line 417... | ||
407 | void thread_attach(thread_t *t, task_t *task) |
417 | void thread_attach(thread_t *t, task_t *task) |
408 | { |
418 | { |
409 | ipl_t ipl; |
419 | ipl_t ipl; |
410 | 420 | ||
411 | /* |
421 | /* |
412 | * Attach to the current task. |
422 | * Attach to the specified task. |
413 | */ |
423 | */ |
414 | ipl = interrupts_disable(); |
424 | ipl = interrupts_disable(); |
415 | spinlock_lock(&task->lock); |
425 | spinlock_lock(&task->lock); |
- | 426 | ||
416 | 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) |
|
417 | atomic_inc(&task->lifecount); |
431 | atomic_inc(&task->lifecount); |
- | 432 | ||
418 | list_append(&t->th_link, &task->th_head); |
433 | list_append(&t->th_link, &task->th_head); |
419 | spinlock_unlock(&task->lock); |
434 | spinlock_unlock(&task->lock); |
420 | 435 | ||
421 | /* |
436 | /* |
422 | * Register this thread in the system-wide list. |
437 | * Register this thread in the system-wide list. |
Line 435... | Line 450... | ||
435 | */ |
450 | */ |
436 | void thread_exit(void) |
451 | void thread_exit(void) |
437 | { |
452 | { |
438 | ipl_t ipl; |
453 | ipl_t ipl; |
439 | 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 |
|
440 | if (atomic_predec(&TASK->lifecount) == 0) { |
460 | if (atomic_predec(&TASK->lifecount) == 0) { |
441 | /* |
461 | /* |
442 | * 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 |
|
443 | * With the exception of the moment the task was created, new |
464 | * moment the task was created, new userspace threads |
444 | * threads can only be created by threads of the same task. |
465 | * can only be created by threads of the same task. |
445 | * We are safe to perform cleanup. |
466 | * We are safe to perform cleanup. |
446 | */ |
467 | */ |
447 | if (THREAD->flags & THREAD_FLAG_USPACE) { |
- | |
448 | ipc_cleanup(); |
468 | ipc_cleanup(); |
449 | futex_cleanup(); |
469 | futex_cleanup(); |
450 | LOG("Cleanup of task %" PRIu64" completed.", TASK->taskid); |
470 | LOG("Cleanup of task %" PRIu64" completed.", TASK->taskid); |
451 | } |
471 | } |
452 | } |
472 | } |
Line 687... | Line 707... | ||
687 | 707 | ||
688 | /** Process syscall to create new thread. |
708 | /** Process syscall to create new thread. |
689 | * |
709 | * |
690 | */ |
710 | */ |
691 | 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, |
692 | thread_id_t *uspace_thread_id) |
712 | size_t name_len, thread_id_t *uspace_thread_id) |
693 | { |
713 | { |
694 | thread_t *t; |
714 | thread_t *t; |
695 | char namebuf[THREAD_NAME_BUFLEN]; |
715 | char namebuf[THREAD_NAME_BUFLEN]; |
696 | uspace_arg_t *kernel_uarg; |
716 | uspace_arg_t *kernel_uarg; |
697 | int rc; |
717 | int rc; |
698 | 718 | ||
- | 719 | if (name_len > THREAD_NAME_BUFLEN - 1) |
|
- | 720 | name_len = THREAD_NAME_BUFLEN - 1; |
|
- | 721 | ||
699 | rc = copy_from_uspace(namebuf, uspace_name, THREAD_NAME_BUFLEN); |
722 | rc = copy_from_uspace(namebuf, uspace_name, name_len); |
700 | if (rc != 0) |
723 | if (rc != 0) |
701 | return (unative_t) rc; |
724 | return (unative_t) rc; |
702 | 725 | ||
- | 726 | namebuf[name_len] = '\0'; |
|
- | 727 | ||
703 | /* |
728 | /* |
704 | * 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. |
705 | * In case of success, kernel_uarg will be freed in uinit(). |
730 | * In case of success, kernel_uarg will be freed in uinit(). |
706 | */ |
731 | */ |
707 | kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0); |
732 | kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0); |
Line 736... | Line 761... | ||
736 | free(kernel_uarg); |
761 | free(kernel_uarg); |
737 | 762 | ||
738 | return (unative_t) rc; |
763 | return (unative_t) rc; |
739 | } |
764 | } |
740 | } |
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 |
|
741 | thread_attach(t, TASK); |
776 | thread_attach(t, TASK); |
- | 777 | #endif |
|
742 | thread_ready(t); |
778 | thread_ready(t); |
743 | 779 | ||
744 | return 0; |
780 | return 0; |
745 | } else |
781 | } else |
746 | free(kernel_uarg); |
782 | free(kernel_uarg); |