diff options
Diffstat (limited to 'src/libstd/sys/wasi')
| -rw-r--r-- | src/libstd/sys/wasi/alloc.rs | 43 | ||||
| -rw-r--r-- | src/libstd/sys/wasi/args.rs | 78 | ||||
| -rw-r--r-- | src/libstd/sys/wasi/backtrace.rs | 27 | ||||
| -rw-r--r-- | src/libstd/sys/wasi/env.rs | 9 | ||||
| -rw-r--r-- | src/libstd/sys/wasi/ext/ffi.rs | 61 | ||||
| -rw-r--r-- | src/libstd/sys/wasi/ext/mod.rs | 10 | ||||
| -rw-r--r-- | src/libstd/sys/wasi/fd.rs | 322 | ||||
| -rw-r--r-- | src/libstd/sys/wasi/fs.rs | 294 | ||||
| -rw-r--r-- | src/libstd/sys/wasi/io.rs | 62 | ||||
| -rw-r--r-- | src/libstd/sys/wasi/mod.rs | 128 | ||||
| -rw-r--r-- | src/libstd/sys/wasi/net.rs | 358 | ||||
| -rw-r--r-- | src/libstd/sys/wasi/os.rs | 171 | ||||
| -rw-r--r-- | src/libstd/sys/wasi/path.rs | 19 | ||||
| -rw-r--r-- | src/libstd/sys/wasi/pipe.rs | 25 | ||||
| -rw-r--r-- | src/libstd/sys/wasi/process.rs | 152 | ||||
| -rw-r--r-- | src/libstd/sys/wasi/stdio.rs | 74 | ||||
| -rw-r--r-- | src/libstd/sys/wasi/thread.rs | 57 | ||||
| -rw-r--r-- | src/libstd/sys/wasi/time.rs | 72 |
18 files changed, 1962 insertions, 0 deletions
diff --git a/src/libstd/sys/wasi/alloc.rs b/src/libstd/sys/wasi/alloc.rs new file mode 100644 index 00000000000..c8529937bbd --- /dev/null +++ b/src/libstd/sys/wasi/alloc.rs @@ -0,0 +1,43 @@ +use crate::alloc::{GlobalAlloc, Layout, System}; +use crate::ptr; +use crate::sys_common::alloc::{MIN_ALIGN, realloc_fallback}; +use libc; + +#[stable(feature = "alloc_system_type", since = "1.28.0")] +unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { + libc::malloc(layout.size()) as *mut u8 + } else { + libc::aligned_alloc(layout.size(), layout.align()) as *mut u8 + } + } + + #[inline] + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { + libc::calloc(layout.size(), 1) as *mut u8 + } else { + let ptr = self.alloc(layout.clone()); + if !ptr.is_null() { + ptr::write_bytes(ptr, 0, layout.size()); + } + ptr + } + } + + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { + libc::free(ptr as *mut libc::c_void) + } + + #[inline] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + if layout.align() <= MIN_ALIGN && layout.align() <= new_size { + libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 + } else { + realloc_fallback(self, ptr, layout, new_size) + } + } +} diff --git a/src/libstd/sys/wasi/args.rs b/src/libstd/sys/wasi/args.rs new file mode 100644 index 00000000000..20558a8042d --- /dev/null +++ b/src/libstd/sys/wasi/args.rs @@ -0,0 +1,78 @@ +use crate::any::Any; +use crate::ffi::CStr; +use crate::ffi::OsString; +use crate::marker::PhantomData; +use crate::os::wasi::ffi::OsStringExt; +use crate::ptr; +use crate::vec; + +static mut ARGC: isize = 0; +static mut ARGV: *const *const u8 = ptr::null(); + +#[cfg(not(target_feature = "atomics"))] +pub unsafe fn args_lock() -> impl Any { + // No need for a lock if we're single-threaded, but this function will need + // to get implemented for multi-threaded scenarios +} + +pub unsafe fn init(argc: isize, argv: *const *const u8) { + let _guard = args_lock(); + ARGC = argc; + ARGV = argv; +} + +pub unsafe fn cleanup() { + let _guard = args_lock(); + ARGC = 0; + ARGV = ptr::null(); +} + +pub struct Args { + iter: vec::IntoIter<OsString>, + _dont_send_or_sync_me: PhantomData<*mut ()>, +} + +/// Returns the command line arguments +pub fn args() -> Args { + unsafe { + let _guard = args_lock(); + let args = (0..ARGC) + .map(|i| { + let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char); + OsStringExt::from_vec(cstr.to_bytes().to_vec()) + }) + .collect::<Vec<_>>(); + Args { + iter: args.into_iter(), + _dont_send_or_sync_me: PhantomData, + } + } +} + +impl Args { + pub fn inner_debug(&self) -> &[OsString] { + self.iter.as_slice() + } +} + +impl Iterator for Args { + type Item = OsString; + fn next(&mut self) -> Option<OsString> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} + +impl ExactSizeIterator for Args { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option<OsString> { + self.iter.next_back() + } +} diff --git a/src/libstd/sys/wasi/backtrace.rs b/src/libstd/sys/wasi/backtrace.rs new file mode 100644 index 00000000000..7d56b298997 --- /dev/null +++ b/src/libstd/sys/wasi/backtrace.rs @@ -0,0 +1,27 @@ +use crate::io; +use crate::sys::unsupported; +use crate::sys_common::backtrace::Frame; + +pub struct BacktraceContext; + +pub fn unwind_backtrace(_frames: &mut [Frame]) + -> io::Result<(usize, BacktraceContext)> +{ + unsupported() +} + +pub fn resolve_symname<F>(_frame: Frame, + _callback: F, + _: &BacktraceContext) -> io::Result<()> + where F: FnOnce(Option<&str>) -> io::Result<()> +{ + unsupported() +} + +pub fn foreach_symbol_fileline<F>(_: Frame, + _: F, + _: &BacktraceContext) -> io::Result<bool> + where F: FnMut(&[u8], u32) -> io::Result<()> +{ + unsupported() +} diff --git a/src/libstd/sys/wasi/env.rs b/src/libstd/sys/wasi/env.rs new file mode 100644 index 00000000000..730e356d7fe --- /dev/null +++ b/src/libstd/sys/wasi/env.rs @@ -0,0 +1,9 @@ +pub mod os { + pub const FAMILY: &str = ""; + pub const OS: &str = ""; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ".wasm"; + pub const DLL_EXTENSION: &str = "wasm"; + pub const EXE_SUFFIX: &str = ".wasm"; + pub const EXE_EXTENSION: &str = "wasm"; +} diff --git a/src/libstd/sys/wasi/ext/ffi.rs b/src/libstd/sys/wasi/ext/ffi.rs new file mode 100644 index 00000000000..07b93dd143f --- /dev/null +++ b/src/libstd/sys/wasi/ext/ffi.rs @@ -0,0 +1,61 @@ +//! WASI-specific extension to the primitives in the `std::ffi` module + +#![stable(feature = "rust1", since = "1.0.0")] + +use crate::ffi::{OsStr, OsString}; +use crate::mem; +use crate::sys::os_str::Buf; +use crate::sys_common::{FromInner, IntoInner, AsInner}; + +/// WASI-specific extensions to [`OsString`]. +/// +/// [`OsString`]: ../../../../std/ffi/struct.OsString.html +#[stable(feature = "rust1", since = "1.0.0")] +pub trait OsStringExt { + /// Creates an `OsString` from a byte vector. + #[stable(feature = "rust1", since = "1.0.0")] + fn from_vec(vec: Vec<u8>) -> Self; + + /// Yields the underlying byte vector of this `OsString`. + #[stable(feature = "rust1", since = "1.0.0")] + fn into_vec(self) -> Vec<u8>; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl OsStringExt for OsString { + fn from_vec(vec: Vec<u8>) -> OsString { + FromInner::from_inner(Buf { inner: vec }) + } + fn into_vec(self) -> Vec<u8> { + self.into_inner().inner + } +} + +/// WASI-specific extensions to [`OsStr`]. +/// +/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html +#[stable(feature = "rust1", since = "1.0.0")] +pub trait OsStrExt { + #[stable(feature = "rust1", since = "1.0.0")] + /// Creates an [`OsStr`] from a byte slice. + /// + /// [`OsStr`]: ../../../ffi/struct.OsStr.html + fn from_bytes(slice: &[u8]) -> &Self; + + /// Gets the underlying byte view of the [`OsStr`] slice. + /// + /// [`OsStr`]: ../../../ffi/struct.OsStr.html + #[stable(feature = "rust1", since = "1.0.0")] + fn as_bytes(&self) -> &[u8]; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl OsStrExt for OsStr { + fn from_bytes(slice: &[u8]) -> &OsStr { + unsafe { mem::transmute(slice) } + } + fn as_bytes(&self) -> &[u8] { + &self.as_inner().inner + } +} + diff --git a/src/libstd/sys/wasi/ext/mod.rs b/src/libstd/sys/wasi/ext/mod.rs new file mode 100644 index 00000000000..877b9ed89d8 --- /dev/null +++ b/src/libstd/sys/wasi/ext/mod.rs @@ -0,0 +1,10 @@ +pub mod ffi; + +/// A prelude for conveniently writing platform-specific code. +/// +/// Includes all extension traits, and some important type definitions. +#[stable(feature = "rust1", since = "1.0.0")] +pub mod prelude { + #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::sys::ext::ffi::{OsStringExt, OsStrExt}; +} diff --git a/src/libstd/sys/wasi/fd.rs b/src/libstd/sys/wasi/fd.rs new file mode 100644 index 00000000000..1e05e701759 --- /dev/null +++ b/src/libstd/sys/wasi/fd.rs @@ -0,0 +1,322 @@ +#![allow(dead_code)] + +use crate::io::{self, IoVec, IoVecMut, SeekFrom}; +use crate::mem; +use crate::net::Shutdown; +use crate::sys::cvt_wasi; +use libc::{self, c_char, c_void}; + +pub struct WasiFd { + fd: libc::__wasi_fd_t, +} + +// FIXME: these should probably all be fancier structs, builders, enums, etc +pub type LookupFlags = u32; +pub type FdFlags = u16; +pub type Advice = u8; +pub type Rights = u64; +pub type Oflags = u16; +pub type DirCookie = u64; +pub type Timestamp = u64; +pub type FstFlags = u16; +pub type RiFlags = u16; +pub type RoFlags = u16; +pub type SiFlags = u16; + +fn iovec(a: &mut [IoVecMut]) -> (*const libc::__wasi_iovec_t, usize) { + assert_eq!( + mem::size_of::<IoVecMut>(), + mem::size_of::<libc::__wasi_iovec_t>() + ); + assert_eq!( + mem::align_of::<IoVecMut>(), + mem::align_of::<libc::__wasi_iovec_t>() + ); + (a.as_ptr() as *const libc::__wasi_iovec_t, a.len()) +} + +fn ciovec(a: &[IoVec]) -> (*const libc::__wasi_ciovec_t, usize) { + assert_eq!( + mem::size_of::<IoVec>(), + mem::size_of::<libc::__wasi_ciovec_t>() + ); + assert_eq!( + mem::align_of::<IoVec>(), + mem::align_of::<libc::__wasi_ciovec_t>() + ); + (a.as_ptr() as *const libc::__wasi_ciovec_t, a.len()) +} + +impl WasiFd { + pub unsafe fn from_raw(fd: libc::__wasi_fd_t) -> WasiFd { + WasiFd { fd } + } + + pub fn datasync(&self) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_datasync(self.fd) }) + } + + pub fn pread(&self, bufs: &mut [IoVecMut], offset: u64) -> io::Result<usize> { + let mut read = 0; + let (ptr, len) = iovec(bufs); + cvt_wasi(unsafe { libc::__wasi_fd_pread(self.fd, ptr, len, offset, &mut read) })?; + Ok(read) + } + + pub fn pwrite(&self, bufs: &[IoVec], offset: u64) -> io::Result<usize> { + let mut read = 0; + let (ptr, len) = ciovec(bufs); + cvt_wasi(unsafe { libc::__wasi_fd_pwrite(self.fd, ptr, len, offset, &mut read) })?; + Ok(read) + } + + pub fn read(&self, bufs: &mut [IoVecMut]) -> io::Result<usize> { + let mut read = 0; + let (ptr, len) = iovec(bufs); + cvt_wasi(unsafe { libc::__wasi_fd_read(self.fd, ptr, len, &mut read) })?; + Ok(read) + } + + pub fn write(&self, bufs: &[IoVec]) -> io::Result<usize> { + let mut read = 0; + let (ptr, len) = ciovec(bufs); + cvt_wasi(unsafe { libc::__wasi_fd_write(self.fd, ptr, len, &mut read) })?; + Ok(read) + } + + pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> { + let (whence, offset) = match pos { + SeekFrom::Start(pos) => (libc::__WASI_WHENCE_SET, pos as i64), + SeekFrom::End(pos) => (libc::__WASI_WHENCE_END, pos), + SeekFrom::Current(pos) => (libc::__WASI_WHENCE_CUR, pos), + }; + let mut pos = 0; + cvt_wasi(unsafe { libc::__wasi_fd_seek(self.fd, offset, whence, &mut pos) })?; + Ok(pos) + } + + pub fn tell(&self) -> io::Result<u64> { + let mut pos = 0; + cvt_wasi(unsafe { libc::__wasi_fd_tell(self.fd, &mut pos) })?; + Ok(pos) + } + + // FIXME: __wasi_fd_fdstat_get + + pub fn set_flags(&self, flags: FdFlags) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_fdstat_set_flags(self.fd, flags) }) + } + + pub fn set_rights(&self, base: Rights, inheriting: Rights) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_fdstat_set_rights(self.fd, base, inheriting) }) + } + + pub fn sync(&self) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_sync(self.fd) }) + } + + pub fn advise(&self, offset: u64, len: u64, advice: Advice) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_advise(self.fd, offset, len, advice as u8) }) + } + + pub fn allocate(&self, offset: u64, len: u64) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_allocate(self.fd, offset, len) }) + } + + pub fn crate_directory(&self, path: &[u8]) -> io::Result<()> { + cvt_wasi(unsafe { + libc::__wasi_path_create_directory(self.fd, path.as_ptr() as *const c_char, path.len()) + }) + } + + pub fn link( + &self, + old_flags: LookupFlags, + old_path: &[u8], + new_fd: &WasiFd, + new_path: &[u8], + ) -> io::Result<()> { + cvt_wasi(unsafe { + libc::__wasi_path_link( + self.fd, + old_flags, + old_path.as_ptr() as *const c_char, + old_path.len(), + new_fd.fd, + new_path.as_ptr() as *const c_char, + new_path.len(), + ) + }) + } + + pub fn open( + &self, + dirflags: LookupFlags, + path: &[u8], + oflags: Oflags, + fs_rights_base: Rights, + fs_rights_inheriting: Rights, + fs_flags: FdFlags, + ) -> io::Result<WasiFd> { + unsafe { + let mut fd = 0; + cvt_wasi(libc::__wasi_path_open( + self.fd, + dirflags, + path.as_ptr() as *const c_char, + path.len(), + oflags, + fs_rights_base, + fs_rights_inheriting, + fs_flags, + &mut fd, + ))?; + Ok(WasiFd::from_raw(fd)) + } + } + + pub fn readdir(&self, buf: &mut [u8], cookie: DirCookie) -> io::Result<usize> { + let mut used = 0; + cvt_wasi(unsafe { + libc::__wasi_fd_readdir( + self.fd, + buf.as_mut_ptr() as *mut c_void, + buf.len(), + cookie, + &mut used, + ) + })?; + Ok(used) + } + + pub fn readlink(&self, path: &[u8], buf: &mut [u8]) -> io::Result<usize> { + let mut used = 0; + cvt_wasi(unsafe { + libc::__wasi_path_readlink( + self.fd, + path.as_ptr() as *const c_char, + path.len(), + buf.as_mut_ptr() as *mut c_char, + buf.len(), + &mut used, + ) + })?; + Ok(used) + } + + pub fn rename(&self, old_path: &[u8], new_fd: &WasiFd, new_path: &[u8]) -> io::Result<()> { + cvt_wasi(unsafe { + libc::__wasi_path_rename( + self.fd, + old_path.as_ptr() as *const c_char, + old_path.len(), + new_fd.fd, + new_path.as_ptr() as *const c_char, + new_path.len(), + ) + }) + } + + // FIXME: __wasi_fd_filestat_get + + pub fn filestat_set_times( + &self, + atim: Timestamp, + mtim: Timestamp, + fstflags: FstFlags, + ) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_filestat_set_times(self.fd, atim, mtim, fstflags) }) + } + + pub fn filestat_set_size(&self, size: u64) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_filestat_set_size(self.fd, size) }) + } + + // FIXME: __wasi_path_filestat_get + + pub fn path_filestat_set_times( + &self, + flags: LookupFlags, + path: &[u8], + atim: Timestamp, + mtim: Timestamp, + fstflags: FstFlags, + ) -> io::Result<()> { + cvt_wasi(unsafe { + libc::__wasi_path_filestat_set_times( + self.fd, + flags, + path.as_ptr() as *const c_char, + path.len(), + atim, + mtim, + fstflags, + ) + }) + } + + pub fn symlink(&self, old_path: &[u8], new_path: &[u8]) -> io::Result<()> { + cvt_wasi(unsafe { + libc::__wasi_path_symlink( + old_path.as_ptr() as *const c_char, + old_path.len(), + self.fd, + new_path.as_ptr() as *const c_char, + new_path.len(), + ) + }) + } + + pub fn unlink_file(&self, path: &[u8]) -> io::Result<()> { + cvt_wasi(unsafe { + libc::__wasi_path_unlink_file(self.fd, path.as_ptr() as *const c_char, path.len()) + }) + } + + pub fn remove_directory(&self, path: &[u8]) -> io::Result<()> { + cvt_wasi(unsafe { + libc::__wasi_path_remove_directory(self.fd, path.as_ptr() as *const c_char, path.len()) + }) + } + + pub fn sock_recv( + &self, + ri_data: &mut [IoVecMut], + ri_flags: RiFlags, + ) -> io::Result<(usize, RoFlags)> { + let mut ro_datalen = 0; + let mut ro_flags = 0; + let (ptr, len) = iovec(ri_data); + cvt_wasi(unsafe { + libc::__wasi_sock_recv(self.fd, ptr, len, ri_flags, &mut ro_datalen, &mut ro_flags) + })?; + Ok((ro_datalen, ro_flags)) + } + + pub fn sock_send(&self, si_data: &[IoVec], si_flags: SiFlags) -> io::Result<usize> { + let mut so_datalen = 0; + let (ptr, len) = ciovec(si_data); + cvt_wasi(unsafe { libc::__wasi_sock_send(self.fd, ptr, len, si_flags, &mut so_datalen) })?; + Ok(so_datalen) + } + + pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> { + let how = match how { + Shutdown::Read => libc::__WASI_SHUT_RD, + Shutdown::Write => libc::__WASI_SHUT_WR, + Shutdown::Both => libc::__WASI_SHUT_WR | libc::__WASI_SHUT_RD, + }; + cvt_wasi(unsafe { libc::__wasi_sock_shutdown(self.fd, how) })?; + Ok(()) + } +} + +impl Drop for WasiFd { + fn drop(&mut self) { + unsafe { + // FIXME: can we handle the return code here even though we can't on + // unix? + libc::__wasi_fd_close(self.fd); + } + } +} diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs new file mode 100644 index 00000000000..485d2c87fbd --- /dev/null +++ b/src/libstd/sys/wasi/fs.rs @@ -0,0 +1,294 @@ +use crate::ffi::OsString; +use crate::fmt; +use crate::hash::{Hash, Hasher}; +use crate::io::{self, SeekFrom}; +use crate::path::{Path, PathBuf}; +use crate::sys::time::SystemTime; +use crate::sys::{unsupported, Void}; + +pub struct File(Void); + +pub struct FileAttr(Void); + +pub struct ReadDir(Void); + +pub struct DirEntry(Void); + +#[derive(Clone, Debug)] +pub struct OpenOptions { } + +pub struct FilePermissions(Void); + +pub struct FileType(Void); + +#[derive(Debug)] +pub struct DirBuilder { } + +impl FileAttr { + pub fn size(&self) -> u64 { + match self.0 {} + } + + pub fn perm(&self) -> FilePermissions { + match self.0 {} + } + + pub fn file_type(&self) -> FileType { + match self.0 {} + } + + pub fn modified(&self) -> io::Result<SystemTime> { + match self.0 {} + } + + pub fn accessed(&self) -> io::Result<SystemTime> { + match self.0 {} + } + + pub fn created(&self) -> io::Result<SystemTime> { + match self.0 {} + } +} + +impl Clone for FileAttr { + fn clone(&self) -> FileAttr { + match self.0 {} + } +} + +impl FilePermissions { + pub fn readonly(&self) -> bool { + match self.0 {} + } + + pub fn set_readonly(&mut self, _readonly: bool) { + match self.0 {} + } +} + +impl Clone for FilePermissions { + fn clone(&self) -> FilePermissions { + match self.0 {} + } +} + +impl PartialEq for FilePermissions { + fn eq(&self, _other: &FilePermissions) -> bool { + match self.0 {} + } +} + +impl Eq for FilePermissions { +} + +impl fmt::Debug for FilePermissions { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +impl FileType { + pub fn is_dir(&self) -> bool { + match self.0 {} + } + + pub fn is_file(&self) -> bool { + match self.0 {} + } + + pub fn is_symlink(&self) -> bool { + match self.0 {} + } +} + +impl Clone for FileType { + fn clone(&self) -> FileType { + match self.0 {} + } +} + +impl Copy for FileType {} + +impl PartialEq for FileType { + fn eq(&self, _other: &FileType) -> bool { + match self.0 {} + } +} + +impl Eq for FileType { +} + +impl Hash for FileType { + fn hash<H: Hasher>(&self, _h: &mut H) { + match self.0 {} + } +} + +impl fmt::Debug for FileType { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +impl fmt::Debug for ReadDir { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +impl Iterator for ReadDir { + type Item = io::Result<DirEntry>; + + fn next(&mut self) -> Option<io::Result<DirEntry>> { + match self.0 {} + } +} + +impl DirEntry { + pub fn path(&self) -> PathBuf { + match self.0 {} + } + + pub fn file_name(&self) -> OsString { + match self.0 {} + } + + pub fn metadata(&self) -> io::Result<FileAttr> { + match self.0 {} + } + + pub fn file_type(&self) -> io::Result<FileType> { + match self.0 {} + } +} + +impl OpenOptions { + pub fn new() -> OpenOptions { + OpenOptions { } + } + + pub fn read(&mut self, _read: bool) { } + pub fn write(&mut self, _write: bool) { } + pub fn append(&mut self, _append: bool) { } + pub fn truncate(&mut self, _truncate: bool) { } + pub fn create(&mut self, _create: bool) { } + pub fn create_new(&mut self, _create_new: bool) { } +} + +impl File { + pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> { + unsupported() + } + + pub fn file_attr(&self) -> io::Result<FileAttr> { + match self.0 {} + } + + pub fn fsync(&self) -> io::Result<()> { + match self.0 {} + } + + pub fn datasync(&self) -> io::Result<()> { + match self.0 {} + } + + pub fn truncate(&self, _size: u64) -> io::Result<()> { + match self.0 {} + } + + pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> { + match self.0 {} + } + + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { + match self.0 {} + } + + pub fn flush(&self) -> io::Result<()> { + match self.0 {} + } + + pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> { + match self.0 {} + } + + pub fn duplicate(&self) -> io::Result<File> { + match self.0 {} + } + + pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { + match self.0 {} + } + + pub fn diverge(&self) -> ! { + match self.0 {} + } +} + +impl DirBuilder { + pub fn new() -> DirBuilder { + DirBuilder { } + } + + pub fn mkdir(&self, _p: &Path) -> io::Result<()> { + unsupported() + } +} + +impl fmt::Debug for File { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +pub fn readdir(_p: &Path) -> io::Result<ReadDir> { + unsupported() +} + +pub fn unlink(_p: &Path) -> io::Result<()> { + unsupported() +} + +pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { + unsupported() +} + +pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> { + match perm.0 {} +} + +pub fn rmdir(_p: &Path) -> io::Result<()> { + unsupported() +} + +pub fn remove_dir_all(_path: &Path) -> io::Result<()> { + unsupported() +} + +pub fn readlink(_p: &Path) -> io::Result<PathBuf> { + unsupported() +} + +pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> { + unsupported() +} + +pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { + unsupported() +} + +pub fn stat(_p: &Path) -> io::Result<FileAttr> { + unsupported() +} + +pub fn lstat(_p: &Path) -> io::Result<FileAttr> { + unsupported() +} + +pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> { + unsupported() +} + +pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> { + unsupported() +} diff --git a/src/libstd/sys/wasi/io.rs b/src/libstd/sys/wasi/io.rs new file mode 100644 index 00000000000..5f0315d279e --- /dev/null +++ b/src/libstd/sys/wasi/io.rs @@ -0,0 +1,62 @@ +use crate::marker::PhantomData; +use crate::slice; + +use libc::{__wasi_ciovec_t, __wasi_iovec_t, c_void}; + +#[repr(transparent)] +pub struct IoVec<'a> { + vec: __wasi_ciovec_t, + _p: PhantomData<&'a [u8]>, +} + +impl<'a> IoVec<'a> { + #[inline] + pub fn new(buf: &'a [u8]) -> IoVec<'a> { + IoVec { + vec: __wasi_ciovec_t { + buf: buf.as_ptr() as *const c_void, + buf_len: buf.len(), + }, + _p: PhantomData, + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self.vec.buf as *const u8, self.vec.buf_len) + } + } +} + +pub struct IoVecMut<'a> { + vec: __wasi_iovec_t, + _p: PhantomData<&'a mut [u8]>, +} + +impl<'a> IoVecMut<'a> { + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> { + IoVecMut { + vec: __wasi_iovec_t { + buf: buf.as_mut_ptr() as *mut c_void, + buf_len: buf.len() + }, + _p: PhantomData, + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self.vec.buf as *const u8, self.vec.buf_len) + } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.buf_len) + } + } +} diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs new file mode 100644 index 00000000000..a9bb0151d05 --- /dev/null +++ b/src/libstd/sys/wasi/mod.rs @@ -0,0 +1,128 @@ +//! System bindings for the wasm/web platform +//! +//! This module contains the facade (aka platform-specific) implementations of +//! OS level functionality for wasm. Note that this wasm is *not* the emscripten +//! wasm, so we have no runtime here. +//! +//! This is all super highly experimental and not actually intended for +//! wide/production use yet, it's still all in the experimental category. This +//! will likely change over time. +//! +//! Currently all functions here are basically stubs that immediately return +//! errors. The hope is that with a portability lint we can turn actually just +//! remove all this and just omit parts of the standard library if we're +//! compiling for wasm. That way it's a compile time error for something that's +//! guaranteed to be a runtime error! + +use libc; +use crate::io::{Error, ErrorKind}; +use crate::mem; +use crate::os::raw::c_char; + +pub mod alloc; +pub mod args; +#[cfg(feature = "backtrace")] +pub mod backtrace; +#[path = "../wasm/cmath.rs"] +pub mod cmath; +#[path = "../wasm/condvar.rs"] +pub mod condvar; +pub mod env; +pub mod fd; +pub mod fs; +#[path = "../wasm/memchr.rs"] +pub mod memchr; +#[path = "../wasm/mutex.rs"] +pub mod mutex; +pub mod net; +pub mod io; +pub mod os; +pub use crate::sys_common::os_str_bytes as os_str; +pub mod path; +pub mod pipe; +pub mod process; +#[path = "../wasm/rwlock.rs"] +pub mod rwlock; +#[path = "../wasm/stack_overflow.rs"] +pub mod stack_overflow; +pub mod stdio; +pub mod thread; +#[path = "../wasm/thread_local.rs"] +pub mod thread_local; +pub mod time; +pub mod ext; + +#[cfg(not(test))] +pub fn init() { +} + +pub fn unsupported<T>() -> crate::io::Result<T> { + Err(unsupported_err()) +} + +pub fn unsupported_err() -> Error { + Error::new(ErrorKind::Other, "operation not supported on wasm yet") +} + +pub fn decode_error_kind(_code: i32) -> ErrorKind { + ErrorKind::Other +} + +// This enum is used as the storage for a bunch of types which can't actually +// exist. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub enum Void {} + +pub unsafe fn strlen(mut s: *const c_char) -> usize { + let mut n = 0; + while *s != 0 { + n += 1; + s = s.offset(1); + } + return n +} + +pub unsafe fn abort_internal() -> ! { + libc::abort() +} + +pub fn hashmap_random_keys() -> (u64, u64) { + let mut ret = (0u64, 0u64); + unsafe { + let base = &mut ret as *mut (u64, u64) as *mut libc::c_void; + let len = mem::size_of_val(&ret); + cvt_wasi(libc::__wasi_random_get(base, len)).unwrap(); + } + return ret +} + +#[doc(hidden)] +pub trait IsMinusOne { + fn is_minus_one(&self) -> bool; +} + +macro_rules! impl_is_minus_one { + ($($t:ident)*) => ($(impl IsMinusOne for $t { + fn is_minus_one(&self) -> bool { + *self == -1 + } + })*) +} + +impl_is_minus_one! { i8 i16 i32 i64 isize } + +pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> { + if t.is_minus_one() { + Err(Error::last_os_error()) + } else { + Ok(t) + } +} + +pub fn cvt_wasi(r: u16) -> crate::io::Result<()> { + if r != libc::__WASI_ESUCCESS { + Err(Error::from_raw_os_error(r as i32)) + } else { + Ok(()) + } +} diff --git a/src/libstd/sys/wasi/net.rs b/src/libstd/sys/wasi/net.rs new file mode 100644 index 00000000000..af9a22f5b7a --- /dev/null +++ b/src/libstd/sys/wasi/net.rs @@ -0,0 +1,358 @@ +use crate::fmt; +use crate::io::{self, IoVec, IoVecMut}; +use crate::net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr}; +use crate::time::Duration; +use crate::sys::{unsupported, Void}; +use crate::convert::TryFrom; + +pub struct TcpStream(Void); + +impl TcpStream { + pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> { + unsupported() + } + + pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> { + unsupported() + } + + pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> { + match self.0 {} + } + + pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> { + match self.0 {} + } + + pub fn read_timeout(&self) -> io::Result<Option<Duration>> { + match self.0 {} + } + + pub fn write_timeout(&self) -> io::Result<Option<Duration>> { + match self.0 {} + } + + pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> { + match self.0 {} + } + + pub fn read(&self, _: &mut [u8]) -> io::Result<usize> { + match self.0 {} + } + + pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> { + match self.0 {} + } + + pub fn write(&self, _: &[u8]) -> io::Result<usize> { + match self.0 {} + } + + pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> { + match self.0 {} + } + + pub fn peer_addr(&self) -> io::Result<SocketAddr> { + match self.0 {} + } + + pub fn socket_addr(&self) -> io::Result<SocketAddr> { + match self.0 {} + } + + pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { + match self.0 {} + } + + pub fn duplicate(&self) -> io::Result<TcpStream> { + match self.0 {} + } + + pub fn set_nodelay(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn nodelay(&self) -> io::Result<bool> { + match self.0 {} + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + match self.0 {} + } + + pub fn ttl(&self) -> io::Result<u32> { + match self.0 {} + } + + pub fn take_error(&self) -> io::Result<Option<io::Error>> { + match self.0 {} + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + match self.0 {} + } +} + +impl fmt::Debug for TcpStream { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +pub struct TcpListener(Void); + +impl TcpListener { + pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> { + unsupported() + } + + pub fn socket_addr(&self) -> io::Result<SocketAddr> { + match self.0 {} + } + + pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { + match self.0 {} + } + + pub fn duplicate(&self) -> io::Result<TcpListener> { + match self.0 {} + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + match self.0 {} + } + + pub fn ttl(&self) -> io::Result<u32> { + match self.0 {} + } + + pub fn set_only_v6(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn only_v6(&self) -> io::Result<bool> { + match self.0 {} + } + + pub fn take_error(&self) -> io::Result<Option<io::Error>> { + match self.0 {} + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + match self.0 {} + } +} + +impl fmt::Debug for TcpListener { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +pub struct UdpSocket(Void); + +impl UdpSocket { + pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> { + unsupported() + } + + pub fn peer_addr(&self) -> io::Result<SocketAddr> { + match self.0 {} + } + + pub fn socket_addr(&self) -> io::Result<SocketAddr> { + match self.0 {} + } + + pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + match self.0 {} + } + + pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + match self.0 {} + } + + pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> { + match self.0 {} + } + + pub fn duplicate(&self) -> io::Result<UdpSocket> { + match self.0 {} + } + + pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> { + match self.0 {} + } + + pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> { + match self.0 {} + } + + pub fn read_timeout(&self) -> io::Result<Option<Duration>> { + match self.0 {} + } + + pub fn write_timeout(&self) -> io::Result<Option<Duration>> { + match self.0 {} + } + + pub fn set_broadcast(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn broadcast(&self) -> io::Result<bool> { + match self.0 {} + } + + pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn multicast_loop_v4(&self) -> io::Result<bool> { + match self.0 {} + } + + pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { + match self.0 {} + } + + pub fn multicast_ttl_v4(&self) -> io::Result<u32> { + match self.0 {} + } + + pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn multicast_loop_v6(&self) -> io::Result<bool> { + match self.0 {} + } + + pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) + -> io::Result<()> { + match self.0 {} + } + + pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) + -> io::Result<()> { + match self.0 {} + } + + pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) + -> io::Result<()> { + match self.0 {} + } + + pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) + -> io::Result<()> { + match self.0 {} + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + match self.0 {} + } + + pub fn ttl(&self) -> io::Result<u32> { + match self.0 {} + } + + pub fn take_error(&self) -> io::Result<Option<io::Error>> { + match self.0 {} + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + match self.0 {} + } + + pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> { + match self.0 {} + } + + pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> { + match self.0 {} + } + + pub fn send(&self, _: &[u8]) -> io::Result<usize> { + match self.0 {} + } + + pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { + match self.0 {} + } +} + +impl fmt::Debug for UdpSocket { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +pub struct LookupHost(Void); + +impl LookupHost { + pub fn port(&self) -> u16 { + match self.0 {} + } +} + +impl Iterator for LookupHost { + type Item = SocketAddr; + fn next(&mut self) -> Option<SocketAddr> { + match self.0 {} + } +} + +impl<'a> TryFrom<&'a str> for LookupHost { + type Error = io::Error; + + fn try_from(_v: &'a str) -> io::Result<LookupHost> { + unsupported() + } +} + +impl<'a> TryFrom<(&'a str, u16)> for LookupHost { + type Error = io::Error; + + fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> { + unsupported() + } +} + +#[allow(nonstandard_style)] +pub mod netc { + pub const AF_INET: u8 = 0; + pub const AF_INET6: u8 = 1; + pub type sa_family_t = u8; + + #[derive(Copy, Clone)] + pub struct in_addr { + pub s_addr: u32, + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: u16, + pub sin_addr: in_addr, + } + + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: u16, + pub sin6_addr: in6_addr, + pub sin6_flowinfo: u32, + pub sin6_scope_id: u32, + } + + #[derive(Copy, Clone)] + pub struct sockaddr { + } + + pub type socklen_t = usize; +} diff --git a/src/libstd/sys/wasi/os.rs b/src/libstd/sys/wasi/os.rs new file mode 100644 index 00000000000..de18e4ba950 --- /dev/null +++ b/src/libstd/sys/wasi/os.rs @@ -0,0 +1,171 @@ +use crate::any::Any; +use crate::error::Error as StdError; +use crate::ffi::{OsString, OsStr, CString, CStr}; +use crate::fmt; +use crate::io; +use crate::marker::PhantomData; +use crate::os::wasi::prelude::*; +use crate::path::{self, PathBuf}; +use crate::ptr; +use crate::str; +use crate::sys::memchr; +use crate::sys::{cvt, unsupported, Void}; +use crate::vec; + +#[cfg(not(target_feature = "atomics"))] +pub unsafe fn env_lock() -> impl Any { + // No need for a lock if we're single-threaded, but this function will need + // to get implemented for multi-threaded scenarios +} + +pub fn errno() -> i32 { + extern { + #[thread_local] + static errno: libc::c_int; + } + + unsafe { errno as i32 } +} + +pub fn error_string(_errno: i32) -> String { + "operation failed".to_string() +} + +pub fn getcwd() -> io::Result<PathBuf> { + unsupported() +} + +pub fn chdir(_: &path::Path) -> io::Result<()> { + unsupported() +} + +pub struct SplitPaths<'a>(&'a Void); + +pub fn split_paths(_unparsed: &OsStr) -> SplitPaths { + panic!("unsupported") +} + +impl<'a> Iterator for SplitPaths<'a> { + type Item = PathBuf; + fn next(&mut self) -> Option<PathBuf> { + match *self.0 {} + } +} + +#[derive(Debug)] +pub struct JoinPathsError; + +pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError> + where I: Iterator<Item=T>, T: AsRef<OsStr> +{ + Err(JoinPathsError) +} + +impl fmt::Display for JoinPathsError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "not supported on wasm yet".fmt(f) + } +} + +impl StdError for JoinPathsError { + fn description(&self) -> &str { + "not supported on wasm yet" + } +} + +pub fn current_exe() -> io::Result<PathBuf> { + unsupported() +} + +pub struct Env { + iter: vec::IntoIter<(OsString, OsString)>, + _dont_send_or_sync_me: PhantomData<*mut ()>, +} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() } + fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } +} + + +pub fn env() -> Env { + unsafe { + let _guard = env_lock(); + let mut environ = libc::environ; + let mut result = Vec::new(); + while environ != ptr::null_mut() && *environ != ptr::null_mut() { + if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { + result.push(key_value); + } + environ = environ.offset(1); + } + return Env { + iter: result.into_iter(), + _dont_send_or_sync_me: PhantomData, + } + } + + // See src/libstd/sys/unix/os.rs, same as that + fn parse(input: &[u8]) -> Option<(OsString, OsString)> { + if input.is_empty() { + return None; + } + let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); + pos.map(|p| ( + OsStringExt::from_vec(input[..p].to_vec()), + OsStringExt::from_vec(input[p+1..].to_vec()), + )) + } +} + +pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> { + let k = CString::new(k.as_bytes())?; + unsafe { + let _guard = env_lock(); + let s = libc::getenv(k.as_ptr()) as *const libc::c_char; + let ret = if s.is_null() { + None + } else { + Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) + }; + Ok(ret) + } +} + +pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + let k = CString::new(k.as_bytes())?; + let v = CString::new(v.as_bytes())?; + + unsafe { + let _guard = env_lock(); + cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ()) + } +} + +pub fn unsetenv(n: &OsStr) -> io::Result<()> { + let nbuf = CString::new(n.as_bytes())?; + + unsafe { + let _guard = env_lock(); + cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ()) + } +} + +pub fn temp_dir() -> PathBuf { + panic!("no filesystem on wasm") +} + +pub fn home_dir() -> Option<PathBuf> { + None +} + +pub fn exit(code: i32) -> ! { + unsafe { + libc::exit(code) + } +} + +pub fn getpid() -> u32 { + panic!("unsupported"); +} diff --git a/src/libstd/sys/wasi/path.rs b/src/libstd/sys/wasi/path.rs new file mode 100644 index 00000000000..5c062e7c97c --- /dev/null +++ b/src/libstd/sys/wasi/path.rs @@ -0,0 +1,19 @@ +use crate::path::Prefix; +use crate::ffi::OsStr; + +#[inline] +pub fn is_sep_byte(b: u8) -> bool { + b == b'/' +} + +#[inline] +pub fn is_verbatim_sep(b: u8) -> bool { + b == b'/' +} + +pub fn parse_prefix(_: &OsStr) -> Option<Prefix> { + None +} + +pub const MAIN_SEP_STR: &str = "/"; +pub const MAIN_SEP: char = '/'; diff --git a/src/libstd/sys/wasi/pipe.rs b/src/libstd/sys/wasi/pipe.rs new file mode 100644 index 00000000000..2582b993b60 --- /dev/null +++ b/src/libstd/sys/wasi/pipe.rs @@ -0,0 +1,25 @@ +use crate::io; +use crate::sys::Void; + +pub struct AnonPipe(Void); + +impl AnonPipe { + pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> { + match self.0 {} + } + + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { + match self.0 {} + } + + pub fn diverge(&self) -> ! { + match self.0 {} + } +} + +pub fn read2(p1: AnonPipe, + _v1: &mut Vec<u8>, + _p2: AnonPipe, + _v2: &mut Vec<u8>) -> io::Result<()> { + match p1.0 {} +} diff --git a/src/libstd/sys/wasi/process.rs b/src/libstd/sys/wasi/process.rs new file mode 100644 index 00000000000..c49daaa1632 --- /dev/null +++ b/src/libstd/sys/wasi/process.rs @@ -0,0 +1,152 @@ +use crate::ffi::OsStr; +use crate::fmt; +use crate::io; +use crate::sys::fs::File; +use crate::sys::pipe::AnonPipe; +use crate::sys::{unsupported, Void}; +use crate::sys_common::process::{CommandEnv, DefaultEnvKey}; + +//////////////////////////////////////////////////////////////////////////////// +// Command +//////////////////////////////////////////////////////////////////////////////// + +pub struct Command { + env: CommandEnv<DefaultEnvKey> +} + +// passed back to std::process with the pipes connected to the child, if any +// were requested +pub struct StdioPipes { + pub stdin: Option<AnonPipe>, + pub stdout: Option<AnonPipe>, + pub stderr: Option<AnonPipe>, +} + +pub enum Stdio { + Inherit, + Null, + MakePipe, +} + +impl Command { + pub fn new(_program: &OsStr) -> Command { + Command { + env: Default::default() + } + } + + pub fn arg(&mut self, _arg: &OsStr) { + } + + pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> { + &mut self.env + } + + pub fn cwd(&mut self, _dir: &OsStr) { + } + + pub fn stdin(&mut self, _stdin: Stdio) { + } + + pub fn stdout(&mut self, _stdout: Stdio) { + } + + pub fn stderr(&mut self, _stderr: Stdio) { + } + + pub fn spawn(&mut self, _default: Stdio, _needs_stdin: bool) + -> io::Result<(Process, StdioPipes)> { + unsupported() + } +} + +impl From<AnonPipe> for Stdio { + fn from(pipe: AnonPipe) -> Stdio { + pipe.diverge() + } +} + +impl From<File> for Stdio { + fn from(file: File) -> Stdio { + file.diverge() + } +} + +impl fmt::Debug for Command { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } +} + +pub struct ExitStatus(Void); + +impl ExitStatus { + pub fn success(&self) -> bool { + match self.0 {} + } + + pub fn code(&self) -> Option<i32> { + match self.0 {} + } +} + +impl Clone for ExitStatus { + fn clone(&self) -> ExitStatus { + match self.0 {} + } +} + +impl Copy for ExitStatus {} + +impl PartialEq for ExitStatus { + fn eq(&self, _other: &ExitStatus) -> bool { + match self.0 {} + } +} + +impl Eq for ExitStatus { +} + +impl fmt::Debug for ExitStatus { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +impl fmt::Display for ExitStatus { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match self.0 {} + } +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitCode(bool); + +impl ExitCode { + pub const SUCCESS: ExitCode = ExitCode(false); + pub const FAILURE: ExitCode = ExitCode(true); + + pub fn as_i32(&self) -> i32 { + self.0 as i32 + } +} + +pub struct Process(Void); + +impl Process { + pub fn id(&self) -> u32 { + match self.0 {} + } + + pub fn kill(&mut self) -> io::Result<()> { + match self.0 {} + } + + pub fn wait(&mut self) -> io::Result<ExitStatus> { + match self.0 {} + } + + pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> { + match self.0 {} + } +} diff --git a/src/libstd/sys/wasi/stdio.rs b/src/libstd/sys/wasi/stdio.rs new file mode 100644 index 00000000000..f6a4958897d --- /dev/null +++ b/src/libstd/sys/wasi/stdio.rs @@ -0,0 +1,74 @@ +use crate::io; +use crate::libc; +use crate::sys::cvt; + +pub struct Stdin; +pub struct Stdout; +pub struct Stderr; + +impl Stdin { + pub fn new() -> io::Result<Stdin> { + Ok(Stdin) + } + + pub fn read(&self, data: &mut [u8]) -> io::Result<usize> { + let amt = cvt(unsafe { + libc::read(libc::STDIN_FILENO, data.as_mut_ptr() as *mut _, data.len()) + })?; + Ok(amt as usize) + } +} + +impl Stdout { + pub fn new() -> io::Result<Stdout> { + Ok(Stdout) + } + + pub fn write(&self, data: &[u8]) -> io::Result<usize> { + let amt = cvt(unsafe { + libc::write(libc::STDOUT_FILENO, data.as_ptr() as *const _, data.len()) + })?; + Ok(amt as usize) + } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } +} + +impl Stderr { + pub fn new() -> io::Result<Stderr> { + Ok(Stderr) + } + + pub fn write(&self, data: &[u8]) -> io::Result<usize> { + let amt = cvt(unsafe { + libc::write(libc::STDERR_FILENO, data.as_ptr() as *const _, data.len()) + })?; + Ok(amt as usize) + } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } +} + +impl io::Write for Stderr { + fn write(&mut self, data: &[u8]) -> io::Result<usize> { + (&*self).write(data) + } + + fn flush(&mut self) -> io::Result<()> { + (&*self).flush() + } +} + +pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; + +pub fn is_ebadf(err: &io::Error) -> bool { + err.raw_os_error() == Some(libc::__WASI_EBADF as i32) +} + +pub fn panic_output() -> Option<impl io::Write> { + Stderr::new().ok() +} diff --git a/src/libstd/sys/wasi/thread.rs b/src/libstd/sys/wasi/thread.rs new file mode 100644 index 00000000000..9d3c6ac59d1 --- /dev/null +++ b/src/libstd/sys/wasi/thread.rs @@ -0,0 +1,57 @@ +use crate::boxed::FnBox; +use crate::cmp; +use crate::ffi::CStr; +use crate::io; +use crate::sys::cvt; +use crate::sys::{unsupported, Void}; +use crate::time::Duration; +use libc; + +pub struct Thread(Void); + +pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; + +impl Thread { + // unsafe: see thread::Builder::spawn_unchecked for safety requirements + pub unsafe fn new(_stack: usize, _p: Box<dyn FnBox()>) + -> io::Result<Thread> + { + unsupported() + } + + pub fn yield_now() { + let ret = unsafe { libc::__wasi_sched_yield() }; + debug_assert_eq!(ret, 0); + } + + pub fn set_name(_name: &CStr) { + // nope + } + + pub fn sleep(dur: Duration) { + let mut secs = dur.as_secs(); + let mut nsecs = dur.subsec_nanos() as i32; + + unsafe { + while secs > 0 || nsecs > 0 { + let mut ts = libc::timespec { + tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t, + tv_nsec: nsecs, + }; + secs -= ts.tv_sec as u64; + cvt(libc::nanosleep(&ts, &mut ts)).unwrap(); + nsecs = 0; + } + } + } + + pub fn join(self) { + match self.0 {} + } +} + +pub mod guard { + pub type Guard = !; + pub unsafe fn current() -> Option<Guard> { None } + pub unsafe fn init() -> Option<Guard> { None } +} diff --git a/src/libstd/sys/wasi/time.rs b/src/libstd/sys/wasi/time.rs new file mode 100644 index 00000000000..e1b92e7c5a7 --- /dev/null +++ b/src/libstd/sys/wasi/time.rs @@ -0,0 +1,72 @@ +use crate::time::Duration; +use crate::mem; +use crate::sys::cvt_wasi; +use libc; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct Instant(Duration); + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct SystemTime(Duration); + +pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); + +fn current_time(clock: u32) -> Duration { + unsafe { + let mut ts = mem::zeroed(); + cvt_wasi(libc::__wasi_clock_time_get( + clock, + 1, // precision... seems ignored though? + &mut ts, + )).unwrap(); + Duration::new( + (ts / 1_000_000_000) as u64, + (ts % 1_000_000_000) as u32, + ) + } +} + +impl Instant { + pub fn now() -> Instant { + Instant(current_time(libc::__WASI_CLOCK_MONOTONIC)) + } + + pub const fn zero() -> Instant { + Instant(Duration::from_secs(0)) + } + + pub fn actually_monotonic() -> bool { + true + } + + pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> { + self.0.checked_sub(other.0) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> { + Some(Instant(self.0.checked_add(*other)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> { + Some(Instant(self.0.checked_sub(*other)?)) + } +} + +impl SystemTime { + pub fn now() -> SystemTime { + SystemTime(current_time(libc::__WASI_CLOCK_REALTIME)) + } + + pub fn sub_time(&self, other: &SystemTime) + -> Result<Duration, Duration> { + self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { + Some(SystemTime(self.0.checked_add(*other)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { + Some(SystemTime(self.0.checked_sub(*other)?)) + } +} |
