summaryrefslogtreecommitdiff
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
parentc57a919d019606c7d83fea574159f542e431c199 (diff)
downloadTCE-7fde5e61bc7047433bfc1f47229b72d0ccd302e7.tar.gz
TCE-7fde5e61bc7047433bfc1f47229b72d0ccd302e7.zip
Correected some nasty tasking bugs. Still not perfect.
-rw-r--r--src/kernel/task/sched.cpp7
-rw-r--r--src/kernel/task/task.cpp115
-rw-r--r--src/kernel/task/task.h5
-rw-r--r--src/user/app/test/main.c18
-rw-r--r--src/user/app/yosh/main.cpp27
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<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;
}
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 <tce/syscall.h>
+#include <stdio.h>
-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;