@ -1,12 +1,10 @@
#![ allow(non_camel_case_types) ]
#![ allow(unused_unsafe) ]
use crate ::memory ::* ;
use crate ::hostcalls_impl ::{ ClockEventData , FdEventData } ;
use crate ::sys ::host_impl ;
use crate ::{ host , wasm32 , Error , Result } ;
use crate ::{ host , Error , Result } ;
use nix ::libc ::{ self , c_int } ;
use std ::cmp ;
use std ::mem ::MaybeUninit ;
use std ::time ::SystemTime ;
pub ( crate ) fn clock_res_get ( clock_id : host ::__wasi_clockid_t ) -> Result < host ::__wasi_timestamp_t > {
// convert the supported clocks to the libc types, or return EINVAL
@ -70,198 +68,149 @@ pub(crate) fn clock_time_get(clock_id: host::__wasi_clockid_t) -> Result<host::_
}
pub ( crate ) fn poll_oneoff (
input : Vec < Result < host ::__wasi_subscription_t > > ,
output_slice : & mut [ wasm32 ::__wasi_event_t ] ,
) -> Result < wasm32 ::size_t > {
let timeout = input
. iter ( )
. filter_map ( | event | match event {
Ok ( event ) if event . type_ = = wasm32 ::__WASI_EVENTTYPE_CLOCK = > Some ( ClockEventData {
delay : wasi_clock_to_relative_ns_delay ( unsafe { event . u . clock } ) . ok ( ) ? / 1_000_000 ,
userdata : event . userdata ,
} ) ,
_ = > None ,
} )
. min_by_key ( | event | event . delay ) ;
timeout : Option < ClockEventData > ,
fd_events : Vec < FdEventData > ,
) -> Result < Vec < host ::__wasi_event_t > > {
use nix ::{
errno ::Errno ,
poll ::{ poll , PollFd , PollFlags } ,
} ;
use std ::{ convert ::TryInto , os ::unix ::prelude ::AsRawFd } ;
let fd_events : Vec < _ > = input
. iter ( )
. filter_map ( | event | match event {
Ok ( event )
if event . type_ = = wasm32 ::__WASI_EVENTTYPE_FD_READ
| | event . type_ = = wasm32 ::__WASI_EVENTTYPE_FD_WRITE = >
{
Some ( FdEventData {
fd : unsafe { event . u . fd_readwrite . fd } as c_int ,
type_ : event . type_ ,
userdata : event . userdata ,
} )
}
_ = > None ,
} )
. collect ( ) ;
if fd_events . is_empty ( ) & & timeout . is_none ( ) {
return Ok ( 0 ) ;
return Ok ( vec ! [ ] ) ;
}
let mut poll_fds : Vec < _ > = fd_events
. iter ( )
. map ( | event | {
let mut flags = nix ::poll ::PollFlags ::empty ( ) ;
let mut flags = PollFlags ::empty ( ) ;
match event . type_ {
wasm32 ::__WASI_EVENTTYPE_FD_READ = > flags . insert ( nix ::poll ::PollFlags ::POLLIN ) ,
wasm32 ::__WASI_EVENTTYPE_FD_WRITE = > flags . insert ( nix ::poll ::PollFlags ::POLLOUT ) ,
host ::__WASI_EVENTTYPE_FD_READ = > flags . insert ( PollFlags ::POLLIN ) ,
host ::__WASI_EVENTTYPE_FD_WRITE = > flags . insert ( PollFlags ::POLLOUT ) ,
// An event on a file descriptor can currently only be of type FD_READ or FD_WRITE
// Nothing else has been defined in the specification, and these are also the only two
// events we filtered before. If we get something else here, the code has a serious bug.
_ = > unreachable ! ( ) ,
} ;
nix ::poll ::PollFd ::new ( event . fd , flags )
PollFd ::new ( event . descriptor . as_raw_ fd( ) , flags )
} )
. collect ( ) ;
let timeout = timeout . map ( | ClockEventData { delay , userdata } | ClockEventData {
delay : cmp ::min ( delay , c_int ::max_value ( ) as u128 ) ,
userdata ,
let poll_timeout = timeout . map_or ( - 1 , | timeout | {
let delay = timeout . delay / 1_000_000 ; // poll syscall requires delay to expressed in milliseconds
delay . try_into ( ) . unwrap_or ( c_int ::max_value ( ) )
} ) ;
let poll_timeout = timeout . map_or ( - 1 , | timeout | timeout . delay as c_int ) ;
log ::debug ! ( "poll_oneoff poll_timeout = {:?}" , poll_timeout ) ;
let ready = loop {
match nix ::poll ::poll ( & mut poll_fds , poll_timeout ) {
match poll ( & mut poll_fds , poll_timeout ) {
Err ( _ ) = > {
if nix ::errno ::Errno ::last ( ) = = nix ::errno ::Errno ::EINTR {
if Errno ::last ( ) = = Errno ::EINTR {
continue ;
}
return Err ( host_impl ::errno_from_nix ( nix ::errno ::Errno ::last ( ) ) ) ;
return Err ( host_impl ::errno_from_nix ( Errno ::last ( ) ) ) ;
}
Ok ( ready ) = > break ready as usize ,
}
} ;
let events_count = if ready = = 0 {
poll_oneoff_handle_timeout_event ( output_slice , timeout )
} else {
let events = fd_events . iter ( ) . zip ( poll_fds . iter ( ) ) . take ( ready ) ;
poll_oneoff_handle_fd_event ( output_slice , events )
} ;
Ok ( events_count )
Ok ( if ready = = 0 {
poll_oneoff_handle_timeout_event ( timeout . expect ( "timeout should not be None" ) )
} else {
let events = fd_events . into_iter ( ) . zip ( poll_fds . into_iter ( ) ) . take ( ready ) ;
poll_oneoff_handle_fd_event ( events ) ?
} )
}
// define the `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)`
nix ::ioctl_read_bad ! ( fionread , nix ::libc ::FIONREAD , c_int ) ;
fn wasi_clock_to_relative_ns_delay (
wasi_clock : host ::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t ,
) -> Result < u128 > {
if wasi_clock . flags ! = wasm32 ::__WASI_SUBSCRIPTION_CLOCK_ABSTIME {
return Ok ( u128 ::from ( wasi_clock . timeout ) ) ;
}
let now : u128 = SystemTime ::now ( )
. duration_since ( SystemTime ::UNIX_EPOCH )
. map_err ( | _ | Error ::ENOTCAPABLE ) ?
. as_nanos ( ) ;
let deadline = u128 ::from ( wasi_clock . timeout ) ;
Ok ( deadline . saturating_sub ( now ) )
}
#[ derive(Debug, Copy, Clone) ]
struct ClockEventData {
delay : u128 ,
userdata : host ::__wasi_userdata_t ,
}
#[ derive(Debug, Copy, Clone) ]
struct FdEventData {
fd : c_int ,
type_ : host ::__wasi_eventtype_t ,
userdata : host ::__wasi_userdata_t ,
}
fn poll_oneoff_handle_timeout_event (
output_slice : & mut [ wasm32 ::__wasi_event_t ] ,
timeout : Option < ClockEventData > ,
) -> wasm32 ::size_t {
if let Some ( ClockEventData { userdata , . . } ) = timeout {
let output_event = host ::__wasi_event_t {
userdata ,
type_ : wasm32 ::__WASI_EVENTTYPE_CLOCK ,
error : wasm32 ::__WASI_ESUCCESS ,
u : host ::__wasi_event_t___wasi_event_u {
fd_readwrite : host ::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
nbytes : 0 ,
flags : 0 ,
} ,
fn poll_oneoff_handle_timeout_event ( timeout : ClockEventData ) -> Vec < host ::__wasi_event_t > {
vec ! [ host ::__wasi_event_t {
userdata : timeout . userdata ,
type_ : host ::__WASI_EVENTTYPE_CLOCK ,
error : host ::__WASI_ESUCCESS ,
u : host ::__wasi_event_t___wasi_event_u {
fd_readwrite : host ::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
nbytes : 0 ,
flags : 0 ,
} ,
} ;
output_slice [ 0 ] = enc_event ( output_event ) ;
1
} else {
// shouldn't happen
0
}
} ,
} ]
}
fn poll_oneoff_handle_fd_event < 't > (
output_slice : & mut [ wasm32 ::__wasi_event_t ] ,
events : impl Iterator < Item = ( & 't FdEventData , & 't nix ::poll ::PollFd ) > ,
) -> wasm32 ::size_t {
let mut output_slice_cur = output_slice . iter_mut ( ) ;
let mut revents_count = 0 ;
fn poll_oneoff_handle_fd_event < 'a > (
events : impl Iterator < Item = ( FdEventData < 'a > , nix ::poll ::PollFd ) > ,
) -> Result < Vec < host ::__wasi_event_t > > {
use nix ::poll ::PollFlags ;
use std ::{ convert ::TryInto , os ::unix ::prelude ::AsRawFd } ;
let mut output_events = Vec ::new ( ) ;
for ( fd_event , poll_fd ) in events {
log ::debug ! ( "poll_oneoff_handle_fd_event fd_event = {:?}" , fd_event ) ;
log ::debug ! ( "poll_oneoff_handle_fd_event poll_fd = {:?}" , poll_fd ) ;
let revents = match poll_fd . revents ( ) {
Some ( revents ) = > revents ,
None = > continue ,
} ;
log ::debug ! ( "poll_oneoff_handle_fd_event revents = {:?}" , revents ) ;
let mut nbytes = 0 ;
if fd_event . type_ = = wasm32 ::__WASI_EVENTTYPE_FD_READ {
let _ = unsafe { fionread ( fd_event . fd , & mut nbytes ) } ;
if fd_event . type_ = = host ::__WASI_EVENTTYPE_FD_READ {
let _ = unsafe { fionread ( fd_event . descriptor . as_raw_fd ( ) , & mut nbytes ) } ;
}
let output_event = if revents . contains ( nix ::poll ::PollFlags ::POLLNVAL ) {
let output_event = if revents . contains ( PollFlags ::POLLNVAL ) {
host ::__wasi_event_t {
userdata : fd_event . userdata ,
type_ : fd_event . type_ ,
error : wasm32 ::__WASI_EBADF ,
error : host ::__WASI_EBADF ,
u : host ::__wasi_event_t___wasi_event_u {
fd_readwrite :
host ::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
nbytes : 0 ,
flags : wasm32 ::__WASI_EVENT_FD_READWRITE_HANGUP ,
flags : host ::__WASI_EVENT_FD_READWRITE_HANGUP ,
} ,
} ,
}
} else if revents . contains ( nix ::poll ::PollFlags ::POLLERR ) {
} else if revents . contains ( PollFlags ::POLLERR ) {
host ::__wasi_event_t {
userdata : fd_event . userdata ,
type_ : fd_event . type_ ,
error : wasm32 ::__WASI_EIO ,
error : host ::__WASI_EIO ,
u : host ::__wasi_event_t___wasi_event_u {
fd_readwrite :
host ::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
nbytes : 0 ,
flags : wasm32 ::__WASI_EVENT_FD_READWRITE_HANGUP ,
flags : host ::__WASI_EVENT_FD_READWRITE_HANGUP ,
} ,
} ,
}
} else if revents . contains ( nix ::poll ::PollFlags ::POLLHUP ) {
} else if revents . contains ( PollFlags ::POLLHUP ) {
host ::__wasi_event_t {
userdata : fd_event . userdata ,
type_ : fd_event . type_ ,
error : wasm32 ::__WASI_ESUCCESS ,
error : host ::__WASI_ESUCCESS ,
u : host ::__wasi_event_t___wasi_event_u {
fd_readwrite :
host ::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
nbytes : 0 ,
flags : wasm32 ::__WASI_EVENT_FD_READWRITE_HANGUP ,
flags : host ::__WASI_EVENT_FD_READWRITE_HANGUP ,
} ,
} ,
}
} else if revents . contains ( nix ::poll ::PollFlags ::POLLIN )
| revents . contains ( nix ::poll ::PollFlags ::POLLOUT )
{
} else if revents . contains ( PollFlags ::POLLIN ) | revents . contains ( PollFlags ::POLLOUT ) {
host ::__wasi_event_t {
userdata : fd_event . userdata ,
type_ : fd_event . type_ ,
error : wasm32 ::__WASI_ESUCCESS ,
error : host ::__WASI_ESUCCESS ,
u : host ::__wasi_event_t___wasi_event_u {
fd_readwrite :
host ::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
nbytes : nbytes as host ::__wasi_filesize_t ,
nbytes : nbytes . try_into ( ) ? ,
flags : 0 ,
} ,
} ,
@ -269,8 +218,9 @@ fn poll_oneoff_handle_fd_event<'t>(
} else {
continue ;
} ;
* output_slice_cur . next ( ) . unwrap ( ) = enc_event ( output_event ) ;
revents_count + = 1 ;
output_events . push ( output_event ) ;
}
revents_count
Ok ( output_events )
}