blob: b863c750d273e8434be6f74eaee7d922be258187 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
/** @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 1
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(stack_frame_t* f) {
pic_acknowledge(TIMER_IRQ);
ticks++;
check_timers();
pv_inject_interrupt(f, TIMER_IDT_ENTRY, 0);
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);
}
|