1use core::{
2 ptr,
3 sync::atomic::{AtomicU32, AtomicU64},
4 time::Duration,
5};
6
7use bitflags::bitflags;
8use twizzler_rt_abi::error::TwzError;
9
10use super::{convert_codes_to_result, twzerr, Syscall};
11use crate::{arch::syscall::raw_syscall, object::ObjID};
12#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
13#[repr(u32)]
14pub enum ThreadSyncOp {
19 Equal = 0,
21}
22
23impl ThreadSyncOp {
24 pub fn check<T: Eq + PartialEq + Ord + PartialOrd>(
26 &self,
27 a: T,
28 b: T,
29 flags: ThreadSyncFlags,
30 ) -> bool {
31 let res = match self {
32 Self::Equal => a == b,
33 };
34
35 if flags.contains(ThreadSyncFlags::INVERT) {
36 !res
37 } else {
38 res
39 }
40 }
41}
42
43bitflags! {
44 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
46 pub struct ThreadSyncFlags: u32 {
47 const INVERT = 1;
49 }
50}
51
52#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
53#[repr(C)]
54pub enum ThreadSyncReference {
57 ObjectRef(ObjID, usize),
58 Virtual(*const AtomicU64),
59 Virtual32(*const AtomicU32),
60}
61unsafe impl Send for ThreadSyncReference {}
62
63impl ThreadSyncReference {
64 pub fn load(&self) -> u64 {
65 match self {
66 ThreadSyncReference::ObjectRef(_, _) => todo!(),
67 ThreadSyncReference::Virtual(p) => {
68 unsafe { &**p }.load(core::sync::atomic::Ordering::SeqCst)
69 }
70 ThreadSyncReference::Virtual32(p) => unsafe { &**p }
71 .load(core::sync::atomic::Ordering::SeqCst)
72 .into(),
73 }
74 }
75
76 pub fn address(&self) -> Option<*mut u8> {
77 match self {
78 ThreadSyncReference::ObjectRef(_, _) => None,
79 ThreadSyncReference::Virtual(p) => Some(*p as *mut u8),
80 ThreadSyncReference::Virtual32(p) => Some(*p as *mut u8),
81 }
82 }
83}
84
85#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
86#[repr(C)]
87pub struct ThreadSyncSleep {
89 pub reference: ThreadSyncReference,
91 pub value: u64,
93 pub op: ThreadSyncOp,
95 pub flags: ThreadSyncFlags,
97}
98
99impl From<(&AtomicU64, u64)> for ThreadSyncSleep {
100 fn from((reference, value): (&AtomicU64, u64)) -> Self {
101 Self {
102 reference: ThreadSyncReference::Virtual(reference),
103 value,
104 op: ThreadSyncOp::Equal,
105 flags: ThreadSyncFlags::empty(),
106 }
107 }
108}
109
110impl From<(*const AtomicU64, u64)> for ThreadSyncSleep {
111 fn from((reference, value): (*const AtomicU64, u64)) -> Self {
112 Self {
113 reference: ThreadSyncReference::Virtual(reference),
114 value,
115 op: ThreadSyncOp::Equal,
116 flags: ThreadSyncFlags::empty(),
117 }
118 }
119}
120
121#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
122#[repr(C)]
123pub struct ThreadSyncWake {
125 pub reference: ThreadSyncReference,
127 pub count: usize,
129}
130
131impl ThreadSyncSleep {
132 pub fn new(
141 reference: ThreadSyncReference,
142 value: u64,
143 op: ThreadSyncOp,
144 flags: ThreadSyncFlags,
145 ) -> Self {
146 Self {
147 reference,
148 value,
149 op,
150 flags,
151 }
152 }
153
154 pub fn ready(&self) -> bool {
155 let st = self.reference.load();
156 match self.op {
157 ThreadSyncOp::Equal => st != self.value,
158 }
159 }
160}
161
162impl ThreadSyncWake {
163 pub fn new(reference: ThreadSyncReference, count: usize) -> Self {
168 Self { reference, count }
169 }
170}
171
172pub type ThreadSyncResult = Result<usize, TwzError>;
174
175#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
176#[repr(C)]
177pub enum ThreadSync {
180 Sleep(ThreadSyncSleep, ThreadSyncResult),
181 Wake(ThreadSyncWake, ThreadSyncResult),
182}
183
184impl ThreadSync {
185 pub fn new_sleep(sleep: ThreadSyncSleep) -> Self {
187 Self::Sleep(sleep, Ok(0))
188 }
189
190 pub fn new_wake(wake: ThreadSyncWake) -> Self {
192 Self::Wake(wake, Ok(0))
193 }
194
195 pub fn get_result(&self) -> ThreadSyncResult {
197 match self {
198 ThreadSync::Sleep(_, e) => *e,
199 ThreadSync::Wake(_, e) => *e,
200 }
201 }
202
203 pub fn ready(&self) -> bool {
204 match self {
205 ThreadSync::Sleep(o, _) => o.ready(),
206 ThreadSync::Wake(_, _) => true,
207 }
208 }
209}
210
211pub fn sys_thread_sync(
230 operations: &mut [ThreadSync],
231 timeout: Option<Duration>,
232) -> Result<usize, TwzError> {
233 let ptr = operations.as_mut_ptr();
234 let count = operations.len();
235 let timeout = timeout
236 .as_ref()
237 .map_or(ptr::null(), |t| t as *const Duration);
238
239 let (code, val) = unsafe {
240 raw_syscall(
241 Syscall::ThreadSync,
242 &[ptr as u64, count as u64, timeout as u64],
243 )
244 };
245 convert_codes_to_result(code, val, |c, _| c != 0, |_, v| v as usize, twzerr)
246}