diff --git a/lib/emscripten/src/syscalls/emscripten_vfs.rs b/lib/emscripten/src/syscalls/emscripten_vfs.rs index a34a42e68..71e5ca1b7 100644 --- a/lib/emscripten/src/syscalls/emscripten_vfs.rs +++ b/lib/emscripten/src/syscalls/emscripten_vfs.rs @@ -102,7 +102,7 @@ impl EmscriptenVfs { panic!() } Some(*fd) - }, + } _ => None, } } diff --git a/lib/emscripten/src/syscalls/unix/select.rs b/lib/emscripten/src/syscalls/unix/select.rs index 315154988..a8ff97dbc 100644 --- a/lib/emscripten/src/syscalls/unix/select.rs +++ b/lib/emscripten/src/syscalls/unix/select.rs @@ -1,268 +1,70 @@ use crate::macros::emscripten_memory_ptr; -use crate::syscalls::emscripten_vfs::{FileHandle, VirtualFd}; +use crate::syscalls::emscripten_vfs::{EmscriptenVfs, VirtualFd}; use crate::varargs::VarArgs; -use std::collections::HashMap; -use std::ffi::c_void; -use std::slice; +use crate::EmscriptenData; use wasmer_runtime_core::vm::Ctx; -#[cfg(feature = "vfs")] -#[derive(Debug)] -struct FdPair { - pub virtual_fd: i32, - pub host_fd: i32, -} - -#[cfg(feature = "vfs")] fn translate_to_host_file_descriptors( - ctx: &mut Ctx, - mut varargs: &mut VarArgs, + vfs: &EmscriptenVfs, + set_ptr: *mut libc::fd_set, nfds: i32, - fds_set_offset: u32, -) -> (i32, HashMap, Vec) { - let set_ptr = emscripten_memory_ptr(ctx.memory(0), fds_set_offset) as *mut _; // e.g. libc::unix::bsd::fd_set - let set_u8_ptr = set_ptr as *mut u8; - - let bit_array_size = if nfds >= 0 { (nfds + 7) / 8 } else { 0 } as usize; - let end_offset = fds_set_offset as usize + bit_array_size; - let set_view = &ctx.memory(0).view::()[(fds_set_offset as usize)..end_offset]; - use bit_field::BitArray; - // let check = set_ptr.get_bit(1); - - let fds_slice = unsafe { slice::from_raw_parts(set_u8_ptr, bit_array_size) }; - - // (0usize..nfds as usize).filter_map(|x| fds_slice.get_bit(x)); - // let ofds = (0..nfds).filter_map(|v| fd_slice.v) - let original_fds: Vec = (0..nfds) - .filter_map(|virtual_fd| { - if fds_slice.get_bit(virtual_fd as usize) { - Some(virtual_fd as i32) - } else { - None - } - }) +) -> (i32, Vec) { + let pairs = (0..nfds) + .map(|vfd| (vfd, vfs.get_host_socket_fd(&VirtualFd(vfd)).unwrap_or(-1))) + .filter(|(vfd, _)| unsafe { libc::FD_ISSET(*vfd, set_ptr) }) .collect::>(); - - let vfs = crate::env::get_emscripten_data(ctx).vfs.as_mut().unwrap(); - - // virtual read and write file descriptors - let file_descriptor_pairs = original_fds + let max = pairs .iter() - .filter(|vfd| { - if let FileHandle::VirtualFile(handle) = vfs.fd_map.get(&VirtualFd(**vfd)).unwrap() { - debug!( - "skipping virtual fd {} (vbox handle {}) because is a virtual file", - *vfd, *handle - ); - false - } else { - true - } - }) - .map(|vfd| { - let vfd = VirtualFd(*vfd); - let file_handle = vfs.fd_map.get(&vfd).unwrap(); - let host_fd = match file_handle { - FileHandle::Socket(host_fd) => host_fd, - // FileHandle::VirtualFile(handle) => handle, - _ => panic!(), - }; - let pair = FdPair { - virtual_fd: vfd.0, - host_fd: *host_fd, - }; - // swap the read descriptors - unsafe { - libc::FD_CLR(pair.virtual_fd, set_ptr); - libc::FD_SET(pair.host_fd, set_ptr); - }; - pair - }) - .collect::>(); - - let mut sz = 0; - - // helper look up tables - let mut lookup = HashMap::new(); - for pair in file_descriptor_pairs.iter() { - // if pair.virtual_fd > sz { sz = pair.host_fd } - if pair.host_fd > sz { - sz = pair.host_fd - } - lookup.insert(pair.host_fd, pair.virtual_fd); - } - - let max_file_descriptor = sz; - (max_file_descriptor, lookup, file_descriptor_pairs) + .map(|(_, host_fd)| *host_fd) + .max() + .unwrap_or(-1) + + 1; + let mut internal_handles = vec![0; max as usize]; + unsafe { libc::FD_ZERO(set_ptr) }; + pairs.iter().for_each(|(vfd, host_fd)| { + internal_handles[*host_fd as usize] = *vfd; + unsafe { + libc::FD_SET(*host_fd, set_ptr); + }; + }); + (max, internal_handles) } -#[cfg(feature = "vfs")] -fn translate_to_virtual_file_descriptors( - ctx: &mut Ctx, - nfds: i32, - fds_set_offset: u32, - lookup: HashMap, -) -> Vec { - let set_ptr = emscripten_memory_pointer!(ctx.memory(0), fds_set_offset) as *mut _; - let set_u8_ptr = set_ptr as *mut u8; - let fds_slice = unsafe { slice::from_raw_parts_mut(set_u8_ptr, nfds as usize) }; - use bit_field::BitArray; - - let fds = (0..nfds) - .filter_map(|virtual_fd| { - if fds_slice.get_bit(virtual_fd as usize) { - Some(virtual_fd as i32) - } else { - None - } - }) - .collect::>(); - - // swap descriptors back - let pairs = fds +fn translate_to_virtual_file_descriptors(set_ptr: *mut libc::fd_set, internal_handles: Vec) { + let virtual_fds = internal_handles .iter() - .filter_map(|host_fd| { - lookup - .get(&host_fd) - .map(|virtual_fd| (*virtual_fd, host_fd)) - }) - .map(|(virtual_fd, host_fd)| { - unsafe { - libc::FD_CLR(*host_fd, set_ptr); - libc::FD_SET(virtual_fd, set_ptr); - } - FdPair { - virtual_fd, - host_fd: *host_fd, - } - }) + .enumerate() + .filter(|(host_fd, _)| unsafe { libc::FD_ISSET(*host_fd as i32, set_ptr) }) + .map(|(_, vfd)| *vfd) .collect::>(); - pairs + unsafe { libc::FD_ZERO(set_ptr) }; + virtual_fds + .iter() + .for_each(|vfd| unsafe { libc::FD_SET(*vfd, set_ptr) }); } /// select -#[cfg(feature = "vfs")] #[allow(clippy::cast_ptr_alignment)] -pub fn ___syscall142(ctx: &mut Ctx, _which: libc::c_int, mut varargs: VarArgs) -> libc::c_int { - debug!("emscripten::___syscall142 (newselect) {}", _which); +pub fn ___syscall142(ctx: &mut Ctx, _: libc::c_int, mut varargs: VarArgs) -> libc::c_int { + debug!("emscripten::___syscall142 (select)"); let nfds: i32 = varargs.get(ctx); let readfds: u32 = varargs.get(ctx); let writefds: u32 = varargs.get(ctx); let _exceptfds: u32 = varargs.get(ctx); - let timeout: i32 = varargs.get(ctx); + let _timeout: i32 = varargs.get(ctx); assert!(nfds <= 64, "`nfds` must be less than or equal to 64"); - let readfds_set_ptr = emscripten_memory_pointer!(ctx.memory(0), readfds) as *mut _; - let writefds_set_ptr = emscripten_memory_pointer!(ctx.memory(0), writefds) as *mut _; - - // debug!(" select read descriptors: {:?}", read_fds); - // - // debug!("select write descriptors: {:?}", write_fds); - - let (read_max, read_lookup, read_pairs) = - translate_to_host_file_descriptors(ctx, &mut varargs, nfds, readfds); - let (write_max, write_lookup, write_pairs) = - translate_to_host_file_descriptors(ctx, &mut varargs, nfds, writefds); - - let max = if read_max > write_max { - read_max - } else { - write_max - }; - debug!("max host fd for select: {}", max); - - let mut sz = max; - - debug!( - "set read descriptors BEFORE select: {:?}", - read_pairs // .iter() - // .map(|pair| pair.virtual_fd) - // .collect::>() - ); - debug!( - "set write descriptors BEFORE select: {:?}", - write_pairs // .iter() - // .map(|pair| pair.virtual_fd) - // .collect::>() - ); - - // call `select` - sz = sz + 1; - debug!( - "readfds_set_ptr: {:?}", - read_pairs - .iter() - .map(|pair| pair.host_fd) - .collect::>() - ); - - unsafe { - use libc::FD_ISSET; - let s = 3; - let x = [ - FD_ISSET(s, readfds_set_ptr), - FD_ISSET(s + 1, readfds_set_ptr), - FD_ISSET(s + 2, readfds_set_ptr), - FD_ISSET(s + 3, readfds_set_ptr), - FD_ISSET(s + 4, readfds_set_ptr), - FD_ISSET(s + 5, readfds_set_ptr), - FD_ISSET(s + 6, readfds_set_ptr), - FD_ISSET(s + 7, readfds_set_ptr), - FD_ISSET(s + 8, readfds_set_ptr), - FD_ISSET(s + 9, readfds_set_ptr), - FD_ISSET(s + 10, readfds_set_ptr), - FD_ISSET(s + 11, readfds_set_ptr), - ]; - debug!("BEFORE sets start with fd #{}: {:?}", s, x); - } - - let fds_slice = unsafe { slice::from_raw_parts(readfds_set_ptr as *const u8, 4) } as &[u8]; - debug!("host read set before: {:?}", fds_slice); - let mut result = unsafe { libc::select(sz, readfds_set_ptr, writefds_set_ptr, 0 as _, 0 as _) }; - debug!("host read set after: {:?}", fds_slice); - - unsafe { - use libc::FD_ISSET; - let s = 3; - let x = [ - FD_ISSET(s, readfds_set_ptr), - FD_ISSET(s + 1, readfds_set_ptr), - FD_ISSET(s + 2, readfds_set_ptr), - FD_ISSET(s + 3, readfds_set_ptr), - FD_ISSET(s + 4, readfds_set_ptr), - FD_ISSET(s + 5, readfds_set_ptr), - FD_ISSET(s + 6, readfds_set_ptr), - FD_ISSET(s + 7, readfds_set_ptr), - FD_ISSET(s + 8, readfds_set_ptr), - FD_ISSET(s + 9, readfds_set_ptr), - FD_ISSET(s + 10, readfds_set_ptr), - FD_ISSET(s + 11, readfds_set_ptr), - ]; - debug!("AFTER sets (start with fd #{}: {:?}", s, x); - } - - if result == -1 { - panic!( - "result returned from select was -1. The errno code: {}", - errno::errno() - ); - } - - let read_pairs = translate_to_virtual_file_descriptors(ctx, sz, readfds, read_lookup); - debug!( - "select read descriptors after select completes: {:?}", - read_pairs // .iter() - // .map(|pair| pair.virtual_fd) - // .collect::>() - ); - - let write_pairs = translate_to_virtual_file_descriptors(ctx, sz, writefds, write_lookup); - debug!( - "select write descriptors after select completes: {:?}", - write_pairs // .iter() - // .map(|pair| pair.virtual_fd) - // .collect::>() - ); - + let emscripten_memory = ctx.memory(0); + let read_set_ptr = emscripten_memory_ptr(emscripten_memory, readfds) as _; + let write_set_ptr = emscripten_memory_ptr(emscripten_memory, writefds) as _; + let vfs = unsafe { (*(ctx.data as *const EmscriptenData)).vfs.as_ref().unwrap() }; + let (read_host_nfds, read_lookup) = translate_to_host_file_descriptors(vfs, read_set_ptr, nfds); + let (write_host_nfds, write_lookup) = + translate_to_host_file_descriptors(vfs, write_set_ptr, nfds); + let host_nfds = std::cmp::max(read_host_nfds, write_host_nfds); + // TODO: timeout and except fds set + let result = unsafe { libc::select(host_nfds, read_set_ptr, write_set_ptr, 0 as _, 0 as _) }; + translate_to_virtual_file_descriptors(read_set_ptr, read_lookup); + translate_to_virtual_file_descriptors(write_set_ptr, write_lookup); debug!("select returns {}", result); result } diff --git a/lib/emscripten/src/syscalls/unix/vfs.rs b/lib/emscripten/src/syscalls/unix/vfs.rs index d00cc5879..a4452f29a 100644 --- a/lib/emscripten/src/syscalls/unix/vfs.rs +++ b/lib/emscripten/src/syscalls/unix/vfs.rs @@ -3,9 +3,7 @@ use crate::syscalls::emscripten_vfs::FileHandle::{Socket, VirtualFile}; use crate::syscalls::emscripten_vfs::{FileHandle, VirtualFd}; use crate::utils::{copy_stat_into_wasm, read_string_from_wasm}; use crate::varargs::VarArgs; -use bit_field::BitArray; use libc::stat; -use std::collections::HashMap; use std::ffi::c_void; use std::os::raw::c_int; use std::slice; @@ -553,7 +551,10 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in socket, flags, len, recv_result ); if recv_result < 0 { - panic!("recvfrom result was less than zero. Errno: {}", errno::errno()); + panic!( + "recvfrom result was less than zero. Errno: {}", + errno::errno() + ); } recv_result } @@ -608,7 +609,13 @@ pub fn ___syscall102(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in let host_socket_fd = vfs.get_host_socket_fd(&vfd).unwrap(); let result = unsafe { - libc::getsockopt(host_socket_fd, correct_level, correct_name, value_addr, option_len_addr) + libc::getsockopt( + host_socket_fd, + correct_level, + correct_name, + value_addr, + option_len_addr, + ) }; if result == -1 { @@ -698,7 +705,10 @@ pub fn ___syscall146(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { Some(FileHandle::Socket(host_fd)) => unsafe { let count = libc::write(*host_fd, iov_buf_ptr, count); if count < 0 { - panic!("the count from write was less than zero. errno: {}", errno::errno()); + panic!( + "the count from write was less than zero. errno: {}", + errno::errno() + ); } count as usize },