1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! System bindings for the wasm/web platform
13 //! This module contains the facade (aka platform-specific) implementations of
14 //! OS level functionality for wasm. Note that this wasm is *not* the emscripten
15 //! wasm, so we have no runtime here.
17 //! This is all super highly experimental and not actually intended for
18 //! wide/production use yet, it's still all in the experimental category. This
19 //! will likely change over time.
21 //! Currently all functions here are basically stubs that immediately return
22 //! errors. The hope is that with a portability lint we can turn actually just
23 //! remove all this and just omit parts of the standard library if we're
24 //! compiling for wasm. That way it's a compile time error for something that's
25 //! guaranteed to be a runtime error!
31 use sys_common::{AsInner, FromInner};
32 use ffi::{OsString, OsStr};
36 #[cfg(feature = "backtrace")]
48 pub mod stack_overflow;
54 if #[cfg(target_feature = "atomics")] {
55 #[path = "condvar_atomics.rs"]
57 #[path = "mutex_atomics.rs"]
59 #[path = "rwlock_atomics.rs"]
61 #[path = "thread_local_atomics.rs"]
75 pub fn unsupported<T>() -> io::Result<T> {
76 Err(unsupported_err())
79 pub fn unsupported_err() -> io::Error {
80 io::Error::new(io::ErrorKind::Other,
81 "operation not supported on wasm yet")
84 pub fn decode_error_kind(_code: i32) -> io::ErrorKind {
88 // This enum is used as the storage for a bunch of types which can't actually
90 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
93 pub unsafe fn strlen(mut s: *const c_char) -> usize {
102 pub unsafe fn abort_internal() -> ! {
103 ExitSysCall::perform(1)
106 // We don't have randomness yet, but I totally used a random number generator to
107 // generate these numbers.
109 // More seriously though this is just for DOS protection in hash maps. It's ok
110 // if we don't do that on wasm just yet.
111 pub fn hashmap_random_keys() -> (u64, u64) {
115 // Implement a minimal set of system calls to enable basic IO
116 pub enum SysCallIndex {
127 pub struct ReadSysCall {
135 pub fn perform(fd: usize, buffer: &mut [u8]) -> usize {
136 let mut call_record = ReadSysCall {
139 ptr: buffer.as_mut_ptr(),
142 if unsafe { syscall(SysCallIndex::Read, &mut call_record) } {
151 pub struct WriteSysCall {
158 pub fn perform(fd: usize, buffer: &[u8]) {
159 let mut call_record = WriteSysCall {
164 unsafe { syscall(SysCallIndex::Write, &mut call_record); }
169 pub struct ExitSysCall {
174 pub fn perform(code: usize) -> ! {
175 let mut call_record = ExitSysCall {
179 syscall(SysCallIndex::Exit, &mut call_record);
180 ::intrinsics::abort();
185 fn receive_buffer<E, F: FnMut(&mut [u8]) -> Result<usize, E>>(estimate: usize, mut f: F)
186 -> Result<Vec<u8>, E>
188 let mut buffer = vec![0; estimate];
190 let result = f(&mut buffer)?;
191 if result <= buffer.len() {
192 buffer.truncate(result);
195 buffer.resize(result, 0);
201 pub struct ArgsSysCall {
208 pub fn perform() -> Vec<OsString> {
209 receive_buffer(1024, |buffer| -> Result<usize, !> {
210 let mut call_record = ArgsSysCall {
212 ptr: buffer.as_mut_ptr(),
215 if unsafe { syscall(SysCallIndex::Args, &mut call_record) } {
216 Ok(call_record.result)
223 .map(|s| FromInner::from_inner(Buf { inner: s.to_owned() }))
229 pub struct GetEnvSysCall {
238 pub fn perform(key: &OsStr) -> Option<OsString> {
239 let key_buf = &AsInner::as_inner(key).inner;
240 receive_buffer(64, |buffer| {
241 let mut call_record = GetEnvSysCall {
242 key_len: key_buf.len(),
243 key_ptr: key_buf.as_ptr(),
244 value_len: buffer.len(),
245 value_ptr: buffer.as_mut_ptr(),
248 if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) } {
249 if call_record.result == !0usize {
252 Ok(call_record.result)
258 FromInner::from_inner(Buf { inner: s })
264 pub struct SetEnvSysCall {
267 value_ptr: *const u8,
272 pub fn perform(key: &OsStr, value: Option<&OsStr>) {
273 let key_buf = &AsInner::as_inner(key).inner;
274 let value_buf = value.map(|v| &AsInner::as_inner(v).inner);
275 let mut call_record = SetEnvSysCall {
276 key_len: key_buf.len(),
277 key_ptr: key_buf.as_ptr(),
278 value_len: value_buf.map(|v| v.len()).unwrap_or(!0usize),
279 value_ptr: value_buf.map(|v| v.as_ptr()).unwrap_or(ptr::null())
281 unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); }
291 pub struct TimeSysCall {
299 pub fn perform(clock: TimeClock) -> Duration {
300 let mut call_record = TimeSysCall {
301 clock: clock as usize,
306 if unsafe { syscall(SysCallIndex::Time, &mut call_record) } {
308 ((call_record.secs_hi as u64) << 32) | (call_record.secs_lo as u64),
309 call_record.nanos as u32
312 panic!("Time system call is not implemented by WebAssembly host");
317 unsafe fn syscall<T>(index: SysCallIndex, data: &mut T) -> bool {
318 #[cfg(feature = "wasm_syscall")]
321 fn rust_wasm_syscall(index: usize, data: *mut Void) -> usize;
324 #[cfg(not(feature = "wasm_syscall"))]
325 unsafe fn rust_wasm_syscall(_index: usize, _data: *mut Void) -> usize { 0 }
327 rust_wasm_syscall(index as usize, data as *mut T as *mut Void) != 0