From 7fde5e61bc7047433bfc1f47229b72d0ccd302e7 Mon Sep 17 00:00:00 2001 From: Alex AUVOLAT Date: Sun, 20 May 2012 16:34:27 +0200 Subject: Correected some nasty tasking bugs. Still not perfect. --- src/kernel/task/sched.cpp | 7 ++- src/kernel/task/task.cpp | 115 ++++++++++++++++++++++++++------------------- src/kernel/task/task.h | 5 ++ src/user/app/test/main.c | 18 +++++-- src/user/app/yosh/main.cpp | 27 ++++++----- 5 files changed, 105 insertions(+), 67 deletions(-) diff --git a/src/kernel/task/sched.cpp b/src/kernel/task/sched.cpp index 36f6783..c17f271 100644 --- a/src/kernel/task/sched.cpp +++ b/src/kernel/task/sched.cpp @@ -26,9 +26,10 @@ static void sched_enqueueIn(thread *t, int qid) { static thread *sched_dequeueFrom(int qid) { if (queue[qid] == 0) return 0; thread *it = queue[qid]; - ASSERT((it->queue_next == 0 && it == last[qid]) || it != last[qid]); + ASSERT((it->queue_next == 0 && it == last[qid]) || (it->queue_next != 0 && it != last[qid])); queue[qid] = it->queue_next; if (queue[qid] == 0) last[qid] = 0; + it->queue_next = 0; return it; } @@ -55,11 +56,15 @@ void sched_remove(thread *t) { for (int i = 0; i < PRIORITIES; i++) { if (queue[i] == t) { queue[i] = t->queue_next; + ASSERT((t->queue_next == 0 && last[i] == t) || (t->queue_next != 0 && last[i] != t)); + if (last[i] == t) last[i] = 0; } else if (queue[i] != 0) { thread *it = queue[i]; while (it->queue_next != 0) { if (it->queue_next == t) { it->queue_next = t->queue_next; + ASSERT((t->queue_next == 0 && last[i] == t) || (t->queue_next != 0 && last[i] != t)); + if (last[i] == t) last[i] = it; break; } it = it->queue_next; 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 *proc_by_pid; -earray *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(12, 32); - proc_retval = new earray(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; } diff --git a/src/kernel/task/task.h b/src/kernel/task/task.h index e6e0c6e..fa748c2 100644 --- a/src/kernel/task/task.h +++ b/src/kernel/task/task.h @@ -34,6 +34,8 @@ class process { size_t stack, data; segment_map *dataseg; + bool finished; + int retval; thread *threads; thread *threads_waiting; // threads waiting for this process to end @@ -45,6 +47,8 @@ class process { void* set_args(char** args); size_t sbrk(ptrdiff_t size); + + void finish(int retval); }; class thread { @@ -59,6 +63,7 @@ class thread { thread *next, *queue_next; //queue_next is used in sched.c thread(class process *proc, thread_entry entry_point, void *data, void *u_esp); + ~thread(); void wakeUp(); }; diff --git a/src/user/app/test/main.c b/src/user/app/test/main.c index d235c57..939a15a 100644 --- a/src/user/app/test/main.c +++ b/src/user/app/test/main.c @@ -1,12 +1,11 @@ #include +#include -int threads = 0; +int threads = 1; void thread_cascade(void* d) { int n = (int)d; - threads ++; - if (d == 0) { //printk("{#} 0 cascade element started => end\n"); printk("*"); @@ -21,6 +20,7 @@ void thread_cascade(void* d) { } //printk("{#} FORK + ...\n"); printk(">"); + threads += 2; thread_new(thread_cascade, (void*)(n - 1)); //printk("{#} FORK - ...\n"); printk("<"); @@ -32,6 +32,13 @@ void thread_cascade(void* d) { threads--; } +void useless_thread(void* d) { + while(1) { + printk("~"); + schedule(); + } +} + int main(char** args) { char**a; if (args != 0) { @@ -44,13 +51,16 @@ int main(char** args) { } printk("(test) Creating thread cascade (total 2**5 = 32 threads)\n"); + thread_new(useless_thread, 0); thread_new(thread_cascade, (void*)5); while (1) { - thread_sleep(100); + schedule(); if (threads == 0) break; } printk("\n(test) Test process exiting. Press the super key to go to the home terminal.\n"); + printf("(test) End.\n"); + return 0; } diff --git a/src/user/app/yosh/main.cpp b/src/user/app/yosh/main.cpp index fc9580c..160e728 100644 --- a/src/user/app/yosh/main.cpp +++ b/src/user/app/yosh/main.cpp @@ -167,8 +167,21 @@ int Main(String *sh_args) { } while (1) { - stdio.printf("\x1b[33m %s \x1b[1m", cwd.c_str()); + // check for background processes that may have finished + int p = 0; + while (p < bg_pr_c) { + int ret = libc::waitpid(bg_pr[p], 0); + if (ret != E_NOT_FINISHED) { + stdio.printf("(yosh) child (pid %i) exited with status %i\n", bg_pr[p], ret); + bg_pr_c--; + bg_pr[p] = bg_pr[bg_pr_c]; + } else { + p++; + } + } + // show prompt + stdio.printf("\x1b[33m %s \x1b[1m", cwd.c_str()); String s = term->readline(); stdio.printf("\x1b[0m"); if (s.size() == 0) continue; @@ -252,18 +265,6 @@ int Main(String *sh_args) { } } } - - int i = 0; - while (i < bg_pr_c) { - int ret = libc::waitpid(bg_pr[i], 0); - if (ret != E_NOT_FINISHED) { - stdio.printf("(yosh) child (pid %i) exited with status %i\n", bg_pr[i], ret); - bg_pr_c--; - bg_pr[i] = bg_pr[bg_pr_c]; - } else { - i++; - } - } } return 0; -- cgit v1.2.3