@@ -24,7 +24,13 @@ struct Epoll {
2424 // it.
2525 ready_list : Rc < ReadyList > ,
2626 /// A list of thread ids blocked on this epoll instance.
27- thread_id : RefCell < Vec < ThreadId > > ,
27+ blocked_tid : RefCell < Vec < ThreadId > > ,
28+ }
29+
30+ impl VisitProvenance for Epoll {
31+ fn visit_provenance ( & self , _visit : & mut VisitWith < ' _ > ) {
32+ // No provenance anywhere in this type.
33+ }
2834}
2935
3036/// EpollEventInstance contains information that will be returned by epoll_wait.
@@ -362,7 +368,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
362368
363369 // Notification will be returned for current epfd if there is event in the file
364370 // descriptor we registered.
365- check_and_update_one_event_interest ( & fd_ref, interest, id, this) ?;
371+ check_and_update_one_event_interest ( & fd_ref, & interest, id, this) ?;
366372 interp_ok ( Scalar :: from_i32 ( 0 ) )
367373 } else if op == epoll_ctl_del {
368374 let epoll_key = ( id, fd) ;
@@ -454,24 +460,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
454460 let Some ( epfd) = this. machine . fds . get ( epfd_value) else {
455461 return this. set_last_error_and_return ( LibcError ( "EBADF" ) , dest) ;
456462 } ;
457- let epoll_file_description = epfd
458- . downcast :: < Epoll > ( )
459- . ok_or_else ( || err_unsup_format ! ( "non-epoll FD passed to `epoll_wait`" ) ) ?;
460- // Create a weak ref of epfd and pass it to callback so we will make sure that epfd
461- // is not close after the thread unblocks.
462- let weak_epfd = FileDescriptionRef :: downgrade ( & epoll_file_description) ;
463+ let Some ( epfd) = epfd. downcast :: < Epoll > ( ) else {
464+ return this. set_last_error_and_return ( LibcError ( "EBADF" ) , dest) ;
465+ } ;
463466
464467 // We just need to know if the ready list is empty and borrow the thread_ids out.
465- // The whole logic is wrapped inside a block so we don't need to manually drop epfd later.
466- let ready_list_empty;
467- let mut thread_ids;
468- {
469- ready_list_empty = epoll_file_description. ready_list . mapping . borrow ( ) . is_empty ( ) ;
470- thread_ids = epoll_file_description. thread_id . borrow_mut ( ) ;
471- }
468+ let ready_list_empty = epfd. ready_list . mapping . borrow ( ) . is_empty ( ) ;
472469 if timeout == 0 || !ready_list_empty {
473470 // If the ready list is not empty, or the timeout is 0, we can return immediately.
474- return_ready_list ( epfd_value , weak_epfd , dest, & event, this) ?;
471+ return_ready_list ( & epfd , dest, & event, this) ?;
475472 } else {
476473 // Blocking
477474 let timeout = match timeout {
@@ -486,30 +483,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
486483 ) ;
487484 }
488485 } ;
489- thread_ids. push ( this. active_thread ( ) ) ;
486+ // Record this thread as blocked.
487+ epfd. blocked_tid . borrow_mut ( ) . push ( this. active_thread ( ) ) ;
488+ // And block it.
490489 let dest = dest. clone ( ) ;
490+ // We keep a strong ref to the underlying `Epoll` to make sure it sticks around.
491+ // This means there'll be a leak if we never wake up, but that anyway would imply
492+ // a thread is permanently blocked so this is fine.
491493 this. block_thread (
492494 BlockReason :: Epoll ,
493495 timeout,
494496 callback ! (
495497 @capture<' tcx> {
496- epfd_value: i32 ,
497- weak_epfd: WeakFileDescriptionRef <Epoll >,
498+ epfd: FileDescriptionRef <Epoll >,
498499 dest: MPlaceTy <' tcx>,
499500 event: MPlaceTy <' tcx>,
500501 }
501502 @unblock = |this| {
502- return_ready_list( epfd_value , weak_epfd , & dest, & event, this) ?;
503+ return_ready_list( & epfd , & dest, & event, this) ?;
503504 interp_ok( ( ) )
504505 }
505506 @timeout = |this| {
506- // No notification after blocking timeout.
507- let Some ( epfd) = weak_epfd. upgrade( ) else {
508- throw_unsup_format!( "epoll FD {epfd_value} got closed while blocking." )
509- } ;
510507 // Remove the current active thread_id from the blocked thread_id list.
511508 epfd
512- . thread_id . borrow_mut( )
509+ . blocked_tid . borrow_mut( )
513510 . retain( |& id| id != this. active_thread( ) ) ;
514511 this. write_int( 0 , & dest) ?;
515512 interp_ok( ( ) )
@@ -538,12 +535,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
538535 if let Some ( epoll_interests) = this. machine . epoll_interests . get_epoll_interest ( id) {
539536 for weak_epoll_interest in epoll_interests {
540537 if let Some ( epoll_interest) = weak_epoll_interest. upgrade ( ) {
541- let is_updated = check_and_update_one_event_interest (
542- & fd_ref,
543- epoll_interest. clone ( ) ,
544- id,
545- this,
546- ) ?;
538+ let is_updated =
539+ check_and_update_one_event_interest ( & fd_ref, & epoll_interest, id, this) ?;
547540 if is_updated {
548541 // Edge-triggered notification only notify one thread even if there are
549542 // multiple threads blocked on the same epfd.
@@ -554,7 +547,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
554547 // holds a strong ref to epoll_interest.
555548 let epfd = epoll_interest. borrow ( ) . weak_epfd . upgrade ( ) . unwrap ( ) ;
556549 // FIXME: We can randomly pick a thread to unblock.
557- if let Some ( thread_id) = epfd. thread_id . borrow_mut ( ) . pop ( ) {
550+ if let Some ( thread_id) = epfd. blocked_tid . borrow_mut ( ) . pop ( ) {
558551 waiter. push ( thread_id) ;
559552 } ;
560553 }
@@ -594,7 +587,7 @@ fn ready_list_next(
594587/// notification to only one epoll instance.
595588fn check_and_update_one_event_interest < ' tcx > (
596589 fd_ref : & DynFileDescriptionRef ,
597- interest : Rc < RefCell < EpollEventInterest > > ,
590+ interest : & Rc < RefCell < EpollEventInterest > > ,
598591 id : FdId ,
599592 ecx : & MiriInterpCx < ' tcx > ,
600593) -> InterpResult < ' tcx , bool > {
@@ -625,16 +618,11 @@ fn check_and_update_one_event_interest<'tcx>(
625618/// Stores the ready list of the `epfd` epoll instance into `events` (which must be an array),
626619/// and the number of returned events into `dest`.
627620fn return_ready_list < ' tcx > (
628- epfd_value : i32 ,
629- weak_epfd : WeakFileDescriptionRef < Epoll > ,
621+ epfd : & FileDescriptionRef < Epoll > ,
630622 dest : & MPlaceTy < ' tcx > ,
631623 events : & MPlaceTy < ' tcx > ,
632624 ecx : & mut MiriInterpCx < ' tcx > ,
633625) -> InterpResult < ' tcx > {
634- let Some ( epfd) = weak_epfd. upgrade ( ) else {
635- throw_unsup_format ! ( "epoll FD {epfd_value} got closed while blocking." )
636- } ;
637-
638626 let ready_list = epfd. get_ready_list ( ) ;
639627
640628 let mut ready_list = ready_list. mapping . borrow_mut ( ) ;
0 commit comments