/* * 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 #include #include #include #include #include /* 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; }