1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use alloc::boxed::Box;

use crate::errno::*;
use crate::synch::semaphore::Semaphore;

/// Create a new, unnamed semaphore.
///
/// This function can be used to get the raw memory location of a semaphore.
///
/// Stores the raw memory location of the new semaphore in parameter `sem`.
/// Returns `0` on success, `-EINVAL` if `sem` is null.
extern "C" fn __sys_sem_init(sem: *mut *mut Semaphore, value: u32) -> i32 {
	if sem.is_null() {
		return -EINVAL;
	}

	// Create a new boxed semaphore and return a pointer to the raw memory.
	let boxed_semaphore = Box::new(Semaphore::new(value as isize));
	unsafe {
		*sem = Box::into_raw(boxed_semaphore);
	}
	0
}

#[no_mangle]
pub extern "C" fn sys_sem_init(sem: *mut *mut Semaphore, value: u32) -> i32 {
	kernel_function!(__sys_sem_init(sem, value))
}

/// Destroy and deallocate a semaphore.
///
/// This function can be used to manually deallocate a semaphore via a reference.
///
/// Returns `0` on success, `-EINVAL` if `sem` is null.
extern "C" fn __sys_sem_destroy(sem: *mut Semaphore) -> i32 {
	if sem.is_null() {
		return -EINVAL;
	}

	// Consume the pointer to the raw memory into a Box again
	// and drop the Box to free the associated memory.
	unsafe {
		drop(Box::from_raw(sem));
	}
	0
}

#[no_mangle]
pub extern "C" fn sys_sem_destroy(sem: *mut Semaphore) -> i32 {
	kernel_function!(__sys_sem_destroy(sem))
}

/// Release a semaphore.
///
/// This function can be used to allow the next blocked waiter to access this semaphore.
/// It will notify the next waiter that `sem` is available.
/// The semaphore is not deallocated after being released.
///
/// Returns `0` on success, or `-EINVAL` if `sem` is null.
extern "C" fn __sys_sem_post(sem: *const Semaphore) -> i32 {
	if sem.is_null() {
		return -EINVAL;
	}

	// Get a reference to the given semaphore and release it.
	let semaphore = unsafe { &*sem };
	semaphore.release();
	0
}

#[no_mangle]
pub extern "C" fn sys_sem_post(sem: *const Semaphore) -> i32 {
	kernel_function!(__sys_sem_post(sem))
}

/// Try to acquire a lock on a semaphore.
///
/// This function does not block if the acquire fails.
/// If the acquire fails (i.e. the semaphore's count is already 0), the function returns immediately.
///
/// Returns `0` on lock acquire, `-EINVAL` if `sem` is null, or `-ECANCELED` if the decrement fails.
extern "C" fn __sys_sem_trywait(sem: *const Semaphore) -> i32 {
	if sem.is_null() {
		return -EINVAL;
	}

	// Get a reference to the given semaphore and acquire it in a non-blocking fashion.
	let semaphore = unsafe { &*sem };
	if semaphore.try_acquire() {
		0
	} else {
		-ECANCELED
	}
}

#[no_mangle]
pub extern "C" fn sys_sem_trywait(sem: *const Semaphore) -> i32 {
	kernel_function!(__sys_sem_trywait(sem))
}

/// Try to acquire a lock on a semaphore, blocking for a given amount of milliseconds.
///
/// Blocks until semaphore is acquired or until wake-up time has elapsed.
///
/// Returns `0` on lock acquire, `-EINVAL` if sem is null, or `-ETIME` on timeout.
extern "C" fn __sys_sem_timedwait(sem: *const Semaphore, ms: u32) -> i32 {
	if sem.is_null() {
		return -EINVAL;
	}

	let delay = if ms > 0 { Some(u64::from(ms)) } else { None };

	// Get a reference to the given semaphore and wait until we have acquired it or the wakeup time has elapsed.
	let semaphore = unsafe { &*sem };
	if semaphore.acquire(delay) {
		0
	} else {
		-ETIME
	}
}

#[no_mangle]
pub extern "C" fn sys_sem_timedwait(sem: *const Semaphore, ms: u32) -> i32 {
	kernel_function!(__sys_sem_timedwait(sem, ms))
}

extern "C" fn __sys_sem_cancelablewait(sem: *const Semaphore, ms: u32) -> i32 {
	sys_sem_timedwait(sem, ms)
}

#[no_mangle]
pub extern "C" fn sys_sem_cancelablewait(sem: *const Semaphore, ms: u32) -> i32 {
	kernel_function!(__sys_sem_cancelablewait(sem, ms))
}