1use core::{
2 cell::RefCell,
3 mem,
4 sync::atomic::{AtomicBool, Ordering},
5};
6
7use alloc::{
8 boxed::Box,
9 collections::{BTreeMap, BinaryHeap},
10 vec::Vec,
11};
12use tracing::{info, trace};
13
14use crate::{
15 cpu::{self, idt::InterruptAllSavedState, interrupts},
16 devices::clock::{self, ClockTime},
17 memory_management::virtual_memory_mapper,
18 process::{syscalls, FxSave},
19 sync::spin::mutex::Mutex,
20};
21
22use super::{Process, ProcessContext};
23
24static SCHEDULER: Mutex<Scheduler> = Mutex::new(Scheduler::new());
25static SHUTDOWN: AtomicBool = AtomicBool::new(false);
26
27const MIN_PRIORITY_VALUE: u64 = 100;
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum ProcessState {
33 Running,
34 Scheduled,
35 WaitingForPid(u64),
36 WaitingForTime(ClockTime),
37}
38
39struct SchedulerProcess {
41 process: RefCell<Box<Process>>,
43 state: ProcessState,
44 priority_counter: u64,
45}
46
47impl PartialEq for SchedulerProcess {
48 fn eq(&self, other: &Self) -> bool {
49 self.priority_counter == other.priority_counter
50 }
51}
52
53impl PartialOrd for SchedulerProcess {
54 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
55 Some(self.cmp(other))
56 }
57}
58
59impl Eq for SchedulerProcess {}
60impl Ord for SchedulerProcess {
61 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
62 self.priority_counter.cmp(&other.priority_counter)
63 }
64}
65
66struct Scheduler {
67 interrupt_initialized: bool,
68 scheduled_processes: BinaryHeap<SchedulerProcess>,
69 running_waiting_procs: BTreeMap<u64, SchedulerProcess>,
70 exited_processes: Vec<Process>,
71 max_priority: u64,
72}
73
74impl Scheduler {
75 const fn new() -> Self {
76 Self {
77 interrupt_initialized: false,
78 scheduled_processes: BinaryHeap::new(),
79 running_waiting_procs: BTreeMap::new(),
80 exited_processes: Vec::new(),
81 max_priority: u64::MAX,
82 }
83 }
84
85 pub fn push_process(&mut self, process: Process) {
86 self.reschedule_process(SchedulerProcess {
88 process: RefCell::new(Box::new(process)),
89 state: ProcessState::Scheduled,
90 priority_counter: self.max_priority,
91 })
92 }
93
94 fn init_interrupt(&mut self) {
95 if self.interrupt_initialized {
96 return;
97 }
98 self.interrupt_initialized = true;
99
100 interrupts::create_scheduler_interrupt(scheduler_interrupt_handler);
101 interrupts::create_syscall_interrupt(syscall_interrupt_handler);
102 }
103
104 fn reschedule_process(&mut self, mut process: SchedulerProcess) {
105 if SHUTDOWN.load(Ordering::Acquire) {
106 let mut inner_proc = process.process.into_inner();
107 info!(
108 "Process {} is not rescheduled as the scheduler is shutting down",
109 inner_proc.id
110 );
111 inner_proc.exit(0xFF);
112 self.exited_processes.push(*inner_proc);
113 return;
114 }
115 process.priority_counter = self.max_priority;
116 process.state = ProcessState::Scheduled;
117 self.scheduled_processes.push(process);
118 }
119
120 fn reset_scheduled_processes_counters(&mut self) {
121 let max_priority = u64::MAX;
122 self.scheduled_processes = self
123 .scheduled_processes
124 .drain()
125 .map(|mut p| {
126 p.priority_counter = max_priority;
127 p
128 })
129 .collect::<BinaryHeap<_>>();
130 }
131
132 fn try_wake_waiting_processes(&mut self) {
133 let time_now = clock::clocks().time_since_startup();
134
135 let extracted = self
137 .running_waiting_procs
138 .extract_if(.., |_, process: &mut SchedulerProcess| {
139 let mut remove = false;
140 let mut inner_proc = process.process.borrow_mut();
141 match process.state {
142 ProcessState::WaitingForPid(_) | ProcessState::Running => {
143 self.exited_processes.retain_mut(|exited_proc| {
144 let found_parent = exited_proc.parent_id == inner_proc.id;
145
146 if found_parent {
148 inner_proc.add_child_exit(exited_proc.id, exited_proc.exit_code);
149 }
150
151 if let ProcessState::WaitingForPid(pid) = process.state {
153 if pid == exited_proc.id {
154 remove = true;
155 assert_eq!(
158 inner_proc.context.cs & 0x3,
159 3,
160 "must be from user only"
161 );
162 inner_proc.context.rax = exited_proc.exit_code as u64;
163 }
164 }
165
166 !found_parent
168 });
169 }
170 ProcessState::WaitingForTime(t) => {
171 if t <= time_now {
172 remove = true;
173 }
174 }
175 _ => unreachable!("We can't have Scheduled state here"),
176 }
177 remove
178 })
179 .collect::<Vec<_>>();
180
181 for (_, process) in extracted {
182 self.reschedule_process(process);
183 }
184
185 for exited_proc in self.exited_processes.drain(..) {
188 for process in self.scheduled_processes.iter() {
189 let mut inner_proc = process.process.borrow_mut();
190 if inner_proc.id == exited_proc.parent_id {
191 inner_proc.add_child_exit(exited_proc.id, exited_proc.exit_code);
192 }
193 }
194 }
195
196 self.exited_processes.clear();
198 }
199
200 fn exit_idle_processes(&mut self) {
203 for process in self.scheduled_processes.drain() {
205 let mut inner_proc = process.process.into_inner();
206 info!("Force stopping process {}", inner_proc.id);
207 inner_proc.exit(0);
208 }
209 self.running_waiting_procs
211 .retain(|_, process| match process.state {
212 ProcessState::Running => true,
213 ProcessState::Scheduled
214 | ProcessState::WaitingForPid(_)
215 | ProcessState::WaitingForTime(_) => {
216 let mut inner_proc = process.process.borrow_mut();
217 info!("Force stopping process {}", inner_proc.id);
218 inner_proc.exit(0);
219 false
220 }
221 });
222 }
223}
224
225pub fn push_process(process: Process) {
226 SCHEDULER.lock().push_process(process);
227}
228
229pub fn stop_scheduler() {
232 SHUTDOWN.store(true, Ordering::Relaxed);
233}
234
235pub fn schedule() {
236 SCHEDULER.lock().init_interrupt();
237
238 loop {
239 let current_cpu = cpu::cpu();
240 assert!(current_cpu.context.is_none());
241
242 let mut scheduler = SCHEDULER.lock();
243 let shutdown = SHUTDOWN.load(Ordering::Acquire);
244 if shutdown {
245 scheduler.exit_idle_processes();
246 }
247
248 current_cpu.push_cli();
249
250 scheduler.try_wake_waiting_processes();
251
252 if scheduler
254 .scheduled_processes
255 .peek()
256 .map(|p| p.priority_counter < MIN_PRIORITY_VALUE)
257 .unwrap_or(false)
258 {
259 scheduler.reset_scheduled_processes_counters();
260 }
261
262 let top = scheduler.scheduled_processes.pop();
263
264 if let Some(mut top) = top {
265 assert_eq!(top.state, ProcessState::Scheduled);
266 top.state = ProcessState::Running;
267 let pid;
268 if !shutdown {
269 {
270 let mut inner_proc = top.process.borrow_mut();
271 pid = inner_proc.id;
272
273 let decrement = 6 - inner_proc.priority as u64;
275 top.priority_counter -= decrement;
276
277 scheduler.max_priority = top.priority_counter;
278 unsafe { inner_proc.switch_to_this_vm() };
281 current_cpu.process_id = inner_proc.id;
282 current_cpu.context = Some(inner_proc.context);
283 current_cpu.scheduling = true;
284 }
285 scheduler.running_waiting_procs.insert(pid, top);
286 }
287 }
288
289 current_cpu.pop_cli();
290
291 if shutdown
292 && scheduler.scheduled_processes.is_empty()
293 && scheduler.running_waiting_procs.is_empty()
294 && current_cpu.context.is_none()
295 {
296 break;
297 }
298
299 drop(scheduler);
300
301 if current_cpu.context.is_some() {
302 unsafe { core::arch::asm!("int 0xff", out("rax") _) }
309 unsafe { virtual_memory_mapper::switch_to_kernel() };
311 } else {
312 unsafe { cpu::halt() };
314 }
315 }
316}
317
318fn with_current_process_and_state<F, U>(f: F) -> U
319where
320 F: FnOnce(&mut SchedulerProcess) -> U,
321{
322 let current_cpu = cpu::cpu();
323 let mut scheduler = SCHEDULER.lock();
324 let process = scheduler
325 .running_waiting_procs
326 .get_mut(¤t_cpu.process_id)
327 .expect("current process not found");
328 assert_eq!(process.state, ProcessState::Running);
329 f(process)
330}
331
332unsafe fn take_current_process() -> SchedulerProcess {
336 let current_cpu = cpu::cpu();
337 let process = SCHEDULER
338 .lock()
339 .running_waiting_procs
340 .remove(¤t_cpu.process_id)
341 .expect("current process not found");
342 assert_eq!(process.state, ProcessState::Running);
343 process
344}
345
346pub fn with_current_process<F, U>(f: F) -> U
347where
348 F: FnOnce(&mut Process) -> U,
349{
350 with_current_process_and_state(|p| f(&mut p.process.borrow_mut()))
351}
352
353pub fn with_process<F, U>(pid: u64, f: F) -> U
354where
355 F: FnOnce(&mut Process) -> U,
356{
357 let scheduler = SCHEDULER.lock();
358 let process = scheduler
359 .running_waiting_procs
360 .get(&pid)
361 .unwrap_or_else(|| {
362 scheduler
363 .scheduled_processes
364 .iter()
365 .find(|p| p.process.borrow().id == pid)
366 .expect("process not found")
367 });
368 let r = f(&mut process.process.borrow_mut());
369 r
370}
371
372pub fn exit_current_process(exit_code: i32, all_state: &mut InterruptAllSavedState) {
376 let current_cpu = cpu::cpu();
377 assert!(current_cpu.context.is_some());
378 current_cpu.push_cli();
379
380 let process = unsafe { take_current_process() };
382
383 let mut inner_proc = process.process.into_inner();
384
385 trace!("Process {} exited with code {}", inner_proc.id, exit_code);
386
387 swap_context(current_cpu.context.as_mut().unwrap(), all_state);
388 inner_proc.context = current_cpu.context.take().unwrap();
393 inner_proc.exit(exit_code);
394
395 SCHEDULER.lock().exited_processes.push(*inner_proc);
396
397 current_cpu.pop_cli();
398 }
400
401pub fn sleep_current_process(time: ClockTime, all_state: &mut InterruptAllSavedState) {
402 let current_cpu = cpu::cpu();
403 assert!(current_cpu.context.is_some());
404
405 let deadline = clock::clocks().time_since_startup() + time;
406
407 with_current_process_and_state(|p| {
408 current_cpu.push_cli();
409 let mut inner_proc = p.process.borrow_mut();
410 p.state = ProcessState::WaitingForTime(deadline);
411 trace!(
412 "Process {} is waiting for time {:?}",
413 inner_proc.id,
414 deadline
415 );
416 swap_context(current_cpu.context.as_mut().unwrap(), all_state);
417
418 inner_proc.context = current_cpu.context.take().unwrap();
419 });
420
421 current_cpu.pop_cli();
422 }
424
425pub fn yield_current_if_any(all_state: &mut InterruptAllSavedState) {
426 let current_cpu = cpu::cpu();
427 if current_cpu.context.is_none() || current_cpu.scheduling {
429 return;
430 }
431 current_cpu.push_cli();
432 let process = unsafe { take_current_process() };
434 swap_context(current_cpu.context.as_mut().unwrap(), all_state);
435 process.process.borrow_mut().context = current_cpu.context.take().unwrap();
436
437 SCHEDULER.lock().reschedule_process(process);
438 current_cpu.pop_cli();
439 }
441
442pub fn is_process_running(pid: u64) -> bool {
443 let scheduler = SCHEDULER.lock();
444 scheduler
445 .running_waiting_procs
446 .keys()
447 .cloned()
448 .chain(
449 scheduler
450 .scheduled_processes
451 .iter()
452 .map(|p| p.process.borrow().id),
453 )
454 .any(|id| id == pid)
455}
456
457pub fn wait_for_pid(all_state: &mut InterruptAllSavedState, pid: u64) -> bool {
458 let current_cpu = cpu::cpu();
459 assert!(current_cpu.context.is_some());
460
461 let process_found = is_process_running(pid);
464 if !process_found {
465 return false;
466 }
467
468 with_current_process_and_state(|p| {
469 current_cpu.push_cli();
470 let mut inner_proc = p.process.borrow_mut();
471 p.state = ProcessState::WaitingForPid(pid);
472 trace!("Process {} is waiting for process {}", inner_proc.id, pid);
473
474 swap_context(current_cpu.context.as_mut().unwrap(), all_state);
475 inner_proc.context = current_cpu.context.take().unwrap();
476 });
477
478 current_cpu.pop_cli();
479 true
481}
482
483pub fn swap_context(context: &mut ProcessContext, all_state: &mut InterruptAllSavedState) {
484 let mut fxsave = FxSave::default();
485 unsafe { core::arch::x86_64::_fxsave64(&mut fxsave as *mut FxSave as _) };
486 unsafe { core::arch::x86_64::_fxrstor64(context.fxsave.0.as_ptr() as _) };
487 context.fxsave = fxsave;
488
489 mem::swap(&mut all_state.frame.rflags, &mut context.rflags);
490 mem::swap(&mut all_state.frame.rip, &mut context.rip);
491 all_state.frame.cs = mem::replace(&mut context.cs, all_state.frame.cs as _) as _;
492 mem::swap(&mut all_state.frame.rsp, &mut context.rsp);
493 all_state.frame.ss = mem::replace(&mut context.ss, all_state.frame.ss as _) as _;
494
495 mem::swap(&mut all_state.rest.ds, &mut context.ds);
496 mem::swap(&mut all_state.rest.es, &mut context.es);
497 mem::swap(&mut all_state.rest.fs, &mut context.fs);
498 mem::swap(&mut all_state.rest.gs, &mut context.gs);
499 mem::swap(&mut all_state.rest.dr0, &mut context.dr0);
500 mem::swap(&mut all_state.rest.dr1, &mut context.dr1);
501 mem::swap(&mut all_state.rest.dr2, &mut context.dr2);
502 mem::swap(&mut all_state.rest.dr3, &mut context.dr3);
503 mem::swap(&mut all_state.rest.dr6, &mut context.dr6);
504 mem::swap(&mut all_state.rest.dr7, &mut context.dr7);
505 mem::swap(&mut all_state.rest.rax, &mut context.rax);
506 mem::swap(&mut all_state.rest.rbx, &mut context.rbx);
507 mem::swap(&mut all_state.rest.rcx, &mut context.rcx);
508 mem::swap(&mut all_state.rest.rdx, &mut context.rdx);
509 mem::swap(&mut all_state.rest.rsi, &mut context.rsi);
510 mem::swap(&mut all_state.rest.rdi, &mut context.rdi);
511 mem::swap(&mut all_state.rest.rbp, &mut context.rbp);
512 mem::swap(&mut all_state.rest.r8, &mut context.r8);
513 mem::swap(&mut all_state.rest.r9, &mut context.r9);
514 mem::swap(&mut all_state.rest.r10, &mut context.r10);
515 mem::swap(&mut all_state.rest.r11, &mut context.r11);
516 mem::swap(&mut all_state.rest.r12, &mut context.r12);
517 mem::swap(&mut all_state.rest.r13, &mut context.r13);
518 mem::swap(&mut all_state.rest.r14, &mut context.r14);
519 mem::swap(&mut all_state.rest.r15, &mut context.r15);
520}
521
522extern "C" fn scheduler_interrupt_handler(all_state: &mut InterruptAllSavedState) {
523 assert_eq!(all_state.frame.cs & 0x3, 0, "must be from kernel only");
524 let current_cpu = cpu::cpu();
525 assert!(current_cpu.context.is_some());
526 assert!(current_cpu.scheduling);
527 assert!(current_cpu.interrupts_disabled());
528
529 current_cpu.scheduling = false;
531
532 swap_context(current_cpu.context.as_mut().unwrap(), all_state);
533}
534
535extern "C" fn syscall_interrupt_handler(all_state: &mut InterruptAllSavedState) {
536 assert_eq!(all_state.frame.cs & 0x3, 3, "must be from user only");
537 let current_cpu = cpu::cpu();
538 assert!(current_cpu.context.is_some());
539
540 syscalls::handle_syscall(all_state);
541}