@@ -2,6 +2,7 @@ use std::cell::RefCell;
22use std:: collections:: BTreeMap ;
33use std:: io;
44use std:: rc:: { Rc , Weak } ;
5+ use std:: time:: Duration ;
56
67use crate :: shims:: unix:: fd:: FdId ;
78use crate :: shims:: unix:: * ;
@@ -378,62 +379,74 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
378379 events_op : & OpTy < ' tcx > ,
379380 maxevents : & OpTy < ' tcx > ,
380381 timeout : & OpTy < ' tcx > ,
381- ) -> InterpResult < ' tcx , Scalar > {
382+ place : & ' tcx MPlaceTy < ' tcx > ,
383+ ) -> InterpResult < ' tcx > {
382384 let this = self . eval_context_mut ( ) ;
383385
384- let epfd = this. read_scalar ( epfd) ?. to_i32 ( ) ?;
386+ let epfd_value = this. read_scalar ( epfd) ?. to_i32 ( ) ?;
385387 let maxevents = this. read_scalar ( maxevents) ?. to_i32 ( ) ?;
386388 let event = this. deref_pointer_as (
387389 events_op,
388390 this. libc_array_ty_layout ( "epoll_event" , maxevents. try_into ( ) . unwrap ( ) ) ,
389391 ) ?;
390- let timeout = this. read_scalar ( timeout) ?. to_i32 ( ) ?;
392+ let timeout = this. read_scalar ( timeout) ?. to_u32 ( ) ?;
391393
392- if epfd <= 0 {
394+ if epfd_value <= 0 {
393395 let einval = this. eval_libc ( "EINVAL" ) ;
394396 this. set_last_error ( einval) ?;
395- return Ok ( Scalar :: from_i32 ( -1 ) ) ;
396- }
397- // FIXME: Implement blocking support
398- if timeout != 0 {
399- throw_unsup_format ! ( "epoll_wait: timeout value can only be 0" ) ;
397+ this. write_scalar ( Scalar :: from_i32 ( -1 ) , place) ?;
398+ return Ok ( ( ) ) ;
400399 }
401-
402- let Some ( epfd) = this. machine . fds . get_ref ( epfd) else {
403- return Ok ( Scalar :: from_i32 ( this. fd_not_found ( ) ?) ) ;
400+ let Some ( epfd) = this. machine . fds . get_ref ( epfd_value) else {
401+ let result_value = this. fd_not_found ( ) ?;
402+ this. write_scalar ( Scalar :: from_i32 ( result_value) , place) ?;
403+ return Ok ( ( ) ) ;
404404 } ;
405405 let mut binding = epfd. borrow_mut ( ) ;
406406 let epoll_file_description = & mut binding
407407 . downcast_mut :: < Epoll > ( )
408408 . ok_or_else ( || err_unsup_format ! ( "non-epoll FD passed to `epoll_wait`" ) ) ?;
409409
410410 let binding = epoll_file_description. get_ready_list ( ) ;
411- let mut ready_list = binding. borrow_mut ( ) ;
412- let mut num_of_events: i32 = 0 ;
413- let mut array_iter = this. project_array_fields ( & event) ?;
411+ let ready_list = binding. borrow_mut ( ) ;
414412
415- while let Some ( ( epoll_key, epoll_return) ) = ready_list. pop_first ( ) {
416- // If the file description is fully close, the entry for corresponding FdID in the
417- // global epoll event interest table would be empty.
418- if this. machine . epoll_interests . get_epoll_interest ( epoll_key. 0 ) . is_some ( ) {
419- // Return notification to the caller if the file description is not fully closed.
420- if let Some ( des) = array_iter. next ( this) ? {
421- this. write_int_fields_named (
422- & [
423- ( "events" , epoll_return. events . into ( ) ) ,
424- ( "u64" , epoll_return. data . into ( ) ) ,
425- ] ,
426- & des. 1 ,
427- ) ?;
428- num_of_events = num_of_events. checked_add ( 1 ) . unwrap ( ) ;
429- } else {
430- break ;
431- }
413+ if ready_list. is_empty ( ) {
414+ if timeout == 0 {
415+ // Non-blocking with no notification returned.
416+ this. write_scalar ( Scalar :: from_i32 ( 0 ) , place) ?;
417+ return Ok ( ( ) ) ;
418+ } else {
419+ // Blocking
420+ let duration = Duration :: from_secs ( timeout. into ( ) ) ;
421+ this. block_thread (
422+ BlockReason :: Epoll ,
423+ Some ( ( TimeoutClock :: Monotonic , TimeoutAnchor :: Relative , duration) ) ,
424+ callback ! (
425+ @capture<' tcx> {
426+ epfd_value: i32 ,
427+ place: & ' tcx MPlaceTy <' tcx>,
428+ event: MPlaceTy <' tcx>,
429+ }
430+ @unblock = |this| {
431+ this. blocking_epoll_callback( epfd_value, place, & event) ;
432+ Ok ( ( ) )
433+ }
434+ @timeout = |this| {
435+ this. write_scalar( Scalar :: from_i32( 0 ) , place) ?;
436+ Ok ( ( ) )
437+ }
438+ ) ,
439+ ) ;
432440 }
441+ } else {
442+ // Non-blocking with notification returned.
443+ this. blocking_epoll_callback ( epfd_value, place, & event) ;
444+ return Ok ( ( ) ) ;
433445 }
434- Ok ( Scalar :: from_i32 ( num_of_events) )
435- }
436446
447+ Ok ( ( ) )
448+ }
449+
437450 /// For a specific unique file descriptor id, get its ready events and update
438451 /// the corresponding ready list. This function is called whenever a file description
439452 /// is registered with epoll, or when read, write, or close operations are performed,
0 commit comments