hermit/syscalls/
semaphore.rs1use alloc::boxed::Box;
2
3use crate::errno::Errno;
4use crate::synch::semaphore::Semaphore;
5use crate::syscalls::{CLOCK_REALTIME, sys_clock_gettime};
6use crate::time::timespec;
7
8#[allow(non_camel_case_types)]
9pub type sem_t = *const Semaphore;
10
11#[hermit_macro::system(errno)]
18#[unsafe(no_mangle)]
19pub unsafe extern "C" fn sys_sem_init(sem: *mut sem_t, pshared: i32, value: u32) -> i32 {
20 if sem.is_null() || pshared != 0 {
21 return -i32::from(Errno::Inval);
22 }
23
24 let boxed_semaphore = Box::new(Semaphore::new(value as isize));
26 unsafe {
27 *sem = Box::into_raw(boxed_semaphore);
28 }
29 0
30}
31
32#[hermit_macro::system(errno)]
38#[unsafe(no_mangle)]
39pub unsafe extern "C" fn sys_sem_destroy(sem: *mut sem_t) -> i32 {
40 if sem.is_null() {
41 return -i32::from(Errno::Inval);
42 }
43
44 unsafe {
47 drop(Box::from_raw((*sem).cast_mut()));
48 }
49 0
50}
51
52#[hermit_macro::system(errno)]
60#[unsafe(no_mangle)]
61pub unsafe extern "C" fn sys_sem_post(sem: *mut sem_t) -> i32 {
62 if sem.is_null() {
63 return -i32::from(Errno::Inval);
64 }
65
66 let semaphore = unsafe { &**sem };
68 semaphore.release();
69 0
70}
71
72#[hermit_macro::system(errno)]
79#[unsafe(no_mangle)]
80pub unsafe extern "C" fn sys_sem_trywait(sem: *mut sem_t) -> i32 {
81 if sem.is_null() {
82 return -i32::from(Errno::Inval);
83 }
84
85 let semaphore = unsafe { &**sem };
87 if semaphore.try_acquire() {
88 0
89 } else {
90 -i32::from(Errno::Canceled)
91 }
92}
93
94unsafe fn sem_timedwait(sem: *mut sem_t, ms: u32) -> i32 {
95 if sem.is_null() {
96 return -i32::from(Errno::Inval);
97 }
98
99 let delay = if ms > 0 { Some(u64::from(ms)) } else { None };
100
101 let semaphore = unsafe { &**sem };
103 if semaphore.acquire(delay) {
104 0
105 } else {
106 -i32::from(Errno::Time)
107 }
108}
109
110#[hermit_macro::system(errno)]
116#[unsafe(no_mangle)]
117pub unsafe extern "C" fn sys_sem_timedwait(sem: *mut sem_t, ts: *const timespec) -> i32 {
118 if ts.is_null() {
119 unsafe { sem_timedwait(sem, 0) }
120 } else {
121 let mut current_ts = timespec::default();
122
123 unsafe {
124 sys_clock_gettime(CLOCK_REALTIME, &raw mut current_ts);
125
126 let ts = &*ts;
127 let ms: i64 = (ts.tv_sec - current_ts.tv_sec) * 1000
128 + (i64::from(ts.tv_nsec) - i64::from(current_ts.tv_nsec)) / 1_000_000;
129
130 if ms > 0 {
131 sem_timedwait(sem, ms.try_into().unwrap())
132 } else {
133 0
134 }
135 }
136 }
137}