1use alloc::collections::BTreeMap;
2
3use hermit_sync::InterruptTicketMutex;
4
5use crate::arch::core_local::*;
6use crate::arch::processor::{get_frequency, get_timestamp};
7use crate::config::USER_STACK_SIZE;
8use crate::errno::*;
9use crate::scheduler::PerCoreSchedulerExt;
10use crate::scheduler::task::{Priority, TaskHandle, TaskId};
11use crate::time::timespec;
12use crate::{arch, scheduler};
13
14#[cfg(feature = "newlib")]
15pub type SignalHandler = extern "C" fn(i32);
16pub type Tid = i32;
17
18#[hermit_macro::system]
19#[unsafe(no_mangle)]
20pub extern "C" fn sys_getpid() -> Tid {
21 0
22}
23
24#[cfg(feature = "newlib")]
25#[hermit_macro::system]
26#[unsafe(no_mangle)]
27pub unsafe extern "C" fn sys_getprio(id: *const Tid) -> i32 {
28 let task = core_scheduler().get_current_task_handle();
29
30 if id.is_null() || unsafe { *id } == task.get_id().into() {
31 i32::from(task.get_priority().into())
32 } else {
33 -EINVAL
34 }
35}
36
37#[cfg(feature = "newlib")]
38#[hermit_macro::system]
39#[unsafe(no_mangle)]
40pub unsafe extern "C" fn sys_setprio(_id: *const Tid, _prio: i32) -> i32 {
41 -ENOSYS
42}
43
44fn exit(arg: i32) -> ! {
45 debug!("Exit program with error code {arg}!");
46 super::shutdown(arg)
47}
48
49#[hermit_macro::system]
50#[unsafe(no_mangle)]
51pub extern "C" fn sys_exit(status: i32) -> ! {
52 exit(status)
53}
54
55#[hermit_macro::system]
56#[unsafe(no_mangle)]
57pub extern "C" fn sys_thread_exit(status: i32) -> ! {
58 debug!("Exit thread with error code {status}!");
59 core_scheduler().exit(status)
60}
61
62#[hermit_macro::system]
63#[unsafe(no_mangle)]
64pub extern "C" fn sys_abort() -> ! {
65 exit(-1)
66}
67
68pub(super) fn usleep(usecs: u64) {
69 if usecs >= 10_000 {
70 debug!("sys_usleep blocking the task for {usecs} microseconds");
72 let wakeup_time = arch::processor::get_timer_ticks() + usecs;
73 let core_scheduler = core_scheduler();
74 core_scheduler.block_current_task(Some(wakeup_time));
75
76 core_scheduler.reschedule();
78 } else if usecs > 0 {
79 let end = arch::processor::get_timestamp() + u64::from(get_frequency()) * usecs;
81 while get_timestamp() < end {
82 core_scheduler().reschedule();
83 }
84 }
85}
86
87#[hermit_macro::system]
88#[unsafe(no_mangle)]
89pub extern "C" fn sys_msleep(ms: u32) {
90 usleep(u64::from(ms) * 1000);
91}
92
93#[hermit_macro::system]
94#[unsafe(no_mangle)]
95pub extern "C" fn sys_usleep(usecs: u64) {
96 usleep(usecs);
97}
98
99#[hermit_macro::system]
100#[unsafe(no_mangle)]
101pub unsafe extern "C" fn sys_nanosleep(rqtp: *const timespec, _rmtp: *mut timespec) -> i32 {
102 assert!(
103 !rqtp.is_null(),
104 "sys_nanosleep called with a zero rqtp parameter"
105 );
106 let requested_time = unsafe { &*rqtp };
107 if requested_time.tv_sec < 0 || requested_time.tv_nsec > 999_999_999 {
108 debug!("sys_nanosleep called with an invalid requested time, returning -EINVAL");
109 return -EINVAL;
110 }
111
112 let microseconds =
113 (requested_time.tv_sec as u64) * 1_000_000 + (requested_time.tv_nsec as u64) / 1_000;
114 usleep(microseconds);
115
116 0
117}
118
119#[cfg(feature = "newlib")]
121#[hermit_macro::system]
122#[unsafe(no_mangle)]
123pub unsafe extern "C" fn sys_clone(id: *mut Tid, func: extern "C" fn(usize), arg: usize) -> i32 {
124 let task_id = core_scheduler().clone(func, arg);
125
126 if !id.is_null() {
127 unsafe {
128 *id = task_id.into();
129 }
130 }
131
132 0
133}
134
135#[hermit_macro::system]
136#[unsafe(no_mangle)]
137pub extern "C" fn sys_yield() {
138 core_scheduler().reschedule();
139}
140
141#[cfg(feature = "newlib")]
142#[hermit_macro::system]
143#[unsafe(no_mangle)]
144pub extern "C" fn sys_kill(dest: Tid, signum: i32) -> i32 {
145 debug!("sys_kill is unimplemented, returning -ENOSYS for killing {dest} with signal {signum}");
146 -ENOSYS
147}
148
149#[cfg(feature = "newlib")]
150#[hermit_macro::system]
151#[unsafe(no_mangle)]
152pub extern "C" fn sys_signal(_handler: SignalHandler) -> i32 {
153 debug!("sys_signal is unimplemented");
154 0
155}
156
157#[hermit_macro::system]
158#[unsafe(no_mangle)]
159pub unsafe extern "C" fn sys_spawn2(
160 func: unsafe extern "C" fn(usize),
161 arg: usize,
162 prio: u8,
163 stack_size: usize,
164 selector: isize,
165) -> Tid {
166 unsafe { scheduler::spawn(func, arg, Priority::from(prio), stack_size, selector).into() }
167}
168
169#[hermit_macro::system]
170#[unsafe(no_mangle)]
171pub unsafe extern "C" fn sys_spawn(
172 id: *mut Tid,
173 func: unsafe extern "C" fn(usize),
174 arg: usize,
175 prio: u8,
176 selector: isize,
177) -> i32 {
178 let new_id = unsafe {
179 scheduler::spawn(func, arg, Priority::from(prio), USER_STACK_SIZE, selector).into()
180 };
181
182 if !id.is_null() {
183 unsafe {
184 *id = new_id;
185 }
186 }
187
188 0
189}
190
191#[hermit_macro::system]
192#[unsafe(no_mangle)]
193pub extern "C" fn sys_join(id: Tid) -> i32 {
194 match scheduler::join(TaskId::from(id)) {
195 Ok(()) => 0,
196 _ => -EINVAL,
197 }
198}
199
200static BLOCKED_TASKS: InterruptTicketMutex<BTreeMap<TaskId, TaskHandle>> =
202 InterruptTicketMutex::new(BTreeMap::new());
203
204fn block_current_task(timeout: Option<u64>) {
205 let wakeup_time = timeout.map(|t| arch::processor::get_timer_ticks() + t * 1000);
206 let core_scheduler = core_scheduler();
207 let handle = core_scheduler.get_current_task_handle();
208 let tid = core_scheduler.get_current_task_id();
209
210 BLOCKED_TASKS.lock().insert(tid, handle);
211 core_scheduler.block_current_task(wakeup_time);
212}
213
214#[hermit_macro::system]
216#[unsafe(no_mangle)]
217pub extern "C" fn sys_block_current_task() {
218 block_current_task(None);
219}
220
221#[hermit_macro::system]
223#[unsafe(no_mangle)]
224pub extern "C" fn sys_block_current_task_with_timeout(timeout: u64) {
225 block_current_task(Some(timeout));
226}
227
228#[hermit_macro::system]
230#[unsafe(no_mangle)]
231pub extern "C" fn sys_wakeup_task(id: Tid) {
232 let task_id = TaskId::from(id);
233
234 if let Some(handle) = BLOCKED_TASKS.lock().remove(&task_id) {
235 core_scheduler().custom_wakeup(handle);
236 }
237}
238
239#[hermit_macro::system]
241#[unsafe(no_mangle)]
242pub extern "C" fn sys_get_priority() -> u8 {
243 core_scheduler().get_current_task_prio().into()
244}
245
246#[hermit_macro::system]
248#[unsafe(no_mangle)]
249pub extern "C" fn sys_set_priority(id: Tid, prio: u8) {
250 if prio > 0 {
251 core_scheduler()
252 .set_priority(TaskId::from(id), Priority::from(prio))
253 .expect("Unable to set priority");
254 } else {
255 panic!("Invalid priority {}", prio);
256 }
257}
258
259#[hermit_macro::system]
261#[unsafe(no_mangle)]
262pub extern "C" fn sys_set_current_task_priority(prio: u8) {
263 if prio > 0 {
264 core_scheduler().set_current_task_priority(Priority::from(prio));
265 } else {
266 panic!("Invalid priority {}", prio);
267 }
268}