BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / commit / d41a53cbc7d055b1c00cf0a339dbed6925f4f02c / task / task.c

// Related

Orion

Barry Importing existing Orion kernel d41a53c (2 years, 4 months ago)
diff --git a/task/task.c b/task/task.c
new file mode 100644
index 0000000..294b3cc
--- /dev/null
+++ b/task/task.c
@@ -0,0 +1,420 @@
+/*
+ * This file is responsible for the core functions related to multitasking.  It
+ * relies on a decent paging implementation.  It contains several routines which
+ * are related to the creation, modification and deletion of tasks.
+ */
+
+#include <stdint.h>
+#include <sys/sched.h>
+#include <errno.h>
+#include "task.h"
+#include "../vfs/vfs.h"
+#include "../vfs/inode.h"
+#include "../vfs/cache.h"
+#include "../vfs/tmpfs/fs.h"
+#include "../mem/mem.h"
+#include "../mem/heap.h"
+#include "../mem/paging.h"
+#include "../proc/proc.h"
+#include "../screen.h"
+
+extern TaskQueue readyQueue, tasks;
+pid_t nextPid = 1;
+
+extern uint32_t initialStack;
+extern page_dir_t kernelDir;
+
+uintptr_t read_eip(void);
+
+/* Move the initial stack to a new position */
+static void
+move_stack(void *start, size_t size)
+{
+	uintptr_t i, tmp, *tmpp;
+	uintptr_t oldStackPointer, oldBasePointer, offset;
+	uintptr_t newStackPointer, newBasePointer;
+
+	for (i = (size_t) start - size; i <= (size_t) start; i += 0x1000) {
+		page_t *pg = get_page((void *) i);
+		alloc_page(pg, PTE_PRESENT | PTE_WRITE | PTE_USER, -1);
+	}
+
+	asm volatile("mov %%esp, %0" : "=r" (oldStackPointer));
+	asm volatile("mov %%ebp, %0" : "=r" (oldBasePointer));
+	offset = (uint32_t) start - initialStack;
+	newStackPointer = oldStackPointer + offset;
+	newBasePointer = oldBasePointer + offset;
+
+	memcpy((void *) newStackPointer, (void *) oldStackPointer,
+	       initialStack - oldStackPointer);
+
+	/* Update pointers on stack */
+	for (i = (size_t) start; i > (size_t) start - size; i -= 4) {
+		tmp = *(uint32_t *) i;
+		if ((tmp > oldStackPointer) && (tmp < initialStack)) {
+			tmp += offset;
+			tmpp = (uintptr_t *) i;
+			*tmpp = tmp;
+		}
+	}
+
+	asm volatile("mov %0, %%esp" :: "r" (newStackPointer));
+	asm volatile("mov %0, %%ebp" :: "r" (newBasePointer));
+}
+
+/* Fork a task */
+pid_t
+fork(void)
+{
+	return clone(CLONE_NONE);
+}
+
+/* Clone a task */
+pid_t
+clone(int flags)
+{
+	Task *parent = current, *child = kmalloc(sizeof(Task)), *tmp;
+
+	if (flags & CLONE_THREAD) {
+		flags |= CLONE_PARENT;
+		flags |= CLONE_VM;
+	}
+
+	child->tid = nextPid++;
+	if (flags & CLONE_THREAD)
+		child->tgid = parent->tgid;
+	else
+		child->tgid = child->tid;
+	child->priority = NORMAL;
+	child->state = READY;
+	child->status = 0;
+	child->inSyscall = parent->inSyscall;
+	child->name = kmalloc(strlen(parent->name)+1);
+	memcpy(child->name, parent->name, strlen(parent->name)+1);
+
+	/* Set parent */
+	child->parent = parent;
+	if (flags & CLONE_PARENT)
+		child->parent = parent->parent;
+	child->ppid = child->parent->tgid;
+
+	child->executable = file_get(parent->executable);
+
+	/* Add to list of tasks */
+	tasks.end->tnext = child;
+	tasks.end = child;
+
+	/* Clone parent's file descriptors */
+	int fd;
+	File *file;
+	if (flags & CLONE_FILES) {
+		child->files = parent->files;
+		child->files->usage++;
+	} else {
+		child->files = kmalloc(sizeof(Files));
+		child->files->usage = 1;
+		for (fd = 0; fd < NFILES; fd++) {
+			file = parent->files->fd[fd];
+			if (!file) continue;
+			child->files->fd[fd] = file_get(file);
+		}
+	}
+
+	/* Clone parent's file system context */
+	if (flags & CLONE_FS) {
+		child->fs = parent->fs;
+		child->fs->usage++;
+	} else {
+		child->fs = kmalloc(sizeof(FileSystem));
+		child->fs->usage = 1;
+		child->fs->cwd = parent->fs->cwd;
+		child->fs->cwd->usage++;
+		init_custody_chain(&child->fs->cwdCustody);
+		copy_custody_chain(&parent->fs->cwdCustody,
+		                   &child->fs->cwdCustody);
+		child->fs->root = parent->fs->root;
+		child->fs->root->usage++;
+	}
+
+	/* Clone page directory */
+	if (flags & CLONE_VM) {
+		child->vm = parent->vm;
+		child->vm->usage++;
+	} else {
+		child->vm = kmalloc(sizeof(VirtualMemory));
+		child->vm->usage = 1;
+	}
+	child->pageDir = clone_dir();
+
+	/* Clone parent's VM Regions in child */
+	VMRegion *head;
+	Page *page;
+	off_t i;
+	if (child->vm != parent->vm)
+		child->vm->regions = vm_clone_regions(parent->vm->regions);
+	child->stack = kmalloc(sizeof(VMRegion));
+	memcpy(child->stack, parent->stack, sizeof(VMRegion));
+	child->stack->next = child->stack->prev = NULL;
+	/* Copy stack */
+	if (parent->stack && parent->stack->front) {
+		file = kmalloc(sizeof(File));
+		file->inode = inode_get(kmalloc(sizeof(Inode)));
+		file->ops = &tmpfsFileOps;
+		child->stack->front = file_get(file);
+		for (i = 0; i < child->stack->end - child->stack->start;
+		     i += 0x1000) {
+			page = page_find(parent->stack->front->inode, i);
+			if (page)
+				page_add(file->inode, page);
+		}
+	}
+	/* Copy thread local storage */
+	if (parent->tls) {
+		child->tls = kmalloc(sizeof(VMRegion));
+		memcpy(child->tls, parent->tls, sizeof(VMRegion));
+		child->tls->next = child->tls->prev = NULL;
+		if (parent->tls->front) {
+			file = kmalloc(sizeof(File));
+			file->inode = inode_get(kmalloc(sizeof(Inode)));
+			file->ops = &tmpfsFileOps;
+			child->tls->front = file_get(file);
+			for (i = 0; i < child->tls->end - child->tls->start;
+			     i += 0x1000) {
+				page = page_find(parent->tls->front->inode, i);
+				if (page)
+					page_add(file->inode, page);
+			}
+		}
+		if (parent->tls->back)
+			child->tls->back = file_get(parent->tls->back);
+	}
+
+	/* Split tasks here */
+	uintptr_t esp, ebp, eip;
+	eip = read_eip();
+	if (current == parent) {
+		asm volatile("mov %%esp, %0" : "=r" (esp));
+		asm volatile("mov %%ebp, %0" : "=r" (ebp));
+		child->esp = esp;
+		child->ebp = ebp;
+		child->eip = eip;
+		add_to_queue(&readyQueue, child);
+		return child->tid;
+	}
+	return 0;
+}
+
+/* Terminate the current task */
+void
+terminate(void)
+{
+	/* Close files */
+	int fd;
+	if (--current->files->usage == 0) {
+		for (fd = 0; fd < NFILES; fd++)
+			if (current->files->fd[fd])
+				close(fd);
+		kfree(current->files);
+	}
+	if (current->executable)
+		file_put(current->executable);
+
+	/* Clean File System info */
+	if (--current->fs->usage == 0)
+		kfree(current->fs);
+
+	/* Clean VM Regions and unreferenced VM Objects */
+	VMRegion *head;
+	if (--current->vm->usage == 0) {
+		for (head = current->vm->regions; head; head = head->next)
+			vm_destroy_region(head);
+		kfree(current->vm);
+	}
+	vm_destroy_region(current->stack);
+
+	/* Clean unread IPC messages */
+	/* TODO */
+
+	/* Clean signals */
+	/* TODO */
+
+	/* Deschedule */
+	current->state = TERMINATED;
+	acquire(&readyQueue.lock);
+	Task *tmp, *next;
+	for (tmp = current->waiting.start; tmp; tmp = next) {
+		next = tmp->next;
+		add_to_queue(&readyQueue, tmp);
+	}
+	release(&readyQueue.lock);
+	schedule();
+	panic("Unreached");
+
+	/* Clean task - FIXME */
+	kfree(current->name);
+	kfree(current);
+	clean_dir();
+	schedule();
+	/* UNREACHED */
+}
+
+/* Exit the current task */
+void
+exit(int status)
+{
+	if (current->tid == 1)
+		panic("Attempted to exit init! Exit code %d", status);
+	current->status = (1 << 31) | (status & 0x0F);
+	terminate();
+}
+
+/* Wait for a child process to change state */
+pid_t
+waitpid(pid_t pid, int *wstatus, int options)
+{
+	if (!verify_access(wstatus, sizeof(int), PROT_WRITE))
+		return -EFAULT;
+
+	Task *task = find_task(pid);
+	if (!task)
+		return -ECHILD;
+	if (task->ppid != current->tgid && task->tgid != current->tgid)
+		return -ECHILD;
+
+	if (task->state != TERMINATED) {
+		add_to_queue(&task->waiting, current);
+		block_task(WAITING_FOR_CHILD);
+	}
+
+	if (wstatus)
+		*wstatus = task->status;
+	return task->tid;
+}
+
+/* Get current task's PID */
+pid_t
+getpid(void)
+{
+	return current->tgid;
+}
+
+/* Get current task's UID */
+uid_t
+getuid(void)
+{
+	return current->uid;
+}
+
+/* Set current task's (E)UID */
+int
+setuid(uid_t uid)
+{
+	if (uid != current->uid && uid != current->suid && !super_user())
+		return -EPERM;
+	if (super_user()) {
+		current->uid = uid;
+		current->suid = uid;
+	}
+	current->euid = uid;
+	return 0;
+}
+
+/* Get current task's EUID */
+uid_t
+geteuid(void)
+{
+	return current->euid;
+}
+
+/* Set the current task's EUID */
+int
+seteuid(uid_t euid)
+{
+	if (euid != current->uid
+	 && euid != current->euid
+	 && euid != current->suid
+	 && !super_user())
+		return -EPERM;
+	current->euid = euid;
+	return 0;
+}
+
+/* Get current task's GID */
+gid_t
+getgid(void)
+{
+	return current->gid;
+}
+
+/* Set current task's (E)GID */
+int
+setgid(gid_t gid)
+{
+	if (gid != current->gid
+	 && gid != current->sgid
+	 && !super_user())
+		return -EPERM;
+	if (super_user()) {
+		current->gid = gid;
+		current->sgid = gid;
+	}
+	current->egid = gid;
+	return 0;
+}
+
+/* Get current task's EGID */
+gid_t
+getegid(void)
+{
+	return current->egid;
+}
+
+/* Set the current task's EUID */
+int
+setegid(gid_t egid)
+{
+	if (egid != current->gid
+	 && egid != current->egid
+	 && egid != current->sgid
+	 && !super_user())
+		return -EPERM;
+	current->egid = egid;
+	return 0;
+}
+
+/* Initialse tasking */
+void
+init_tasking(void)
+{
+	move_stack((void *) (0xF0800000 - sizeof(uintptr_t)), 0x2000);
+
+	/* Initialise the Kernel Task */
+	tasks.start = tasks.end = current = kmalloc(sizeof(Task));
+	current->tid = nextPid++;
+	current->tgid = current->tid;
+	current->priority = NORMAL;
+	current->name = kmalloc(7);
+	current->state = RUNNING;
+	memcpy(current->name, "kernel", 7);
+	current->pageDir = kernelDir;
+
+	/* Files Namespace */
+	current->files = kmalloc(sizeof(Files));
+	current->files->usage = 1;
+
+	/* File System Namespace */
+	current->fs = kmalloc(sizeof(FileSystem));
+	init_custody_chain(&current->fs->cwdCustody);
+	current->fs->usage = 1;
+
+	/* Virtual Memory Namespace */
+	current->vm = kmalloc(sizeof(Files));
+	current->vm->regions = NULL;
+	current->vm->usage = 1;
+
+	/* Inter-Process Communication Namespace */
+
+	/* Signals Namespace */
+
+	register_interrupt(0, timer_handler);
+}