BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / blob / master / task / clone.c

// Related

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;
}