aboutsummaryrefslogtreecommitdiff
path: root/src/kernel/core
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2015-03-02 17:55:31 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2015-03-02 17:55:31 +0100
commitb68881abc4c50bbc8ee9e81b4e18b0ea011b83b7 (patch)
tree56af7d51db555183d62c3c50c614c8775efc6aa7 /src/kernel/core
parentf610cb7baa26b2803fce8b6e4604e8639c71d1d3 (diff)
downloadkogata-b68881abc4c50bbc8ee9e81b4e18b0ea011b83b7.tar.gz
kogata-b68881abc4c50bbc8ee9e81b4e18b0ea011b83b7.zip
Setup critical section management for parts that must not be interrupted.
Diffstat (limited to 'src/kernel/core')
-rw-r--r--src/kernel/core/idt.c4
-rw-r--r--src/kernel/core/thread.c61
-rw-r--r--src/kernel/core/worker.c2
3 files changed, 38 insertions, 29 deletions
diff --git a/src/kernel/core/idt.c b/src/kernel/core/idt.c
index d34d03f..5c77502 100644
--- a/src/kernel/core/idt.c
+++ b/src/kernel/core/idt.c
@@ -107,6 +107,8 @@ void idt_ex_handler(registers_t *regs) {
/* Called in interrupt.s when an IRQ fires (interrupt 32 to 47) */
void idt_irq_handler(registers_t *regs) {
+ int st = enter_critical(CL_EXCL); // if someone tries to yield(), an assert will fail
+
if (regs->err_code > 7) {
outb(0xA0, 0x20);
}
@@ -116,6 +118,8 @@ void idt_irq_handler(registers_t *regs) {
if (irq_handlers[regs->err_code] != 0) {
irq_handlers[regs->err_code](regs);
}
+
+ exit_critical(st);
}
/* Caled in interrupt.s when a syscall is called */
diff --git a/src/kernel/core/thread.c b/src/kernel/core/thread.c
index 60dccde..5d2abae 100644
--- a/src/kernel/core/thread.c
+++ b/src/kernel/core/thread.c
@@ -30,19 +30,30 @@ void set_pit_frequency(uint32_t freq) {
outb(0x40, h);
}
-// ============================= //
-// HELPER : IF FLAG MANIPULATION //
-// ============================= //
+// =========================== //
+// CRITICAL SECTION MANAGEMENT //
+// =========================== //
-static inline bool disable_interrupts() {
- uint32_t eflags;
- asm volatile("pushf; pop %0" : "=r"(eflags));
+int enter_critical(int level) {
asm volatile("cli");
- return (eflags & EFLAGS_IF) != 0;
+
+ if (current_thread == 0) return CL_EXCL;
+
+ int prev_level = current_thread->critical_level;
+ if (level > prev_level) current_thread->critical_level = level;
+
+ if (current_thread->critical_level < CL_NOINT) asm volatile("sti");
+
+ return prev_level;
}
-static inline void resume_interrupts(bool st) {
- if (st) asm volatile("sti");
+void exit_critical(int prev_level) {
+ asm volatile("cli");
+
+ if (current_thread == 0) return;
+
+ if (prev_level < current_thread->critical_level) current_thread->critical_level = prev_level;
+ if (current_thread->critical_level < CL_NOINT) asm volatile("sti");
}
// ================== //
@@ -89,8 +100,8 @@ void run_scheduler() {
if (current_thread->proc) current_thread->proc->last_ran = current_thread->last_ran;
enqueue_thread(current_thread, true);
}
-
current_thread = dequeue_thread();
+
if (current_thread != 0) {
set_kernel_stack(current_thread->stack_region->addr + current_thread->stack_region->size);
resume_context(&current_thread->ctx);
@@ -100,7 +111,6 @@ void run_scheduler() {
// At this point an IRQ has happenned
// and has been processed. Loop around.
run_scheduler();
- ASSERT(false);
}
}
@@ -151,6 +161,7 @@ thread_t *new_thread(entry_t entry, void* data) {
// used by user processes
t->proc = 0;
t->user_ex_handler = 0;
+ t->critical_level = CL_USER;
return t;
}
@@ -161,7 +172,7 @@ thread_t *new_thread(entry_t entry, void* data) {
static void irq0_handler(registers_t *regs) {
worker_notify_time(1000000 / TASK_SWITCH_FREQUENCY);
- if (current_thread != 0) {
+ if (current_thread != 0 && current_thread->critical_level == CL_USER) {
save_context_and_enter_scheduler(&current_thread->ctx);
}
}
@@ -172,7 +183,8 @@ void threading_setup(entry_t cont, void* arg) {
thread_t *t = new_thread(cont, arg);
ASSERT(t != 0);
- resume_thread(t, false);
+ resume_thread(t);
+ exit_critical(CL_USER);
run_scheduler(); // never returns
ASSERT(false);
@@ -183,28 +195,22 @@ void threading_setup(entry_t cont, void* arg) {
// ======================= //
void yield() {
- if (current_thread == 0) {
- // might happen before threading is initialized
- // (but should not...)
- dbg_printf("Warning: probable deadlock.\n");
- } else {
- save_context_and_enter_scheduler(&current_thread->ctx);
- }
+ ASSERT(current_thread != 0 && current_thread->critical_level != CL_EXCL);
+
+ save_context_and_enter_scheduler(&current_thread->ctx);
}
void pause() {
- bool st = disable_interrupts();
+ ASSERT(current_thread != 0 && current_thread->critical_level != CL_EXCL);
current_thread->state = T_STATE_PAUSED;
save_context_and_enter_scheduler(&current_thread->ctx);
-
- resume_interrupts(st);
}
void usleep(int usecs) {
void sleeper_resume(void* t) {
thread_t *thread = (thread_t*)t;
- resume_thread(thread, true);
+ resume_thread(thread);
}
if (current_thread == 0) return;
bool ok = worker_push_in(usecs, sleeper_resume, current_thread);
@@ -218,19 +224,18 @@ void exit() {
ASSERT(false);
}
-bool resume_thread(thread_t *thread, bool run_at_once) {
+bool resume_thread(thread_t *thread) {
bool ret = false;
- bool st = disable_interrupts();
+ int st = enter_critical(CL_NOINT);
if (thread->state == T_STATE_PAUSED) {
ret = true;
thread->state = T_STATE_RUNNING;
enqueue_thread(thread, false);
}
- if (run_at_once) yield();
- resume_interrupts(st);
+ exit_critical(st);
return ret;
}
diff --git a/src/kernel/core/worker.c b/src/kernel/core/worker.c
index 4be2f93..4f37b22 100644
--- a/src/kernel/core/worker.c
+++ b/src/kernel/core/worker.c
@@ -88,7 +88,7 @@ void worker_notify_time(int usecs) {
time += usecs;
if (next_task_time <= time) {
for (int i = 0; i < nworkers; i++) {
- if (resume_thread(workers[i], false)) break;
+ if (resume_thread(workers[i])) break;
}
}
}