shrink select

This commit is contained in:
Mackenzie Clark 2019-03-23 16:19:25 -07:00
parent e5951ce56d
commit e986ec13fa
3 changed files with 62 additions and 250 deletions

View File

@ -102,7 +102,7 @@ impl EmscriptenVfs {
panic!()
}
Some(*fd)
},
}
_ => None,
}
}

View File

@ -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<i32, i32>, Vec<FdPair>) {
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::<u8>()[(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<i32> = (0..nfds)
.filter_map(|virtual_fd| {
if fds_slice.get_bit(virtual_fd as usize) {
Some(virtual_fd as i32)
} else {
None
}
})
) -> (i32, Vec<i32>) {
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::<Vec<_>>();
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::<Vec<_>>();
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<i32, i32>,
) -> Vec<FdPair> {
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::<Vec<_>>();
// swap descriptors back
let pairs = fds
fn translate_to_virtual_file_descriptors(set_ptr: *mut libc::fd_set, internal_handles: Vec<i32>) {
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::<Vec<_>>();
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::<Vec<_>>()
);
debug!(
"set write descriptors BEFORE select: {:?}",
write_pairs // .iter()
// .map(|pair| pair.virtual_fd)
// .collect::<Vec<_>>()
);
// call `select`
sz = sz + 1;
debug!(
"readfds_set_ptr: {:?}",
read_pairs
.iter()
.map(|pair| pair.host_fd)
.collect::<Vec<_>>()
);
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::<Vec<_>>()
);
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::<Vec<_>>()
);
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
}

View File

@ -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
},