@@ -12,17 +12,15 @@ use crate::shims::unix::UnixFileDescription;
12
12
use crate :: * ;
13
13
14
14
/// An `Epoll` file descriptor connects file handles and epoll events
15
- #[ derive( Clone , Debug , Default ) ]
15
+ #[ derive( Debug , Default ) ]
16
16
struct Epoll {
17
17
/// A map of EpollEventInterests registered under this epoll instance.
18
18
/// Each entry is differentiated using FdId and file descriptor value.
19
19
interest_list : RefCell < BTreeMap < ( FdId , i32 ) , Rc < RefCell < EpollEventInterest > > > > ,
20
20
/// A map of EpollEventInstance that will be returned when `epoll_wait` is called.
21
21
/// Similar to interest_list, the entry is also differentiated using FdId
22
22
/// 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 ,
26
24
/// A list of thread ids blocked on this epoll instance.
27
25
blocked_tid : RefCell < Vec < ThreadId > > ,
28
26
}
@@ -59,7 +57,7 @@ impl EpollEventInstance {
59
57
/// see the man page:
60
58
///
61
59
/// <https://man7.org/linux/man-pages/man2/epoll_ctl.2.html>
62
- #[ derive( Clone , Debug ) ]
60
+ #[ derive( Debug ) ]
63
61
pub struct EpollEventInterest {
64
62
/// The file descriptor value of the file description registered.
65
63
/// This is only used for ready_list, to inform userspace which FD triggered an event.
@@ -73,9 +71,9 @@ pub struct EpollEventInterest {
73
71
/// but only u64 is supported for now.
74
72
/// <https://man7.org/linux/man-pages/man3/epoll_event.3type.html>
75
73
data : u64 ,
76
- /// Ready list of the epoll instance under which this EpollEventInterest is registered.
77
- ready_list : Rc < ReadyList > ,
78
74
/// 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`.
79
77
weak_epfd : WeakFileDescriptionRef < Epoll > ,
80
78
}
81
79
@@ -142,12 +140,6 @@ impl EpollReadyEvents {
142
140
}
143
141
}
144
142
145
- impl Epoll {
146
- fn get_ready_list ( & self ) -> Rc < ReadyList > {
147
- Rc :: clone ( & self . ready_list )
148
- }
149
- }
150
-
151
143
impl FileDescription for Epoll {
152
144
fn name ( & self ) -> & ' static str {
153
145
"epoll"
@@ -279,12 +271,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
279
271
let Some ( epfd) = this. machine . fds . get ( epfd_value) else {
280
272
return this. set_last_error_and_return_i32 ( LibcError ( "EBADF" ) ) ;
281
273
} ;
282
- let epoll_file_description = epfd
274
+ let epfd = epfd
283
275
. downcast :: < Epoll > ( )
284
276
. ok_or_else ( || err_unsup_format ! ( "non-epoll FD passed to `epoll_ctl`" ) ) ?;
285
277
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 ( ) ;
288
279
289
280
let Some ( fd_ref) = this. machine . fds . get ( fd) else {
290
281
return this. set_last_error_and_return_i32 ( LibcError ( "EBADF" ) ) ;
@@ -345,30 +336,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
345
336
}
346
337
}
347
338
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
-
357
339
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
+
358
351
// Insert an epoll_interest to global epoll_interest list.
359
352
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) ;
361
354
} 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) ?;
367
364
}
368
365
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) ?;
372
366
interp_ok ( Scalar :: from_i32 ( 0 ) )
373
367
} else if op == epoll_ctl_del {
374
368
let epoll_key = ( id, fd) ;
@@ -381,7 +375,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
381
375
drop ( epoll_interest) ;
382
376
383
377
// 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) ;
385
379
386
380
// Remove dangling EpollEventInterest from its global table.
387
381
// .unwrap() below should succeed because the file description id must have registered
@@ -587,21 +581,22 @@ fn ready_list_next(
587
581
/// notification to only one epoll instance.
588
582
fn check_and_update_one_event_interest < ' tcx > (
589
583
fd_ref : & DynFileDescriptionRef ,
590
- interest : & Rc < RefCell < EpollEventInterest > > ,
584
+ interest : & RefCell < EpollEventInterest > ,
591
585
id : FdId ,
592
586
ecx : & MiriInterpCx < ' tcx > ,
593
587
) -> InterpResult < ' tcx , bool > {
594
588
// Get the bitmask of ready events for a file description.
595
589
let ready_events_bitmask = fd_ref. as_unix ( ) . get_epoll_ready_events ( ) ?. get_event_bitmask ( ecx) ;
596
590
let epoll_event_interest = interest. borrow ( ) ;
591
+ let epfd = epoll_event_interest. weak_epfd . upgrade ( ) . unwrap ( ) ;
597
592
// This checks if any of the events specified in epoll_event_interest.events
598
593
// match those in ready_events.
599
594
let flags = epoll_event_interest. events & ready_events_bitmask;
600
595
// If there is any event that we are interested in being specified as ready,
601
596
// insert an epoll_return to the ready list.
602
597
if flags != 0 {
603
598
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 ( ) ;
605
600
let mut event_instance = EpollEventInstance :: new ( flags, epoll_event_interest. data ) ;
606
601
// If we are tracking data races, remember the current clock so we can sync with it later.
607
602
ecx. release_clock ( |clock| {
@@ -623,9 +618,7 @@ fn return_ready_list<'tcx>(
623
618
events : & MPlaceTy < ' tcx > ,
624
619
ecx : & mut MiriInterpCx < ' tcx > ,
625
620
) -> 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 ( ) ;
629
622
let mut num_of_events: i32 = 0 ;
630
623
let mut array_iter = ecx. project_array_fields ( events) ?;
631
624
0 commit comments