rustubs/proc/sync/
semaphore.rs1use super::L2_GUARD;
2use crate::arch::x86_64::is_int_enabled;
3use crate::proc::task::{Task, TaskId};
4use crate::Scheduler;
5use alloc::collections::VecDeque;
6use core::sync::atomic::Ordering;
7use core::{cell::SyncUnsafeCell, sync::atomic::AtomicU64};
8
9pub trait Semaphore<T, E>
10where
11 T: ResourceMan<E>,
12 E: Copy + Clone,
13{
14 fn p(&self) -> Option<E>;
16 fn v(&self, e: E);
19 fn is_empty(&self) -> bool;
21 fn is_full(&self) -> bool;
23 unsafe fn p_unguarded(&self) -> Option<E> { return None; }
26 #[allow(unused_variables)]
27 unsafe fn v_unguarded(&self, e: E) {}
28}
29
30pub trait ResourceMan<E>
34where E: Copy + Clone
35{
36 fn get_resource(&mut self) -> Option<E>;
37 fn insert_resource(&mut self, e: E) -> bool;
38}
39
40impl<E> ResourceMan<E> for VecDeque<E>
41where E: Copy + Clone
42{
43 fn get_resource(&mut self) -> Option<E> { self.pop_front() }
44 fn insert_resource(&mut self, e: E) -> bool {
45 self.push_back(e);
46 true
49 }
50}
51
52pub struct SleepSemaphore<T> {
53 pub resource_pool: SyncUnsafeCell<T>,
54 pub sema: AtomicU64,
55 pub wait_room: SyncUnsafeCell<VecDeque<TaskId>>,
58}
59
60impl<T> SleepSemaphore<T> {
61 pub const fn new(t: T) -> Self {
62 Self {
63 resource_pool: SyncUnsafeCell::new(t),
64 sema: AtomicU64::new(0),
65 wait_room: SyncUnsafeCell::new(VecDeque::new()),
66 }
67 }
68
69 unsafe fn wait(&self) {
70 let wq = &mut *self.wait_room.get();
71 Task::curr_wait_in(wq);
72 debug_assert!(is_int_enabled());
73 Scheduler::yield_cpu();
74 }
75
76 unsafe fn wakeup_one(&self) {
77 let wq = &mut *self.wait_room.get();
78 if let Some(t) = wq.pop_front() {
79 t.get_task_ref_mut().wakeup();
80 }
81 }
82
83 pub unsafe fn get_pool_mut(&self) -> &mut T {
84 &mut (*self.resource_pool.get())
85 }
86}
87
88impl<T, E> Semaphore<T, E> for SleepSemaphore<T>
89where
90 T: ResourceMan<E>,
91 E: Copy + Clone,
92{
93 fn p(&self) -> Option<E> {
94 L2_GUARD.lock();
95 unsafe { return self.p_unguarded() };
96 }
97 fn v(&self, e: E) {
98 L2_GUARD.lock();
99 unsafe { self.v_unguarded(e) };
100 }
101 unsafe fn p_unguarded(&self) -> Option<E> {
102 let mut c: u64;
103 loop {
104 c = self.sema.load(Ordering::Relaxed);
105 if c == 0 {
106 unsafe { self.wait() };
107 continue;
108 }
109
110 let r = self.sema.compare_exchange(
111 c,
112 c - 1,
113 Ordering::Acquire,
114 Ordering::Relaxed,
115 );
116 match r {
117 Ok(_) => break,
118 Err(_) => continue,
119 }
120 }
121
122 let thing = (*self.resource_pool.get()).get_resource();
123 return thing;
124 }
125 unsafe fn v_unguarded(&self, e: E) {
126 (*self.resource_pool.get()).insert_resource(e);
127 let _ = self.sema.fetch_add(1, Ordering::SeqCst);
128 self.wakeup_one();
129 }
130 fn is_empty(&self) -> bool { todo!() }
131 fn is_full(&self) -> bool { todo!() }
132}