Nucleus
Barry Kernel threads + threads share address space 6217f0d (3 years, 1 month ago)
/*
* This file contains the clone() function/system call. It creates a new task,
* and copies most of the attributes from the parent task into it.
*/
#include <sys/sched.h>
#include <sys/types.h>
#include <nucleus/io.h>
#include <nucleus/lib.h>
#include <nucleus/task.h>
#include <nucleus/vfs.h>
/* Copy the stack */
static void
copy_kernel_stack(Task *parent, Task *child)
{
size_t offset = (size_t) child - (uintptr_t) parent;
uintptr_t oldTop = (uintptr_t) parent + KERNEL_STACK_SIZE,
oldStack = child->esp;
uintptr_t newTop = (uintptr_t) child + KERNEL_STACK_SIZE,
newStack = child->esp + offset;
/* Copy contents and change stack */
memcpy((void *) newStack, (void *) oldStack,
(size_t) oldTop - oldStack);
child->esp += offset;
child->ebp += offset;
/* Update pointers on the stack */
uintptr_t i, tmp;
for (i = newStack & ~(sizeof(uintptr_t) - 1);
i < newTop; i += sizeof(uintptr_t)) {
tmp = *(uintptr_t *) i;
if (tmp > oldStack && tmp < (uintptr_t) oldTop)
*(uintptr_t *) i = tmp + offset;
}
}
/* Clone a task */
pid_t
clone(int flags, void *stack)
{
enter_critical_section();
Task *parent = current, *child = new(&taskType), *tmp;
pid_t tid = 0;
if (flags & CLONE_THREAD) {
flags |= CLONE_PARENT;
flags |= CLONE_VM;
}
/* Copy thread information */
if (flags & CLONE_THREAD)
child->tgid = parent->tgid;
child->uid = parent->uid;
child->euid = parent->euid;
child->suid = parent->suid;
child->gid = parent->gid;
child->egid = parent->egid;
child->sgid = parent->sgid;
child->inSyscall = parent->inSyscall;
/* Get executable file */
if (parent->executable)
child->executable = get(parent->executable);
/* Clone parent's file system namespace */
if (flags & CLONE_FS)
child->fs = get(parent->fs);
else
child->fs = copy(parent->fs);
/* Clone parent's files namespace */
if (flags & CLONE_FILES)
child->files = get(parent->files);
else
child->files = copy(parent->files);
/* Clone parent's virtual memory namespace */
if (flags & CLONE_VM)
child->vm = get(parent->vm);
else
child->vm = copy(parent->vm);
/* Clone parent's signals namespace */
if (flags & CLONE_SIGHAND)
child->signals = get(parent->signals);
else
child->signals = copy(parent->signals);
/* Split tasks here */
asm volatile("mov %%esi, %0" : "=r" (child->esi));
asm volatile("mov %%edi, %0" : "=r" (child->edi));
asm volatile("mov %%ebx, %0" : "=r" (child->ebx));
asm volatile("mov %%esp, %0" : "=r" (child->esp));
asm volatile("mov %%ebp, %0" : "=r" (child->ebp));
copy_kernel_stack(parent, child);
child->eip = (uintptr_t) &&end;
enqueue_task(child);
tid = child->tid;
put(child);
exit_critical_section();
end:
if ((flags & CLONE_VM) && current == child) {
/* Set the child's user stack */
cpu->frame->esp = (uintptr_t) stack;
}
return tid;
}