hermit/syscalls/
spinlock.rs

1use alloc::boxed::Box;
2
3use hermit_sync::{InterruptTicketMutex, InterruptTicketMutexGuard, TicketMutex, TicketMutexGuard};
4
5use crate::errno::*;
6
7pub struct SpinlockContainer<'a> {
8	lock: TicketMutex<()>,
9	guard: Option<TicketMutexGuard<'a, ()>>,
10}
11
12pub struct SpinlockIrqSaveContainer<'a> {
13	lock: InterruptTicketMutex<()>,
14	guard: Option<InterruptTicketMutexGuard<'a, ()>>,
15}
16
17#[hermit_macro::system]
18#[unsafe(no_mangle)]
19pub unsafe extern "C" fn sys_spinlock_init(lock: *mut *mut SpinlockContainer<'_>) -> i32 {
20	if lock.is_null() {
21		return -EINVAL;
22	}
23
24	let boxed_container = Box::new(SpinlockContainer {
25		lock: TicketMutex::new(()),
26		guard: None,
27	});
28	unsafe {
29		*lock = Box::into_raw(boxed_container);
30	}
31	0
32}
33
34#[hermit_macro::system]
35#[unsafe(no_mangle)]
36pub unsafe extern "C" fn sys_spinlock_destroy(lock: *mut SpinlockContainer<'_>) -> i32 {
37	if lock.is_null() {
38		return -EINVAL;
39	}
40
41	// Consume the lock into a box, which is then dropped.
42	unsafe {
43		drop(Box::from_raw(lock));
44	}
45	0
46}
47
48#[hermit_macro::system]
49#[unsafe(no_mangle)]
50pub unsafe extern "C" fn sys_spinlock_lock(lock: *mut SpinlockContainer<'_>) -> i32 {
51	if lock.is_null() {
52		return -EINVAL;
53	}
54
55	let container = unsafe { &mut *lock };
56	assert!(
57		container.guard.is_none(),
58		"Called sys_spinlock_lock when a lock is already held!"
59	);
60	container.guard = Some(container.lock.lock());
61	0
62}
63
64#[hermit_macro::system]
65#[unsafe(no_mangle)]
66pub unsafe extern "C" fn sys_spinlock_unlock(lock: *mut SpinlockContainer<'_>) -> i32 {
67	if lock.is_null() {
68		return -EINVAL;
69	}
70
71	let container = unsafe { &mut *lock };
72	assert!(
73		container.guard.is_some(),
74		"Called sys_spinlock_unlock when no lock is currently held!"
75	);
76	container.guard = None;
77	0
78}
79
80#[hermit_macro::system]
81#[unsafe(no_mangle)]
82pub unsafe extern "C" fn sys_spinlock_irqsave_init(
83	lock: *mut *mut SpinlockIrqSaveContainer<'_>,
84) -> i32 {
85	if lock.is_null() {
86		return -EINVAL;
87	}
88
89	let boxed_container = Box::new(SpinlockIrqSaveContainer {
90		lock: InterruptTicketMutex::new(()),
91		guard: None,
92	});
93	unsafe {
94		*lock = Box::into_raw(boxed_container);
95	}
96	0
97}
98
99#[hermit_macro::system]
100#[unsafe(no_mangle)]
101pub unsafe extern "C" fn sys_spinlock_irqsave_destroy(
102	lock: *mut SpinlockIrqSaveContainer<'_>,
103) -> i32 {
104	if lock.is_null() {
105		return -EINVAL;
106	}
107
108	// Consume the lock into a box, which is then dropped.
109	unsafe {
110		drop(Box::from_raw(lock));
111	}
112	0
113}
114
115#[hermit_macro::system]
116#[unsafe(no_mangle)]
117pub unsafe extern "C" fn sys_spinlock_irqsave_lock(lock: *mut SpinlockIrqSaveContainer<'_>) -> i32 {
118	if lock.is_null() {
119		return -EINVAL;
120	}
121
122	let container = unsafe { &mut *lock };
123	assert!(
124		container.guard.is_none(),
125		"Called sys_spinlock_irqsave_lock when a lock is already held!"
126	);
127	container.guard = Some(container.lock.lock());
128	0
129}
130
131#[hermit_macro::system]
132#[unsafe(no_mangle)]
133pub unsafe extern "C" fn sys_spinlock_irqsave_unlock(
134	lock: *mut SpinlockIrqSaveContainer<'_>,
135) -> i32 {
136	if lock.is_null() {
137		return -EINVAL;
138	}
139
140	let container = unsafe { &mut *lock };
141	assert!(
142		container.guard.is_some(),
143		"Called sys_spinlock_irqsave_unlock when no lock is currently held!"
144	);
145	container.guard = None;
146	0
147}