Nucleus
Barry Fixed scheduler double-schedule bug 6063f66 (3 years, 2 months ago)
diff --git a/include/nucleus/task.h b/include/nucleus/task.h
index 5c3d606..17b5c09 100644
--- a/include/nucleus/task.h
+++ b/include/nucleus/task.h
@@ -39,7 +39,7 @@ struct Task {
enum Priority priority;
enum State state;
uint32_t inCriticalSection;
- uint8_t inSyscall;
+ uint32_t inSyscall;
uintptr_t esi, edi, ebx;
uintptr_t esp, ebp, eip;
@@ -83,8 +83,24 @@ exit_critical_section(void)
__atomic_sub_fetch(¤t->inCriticalSection, 1, __ATOMIC_RELAXED);
}
+/* Enter system call context */
+static inline void
+enter_syscall_context(uint32_t syscall)
+{
+ current->inSyscall = syscall;
+}
+/* Exit system call context */
+static inline uint32_t
+exit_syscall_context(void)
+{
+ uint32_t syscall = current->inSyscall;
+ current->inSyscall = 0;
+ return syscall;
+}
+
void init_tasking(void);
void block_task(enum State reason, ObjectList *list);
+void unblock_task(Task *task);
Task *find_task(pid_t tid);
void schedule(void);
pid_t clone(int flags);
diff --git a/task/clone.c b/task/clone.c
index 7516f18..fe0ad88 100644
--- a/task/clone.c
+++ b/task/clone.c
@@ -20,6 +20,11 @@ clone(int flags)
Task *parent = current, *child = new(&taskType), *tmp;
pid_t tid = 0;
+ if (flags & CLONE_THREAD) {
+ flags |= CLONE_PARENT;
+ flags |= CLONE_VM;
+ }
+
/* Clone parent's file system namespace */
if (flags & CLONE_FS)
child->fs = get(parent->fs);
diff --git a/task/exec.c b/task/exec.c
index 8f7da4e..d4b4c3d 100644
--- a/task/exec.c
+++ b/task/exec.c
@@ -132,7 +132,7 @@ execve(const char *file, char *argv[], char *envp[])
* POINT OF NO RETURN
*/
- current->inSyscall = 0;
+ exit_syscall_context();
/* Store everything (pointers adjusted) in temporary buffer */
uintptr_t esp = 0xE0000000 - ssz;
diff --git a/task/exit.c b/task/exit.c
index 52547b9..4069775 100644
--- a/task/exit.c
+++ b/task/exit.c
@@ -4,11 +4,9 @@
* tasks and the parent.
*/
-#include <nucleus/panic.h>
+#include <nucleus/kernel.h>
#include <nucleus/task.h>
-extern ObjectList *readyQueue[];
-
/* Terminate the current task */
_Noreturn void
terminate(void)
@@ -20,7 +18,7 @@ terminate(void)
Task *tmp;
while (current->wait && count(current->wait)) {
tmp = pop_from_start(current->wait);
- add(readyQueue[tmp->priority], tmp);
+ unblock_task(tmp);
put(tmp);
}
diff --git a/task/scheduler.c b/task/scheduler.c
index dc7551f..485301e 100644
--- a/task/scheduler.c
+++ b/task/scheduler.c
@@ -6,7 +6,7 @@
* available. This avoids the need for an idle task.
*/
-#include <nucleus/panic.h>
+#include <nucleus/kernel.h>
#include <nucleus/task.h>
#define PRIORITY_COUNT 6
@@ -28,7 +28,11 @@ switch_to_task(Task *task)
}
/* Switch to new context */
+ uintptr_t eip, esp, ebp;
current = task; /* Given reference, so no get() */
+ eip = current->eip;
+ esp = current->esp;
+ ebp = current->ebp;
asm volatile (
"cli;"
"movl %0, %%ecx;"
@@ -37,8 +41,8 @@ switch_to_task(Task *task)
"movl %3, %%cr3;"
"sti;"
"jmp *%%ecx"
- :: "g" (current->eip), "g" (current->esp),
- "g" (current->ebp), "g" (current->pageDir)
+ :: "g" (eip), "g" (esp),
+ "g" (ebp), "g" (current->pageDir)
);
end:
/* This prevents GCC from optimising the jump to be after the return */
@@ -82,6 +86,8 @@ schedule(void)
/* Schedule next task */
task = pop_from_start(queue);
task->state = RUNNING;
+ if (task == current)
+ return;
if (current && current->state == RUNNING) {
current->state = READY;
add(readyQueue[current->priority], current);
diff --git a/task/task.c b/task/task.c
index a4d137d..597df30 100644
--- a/task/task.c
+++ b/task/task.c
@@ -29,6 +29,7 @@ ObjectType taskType = {
Task *currentTask[MAX_CPUS];
pid_t nextTid = 1;
extern char stackTop[];
+extern ObjectList *readyQueue[];
/* Create a new Task */
static void
@@ -131,6 +132,16 @@ block_task(enum State reason, ObjectList *list)
schedule();
}
+/* Unblock a task */
+void
+unblock_task(Task *task)
+{
+ lock(task);
+ task->state = READY;
+ add(readyQueue[task->priority], task);
+ unlock(task);
+}
+
/* Find a task by ID */
Task *
find_task(pid_t tid)