alnyan/yggdrasil: thread+static TLS, mutex+condvar impl

This commit is contained in:
2023-11-24 11:06:21 +02:00
parent 3a77d57bab
commit e8b7d33684
18 changed files with 578 additions and 437 deletions
@@ -16,6 +16,8 @@ SECTIONS {
.rodata : {
*(.rodata*)
/* TODO: this is unused currently */
*(.eh_frame*)
}
. = ALIGN(4K);
@@ -31,4 +33,10 @@ SECTIONS {
*(COMMON)
*(.bss*)
}
. = ALIGN(4K);
.tbss : {
*(.tbss*)
}
}
@@ -14,6 +14,8 @@ SECTIONS {
.rodata : {
*(.rodata*)
/* TODO: this is unused currently */
*(.eh_frame*)
}
. = ALIGN(4K);
@@ -29,4 +31,10 @@ SECTIONS {
*(COMMON)
*(.bss*)
}
. = ALIGN(4K);
.tbss : {
*(.tbss*)
}
}
@@ -10,6 +10,7 @@ pub fn opts() -> TargetOptions {
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
lld_flavor_json: LldFlavor::Ld,
stack_probes: StackProbeType::Inline,
has_thread_local: true,
max_atomic_width: Some(128),
eh_frame_header: false,
relocation_model: RelocModel::Static,
-297
View File
@@ -1,297 +0,0 @@
#![stable(feature = "os_fd", since = "1.66.0")]
#![allow(dead_code)]
use crate::mem::MaybeUninit;
use crate::sys::cvt_io;
use yggdrasil_rt::sys as syscall;
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub use yggdrasil_rt::io::{
DeviceRequest, TerminalInputOptions, TerminalLineOptions, TerminalOptions,
TerminalOutputOptions,
};
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub trait FdDeviceRequest {
#[unstable(feature = "yggdrasil_os", issue = "none")]
unsafe fn device_request(&self, req: &mut DeviceRequest) -> crate::io::Result<()>;
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl<T: AsRawFd> FdDeviceRequest for T {
unsafe fn device_request(&self, req: &mut DeviceRequest) -> crate::io::Result<()> {
cvt_io(syscall::device_request(self.as_raw_fd(), req))?;
Ok(())
}
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub unsafe fn set_terminal_options<F: raw::AsRawFd>(
fd: F,
opt: TerminalOptions,
) -> crate::io::Result<()> {
let mut req = DeviceRequest::SetTerminalOptions(opt);
cvt_io(syscall::device_request(fd.as_raw_fd(), &mut req))
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub unsafe fn get_terminal_options<F: raw::AsRawFd>(fd: F) -> crate::io::Result<TerminalOptions> {
let mut req = DeviceRequest::GetTerminalOptions(MaybeUninit::uninit());
cvt_io(syscall::device_request(fd.as_raw_fd(), &mut req))?;
let DeviceRequest::GetTerminalOptions(opt) = req else {
unreachable!();
};
Ok(opt.assume_init())
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub unsafe fn update_terminal_options<
F: raw::AsRawFd,
M: Fn(TerminalOptions) -> TerminalOptions,
>(
fd: F,
mutator: M,
) -> crate::io::Result<TerminalOptions> {
let fd = fd.as_raw_fd();
let old = get_terminal_options(fd)?;
let new = mutator(old);
set_terminal_options(fd, new)?;
Ok(old)
}
mod net {
use crate::os::yggdrasil::io::OwnedFd;
use crate::os::yggdrasil::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::sys_common::{self, AsInner, FromInner, IntoInner};
use crate::{net, sys};
macro_rules! impl_as_raw_fd {
($($t:ident)*) => {$(
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::$t {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.as_inner().socket().as_raw_fd()
}
}
)*};
}
macro_rules! impl_from_raw_fd {
($($t:ident)*) => {$(
#[stable(feature = "rust1", since = "1.0.0")]
impl FromRawFd for net::$t {
#[inline]
unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)));
net::$t::from_inner(sys_common::net::$t::from_inner(socket))
}
}
)*};
}
macro_rules! impl_into_raw_fd {
($($t:ident)*) => {$(
#[stable(feature = "rust1", since = "1.0.0")]
impl IntoRawFd for net::$t {
#[inline]
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_socket().into_inner().into_raw_fd()
}
}
)*};
}
impl_as_raw_fd! { TcpStream TcpListener UdpSocket }
impl_from_raw_fd! { TcpStream TcpListener UdpSocket }
impl_into_raw_fd! { TcpStream TcpListener UdpSocket }
}
#[stable(feature = "os_fd", since = "1.66.0")]
pub(crate) mod raw {
#[stable(feature = "rust1", since = "1.0.0")]
pub type RawFd = yggdrasil_rt::io::RawFd;
macro_rules! stdio_impl_as_raw_fd {
($($ty:ty => $n:expr),*) => {$(
#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawFd for $ty {
#[inline]
fn as_raw_fd(&self) -> RawFd {
$n
}
}
#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawFd for &$ty {
#[inline]
fn as_raw_fd(&self) -> RawFd {
$n
}
}
)*};
}
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawFd {
#[stable(feature = "rust1", since = "1.0.0")]
fn as_raw_fd(&self) -> RawFd;
}
#[stable(feature = "rust1", since = "1.0.0")]
pub trait FromRawFd {
#[stable(feature = "rust1", since = "1.0.0")]
unsafe fn from_raw_fd(fd: RawFd) -> Self;
}
#[stable(feature = "rust1", since = "1.0.0")]
pub trait IntoRawFd {
#[stable(feature = "rust1", since = "1.0.0")]
fn into_raw_fd(self) -> RawFd;
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for RawFd {
fn as_raw_fd(&self) -> RawFd {
*self
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl FromRawFd for RawFd {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
fd
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl IntoRawFd for RawFd {
fn into_raw_fd(self) -> RawFd {
self
}
}
stdio_impl_as_raw_fd!(
crate::io::Stdin => RawFd::STDIN,
crate::io::Stdout => RawFd::STDOUT,
crate::io::Stderr => RawFd::STDERR
);
}
pub mod owned {
#![stable(feature = "io_safety", since = "1.63.0")]
use super::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::marker::PhantomData;
use crate::mem::forget;
#[stable(feature = "io_safety", since = "1.63.0")]
#[repr(transparent)]
#[derive(Debug)]
pub struct OwnedFd {
fd: RawFd,
}
#[stable(feature = "io_safety", since = "1.63.0")]
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
pub struct BorrowedFd<'fd> {
fd: RawFd,
_pd: PhantomData<&'fd OwnedFd>,
}
#[stable(feature = "io_safety", since = "1.63.0")]
pub trait AsFd {
#[stable(feature = "io_safety", since = "1.63.0")]
fn as_fd(&self) -> BorrowedFd<'_>;
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl<T: AsFd> AsFd for &T {
fn as_fd(&self) -> BorrowedFd<'_> {
T::as_fd(self)
}
}
// Borrowed
impl BorrowedFd<'_> {
#[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
#[stable(feature = "io_safety", since = "1.63.0")]
pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
// assert_ne!(fd, u32::MAX as RawFd);
Self { fd, _pd: PhantomData }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsFd for BorrowedFd<'_> {
fn as_fd(&self) -> BorrowedFd<'_> {
*self
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsRawFd for BorrowedFd<'_> {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
// Owned
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsFd for OwnedFd {
fn as_fd(&self) -> BorrowedFd<'_> {
unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl IntoRawFd for OwnedFd {
fn into_raw_fd(self) -> RawFd {
let fd = self.fd;
forget(self);
fd
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl FromRawFd for OwnedFd {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self { fd }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsRawFd for OwnedFd {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl Drop for OwnedFd {
fn drop(&mut self) {
unsafe {
yggdrasil_rt::sys::close(self.fd).ok();
}
}
}
// TODO: AsFd for File, From<File> for OwnedFd, From<OwnedFd> for File,
}
#[stable(feature = "io_safety", since = "1.63.0")]
pub use owned::*;
#[stable(feature = "rust1", since = "1.0.0")]
pub use raw::*;
use crate::io::StdinLock;
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> AsRawFd for StdinLock<'a> {
fn as_raw_fd(&self) -> RawFd {
todo!()
}
}
+80
View File
@@ -0,0 +1,80 @@
#![stable(feature = "os_fd", since = "1.66.0")]
#![allow(dead_code)]
mod net;
pub mod owned;
pub(crate) mod raw;
use crate::io::StdinLock;
use crate::mem::MaybeUninit;
use crate::sys::cvt_io;
use yggdrasil_rt::sys as syscall;
// Public exports
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub use yggdrasil_rt::io::{
DeviceRequest, TerminalInputOptions, TerminalLineOptions, TerminalOptions,
TerminalOutputOptions,
};
#[stable(feature = "io_safety", since = "1.63.0")]
pub use owned::*;
#[stable(feature = "rust1", since = "1.0.0")]
pub use raw::*;
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub trait FdDeviceRequest {
#[unstable(feature = "yggdrasil_os", issue = "none")]
unsafe fn device_request(&self, req: &mut DeviceRequest) -> crate::io::Result<()>;
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
impl<T: AsRawFd> FdDeviceRequest for T {
unsafe fn device_request(&self, req: &mut DeviceRequest) -> crate::io::Result<()> {
cvt_io(syscall::device_request(self.as_raw_fd(), req))?;
Ok(())
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> AsRawFd for StdinLock<'a> {
fn as_raw_fd(&self) -> RawFd {
todo!()
}
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub unsafe fn set_terminal_options<F: raw::AsRawFd>(
fd: F,
opt: TerminalOptions,
) -> crate::io::Result<()> {
let mut req = DeviceRequest::SetTerminalOptions(opt);
cvt_io(syscall::device_request(fd.as_raw_fd(), &mut req))
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub unsafe fn get_terminal_options<F: raw::AsRawFd>(fd: F) -> crate::io::Result<TerminalOptions> {
let mut req = DeviceRequest::GetTerminalOptions(MaybeUninit::uninit());
cvt_io(syscall::device_request(fd.as_raw_fd(), &mut req))?;
let DeviceRequest::GetTerminalOptions(opt) = req else {
unreachable!();
};
Ok(opt.assume_init())
}
#[unstable(feature = "yggdrasil_os", issue = "none")]
pub unsafe fn update_terminal_options<
F: raw::AsRawFd,
M: Fn(TerminalOptions) -> TerminalOptions,
>(
fd: F,
mutator: M,
) -> crate::io::Result<TerminalOptions> {
let fd = fd.as_raw_fd();
let old = get_terminal_options(fd)?;
let new = mutator(old);
set_terminal_options(fd, new)?;
Ok(old)
}
+45
View File
@@ -0,0 +1,45 @@
use crate::os::yggdrasil::io::OwnedFd;
use crate::os::yggdrasil::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::sys_common::{self, AsInner, FromInner, IntoInner};
use crate::{net, sys};
macro_rules! impl_as_raw_fd {
($($t:ident)*) => {$(
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::$t {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.as_inner().socket().as_raw_fd()
}
}
)*};
}
macro_rules! impl_from_raw_fd {
($($t:ident)*) => {$(
#[stable(feature = "rust1", since = "1.0.0")]
impl FromRawFd for net::$t {
#[inline]
unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)));
net::$t::from_inner(sys_common::net::$t::from_inner(socket))
}
}
)*};
}
macro_rules! impl_into_raw_fd {
($($t:ident)*) => {$(
#[stable(feature = "rust1", since = "1.0.0")]
impl IntoRawFd for net::$t {
#[inline]
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_socket().into_inner().into_raw_fd()
}
}
)*};
}
impl_as_raw_fd! { TcpStream TcpListener UdpSocket }
impl_from_raw_fd! { TcpStream TcpListener UdpSocket }
impl_into_raw_fd! { TcpStream TcpListener UdpSocket }
+101
View File
@@ -0,0 +1,101 @@
#![stable(feature = "io_safety", since = "1.63.0")]
use super::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::marker::PhantomData;
use crate::mem::forget;
#[stable(feature = "io_safety", since = "1.63.0")]
#[repr(transparent)]
#[derive(Debug)]
pub struct OwnedFd {
fd: RawFd,
}
#[stable(feature = "io_safety", since = "1.63.0")]
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
pub struct BorrowedFd<'fd> {
fd: RawFd,
_pd: PhantomData<&'fd OwnedFd>,
}
#[stable(feature = "io_safety", since = "1.63.0")]
pub trait AsFd {
#[stable(feature = "io_safety", since = "1.63.0")]
fn as_fd(&self) -> BorrowedFd<'_>;
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl<T: AsFd> AsFd for &T {
fn as_fd(&self) -> BorrowedFd<'_> {
T::as_fd(self)
}
}
// Borrowed
impl BorrowedFd<'_> {
#[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
#[stable(feature = "io_safety", since = "1.63.0")]
pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
// assert_ne!(fd, u32::MAX as RawFd);
Self { fd, _pd: PhantomData }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsFd for BorrowedFd<'_> {
fn as_fd(&self) -> BorrowedFd<'_> {
*self
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsRawFd for BorrowedFd<'_> {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
// Owned
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsFd for OwnedFd {
fn as_fd(&self) -> BorrowedFd<'_> {
unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl IntoRawFd for OwnedFd {
fn into_raw_fd(self) -> RawFd {
let fd = self.fd;
forget(self);
fd
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl FromRawFd for OwnedFd {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self { fd }
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsRawFd for OwnedFd {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
#[stable(feature = "io_safety", since = "1.63.0")]
impl Drop for OwnedFd {
fn drop(&mut self) {
unsafe {
yggdrasil_rt::sys::close(self.fd).ok();
}
}
}
// TODO: AsFd for File, From<File> for OwnedFd, From<OwnedFd> for File,
+69
View File
@@ -0,0 +1,69 @@
#![stable(feature = "os_fd", since = "1.66.0")]
#[stable(feature = "rust1", since = "1.0.0")]
pub type RawFd = yggdrasil_rt::io::RawFd;
macro_rules! stdio_impl_as_raw_fd {
($($ty:ty => $n:expr),*) => {$(
#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawFd for $ty {
#[inline]
fn as_raw_fd(&self) -> RawFd {
$n
}
}
#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawFd for &$ty {
#[inline]
fn as_raw_fd(&self) -> RawFd {
$n
}
}
)*};
}
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawFd {
#[stable(feature = "rust1", since = "1.0.0")]
fn as_raw_fd(&self) -> RawFd;
}
#[stable(feature = "rust1", since = "1.0.0")]
pub trait FromRawFd {
#[stable(feature = "rust1", since = "1.0.0")]
unsafe fn from_raw_fd(fd: RawFd) -> Self;
}
#[stable(feature = "rust1", since = "1.0.0")]
pub trait IntoRawFd {
#[stable(feature = "rust1", since = "1.0.0")]
fn into_raw_fd(self) -> RawFd;
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for RawFd {
fn as_raw_fd(&self) -> RawFd {
*self
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl FromRawFd for RawFd {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
fd
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl IntoRawFd for RawFd {
fn into_raw_fd(self) -> RawFd {
self
}
}
stdio_impl_as_raw_fd!(
crate::io::Stdin => RawFd::STDIN,
crate::io::Stdout => RawFd::STDOUT,
crate::io::Stderr => RawFd::STDERR
);
-135
View File
@@ -1,135 +0,0 @@
mod condvar {
use crate::sys::locks::Mutex;
use crate::time::Duration;
pub struct Condvar {}
impl Condvar {
#[inline]
#[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
pub const fn new() -> Condvar {
Condvar {}
}
#[inline]
pub fn notify_one(&self) {}
#[inline]
pub fn notify_all(&self) {}
pub unsafe fn wait(&self, _mutex: &Mutex) {
panic!("condvar wait not supported")
}
pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
panic!("condvar wait not supported");
}
}
}
mod mutex {
use crate::cell::Cell;
pub struct Mutex {
// This platform has no threads, so we can use a Cell here.
locked: Cell<bool>,
}
unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {} // no threads on this platform
impl Mutex {
#[inline]
#[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
pub const fn new() -> Mutex {
Mutex { locked: Cell::new(false) }
}
#[inline]
pub fn lock(&self) {
assert_eq!(self.locked.replace(true), false, "cannot recursively acquire mutex");
}
#[inline]
pub unsafe fn unlock(&self) {
self.locked.set(false);
}
#[inline]
pub fn try_lock(&self) -> bool {
self.locked.replace(true) == false
}
}
}
mod rwlock {
use crate::cell::Cell;
pub struct RwLock {
// This platform has no threads, so we can use a Cell here.
mode: Cell<isize>,
}
unsafe impl Send for RwLock {}
unsafe impl Sync for RwLock {} // no threads on this platform
impl RwLock {
#[inline]
#[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
pub const fn new() -> RwLock {
RwLock { mode: Cell::new(0) }
}
#[inline]
pub fn read(&self) {
let m = self.mode.get();
if m >= 0 {
self.mode.set(m + 1);
} else {
rtabort!("rwlock locked for writing");
}
}
#[inline]
pub fn try_read(&self) -> bool {
let m = self.mode.get();
if m >= 0 {
self.mode.set(m + 1);
true
} else {
false
}
}
#[inline]
pub fn write(&self) {
if self.mode.replace(-1) != 0 {
rtabort!("rwlock locked for reading")
}
}
#[inline]
pub fn try_write(&self) -> bool {
if self.mode.get() == 0 {
self.mode.set(-1);
true
} else {
false
}
}
#[inline]
pub unsafe fn read_unlock(&self) {
self.mode.set(self.mode.get() - 1);
}
#[inline]
pub unsafe fn write_unlock(&self) {
assert_eq!(self.mode.replace(0), -1);
}
}
}
pub use condvar::Condvar;
pub use mutex::Mutex;
pub use rwlock::RwLock;
@@ -0,0 +1,68 @@
use crate::sync::atomic::{AtomicU32, Ordering};
use crate::sys::locks::Mutex;
use crate::time::Duration;
use yggdrasil_rt::{process::MutexOperation, sys};
pub struct Condvar {
value: AtomicU32,
}
impl Condvar {
#[inline]
#[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
pub const fn new() -> Condvar {
Condvar { value: AtomicU32::new(0) }
}
#[inline]
pub fn notify_one(&self) {
self.value.fetch_add(1, Ordering::Release);
unsafe {
sys::mutex(&self.value, &MutexOperation::Wake).ok();
}
}
#[inline]
pub fn notify_all(&self) {
self.value.fetch_add(1, Ordering::Release);
unsafe {
sys::mutex(&self.value, &MutexOperation::WakeAll).ok();
}
}
pub unsafe fn wait(&self, mutex: &Mutex) {
// Load the old value while the lock is still held
let compare_value = self.value.load(Ordering::Acquire);
// Release the lock so others can now access the value
mutex.unlock();
// Wait for the value to change
self.wait_inner(compare_value, None);
// Re-lock the mutex
mutex.lock();
}
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
// Load the old value while the lock is still held
let compare_value = self.value.load(Ordering::Acquire);
// Release the lock so others can now access the value
mutex.unlock();
// Wait for the value to change
let r = self.wait_inner(compare_value, Some(dur));
// Re-lock the mutex
mutex.lock();
r
}
unsafe fn wait_inner(&self, value: u32, timeout: Option<Duration>) -> bool {
sys::mutex(&self.value, &MutexOperation::Wait(value, timeout)).is_ok()
}
}
@@ -0,0 +1,7 @@
mod condvar;
mod mutex;
mod rwlock;
pub use condvar::Condvar;
pub use mutex::Mutex;
pub use rwlock::RwLock;
@@ -0,0 +1,60 @@
use crate::sync::atomic::{AtomicU32, Ordering};
use crate::time::Duration;
use yggdrasil_rt::{process::MutexOperation, sys};
pub struct Mutex {
value: AtomicU32,
}
unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {} // no threads on this platform
impl Mutex {
const UNLOCKED: u32 = 0;
const LOCKED: u32 = 1;
#[inline]
#[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
pub const fn new() -> Mutex {
Mutex { value: AtomicU32::new(Self::UNLOCKED) }
}
#[inline]
pub fn lock(&self) {
loop {
if self.try_lock() {
// Got a lock!
return;
}
// Wait until the value becomes something other than "1" (0)
self.wait(Self::LOCKED);
}
}
#[inline]
pub unsafe fn unlock(&self) {
if self.value.swap(Self::UNLOCKED, Ordering::Release) != Self::UNLOCKED {
self.wake();
}
}
#[inline]
pub fn try_lock(&self) -> bool {
self.value
.compare_exchange(Self::UNLOCKED, Self::LOCKED, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
}
fn wait(&self, value: u32) {
unsafe {
sys::mutex(&self.value, &MutexOperation::Wait(value, None)).ok();
}
}
fn wake(&self) {
unsafe {
sys::mutex(&self.value, &MutexOperation::Wake).ok();
}
}
}
@@ -0,0 +1,64 @@
use crate::cell::Cell;
pub struct RwLock {
mode: Cell<i32>,
}
unsafe impl Send for RwLock {}
unsafe impl Sync for RwLock {} // no threads on this platform
impl RwLock {
#[inline]
#[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
pub const fn new() -> RwLock {
RwLock { mode: Cell::new(0) }
}
#[inline]
pub fn read(&self) {
let m = self.mode.get();
if m >= 0 {
self.mode.set(m + 1);
} else {
rtabort!("rwlock locked for writing");
}
}
#[inline]
pub fn try_read(&self) -> bool {
let m = self.mode.get();
if m >= 0 {
self.mode.set(m + 1);
true
} else {
false
}
}
#[inline]
pub fn write(&self) {
if self.mode.replace(-1) != 0 {
rtabort!("rwlock locked for reading")
}
}
#[inline]
pub fn try_write(&self) -> bool {
if self.mode.get() == 0 {
self.mode.set(-1);
true
} else {
false
}
}
#[inline]
pub unsafe fn read_unlock(&self) {
self.mode.set(self.mode.get() - 1);
}
#[inline]
pub unsafe fn write_unlock(&self) {
assert_eq!(self.mode.replace(0), -1);
}
}
+1
View File
@@ -28,6 +28,7 @@ pub mod pipe;
pub mod process;
pub mod stdio;
pub mod thread;
pub mod thread_local_dtor;
pub mod thread_local_key;
pub mod time;
+35 -4
View File
@@ -1,16 +1,32 @@
use crate::ffi::CStr;
use crate::io;
use crate::num::NonZeroUsize;
use crate::sys::cvt_io;
use crate::time::Duration;
pub struct Thread(!);
use yggdrasil_rt::{process::ThreadSpawnOptions, sys};
#[repr(C)]
pub struct Thread {
id: u32,
}
pub const DEFAULT_MIN_STACK_SIZE: usize = 8192;
impl Thread {
pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
yggdrasil_rt::sys::debug_trace("Thread::new()");
loop {}
pub unsafe fn new(stack_size: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
// Allocate the stack
let (stack_bottom, _, _) = Vec::into_raw_parts(vec![0u8; stack_size]);
let stack_bottom = stack_bottom.addr();
let stack_top = stack_bottom + stack_size - 8;
// Get the "argument"
let argument = Box::into_raw(Box::new(p)).addr() as u64;
let options = ThreadSpawnOptions { entry: Thread::entry, argument, stack_top };
let id = cvt_io(sys::spawn_thread(&options))?;
Ok(Thread { id })
}
pub fn yield_now() {
@@ -35,6 +51,21 @@ impl Thread {
}
loop {}
}
extern "C" fn entry(arg: u64) -> ! {
use yggdrasil_rt::{debug_trace, process::ExitCode, sys};
unsafe {
#[allow(fuzzy_provenance_casts)]
let p: Box<Box<dyn FnOnce()>> = Box::from_raw(arg as *mut _);
debug_trace!("Execute thread");
p();
debug_trace!("Thread finish");
sys::exit(ExitCode::Exited(0));
}
}
}
pub fn available_parallelism() -> io::Result<NonZeroUsize> {
@@ -0,0 +1,29 @@
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
yggdrasil_rt::debug_trace!("TODO: thread_local_dtor::register_dtor()");
// From *nix impl:
//
// use crate::mem;
// use crate::sys_common::thread_local_dtor::register_dtor_fallback;
// extern "C" {
// #[linkage = "extern_weak"]
// static __dso_handle: *mut u8;
// #[linkage = "extern_weak"]
// static __cxa_thread_atexit_impl: *const libc::c_void;
// }
// if !__cxa_thread_atexit_impl.is_null() {
// type F = unsafe extern "C" fn(
// dtor: unsafe extern "C" fn(*mut u8),
// arg: *mut u8,
// dso_handle: *mut u8,
// ) -> libc::c_int;
// mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl)(
// dtor,
// t,
// &__dso_handle as *const _ as *mut _,
// );
// return;
// }
// register_dtor_fallback(t, dtor);
}
@@ -27,6 +27,7 @@ impl LocalKey {
#[inline]
pub unsafe fn create(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
yggdrasil_rt::debug_trace!("LocalKey::create()");
let boxed = Box::new(LocalKey::new(dtor));
let key = Box::into_raw(boxed);
key as usize