Skip to content

Commit 4721437

Browse files
committed
eventloop: add task method to run with lifecycle callbacks
1 parent c2c293e commit 4721437

File tree

1 file changed

+110
-14
lines changed

1 file changed

+110
-14
lines changed

src/core/eventloop.rs

Lines changed: 110 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,20 @@ impl<C: Callback> EventLoop<C> {
280280
}
281281
}
282282

283+
/// Constructs an event loop and executes it asynchronously. `setup` is
284+
/// called just prior to executing, and `done` is called when the event
285+
/// loop exits.
286+
pub async fn task<S, D>(registrations_max: usize, setup: S, done: D)
287+
where
288+
S: FnOnce(&Rc<Self>) + 'static,
289+
D: FnOnce(i32) + 'static,
290+
{
291+
let l = Rc::new(Self::new(registrations_max));
292+
setup(&l);
293+
let code = l.exec_async().await;
294+
done(code);
295+
}
296+
283297
pub fn step(&self) -> Option<i32> {
284298
self.poll_and_dispatch(Some(Duration::from_millis(0)))
285299
}
@@ -503,10 +517,10 @@ mod ffi {
503517
#[allow(clippy::missing_safety_doc)]
504518
#[no_mangle]
505519
pub unsafe extern "C" fn event_loop_step(
506-
l: *mut EventLoopRaw,
520+
l: *const EventLoopRaw,
507521
out_code: *mut libc::c_int,
508522
) -> libc::c_int {
509-
let l = l.as_mut().unwrap();
523+
let l = l.as_ref().unwrap();
510524

511525
match l.step() {
512526
Some(code) => {
@@ -520,31 +534,31 @@ mod ffi {
520534

521535
#[allow(clippy::missing_safety_doc)]
522536
#[no_mangle]
523-
pub unsafe extern "C" fn event_loop_exec(l: *mut EventLoopRaw) -> libc::c_int {
524-
let l = l.as_mut().unwrap();
537+
pub unsafe extern "C" fn event_loop_exec(l: *const EventLoopRaw) -> libc::c_int {
538+
let l = l.as_ref().unwrap();
525539

526540
l.exec() as libc::c_int
527541
}
528542

529543
#[allow(clippy::missing_safety_doc)]
530544
#[no_mangle]
531-
pub unsafe extern "C" fn event_loop_exit(l: *mut EventLoopRaw, code: libc::c_int) {
532-
let l = l.as_mut().unwrap();
545+
pub unsafe extern "C" fn event_loop_exit(l: *const EventLoopRaw, code: libc::c_int) {
546+
let l = l.as_ref().unwrap();
533547

534548
l.exit(code);
535549
}
536550

537551
#[allow(clippy::missing_safety_doc)]
538552
#[no_mangle]
539553
pub unsafe extern "C" fn event_loop_register_fd(
540-
l: *mut EventLoopRaw,
554+
l: *const EventLoopRaw,
541555
fd: std::os::raw::c_int,
542556
interest: u8,
543557
cb: unsafe extern "C" fn(*mut libc::c_void, u8),
544558
ctx: *mut libc::c_void,
545559
out_id: *mut libc::size_t,
546560
) -> libc::c_int {
547-
let l = l.as_mut().unwrap();
561+
let l = l.as_ref().unwrap();
548562

549563
let Ok(interest) = interest_int_to_mio(interest) else {
550564
return -1;
@@ -567,13 +581,13 @@ mod ffi {
567581
#[allow(clippy::missing_safety_doc)]
568582
#[no_mangle]
569583
pub unsafe extern "C" fn event_loop_register_timer(
570-
l: *mut EventLoopRaw,
584+
l: *const EventLoopRaw,
571585
timeout: u64,
572586
cb: unsafe extern "C" fn(*mut libc::c_void, u8),
573587
ctx: *mut libc::c_void,
574588
out_id: *mut libc::size_t,
575589
) -> libc::c_int {
576-
let l = l.as_mut().unwrap();
590+
let l = l.as_ref().unwrap();
577591

578592
// SAFETY: we assume caller guarantees that the callback is safe to
579593
// call for the lifetime of the registration
@@ -592,13 +606,13 @@ mod ffi {
592606
#[allow(clippy::missing_safety_doc)]
593607
#[no_mangle]
594608
pub unsafe extern "C" fn event_loop_register_custom(
595-
l: *mut EventLoopRaw,
609+
l: *const EventLoopRaw,
596610
cb: unsafe extern "C" fn(*mut libc::c_void, u8),
597611
ctx: *mut libc::c_void,
598612
out_id: *mut libc::size_t,
599613
out_set_readiness: *mut *mut event::ffi::SetReadiness,
600614
) -> libc::c_int {
601-
let l = l.as_mut().unwrap();
615+
let l = l.as_ref().unwrap();
602616

603617
// SAFETY: we assume caller guarantees that the callback is safe to
604618
// call for the lifetime of the registration
@@ -618,10 +632,10 @@ mod ffi {
618632
#[allow(clippy::missing_safety_doc)]
619633
#[no_mangle]
620634
pub unsafe extern "C" fn event_loop_deregister(
621-
l: *mut EventLoopRaw,
635+
l: *const EventLoopRaw,
622636
id: libc::size_t,
623637
) -> libc::c_int {
624-
let l = l.as_mut().unwrap();
638+
let l = l.as_ref().unwrap();
625639

626640
if l.deregister(id).is_err() {
627641
return -1;
@@ -861,4 +875,86 @@ mod tests {
861875

862876
executor.run(|timeout| reactor.poll(timeout)).unwrap();
863877
}
878+
879+
#[test]
880+
fn task() {
881+
let reactor = Reactor::new(1);
882+
let executor = Executor::new(1);
883+
884+
struct State {
885+
listener: Option<std::net::TcpListener>,
886+
listener_reg_id: Option<usize>,
887+
stream: Option<mio::net::TcpStream>,
888+
code: Option<i32>,
889+
}
890+
891+
let state = Rc::new(RefCell::new(State {
892+
listener: None,
893+
listener_reg_id: None,
894+
stream: None,
895+
code: None,
896+
}));
897+
898+
let setup_fn = {
899+
let state = Rc::clone(&state);
900+
901+
Box::new(move |l: &Rc<EventLoop<Box<dyn Callback>>>| {
902+
let cb = {
903+
let l = Rc::clone(&l);
904+
let state = Rc::clone(&state);
905+
906+
Box::new(FnCallback(move |readiness: event::Readiness| {
907+
assert!(readiness.contains_any(mio::Interest::READABLE));
908+
909+
let mut state = state.borrow_mut();
910+
let listener = state.listener.as_ref().unwrap();
911+
let id = state.listener_reg_id.unwrap();
912+
913+
let _stream = listener.accept().unwrap();
914+
l.deregister(id).unwrap();
915+
916+
state.listener = None;
917+
state.listener_reg_id = None;
918+
919+
l.exit(0);
920+
}))
921+
};
922+
923+
let mut state = state.borrow_mut();
924+
925+
let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
926+
listener.set_nonblocking(true).unwrap();
927+
928+
let addr = listener.local_addr().unwrap();
929+
let fd = listener.as_raw_fd();
930+
931+
let id = l.register_fd(fd, mio::Interest::READABLE, cb).unwrap();
932+
933+
// non-blocking connect attempt to trigger listener
934+
let stream = mio::net::TcpStream::connect(addr).unwrap();
935+
936+
state.listener = Some(listener);
937+
state.listener_reg_id = Some(id);
938+
state.stream = Some(stream);
939+
})
940+
};
941+
942+
let done_fn = {
943+
let state = Rc::clone(&state);
944+
945+
Box::new(move |code| {
946+
state.borrow_mut().code = Some(code);
947+
})
948+
};
949+
950+
executor
951+
.spawn(async {
952+
EventLoop::<Box<dyn Callback>>::task(1, setup_fn, done_fn).await;
953+
})
954+
.unwrap();
955+
956+
executor.run(|timeout| reactor.poll(timeout)).unwrap();
957+
958+
assert_eq!(state.borrow().code, Some(0));
959+
}
864960
}

0 commit comments

Comments
 (0)