|
| 1 | +//! Platform-specific parts of the standard library |
| 2 | +//! that can be plugged-in at runtime. |
| 3 | +//! |
| 4 | +//! Using these modules, code can set an implementation for |
| 5 | +//! each platform-specific part of the standard library at |
| 6 | +//! runtime. It does so via the `set_impl` functions. |
| 7 | +//! |
| 8 | +//! This is primarily geared toward experimental platforms such |
| 9 | +//! as new kernels and bare-bones environments, where you might |
| 10 | +//! want to use the standard library without recompiling |
| 11 | +//! everything or adding support upstream. |
| 12 | +//! |
| 13 | +//! # Initial state |
| 14 | +//! |
| 15 | +//! Initially, as no implementation has been defined, most |
| 16 | +//! of these parts panic with this message: |
| 17 | +//! |
| 18 | +//! ```text |
| 19 | +//! std::os::thread::IMPL has not been initialized at this point. |
| 20 | +//! ``` |
| 21 | +//! |
| 22 | +//! There are three exceptions: |
| 23 | +//! |
| 24 | +//! - There is a default allocator, allowing for 16KiB of heap use. |
| 25 | +//! It implements the sequential fit algorithm. |
| 26 | +//! - Initially, locking primitives are functional and behave as spinlocks. |
| 27 | +//! - Before `os::set_impl` has been called, any call to `abort_internal` |
| 28 | +//! will result in an infinite loop. |
| 29 | +//! |
| 30 | +//! These should be set/changed as soon as possible, as they are used internally. |
| 31 | +//! |
| 32 | +//! # To do |
| 33 | +//! |
| 34 | +//! - thread parking support |
| 35 | +//! - thread-safe Once support |
| 36 | +//! - invocation arguments (returns an empty iterator at the moment) |
| 37 | +//! - `pipe::read2` |
| 38 | +//! |
| 39 | +
|
| 40 | +#![unstable(issue = "none", feature = "std_internals")] |
| 41 | + |
| 42 | +#[doc(hidden)] |
| 43 | +#[macro_export] |
| 44 | +macro_rules! custom_os_impl { |
| 45 | + ($module:ident, $method:ident $(, $arg:expr)*) => {{ |
| 46 | + let errmsg = concat!( |
| 47 | + "std::os::", stringify!($module), "::IMPL", |
| 48 | + " has not been initialized at this point", |
| 49 | + ); |
| 50 | + |
| 51 | + let rwlock = &crate::os::custom::$module::IMPL; |
| 52 | + let reader = rwlock.read().expect("poisoned lock"); |
| 53 | + let some_impl = reader.as_ref().expect(errmsg); |
| 54 | + |
| 55 | + some_impl.$method($($arg,)*) |
| 56 | + }}; |
| 57 | +} |
| 58 | + |
| 59 | +macro_rules! static_rwlock_box_impl { |
| 60 | + ($api:ident) => { |
| 61 | + pub(crate) static IMPL: RwLock<Option<Box<dyn $api>>> = RwLock::new(None); |
| 62 | + |
| 63 | + /// Sets the implementation singleton |
| 64 | + /// |
| 65 | + /// This parameter takes a `transition` closure responsible |
| 66 | + /// for properly transitioning from the previous implementation |
| 67 | + /// to a new one. |
| 68 | + /// |
| 69 | + /// Initially, there is no implementation; the first time this is called, |
| 70 | + /// the closure parameter will be `None`. |
| 71 | + /// |
| 72 | + /// Removing an implementation (i.e. setting the internal singleton to `None`) |
| 73 | + /// is intentionally not allowed. |
| 74 | + pub fn set_impl<F: FnMut(Option<Box<dyn $api>>) -> Box<dyn $api>>(mut transition: F) { |
| 75 | + let mut writer = IMPL.write().expect("poisoned lock"); |
| 76 | + let maybe_impl = core::mem::replace(&mut *writer, None); |
| 77 | + let new_impl = transition(maybe_impl); |
| 78 | + *writer = Some(new_impl); |
| 79 | + } |
| 80 | + } |
| 81 | +} |
| 82 | + |
| 83 | +/// Platform-specific allocator |
| 84 | +pub mod alloc { |
| 85 | + use crate::alloc::GlobalAlloc; |
| 86 | + use crate::sync::RwLock; |
| 87 | + |
| 88 | + static_rwlock_box_impl!(Allocator); |
| 89 | + |
| 90 | + /// Platform-specific allocator |
| 91 | + pub trait Allocator: GlobalAlloc + Send + Sync {} |
| 92 | +} |
| 93 | + |
| 94 | +/// Platform-specific interface to a filesystem |
| 95 | +pub mod fs { |
| 96 | + use crate::sync::RwLock; |
| 97 | + use crate::path::{Path, PathBuf}; |
| 98 | + use crate::io; |
| 99 | + |
| 100 | + #[doc(inline)] |
| 101 | + pub use crate::sys::fs::{ |
| 102 | + File, FileAttr, ReadDir, ReadDirApi, FileApi, DirEntry, |
| 103 | + FilePermissions, OpenOptions, FileTimes, FileType, |
| 104 | + }; |
| 105 | + |
| 106 | + static_rwlock_box_impl!(FilesystemInterface); |
| 107 | + |
| 108 | + /// Platform-specific interface to a filesystem |
| 109 | + pub trait FilesystemInterface: Send + Sync { |
| 110 | + fn open(&self, path: &Path, opts: &OpenOptions) -> io::Result<File>; |
| 111 | + fn mkdir(&self, p: &Path) -> io::Result<()>; |
| 112 | + fn read_dir(&self, p: &Path) -> io::Result<ReadDir>; |
| 113 | + fn unlink(&self, p: &Path) -> io::Result<()>; |
| 114 | + fn rename(&self, old: &Path, new: &Path) -> io::Result<()>; |
| 115 | + fn set_perm(&self, p: &Path, perm: FilePermissions) -> io::Result<()>; |
| 116 | + fn rmdir(&self, p: &Path) -> io::Result<()>; |
| 117 | + fn remove_dir_all(&self, path: &Path) -> io::Result<()>; |
| 118 | + fn try_exists(&self, path: &Path) -> io::Result<bool>; |
| 119 | + fn readlink(&self, p: &Path) -> io::Result<PathBuf>; |
| 120 | + fn symlink(&self, original: &Path, link: &Path) -> io::Result<()>; |
| 121 | + fn link(&self, src: &Path, dst: &Path) -> io::Result<()>; |
| 122 | + fn stat(&self, p: &Path) -> io::Result<FileAttr>; |
| 123 | + fn lstat(&self, p: &Path) -> io::Result<FileAttr>; |
| 124 | + fn canonicalize(&self, p: &Path) -> io::Result<PathBuf>; |
| 125 | + fn copy(&self, from: &Path, to: &Path) -> io::Result<u64>; |
| 126 | + } |
| 127 | +} |
| 128 | + |
| 129 | +/// Platform-specific management of `AtomicU32`-based futexes |
| 130 | +pub mod futex { |
| 131 | + use crate::sync::{atomic::AtomicU32, RwLock}; |
| 132 | + use crate::time::Duration; |
| 133 | + |
| 134 | + // by default (None) => spinlock |
| 135 | + static_rwlock_box_impl!(FutexManager); |
| 136 | + |
| 137 | + /// Platform-specific management of `AtomicU32`-based futexes |
| 138 | + pub trait FutexManager: Send + Sync { |
| 139 | + /// Wait for a futex_wake operation to wake us. |
| 140 | + /// |
| 141 | + /// Returns directly if the futex doesn't hold the expected value. |
| 142 | + /// |
| 143 | + /// Returns false on timeout, and true in all other cases. |
| 144 | + fn futex_wait(&self, futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool; |
| 145 | + |
| 146 | + /// Wake up one thread that's blocked on futex_wait on this futex. |
| 147 | + /// |
| 148 | + /// Returns true if this actually woke up such a thread, |
| 149 | + /// or false if no thread was waiting on this futex. |
| 150 | + /// |
| 151 | + /// On some platforms, this always returns false. |
| 152 | + fn futex_wake(&self, futex: &AtomicU32) -> bool; |
| 153 | + |
| 154 | + /// Wake up all threads that are waiting on futex_wait on this futex. |
| 155 | + fn futex_wake_all(&self, futex: &AtomicU32); |
| 156 | + } |
| 157 | +} |
| 158 | + |
| 159 | +/// Platform-specific interface to a network |
| 160 | +pub mod net { |
| 161 | + use crate::sync::RwLock; |
| 162 | + use crate::net::SocketAddr; |
| 163 | + use crate::time::Duration; |
| 164 | + use crate::io; |
| 165 | + |
| 166 | + #[doc(inline)] |
| 167 | + pub use crate::sys::net::{ |
| 168 | + TcpStreamApi, TcpListenerApi, UdpSocketApi, |
| 169 | + TcpStream, TcpListener, UdpSocket, LookupHost, |
| 170 | + }; |
| 171 | + |
| 172 | + static_rwlock_box_impl!(NetworkInterface); |
| 173 | + |
| 174 | + /// Platform-specific interface to a network |
| 175 | + pub trait NetworkInterface: Send + Sync { |
| 176 | + fn tcp_connect(&self, addr: &SocketAddr, timeout: Option<Duration>) -> io::Result<TcpStream>; |
| 177 | + fn tcp_bind (&self, addr: &SocketAddr) -> io::Result<TcpListener>; |
| 178 | + fn udp_bind (&self, addr: &SocketAddr) -> io::Result<UdpSocket>; |
| 179 | + fn lookup_str (&self, v: &str) -> io::Result<LookupHost>; |
| 180 | + fn lookup_tuple(&self, v: (&str, u16)) -> io::Result<LookupHost>; |
| 181 | + } |
| 182 | +} |
| 183 | + |
| 184 | +/// Platform-specific interface to the running operating system |
| 185 | +pub mod os { |
| 186 | + use crate::ffi::{OsStr, OsString}; |
| 187 | + use crate::path::{Path, PathBuf}; |
| 188 | + use crate::sync::RwLock; |
| 189 | + use crate::io; |
| 190 | + |
| 191 | + #[doc(inline)] |
| 192 | + pub use crate::sys::os::{Variable, Env, SplitPaths, JoinPathsError}; |
| 193 | + |
| 194 | + static_rwlock_box_impl!(Os); |
| 195 | + |
| 196 | + /// Platform-specific interface to the running operating system |
| 197 | + pub trait Os: Send + Sync { |
| 198 | + fn errno(&self) -> i32; |
| 199 | + fn error_string(&self, errno: i32) -> String; |
| 200 | + |
| 201 | + fn current_exe(&self) -> io::Result<PathBuf>; |
| 202 | + fn env(&self) -> Env; |
| 203 | + fn get_env(&self, variable: &OsStr) -> Option<OsString>; |
| 204 | + fn set_env(&self, variable: &OsStr, value: &OsStr) -> io::Result<()>; |
| 205 | + fn unset_env(&self, variable: &OsStr) -> io::Result<()>; |
| 206 | + fn env_path_delim(&self) -> &'static str; |
| 207 | + |
| 208 | + fn getcwd(&self) -> io::Result<PathBuf>; |
| 209 | + fn temp_dir(&self) -> PathBuf; |
| 210 | + fn home_dir(&self) -> Option<PathBuf>; |
| 211 | + fn chdir(&self, path: &Path) -> io::Result<()>; |
| 212 | + |
| 213 | + fn exit(&self, code: i32) -> !; |
| 214 | + fn get_pid(&self) -> u32; |
| 215 | + |
| 216 | + fn decode_error_kind(&self, errno: i32) -> crate::io::ErrorKind; |
| 217 | + fn hashmap_random_keys(&self) -> (u64, u64); |
| 218 | + } |
| 219 | +} |
| 220 | + |
| 221 | +/// Platform-specific management of processes |
| 222 | +pub mod process { |
| 223 | + use crate::sync::RwLock; |
| 224 | + use crate::io; |
| 225 | + |
| 226 | + #[doc(inline)] |
| 227 | + pub use crate::sys_common::process::{CommandEnv, CommandEnvs}; |
| 228 | + |
| 229 | + #[doc(inline)] |
| 230 | + pub use crate::sys::process::{ |
| 231 | + Command, Process, ProcessApi, |
| 232 | + ExitStatus, Stdio, StdioPipes, |
| 233 | + }; |
| 234 | + |
| 235 | + static_rwlock_box_impl!(ProcessManager); |
| 236 | + |
| 237 | + /// Platform-specific management of processes |
| 238 | + pub trait ProcessManager: Send + Sync { |
| 239 | + fn spawn(&self, command: &Command) -> io::Result<(Process, StdioPipes)>; |
| 240 | + } |
| 241 | +} |
| 242 | + |
| 243 | +/// Platform-specific standard IO interface |
| 244 | +pub mod stdio { |
| 245 | + use crate::sync::RwLock; |
| 246 | + use crate::io; |
| 247 | + |
| 248 | + static_rwlock_box_impl!(StdioInterface); |
| 249 | + |
| 250 | + /// Platform-specific standard IO interface |
| 251 | + pub trait StdioInterface: Send + Sync { |
| 252 | + fn read_stdin(&self, buf: &mut [u8]) -> io::Result<usize>; |
| 253 | + fn write_stdout(&self, buf: &[u8]) -> io::Result<usize>; |
| 254 | + fn flush_stdout(&self) -> io::Result<()>; |
| 255 | + fn write_stderr(&self, buf: &[u8]) -> io::Result<usize>; |
| 256 | + fn flush_stderr(&self) -> io::Result<()>; |
| 257 | + fn is_ebadf(&self, err: &io::Error) -> bool; |
| 258 | + fn panic_output(&self) -> Option<Vec<u8>>; |
| 259 | + } |
| 260 | +} |
| 261 | + |
| 262 | +/// Platform-specific management of threads |
| 263 | +pub mod thread { |
| 264 | + use crate::sync::RwLock; |
| 265 | + use crate::ffi::CStr; |
| 266 | + use crate::num::NonZeroUsize; |
| 267 | + use crate::time::Duration; |
| 268 | + use crate::io; |
| 269 | + |
| 270 | + #[doc(inline)] |
| 271 | + pub use crate::sys::thread::{Thread, ThreadApi}; |
| 272 | + |
| 273 | + static_rwlock_box_impl!(ThreadManager); |
| 274 | + |
| 275 | + /// Platform-specific management of threads |
| 276 | + pub trait ThreadManager: Send + Sync { |
| 277 | + /// unsafe: see thread::Builder::spawn_unchecked for safety requirements |
| 278 | + unsafe fn new(&self, stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread>; |
| 279 | + fn yield_now(&self); |
| 280 | + fn set_name(&self, name: &CStr); |
| 281 | + fn sleep(&self, dur: Duration); |
| 282 | + fn join(&self, thread: &Thread); |
| 283 | + fn available_parallelism(&self) -> io::Result<NonZeroUsize>; |
| 284 | + |
| 285 | + // todo: thread parking |
| 286 | + } |
| 287 | +} |
| 288 | + |
| 289 | +/// Platform-specific timer interface |
| 290 | +pub mod time { |
| 291 | + use crate::sync::RwLock; |
| 292 | + |
| 293 | + pub use crate::sys::time::{Instant, SystemTime}; |
| 294 | + |
| 295 | + static_rwlock_box_impl!(Timer); |
| 296 | + |
| 297 | + /// Platform-specific timer interface |
| 298 | + pub trait Timer: Send + Sync { |
| 299 | + fn now_instant(&self) -> Instant; |
| 300 | + fn now_systime(&self) -> SystemTime; |
| 301 | + } |
| 302 | +} |
0 commit comments