Skip to content

Commit 48edfc7

Browse files
committed
Supports runtime plugging of standard library implementations
1 parent c545019 commit 48edfc7

File tree

22 files changed

+2358
-8
lines changed

22 files changed

+2358
-8
lines changed

library/std/src/os/custom/mod.rs

Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
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+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//! This is a doc-build trick artefact. Check the upstream documentation.
2+
3+
/// This is a doc-build trick artefact. Check the upstream documentation.
4+
pub mod process {
5+
/// This is a doc-build trick artefact. Check the upstream documentation.
6+
pub mod ExitStatusExt {}
7+
}
8+
9+
/// This is a doc-build trick artefact. Check the upstream documentation.
10+
pub mod fs {
11+
/// This is a doc-build trick artefact. Check the upstream documentation.
12+
pub mod PermissionsExt {}
13+
/// This is a doc-build trick artefact. Check the upstream documentation.
14+
pub mod symlink {}
15+
/// This is a doc-build trick artefact. Check the upstream documentation.
16+
pub mod symlink_file {}
17+
/// This is a doc-build trick artefact. Check the upstream documentation.
18+
pub mod symlink_dir {}
19+
}
20+
21+
/// This is a doc-build trick artefact. Check the upstream documentation.
22+
pub mod ffi {
23+
/// This is a doc-build trick artefact. Check the upstream documentation.
24+
pub mod OsStrExt {
25+
/// This is a doc-build trick artefact. Check the upstream documentation.
26+
pub mod encode_wide {}
27+
/// This is a doc-build trick artefact. Check the upstream documentation.
28+
pub mod from_bytes {}
29+
/// This is a doc-build trick artefact. Check the upstream documentation.
30+
pub mod as_bytes {}
31+
}
32+
33+
/// This is a doc-build trick artefact. Check the upstream documentation.
34+
pub mod OsStringExt {
35+
/// This is a doc-build trick artefact. Check the upstream documentation.
36+
pub mod from_wide {}
37+
/// This is a doc-build trick artefact. Check the upstream documentation.
38+
pub mod from_vec {}
39+
/// This is a doc-build trick artefact. Check the upstream documentation.
40+
pub mod into_vec {}
41+
}
42+
}

0 commit comments

Comments
 (0)