11//! Linux `eventfd` implementation. 
22use  std:: io; 
33use  std:: io:: { Error ,  ErrorKind } ; 
4+ use  std:: mem; 
45
56use  rustc_target:: abi:: Endian ; 
67
@@ -9,8 +10,8 @@ use crate::{concurrency::VClock, *};
910
1011use  self :: shims:: unix:: fd:: FileDescriptor ; 
1112
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 > ( ) ; 
1415
1516/// Maximum value that the eventfd counter can hold. 
1617const  MAX_COUNTER :  u64  = u64:: MAX  - 1 ; 
@@ -51,7 +52,7 @@ impl FileDescription for Event {
5152        ecx :  & mut  MiriInterpCx < ' tcx > , 
5253    )  -> InterpResult < ' tcx ,  io:: Result < usize > >  { 
5354        // 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  { 
5556            return  Ok ( Err ( Error :: from ( ErrorKind :: InvalidInput ) ) ) ; 
5657        } ; 
5758        // Block when counter == 0. 
@@ -63,15 +64,15 @@ impl FileDescription for Event {
6364                throw_unsup_format ! ( "eventfd: blocking is unsupported" ) ; 
6465            } 
6566        }  else  { 
66-             // Prevent false alarm in data race detection when doing synchronisation via eventfd . 
67+             // Synchronize with all prior `write` calls to this FD . 
6768            ecx. acquire_clock ( & self . clock ) ; 
6869            // Return the counter in the host endianness using the buffer provided by caller. 
6970            * bytes = match  ecx. tcx . sess . target . endian  { 
7071                Endian :: Little  => self . counter . to_le_bytes ( ) , 
7172                Endian :: Big  => self . counter . to_be_bytes ( ) , 
7273            } ; 
7374            self . counter  = 0 ; 
74-             return  Ok ( Ok ( U64_MIN_ARRAY_SIZE ) ) ; 
75+             return  Ok ( Ok ( U64_ARRAY_SIZE ) ) ; 
7576        } 
7677    } 
7778
@@ -94,7 +95,7 @@ impl FileDescription for Event {
9495        ecx :  & mut  MiriInterpCx < ' tcx > , 
9596    )  -> InterpResult < ' tcx ,  io:: Result < usize > >  { 
9697        // 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  { 
9899            return  Ok ( Err ( Error :: from ( ErrorKind :: InvalidInput ) ) ) ; 
99100        } ; 
100101        // Convert from bytes to int according to host endianness. 
@@ -110,8 +111,10 @@ impl FileDescription for Event {
110111        // Else, block. 
111112        match  self . counter . checked_add ( num)  { 
112113            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+                 } 
115118                self . counter  = new_count; 
116119            } 
117120            None  | Some ( u64:: MAX )  => { 
@@ -123,7 +126,7 @@ impl FileDescription for Event {
123126                } 
124127            } 
125128        } ; 
126-         Ok ( Ok ( U64_MIN_ARRAY_SIZE ) ) 
129+         Ok ( Ok ( U64_ARRAY_SIZE ) ) 
127130    } 
128131} 
129132
@@ -163,19 +166,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
163166        } 
164167
165168        let  mut  is_nonblock = false ; 
166-         // Unload  the flag that we support. 
169+         // Unset  the flag that we support. 
167170        // After unloading, flags != 0 means other flags are used. 
168171        if  flags &  efd_cloexec == efd_cloexec { 
172+             // cloexec is ignored because Miri does not support exec. 
169173            flags &= !efd_cloexec; 
170174        } 
171175        if  flags &  efd_nonblock == efd_nonblock { 
172176            flags &= !efd_nonblock; 
173177            is_nonblock = true ; 
174178        } 
175179        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) ; 
179181        } 
180182
181183        let  fd = this. machine . fds . insert_fd ( FileDescriptor :: new ( Event  { 
0 commit comments