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