1use slotmap::{new_key_type, SlotMap};
9use std::cmp::Reverse;
10use std::collections::{BinaryHeap, HashMap};
11use std::io;
12use std::os::unix::io::RawFd;
13use thiserror::Error;
14
15pub const E_READ: u32 = 0x1;
21
22pub const E_WRITE: u32 = 0x2;
24
25pub const EPSILON: f64 = 1.0e-3;
27
28pub const FANOUT_UNLIMITED: i32 = -1;
30
31#[derive(Error, Debug)]
37pub enum EngineError {
38 #[error("Operation aborted (kill={kill})")]
40 Abort { kill: bool },
41
42 #[error("Operation timed out")]
44 Timeout,
45
46 #[error("Illegal operation: {0}")]
48 IllegalOperation(String),
49
50 #[error("Engine is already running")]
52 AlreadyRunning,
53
54 #[error("Not supported: {0}")]
56 NotSupported(String),
57
58 #[error("I/O error: {0}")]
60 Io(#[from] io::Error),
61}
62
63new_key_type! { pub struct TimerId; }
68
69#[derive(Debug, Clone)]
78pub struct EngineBaseTimer {
79 fire_delay: f64,
80 interval: f64,
81 autoclose: bool,
82}
83
84impl EngineBaseTimer {
85 pub fn new(fire_delay: f64, interval: f64, autoclose: bool) -> Self {
92 Self {
93 fire_delay,
94 interval,
95 autoclose,
96 }
97 }
98
99 pub fn invalidate(&mut self) {
101 self.fire_delay = -1.0;
102 }
103
104 pub fn is_valid(&self) -> bool {
106 self.fire_delay >= 0.0
107 }
108
109 pub fn set_nextfire(&mut self, fire_delay: f64, interval: f64) {
115 self.fire_delay = fire_delay;
116 self.interval = interval;
117 }
118
119 pub fn fire_delay(&self) -> f64 {
121 self.fire_delay
122 }
123
124 pub fn interval(&self) -> f64 {
126 self.interval
127 }
128
129 pub fn autoclose(&self) -> bool {
131 self.autoclose
132 }
133}
134
135#[derive(Debug, Clone, PartialEq)]
141struct TimerEntry {
142 fire_date: f64,
143 timer_id: TimerId,
144 armed: bool,
145}
146
147impl Eq for TimerEntry {}
148
149impl Ord for TimerEntry {
150 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
151 self.fire_date
153 .partial_cmp(&other.fire_date)
154 .unwrap_or(std::cmp::Ordering::Equal)
155 .then_with(|| self.timer_id.cmp(&other.timer_id))
156 }
157}
158
159impl PartialOrd for TimerEntry {
160 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
161 Some(self.cmp(other))
162 }
163}
164
165#[derive(Debug)]
170pub struct TimerQueue {
171 timers: BinaryHeap<Reverse<TimerEntry>>,
172 timer_data: SlotMap<TimerId, EngineBaseTimer>,
173 armed_count: usize,
174 current_time: f64,
175}
176
177impl TimerQueue {
178 pub fn new() -> Self {
180 Self {
181 timers: BinaryHeap::new(),
182 timer_data: SlotMap::with_capacity_and_key(16),
183 armed_count: 0,
184 current_time: 0.0,
185 }
186 }
187
188 pub fn schedule(&mut self, timer_id: TimerId) {
193 if let Some(timer) = self.timer_data.get(timer_id) {
194 if timer.fire_delay >= 0.0 {
195 let fire_date = self.current_time + timer.fire_delay;
196 let entry = TimerEntry {
197 fire_date,
198 timer_id,
199 armed: true,
200 };
201 self.timers.push(Reverse(entry));
202 self.armed_count += 1;
203 }
204 }
205 }
206
207 pub fn reschedule(&mut self, timer_id: TimerId) {
212 self.invalidate(timer_id);
214 self.schedule(timer_id);
215 }
216
217 pub fn invalidate(&mut self, timer_id: TimerId) {
222 let mut found = false;
224 let mut new_heap = BinaryHeap::new();
225 for Reverse(entry) in self.timers.drain() {
226 if entry.timer_id == timer_id {
227 found = true;
228 if let Some(timer) = self.timer_data.get_mut(timer_id) {
230 timer.invalidate();
231 }
232 } else {
233 new_heap.push(Reverse(entry));
234 }
235 }
236 self.timers = new_heap;
237 if found {
238 self.armed_count = self.armed_count.saturating_sub(1);
239 }
240 }
241
242 pub fn fire_expired(&mut self) -> Vec<(TimerId, bool)> {
246 let mut fired = Vec::new();
247 let now = self.current_time;
248
249 while let Some(Reverse(entry)) = self.timers.peek() {
251 if entry.fire_date > now + EPSILON {
252 break;
253 }
254
255 let entry = self.timers.pop().unwrap().0;
256 let timer_id = entry.timer_id;
257
258 if let Some(timer) = self.timer_data.get(timer_id) {
259 if entry.armed && timer.fire_delay >= 0.0 {
260 fired.push((timer_id, timer.autoclose));
261
262 if timer.interval >= 0.0 {
264 let new_fire_date = now + timer.interval;
265 let new_entry = TimerEntry {
266 fire_date: new_fire_date,
267 timer_id,
268 armed: true,
269 };
270 self.timers.push(Reverse(new_entry));
271 } else {
272 if let Some(t) = self.timer_data.get_mut(timer_id) {
274 t.invalidate();
275 }
276 self.armed_count = self.armed_count.saturating_sub(1);
277 }
278 }
279 }
280 }
281
282 fired
283 }
284
285 pub fn nextfire_delay(&self) -> Option<f64> {
289 if let Some(Reverse(entry)) = self.timers.peek() {
290 let delay = entry.fire_date - self.current_time;
291 if delay > EPSILON {
292 Some(delay)
293 } else {
294 Some(0.0)
295 }
296 } else {
297 None
298 }
299 }
300
301 pub fn clear(&mut self) {
303 self.timers.clear();
304 self.timer_data.clear();
305 self.armed_count = 0;
306 }
307
308 pub fn add_timer(&mut self, timer: EngineBaseTimer) -> TimerId {
312 self.timer_data.insert(timer)
313 }
314
315 pub fn remove_timer(&mut self, timer_id: TimerId) {
317 self.invalidate(timer_id);
318 self.timer_data.remove(timer_id);
319 }
320
321 pub fn armed_count(&self) -> usize {
323 self.armed_count
324 }
325
326 pub fn update_time(&mut self, time: f64) {
328 self.current_time = time;
329 }
330
331 pub fn is_valid(&self, timer_id: TimerId) -> bool {
333 self.timer_data
334 .get(timer_id)
335 .map(|t| t.is_valid())
336 .unwrap_or(false)
337 }
338}
339
340impl Default for TimerQueue {
341 fn default() -> Self {
342 Self::new()
343 }
344}
345
346pub struct EngineTimer {
355 base: EngineBaseTimer,
356 handler: Box<dyn FnMut() + Send>,
357}
358
359impl EngineTimer {
360 pub fn new(
368 fire_delay: f64,
369 interval: f64,
370 autoclose: bool,
371 handler: impl FnMut() + Send + 'static,
372 ) -> Self {
373 Self {
374 base: EngineBaseTimer::new(fire_delay, interval, autoclose),
375 handler: Box::new(handler),
376 }
377 }
378
379 pub fn fire(&mut self) {
381 (self.handler)();
382 }
383
384 pub fn base(&self) -> &EngineBaseTimer {
386 &self.base
387 }
388
389 pub fn base_mut(&mut self) -> &mut EngineBaseTimer {
391 &mut self.base
392 }
393}
394
395impl std::fmt::Debug for EngineTimer {
396 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
397 f.debug_struct("EngineTimer")
398 .field("base", &self.base)
399 .field("handler", &"<fn>")
400 .finish()
401 }
402}
403
404pub trait EngineClient: Send {
413 fn start(&mut self) -> io::Result<()>;
415
416 fn close(&mut self, abort: bool, timeout: bool);
422
423 fn fd(&self) -> Option<RawFd>;
425
426 fn events(&self) -> u32;
428
429 fn is_delayable(&self) -> bool;
431
432 fn is_registered(&self) -> bool;
434
435 fn set_registered(&mut self, val: bool);
437
438 fn autoclose(&self) -> bool;
440
441 fn handle_read(&mut self) -> io::Result<usize> {
444 Ok(0)
445 }
446
447 fn handle_write(&mut self) -> io::Result<usize> {
450 Ok(0)
451 }
452}
453
454new_key_type! { pub struct ClientId; }
459
460pub trait PollBackend: Send + Sync {
469 fn register(&mut self, fd: RawFd, events: u32, client_id: ClientId) -> io::Result<()>;
476
477 fn modify(&mut self, fd: RawFd, events: u32, client_id: ClientId) -> io::Result<()>;
479
480 fn unregister(&mut self, fd: RawFd) -> io::Result<()>;
482
483 fn wait(&mut self, timeout: Option<f64>) -> io::Result<Vec<(RawFd, u32, ClientId)>>;
487
488 fn name(&self) -> &str;
490}
491
492pub struct Engine<B: PollBackend> {
513 clients: SlotMap<ClientId, Box<dyn EngineClient>>,
514 timerq: TimerQueue,
515 reg_clifds: HashMap<RawFd, ClientId>,
516 poll_backend: B,
517 fanout: usize,
518 running: bool,
519 exited: bool,
520 evlooprefcnt: i32,
521}
522
523impl<B: PollBackend> Engine<B> {
524 pub fn with_backend(backend: B, fanout: usize) -> Self {
530 Self {
531 clients: SlotMap::with_key(),
532 timerq: TimerQueue::new(),
533 reg_clifds: HashMap::new(),
534 poll_backend: backend,
535 fanout,
536 running: false,
537 exited: false,
538 evlooprefcnt: 0,
539 }
540 }
541
542 pub fn add_timer(&mut self, timer: EngineBaseTimer) -> TimerId {
547 let timer_id = self.timerq.add_timer(timer);
548 self.timerq.schedule(timer_id);
549 timer_id
550 }
551
552 pub fn remove_timer(&mut self, id: TimerId) {
557 self.timerq.remove_timer(id);
558 }
559
560 pub fn fire_timers(&mut self) {
562 let _fired = self.timerq.fire_expired();
563 }
567
568 pub fn run(&mut self, timeout: Option<f64>) -> Result<(), EngineError> {
578 if self.running {
579 return Err(EngineError::AlreadyRunning);
580 }
581
582 self.running = true;
583 self.exited = false;
584
585 let start_time = self.timerq.current_time;
586 let max_time = timeout.map(|t| start_time + t);
587
588 while self.running {
589 self.timerq.update_time(self.timerq.current_time + 0.001);
591
592 self.fire_timers();
594
595 if !self.running {
597 break;
598 }
599
600 let next_timer_delay = self.timerq.nextfire_delay();
602
603 let poll_timeout = match (max_time, next_timer_delay) {
605 (Some(max), Some(timer_delay)) => {
606 let remaining = max - self.timerq.current_time;
607 if remaining <= EPSILON {
608 self.running = false;
609 self.exited = true;
610 return Err(EngineError::Timeout);
611 }
612 Some(if remaining < timer_delay {
614 remaining
615 } else {
616 timer_delay
617 })
618 }
619 (Some(max), None) => {
620 let remaining = max - self.timerq.current_time;
621 if remaining <= EPSILON {
622 self.running = false;
623 self.exited = true;
624 return Err(EngineError::Timeout);
625 }
626 Some(remaining)
627 }
628 (None, Some(timer_delay)) => Some(timer_delay),
629 (None, None) => None,
630 };
631
632 let events = match self.poll_backend.wait(poll_timeout.map(|t| t.max(0.0))) {
634 Ok(events) => events,
635 Err(err) if err.kind() == io::ErrorKind::Interrupted => {
636 continue;
639 }
640 Err(err) => {
641 self.running = false;
645 self.exited = true;
646 return Err(EngineError::Io(err));
647 }
648 };
649
650 for (_fd, events_mask, client_id) in events {
652 if let Some(client) = self.clients.get_mut(client_id) {
653 if events_mask & E_READ != 0 {
654 let _ = client.handle_read();
655 }
656 if events_mask & E_WRITE != 0 {
657 let _ = client.handle_write();
658 }
659 }
660 }
661
662 if let Some(max) = max_time {
664 if self.timerq.current_time >= max {
665 self.running = false;
666 self.exited = true;
667 return Err(EngineError::Timeout);
668 }
669 }
670 }
671
672 self.exited = true;
673 self.running = false;
674 Ok(())
675 }
676
677 pub fn abort(&mut self, kill: bool) {
682 if kill {
683 for (_, client) in self.clients.iter_mut() {
685 client.close(true, false);
686 }
687 }
688 self.running = false;
689 }
690
691 pub fn is_running(&self) -> bool {
693 self.running
694 }
695
696 pub fn exited(&self) -> bool {
698 self.exited
699 }
700
701 pub fn add_client(&mut self, client: Box<dyn EngineClient>) -> Result<ClientId, EngineError> {
706 let client_id = self.clients.insert(client);
707
708 if let Some(client) = self.clients.get(client_id) {
709 if let Some(fd) = client.fd() {
710 if fd >= 0 {
711 let events = client.events();
712 self.poll_backend.register(fd, events, client_id)?;
713 self.reg_clifds.insert(fd, client_id);
714 }
715 }
716 }
717
718 Ok(client_id)
719 }
720
721 pub fn remove_client(&mut self, id: ClientId) {
726 if let Some(client) = self.clients.get(id) {
727 if let Some(fd) = client.fd() {
728 if fd >= 0 {
729 let _ = self.poll_backend.unregister(fd);
730 self.reg_clifds.remove(&fd);
731 }
732 }
733 }
734 self.clients.remove(id);
735 }
736
737 pub fn fanout(&self) -> usize {
739 self.fanout
740 }
741
742 pub fn update_client_events(&mut self, client_id: ClientId) -> Result<(), EngineError> {
744 if let Some(client) = self.clients.get(client_id) {
745 if let Some(fd) = client.fd() {
746 if fd >= 0 {
747 let events = client.events();
748 if self.reg_clifds.contains_key(&fd) {
749 self.poll_backend.modify(fd, events, client_id)?;
750 } else {
751 self.poll_backend.register(fd, events, client_id)?;
752 self.reg_clifds.insert(fd, client_id);
753 }
754 }
755 }
756 }
757 Ok(())
758 }
759
760 pub fn stop(&mut self) {
762 self.running = false;
763 }
764
765 pub fn evloop_acquire(&mut self) {
768 self.evlooprefcnt += 1;
769 }
770
771 pub fn evloop_release(&mut self) {
774 self.evlooprefcnt -= 1;
775 if self.evlooprefcnt <= 0 {
776 self.running = false;
777 }
778 }
779
780 pub fn client_count(&self) -> usize {
782 self.clients.len()
783 }
784
785 pub fn timerq(&self) -> &TimerQueue {
787 &self.timerq
788 }
789
790 pub fn timerq_mut(&mut self) -> &mut TimerQueue {
792 &mut self.timerq
793 }
794
795 pub fn start_all_clients(&mut self) -> io::Result<()> {
797 let ids: Vec<ClientId> = self.clients.keys().collect();
798 for id in ids {
799 if let Some(client) = self.clients.get_mut(id) {
800 client.start()?;
801 }
802 }
803 Ok(())
804 }
805}
806
807#[derive(Debug, Default)]
815pub struct NullBackend;
816
817impl PollBackend for NullBackend {
818 fn register(&mut self, _fd: RawFd, _events: u32, _client_id: ClientId) -> io::Result<()> {
819 Ok(())
820 }
821
822 fn modify(&mut self, _fd: RawFd, _events: u32, _client_id: ClientId) -> io::Result<()> {
823 Ok(())
824 }
825
826 fn unregister(&mut self, _fd: RawFd) -> io::Result<()> {
827 Ok(())
828 }
829
830 fn wait(&mut self, _timeout: Option<f64>) -> io::Result<Vec<(RawFd, u32, ClientId)>> {
831 Ok(Vec::new())
832 }
833
834 fn name(&self) -> &str {
835 "null"
836 }
837}
838
839#[cfg(test)]
844mod tests {
845 use super::*;
846
847 #[test]
848 fn test_engine_constants() {
849 assert_eq!(E_READ, 0x1);
850 assert_eq!(E_WRITE, 0x2);
851 assert!((EPSILON - 1.0e-3).abs() < EPSILON);
852 assert_eq!(FANOUT_UNLIMITED, -1);
853 }
854
855 #[test]
856 fn test_engine_base_timer() {
857 let mut timer = EngineBaseTimer::new(5.0, -1.0, false);
858 assert!(timer.is_valid());
859 assert_eq!(timer.fire_delay(), 5.0);
860 assert_eq!(timer.interval(), -1.0);
861
862 timer.invalidate();
863 assert!(!timer.is_valid());
864 assert_eq!(timer.fire_delay(), -1.0);
865
866 timer.set_nextfire(10.0, 2.0);
867 assert!(timer.is_valid());
868 assert_eq!(timer.fire_delay(), 10.0);
869 assert_eq!(timer.interval(), 2.0);
870 }
871
872 #[test]
873 fn test_timer_queue_scheduling() {
874 let mut timerq = TimerQueue::new();
875
876 let timer1 = timerq.add_timer(EngineBaseTimer::new(1.0, -1.0, false));
878 let timer2 = timerq.add_timer(EngineBaseTimer::new(2.0, -1.0, false));
879 let timer3 = timerq.add_timer(EngineBaseTimer::new(0.5, -1.0, false));
880
881 timerq.schedule(timer1);
883 timerq.schedule(timer2);
884 timerq.schedule(timer3);
885
886 assert_eq!(timerq.armed_count(), 3);
888
889 let delay = timerq.nextfire_delay();
891 assert!(delay.is_some());
892 assert!((delay.unwrap() - 0.5).abs() < EPSILON);
893 }
894
895 #[test]
896 fn test_timer_queue_firing() {
897 let mut timerq = TimerQueue::new();
898
899 let timer1 = timerq.add_timer(EngineBaseTimer::new(0.1, -1.0, false));
901 let timer2 = timerq.add_timer(EngineBaseTimer::new(0.2, -1.0, false));
902
903 timerq.schedule(timer1);
904 timerq.schedule(timer2);
905
906 timerq.update_time(0.3);
908
909 let fired = timerq.fire_expired();
911
912 assert_eq!(fired.len(), 2);
914
915 assert!(!timerq.is_valid(timer1));
917 assert!(!timerq.is_valid(timer2));
918 }
919
920 #[test]
921 fn test_timer_queue_invalidation() {
922 let mut timerq = TimerQueue::new();
923
924 let timer1 = timerq.add_timer(EngineBaseTimer::new(1.0, -1.0, false));
925 let timer2 = timerq.add_timer(EngineBaseTimer::new(2.0, -1.0, false));
926
927 timerq.schedule(timer1);
928 timerq.schedule(timer2);
929
930 timerq.invalidate(timer1);
932
933 assert_eq!(timerq.armed_count(), 1);
935
936 let delay = timerq.nextfire_delay();
938 assert!(delay.is_some());
939 assert!((delay.unwrap() - 2.0).abs() < EPSILON);
940 }
941
942 #[test]
943 fn test_timer_queue_repeat() {
944 let mut timerq = TimerQueue::new();
945
946 let timer = timerq.add_timer(EngineBaseTimer::new(0.1, 0.1, false));
948 timerq.schedule(timer);
949
950 timerq.update_time(0.15);
952 let fired = timerq.fire_expired();
953 assert_eq!(fired.len(), 1);
954
955 assert!(timerq.is_valid(timer));
957
958 timerq.update_time(0.25);
960 let fired = timerq.fire_expired();
961 assert_eq!(fired.len(), 1);
962
963 assert!(timerq.is_valid(timer));
965 }
966
967 #[test]
968 fn test_engine_error_types() {
969 let err = EngineError::Abort { kill: true };
970 assert!(matches!(err, EngineError::Abort { kill: true }));
971
972 let err = EngineError::Timeout;
973 assert!(matches!(err, EngineError::Timeout));
974
975 let err = EngineError::IllegalOperation("test".to_string());
976 assert!(matches!(err, EngineError::IllegalOperation(_)));
977
978 let err = EngineError::AlreadyRunning;
979 assert!(matches!(err, EngineError::AlreadyRunning));
980
981 let err = EngineError::NotSupported("test".to_string());
982 assert!(matches!(err, EngineError::NotSupported(_)));
983
984 let io_err = io::Error::new(io::ErrorKind::NotFound, "not found");
985 let err = EngineError::Io(io_err);
986 assert!(matches!(err, EngineError::Io(_)));
987 }
988
989 #[test]
992 fn test_null_backend_name() {
993 let nb = NullBackend;
994 assert_eq!(nb.name(), "null");
995 }
996
997 #[test]
998 fn test_null_backend_wait_returns_empty() {
999 let mut nb = NullBackend;
1000 let events = nb.wait(Some(0.0)).unwrap();
1001 assert!(events.is_empty());
1002 }
1003
1004 #[test]
1005 fn test_null_backend_register_modify_unregister() {
1006 let mut nb = NullBackend;
1007 let mut sm: SlotMap<ClientId, ()> = SlotMap::with_key();
1010 let cid = sm.insert(());
1011 nb.register(0, E_READ, cid).unwrap();
1012 nb.modify(0, E_WRITE, cid).unwrap();
1013 nb.unregister(0).unwrap();
1014 }
1015
1016 struct DummyClient {
1019 registered: bool,
1020 started: bool,
1021 }
1022
1023 impl DummyClient {
1024 fn new() -> Self {
1025 Self {
1026 registered: false,
1027 started: false,
1028 }
1029 }
1030 }
1031
1032 impl EngineClient for DummyClient {
1033 fn start(&mut self) -> io::Result<()> {
1034 self.started = true;
1035 Ok(())
1036 }
1037
1038 fn close(&mut self, _abort: bool, _timeout: bool) {}
1039
1040 fn fd(&self) -> Option<RawFd> {
1041 None }
1043
1044 fn events(&self) -> u32 {
1045 E_READ
1046 }
1047
1048 fn is_delayable(&self) -> bool {
1049 false
1050 }
1051
1052 fn is_registered(&self) -> bool {
1053 self.registered
1054 }
1055
1056 fn set_registered(&mut self, val: bool) {
1057 self.registered = val;
1058 }
1059
1060 fn autoclose(&self) -> bool {
1061 false
1062 }
1063 }
1064
1065 #[test]
1066 fn test_engine_creation() {
1067 let engine = Engine::with_backend(NullBackend, 0);
1068 assert!(!engine.is_running());
1069 assert!(!engine.exited());
1070 assert_eq!(engine.fanout(), 0);
1071 assert_eq!(engine.client_count(), 0);
1072 }
1073
1074 #[test]
1075 fn test_engine_add_remove_client() {
1076 let mut engine = Engine::with_backend(NullBackend, 0);
1077 let cid = engine.add_client(Box::new(DummyClient::new())).unwrap();
1078 assert_eq!(engine.client_count(), 1);
1079 engine.remove_client(cid);
1080 assert_eq!(engine.client_count(), 0);
1081 }
1082
1083 #[test]
1084 fn test_engine_add_timer() {
1085 let mut engine = Engine::with_backend(NullBackend, 0);
1086 let tid = engine.add_timer(EngineBaseTimer::new(1.0, -1.0, false));
1087 assert!(engine.timerq().is_valid(tid));
1088 engine.remove_timer(tid);
1089 assert!(!engine.timerq().is_valid(tid));
1090 }
1091
1092 #[test]
1093 fn test_engine_fire_timers() {
1094 let mut engine = Engine::with_backend(NullBackend, 0);
1095 let tid = engine.add_timer(EngineBaseTimer::new(0.1, -1.0, false));
1096 assert!(engine.timerq().is_valid(tid));
1097 engine.timerq_mut().update_time(1.0);
1098 engine.fire_timers();
1099 assert!(!engine.timerq().is_valid(tid));
1100 }
1101
1102 #[test]
1103 fn test_engine_abort() {
1104 let mut engine = Engine::with_backend(NullBackend, 0);
1105 engine.abort(false);
1106 assert!(!engine.is_running());
1107 }
1108
1109 #[test]
1110 fn test_engine_evloop_refcnt() {
1111 let mut engine = Engine::with_backend(NullBackend, 0);
1112 engine.evloop_acquire();
1113 engine.evloop_acquire();
1114 engine.evloop_release();
1115 engine.evloop_release();
1118 assert!(!engine.is_running());
1120 }
1121
1122 #[test]
1123 fn test_engine_stop() {
1124 let mut engine = Engine::with_backend(NullBackend, 0);
1125 engine.stop();
1127 assert!(!engine.is_running());
1128 }
1129
1130 #[test]
1131 fn test_engine_start_all_clients() {
1132 let mut engine = Engine::with_backend(NullBackend, 0);
1133 engine.add_client(Box::new(DummyClient::new())).unwrap();
1134 engine.add_client(Box::new(DummyClient::new())).unwrap();
1135 engine.start_all_clients().unwrap();
1136 assert_eq!(engine.client_count(), 2);
1137 }
1138
1139 #[test]
1140 fn test_engine_update_client_events() {
1141 let mut engine = Engine::with_backend(NullBackend, 0);
1142 let cid = engine.add_client(Box::new(DummyClient::new())).unwrap();
1143 engine.update_client_events(cid).unwrap();
1145 }
1146
1147 struct FailBackend {
1157 errno: i32,
1158 wait_calls: usize,
1159 }
1160
1161 impl FailBackend {
1162 fn new(errno: i32) -> Self {
1163 Self {
1164 errno,
1165 wait_calls: 0,
1166 }
1167 }
1168 }
1169
1170 impl PollBackend for FailBackend {
1171 fn register(&mut self, _fd: RawFd, _events: u32, _client_id: ClientId) -> io::Result<()> {
1172 Ok(())
1173 }
1174
1175 fn modify(&mut self, _fd: RawFd, _events: u32, _client_id: ClientId) -> io::Result<()> {
1176 Ok(())
1177 }
1178
1179 fn unregister(&mut self, _fd: RawFd) -> io::Result<()> {
1180 Ok(())
1181 }
1182
1183 fn wait(&mut self, _timeout: Option<f64>) -> io::Result<Vec<(RawFd, u32, ClientId)>> {
1184 self.wait_calls += 1;
1185 Err(io::Error::from_raw_os_error(self.errno))
1186 }
1187
1188 fn name(&self) -> &str {
1189 "fail"
1190 }
1191 }
1192
1193 struct IntrThenFailBackend {
1196 eintr_count: usize,
1197 final_errno: i32,
1198 wait_calls: usize,
1199 }
1200
1201 impl PollBackend for IntrThenFailBackend {
1202 fn register(&mut self, _fd: RawFd, _events: u32, _client_id: ClientId) -> io::Result<()> {
1203 Ok(())
1204 }
1205
1206 fn modify(&mut self, _fd: RawFd, _events: u32, _client_id: ClientId) -> io::Result<()> {
1207 Ok(())
1208 }
1209
1210 fn unregister(&mut self, _fd: RawFd) -> io::Result<()> {
1211 Ok(())
1212 }
1213
1214 fn wait(&mut self, _timeout: Option<f64>) -> io::Result<Vec<(RawFd, u32, ClientId)>> {
1215 self.wait_calls += 1;
1216 if self.wait_calls <= self.eintr_count {
1217 Err(io::Error::from_raw_os_error(libc::EINTR))
1218 } else {
1219 Err(io::Error::from_raw_os_error(self.final_errno))
1220 }
1221 }
1222
1223 fn name(&self) -> &str {
1224 "intr-then-fail"
1225 }
1226 }
1227
1228 #[test]
1229 fn test_engine_poll_error_propagates() {
1230 let mut engine = Engine::with_backend(FailBackend::new(libc::EBADF), 0);
1233 engine.evloop_acquire();
1234
1235 let result = engine.run(None);
1236 match result {
1237 Err(EngineError::Io(err)) => {
1238 assert_eq!(err.raw_os_error(), Some(libc::EBADF));
1239 }
1240 other => panic!("expected EngineError::Io(EBADF), got: {:?}", other),
1241 }
1242
1243 assert!(!engine.is_running());
1245 assert!(engine.exited());
1246
1247 match engine.run(None) {
1250 Err(EngineError::Io(err)) => {
1251 assert_eq!(err.raw_os_error(), Some(libc::EBADF));
1252 }
1253 other => panic!("expected EngineError::Io(EBADF), got: {:?}", other),
1254 }
1255 }
1256
1257 #[test]
1258 fn test_engine_select_style_errors_propagate() {
1259 for errno in [libc::EINVAL, libc::EBADF, libc::ENOMEM] {
1263 let mut engine = Engine::with_backend(FailBackend::new(errno), 0);
1264 match engine.run(None) {
1265 Err(EngineError::Io(err)) => {
1266 assert_eq!(err.raw_os_error(), Some(errno));
1267 }
1268 other => panic!("expected EngineError::Io({}), got: {:?}", errno, other),
1269 }
1270 assert!(!engine.is_running());
1271 assert!(engine.exited());
1272 }
1273 }
1274
1275 #[test]
1276 fn test_engine_eintr_is_retried() {
1277 let backend = IntrThenFailBackend {
1280 eintr_count: 2,
1281 final_errno: libc::EBADF,
1282 wait_calls: 0,
1283 };
1284 let mut engine = Engine::with_backend(backend, 0);
1285
1286 match engine.run(None) {
1287 Err(EngineError::Io(err)) => {
1288 assert_eq!(err.raw_os_error(), Some(libc::EBADF));
1289 }
1290 other => panic!("expected EngineError::Io(EBADF), got: {:?}", other),
1291 }
1292 assert_eq!(engine.poll_backend.wait_calls, 3);
1294 assert!(!engine.is_running());
1295 assert!(engine.exited());
1296 }
1297
1298 #[test]
1299 fn test_engine_timeout_leaves_clean_state() {
1300 let mut engine = Engine::with_backend(NullBackend, 0);
1303 match engine.run(Some(0.0)) {
1304 Err(EngineError::Timeout) => {}
1305 other => panic!("expected EngineError::Timeout, got: {:?}", other),
1306 }
1307 assert!(!engine.is_running());
1308 assert!(engine.exited());
1309 }
1310
1311 #[test]
1314 fn test_engine_timer_creation() {
1315 let timer = EngineTimer::new(1.0, -1.0, false, || {});
1316 assert!(timer.base().is_valid());
1317 assert_eq!(timer.base().fire_delay(), 1.0);
1318 assert_eq!(timer.base().interval(), -1.0);
1319 assert!(!timer.base().autoclose());
1320 }
1321
1322 #[test]
1323 fn test_engine_timer_fire_calls_handler() {
1324 use std::sync::{
1325 atomic::{AtomicUsize, Ordering},
1326 Arc,
1327 };
1328 let counter = Arc::new(AtomicUsize::new(0));
1329 let counter_clone = counter.clone();
1330
1331 let mut timer = EngineTimer::new(0.5, -1.0, false, move || {
1332 counter_clone.fetch_add(1, Ordering::SeqCst);
1333 });
1334
1335 assert_eq!(counter.load(Ordering::SeqCst), 0);
1336 timer.fire();
1337 assert_eq!(counter.load(Ordering::SeqCst), 1);
1338 timer.fire();
1339 assert_eq!(counter.load(Ordering::SeqCst), 2);
1340 }
1341
1342 #[test]
1343 fn test_engine_timer_invalidate() {
1344 let mut timer = EngineTimer::new(1.0, -1.0, false, || {});
1345 assert!(timer.base().is_valid());
1346 timer.base_mut().invalidate();
1347 assert!(!timer.base().is_valid());
1348 }
1349
1350 #[test]
1351 fn test_engine_timer_debug() {
1352 let timer = EngineTimer::new(1.0, -1.0, false, || {});
1353 let debug_str = format!("{:?}", timer);
1354 assert!(debug_str.contains("EngineTimer"));
1355 assert!(debug_str.contains("<fn>"));
1356 }
1357
1358 #[test]
1359 fn test_engine_timer_with_autoclose() {
1360 let timer = EngineTimer::new(2.0, 0.5, true, || {});
1361 assert!(timer.base().autoclose());
1362 assert_eq!(timer.base().interval(), 0.5);
1363 }
1364}