hermit/syscalls/
semaphore.rs1use alloc::boxed::Box;
2
3use crate::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]
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 -EINVAL;
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]
38#[unsafe(no_mangle)]
39pub unsafe extern "C" fn sys_sem_destroy(sem: *mut sem_t) -> i32 {
40 if sem.is_null() {
41 return -EINVAL;
42 }
43
44 unsafe {
47 drop(Box::from_raw((*sem).cast_mut()));
48 }
49 0
50}
51
52#[hermit_macro::system]
60#[unsafe(no_mangle)]
61pub unsafe extern "C" fn sys_sem_post(sem: *mut sem_t) -> i32 {
62 if sem.is_null() {
63 return -EINVAL;
64 }
65
66 let semaphore = unsafe { &**sem };
68 semaphore.release();
69 0
70}
71
72#[hermit_macro::system]
79#[unsafe(no_mangle)]
80pub unsafe extern "C" fn sys_sem_trywait(sem: *mut sem_t) -> i32 {
81 if sem.is_null() {
82 return -EINVAL;
83 }
84
85 let semaphore = unsafe { &**sem };
87 if semaphore.try_acquire() {
88 0
89 } else {
90 -ECANCELED
91 }
92}
93
94unsafe fn sem_timedwait(sem: *mut sem_t, ms: u32) -> i32 {
95 if sem.is_null() {
96 return -EINVAL;
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) { 0 } else { -ETIME }
104}
105
106#[hermit_macro::system]
112#[unsafe(no_mangle)]
113pub unsafe extern "C" fn sys_sem_timedwait(sem: *mut sem_t, ts: *const timespec) -> i32 {
114 if ts.is_null() {
115 unsafe { sem_timedwait(sem, 0) }
116 } else {
117 let mut current_ts = timespec::default();
118
119 unsafe {
120 sys_clock_gettime(CLOCK_REALTIME, &mut current_ts);
121
122 let ts = &*ts;
123 let ms: i64 = (ts.tv_sec - current_ts.tv_sec) * 1000
124 + (i64::from(ts.tv_nsec) - i64::from(current_ts.tv_nsec)) / 1_000_000;
125
126 if ms > 0 {
127 sem_timedwait(sem, ms.try_into().unwrap())
128 } else {
129 0
130 }
131 }
132 }
133}