Add kill_this_thread(), kill thread on return
diff --git a/src/kernel/main.c b/src/kernel/main.c
index 46fc885..6a37471 100644
--- a/src/kernel/main.c
+++ b/src/kernel/main.c
@@ -17,14 +17,13 @@
 			get_task_id(), get_process_id());
 }
 
-void other_thread()
+void other_thread(size_t data)
 {
-	while (true)
-	{
-		greet();
-		for (int i = 0; i < 0xffffff; i++)
-			asm volatile("nop");
-	}
+	kprintf("data is 0x%x\n", data);
+	greet();
+	kprintf("Returning from other_thread\n");
+
+	return;
 }
 
 int kmain(struct multiboot_info *mboot)
@@ -77,19 +76,15 @@
 	init_tasks();
 	kprintf("\ndone initializing tasks\n");
 
-	spawn_thread(other_thread);
+	spawn_thread(other_thread, NULL);
 
-	asm volatile("sti");
+	greet();
 
-	while (true)
-	{
-		greet();
-		for (int i = 0; i < 0xffffff; i++)
-			asm volatile("nop");
-	}
+	asm volatile("cli");
 
 	while (true)
 		asm volatile("hlt");
 
+
 	return 0xCAFEBABE;
 }
diff --git a/src/kernel/task.c b/src/kernel/task.c
index e891ff2..1285a44 100644
--- a/src/kernel/task.c
+++ b/src/kernel/task.c
@@ -32,6 +32,7 @@
 	first_task = last_task = current_task = malloc(sizeof(struct ll_task_i));
 
 	first_task->next = NULL;
+	first_task->prev = NULL;
 	first_task->task = (struct task){
 		.proc = &processes[0],
 		.esp = kernel_esp,
@@ -61,27 +62,26 @@
 	return current_task->task.proc->id;
 }
 
-void spawn_thread(void (*function)())
+void spawn_thread(void (*function)(void *), void *data)
 {
 	asm volatile("cli");
 
 	struct process *proc = current_task->task.proc;
 	// Virtual address of page directory (in kernel memory)
 	uint *dir_v = PHYS_TO_VIRT(proc->page_directory_p);
-	// Virtual location of new stack
-	uint new_stack_base_v = proc->last_stack_pos - sizeof(uint);
+
+	// Virtual location of new stack, with space reserved for argument and
+	// return address to kill_this_thread().
+	uint new_stack_base_v = proc->last_stack_pos;
 	proc->last_stack_pos -= 0x1000;
 
 	// Alloc a new page in the current process mapping to the new stack
 	alloc_page(dir_v, (void *)proc->last_stack_pos);
 
-	// <TEST>: see if we can assign to the new stack memory (ie: did mapping succeed)
-	uint *base = (uint *)new_stack_base_v;
-
-	kprintf("base = 0x%x\n", base);
-
-	*base = 0;
-	// </TEST>
+	new_stack_base_v -= sizeof(uint);
+	*((uint *)new_stack_base_v) = (size_t)data;
+	new_stack_base_v -= sizeof(uint);
+	*((uint *)new_stack_base_v) = (size_t)&kill_this_thread;
 
 	struct ll_task_i *ll_task = malloc(sizeof(struct ll_task_i));
 	memset(ll_task, 0, sizeof(struct ll_task_i));
@@ -93,11 +93,49 @@
 	task->eip = (uint)function;
 
 	last_task->next = ll_task;
+	ll_task->prev = last_task;
 	last_task = ll_task;
 
 	asm volatile("sti");
 }
 
+void kill_this_thread()
+{
+	asm volatile("cli");
+
+	if (current_task->prev == NULL && current_task->next == NULL)
+	{
+		kpanic("You may not kill the last task in the kernel");
+	}
+
+	struct ll_task_i *task = first_task,
+		*old_task = current_task;
+
+	if (current_task->prev != NULL)
+		current_task->prev->next = current_task->next;
+
+	if (current_task->next != NULL)
+	{
+		// If this is NULL, task will be first_task, which can't be the current task
+		// because we know there are more than one task, and this is the last one.
+		current_task->next->prev = current_task->prev;
+		task = current_task->next;
+	}
+
+	if (current_task == first_task)
+		first_task = current_task->next;
+
+	if (current_task == last_task)
+		last_task = current_task->prev;
+
+	current_task = task;
+	free(old_task);
+
+	switch_to_task(&current_task->task);
+
+	asm volatile("sti");
+}
+
 extern void _switch_to_task(uint page_directory, uint eip, uint ebp, uint esp);
 
 void switch_to_task(struct task *task)
diff --git a/src/kernel/task.h b/src/kernel/task.h
index c31162e..ce5b04c 100644
--- a/src/kernel/task.h
+++ b/src/kernel/task.h
@@ -27,7 +27,7 @@
 
 struct ll_task_i
 {
-	struct ll_task_i *next;
+	struct ll_task_i *next, *prev;
 	struct task task;
 };
 
@@ -43,5 +43,7 @@
 // For compatibility I guess
 #define getpid get_process_id
 
-void spawn_thread(void (*function)());
+void spawn_thread(void (*function)(void *), void *data);
+void kill_this_thread();
 extern void switch_task();
+void switch_to_task(struct task *task);