1
1
//! Linux `eventfd` implementation.
2
2
use std:: io;
3
3
use std:: io:: { Error , ErrorKind } ;
4
+ use std:: mem;
4
5
5
6
use rustc_target:: abi:: Endian ;
6
7
@@ -9,8 +10,8 @@ use crate::{concurrency::VClock, *};
9
10
10
11
use self :: shims:: unix:: fd:: FileDescriptor ;
11
12
12
- /// Minimum size of u8 array to hold u64 value .
13
- const U64_MIN_ARRAY_SIZE : usize = 8 ;
13
+ // We'll only do reads and writes in chunks of size u64 .
14
+ const U64_ARRAY_SIZE : usize = mem :: size_of :: < u64 > ( ) ;
14
15
15
16
/// Maximum value that the eventfd counter can hold.
16
17
const MAX_COUNTER : u64 = u64:: MAX - 1 ;
@@ -51,7 +52,7 @@ impl FileDescription for Event {
51
52
ecx : & mut MiriInterpCx < ' tcx > ,
52
53
) -> InterpResult < ' tcx , io:: Result < usize > > {
53
54
// Check the size of slice, and return error only if the size of the slice < 8.
54
- let Some ( bytes) = bytes. first_chunk_mut :: < U64_MIN_ARRAY_SIZE > ( ) else {
55
+ let Some ( bytes) = bytes. first_chunk_mut :: < U64_ARRAY_SIZE > ( ) else {
55
56
return Ok ( Err ( Error :: from ( ErrorKind :: InvalidInput ) ) ) ;
56
57
} ;
57
58
// Block when counter == 0.
@@ -63,15 +64,15 @@ impl FileDescription for Event {
63
64
throw_unsup_format ! ( "eventfd: blocking is unsupported" ) ;
64
65
}
65
66
} else {
66
- // Prevent false alarm in data race detection when doing synchronisation via eventfd .
67
+ // Synchronize with all prior `write` calls to this FD .
67
68
ecx. acquire_clock ( & self . clock ) ;
68
69
// Return the counter in the host endianness using the buffer provided by caller.
69
70
* bytes = match ecx. tcx . sess . target . endian {
70
71
Endian :: Little => self . counter . to_le_bytes ( ) ,
71
72
Endian :: Big => self . counter . to_be_bytes ( ) ,
72
73
} ;
73
74
self . counter = 0 ;
74
- return Ok ( Ok ( U64_MIN_ARRAY_SIZE ) ) ;
75
+ return Ok ( Ok ( U64_ARRAY_SIZE ) ) ;
75
76
}
76
77
}
77
78
@@ -94,7 +95,7 @@ impl FileDescription for Event {
94
95
ecx : & mut MiriInterpCx < ' tcx > ,
95
96
) -> InterpResult < ' tcx , io:: Result < usize > > {
96
97
// Check the size of slice, and return error only if the size of the slice < 8.
97
- let Some ( bytes) = bytes. first_chunk :: < U64_MIN_ARRAY_SIZE > ( ) else {
98
+ let Some ( bytes) = bytes. first_chunk :: < U64_ARRAY_SIZE > ( ) else {
98
99
return Ok ( Err ( Error :: from ( ErrorKind :: InvalidInput ) ) ) ;
99
100
} ;
100
101
// Convert from bytes to int according to host endianness.
@@ -110,8 +111,10 @@ impl FileDescription for Event {
110
111
// Else, block.
111
112
match self . counter . checked_add ( num) {
112
113
Some ( new_count @ 0 ..=MAX_COUNTER ) => {
113
- // Prevent false alarm in data race detection when doing synchronisation via eventfd.
114
- self . clock . join ( & ecx. release_clock ( ) . unwrap ( ) ) ;
114
+ // Future `read` calls will synchronize with this write, so update the FD clock.
115
+ if let Some ( clock) = & ecx. release_clock ( ) {
116
+ self . clock . join ( clock) ;
117
+ }
115
118
self . counter = new_count;
116
119
}
117
120
None | Some ( u64:: MAX ) => {
@@ -123,7 +126,7 @@ impl FileDescription for Event {
123
126
}
124
127
}
125
128
} ;
126
- Ok ( Ok ( U64_MIN_ARRAY_SIZE ) )
129
+ Ok ( Ok ( U64_ARRAY_SIZE ) )
127
130
}
128
131
}
129
132
@@ -163,19 +166,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
163
166
}
164
167
165
168
let mut is_nonblock = false ;
166
- // Unload the flag that we support.
169
+ // Unset the flag that we support.
167
170
// After unloading, flags != 0 means other flags are used.
168
171
if flags & efd_cloexec == efd_cloexec {
172
+ // cloexec is ignored because Miri does not support exec.
169
173
flags &= !efd_cloexec;
170
174
}
171
175
if flags & efd_nonblock == efd_nonblock {
172
176
flags &= !efd_nonblock;
173
177
is_nonblock = true ;
174
178
}
175
179
if flags != 0 {
176
- let einval = this. eval_libc ( "EINVAL" ) ;
177
- this. set_last_error ( einval) ?;
178
- return Ok ( Scalar :: from_i32 ( -1 ) ) ;
180
+ throw_unsup_format ! ( "eventfd: encountered unknown unsupported flags {:#x}" , flags) ;
179
181
}
180
182
181
183
let fd = this. machine . fds . insert_fd ( FileDescriptor :: new ( Event {
0 commit comments