]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/wasm/mod.rs
Rollup merge of #47846 - roblabla:bugfix-ocaml, r=kennytm
[rust.git] / src / libstd / sys / wasm / mod.rs
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.
4 //
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.
10
11 //! System bindings for the wasm/web platform
12 //!
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.
16 //!
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.
20 //!
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!
26
27 use io;
28 use os::raw::c_char;
29 use ptr;
30 use sys::os_str::Buf;
31 use sys_common::{AsInner, FromInner};
32 use ffi::{OsString, OsStr};
33 use time::Duration;
34
35 pub mod args;
36 #[cfg(feature = "backtrace")]
37 pub mod backtrace;
38 pub mod cmath;
39 pub mod condvar;
40 pub mod env;
41 pub mod fs;
42 pub mod memchr;
43 pub mod mutex;
44 pub mod net;
45 pub mod os;
46 pub mod os_str;
47 pub mod path;
48 pub mod pipe;
49 pub mod process;
50 pub mod rwlock;
51 pub mod stack_overflow;
52 pub mod thread;
53 pub mod thread_local;
54 pub mod time;
55 pub mod stdio;
56
57 #[cfg(not(test))]
58 pub fn init() {
59 }
60
61 pub fn unsupported<T>() -> io::Result<T> {
62     Err(unsupported_err())
63 }
64
65 pub fn unsupported_err() -> io::Error {
66     io::Error::new(io::ErrorKind::Other,
67                    "operation not supported on wasm yet")
68 }
69
70 pub fn decode_error_kind(_code: i32) -> io::ErrorKind {
71     io::ErrorKind::Other
72 }
73
74 // This enum is used as the storage for a bunch of types which can't actually
75 // exist.
76 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
77 pub enum Void {}
78
79 pub unsafe fn strlen(mut s: *const c_char) -> usize {
80     let mut n = 0;
81     while *s != 0 {
82         n += 1;
83         s = s.offset(1);
84     }
85     return n
86 }
87
88 pub unsafe fn abort_internal() -> ! {
89     ExitSysCall::perform(1)
90 }
91
92 // We don't have randomness yet, but I totally used a random number generator to
93 // generate these numbers.
94 //
95 // More seriously though this is just for DOS protection in hash maps. It's ok
96 // if we don't do that on wasm just yet.
97 pub fn hashmap_random_keys() -> (u64, u64) {
98     (1, 2)
99 }
100
101 // Implement a minimal set of system calls to enable basic IO
102 pub enum SysCallIndex {
103     Read = 0,
104     Write = 1,
105     Exit = 2,
106     Args = 3,
107     GetEnv = 4,
108     SetEnv = 5,
109     Time = 6,
110 }
111
112 #[repr(C)]
113 pub struct ReadSysCall {
114     fd: usize,
115     ptr: *mut u8,
116     len: usize,
117     result: usize,
118 }
119
120 impl ReadSysCall {
121     pub fn perform(fd: usize, buffer: &mut [u8]) -> usize {
122         let mut call_record = ReadSysCall {
123             fd,
124             len: buffer.len(),
125             ptr: buffer.as_mut_ptr(),
126             result: 0
127         };
128         if unsafe { syscall(SysCallIndex::Read, &mut call_record) } {
129             call_record.result
130         } else {
131             0
132         }
133     }
134 }
135
136 #[repr(C)]
137 pub struct WriteSysCall {
138     fd: usize,
139     ptr: *const u8,
140     len: usize,
141 }
142
143 impl WriteSysCall {
144     pub fn perform(fd: usize, buffer: &[u8]) {
145         let mut call_record = WriteSysCall {
146             fd,
147             len: buffer.len(),
148             ptr: buffer.as_ptr()
149         };
150         unsafe { syscall(SysCallIndex::Write, &mut call_record); }
151     }
152 }
153
154 #[repr(C)]
155 pub struct ExitSysCall {
156     code: usize,
157 }
158
159 impl ExitSysCall {
160     pub fn perform(code: usize) -> ! {
161         let mut call_record = ExitSysCall {
162             code
163         };
164         unsafe {
165             syscall(SysCallIndex::Exit, &mut call_record);
166             ::intrinsics::abort();
167         }
168     }
169 }
170
171 fn receive_buffer<E, F: FnMut(&mut [u8]) -> Result<usize, E>>(estimate: usize, mut f: F)
172     -> Result<Vec<u8>, E>
173 {
174     let mut buffer = vec![0; estimate];
175     loop {
176         let result = f(&mut buffer)?;
177         if result <= buffer.len() {
178             buffer.truncate(result);
179             break;
180         }
181         buffer.resize(result, 0);
182     }
183     Ok(buffer)
184 }
185
186 #[repr(C)]
187 pub struct ArgsSysCall {
188     ptr: *mut u8,
189     len: usize,
190     result: usize
191 }
192
193 impl ArgsSysCall {
194     pub fn perform() -> Vec<OsString> {
195         receive_buffer(1024, |buffer| -> Result<usize, !> {
196             let mut call_record = ArgsSysCall {
197                 len: buffer.len(),
198                 ptr: buffer.as_mut_ptr(),
199                 result: 0
200             };
201             if unsafe { syscall(SysCallIndex::Args, &mut call_record) } {
202                 Ok(call_record.result)
203             } else {
204                 Ok(0)
205             }
206         })
207             .unwrap()
208             .split(|b| *b == 0)
209             .map(|s| FromInner::from_inner(Buf { inner: s.to_owned() }))
210             .collect()
211     }
212 }
213
214 #[repr(C)]
215 pub struct GetEnvSysCall {
216     key_ptr: *const u8,
217     key_len: usize,
218     value_ptr: *mut u8,
219     value_len: usize,
220     result: usize
221 }
222
223 impl GetEnvSysCall {
224     pub fn perform(key: &OsStr) -> Option<OsString> {
225         let key_buf = &AsInner::as_inner(key).inner;
226         receive_buffer(64, |buffer| {
227             let mut call_record = GetEnvSysCall {
228                 key_len: key_buf.len(),
229                 key_ptr: key_buf.as_ptr(),
230                 value_len: buffer.len(),
231                 value_ptr: buffer.as_mut_ptr(),
232                 result: !0usize
233             };
234             if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) } {
235                 if call_record.result == !0usize {
236                     Err(())
237                 } else {
238                     Ok(call_record.result)
239                 }
240             } else {
241                 Err(())
242             }
243         }).ok().map(|s| {
244             FromInner::from_inner(Buf { inner: s })
245         })
246     }
247 }
248
249 #[repr(C)]
250 pub struct SetEnvSysCall {
251     key_ptr: *const u8,
252     key_len: usize,
253     value_ptr: *const u8,
254     value_len: usize
255 }
256
257 impl SetEnvSysCall {
258     pub fn perform(key: &OsStr, value: Option<&OsStr>) {
259         let key_buf = &AsInner::as_inner(key).inner;
260         let value_buf = value.map(|v| &AsInner::as_inner(v).inner);
261         let mut call_record = SetEnvSysCall {
262             key_len: key_buf.len(),
263             key_ptr: key_buf.as_ptr(),
264             value_len: value_buf.map(|v| v.len()).unwrap_or(!0usize),
265             value_ptr: value_buf.map(|v| v.as_ptr()).unwrap_or(ptr::null())
266         };
267         unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); }
268     }
269 }
270
271 pub enum TimeClock {
272     Monotonic = 0,
273     System = 1,
274 }
275
276 #[repr(C)]
277 pub struct TimeSysCall {
278     clock: usize,
279     secs_hi: usize,
280     secs_lo: usize,
281     nanos: usize
282 }
283
284 impl TimeSysCall {
285     pub fn perform(clock: TimeClock) -> Duration {
286         let mut call_record = TimeSysCall {
287             clock: clock as usize,
288             secs_hi: 0,
289             secs_lo: 0,
290             nanos: 0
291         };
292         if unsafe { syscall(SysCallIndex::Time, &mut call_record) } {
293             Duration::new(
294                 ((call_record.secs_hi as u64) << 32) | (call_record.secs_lo as u64),
295                 call_record.nanos as u32
296             )
297         } else {
298             panic!("Time system call is not implemented by WebAssembly host");
299         }
300     }
301 }
302
303 unsafe fn syscall<T>(index: SysCallIndex, data: &mut T) -> bool {
304     #[cfg(feature = "wasm_syscall")]
305     extern {
306         #[no_mangle]
307         fn rust_wasm_syscall(index: usize, data: *mut Void) -> usize;
308     }
309
310     #[cfg(not(feature = "wasm_syscall"))]
311     unsafe fn rust_wasm_syscall(_index: usize, _data: *mut Void) -> usize { 0 }
312
313     rust_wasm_syscall(index as usize, data as *mut T as *mut Void) != 0
314 }