Skip to content

Commit f8279bf

Browse files
committed
Attempt to use this.block_thread in epoll_wait
1 parent a1fc187 commit f8279bf

File tree

6 files changed

+99
-42
lines changed

6 files changed

+99
-42
lines changed

src/concurrency/thread.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ pub enum BlockReason {
172172
Futex { addr: u64 },
173173
/// Blocked on an InitOnce.
174174
InitOnce(InitOnceId),
175+
/// Blocked on epoll
176+
Epoll,
175177
}
176178

177179
/// The state of a thread.

src/machine.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -956,11 +956,11 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
956956

957957
#[inline(always)]
958958
fn find_mir_or_eval_fn(
959-
ecx: &mut MiriInterpCx<'tcx>,
959+
ecx: &'tcx mut MiriInterpCx<'tcx>,
960960
instance: ty::Instance<'tcx>,
961961
abi: Abi,
962-
args: &[FnArg<'tcx, Provenance>],
963-
dest: &MPlaceTy<'tcx>,
962+
args: &'tcx [FnArg<'tcx, Provenance>],
963+
dest: &'tcx MPlaceTy<'tcx>,
964964
ret: Option<mir::BasicBlock>,
965965
unwind: mir::UnwindAction,
966966
) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> {
@@ -983,11 +983,11 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
983983

984984
#[inline(always)]
985985
fn call_extra_fn(
986-
ecx: &mut MiriInterpCx<'tcx>,
986+
ecx: &'tcx mut MiriInterpCx<'tcx>,
987987
fn_val: DynSym,
988988
abi: Abi,
989-
args: &[FnArg<'tcx, Provenance>],
990-
dest: &MPlaceTy<'tcx>,
989+
args: &'tcx [FnArg<'tcx, Provenance>],
990+
dest: &'tcx MPlaceTy<'tcx>,
991991
ret: Option<mir::BasicBlock>,
992992
unwind: mir::UnwindAction,
993993
) -> InterpResult<'tcx> {

src/shims/foreign_items.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
4141
link_name: Symbol,
4242
abi: Abi,
4343
args: &[OpTy<'tcx>],
44-
dest: &MPlaceTy<'tcx>,
44+
dest: &'tcx MPlaceTy<'tcx>,
4545
ret: Option<mir::BasicBlock>,
4646
unwind: mir::UnwindAction,
4747
) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> {
@@ -109,7 +109,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
109109
sym: DynSym,
110110
abi: Abi,
111111
args: &[OpTy<'tcx>],
112-
dest: &MPlaceTy<'tcx>,
112+
dest: &'tcx MPlaceTy<'tcx>,
113113
ret: Option<mir::BasicBlock>,
114114
unwind: mir::UnwindAction,
115115
) -> InterpResult<'tcx> {
@@ -210,7 +210,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
210210
link_name: Symbol,
211211
abi: Abi,
212212
args: &[OpTy<'tcx>],
213-
dest: &MPlaceTy<'tcx>,
213+
dest: &'tcx MPlaceTy<'tcx>,
214214
) -> InterpResult<'tcx, EmulateItemResult> {
215215
let this = self.eval_context_mut();
216216

src/shims/unix/foreign_items.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
4646
link_name: Symbol,
4747
abi: Abi,
4848
args: &[OpTy<'tcx>],
49-
dest: &MPlaceTy<'tcx>,
49+
dest: &'tcx MPlaceTy<'tcx>,
5050
) -> InterpResult<'tcx, EmulateItemResult> {
5151
let this = self.eval_context_mut();
5252

src/shims/unix/linux/epoll.rs

Lines changed: 86 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::cell::RefCell;
22
use std::collections::BTreeMap;
33
use std::io;
44
use std::rc::{Rc, Weak};
5+
use std::time::Duration;
56

67
use crate::shims::unix::fd::FdId;
78
use crate::shims::unix::*;
@@ -378,30 +379,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
378379
events_op: &OpTy<'tcx>,
379380
maxevents: &OpTy<'tcx>,
380381
timeout: &OpTy<'tcx>,
381-
place: &MPlaceTy<'tcx>,
382+
place: &'tcx MPlaceTy<'tcx>,
382383
) -> InterpResult<'tcx> {
383384
let this = self.eval_context_mut();
384385

385-
let epfd = this.read_scalar(epfd)?.to_i32()?;
386+
let epfd_value = this.read_scalar(epfd)?.to_i32()?;
386387
let maxevents = this.read_scalar(maxevents)?.to_i32()?;
387388
let event = this.deref_pointer_as(
388389
events_op,
389390
this.libc_array_ty_layout("epoll_event", maxevents.try_into().unwrap()),
390391
)?;
391-
let timeout = this.read_scalar(timeout)?.to_i32()?;
392+
let timeout = this.read_scalar(timeout)?.to_u32()?;
392393

393-
if epfd <= 0 {
394+
if epfd_value <= 0 {
394395
let einval = this.eval_libc("EINVAL");
395396
this.set_last_error(einval)?;
396397
this.write_scalar(Scalar::from_i32(-1), place)?;
397398
return Ok(());
398399
}
399-
// FIXME: Implement blocking support
400-
if timeout != 0 {
401-
throw_unsup_format!("epoll_wait: timeout value can only be 0");
402-
}
403-
404-
let Some(epfd) = this.machine.fds.get_ref(epfd) else {
400+
let Some(epfd) = this.machine.fds.get_ref(epfd_value) else {
405401
let result_value = this.fd_not_found()?;
406402
this.write_scalar(Scalar::from_i32(result_value), place)?;
407403
return Ok(());
@@ -412,30 +408,42 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
412408
.ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?;
413409

414410
let binding = epoll_file_description.get_ready_list();
415-
let mut ready_list = binding.borrow_mut();
416-
let mut num_of_events: i32 = 0;
417-
let mut array_iter = this.project_array_fields(&event)?;
411+
let ready_list = binding.borrow_mut();
418412

419-
while let Some((epoll_key, epoll_return)) = ready_list.pop_first() {
420-
// If the file description is fully close, the entry for corresponding FdID in the
421-
// global epoll event interest table would be empty.
422-
if this.machine.epoll_interests.get_epoll_interest(epoll_key.0).is_some() {
423-
// Return notification to the caller if the file description is not fully closed.
424-
if let Some(des) = array_iter.next(this)? {
425-
this.write_int_fields_named(
426-
&[
427-
("events", epoll_return.events.into()),
428-
("u64", epoll_return.data.into()),
429-
],
430-
&des.1,
431-
)?;
432-
num_of_events = num_of_events.checked_add(1).unwrap();
433-
} else {
434-
break;
435-
}
413+
if ready_list.is_empty() {
414+
if timeout == 0 {
415+
// Non-blocking with no notification returned.
416+
this.write_scalar(Scalar::from_i32(0), place)?;
417+
return Ok(());
418+
} else {
419+
// Blocking
420+
let duration = Duration::from_secs(timeout.into());
421+
this.block_thread(
422+
BlockReason::Epoll,
423+
Some((TimeoutClock::Monotonic, TimeoutAnchor::Relative, duration)),
424+
callback!(
425+
@capture<'tcx> {
426+
epfd_value: i32,
427+
place: &'tcx MPlaceTy<'tcx>,
428+
event: MPlaceTy<'tcx>,
429+
}
430+
@unblock = |this| {
431+
this.blocking_epoll_callback(epfd_value, place, &event);
432+
Ok(())
433+
}
434+
@timeout = |this| {
435+
this.write_scalar(Scalar::from_i32(0), place)?;
436+
Ok(())
437+
}
438+
),
439+
);
436440
}
441+
} else {
442+
// Non-blocking with notification returned.
443+
this.blocking_epoll_callback(epfd_value, place, &event);
444+
return Ok(());
437445
}
438-
this.write_scalar(Scalar::from_i32(num_of_events), place)?;
446+
439447
Ok(())
440448
}
441449
/// For a specific unique file descriptor id, get its ready events and update
@@ -477,4 +485,51 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
477485
}
478486
Ok(())
479487
}
488+
489+
/// Callback function after epoll_wait unblocks
490+
fn blocking_epoll_callback(
491+
&mut self,
492+
epfd: i32,
493+
place: &MPlaceTy<'tcx>,
494+
event: &MPlaceTy<'tcx>,
495+
) -> InterpResult<'tcx> {
496+
let this = self.eval_context_mut();
497+
498+
let Some(epfd) = this.machine.fds.get_ref(epfd) else {
499+
let result_value = this.fd_not_found()?;
500+
this.write_scalar(Scalar::from_i32(result_value), place)?;
501+
return Ok(());
502+
};
503+
let mut binding = epfd.borrow_mut();
504+
let epoll_file_description = &mut binding
505+
.downcast_mut::<Epoll>()
506+
.ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?;
507+
508+
let binding = epoll_file_description.get_ready_list();
509+
let mut ready_list = binding.borrow_mut();
510+
let mut num_of_events: i32 = 0;
511+
let mut array_iter = this.project_array_fields(event)?;
512+
513+
while let Some((epoll_key, epoll_return)) = ready_list.pop_first() {
514+
// If the file description is fully close, the entry for corresponding FdID in the
515+
// global epoll event interest table would be empty.
516+
if this.machine.epoll_interests.get_epoll_interest(epoll_key.0).is_some() {
517+
// Return notification to the caller if the file description is not fully closed.
518+
if let Some(des) = array_iter.next(this)? {
519+
this.write_int_fields_named(
520+
&[
521+
("events", epoll_return.events.into()),
522+
("u64", epoll_return.data.into()),
523+
],
524+
&des.1,
525+
)?;
526+
num_of_events = num_of_events.checked_add(1).unwrap();
527+
} else {
528+
break;
529+
}
530+
}
531+
}
532+
this.write_scalar(Scalar::from_i32(num_of_events), place)?;
533+
Ok(())
534+
}
480535
}

src/shims/unix/linux/foreign_items.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
2121
link_name: Symbol,
2222
abi: Abi,
2323
args: &[OpTy<'tcx>],
24-
dest: &MPlaceTy<'tcx>,
24+
dest: &'tcx MPlaceTy<'tcx>,
2525
) -> InterpResult<'tcx, EmulateItemResult> {
2626
let this = self.eval_context_mut();
2727

0 commit comments

Comments
 (0)