67,9 → 67,13 |
#include <main/uinit.h> |
#include <syscall/copy.h> |
#include <errno.h> |
#include <console/klog.h> |
|
|
#ifndef LOADED_PROG_STACK_PAGES_NO |
#define LOADED_PROG_STACK_PAGES_NO 1 |
#endif |
|
|
/** Thread states */ |
char *thread_states[] = { |
"Invalid", |
98,7 → 102,7 |
thread_id_t last_tid = 0; |
|
static slab_cache_t *thread_slab; |
#ifdef ARCH_HAS_FPU |
#ifdef CONFIG_FPU |
slab_cache_t *fpu_context_slab; |
#endif |
|
157,7 → 161,7 |
/* call the architecture-specific part of the constructor */ |
thr_constructor_arch(t); |
|
#ifdef ARCH_HAS_FPU |
#ifdef CONFIG_FPU |
#ifdef CONFIG_FPU_LAZY |
t->saved_fpu_context = NULL; |
#else |
165,11 → 169,11 |
if (!t->saved_fpu_context) |
return -1; |
#endif |
#endif |
#endif |
|
t->kstack = (uint8_t *) frame_alloc(STACK_FRAMES, FRAME_KA | kmflags); |
if (!t->kstack) { |
#ifdef ARCH_HAS_FPU |
#ifdef CONFIG_FPU |
if (t->saved_fpu_context) |
slab_free(fpu_context_slab, t->saved_fpu_context); |
#endif |
176,6 → 180,10 |
return -1; |
} |
|
#ifdef CONFIG_UDEBUG |
mutex_initialize(&t->udebug.lock, MUTEX_PASSIVE); |
#endif |
|
return 0; |
} |
|
188,7 → 196,7 |
thr_destructor_arch(t); |
|
frame_free(KA2PA(t->kstack)); |
#ifdef ARCH_HAS_FPU |
#ifdef CONFIG_FPU |
if (t->saved_fpu_context) |
slab_free(fpu_context_slab, t->saved_fpu_context); |
#endif |
203,11 → 211,11 |
void thread_init(void) |
{ |
THREAD = NULL; |
atomic_set(&nrdy,0); |
atomic_set(&nrdy, 0); |
thread_slab = slab_cache_create("thread_slab", sizeof(thread_t), 0, |
thr_constructor, thr_destructor, 0); |
|
#ifdef ARCH_HAS_FPU |
#ifdef CONFIG_FPU |
fpu_context_slab = slab_cache_create("fpu_slab", sizeof(fpu_context_t), |
FPU_CONTEXT_ALIGN, NULL, NULL, 0); |
#endif |
271,7 → 279,7 |
* guarantee that the task won't cease to exist during the |
* call. The task's lock may not be held. |
* @param flags Thread flags. |
* @param name Symbolic name. |
* @param name Symbolic name (a copy is made). |
* @param uncounted Thread's accounting doesn't affect accumulated task |
* accounting. |
* |
289,8 → 297,7 |
return NULL; |
|
/* Not needed, but good for debugging */ |
memsetb((uintptr_t) t->kstack, THREAD_STACK_SIZE * 1 << STACK_FRAMES, |
0); |
memsetb(t->kstack, THREAD_STACK_SIZE * 1 << STACK_FRAMES, 0); |
|
ipl = interrupts_disable(); |
spinlock_lock(&tidlock); |
309,6 → 316,7 |
interrupts_restore(ipl); |
|
memcpy(t->name, name, THREAD_NAME_BUFLEN); |
t->name[THREAD_NAME_BUFLEN - 1] = '\0'; |
|
t->thread_code = func; |
t->thread_arg = arg; |
344,6 → 352,11 |
avltree_node_initialize(&t->threads_tree_node); |
t->threads_tree_node.key = (uintptr_t) t; |
|
#ifdef CONFIG_UDEBUG |
/* Init debugging stuff */ |
udebug_thread_initialize(&t->udebug); |
#endif |
|
/* might depend on previous initialization */ |
thread_create_arch(t); |
|
406,12 → 419,17 |
ipl_t ipl; |
|
/* |
* Attach to the current task. |
* Attach to the specified task. |
*/ |
ipl = interrupts_disable(); |
spinlock_lock(&task->lock); |
|
atomic_inc(&task->refcount); |
atomic_inc(&task->lifecount); |
|
/* Must not count kbox thread into lifecount */ |
if (t->flags & THREAD_FLAG_USPACE) |
atomic_inc(&task->lifecount); |
|
list_append(&t->th_link, &task->th_head); |
spinlock_unlock(&task->lock); |
|
434,18 → 452,22 |
{ |
ipl_t ipl; |
|
if (atomic_predec(&TASK->lifecount) == 0) { |
/* |
* We are the last thread in the task that still has not exited. |
* With the exception of the moment the task was created, new |
* threads can only be created by threads of the same task. |
* We are safe to perform cleanup. |
*/ |
if (THREAD->flags & THREAD_FLAG_USPACE) { |
if (THREAD->flags & THREAD_FLAG_USPACE) { |
#ifdef CONFIG_UDEBUG |
/* Generate udebug THREAD_E event */ |
udebug_thread_e_event(); |
#endif |
if (atomic_predec(&TASK->lifecount) == 0) { |
/* |
* We are the last userspace thread in the task that |
* still has not exited. With the exception of the |
* moment the task was created, new userspace threads |
* can only be created by threads of the same task. |
* We are safe to perform cleanup. |
*/ |
ipc_cleanup(); |
futex_cleanup(); |
klog_printf("Cleanup of task %llu completed.", |
TASK->taskid); |
futex_cleanup(); |
LOG("Cleanup of task %" PRIu64" completed.", TASK->taskid); |
} |
} |
|
581,33 → 603,37 |
|
static bool thread_walker(avltree_node_t *node, void *arg) |
{ |
thread_t *t; |
|
t = avltree_get_instance(node, thread_t, threads_tree_node); |
|
thread_t *t = avltree_get_instance(node, thread_t, threads_tree_node); |
|
uint64_t cycles; |
char suffix; |
order(t->cycles, &cycles, &suffix); |
|
if (sizeof(void *) == 4) |
printf("%-6llu %-10s %#10zx %-8s %#10zx %-3ld %#10zx %#10zx %9llu%c ", |
t->tid, t->name, t, thread_states[t->state], t->task, |
t->task->context, t->thread_code, t->kstack, cycles, suffix); |
else |
printf("%-6llu %-10s %#18zx %-8s %#18zx %-3ld %#18zx %#18zx %9llu%c ", |
t->tid, t->name, t, thread_states[t->state], t->task, |
t->task->context, t->thread_code, t->kstack, cycles, suffix); |
|
#ifdef __32_BITS__ |
printf("%-6" PRIu64" %-10s %10p %-8s %10p %-3" PRIu32 " %10p %10p %9" PRIu64 "%c ", |
t->tid, t->name, t, thread_states[t->state], t->task, |
t->task->context, t->thread_code, t->kstack, cycles, suffix); |
#endif |
|
#ifdef __64_BITS__ |
printf("%-6" PRIu64" %-10s %18p %-8s %18p %-3" PRIu32 " %18p %18p %9" PRIu64 "%c ", |
t->tid, t->name, t, thread_states[t->state], t->task, |
t->task->context, t->thread_code, t->kstack, cycles, suffix); |
#endif |
|
if (t->cpu) |
printf("%-4zd", t->cpu->id); |
printf("%-4u", t->cpu->id); |
else |
printf("none"); |
|
if (t->state == Sleeping) { |
if (sizeof(uintptr_t) == 4) |
printf(" %#10zx", t->sleep_queue); |
else |
printf(" %#18zx", t->sleep_queue); |
#ifdef __32_BITS__ |
printf(" %10p", t->sleep_queue); |
#endif |
|
#ifdef __64_BITS__ |
printf(" %18p", t->sleep_queue); |
#endif |
} |
|
printf("\n"); |
623,23 → 649,25 |
/* Messing with thread structures, avoid deadlock */ |
ipl = interrupts_disable(); |
spinlock_lock(&threads_lock); |
|
if (sizeof(uintptr_t) == 4) { |
printf("tid name address state task " |
"ctx code stack cycles cpu " |
"waitqueue\n"); |
printf("------ ---------- ---------- -------- ---------- " |
"--- ---------- ---------- ---------- ---- " |
"----------\n"); |
} else { |
printf("tid name address state task " |
"ctx code stack cycles cpu " |
"waitqueue\n"); |
printf("------ ---------- ------------------ -------- ------------------ " |
"--- ------------------ ------------------ ---------- ---- " |
"------------------\n"); |
} |
|
#ifdef __32_BITS__ |
printf("tid name address state task " |
"ctx code stack cycles cpu " |
"waitqueue\n"); |
printf("------ ---------- ---------- -------- ---------- " |
"--- ---------- ---------- ---------- ---- " |
"----------\n"); |
#endif |
|
#ifdef __64_BITS__ |
printf("tid name address state task " |
"ctx code stack cycles cpu " |
"waitqueue\n"); |
printf("------ ---------- ------------------ -------- ------------------ " |
"--- ------------------ ------------------ ---------- ---- " |
"------------------\n"); |
#endif |
|
avltree_walk(&threads_tree, thread_walker, NULL); |
|
spinlock_unlock(&threads_lock); |
664,7 → 692,6 |
return node != NULL; |
} |
|
|
/** Update accounting of current thread. |
* |
* Note that thread_lock on THREAD must be already held and |
682,7 → 709,7 |
* |
*/ |
unative_t sys_thread_create(uspace_arg_t *uspace_uarg, char *uspace_name, |
thread_id_t *uspace_thread_id) |
size_t name_len, thread_id_t *uspace_thread_id) |
{ |
thread_t *t; |
char namebuf[THREAD_NAME_BUFLEN]; |
689,10 → 716,15 |
uspace_arg_t *kernel_uarg; |
int rc; |
|
rc = copy_from_uspace(namebuf, uspace_name, THREAD_NAME_BUFLEN); |
if (name_len > THREAD_NAME_BUFLEN - 1) |
name_len = THREAD_NAME_BUFLEN - 1; |
|
rc = copy_from_uspace(namebuf, uspace_name, name_len); |
if (rc != 0) |
return (unative_t) rc; |
|
namebuf[name_len] = '\0'; |
|
/* |
* In case of failure, kernel_uarg will be deallocated in this function. |
* In case of success, kernel_uarg will be freed in uinit(). |
731,7 → 763,18 |
return (unative_t) rc; |
} |
} |
#ifdef CONFIG_UDEBUG |
/* |
* Generate udebug THREAD_B event and attach the thread. |
* This must be done atomically (with the debug locks held), |
* otherwise we would either miss some thread or receive |
* THREAD_B events for threads that already existed |
* and could be detected with THREAD_READ before. |
*/ |
udebug_thread_b_event_attach(t, TASK); |
#else |
thread_attach(t, TASK); |
#endif |
thread_ready(t); |
|
return 0; |