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!
21 use sys_common
::{AsInner, FromInner}
;
22 use ffi
::{OsString, OsStr}
;
27 #[cfg(feature = "backtrace")]
39 pub mod stack_overflow
;
45 if #[cfg(target_feature = "atomics")] {
46 #[path = "condvar_atomics.rs"]
48 #[path = "mutex_atomics.rs"]
50 #[path = "rwlock_atomics.rs"]
52 #[path = "thread_local_atomics.rs"]
66 pub fn unsupported
<T
>() -> io
::Result
<T
> {
67 Err(unsupported_err())
70 pub fn unsupported_err() -> io
::Error
{
71 io
::Error
::new(io
::ErrorKind
::Other
,
72 "operation not supported on wasm yet")
75 pub fn decode_error_kind(_code
: i32) -> io
::ErrorKind
{
79 // This enum is used as the storage for a bunch of types which can't actually
81 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
84 pub unsafe fn strlen(mut s
: *const c_char
) -> usize {
93 pub unsafe fn abort_internal() -> ! {
94 ExitSysCall
::perform(1)
97 // We don't have randomness yet, but I totally used a random number generator to
98 // generate these numbers.
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) {
106 // Implement a minimal set of system calls to enable basic IO
107 pub enum SysCallIndex
{
118 pub struct ReadSysCall
{
126 pub fn perform(fd
: usize, buffer
: &mut [u8]) -> usize {
127 let mut call_record
= ReadSysCall
{
130 ptr
: buffer
.as_mut_ptr(),
133 if unsafe { syscall(SysCallIndex::Read, &mut call_record) }
{
142 pub struct WriteSysCall
{
149 pub fn perform(fd
: usize, buffer
: &[u8]) {
150 let mut call_record
= WriteSysCall
{
155 unsafe { syscall(SysCallIndex::Write, &mut call_record); }
160 pub struct ExitSysCall
{
165 pub fn perform(code
: usize) -> ! {
166 let mut call_record
= ExitSysCall
{
170 syscall(SysCallIndex
::Exit
, &mut call_record
);
171 ::intrinsics
::abort();
176 fn receive_buffer
<E
, F
: FnMut(&mut [u8]) -> Result
<usize, E
>>(estimate
: usize, mut f
: F
)
177 -> Result
<Vec
<u8>, E
>
179 let mut buffer
= vec
![0; estimate
];
181 let result
= f(&mut buffer
)?
;
182 if result
<= buffer
.len() {
183 buffer
.truncate(result
);
186 buffer
.resize(result
, 0);
192 pub struct ArgsSysCall
{
199 pub fn perform() -> Vec
<OsString
> {
200 receive_buffer(1024, |buffer
| -> Result
<usize, !> {
201 let mut call_record
= ArgsSysCall
{
203 ptr
: buffer
.as_mut_ptr(),
206 if unsafe { syscall(SysCallIndex::Args, &mut call_record) }
{
207 Ok(call_record
.result
)
214 .map(|s
| FromInner
::from_inner(Buf { inner: s.to_owned() }
))
220 pub struct 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(),
239 if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) }
{
240 if call_record
.result
== !0usize
{
243 Ok(call_record
.result
)
249 FromInner
::from_inner(Buf { inner: s }
)
255 pub struct SetEnvSysCall
{
258 value_ptr
: *const u8,
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())
272 unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); }
282 pub struct TimeSysCall
{
290 pub fn perform(clock
: TimeClock
) -> Duration
{
291 let mut call_record
= TimeSysCall
{
292 clock
: clock
as usize,
297 if unsafe { syscall(SysCallIndex::Time, &mut call_record) }
{
299 ((call_record
.secs_hi
as u64) << 32) | (call_record
.secs_lo
as u64),
300 call_record
.nanos
as u32
303 panic
!("Time system call is not implemented by WebAssembly host");
308 unsafe fn syscall
<T
>(index
: SysCallIndex
, data
: &mut T
) -> bool
{
309 #[cfg(feature = "wasm_syscall")]
312 fn rust_wasm_syscall(index
: usize, data
: *mut Void
) -> usize;
315 #[cfg(not(feature = "wasm_syscall"))]
316 unsafe fn rust_wasm_syscall(_index
: usize, _data
: *mut Void
) -> usize { 0 }
318 rust_wasm_syscall(index
as usize, data
as *mut T
as *mut Void
) != 0