@@ -24,7 +24,13 @@ struct Epoll {
24
24
// it.
25
25
ready_list : Rc < ReadyList > ,
26
26
/// 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
+ }
28
34
}
29
35
30
36
/// EpollEventInstance contains information that will be returned by epoll_wait.
@@ -362,7 +368,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
362
368
363
369
// Notification will be returned for current epfd if there is event in the file
364
370
// 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) ?;
366
372
interp_ok ( Scalar :: from_i32 ( 0 ) )
367
373
} else if op == epoll_ctl_del {
368
374
let epoll_key = ( id, fd) ;
@@ -454,24 +460,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
454
460
let Some ( epfd) = this. machine . fds . get ( epfd_value) else {
455
461
return this. set_last_error_and_return ( LibcError ( "EBADF" ) , dest) ;
456
462
} ;
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
+ } ;
463
466
464
467
// 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 ( ) ;
472
469
if timeout == 0 || !ready_list_empty {
473
470
// 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) ?;
475
472
} else {
476
473
// Blocking
477
474
let timeout = match timeout {
@@ -486,30 +483,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
486
483
) ;
487
484
}
488
485
} ;
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.
490
489
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.
491
493
this. block_thread (
492
494
BlockReason :: Epoll ,
493
495
timeout,
494
496
callback ! (
495
497
@capture<' tcx> {
496
- epfd_value: i32 ,
497
- weak_epfd: WeakFileDescriptionRef <Epoll >,
498
+ epfd: FileDescriptionRef <Epoll >,
498
499
dest: MPlaceTy <' tcx>,
499
500
event: MPlaceTy <' tcx>,
500
501
}
501
502
@unblock = |this| {
502
- return_ready_list( epfd_value , weak_epfd , & dest, & event, this) ?;
503
+ return_ready_list( & epfd , & dest, & event, this) ?;
503
504
interp_ok( ( ) )
504
505
}
505
506
@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
- } ;
510
507
// Remove the current active thread_id from the blocked thread_id list.
511
508
epfd
512
- . thread_id . borrow_mut( )
509
+ . blocked_tid . borrow_mut( )
513
510
. retain( |& id| id != this. active_thread( ) ) ;
514
511
this. write_int( 0 , & dest) ?;
515
512
interp_ok( ( ) )
@@ -538,12 +535,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
538
535
if let Some ( epoll_interests) = this. machine . epoll_interests . get_epoll_interest ( id) {
539
536
for weak_epoll_interest in epoll_interests {
540
537
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) ?;
547
540
if is_updated {
548
541
// Edge-triggered notification only notify one thread even if there are
549
542
// multiple threads blocked on the same epfd.
@@ -554,7 +547,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
554
547
// holds a strong ref to epoll_interest.
555
548
let epfd = epoll_interest. borrow ( ) . weak_epfd . upgrade ( ) . unwrap ( ) ;
556
549
// 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 ( ) {
558
551
waiter. push ( thread_id) ;
559
552
} ;
560
553
}
@@ -594,7 +587,7 @@ fn ready_list_next(
594
587
/// notification to only one epoll instance.
595
588
fn check_and_update_one_event_interest < ' tcx > (
596
589
fd_ref : & DynFileDescriptionRef ,
597
- interest : Rc < RefCell < EpollEventInterest > > ,
590
+ interest : & Rc < RefCell < EpollEventInterest > > ,
598
591
id : FdId ,
599
592
ecx : & MiriInterpCx < ' tcx > ,
600
593
) -> InterpResult < ' tcx , bool > {
@@ -625,16 +618,11 @@ fn check_and_update_one_event_interest<'tcx>(
625
618
/// Stores the ready list of the `epfd` epoll instance into `events` (which must be an array),
626
619
/// and the number of returned events into `dest`.
627
620
fn return_ready_list < ' tcx > (
628
- epfd_value : i32 ,
629
- weak_epfd : WeakFileDescriptionRef < Epoll > ,
621
+ epfd : & FileDescriptionRef < Epoll > ,
630
622
dest : & MPlaceTy < ' tcx > ,
631
623
events : & MPlaceTy < ' tcx > ,
632
624
ecx : & mut MiriInterpCx < ' tcx > ,
633
625
) -> InterpResult < ' tcx > {
634
- let Some ( epfd) = weak_epfd. upgrade ( ) else {
635
- throw_unsup_format ! ( "epoll FD {epfd_value} got closed while blocking." )
636
- } ;
637
-
638
626
let ready_list = epfd. get_ready_list ( ) ;
639
627
640
628
let mut ready_list = ready_list. mapping . borrow_mut ( ) ;
0 commit comments