1use rustix::time::{
2    timerfd_create, timerfd_gettime, timerfd_settime, Itimerspec, TimerfdClockId, TimerfdFlags,
3    TimerfdTimerFlags, Timespec,
4};
5
6#[test]
7fn test_timerfd() {
8    let fd = timerfd_create(TimerfdClockId::Monotonic, TimerfdFlags::CLOEXEC).unwrap();
9
10    let set = Itimerspec {
11        it_interval: Timespec {
12            tv_sec: 0,
13            tv_nsec: 0,
14        },
15        it_value: Timespec {
16            tv_sec: 1,
17            tv_nsec: 2,
18        },
19    };
20    let _old: Itimerspec = timerfd_settime(&fd, TimerfdTimerFlags::ABSTIME, &set).unwrap();
21
22    // Wait for the timer to expire.
23    let mut buf = [0_u8; 8];
24    assert_eq!(rustix::io::read(&fd, &mut buf), Ok(8));
25    assert!(u64::from_ne_bytes(buf) >= 1);
26
27    let new = timerfd_gettime(&fd).unwrap();
28
29    // The timer counts down.
30    assert_eq!(set.it_interval.tv_sec, new.it_interval.tv_sec);
31    assert_eq!(set.it_interval.tv_nsec, new.it_interval.tv_nsec);
32    assert!(new.it_value.tv_sec <= set.it_value.tv_sec);
33    assert!(
34        new.it_value.tv_nsec < set.it_value.tv_nsec || new.it_value.tv_sec < set.it_value.tv_sec
35    );
36}
37
38/// Similar, but set an interval for a repeated timer. Don't check that the
39/// times are monotonic because that would race with the timer repeating.
40#[test]
41fn test_timerfd_with_interval() {
42    let fd = timerfd_create(TimerfdClockId::Monotonic, TimerfdFlags::CLOEXEC).unwrap();
43
44    let set = Itimerspec {
45        it_interval: Timespec {
46            tv_sec: 0,
47            tv_nsec: 6,
48        },
49        it_value: Timespec {
50            tv_sec: 1,
51            tv_nsec: 7,
52        },
53    };
54    let _old: Itimerspec = timerfd_settime(&fd, TimerfdTimerFlags::ABSTIME, &set).unwrap();
55
56    // Wait for the timer to expire.
57    let mut buf = [0_u8; 8];
58    assert_eq!(rustix::io::read(&fd, &mut buf), Ok(8));
59    assert!(u64::from_ne_bytes(buf) >= 1);
60
61    let new = timerfd_gettime(&fd).unwrap();
62
63    assert_eq!(set.it_interval.tv_sec, new.it_interval.tv_sec);
64    assert_eq!(set.it_interval.tv_nsec, new.it_interval.tv_nsec);
65
66    // Wait for the timer to expire again.
67    let mut buf = [0_u8; 8];
68    assert_eq!(rustix::io::read(&fd, &mut buf), Ok(8));
69    assert!(u64::from_ne_bytes(buf) >= 1);
70
71    let new = timerfd_gettime(&fd).unwrap();
72
73    assert_eq!(set.it_interval.tv_sec, new.it_interval.tv_sec);
74    assert_eq!(set.it_interval.tv_nsec, new.it_interval.tv_nsec);
75}
76