safa_api/syscalls/thread.rs
1use core::{num::NonZero, time::Duration};
2
3use safa_abi::{
4 errors::ErrorStatus,
5 process::{RawContextPriority, RawTSpawnConfig},
6};
7
8use crate::{
9 exported_func,
10 syscalls::types::{Cid, OptionalPtrMut, RequiredPtr, RequiredPtrMut, SyscallResult},
11};
12
13use super::{define_syscall, SyscallNum};
14
15define_syscall! {
16 SyscallNum::SysTExit => {
17 /// Exits the current thread, threads don't have an exit code
18 /// however if the thread was the last thread in the process,
19 /// then the process will exit with code [`code`]
20 syst_exit(code: usize) unreachable
21 },
22 SyscallNum::SysTWait => {
23 /// Waits for a child thread with the cid `cid` to exit
24 ///
25 /// # Returns
26 /// - [`ErrorStatus::InvalidTid`] if thread doesn't exist at the time of wait
27 syst_wait(cid: Cid)
28 },
29 SyscallNum::SysTSleep => {
30 /// Sleeps for N ms
31 ///
32 /// should always succeed
33 syst_sleep(n: usize)
34 },
35 SyscallNum::SysTYield => {
36 /// Switches to the next thread in the thread queue of the current CPU
37 sysyield()
38 },
39}
40
41/// Exits the current thread, threads don't have an exit code
42/// however if the thread was the last thread in the process,
43/// then the process will exit with code `code`
44#[inline]
45pub fn exit(code: usize) -> ! {
46 syst_exit(code)
47}
48
49/// Switches to the next thread in the thread queue of the current CPU
50#[inline]
51pub fn yield_now() {
52 debug_assert!(sysyield().is_success())
53}
54
55#[inline]
56/// Waits for the thread with the id `cid` to exit
57//
58/// # Returns
59///
60/// - [`ErrorStatus::InvalidTid`] if the target thread doesn't exist at the time of wait
61pub fn wait(cid: Cid) -> Result<(), ErrorStatus> {
62 err_from_u16!(syst_wait(cid))
63}
64
65#[inline]
66/// Sleeps for a given duration
67///
68/// # Returns
69/// - Err(()) if duration as milliseconds is larger than usize::MAX
70pub fn sleep(duration: Duration) -> Result<(), ()> {
71 let ms: usize = duration.as_millis() as usize;
72 Ok(assert!(syst_sleep(ms).is_success()))
73}
74
75define_syscall! {
76 SyscallNum::SysTSpawn => {
77 /// Spawns a thread at the entry point `entry_point` with the config `config`
78 ///
79 /// - if `dest_cid` is not null it will be set to the spawned thread's ID (CID or TID)
80 syst_spawn_raw(entry_point: usize, config: RequiredPtr<RawTSpawnConfig>, dest_cid: OptionalPtrMut<Cid>)
81 },
82}
83
84exported_func! {
85 /// Spawns a thread as a child of self
86 /// # Arguments
87 /// - `entry_point`: a pointer to the main function of the thread,
88 /// the main function looks like this: `fn main(thread_id: Cid, argument_ptr: usize)` see `dest_cid` below for thread_id, argument_ptr == `argument_ptr`
89 ///
90 /// - `argument_ptr`: a pointer to the arguments that will be passed to the thread, this pointer will be based as is,
91 /// and therefore can also be used to pass a single usize argument
92 ///
93 /// - `priotrity`: the pritority of the thread in the thread queue, will default to the parent's
94 ///
95 /// - `dest_cid`: if not null, will be set to the thread ID of the spawned thread
96 extern "C" fn syst_spawn(
97 entry_point: usize,
98 argument_ptr: *const (),
99 priority: RawContextPriority,
100 custom_stack_size: Option<NonZero<usize>>,
101 dest_cid: OptionalPtrMut<Cid>,
102 ) -> SyscallResult {
103 let mut config = RawTSpawnConfig::new(
104 argument_ptr,
105 priority.into(),
106 None,
107 custom_stack_size.into(),
108 );
109 let config = unsafe {RequiredPtr::new_unchecked(&raw mut config)};
110 syst_spawn_raw(entry_point, config, dest_cid)
111 }
112}
113
114#[inline]
115/// Spawns a thread as a child of self
116/// unlike [`spawn`], this will pass no arguments to the thread
117/// # Arguments
118/// - `entry_point`: a pointer to the main function of the thread
119///
120/// - `priotrity`: the pritority of the thread in the thread queue, will default to the parent's
121///
122/// # Returns
123/// - the thread ID of the spawned thread
124pub fn spawn3(
125 entry_point: fn(thread_id: Cid) -> !,
126 priority: RawContextPriority,
127 custom_stack_size: Option<NonZero<usize>>,
128) -> Result<Cid, ErrorStatus> {
129 spawn_inner(
130 entry_point as usize,
131 core::ptr::null(),
132 priority,
133 custom_stack_size,
134 )
135}
136
137#[inline]
138/// Spawns a thread as a child of self
139/// unlike [`spawn`], instead of taking a reference as an argument to pass to the thread, this will take a usize
140/// # Arguments
141/// - `entry_point`: a pointer to the main function of the thread
142///
143/// - `argument`: a usize argument that will be passed to the thread
144///
145/// - `priotrity`: the pritority of the thread in the thread queue, will default to the parent's
146///
147/// # Returns
148/// - the thread ID of the spawned thread
149pub fn spawn2(
150 entry_point: fn(thread_id: Cid, argument: usize) -> !,
151 argument: usize,
152 priority: RawContextPriority,
153 custom_stack_size: Option<NonZero<usize>>,
154) -> Result<Cid, ErrorStatus> {
155 spawn_inner(
156 entry_point as usize,
157 argument as *const (),
158 priority,
159 custom_stack_size,
160 )
161}
162
163#[inline]
164/// Spawns a thread as a child of self
165/// # Arguments
166/// - `entry_point`: a pointer to the main function of the thread
167///
168/// - `argument_ptr`: a pointer to the arguments that will be passed to the thread, this pointer will be based as is,
169///
170/// - `priotrity`: the pritority of the thread in the thread queue, will default to the parent's
171///
172/// # Returns
173/// - the thread ID of the spawned thread
174pub fn spawn<T>(
175 entry_point: fn(thread_id: Cid, argument_ptr: &'static T) -> !,
176 argument_ptr: &'static T,
177 priority: RawContextPriority,
178 custom_stack_size: Option<NonZero<usize>>,
179) -> Result<Cid, ErrorStatus> {
180 spawn_inner(
181 entry_point as usize,
182 argument_ptr as *const T as *const (),
183 priority,
184 custom_stack_size,
185 )
186}
187
188#[inline(always)]
189fn spawn_inner(
190 entry_point: usize,
191 argument_ptr: *const (),
192 priority: RawContextPriority,
193 custom_stack_size: Option<NonZero<usize>>,
194) -> Result<Cid, ErrorStatus> {
195 let mut cid = 0;
196 let ptr = RequiredPtrMut::new(&raw mut cid).into();
197 err_from_u16!(
198 syst_spawn(
199 entry_point,
200 argument_ptr,
201 priority.into(),
202 custom_stack_size.into(),
203 ptr
204 ),
205 cid
206 )
207}