@@ -12,17 +12,15 @@ use crate::shims::unix::UnixFileDescription;
1212use crate :: * ;
1313
1414/// An `Epoll` file descriptor connects file handles and epoll events
15- #[ derive( Clone , Debug , Default ) ]
15+ #[ derive( Debug , Default ) ]
1616struct Epoll {
1717 /// A map of EpollEventInterests registered under this epoll instance.
1818 /// Each entry is differentiated using FdId and file descriptor value.
1919 interest_list : RefCell < BTreeMap < ( FdId , i32 ) , Rc < RefCell < EpollEventInterest > > > > ,
2020 /// A map of EpollEventInstance that will be returned when `epoll_wait` is called.
2121 /// Similar to interest_list, the entry is also differentiated using FdId
2222 /// and file descriptor value.
23- // This is an Rc because EpollInterest need to hold a reference to update
24- // it.
25- ready_list : Rc < ReadyList > ,
23+ ready_list : ReadyList ,
2624 /// A list of thread ids blocked on this epoll instance.
2725 blocked_tid : RefCell < Vec < ThreadId > > ,
2826}
@@ -59,7 +57,7 @@ impl EpollEventInstance {
5957/// see the man page:
6058///
6159/// <https://man7.org/linux/man-pages/man2/epoll_ctl.2.html>
62- #[ derive( Clone , Debug ) ]
60+ #[ derive( Debug ) ]
6361pub struct EpollEventInterest {
6462 /// The file descriptor value of the file description registered.
6563 /// This is only used for ready_list, to inform userspace which FD triggered an event.
@@ -73,9 +71,9 @@ pub struct EpollEventInterest {
7371 /// but only u64 is supported for now.
7472 /// <https://man7.org/linux/man-pages/man3/epoll_event.3type.html>
7573 data : u64 ,
76- /// Ready list of the epoll instance under which this EpollEventInterest is registered.
77- ready_list : Rc < ReadyList > ,
7874 /// The epoll file description that this EpollEventInterest is registered under.
75+ /// This is weak to avoid cycles, but an upgrade is always guaranteed to succeed
76+ /// because only the `Epoll` holds a strong ref to a `EpollEventInterest`.
7977 weak_epfd : WeakFileDescriptionRef < Epoll > ,
8078}
8179
@@ -142,12 +140,6 @@ impl EpollReadyEvents {
142140 }
143141}
144142
145- impl Epoll {
146- fn get_ready_list ( & self ) -> Rc < ReadyList > {
147- Rc :: clone ( & self . ready_list )
148- }
149- }
150-
151143impl FileDescription for Epoll {
152144 fn name ( & self ) -> & ' static str {
153145 "epoll"
@@ -279,12 +271,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
279271 let Some ( epfd) = this. machine . fds . get ( epfd_value) else {
280272 return this. set_last_error_and_return_i32 ( LibcError ( "EBADF" ) ) ;
281273 } ;
282- let epoll_file_description = epfd
274+ let epfd = epfd
283275 . downcast :: < Epoll > ( )
284276 . ok_or_else ( || err_unsup_format ! ( "non-epoll FD passed to `epoll_ctl`" ) ) ?;
285277
286- let mut interest_list = epoll_file_description. interest_list . borrow_mut ( ) ;
287- let ready_list = & epoll_file_description. ready_list ;
278+ let mut interest_list = epfd. interest_list . borrow_mut ( ) ;
288279
289280 let Some ( fd_ref) = this. machine . fds . get ( fd) else {
290281 return this. set_last_error_and_return_i32 ( LibcError ( "EBADF" ) ) ;
@@ -345,30 +336,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
345336 }
346337 }
347338
348- // Create an epoll_interest.
349- let interest = Rc :: new ( RefCell :: new ( EpollEventInterest {
350- fd_num : fd,
351- events,
352- data,
353- ready_list : Rc :: clone ( ready_list) ,
354- weak_epfd : FileDescriptionRef :: downgrade ( & epoll_file_description) ,
355- } ) ) ;
356-
357339 if op == epoll_ctl_add {
340+ // Create an epoll_interest.
341+ let interest = Rc :: new ( RefCell :: new ( EpollEventInterest {
342+ fd_num : fd,
343+ events,
344+ data,
345+ weak_epfd : FileDescriptionRef :: downgrade ( & epfd) ,
346+ } ) ) ;
347+ // Notification will be returned for current epfd if there is event in the file
348+ // descriptor we registered.
349+ check_and_update_one_event_interest ( & fd_ref, & interest, id, this) ?;
350+
358351 // Insert an epoll_interest to global epoll_interest list.
359352 this. machine . epoll_interests . insert_epoll_interest ( id, Rc :: downgrade ( & interest) ) ;
360- interest_list. insert ( epoll_key, Rc :: clone ( & interest) ) ;
353+ interest_list. insert ( epoll_key, interest) ;
361354 } else {
362- // Directly modify the epoll_interest so the global epoll_event_interest table
363- // will be updated too.
364- let mut epoll_interest = interest_list. get_mut ( & epoll_key) . unwrap ( ) . borrow_mut ( ) ;
365- epoll_interest. events = events;
366- epoll_interest. data = data;
355+ // Modify the existing interest.
356+ let epoll_interest = interest_list. get_mut ( & epoll_key) . unwrap ( ) ;
357+ {
358+ let mut epoll_interest = epoll_interest. borrow_mut ( ) ;
359+ epoll_interest. events = events;
360+ epoll_interest. data = data;
361+ }
362+ // Updating an FD interest triggers events.
363+ check_and_update_one_event_interest ( & fd_ref, epoll_interest, id, this) ?;
367364 }
368365
369- // Notification will be returned for current epfd if there is event in the file
370- // descriptor we registered.
371- check_and_update_one_event_interest ( & fd_ref, & interest, id, this) ?;
372366 interp_ok ( Scalar :: from_i32 ( 0 ) )
373367 } else if op == epoll_ctl_del {
374368 let epoll_key = ( id, fd) ;
@@ -381,7 +375,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
381375 drop ( epoll_interest) ;
382376
383377 // Remove related epoll_interest from ready list.
384- ready_list. mapping . borrow_mut ( ) . remove ( & epoll_key) ;
378+ epfd . ready_list . mapping . borrow_mut ( ) . remove ( & epoll_key) ;
385379
386380 // Remove dangling EpollEventInterest from its global table.
387381 // .unwrap() below should succeed because the file description id must have registered
@@ -587,21 +581,22 @@ fn ready_list_next(
587581/// notification to only one epoll instance.
588582fn check_and_update_one_event_interest < ' tcx > (
589583 fd_ref : & DynFileDescriptionRef ,
590- interest : & Rc < RefCell < EpollEventInterest > > ,
584+ interest : & RefCell < EpollEventInterest > ,
591585 id : FdId ,
592586 ecx : & MiriInterpCx < ' tcx > ,
593587) -> InterpResult < ' tcx , bool > {
594588 // Get the bitmask of ready events for a file description.
595589 let ready_events_bitmask = fd_ref. as_unix ( ) . get_epoll_ready_events ( ) ?. get_event_bitmask ( ecx) ;
596590 let epoll_event_interest = interest. borrow ( ) ;
591+ let epfd = epoll_event_interest. weak_epfd . upgrade ( ) . unwrap ( ) ;
597592 // This checks if any of the events specified in epoll_event_interest.events
598593 // match those in ready_events.
599594 let flags = epoll_event_interest. events & ready_events_bitmask;
600595 // If there is any event that we are interested in being specified as ready,
601596 // insert an epoll_return to the ready list.
602597 if flags != 0 {
603598 let epoll_key = ( id, epoll_event_interest. fd_num ) ;
604- let ready_list = & mut epoll_event_interest . ready_list . mapping . borrow_mut ( ) ;
599+ let mut ready_list = epfd . ready_list . mapping . borrow_mut ( ) ;
605600 let mut event_instance = EpollEventInstance :: new ( flags, epoll_event_interest. data ) ;
606601 // If we are tracking data races, remember the current clock so we can sync with it later.
607602 ecx. release_clock ( |clock| {
@@ -623,9 +618,7 @@ fn return_ready_list<'tcx>(
623618 events : & MPlaceTy < ' tcx > ,
624619 ecx : & mut MiriInterpCx < ' tcx > ,
625620) -> InterpResult < ' tcx > {
626- let ready_list = epfd. get_ready_list ( ) ;
627-
628- let mut ready_list = ready_list. mapping . borrow_mut ( ) ;
621+ let mut ready_list = epfd. ready_list . mapping . borrow_mut ( ) ;
629622 let mut num_of_events: i32 = 0 ;
630623 let mut array_iter = ecx. project_array_fields ( events) ?;
631624
0 commit comments