Skip to content

Commit 4560606

Browse files
committed
epoll: change clock to be per event
1 parent 6f854ce commit 4560606

File tree

3 files changed

+41
-28
lines changed

3 files changed

+41
-28
lines changed

src/tools/miri/src/shims/unix/linux/epoll.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@ pub struct EpollEventInstance {
3232
events: u32,
3333
/// Original data retrieved from `epoll_event` during `epoll_ctl`.
3434
data: u64,
35+
/// The release clock associated with this event.
36+
clock: VClock,
3537
}
3638

3739
impl EpollEventInstance {
3840
pub fn new(events: u32, data: u64) -> EpollEventInstance {
39-
EpollEventInstance { events, data }
41+
EpollEventInstance { events, data, clock: Default::default() }
4042
}
4143
}
4244

@@ -92,7 +94,6 @@ pub struct EpollReadyEvents {
9294
#[derive(Debug, Default)]
9395
struct ReadyList {
9496
mapping: RefCell<BTreeMap<(FdId, i32), EpollEventInstance>>,
95-
clock: RefCell<VClock>,
9697
}
9798

9899
impl EpollReadyEvents {
@@ -567,11 +568,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
567568

568569
let epoll = epfd.downcast::<Epoll>().unwrap();
569570

570-
// Synchronize running thread to the epoll ready list.
571-
this.release_clock(|clock| {
572-
epoll.ready_list.clock.borrow_mut().join(clock);
573-
});
574-
575571
if let Some(thread_id) = epoll.thread_id.borrow_mut().pop() {
576572
waiter.push(thread_id);
577573
};
@@ -627,7 +623,11 @@ fn check_and_update_one_event_interest<'tcx>(
627623
if flags != 0 {
628624
let epoll_key = (id, epoll_event_interest.fd_num);
629625
let ready_list = &mut epoll_event_interest.ready_list.mapping.borrow_mut();
630-
let event_instance = EpollEventInstance::new(flags, epoll_event_interest.data);
626+
let mut event_instance = EpollEventInstance::new(flags, epoll_event_interest.data);
627+
// If we are tracking data races, remember the current clock so we can sync with it later.
628+
ecx.release_clock(|clock| {
629+
event_instance.clock.join(clock);
630+
});
631631
// Triggers the notification by inserting it to the ready list.
632632
ready_list.insert(epoll_key, event_instance);
633633
interp_ok(true)
@@ -654,9 +654,6 @@ fn blocking_epoll_callback<'tcx>(
654654

655655
let ready_list = epoll_file_description.get_ready_list();
656656

657-
// Synchronize waking thread from the epoll ready list.
658-
ecx.acquire_clock(&ready_list.clock.borrow());
659-
660657
let mut ready_list = ready_list.mapping.borrow_mut();
661658
let mut num_of_events: i32 = 0;
662659
let mut array_iter = ecx.project_array_fields(events)?;
@@ -670,6 +667,9 @@ fn blocking_epoll_callback<'tcx>(
670667
],
671668
&des.1,
672669
)?;
670+
// Synchronize waking thread with the event of interest.
671+
ecx.acquire_clock(&epoll_event_instance.clock);
672+
673673
num_of_events = num_of_events.strict_add(1);
674674
} else {
675675
break;

src/tools/miri/tests/pass-dep/libc/libc-epoll-clock-sync.rs renamed to src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
//! This ensures that when an epoll_wait wakes up and there are multiple events,
2+
//! and we only read one of them, we do not synchronize with the other events
3+
//! and therefore still report a data race for things that need to see the second event
4+
//! to be considered synchronized.
15
//@only-target: linux
2-
// ensure single way to order the thread tests
6+
// ensure deterministic schedule
37
//@compile-flags: -Zmiri-preemption-rate=0
48

59
use std::convert::TryInto;
@@ -30,7 +34,7 @@ fn check_epoll_wait<const N: usize>(epfd: i32, expected_notifications: &[(u32, u
3034
}
3135
}
3236

33-
fn common_setup() -> (i32, [i32; 2], [i32; 2]) {
37+
fn main() {
3438
// Create an epoll instance.
3539
let epfd = unsafe { libc::epoll_create1(0) };
3640
assert_ne!(epfd, -1);
@@ -59,17 +63,6 @@ fn common_setup() -> (i32, [i32; 2], [i32; 2]) {
5963
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds_b[1], &mut ev) };
6064
assert_eq!(res, 0);
6165

62-
(epfd, fds_a, fds_b)
63-
}
64-
65-
// Test that the clock sync that happens through an epoll_wait only synchronizes with the clock(s)
66-
// that were reported. It is possible more events had become ready but the epoll_wait didn't
67-
// provide room for them all.
68-
//
69-
// Well before the fix, this fails to report UB.
70-
fn main() {
71-
let (epfd, fds_a, fds_b) = common_setup();
72-
7366
static mut VAL_ONE: u8 = 40; // This one will be read soundly.
7467
static mut VAL_TWO: u8 = 50; // This one will be read unsoundly.
7568
let thread1 = spawn(move || {
@@ -91,13 +84,13 @@ fn main() {
9184
let expected_value = u64::try_from(fds_a[1]).unwrap();
9285
check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)]);
9386

94-
#[allow(static_mut_refs)]
87+
// Since we only received one event, we have synchronized with
88+
// the write to VAL_ONE but not with the one to VAL_TWO.
9589
unsafe {
96-
assert_eq!(VAL_ONE, 41) // This one is not UB
90+
assert_eq!({ VAL_ONE }, 41) // This one is not UB
9791
};
98-
#[allow(static_mut_refs)]
9992
unsafe {
100-
assert_eq!(VAL_TWO, 51) // This one should be UB but isn't (yet).
93+
assert_eq!({ VAL_TWO }, 51) //~ERROR: Data race detected
10194
};
10295

10396
thread1.join().unwrap();
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic read on thread `main` at ALLOC. (2) just happened here
2+
--> tests/fail-dep/libc/libc-epoll-data-race.rs:LL:CC
3+
|
4+
LL | assert_eq!({ VAL_TWO }, 51)
5+
| ^^^^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic read on thread `main` at ALLOC. (2) just happened here
6+
|
7+
help: and (1) occurred earlier here
8+
--> tests/fail-dep/libc/libc-epoll-data-race.rs:LL:CC
9+
|
10+
LL | unsafe { VAL_TWO = 51 };
11+
| ^^^^^^^^^^^^
12+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
13+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
14+
= note: BACKTRACE (of the first span):
15+
= note: inside `main` at tests/fail-dep/libc/libc-epoll-data-race.rs:LL:CC
16+
17+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
18+
19+
error: aborting due to 1 previous error
20+

0 commit comments

Comments
 (0)