Skip to content

Commit d7741a9

Browse files
committed
simplify eventfd handling a bit
1 parent c6607e2 commit d7741a9

File tree

1 file changed

+30
-49
lines changed

1 file changed

+30
-49
lines changed

src/shims/unix/linux/eventfd.rs

+30-49
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,12 @@
22
use std::cell::{Cell, RefCell};
33
use std::io;
44
use std::io::{Error, ErrorKind};
5-
use std::mem;
65

76
use crate::shims::unix::fd::FileDescriptionRef;
87
use crate::shims::unix::linux::epoll::{EpollReadyEvents, EvalContextExt as _};
98
use crate::shims::unix::*;
109
use 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.
1612
const 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

Comments
 (0)