22use std:: cell:: { Cell , RefCell } ;
33use std:: io;
44use std:: io:: { Error , ErrorKind } ;
5- use std:: mem;
65
76use crate :: shims:: unix:: fd:: FileDescriptionRef ;
87use crate :: shims:: unix:: linux:: epoll:: { EpollReadyEvents , EvalContextExt as _} ;
98use crate :: shims:: unix:: * ;
109use crate :: { concurrency:: VClock , * } ;
1110
12- // We'll only do reads and writes in chunks of size u64.
13- const U64_ARRAY_SIZE : usize = mem:: size_of :: < u64 > ( ) ;
14-
1511/// Maximum value that the eventfd counter can hold.
1612const MAX_COUNTER : u64 = u64:: MAX - 1 ;
1713
@@ -65,35 +61,45 @@ impl FileDescription for Event {
6561 dest : & MPlaceTy < ' tcx > ,
6662 ecx : & mut MiriInterpCx < ' tcx > ,
6763 ) -> InterpResult < ' tcx > {
68- // eventfd read at the size of u64.
69- let buf_place = ecx. ptr_to_mplace_unaligned ( ptr , ecx . machine . layouts . u64 ) ;
64+ // We're treating the buffer as a ` u64` .
65+ let ty = ecx. machine . layouts . u64 ;
7066 // Check the size of slice, and return error only if the size of the slice < 8.
71- if len < U64_ARRAY_SIZE {
72- let result = Err ( Error :: from ( ErrorKind :: InvalidInput ) ) ;
73- return return_read_bytes_and_count_ev ( & buf_place, None , result, dest, ecx) ;
67+ if len < ty. size . bytes_usize ( ) {
68+ ecx. set_last_error_from_io_error ( Error :: from ( ErrorKind :: InvalidInput ) ) ?;
69+ ecx. write_int ( -1 , dest) ?;
70+ return Ok ( ( ) ) ;
7471 }
7572
73+ // eventfd read at the size of u64.
74+ let buf_place = ecx. ptr_to_mplace_unaligned ( ptr, ty) ;
75+
7676 // Block when counter == 0.
7777 let counter = self . counter . get ( ) ;
7878 if counter == 0 {
7979 if self . is_nonblock {
80- let result = Err ( Error :: from ( ErrorKind :: WouldBlock ) ) ;
81- return return_read_bytes_and_count_ev ( & buf_place, None , result, dest, ecx) ;
82- } else {
83- //FIXME: blocking is not supported
84- throw_unsup_format ! ( "eventfd: blocking is unsupported" ) ;
80+ ecx. set_last_error_from_io_error ( Error :: from ( ErrorKind :: WouldBlock ) ) ?;
81+ ecx. write_int ( -1 , dest) ?;
82+ return Ok ( ( ) ) ;
8583 }
84+
85+ throw_unsup_format ! ( "eventfd: blocking is unsupported" ) ;
8686 } else {
8787 // Synchronize with all prior `write` calls to this FD.
8888 ecx. acquire_clock ( & self . clock . borrow ( ) ) ;
89- let result = Ok ( U64_ARRAY_SIZE ) ;
89+
90+ // Give old counter value to userspace, and set counter value to 0.
91+ ecx. write_int ( counter, & buf_place) ?;
9092 self . counter . set ( 0 ) ;
93+
9194 // When any of the event happened, we check and update the status of all supported event
9295 // types for current file description.
9396 ecx. check_and_update_readiness ( self_ref) ?;
9497
95- return_read_bytes_and_count_ev ( & buf_place, Some ( counter) , result, dest, ecx)
98+ // Tell userspace how many bytes we wrote.
99+ ecx. write_int ( buf_place. layout . size . bytes ( ) , dest) ?;
96100 }
101+
102+ Ok ( ( ) )
97103 }
98104
99105 /// A write call adds the 8-byte integer value supplied in
@@ -117,14 +123,16 @@ impl FileDescription for Event {
117123 dest : & MPlaceTy < ' tcx > ,
118124 ecx : & mut MiriInterpCx < ' tcx > ,
119125 ) -> InterpResult < ' tcx > {
126+ // We're treating the buffer as a `u64`.
127+ let ty = ecx. machine . layouts . u64 ;
120128 // Check the size of slice, and return error only if the size of the slice < 8.
121- if len < U64_ARRAY_SIZE {
129+ if len < ty . layout . size . bytes_usize ( ) {
122130 let result = Err ( Error :: from ( ErrorKind :: InvalidInput ) ) ;
123131 return ecx. return_written_byte_count_or_error ( result, dest) ;
124132 }
125133
126134 // Read the user supplied value from the pointer.
127- let buf_place = ecx. ptr_to_mplace_unaligned ( ptr, ecx . machine . layouts . u64 ) ;
135+ let buf_place = ecx. ptr_to_mplace_unaligned ( ptr, ty ) ;
128136 let num = ecx. read_scalar ( & buf_place) ?. to_u64 ( ) ?;
129137
130138 // u64::MAX as input is invalid because the maximum value of counter is u64::MAX - 1.
@@ -142,22 +150,20 @@ impl FileDescription for Event {
142150 }
143151 self . counter . set ( new_count) ;
144152 }
145- None | Some ( u64:: MAX ) => {
153+ None | Some ( u64:: MAX ) =>
146154 if self . is_nonblock {
147155 let result = Err ( Error :: from ( ErrorKind :: WouldBlock ) ) ;
148156 return ecx. return_written_byte_count_or_error ( result, dest) ;
149157 } else {
150- //FIXME: blocking is not supported
151158 throw_unsup_format ! ( "eventfd: blocking is unsupported" ) ;
152- }
153- }
159+ } ,
154160 } ;
155161 // When any of the event happened, we check and update the status of all supported event
156162 // types for current file description.
157163 ecx. check_and_update_readiness ( self_ref) ?;
158164
159- let result = Ok ( U64_ARRAY_SIZE ) ;
160- ecx. return_written_byte_count_or_error ( result , dest)
165+ // Return how many bytes we read.
166+ ecx. write_int ( buf_place . layout . size . bytes ( ) , dest)
161167 }
162168}
163169
@@ -222,28 +228,3 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
222228 Ok ( Scalar :: from_i32 ( fd_value) )
223229 }
224230}
225-
226- /// This function either writes to the user supplied buffer and to dest place, or sets the
227- /// last libc error and writes -1 to dest. This is only used by eventfd.
228- fn return_read_bytes_and_count_ev < ' tcx > (
229- buf_place : & MPlaceTy < ' tcx > ,
230- read_val : Option < u64 > ,
231- result : io:: Result < usize > ,
232- dest : & MPlaceTy < ' tcx > ,
233- ecx : & mut MiriInterpCx < ' tcx > ,
234- ) -> InterpResult < ' tcx > {
235- match result. map ( |c| i64:: try_from ( c) . unwrap ( ) ) {
236- Ok ( read_bytes) => {
237- // Write to the user supplied buffer.
238- ecx. write_int ( read_val. unwrap ( ) , buf_place) ?;
239- // Write to the function return value place.
240- ecx. write_int ( read_bytes, dest) ?;
241- return Ok ( ( ) ) ;
242- }
243- Err ( e) => {
244- ecx. set_last_error_from_io_error ( e) ?;
245- ecx. write_int ( -1 , dest) ?;
246- return Ok ( ( ) ) ;
247- }
248- }
249- }
0 commit comments