1 //! System bindings for the wasm/web platform
3 //! This module contains the facade (aka platform-specific) implementations of
4 //! OS level functionality for wasm. Note that this wasm is *not* the emscripten
5 //! wasm, so we have no runtime here.
7 //! This is all super highly experimental and not actually intended for
8 //! wide/production use yet, it's still all in the experimental category. This
9 //! will likely change over time.
11 //! Currently all functions here are basically stubs that immediately return
12 //! errors. The hope is that with a portability lint we can turn actually just
13 //! remove all this and just omit parts of the standard library if we're
14 //! compiling for wasm. That way it's a compile time error for something that's
15 //! guaranteed to be a runtime error!
17 use crate::os::raw::c_char;
19 use crate::sys::os_str::Buf;
20 use crate::sys_common::{AsInner, FromInner};
21 use crate::ffi::{OsString, OsStr};
22 use crate::time::Duration;
36 pub mod stack_overflow;
41 pub use crate::sys_common::os_str_bytes as os_str;
44 if #[cfg(target_feature = "atomics")] {
45 #[path = "condvar_atomics.rs"]
47 #[path = "mutex_atomics.rs"]
49 #[path = "rwlock_atomics.rs"]
51 #[path = "thread_local_atomics.rs"]
65 pub fn unsupported<T>() -> crate::io::Result<T> {
66 Err(unsupported_err())
69 pub fn unsupported_err() -> crate::io::Error {
70 crate::io::Error::new(crate::io::ErrorKind::Other,
71 "operation not supported on wasm yet")
74 pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind {
75 crate::io::ErrorKind::Other
78 // This enum is used as the storage for a bunch of types which can't actually
80 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
83 pub unsafe fn strlen(mut s: *const c_char) -> usize {
92 pub unsafe fn abort_internal() -> ! {
93 ExitSysCall::perform(1)
96 // We don't have randomness yet, but I totally used a random number generator to
97 // generate these numbers.
99 // More seriously though this is just for DOS protection in hash maps. It's ok
100 // if we don't do that on wasm just yet.
101 pub fn hashmap_random_keys() -> (u64, u64) {
105 // Implement a minimal set of system calls to enable basic IO
106 pub enum SysCallIndex {
117 pub struct ReadSysCall {
125 pub fn perform(fd: usize, buffer: &mut [u8]) -> usize {
126 let mut call_record = ReadSysCall {
129 ptr: buffer.as_mut_ptr(),
132 if unsafe { syscall(SysCallIndex::Read, &mut call_record) } {
141 pub struct WriteSysCall {
148 pub fn perform(fd: usize, buffer: &[u8]) {
149 let mut call_record = WriteSysCall {
154 unsafe { syscall(SysCallIndex::Write, &mut call_record); }
159 pub struct ExitSysCall {
164 pub fn perform(code: usize) -> ! {
165 let mut call_record = ExitSysCall {
169 syscall(SysCallIndex::Exit, &mut call_record);
170 crate::intrinsics::abort();
175 fn receive_buffer<E, F: FnMut(&mut [u8]) -> Result<usize, E>>(estimate: usize, mut f: F)
176 -> Result<Vec<u8>, E>
178 let mut buffer = vec![0; estimate];
180 let result = f(&mut buffer)?;
181 if result <= buffer.len() {
182 buffer.truncate(result);
185 buffer.resize(result, 0);
191 pub struct ArgsSysCall {
198 pub fn perform() -> Vec<OsString> {
199 receive_buffer(1024, |buffer| -> Result<usize, !> {
200 let mut call_record = ArgsSysCall {
202 ptr: buffer.as_mut_ptr(),
205 if unsafe { syscall(SysCallIndex::Args, &mut call_record) } {
206 Ok(call_record.result)
213 .map(|s| FromInner::from_inner(Buf { inner: s.to_owned() }))
219 pub struct GetEnvSysCall {
228 pub fn perform(key: &OsStr) -> Option<OsString> {
229 let key_buf = &AsInner::as_inner(key).inner;
230 receive_buffer(64, |buffer| {
231 let mut call_record = GetEnvSysCall {
232 key_len: key_buf.len(),
233 key_ptr: key_buf.as_ptr(),
234 value_len: buffer.len(),
235 value_ptr: buffer.as_mut_ptr(),
238 if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) } {
239 if call_record.result == !0usize {
242 Ok(call_record.result)
248 FromInner::from_inner(Buf { inner: s })
254 pub struct SetEnvSysCall {
257 value_ptr: *const u8,
262 pub fn perform(key: &OsStr, value: Option<&OsStr>) {
263 let key_buf = &AsInner::as_inner(key).inner;
264 let value_buf = value.map(|v| &AsInner::as_inner(v).inner);
265 let mut call_record = SetEnvSysCall {
266 key_len: key_buf.len(),
267 key_ptr: key_buf.as_ptr(),
268 value_len: value_buf.map(|v| v.len()).unwrap_or(!0usize),
269 value_ptr: value_buf.map(|v| v.as_ptr()).unwrap_or(ptr::null())
271 unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); }
281 pub struct TimeSysCall {
289 pub fn perform(clock: TimeClock) -> Duration {
290 let mut call_record = TimeSysCall {
291 clock: clock as usize,
296 if unsafe { syscall(SysCallIndex::Time, &mut call_record) } {
298 ((call_record.secs_hi as u64) << 32) | (call_record.secs_lo as u64),
299 call_record.nanos as u32
302 panic!("Time system call is not implemented by WebAssembly host");
307 unsafe fn syscall<T>(index: SysCallIndex, data: &mut T) -> bool {
308 #[cfg(feature = "wasm_syscall")]
311 fn rust_wasm_syscall(index: usize, data: *mut Void) -> usize;
314 #[cfg(not(feature = "wasm_syscall"))]
315 unsafe fn rust_wasm_syscall(_index: usize, _data: *mut Void) -> usize { 0 }
317 rust_wasm_syscall(index as usize, data as *mut T as *mut Void) != 0