syscall: task: initial implementation of task_duplicate

This commit is contained in:
2026-04-01 18:40:28 +01:00
parent 304ba8b254
commit b8d3125233
3 changed files with 105 additions and 0 deletions
+3
View File
@@ -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);
+1
View File
@@ -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
View File
@@ -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;
}