syscall: task: initial implementation of task_duplicate
This commit is contained in:
@@ -66,6 +66,9 @@ extern kern_status_t sys_task_config_set(
|
||||
kern_config_key_t key,
|
||||
const void *ptr,
|
||||
size_t len);
|
||||
extern kern_status_t sys_task_duplicate(
|
||||
kern_handle_t *out_task,
|
||||
kern_handle_t *out_address_space);
|
||||
|
||||
extern kern_status_t sys_thread_self(kern_handle_t *out);
|
||||
extern kern_status_t sys_thread_start(kern_handle_t thread);
|
||||
|
||||
@@ -10,6 +10,7 @@ static const virt_addr_t syscall_table[] = {
|
||||
SYSCALL_TABLE_ENTRY(TASK_CREATE, task_create),
|
||||
SYSCALL_TABLE_ENTRY(TASK_CREATE_THREAD, task_create_thread),
|
||||
SYSCALL_TABLE_ENTRY(TASK_GET_ADDRESS_SPACE, task_get_address_space),
|
||||
SYSCALL_TABLE_ENTRY(TASK_DUPLICATE, task_duplicate),
|
||||
SYSCALL_TABLE_ENTRY(THREAD_SELF, thread_self),
|
||||
SYSCALL_TABLE_ENTRY(THREAD_START, thread_start),
|
||||
SYSCALL_TABLE_ENTRY(THREAD_EXIT, thread_exit),
|
||||
|
||||
+101
@@ -1,5 +1,6 @@
|
||||
#include <kernel/address-space.h>
|
||||
#include <kernel/machine/cpu.h>
|
||||
#include <kernel/panic.h>
|
||||
#include <kernel/printk.h>
|
||||
#include <kernel/sched.h>
|
||||
#include <kernel/syscall.h>
|
||||
@@ -440,3 +441,103 @@ kern_status_t sys_thread_config_set(
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
kern_status_t sys_task_duplicate(
|
||||
kern_handle_t *out_task,
|
||||
kern_handle_t *out_address_space)
|
||||
{
|
||||
struct task *self = get_current_task();
|
||||
|
||||
if (!validate_access_w(self, out_task, sizeof *out_task)) {
|
||||
put_current_task(self);
|
||||
return KERN_MEMORY_FAULT;
|
||||
}
|
||||
|
||||
if (!validate_access_w(
|
||||
self,
|
||||
out_address_space,
|
||||
sizeof *out_address_space)) {
|
||||
put_current_task(self);
|
||||
return KERN_MEMORY_FAULT;
|
||||
}
|
||||
|
||||
*out_task = KERN_HANDLE_INVALID;
|
||||
*out_address_space = KERN_HANDLE_INVALID;
|
||||
|
||||
kern_status_t status = KERN_OK;
|
||||
unsigned long flags;
|
||||
task_lock_irqsave(self, &flags);
|
||||
|
||||
struct handle *child_handle_slot = NULL, *space_handle_slot = NULL;
|
||||
kern_handle_t child_handle, space_handle;
|
||||
status = handle_table_alloc_handle(
|
||||
self->t_handles,
|
||||
KERN_HANDLE_INVALID,
|
||||
&child_handle_slot,
|
||||
&child_handle);
|
||||
if (status != KERN_OK) {
|
||||
task_unlock_irqrestore(self, flags);
|
||||
put_current_task(self);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = handle_table_alloc_handle(
|
||||
self->t_handles,
|
||||
KERN_HANDLE_INVALID,
|
||||
&space_handle_slot,
|
||||
&space_handle);
|
||||
if (status != KERN_OK) {
|
||||
handle_table_free_handle(self->t_handles, child_handle);
|
||||
task_unlock_irqrestore(self, flags);
|
||||
put_current_task(self);
|
||||
return status;
|
||||
}
|
||||
|
||||
struct task *new_task = task_create(self->t_name, strlen(self->t_name));
|
||||
if (!new_task) {
|
||||
put_current_task(self);
|
||||
return KERN_NO_MEMORY;
|
||||
}
|
||||
|
||||
struct thread *new_thread = task_create_thread(new_task);
|
||||
if (!new_thread) {
|
||||
handle_table_free_handle(self->t_handles, child_handle);
|
||||
handle_table_free_handle(self->t_handles, space_handle);
|
||||
task_unlock_irqrestore(self, flags);
|
||||
object_unref(&new_task->t_base);
|
||||
put_current_task(self);
|
||||
return KERN_NO_MEMORY;
|
||||
}
|
||||
|
||||
struct thread *self_thread = get_current_thread();
|
||||
thread_init_user_clone(new_thread, self_thread, KERN_OK);
|
||||
put_current_thread(self_thread);
|
||||
|
||||
status = address_space_duplicate(
|
||||
new_task->t_address_space,
|
||||
self->t_address_space);
|
||||
if (status != KERN_OK) {
|
||||
handle_table_free_handle(self->t_handles, child_handle);
|
||||
handle_table_free_handle(self->t_handles, space_handle);
|
||||
task_unlock_irqrestore(self, flags);
|
||||
object_unref(&new_thread->tr_base);
|
||||
object_unref(&new_task->t_base);
|
||||
put_current_task(self);
|
||||
return status;
|
||||
}
|
||||
|
||||
schedule_thread_on_cpu(new_thread);
|
||||
|
||||
child_handle_slot->h_object = &new_task->t_base;
|
||||
space_handle_slot->h_object = &new_task->t_address_space->s_base;
|
||||
task_unlock_irqrestore(self, flags);
|
||||
|
||||
*out_task = child_handle;
|
||||
*out_address_space = space_handle;
|
||||
|
||||
/* clear TLB */
|
||||
pmap_switch(self->t_pmap);
|
||||
put_current_task(self);
|
||||
|
||||
return KERN_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user