Rollup merge of #77610 - hermitcore:dtors, r=m-ou-se
revise Hermit's mutex interface to support the behaviour of StaticMutex rust-lang/rust#77147 simplifies things by splitting this Mutex type into two types matching the two use cases: StaticMutex and MovableMutex. To support the new behavior of StaticMutex, we move part of the mutex implementation into libstd. The interface to the OS changed. Consequently, I removed a few functions, which aren't longer needed.
This commit is contained in:
commit
e34263d86a
8 changed files with 187 additions and 168 deletions
|
@ -1366,9 +1366,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.1.15"
|
version = "0.1.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
|
checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compiler_builtins",
|
"compiler_builtins",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
|
@ -372,7 +372,7 @@ pub fn handle_alloc_error(layout: Layout) -> ! {
|
||||||
unsafe { oom_impl(layout) }
|
unsafe { oom_impl(layout) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(test, bootstrap)))]
|
#[cfg(not(any(target_os = "hermit", test, bootstrap)))]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(unused_attributes)]
|
#[allow(unused_attributes)]
|
||||||
#[unstable(feature = "alloc_internals", issue = "none")]
|
#[unstable(feature = "alloc_internals", issue = "none")]
|
||||||
|
|
|
@ -42,7 +42,7 @@ dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] }
|
||||||
fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
|
fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
|
||||||
|
|
||||||
[target.'cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_os = "hermit"))'.dependencies]
|
[target.'cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_os = "hermit"))'.dependencies]
|
||||||
hermit-abi = { version = "0.1.15", features = ['rustc-dep-of-std'] }
|
hermit-abi = { version = "0.1.17", features = ['rustc-dep-of-std'] }
|
||||||
|
|
||||||
[target.wasm32-wasi.dependencies]
|
[target.wasm32-wasi.dependencies]
|
||||||
wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false }
|
wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false }
|
||||||
|
|
|
@ -334,10 +334,6 @@ impl File {
|
||||||
pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
|
pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
|
||||||
Err(Error::from_raw_os_error(22))
|
Err(Error::from_raw_os_error(22))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn diverge(&self) -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DirBuilder {
|
impl DirBuilder {
|
||||||
|
|
|
@ -31,6 +31,7 @@ pub mod net;
|
||||||
pub mod os;
|
pub mod os;
|
||||||
pub mod path;
|
pub mod path;
|
||||||
pub mod pipe;
|
pub mod pipe;
|
||||||
|
#[path = "../unsupported/process.rs"]
|
||||||
pub mod process;
|
pub mod process;
|
||||||
pub mod rwlock;
|
pub mod rwlock;
|
||||||
pub mod stack_overflow;
|
pub mod stack_overflow;
|
||||||
|
|
|
@ -1,44 +1,214 @@
|
||||||
|
use crate::cell::UnsafeCell;
|
||||||
|
use crate::collections::VecDeque;
|
||||||
use crate::ffi::c_void;
|
use crate::ffi::c_void;
|
||||||
|
use crate::ops::{Deref, DerefMut, Drop};
|
||||||
use crate::ptr;
|
use crate::ptr;
|
||||||
|
use crate::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering};
|
||||||
use crate::sys::hermit::abi;
|
use crate::sys::hermit::abi;
|
||||||
|
|
||||||
pub struct Mutex {
|
/// This type provides a lock based on busy waiting to realize mutual exclusion
|
||||||
inner: *const c_void,
|
///
|
||||||
|
/// # Description
|
||||||
|
///
|
||||||
|
/// This structure behaves a lot like a common mutex. There are some differences:
|
||||||
|
///
|
||||||
|
/// - By using busy waiting, it can be used outside the runtime.
|
||||||
|
/// - It is a so called ticket lock and is completly fair.
|
||||||
|
#[cfg_attr(target_arch = "x86_64", repr(align(128)))]
|
||||||
|
#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))]
|
||||||
|
struct Spinlock<T: ?Sized> {
|
||||||
|
queue: AtomicUsize,
|
||||||
|
dequeue: AtomicUsize,
|
||||||
|
data: UnsafeCell<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: ?Sized + Send> Sync for Spinlock<T> {}
|
||||||
|
unsafe impl<T: ?Sized + Send> Send for Spinlock<T> {}
|
||||||
|
|
||||||
|
/// A guard to which the protected data can be accessed
|
||||||
|
///
|
||||||
|
/// When the guard falls out of scope it will release the lock.
|
||||||
|
struct SpinlockGuard<'a, T: ?Sized + 'a> {
|
||||||
|
dequeue: &'a AtomicUsize,
|
||||||
|
data: &'a mut T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Spinlock<T> {
|
||||||
|
pub const fn new(user_data: T) -> Spinlock<T> {
|
||||||
|
Spinlock {
|
||||||
|
queue: AtomicUsize::new(0),
|
||||||
|
dequeue: AtomicUsize::new(1),
|
||||||
|
data: UnsafeCell::new(user_data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn obtain_lock(&self) {
|
||||||
|
let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
|
||||||
|
while self.dequeue.load(Ordering::SeqCst) != ticket {
|
||||||
|
spin_loop_hint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> {
|
||||||
|
self.obtain_lock();
|
||||||
|
SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + Default> Default for Spinlock<T> {
|
||||||
|
fn default() -> Spinlock<T> {
|
||||||
|
Spinlock::new(Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> {
|
||||||
|
type Target = T;
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
&*self.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
|
&mut *self.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> {
|
||||||
|
/// The dropping of the SpinlockGuard will release the lock it was created from.
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.dequeue.fetch_add(1, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Realize a priority queue for tasks
|
||||||
|
struct PriorityQueue {
|
||||||
|
queues: [Option<VecDeque<abi::Tid>>; abi::NO_PRIORITIES],
|
||||||
|
prio_bitmap: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PriorityQueue {
|
||||||
|
pub const fn new() -> PriorityQueue {
|
||||||
|
PriorityQueue {
|
||||||
|
queues: [
|
||||||
|
None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
||||||
|
None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
||||||
|
None, None, None,
|
||||||
|
],
|
||||||
|
prio_bitmap: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a task id by its priority to the queue
|
||||||
|
pub fn push(&mut self, prio: abi::Priority, id: abi::Tid) {
|
||||||
|
let i: usize = prio.into().into();
|
||||||
|
self.prio_bitmap |= (1 << i) as u64;
|
||||||
|
if let Some(queue) = &mut self.queues[i] {
|
||||||
|
queue.push_back(id);
|
||||||
|
} else {
|
||||||
|
let mut queue = VecDeque::new();
|
||||||
|
queue.push_back(id);
|
||||||
|
self.queues[i] = Some(queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_from_queue(&mut self, queue_index: usize) -> Option<abi::Tid> {
|
||||||
|
if let Some(queue) = &mut self.queues[queue_index] {
|
||||||
|
let id = queue.pop_front();
|
||||||
|
|
||||||
|
if queue.is_empty() {
|
||||||
|
self.prio_bitmap &= !(1 << queue_index as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
id
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pop the task handle with the highest priority from the queue
|
||||||
|
pub fn pop(&mut self) -> Option<abi::Tid> {
|
||||||
|
for i in 0..abi::NO_PRIORITIES {
|
||||||
|
if self.prio_bitmap & (1 << i) != 0 {
|
||||||
|
return self.pop_from_queue(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MutexInner {
|
||||||
|
locked: bool,
|
||||||
|
blocked_task: PriorityQueue,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MutexInner {
|
||||||
|
pub const fn new() -> MutexInner {
|
||||||
|
MutexInner { locked: false, blocked_task: PriorityQueue::new() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Mutex {
|
||||||
|
inner: Spinlock<MutexInner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type MovableMutex = Box<Mutex>;
|
||||||
|
|
||||||
unsafe impl Send for Mutex {}
|
unsafe impl Send for Mutex {}
|
||||||
unsafe impl Sync for Mutex {}
|
unsafe impl Sync for Mutex {}
|
||||||
|
|
||||||
impl Mutex {
|
impl Mutex {
|
||||||
pub const fn new() -> Mutex {
|
pub const fn new() -> Mutex {
|
||||||
Mutex { inner: ptr::null() }
|
Mutex { inner: Spinlock::new(MutexInner::new()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn init(&mut self) {
|
pub unsafe fn init(&mut self) {
|
||||||
let _ = abi::sem_init(&mut self.inner as *mut *const c_void, 1);
|
self.inner = Spinlock::new(MutexInner::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn lock(&self) {
|
pub unsafe fn lock(&self) {
|
||||||
let _ = abi::sem_timedwait(self.inner, 0);
|
loop {
|
||||||
|
let mut guard = self.inner.lock();
|
||||||
|
if guard.locked == false {
|
||||||
|
guard.locked = true;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
let prio = abi::get_priority();
|
||||||
|
let id = abi::getpid();
|
||||||
|
|
||||||
|
guard.blocked_task.push(prio, id);
|
||||||
|
abi::block_current_task();
|
||||||
|
drop(guard);
|
||||||
|
abi::yield_now();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn unlock(&self) {
|
pub unsafe fn unlock(&self) {
|
||||||
let _ = abi::sem_post(self.inner);
|
let mut guard = self.inner.lock();
|
||||||
|
guard.locked = false;
|
||||||
|
if let Some(tid) = guard.blocked_task.pop() {
|
||||||
|
abi::wakeup_task(tid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn try_lock(&self) -> bool {
|
pub unsafe fn try_lock(&self) -> bool {
|
||||||
let result = abi::sem_trywait(self.inner);
|
let mut guard = self.inner.lock();
|
||||||
result == 0
|
if guard.locked == false {
|
||||||
|
guard.locked = true;
|
||||||
|
}
|
||||||
|
guard.locked
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn destroy(&self) {
|
pub unsafe fn destroy(&self) {}
|
||||||
let _ = abi::sem_destroy(self.inner);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ReentrantMutex {
|
pub struct ReentrantMutex {
|
||||||
|
|
|
@ -1,149 +0,0 @@
|
||||||
use crate::ffi::OsStr;
|
|
||||||
use crate::fmt;
|
|
||||||
use crate::io;
|
|
||||||
use crate::sys::fs::File;
|
|
||||||
use crate::sys::pipe::AnonPipe;
|
|
||||||
use crate::sys::{unsupported, Void};
|
|
||||||
use crate::sys_common::process::CommandEnv;
|
|
||||||
|
|
||||||
pub use crate::ffi::OsString as EnvKey;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Command
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
pub struct Command {
|
|
||||||
env: CommandEnv,
|
|
||||||
}
|
|
||||||
|
|
||||||
// passed back to std::process with the pipes connected to the child, if any
|
|
||||||
// were requested
|
|
||||||
pub struct StdioPipes {
|
|
||||||
pub stdin: Option<AnonPipe>,
|
|
||||||
pub stdout: Option<AnonPipe>,
|
|
||||||
pub stderr: Option<AnonPipe>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Stdio {
|
|
||||||
Inherit,
|
|
||||||
Null,
|
|
||||||
MakePipe,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command {
|
|
||||||
pub fn new(_program: &OsStr) -> Command {
|
|
||||||
Command { env: Default::default() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn arg(&mut self, _arg: &OsStr) {}
|
|
||||||
|
|
||||||
pub fn env_mut(&mut self) -> &mut CommandEnv {
|
|
||||||
&mut self.env
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cwd(&mut self, _dir: &OsStr) {}
|
|
||||||
|
|
||||||
pub fn stdin(&mut self, _stdin: Stdio) {}
|
|
||||||
|
|
||||||
pub fn stdout(&mut self, _stdout: Stdio) {}
|
|
||||||
|
|
||||||
pub fn stderr(&mut self, _stderr: Stdio) {}
|
|
||||||
|
|
||||||
pub fn spawn(
|
|
||||||
&mut self,
|
|
||||||
_default: Stdio,
|
|
||||||
_needs_stdin: bool,
|
|
||||||
) -> io::Result<(Process, StdioPipes)> {
|
|
||||||
unsupported()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<AnonPipe> for Stdio {
|
|
||||||
fn from(pipe: AnonPipe) -> Stdio {
|
|
||||||
pipe.diverge()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<File> for Stdio {
|
|
||||||
fn from(file: File) -> Stdio {
|
|
||||||
file.diverge()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Command {
|
|
||||||
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ExitStatus(Void);
|
|
||||||
|
|
||||||
impl ExitStatus {
|
|
||||||
pub fn success(&self) -> bool {
|
|
||||||
match self.0 {}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn code(&self) -> Option<i32> {
|
|
||||||
match self.0 {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for ExitStatus {
|
|
||||||
fn clone(&self) -> ExitStatus {
|
|
||||||
match self.0 {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Copy for ExitStatus {}
|
|
||||||
|
|
||||||
impl PartialEq for ExitStatus {
|
|
||||||
fn eq(&self, _other: &ExitStatus) -> bool {
|
|
||||||
match self.0 {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for ExitStatus {}
|
|
||||||
|
|
||||||
impl fmt::Debug for ExitStatus {
|
|
||||||
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self.0 {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ExitStatus {
|
|
||||||
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self.0 {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
|
||||||
pub struct ExitCode(bool);
|
|
||||||
|
|
||||||
impl ExitCode {
|
|
||||||
pub const SUCCESS: ExitCode = ExitCode(false);
|
|
||||||
pub const FAILURE: ExitCode = ExitCode(true);
|
|
||||||
|
|
||||||
pub fn as_i32(&self) -> i32 {
|
|
||||||
self.0 as i32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Process(Void);
|
|
||||||
|
|
||||||
impl Process {
|
|
||||||
pub fn id(&self) -> u32 {
|
|
||||||
match self.0 {}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kill(&mut self) -> io::Result<()> {
|
|
||||||
match self.0 {}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn wait(&mut self) -> io::Result<ExitStatus> {
|
|
||||||
match self.0 {}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
|
|
||||||
match self.0 {}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -89,6 +89,7 @@ cfg_if::cfg_if! {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use self::ext as windows_ext;
|
pub use self::ext as windows_ext;
|
||||||
} else if #[cfg(any(target_os = "cloudabi",
|
} else if #[cfg(any(target_os = "cloudabi",
|
||||||
|
target_os = "hermit",
|
||||||
target_arch = "wasm32",
|
target_arch = "wasm32",
|
||||||
all(target_vendor = "fortanix", target_env = "sgx")))] {
|
all(target_vendor = "fortanix", target_env = "sgx")))] {
|
||||||
// On CloudABI and wasm right now the shim below doesn't compile, so
|
// On CloudABI and wasm right now the shim below doesn't compile, so
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue