summaryrefslogtreecommitdiff
path: root/src/kernel/task/task.cpp
diff options
context:
space:
mode:
authorAlex AUVOLAT <alexis211@gmail.com>2012-05-20 16:34:27 +0200
committerAlex AUVOLAT <alexis211@gmail.com>2012-05-20 16:34:27 +0200
commit7fde5e61bc7047433bfc1f47229b72d0ccd302e7 (patch)
tree7228e9008ecffa85100ac31ee5063edc62abf41e /src/kernel/task/task.cpp
parentc57a919d019606c7d83fea574159f542e431c199 (diff)
downloadTCE-7fde5e61bc7047433bfc1f47229b72d0ccd302e7.tar.gz
TCE-7fde5e61bc7047433bfc1f47229b72d0ccd302e7.zip
Correected some nasty tasking bugs. Still not perfect.
Diffstat (limited to 'src/kernel/task/task.cpp')
-rw-r--r--src/kernel/task/task.cpp115
1 files changed, 66 insertions, 49 deletions
diff --git a/src/kernel/task/task.cpp b/src/kernel/task/task.cpp
index 3863850..ad9ce50 100644
--- a/src/kernel/task/task.cpp
+++ b/src/kernel/task/task.cpp
@@ -17,15 +17,12 @@
//Static routines for handling threads exiting and all cleanup
static void thread_exit_stackJmp(uint32_t reason);
static void thread_exit2(uint32_t reason);
-static void thread_delete(thread *th);
-static void process_finish(process *pr, int retval);
//From task_.asm
extern "C" uint32_t read_eip();
extern "C" void task_idle(void*);
earray<process> *proc_by_pid;
-earray<void> *proc_retval;
process *kernel_process = 0, *current_process = 0;
thread *current_thread = 0, *idle_thread = 0;
@@ -38,7 +35,6 @@ uint32_t tasking_tmpStack[KSTACKSIZE];
Creates a kernel process and an IDLE thread in it. */
void tasking_init() {
proc_by_pid = new earray<process>(12, 32);
- proc_retval = new earray<void>(12, 32);
cli();
kernel_process = new process();
@@ -47,8 +43,9 @@ void tasking_init() {
kernel_process->privilege = PL_KERNEL;
kernel_process->parent = kernel_process;
kernel_process->pagedir = kernel_pagedir;
- kernel_process->threads = 0;
- kernel_process->threads_waiting = 0;
+ kernel_process->threads = kernel_process->threads_waiting = 0;
+ kernel_process->finished = false;
+ kernel_process->data = kernel_process->stack = 0;
current_thread = 0;
idle_thread = new thread(kernel_process, task_idle, 0, 0);
sti();
@@ -154,7 +151,7 @@ int proc_priv() {
Exits current thread or process, depending on the reason. */
void thread_exit2(uint32_t reason) { //See EX_TH_* defines in task.h
/*
- * if reason == EX_TH_NORMAL, it is just one thread exiting because it has to
+ * if reason == EX_TH_NORMAL, it is just one thread exiting because it has finished
* if reason == EX_TH_EXCEPTION, it is just one thread exiting because of an exception
* if reason is none of the two cases above, it is the whole process exiting (with error code = reason)
*/
@@ -163,19 +160,18 @@ void thread_exit2(uint32_t reason) { //See EX_TH_* defines in task.h
if (th == 0 || th->process == 0) goto retrn;
pr = th->process;
if ((reason == EX_TH_NORMAL || reason == EX_TH_EXCEPTION) && pr->thread_count > 1) {
- thread_delete(th);
+ delete th;
} else {
- process_finish(pr, reason);
+ pr->finish(reason);
}
retrn:
- sti();
schedule();
}
/* For internal use only. Called by thread_exit and process_exit.
Switches to a stack that will not be deleted when current thread is deleted. */
void thread_exit_stackJmp(uint32_t reason) {
- cli();
+ asm volatile("cli");
uint32_t *stack;
stack = tasking_tmpStack + (KSTACKSIZE / 4);
stack--; *stack = reason;
@@ -250,7 +246,6 @@ static void thread_run(void* u_esp, thread *thread, thread_entry entry_point, vo
Sets up the kernel stack for values to be passed to thread_run. */
thread::thread(class process *proc, thread_entry entry_point, void *data, void *u_esp) {
process = proc;
- next = 0;
proc->thread_count++;
if (u_esp == 0) u_esp = (void*)proc->stack;
@@ -270,13 +265,8 @@ thread::thread(class process *proc, thread_entry entry_point, void *data, void *
ebp = esp + 16;
eip = (uint32_t)thread_run;
- if (proc->threads == 0) {
- proc->threads = this;
- } else {
- thread *i = proc->threads;
- while (i->next != 0) i = i->next;
- i->next = this;
- }
+ next = proc->threads;
+ proc->threads = this;
state = TS_RUNNING;
sched_enqueue(this);
@@ -293,6 +283,8 @@ process::process(process* _parent, uint32_t _uid, uint32_t _privilege) : fd(12,
pagedir = pagedir_new();
data = 0;
dataseg = 0;
+ finished = false;
+ retval = E_NOT_FINISHED;
stack = 0;
if (privilege >= PL_USER) { //We are running in user mode
@@ -307,42 +299,41 @@ process::process(process* _parent, uint32_t _uid, uint32_t _privilege) : fd(12,
}
/* Deletes given thread, freeing the stack(s). */
-static void thread_delete(thread *th) {
- sched_remove(th);
- if (th->process->threads == th) {
- th->process->threads = th->next;
+thread::~thread() {
+ sched_remove(this);
+ if (process->threads == this) {
+ process->threads = next;
} else {
- thread *it = th->process->threads;
- while (it) {
- if (it->next == th) {
- it->next = th->next;
- break;
- }
- it = it->next;
- }
+ thread *it = process->threads;
+ ASSERT(it != 0);
+ while (it->next != 0 && it->next != this) it = it->next;
+ ASSERT(it->next = this);
+ it->next = next;
}
- if (current_thread == th) current_thread = 0;
- th->process->thread_count--;
- kfree(th->kernelStack_addr);
- kfree(th);
+ if (current_thread == this) current_thread = 0;
+ process->thread_count--;
+ kfree(kernelStack_addr);
}
/* Deletes a process. First, deletes all its threads. Also deletes the corresponding page directory. */
-static void process_finish(process *pr, int retval) {
- proc_retval->set(pr->pid, (void*)retval);
+void process::finish(int ret) {
+ if (finished) return;
+ finished = true;
- thread *it = pr->threads;
- while (it != 0) {
- thread_delete(it);
- it = it->next;
+ retval = ret;
+
+ while (threads != 0) {
+ delete threads;
}
- pagedir_delete(pr->pagedir);
- proc_by_pid->set(pr->pid, 0);
- while (pr->threads_waiting != 0) {
- pr->threads_waiting->wakeUp();
- pr->threads_waiting = pr->threads_waiting->queue_next;
+ ASSERT(thread_count == 0);
+
+ pagedir_delete(pagedir);
+
+ thread *it = threads_waiting;
+ while (it != 0) {
+ it->wakeUp();
+ it = it->queue_next;
}
- kfree(pr);
proc_count--;
if (proc_count == 0) PANIC("No more processes are running! This is bad! Or is it?");
@@ -476,12 +467,38 @@ int process_waitpid(int pid, int block) {
if (pid <= 0) return E_INVALID_RANGE;
process *p = proc_by_pid->at(pid);
- if (p != 0) {
+ if (p == 0) return E_NOT_FOUND;
+
+ asm volatile("cli");
+ int ret = p->retval;
+
+ if (!p->finished) {
if (block == 0) return E_NOT_FINISHED;
current_thread->queue_next = p->threads_waiting;
p->threads_waiting = current_thread;
thread_goInactive();
+
+ asm volatile("cli");
+ ASSERT(p->finished);
+ ret = p->retval;
+
+ if (p->threads_waiting == current_thread) {
+ p->threads_waiting = current_thread->queue_next;
+ } else {
+ thread *it = p->threads_waiting;
+ ASSERT(it != 0);
+ while (it->queue_next != 0 && it->queue_next != current_thread) it = it->queue_next;
+ ASSERT(it->queue_next == current_thread);
+ it->queue_next = current_thread->queue_next;
+ }
+ current_thread->queue_next = 0;
+ }
+
+ if (p->threads_waiting == 0 && p->parent == current_process) {
+ proc_by_pid->set(pid, 0);
+ delete p;
}
- return (int)proc_retval->at(pid);
+
+ return ret;
}