diff --git a/include/kernel/syscall.h b/include/kernel/syscall.h index d237af2..b8476c0 100644 --- a/include/kernel/syscall.h +++ b/include/kernel/syscall.h @@ -68,6 +68,7 @@ extern kern_status_t sys_task_config_set( size_t len); extern kern_status_t sys_thread_start(kern_handle_t thread); +extern kern_status_t sys_thread_exit(void); extern kern_status_t sys_thread_config_get( kern_handle_t thread, kern_config_key_t key, diff --git a/include/kernel/task.h b/include/kernel/task.h index e78c5d5..ce71f75 100644 --- a/include/kernel/task.h +++ b/include/kernel/task.h @@ -48,6 +48,7 @@ static inline void task_unref(struct task *task) { object_unref(&task->t_base); } +extern void task_exit(int status); extern kern_status_t task_add_child(struct task *parent, struct task *child); extern kern_status_t task_add_channel( struct task *task, diff --git a/include/kernel/thread.h b/include/kernel/thread.h index 5e5d722..acdaf03 100644 --- a/include/kernel/thread.h +++ b/include/kernel/thread.h @@ -59,6 +59,9 @@ extern kern_status_t thread_init_user( size_t nr_args); extern int thread_priority(struct thread *thr); extern void thread_awaken(struct thread *thr); +extern void thread_exit(void); +extern void thread_join(struct thread *thread, unsigned long *irq_flags); +extern void thread_kill(struct thread *thread); extern void idle(void); extern struct thread *create_kernel_thread(void (*fn)(void)); extern struct thread *create_idle_thread(void); diff --git a/libmango/arch/x86_64/syscall.S b/libmango/arch/x86_64/syscall.S index 8e69b62..6c7eebb 100644 --- a/libmango/arch/x86_64/syscall.S +++ b/libmango/arch/x86_64/syscall.S @@ -64,6 +64,7 @@ SYSCALL_GATE task_config_get SYS_TASK_CONFIG_GET 4 SYSCALL_GATE task_config_set SYS_TASK_CONFIG_SET 4 SYSCALL_GATE thread_start SYS_THREAD_START 1 +SYSCALL_GATE thread_exit SYS_THREAD_EXIT 0 SYSCALL_GATE thread_config_get SYS_THREAD_CONFIG_GET 4 SYSCALL_GATE thread_config_set SYS_THREAD_CONFIG_SET 4 diff --git a/libmango/include-user/mango/task.h b/libmango/include-user/mango/task.h index 03347c8..11217ff 100644 --- a/libmango/include-user/mango/task.h +++ b/libmango/include-user/mango/task.h @@ -35,6 +35,7 @@ extern kern_status_t task_config_set( size_t len); extern kern_status_t thread_start(kern_handle_t thread); +extern kern_status_t thread_exit(void); extern kern_status_t thread_config_get( kern_handle_t thread, kern_config_key_t key, diff --git a/libmango/include/mango/signal.h b/libmango/include/mango/signal.h index 87ab161..0e720f6 100644 --- a/libmango/include/mango/signal.h +++ b/libmango/include/mango/signal.h @@ -1,6 +1,8 @@ #ifndef MANGO_SIGNAL_H_ #define MANGO_SIGNAL_H_ +#define THREAD_SIGNAL_STOPPED 0x01u + #define CHANNEL_SIGNAL_MSG_RECEIVED 0x01u #define VM_CONTROLLER_SIGNAL_REQUEST_RECEIVED 0x01u diff --git a/libmango/include/mango/syscall.h b/libmango/include/mango/syscall.h index 42e19cb..08b8aa0 100644 --- a/libmango/include/mango/syscall.h +++ b/libmango/include/mango/syscall.h @@ -16,6 +16,7 @@ #define SYS_TASK_CONFIG_GET 0x2Au #define SYS_TASK_CONFIG_SET 0x2Bu #define SYS_THREAD_START 0x0Cu +#define SYS_THREAD_EXIT 0x2Eu #define SYS_THREAD_CONFIG_GET 0x2Cu #define SYS_THREAD_CONFIG_SET 0x2Du #define SYS_VM_OBJECT_CREATE 0x0Du diff --git a/sched/task.c b/sched/task.c index 7e72043..09acbab 100644 --- a/sched/task.c +++ b/sched/task.c @@ -222,13 +222,13 @@ kern_status_t task_add_channel( { channel->c_id = id; - if (!task->b_channels.b_root) { - task->b_channels.b_root = &channel->c_node; - btree_insert_fixup(&task->b_channels, &channel->c_node); + if (!task->t_channels.b_root) { + task->t_channels.b_root = &channel->c_node; + btree_insert_fixup(&task->t_channels, &channel->c_node); return KERN_OK; } - struct btree_node *cur = task->b_channels.b_root; + struct btree_node *cur = task->t_channels.b_root; while (1) { struct channel *cur_node = BTREE_CONTAINER(struct channel, c_node, cur); @@ -255,7 +255,7 @@ kern_status_t task_add_channel( cur = next; } - btree_insert_fixup(&task->b_channels, &channel->c_node); + btree_insert_fixup(&task->t_channels, &channel->c_node); return KERN_OK; } @@ -268,7 +268,7 @@ BTREE_DEFINE_SIMPLE_GET( struct channel *task_get_channel(struct task *task, unsigned int id) { - return get_channel_with_id(&task->b_channels, id); + return get_channel_with_id(&task->t_channels, id); } struct task *task_from_tid(tid_t id) @@ -280,6 +280,72 @@ struct task *task_from_tid(tid_t id) return t; } +void task_exit(int status) +{ + struct task *self = current_task(); + unsigned long flags; + task_lock_irqsave(self, &flags); + struct task *parent = self->t_parent; + + if (parent) { + task_unlock_irqrestore(self, flags); + task_lock_irqsave(parent, &flags); + task_lock(self); + queue_delete(&parent->t_children, &self->t_child_entry); + task_unlock(parent); + } + + struct thread *cur_thread = current_thread(); + + self->t_state = TASK_STOPPED; + cur_thread->tr_state = THREAD_STOPPED; + + struct queue_entry *cur = queue_first(&self->t_threads); + while (cur) { + struct queue_entry *next = queue_next(cur); + struct thread *thread + = QUEUE_CONTAINER(struct thread, tr_parent_entry, cur); + + if (thread == cur_thread) { + cur = next; + continue; + } + + thread_lock(thread); + thread_kill(thread); + queue_delete(&self->t_threads, cur); + thread_unlock(thread); + + cur = next; + } + + object_unref(&self->t_address_space->s_base); + spin_lock_t *handles_lock = &self->t_handles_lock; + struct handle_table *handles = self->t_handles; + spin_lock(&self->t_handles_lock); + + pmap_switch(get_kernel_pmap()); + pmap_destroy(self->t_pmap); + + task_unlock(self); + handle_table_destroy(handles); + + printk("thread %s[%u.%u] killed", + self->t_name, + self->t_id, + cur_thread->tr_id); + printk("task %s[%u] killed (%u, %u)", + self->t_name, + self->t_id, + self->t_base.ob_refcount, + self->t_base.ob_handles); + spin_unlock_irqrestore(handles_lock, flags); + + while (1) { + schedule(SCHED_NORMAL); + } +} + kern_status_t task_open_handle( struct task *task, struct object *obj, diff --git a/sched/thread.c b/sched/thread.c index aa9d271..2f44513 100644 --- a/sched/thread.c +++ b/sched/thread.c @@ -65,9 +65,6 @@ kern_status_t thread_init_user( const uintptr_t *args, size_t nr_args) { - thr->tr_id = thr->tr_parent->t_next_thread_id++; - - thr->tr_prio = PRIO_NORMAL; thr->tr_state = THREAD_READY; thr->tr_quantum_target = default_quantum(); @@ -144,6 +141,55 @@ void thread_awaken(struct thread *thr) rq_unlock(rq, flags); } +void thread_exit(void) +{ + struct thread *self = current_thread(); + unsigned long flags; + thread_lock_irqsave(self, &flags); + self->tr_state = THREAD_STOPPED; + object_assert_signal(&self->tr_base, THREAD_SIGNAL_STOPPED); + printk("thread %s[%u.%u] exited", + self->tr_parent->t_name, + self->tr_parent->t_id, + self->tr_id); + thread_unlock_irqrestore(self, flags); + + while (1) { + schedule(SCHED_NORMAL); + } +} + +void thread_join(struct thread *thread, unsigned long *irq_flags) +{ + while (1) { + if (thread->tr_state == THREAD_STOPPED) { + break; + } + + object_wait_signal( + &thread->tr_base, + THREAD_SIGNAL_STOPPED, + irq_flags); + } +} + +void thread_kill(struct thread *thread) +{ + thread->tr_state = THREAD_STOPPED; + if (thread->tr_rq) { + unsigned long flags; + rq_lock(thread->tr_rq, &flags); + rq_remove_thread(thread->tr_rq, thread); + rq_unlock(thread->tr_rq, flags); + } + + object_assert_signal(&thread->tr_base, THREAD_SIGNAL_STOPPED); + printk("thread %s[%u.%u] killed", + thread->tr_parent->t_name, + thread->tr_parent->t_id, + thread->tr_id); +} + struct thread *create_kernel_thread(void (*fn)(void)) { struct task *kernel = kernel_task(); diff --git a/syscall/dispatch.c b/syscall/dispatch.c index 0e1fa65..64210be 100644 --- a/syscall/dispatch.c +++ b/syscall/dispatch.c @@ -11,6 +11,7 @@ static const virt_addr_t syscall_table[] = { SYSCALL_TABLE_ENTRY(TASK_CREATE_THREAD, task_create_thread), SYSCALL_TABLE_ENTRY(TASK_GET_ADDRESS_SPACE, task_get_address_space), SYSCALL_TABLE_ENTRY(THREAD_START, thread_start), + SYSCALL_TABLE_ENTRY(THREAD_EXIT, thread_exit), SYSCALL_TABLE_ENTRY(THREAD_CONFIG_GET, thread_config_get), SYSCALL_TABLE_ENTRY(THREAD_CONFIG_SET, thread_config_set), SYSCALL_TABLE_ENTRY(VM_OBJECT_CREATE, vm_object_create), diff --git a/syscall/log.c b/syscall/log.c index 2567f05..689ffe0 100644 --- a/syscall/log.c +++ b/syscall/log.c @@ -1,10 +1,12 @@ #include #include #include +#include kern_status_t sys_kern_log(const char *s) { struct task *task = current_task(); - printk("%s[%d]: %s", task->t_name, task->t_id, s); + struct thread *thread = current_thread(); + printk("%s[%d.%d]: %s", task->t_name, task->t_id, thread->tr_id, s); return KERN_OK; } diff --git a/syscall/task.c b/syscall/task.c index b513566..a33c843 100644 --- a/syscall/task.c +++ b/syscall/task.c @@ -10,11 +10,8 @@ extern kern_status_t sys_task_exit(int status) { struct task *self = current_task(); printk("%s[%d]: task_exit(%d)", self->t_name, self->t_id, status); - while (1) { - milli_sleep(5000); - } - - return KERN_UNIMPLEMENTED; + task_exit(status); + return KERN_FATAL_ERROR; } kern_status_t sys_task_self(kern_handle_t *out) @@ -179,6 +176,7 @@ kern_status_t sys_task_create_thread( &target_handle, &out_handle); if (status != KERN_OK) { + object_unref(target_obj); task_unlock_irqrestore(self, flags); return status; } @@ -198,10 +196,11 @@ kern_status_t sys_task_create_thread( } thread_init_user(thread, ip, sp, args, nr_args); - target_handle->h_object = &thread->thr_base; - object_add_handle(&thread->thr_base); + target_handle->h_object = &thread->tr_base; + object_add_handle(&thread->tr_base); task_unlock_irqrestore(target, flags); + object_unref(target_obj); *out_thread = out_handle; return KERN_OK; @@ -288,6 +287,13 @@ kern_status_t sys_thread_start(kern_handle_t thread_handle) return KERN_OK; } +kern_status_t sys_thread_exit(void) +{ + thread_exit(); + /* unreachable */ + return KERN_FATAL_ERROR; +} + kern_status_t sys_thread_config_get( kern_handle_t thread_handle, kern_config_key_t key,