summaryrefslogtreecommitdiff
path: root/kern/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'kern/timer.c')
-rw-r--r--kern/timer.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/kern/timer.c b/kern/timer.c
new file mode 100644
index 0000000..7f39f06
--- /dev/null
+++ b/kern/timer.c
@@ -0,0 +1,74 @@
+/** @file timer.c
+ *
+ * @brief timer functions.
+ *
+ * @author Hanjie Wu (hanjiew)
+ * @bug No functional bugs
+ */
+
+#include <common_kern.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <assert.h>
+#include <x86/asm.h>
+#include <x86/interrupt_defines.h>
+#include <x86/timer_defines.h>
+
+#include <interrupt.h>
+#include <sched.h>
+#include <sync.h>
+#include <timer.h>
+
+unsigned int ticks = 0;
+
+spl_t timer_lock = SPL_INIT;
+
+heap_t timers;
+
+/* we want a 2ms thread switch but since sometimes interrupts are disabled, we
+ * set a higher rate to compensate this
+ */
+#define TIMER_FREQ 1000
+
+void timer_init() {
+ int counter = TIMER_RATE / TIMER_FREQ;
+ outb(TIMER_MODE_IO_PORT, TIMER_SQUARE_WAVE);
+ outb(TIMER_PERIOD_IO_PORT, counter & 0xFF);
+ outb(TIMER_PERIOD_IO_PORT, (counter >> 8) & 0xFF);
+ if (heap_init(&timers) != 0) {
+ panic("no space to initialize timer heap");
+ }
+}
+
+/**
+ * @brief check expired timers
+ */
+static void check_timers() {
+ int old_if = spl_lock(&timer_lock);
+ heap_node_t* node;
+ while ((node = heap_peak(&timers)) != NULL) {
+ if (node->key > ticks) {
+ break;
+ }
+ thread_t* t = (thread_t*)node->value;
+ heap_pop(&timers);
+ int old_if2 = spl_lock(&ready_lock);
+ insert_ready_tail(t);
+ spl_unlock(&ready_lock, old_if2);
+ }
+ spl_unlock(&timer_lock, old_if);
+}
+
+void timer_handler_real() {
+ pic_acknowledge(TIMER_IRQ);
+ ticks++;
+ check_timers();
+ int old_if = spl_lock(&ready_lock);
+ thread_t* current = get_current();
+ if (current != get_idle()) {
+ insert_ready_tail(current);
+ }
+ thread_t* t = select_next();
+ yield_to_spl_unlock(t, &ready_lock, old_if);
+}