Skip to content

Commit 8cde1ee

Browse files
committed
imp(timer): initial epoll/timerfd implementation
1 parent 09e3de9 commit 8cde1ee

File tree

2 files changed

+108
-2
lines changed

2 files changed

+108
-2
lines changed

examples/internals-timer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ fn main() {
2828
std::thread::spawn(move || {
2929
while let result = rx.recv() {
3030
match result {
31-
Ok(time) => println!("Thread 2 Notification: {}", time),
31+
Ok(time) => println!("Thread 1 Notification: {}", time),
3232
Err(err) => {
3333
println!("Error Thread 1");
3434
break;

src/timer/epoll.rs

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,113 @@ pub struct Timer {
2020

2121
impl Timer {
2222
pub fn initialize(self) -> Self {
23-
self
23+
let txs = Arc::clone(&self.txs);
24+
25+
// TODO: use ? instead of unwrap, requires changing Timer initialize function
26+
let timer_fd = Timer::set_timerfd().unwrap();
27+
let epoll_fd = Timer::create_epollfd(timer_fd).unwrap();
28+
29+
let handle = Some(thread::spawn(move || {
30+
loop {
31+
// Exit thread if there are no listeners
32+
if txs.lock()?.len() == 0 {
33+
// TODO: should close file descriptor
34+
return Ok(());
35+
}
36+
37+
// Fire @ 10th sec
38+
Timer::epoll_wait(timer_fd, epoll_fd).unwrap();
39+
40+
// Get current time
41+
let current = std::time::SystemTime::now()
42+
.duration_since(std::time::UNIX_EPOCH)?
43+
.as_secs();
44+
45+
// Iterate through Senders
46+
txs.lock()?.iter().for_each(|tx| {
47+
// Send event to attached Sender
48+
tx.send(current).unwrap();
49+
});
50+
}
51+
}));
52+
53+
Self { handle, ..self }
54+
}
55+
56+
fn set_timerfd() -> Result<libc::c_int> {
57+
let clockid: libc::clockid_t = libc::CLOCK_REALTIME;
58+
let clock_flags: libc::c_int = libc::TFD_NONBLOCK;
59+
60+
// TODO: handler error (-1)
61+
let tfd = unsafe { libc::timerfd_create(clockid, clock_flags) };
62+
63+
let now = std::time::SystemTime::now()
64+
.duration_since(std::time::UNIX_EPOCH)?
65+
.as_secs();
66+
67+
let rem = 10u64.checked_sub(now.checked_rem(10).unwrap()).unwrap();
68+
69+
let first_fire = now + rem;
70+
71+
let mut new_value = libc::itimerspec {
72+
it_interval: libc::timespec {
73+
tv_sec: 10,
74+
tv_nsec: 0,
75+
},
76+
it_value: libc::timespec {
77+
tv_sec: first_fire as i64,
78+
tv_nsec: 0,
79+
},
80+
};
81+
82+
let mut old_value = libc::itimerspec {
83+
it_interval: libc::timespec {
84+
tv_sec: 0,
85+
tv_nsec: 0,
86+
},
87+
it_value: libc::timespec {
88+
tv_sec: 0,
89+
tv_nsec: 0,
90+
},
91+
};
92+
93+
let set_flags = libc::TFD_TIMER_ABSTIME;
94+
95+
// TODO: handler error (-1)
96+
let sfd = unsafe { libc::timerfd_settime(tfd, set_flags, &mut new_value, &mut old_value) };
97+
98+
Ok(tfd)
99+
}
100+
101+
fn create_epollfd(timer_fd: libc::c_int) -> Result<libc::c_int> {
102+
// TODO: handler error (-1)
103+
let epoll_fd = unsafe { libc::epoll_create1(0) };
104+
105+
let mut event = libc::epoll_event {
106+
events: libc::EPOLLIN as u32,
107+
u64: 1,
108+
};
109+
110+
let epoll_flags = libc::EPOLL_CTL_ADD;
111+
112+
// TODO: handler error (-1)
113+
let ctl_fd = unsafe { libc::epoll_ctl(epoll_fd, epoll_flags, timer_fd, &mut event) };
114+
115+
Ok(epoll_fd)
116+
}
117+
118+
fn epoll_wait(timer_fd: libc::c_int, epoll_fd: libc::c_int) -> Result<()> {
119+
let mut events = Vec::with_capacity(1);
120+
121+
// TODO: handler error (-1)
122+
let wait = unsafe { libc::epoll_wait(epoll_fd, events.as_mut_ptr(), 1, -1) };
123+
let mut buffer: u64 = 0;
124+
let bufptr: *mut _ = &mut buffer;
125+
126+
// TODO: handler error (-1)
127+
let read = unsafe { libc::read(timer_fd, bufptr as *mut libc::c_void, 8) };
128+
129+
Ok(())
24130
}
25131

26132
/// Attach an mpsc::Sender to Timer

0 commit comments

Comments
 (0)