safa_api/syscalls/
thread.rs

1use core::time::Duration;
2
3use safa_abi::{
4    errors::ErrorStatus,
5    raw::{
6        processes::{ContextPriority, TSpawnConfig},
7        Optional,
8    },
9};
10
11use crate::syscalls::types::{Cid, OptionalPtr, OptionalPtrMut, RequiredPtr, SyscallResult};
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().try_into().map_err(|_| ())?;
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<TSpawnConfig>, dest_cid: OptionalPtrMut<Cid>)
81    },
82}
83
84/// Spawns a thread as a child of self
85/// # Arguments
86/// - `entry_point`: a pointer to the main function of the thread,
87/// 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`
88///
89/// - `argument_ptr`: a pointer to the arguments that will be passed to the thread, this pointer will be based as is,
90/// and therefore can also be used to pass a single usize argument
91///
92/// - `priotrity`: the pritority of the thread in the thread queue, will default to the parent's
93///
94/// - `dest_cid`: if not null, will be set to the thread ID of the spawned thread
95#[cfg_attr(
96    not(any(feature = "std", feature = "rustc-dep-of-std")),
97    unsafe(no_mangle)
98)]
99#[inline(always)]
100extern "C" fn syst_spawn(
101    entry_point: usize,
102    argument_ptr: OptionalPtr<()>,
103    priority: Optional<ContextPriority>,
104    dest_cid: OptionalPtrMut<Cid>,
105) -> SyscallResult {
106    let config = TSpawnConfig::new(argument_ptr, priority.into(), None);
107    syscall!(
108        SyscallNum::SysTSpawn,
109        entry_point,
110        &config as *const _ as usize,
111        dest_cid as usize
112    )
113}
114
115#[inline]
116/// Spawns a thread as a child of self
117/// unlike [`spawn`], this will pass no arguments to the thread
118/// # Arguments
119/// - `entry_point`: a pointer to the main function of the thread
120///
121/// - `priotrity`: the pritority of the thread in the thread queue, will default to the parent's
122///
123/// # Returns
124/// - the thread ID of the spawned thread
125pub fn spawn3(
126    entry_point: fn(thread_id: Cid) -> !,
127    priority: Option<ContextPriority>,
128) -> Result<Cid, ErrorStatus> {
129    let mut cid = 0;
130    err_from_u16!(
131        syst_spawn(
132            entry_point as usize,
133            core::ptr::null(),
134            priority.into(),
135            &mut cid
136        ),
137        cid
138    )
139}
140
141#[inline]
142/// Spawns a thread as a child of self
143/// unlike [`spawn`], instead of taking a reference as an argument to pass to the thread, this will take a usize
144/// # Arguments
145/// - `entry_point`: a pointer to the main function of the thread
146///
147/// - `argument`: a usize argument that will be passed to the thread
148///
149/// - `priotrity`: the pritority of the thread in the thread queue, will default to the parent's
150///
151/// # Returns
152/// - the thread ID of the spawned thread
153pub fn spawn2(
154    entry_point: fn(thread_id: Cid, argument: usize) -> !,
155    argument: usize,
156    priority: Option<ContextPriority>,
157) -> Result<Cid, ErrorStatus> {
158    let mut cid = 0;
159    err_from_u16!(
160        syst_spawn(
161            entry_point as usize,
162            argument as *const (),
163            priority.into(),
164            &mut cid
165        ),
166        cid
167    )
168}
169
170#[inline]
171/// Spawns a thread as a child of self
172/// # Arguments
173/// - `entry_point`: a pointer to the main function of the thread
174///
175/// - `argument_ptr`: a pointer to the arguments that will be passed to the thread, this pointer will be based as is,
176///
177/// - `priotrity`: the pritority of the thread in the thread queue, will default to the parent's
178///
179/// # Returns
180/// - the thread ID of the spawned thread
181pub fn spawn<T>(
182    entry_point: fn(thread_id: Cid, argument_ptr: &'static T) -> !,
183    argument_ptr: &'static T,
184    priority: Option<ContextPriority>,
185) -> Result<Cid, ErrorStatus> {
186    let mut cid = 0;
187    err_from_u16!(
188        syst_spawn(
189            entry_point as usize,
190            argument_ptr as *const T as *const (),
191            priority.into(),
192            &mut cid
193        ),
194        cid
195    )
196}