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 {} microseconds", usecs);
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!(
146 "sys_kill is unimplemented, returning -ENOSYS for killing {} with signal {}",
147 dest, signum
148 );
149 -ENOSYS
150}
151
152#[cfg(feature = "newlib")]
153#[hermit_macro::system]
154#[unsafe(no_mangle)]
155pub extern "C" fn sys_signal(_handler: SignalHandler) -> i32 {
156 debug!("sys_signal is unimplemented");
157 0
158}
159
160#[hermit_macro::system]
161#[unsafe(no_mangle)]
162pub unsafe extern "C" fn sys_spawn2(
163 func: unsafe extern "C" fn(usize),
164 arg: usize,
165 prio: u8,
166 stack_size: usize,
167 selector: isize,
168) -> Tid {
169 unsafe { scheduler::spawn(func, arg, Priority::from(prio), stack_size, selector).into() }
170}
171
172#[hermit_macro::system]
173#[unsafe(no_mangle)]
174pub unsafe extern "C" fn sys_spawn(
175 id: *mut Tid,
176 func: unsafe extern "C" fn(usize),
177 arg: usize,
178 prio: u8,
179 selector: isize,
180) -> i32 {
181 let new_id = unsafe {
182 scheduler::spawn(func, arg, Priority::from(prio), USER_STACK_SIZE, selector).into()
183 };
184
185 if !id.is_null() {
186 unsafe {
187 *id = new_id;
188 }
189 }
190
191 0
192}
193
194#[hermit_macro::system]
195#[unsafe(no_mangle)]
196pub extern "C" fn sys_join(id: Tid) -> i32 {
197 match scheduler::join(TaskId::from(id)) {
198 Ok(()) => 0,
199 _ => -EINVAL,
200 }
201}
202
203static BLOCKED_TASKS: InterruptTicketMutex<BTreeMap<TaskId, TaskHandle>> =
205 InterruptTicketMutex::new(BTreeMap::new());
206
207fn block_current_task(timeout: Option<u64>) {
208 let wakeup_time = timeout.map(|t| arch::processor::get_timer_ticks() + t * 1000);
209 let core_scheduler = core_scheduler();
210 let handle = core_scheduler.get_current_task_handle();
211 let tid = core_scheduler.get_current_task_id();
212
213 BLOCKED_TASKS.lock().insert(tid, handle);
214 core_scheduler.block_current_task(wakeup_time);
215}
216
217#[hermit_macro::system]
219#[unsafe(no_mangle)]
220pub extern "C" fn sys_block_current_task() {
221 block_current_task(None);
222}
223
224#[hermit_macro::system]
226#[unsafe(no_mangle)]
227pub extern "C" fn sys_block_current_task_with_timeout(timeout: u64) {
228 block_current_task(Some(timeout));
229}
230
231#[hermit_macro::system]
233#[unsafe(no_mangle)]
234pub extern "C" fn sys_wakeup_task(id: Tid) {
235 let task_id = TaskId::from(id);
236
237 if let Some(handle) = BLOCKED_TASKS.lock().remove(&task_id) {
238 core_scheduler().custom_wakeup(handle);
239 }
240}
241
242#[hermit_macro::system]
244#[unsafe(no_mangle)]
245pub extern "C" fn sys_get_priority() -> u8 {
246 core_scheduler().get_current_task_prio().into()
247}
248
249#[hermit_macro::system]
251#[unsafe(no_mangle)]
252pub extern "C" fn sys_set_priority(id: Tid, prio: u8) {
253 if prio > 0 {
254 core_scheduler()
255 .set_priority(TaskId::from(id), Priority::from(prio))
256 .expect("Unable to set priority");
257 } else {
258 panic!("Invalid priority {}", prio);
259 }
260}
261
262#[hermit_macro::system]
264#[unsafe(no_mangle)]
265pub extern "C" fn sys_set_current_task_priority(prio: u8) {
266 if prio > 0 {
267 core_scheduler().set_current_task_priority(Priority::from(prio));
268 } else {
269 panic!("Invalid priority {}", prio);
270 }
271}