diff options
Diffstat (limited to 'src/kernel/task/task.cpp')
-rw-r--r-- | src/kernel/task/task.cpp | 115 |
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; } |