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(¤t_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);