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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//! Virtual interrupt handlers

use std::thread::{self, Thread};
use std::time::Duration;

use crate::hal::interrupts::HostedInterrupt;
use crate::hal::SYSTEM;

/// Dispatch virtual interrupts, if enabled
///
/// For each interrupt in the queue:
///
/// - Halt the hosted kmain thread (kmain hooks will park the thread)
/// - Call the [`HostedInterrupt::dispatch`] method for the interrupt
/// - Unhalt the hosted kmain thread
/// - Manually unpark the hosted kmain thread
///
/// This function should be spawned in a new thread immediately after spawning
/// the thread running [`hosted_kmain`][crate::host::hosted_kmain].
pub fn dispatcher(kmain_thread: Thread) {
	while !SYSTEM.return_next_iter {
		thread::sleep(Duration::from_millis(20));
		if !SYSTEM.interrupts_enabled {
			continue;
		}

		while let Some(interrupt) = SYSTEM.get().pending_interrupts.pop() {
			trace!("dispatching {:?}", interrupt);

			// Halt the CPU, which will park the thread at the next opportunity
			SYSTEM.get().halted = true;

			// Dispatch the interrupt
			interrupt.dispatch();

			// Unhalt the CPU and manually unpark the thread
			SYSTEM.get().halted = false;
			kmain_thread.unpark();
		}
	}
}

/// Update the system clock and queue tick interrupts
///
/// While the hosted system is running (that is, `!SYSTEM.return_next_iter`):
///
/// - Update [`struct@slos::clock::BOOT_CLOCK`] with the real time passed
///   since the last iteration,
/// - Queue a [`HostedInterrupt::ClockTick`] interrupt,
/// - Sleep the current thread for ~50ms
///
/// This function should be spawned in a new thread immediately after spawning
/// the thread running [`hosted_kmain`][crate::host::hosted_kmain].
pub fn clock_tick() {
	use std::time::{SystemTime, UNIX_EPOCH};

	// Get the current time since epoch as milliseconds, which we'll update
	// each iteration so we have the time since the last update
	let mut previous = SystemTime::now()
		.duration_since(UNIX_EPOCH)
		.unwrap()
		.as_millis();

	while !SYSTEM.return_next_iter {
		// Get the current time since epoch as milliseconds
		let current = SystemTime::now()
			.duration_since(UNIX_EPOCH)
			.unwrap()
			.as_millis();

		// Update the BOOT_CLOCK with the actual amount of time passed
		slos::clock::BOOT_CLOCK
			.get()
			.increment_ms(((current - previous) & u32::MAX as u128) as u32);

		// Push a ClockTick interrupt
		SYSTEM
			.get()
			.pending_interrupts
			.push(HostedInterrupt::ClockTick);

		// Update the previous time variable with the current time, so the next
		// iteration can do the subtraction and get the time since last update
		previous = current;

		// And sleep for 50ms
		thread::sleep(Duration::from_millis(50));
	}
}