diff --git a/src/errno.rs b/src/errno.rs index 271c2afd95..b3ad5401ac 100644 --- a/src/errno.rs +++ b/src/errno.rs @@ -407,6 +407,13 @@ pub(crate) static ERRNO: core::cell::UnsafeCell = core::cell::UnsafeCell::n #[cfg(not(feature = "nostd"))] #[no_mangle] pub extern "C" fn sys_get_errno() -> i32 { + sys_errno() +} + +/// Get the error number from the thread local storage +#[cfg(not(feature = "nostd"))] +#[no_mangle] +pub extern "C" fn sys_errno() -> i32 { cfg_if::cfg_if! { if #[cfg(any(feature = "common-os", target_arch = "riscv64"))] { 0 diff --git a/src/scheduler/mod.rs b/src/scheduler/mod.rs index 9484bbfa3c..871d4ecbcc 100644 --- a/src/scheduler/mod.rs +++ b/src/scheduler/mod.rs @@ -9,7 +9,7 @@ use alloc::vec::Vec; use core::cell::RefCell; use core::future::{self, Future}; use core::ptr; -use core::sync::atomic::{AtomicU32, Ordering}; +use core::sync::atomic::{AtomicI32, AtomicU32, Ordering}; use core::task::ready; use core::task::Poll::Ready; @@ -873,7 +873,7 @@ impl PerCoreScheduler { } fn get_tid() -> TaskId { - static TID_COUNTER: AtomicU32 = AtomicU32::new(0); + static TID_COUNTER: AtomicI32 = AtomicI32::new(0); let guard = TASKS.lock(); loop { diff --git a/src/scheduler/task.rs b/src/scheduler/task.rs index d6ff54061c..0a988b65dd 100644 --- a/src/scheduler/task.rs +++ b/src/scheduler/task.rs @@ -56,14 +56,14 @@ pub(crate) enum TaskStatus { /// Unique identifier for a task (i.e. `pid`). #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] -pub struct TaskId(u32); +pub struct TaskId(i32); impl TaskId { - pub const fn into(self) -> u32 { + pub const fn into(self) -> i32 { self.0 } - pub const fn from(x: u32) -> Self { + pub const fn from(x: i32) -> Self { TaskId(x) } } diff --git a/src/syscalls/mod.rs b/src/syscalls/mod.rs index e4dfe7bac3..8674e1602f 100644 --- a/src/syscalls/mod.rs +++ b/src/syscalls/mod.rs @@ -2,7 +2,7 @@ #[cfg(all(target_os = "none", not(feature = "common-os")))] use core::alloc::{GlobalAlloc, Layout}; -use core::ffi::CStr; +use core::ffi::{c_char, CStr}; use core::marker::PhantomData; #[cfg(feature = "newlib")] @@ -80,6 +80,54 @@ pub(crate) fn init() { /// Returning a null pointer indicates that either memory is exhausted or /// `size` and `align` do not meet this allocator's size or alignment constraints. /// +#[cfg(all(target_os = "none", not(feature = "common-os")))] +#[hermit_macro::system] +pub extern "C" fn sys_alloc(size: usize, align: usize) -> *mut u8 { + let layout_res = Layout::from_size_align(size, align); + if layout_res.is_err() || size == 0 { + warn!( + "__sys_alloc called with size {:#x}, align {:#x} is an invalid layout!", + size, align + ); + return core::ptr::null_mut(); + } + let layout = layout_res.unwrap(); + let ptr = unsafe { ALLOCATOR.alloc(layout) }; + + trace!( + "__sys_alloc: allocate memory at {:p} (size {:#x}, align {:#x})", + ptr, + size, + align + ); + + ptr +} + +#[cfg(all(target_os = "none", not(feature = "common-os")))] +#[hermit_macro::system] +pub extern "C" fn sys_alloc_zeroed(size: usize, align: usize) -> *mut u8 { + let layout_res = Layout::from_size_align(size, align); + if layout_res.is_err() || size == 0 { + warn!( + "__sys_alloc_zeroed called with size {:#x}, align {:#x} is an invalid layout!", + size, align + ); + return core::ptr::null_mut(); + } + let layout = layout_res.unwrap(); + let ptr = unsafe { ALLOCATOR.alloc_zeroed(layout) }; + + trace!( + "__sys_alloc_zeroed: allocate memory at {:p} (size {:#x}, align {:#x})", + ptr, + size, + align + ); + + ptr +} + #[cfg(all(target_os = "none", not(feature = "common-os")))] #[hermit_macro::system] pub extern "C" fn sys_malloc(size: usize, align: usize) -> *mut u8 { @@ -169,6 +217,30 @@ pub unsafe extern "C" fn sys_realloc( /// /// # Errors /// May panic if debug assertions are enabled and invalid parameters `size` or `align` where passed. +#[cfg(all(target_os = "none", not(feature = "common-os")))] +#[hermit_macro::system] +pub unsafe extern "C" fn sys_dealloc(ptr: *mut u8, size: usize, align: usize) { + unsafe { + let layout_res = Layout::from_size_align(size, align); + if layout_res.is_err() || size == 0 { + warn!( + "__sys_dealloc called with size {:#x}, align {:#x} is an invalid layout!", + size, align + ); + debug_assert!(layout_res.is_err(), "__sys_dealloc error: Invalid layout"); + debug_assert_ne!(size, 0, "__sys_dealloc error: size cannot be 0"); + } else { + trace!( + "sys_free: deallocate memory at {:p} (size {:#x})", + ptr, + size + ); + } + let layout = layout_res.unwrap(); + ALLOCATOR.dealloc(ptr, layout); + } +} + #[cfg(all(target_os = "none", not(feature = "common-os")))] #[hermit_macro::system] pub unsafe extern "C" fn sys_free(ptr: *mut u8, size: usize, align: usize) { @@ -238,7 +310,7 @@ pub unsafe extern "C" fn sys_mkdir(name: *const u8, mode: u32) -> i32 { } #[hermit_macro::system] -pub unsafe extern "C" fn sys_rmdir(name: *const u8) -> i32 { +pub unsafe extern "C" fn sys_rmdir(name: *const c_char) -> i32 { let name = unsafe { CStr::from_ptr(name as _) }.to_str().unwrap(); fs::FILESYSTEM @@ -249,7 +321,7 @@ pub unsafe extern "C" fn sys_rmdir(name: *const u8) -> i32 { } #[hermit_macro::system] -pub unsafe extern "C" fn sys_stat(name: *const u8, stat: *mut FileAttr) -> i32 { +pub unsafe extern "C" fn sys_stat(name: *const c_char, stat: *mut FileAttr) -> i32 { let name = unsafe { CStr::from_ptr(name as _) }.to_str().unwrap(); match fs::FILESYSTEM.get().unwrap().stat(name) { @@ -262,7 +334,7 @@ pub unsafe extern "C" fn sys_stat(name: *const u8, stat: *mut FileAttr) -> i32 { } #[hermit_macro::system] -pub unsafe extern "C" fn sys_lstat(name: *const u8, stat: *mut FileAttr) -> i32 { +pub unsafe extern "C" fn sys_lstat(name: *const c_char, stat: *mut FileAttr) -> i32 { let name = unsafe { CStr::from_ptr(name as _) }.to_str().unwrap(); match fs::FILESYSTEM.get().unwrap().lstat(name) { @@ -288,7 +360,7 @@ pub unsafe extern "C" fn sys_fstat(fd: FileDescriptor, stat: *mut FileAttr) -> i } #[hermit_macro::system] -pub unsafe extern "C" fn sys_opendir(name: *const u8) -> FileDescriptor { +pub unsafe extern "C" fn sys_opendir(name: *const c_char) -> FileDescriptor { if let Ok(name) = unsafe { CStr::from_ptr(name as _) }.to_str() { crate::fs::opendir(name).unwrap_or_else(|e| -num::ToPrimitive::to_i32(&e).unwrap()) } else { @@ -297,7 +369,7 @@ pub unsafe extern "C" fn sys_opendir(name: *const u8) -> FileDescriptor { } #[hermit_macro::system] -pub unsafe extern "C" fn sys_open(name: *const u8, flags: i32, mode: u32) -> FileDescriptor { +pub unsafe extern "C" fn sys_open(name: *const c_char, flags: i32, mode: u32) -> FileDescriptor { let flags = if let Some(flags) = OpenOption::from_bits(flags) { flags } else { diff --git a/src/syscalls/semaphore.rs b/src/syscalls/semaphore.rs index fcc66c57ab..8aef93d3f9 100644 --- a/src/syscalls/semaphore.rs +++ b/src/syscalls/semaphore.rs @@ -2,6 +2,10 @@ use alloc::boxed::Box; use crate::errno::*; use crate::synch::semaphore::Semaphore; +use crate::time::timespec; + +#[allow(non_camel_case_types)] +pub type sem_t = *const Semaphore; /// Create a new, unnamed semaphore. /// @@ -10,8 +14,8 @@ use crate::synch::semaphore::Semaphore; /// Stores the raw memory location of the new semaphore in parameter `sem`. /// Returns `0` on success, `-EINVAL` if `sem` is null. #[hermit_macro::system] -pub unsafe extern "C" fn sys_sem_init(sem: *mut *mut Semaphore, value: u32) -> i32 { - if sem.is_null() { +pub unsafe extern "C" fn sys_sem_init(sem: *mut sem_t, pshared: i32, value: u32) -> i32 { + if sem.is_null() || pshared != 0 { return -EINVAL; } @@ -29,7 +33,7 @@ pub unsafe extern "C" fn sys_sem_init(sem: *mut *mut Semaphore, value: u32) -> i /// /// Returns `0` on success, `-EINVAL` if `sem` is null. #[hermit_macro::system] -pub unsafe extern "C" fn sys_sem_destroy(sem: *mut Semaphore) -> i32 { +pub unsafe extern "C" fn sys_sem_destroy(sem: *mut sem_t) -> i32 { if sem.is_null() { return -EINVAL; } @@ -50,13 +54,13 @@ pub unsafe extern "C" fn sys_sem_destroy(sem: *mut Semaphore) -> i32 { /// /// Returns `0` on success, or `-EINVAL` if `sem` is null. #[hermit_macro::system] -pub unsafe extern "C" fn sys_sem_post(sem: *const Semaphore) -> i32 { +pub unsafe extern "C" fn sys_sem_post(sem: *mut sem_t) -> i32 { if sem.is_null() { return -EINVAL; } // Get a reference to the given semaphore and release it. - let semaphore = unsafe { &*sem }; + let semaphore = unsafe { &**sem }; semaphore.release(); 0 } @@ -68,13 +72,13 @@ pub unsafe extern "C" fn sys_sem_post(sem: *const Semaphore) -> i32 { /// /// Returns `0` on lock acquire, `-EINVAL` if `sem` is null, or `-ECANCELED` if the decrement fails. #[hermit_macro::system] -pub unsafe extern "C" fn sys_sem_trywait(sem: *const Semaphore) -> i32 { +pub unsafe extern "C" fn sys_sem_trywait(sem: *mut sem_t) -> i32 { if sem.is_null() { return -EINVAL; } // Get a reference to the given semaphore and acquire it in a non-blocking fashion. - let semaphore = unsafe { &*sem }; + let semaphore = unsafe { &**sem }; if semaphore.try_acquire() { 0 } else { @@ -82,7 +86,7 @@ pub unsafe extern "C" fn sys_sem_trywait(sem: *const Semaphore) -> i32 { } } -unsafe fn sem_timedwait(sem: *const Semaphore, ms: u32) -> i32 { +unsafe fn sem_timedwait(sem: *mut sem_t, ms: u32) -> i32 { if sem.is_null() { return -EINVAL; } @@ -90,7 +94,7 @@ unsafe fn sem_timedwait(sem: *const Semaphore, ms: u32) -> i32 { let delay = if ms > 0 { Some(u64::from(ms)) } else { None }; // Get a reference to the given semaphore and wait until we have acquired it or the wakeup time has elapsed. - let semaphore = unsafe { &*sem }; + let semaphore = unsafe { &**sem }; if semaphore.acquire(delay) { 0 } else { @@ -98,17 +102,30 @@ unsafe fn sem_timedwait(sem: *const Semaphore, ms: u32) -> i32 { } } -/// Try to acquire a lock on a semaphore, blocking for a given amount of milliseconds. +/// Try to acquire a lock on a semaphore. /// -/// Blocks until semaphore is acquired or until wake-up time has elapsed. +/// Blocks until semaphore is acquired or until specified time passed /// /// Returns `0` on lock acquire, `-EINVAL` if sem is null, or `-ETIME` on timeout. #[hermit_macro::system] -pub unsafe extern "C" fn sys_sem_timedwait(sem: *const Semaphore, ms: u32) -> i32 { - unsafe { sem_timedwait(sem, ms) } -} +pub unsafe extern "C" fn sys_sem_timedwait(sem: *mut sem_t, ts: *const timespec) -> i32 { + if ts.is_null() { + unsafe { sem_timedwait(sem, 0) } + } else { + let mut current_ts: timespec = Default::default(); -#[hermit_macro::system] -pub unsafe extern "C" fn sys_sem_cancelablewait(sem: *const Semaphore, ms: u32) -> i32 { - unsafe { sem_timedwait(sem, ms) } + unsafe { + crate::sys_clock_gettime(crate::CLOCK_REALTIME, &mut current_ts as *mut _); + + let ts = &*ts; + let ms: i64 = (ts.tv_sec - current_ts.tv_sec) * 1000 + + (ts.tv_nsec as i64 - current_ts.tv_nsec as i64) / 1000000; + + if ms > 0 { + sem_timedwait(sem, ms.try_into().unwrap()) + } else { + 0 + } + } + } } diff --git a/src/syscalls/socket.rs b/src/syscalls/socket.rs index 2ba35ca085..1c93909fdc 100644 --- a/src/syscalls/socket.rs +++ b/src/syscalls/socket.rs @@ -54,7 +54,6 @@ pub type sa_family_t = u8; pub type socklen_t = u32; pub type in_addr_t = u32; pub type in_port_t = u16; -pub type time_t = i64; bitflags! { #[derive(Debug, Copy, Clone)] @@ -70,10 +69,10 @@ bitflags! { #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct in_addr { - pub s_addr: [u8; 4], + pub s_addr: in_addr_t, } -#[repr(C)] +#[repr(C, align(4))] #[derive(Debug, Default, Copy, Clone)] pub struct in6_addr { pub s6_addr: [u8; 16], @@ -101,15 +100,12 @@ pub struct sockaddr_in { impl From for IpListenEndpoint { fn from(addr: sockaddr_in) -> IpListenEndpoint { let port = u16::from_be(addr.sin_port); - if addr.sin_addr.s_addr.into_iter().all(|b| b == 0) { + if addr.sin_addr.s_addr == 0 { IpListenEndpoint { addr: None, port } } else { - let address = IpAddress::v4( - addr.sin_addr.s_addr[0], - addr.sin_addr.s_addr[1], - addr.sin_addr.s_addr[2], - addr.sin_addr.s_addr[3], - ); + let s_addr = addr.sin_addr.s_addr.to_be_bytes(); + + let address = IpAddress::v4(s_addr[0], s_addr[1], s_addr[2], s_addr[3]); IpListenEndpoint::from((address, port)) } @@ -120,12 +116,8 @@ impl From for IpListenEndpoint { impl From for IpEndpoint { fn from(addr: sockaddr_in) -> IpEndpoint { let port = u16::from_be(addr.sin_port); - let address = IpAddress::v4( - addr.sin_addr.s_addr[0], - addr.sin_addr.s_addr[1], - addr.sin_addr.s_addr[2], - addr.sin_addr.s_addr[3], - ); + let s_addr = addr.sin_addr.s_addr.to_be_bytes(); + let address = IpAddress::v4(s_addr[0], s_addr[1], s_addr[2], s_addr[3]); IpEndpoint::from((address, port)) } @@ -136,14 +128,15 @@ impl From for sockaddr_in { fn from(endpoint: IpEndpoint) -> Self { match endpoint.addr { IpAddress::Ipv4(ip) => { - let mut in_addr: in_addr = Default::default(); - in_addr.s_addr.copy_from_slice(ip.as_bytes()); + let sin_addr = in_addr { + s_addr: u32::from_be_bytes(ip.as_bytes().try_into().unwrap()), + }; Self { sin_len: core::mem::size_of::().try_into().unwrap(), sin_port: endpoint.port.to_be(), sin_family: AF_INET.try_into().unwrap(), - sin_addr: in_addr, + sin_addr, ..Default::default() } } @@ -155,10 +148,11 @@ impl From for sockaddr_in { #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct sockaddr_in6 { + pub sin6_len: u8, pub sin6_family: sa_family_t, pub sin6_port: in_port_t, - pub sin6_addr: in6_addr, pub sin6_flowinfo: u32, + pub sin6_addr: in6_addr, pub sin6_scope_id: u32, } @@ -211,6 +205,7 @@ impl From for sockaddr_in6 { in6_addr.s6_addr.copy_from_slice(ip.as_bytes()); Self { + sin6_len: core::mem::size_of::().try_into().unwrap(), sin6_port: endpoint.port.to_be(), sin6_family: AF_INET6.try_into().unwrap(), sin6_addr: in6_addr, @@ -244,8 +239,8 @@ pub struct addrinfo { pub ai_socktype: i32, pub ai_protocol: i32, pub ai_addrlen: socklen_t, - pub ai_addr: *mut sockaddr, pub ai_canonname: *mut u8, + pub ai_addr: *mut sockaddr, pub ai_next: *mut addrinfo, } diff --git a/src/syscalls/tasks.rs b/src/syscalls/tasks.rs index dfb3548f0c..fdfe3a5a9a 100644 --- a/src/syscalls/tasks.rs +++ b/src/syscalls/tasks.rs @@ -17,7 +17,7 @@ use crate::{arch, scheduler}; #[cfg(feature = "newlib")] pub type SignalHandler = extern "C" fn(i32); -pub type Tid = u32; +pub type Tid = i32; #[hermit_macro::system] pub extern "C" fn sys_getpid() -> Tid { @@ -48,14 +48,14 @@ fn exit(arg: i32) -> ! { } #[hermit_macro::system] -pub extern "C" fn sys_exit(arg: i32) -> ! { - exit(arg) +pub extern "C" fn sys_exit(status: i32) -> ! { + exit(status) } #[hermit_macro::system] -pub extern "C" fn sys_thread_exit(arg: i32) -> ! { - debug!("Exit thread with error code {}!", arg); - core_scheduler().exit(arg) +pub extern "C" fn sys_thread_exit(status: i32) -> ! { + debug!("Exit thread with error code {}!", status); + core_scheduler().exit(status) } #[hermit_macro::system] @@ -110,13 +110,13 @@ pub(super) fn usleep(usecs: u64) { } #[hermit_macro::system] -pub extern "C" fn sys_usleep(usecs: u64) { - usleep(usecs) +pub extern "C" fn sys_msleep(ms: u32) { + usleep(u64::from(ms) * 1000) } #[hermit_macro::system] -pub extern "C" fn sys_msleep(ms: u32) { - usleep(u64::from(ms) * 1000) +pub extern "C" fn sys_usleep(usecs: u64) { + usleep(usecs) } #[hermit_macro::system] @@ -126,10 +126,7 @@ pub unsafe extern "C" fn sys_nanosleep(rqtp: *const timespec, _rmtp: *mut timesp "sys_nanosleep called with a zero rqtp parameter" ); let requested_time = unsafe { &*rqtp }; - if requested_time.tv_sec < 0 - || requested_time.tv_nsec < 0 - || requested_time.tv_nsec > 999_999_999 - { + if requested_time.tv_sec < 0 || requested_time.tv_nsec > 999_999_999 { debug!("sys_nanosleep called with an invalid requested time, returning -EINVAL"); return -EINVAL; } @@ -149,7 +146,7 @@ pub extern "C" fn sys_clone(id: *mut Tid, func: extern "C" fn(usize), arg: usize if !id.is_null() { unsafe { - *id = task_id.into() as u32; + *id = task_id.into(); } } diff --git a/src/syscalls/timer.rs b/src/syscalls/timer.rs index 56603665b7..cbcd1f5c00 100644 --- a/src/syscalls/timer.rs +++ b/src/syscalls/timer.rs @@ -96,10 +96,7 @@ pub unsafe extern "C" fn sys_clock_nanosleep( "sys_clock_nanosleep called with a zero rqtp parameter" ); let requested_time = unsafe { &*rqtp }; - if requested_time.tv_sec < 0 - || requested_time.tv_nsec < 0 - || requested_time.tv_nsec > 999_999_999 - { + if requested_time.tv_sec < 0 || requested_time.tv_nsec > 999_999_999 { debug!("sys_clock_nanosleep called with an invalid requested time, returning -EINVAL"); return -EINVAL; } diff --git a/src/time.rs b/src/time.rs index 93d140de29..8b7e6dcea4 100644 --- a/src/time.rs +++ b/src/time.rs @@ -1,21 +1,26 @@ use crate::arch; +#[allow(non_camel_case_types)] +pub type time_t = i64; +#[allow(non_camel_case_types)] +pub type suseconds_t = u32; + /// Represent the number of seconds and microseconds since /// the Epoch (1970-01-01 00:00:00 +0000 (UTC)) #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct timeval { /// seconds - pub tv_sec: i64, + pub tv_sec: time_t, /// microseconds - pub tv_usec: i64, + pub tv_usec: suseconds_t, } impl timeval { pub fn from_usec(microseconds: u64) -> Self { Self { tv_sec: (microseconds / 1_000_000) as i64, - tv_usec: (microseconds % 1_000_000) as i64, + tv_usec: (microseconds % 1_000_000) as u32, } } @@ -23,7 +28,7 @@ impl timeval { u64::try_from(self.tv_sec) .ok() .and_then(|secs| secs.checked_mul(1_000_000)) - .and_then(|millions| millions.checked_add(u64::try_from(self.tv_usec).ok()?)) + .and_then(|millions| millions.checked_add(u64::from(self.tv_usec))) } } @@ -36,20 +41,20 @@ pub struct itimerval { /// Represent the number of seconds and nanoseconds since /// the Epoch (1970-01-01 00:00:00 +0000 (UTC)) -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Default)] #[repr(C)] pub struct timespec { /// seconds - pub tv_sec: i64, + pub tv_sec: time_t, /// nanoseconds - pub tv_nsec: i64, + pub tv_nsec: u32, } impl timespec { pub fn from_usec(microseconds: u64) -> Self { Self { tv_sec: (microseconds / 1_000_000) as i64, - tv_nsec: ((microseconds % 1_000_000) * 1000) as i64, + tv_nsec: ((microseconds % 1_000_000) * 1000) as u32, } } @@ -57,11 +62,11 @@ impl timespec { u64::try_from(self.tv_sec) .ok() .and_then(|secs| secs.checked_mul(1_000_000)) - .and_then(|millions| millions.checked_add(u64::try_from(self.tv_nsec).ok()? / 1000)) + .and_then(|millions| millions.checked_add(u64::from(self.tv_nsec) / 1000)) } } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Default)] pub struct SystemTime(timespec); impl SystemTime {