Skip to content

Commit

Permalink
feat: I/O safety for 'sys/timerfd'
Browse files Browse the repository at this point in the history
  • Loading branch information
SteveLauC committed Dec 9, 2022
1 parent a2356ab commit f592678
Showing 1 changed file with 21 additions and 23 deletions.
44 changes: 21 additions & 23 deletions src/sys/timerfd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,28 @@ pub use crate::sys::time::timer::{Expiration, TimerSetTimeFlags};
use crate::unistd::read;
use crate::{errno::Errno, Result};
use libc::c_int;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};

/// A timerfd instance. This is also a file descriptor, you can feed it to
/// other interfaces consuming file descriptors, epoll for example.
/// other interfaces taking file descriptors as arguments, [`epoll`] for example.
///
/// [`epoll`]: crate::sys::epoll
#[derive(Debug)]
pub struct TimerFd {
fd: RawFd,
fd: OwnedFd,
}

impl AsRawFd for TimerFd {
fn as_raw_fd(&self) -> RawFd {
self.fd
impl AsFd for TimerFd {
fn as_fd(&self) -> BorrowedFd<'_> {
self.fd.as_fd()
}
}

impl FromRawFd for TimerFd {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
TimerFd { fd }
TimerFd {
fd: OwnedFd::from_raw_fd(fd),
}
}
}

Expand Down Expand Up @@ -97,7 +101,9 @@ impl TimerFd {
Errno::result(unsafe {
libc::timerfd_create(clockid as i32, flags.bits())
})
.map(|fd| Self { fd })
.map(|fd| Self {
fd: unsafe { OwnedFd::from_raw_fd(fd) },
})
}

/// Sets a new alarm on the timer.
Expand Down Expand Up @@ -145,7 +151,7 @@ impl TimerFd {
let timerspec: TimerSpec = expiration.into();
Errno::result(unsafe {
libc::timerfd_settime(
self.fd,
self.fd.as_fd().as_raw_fd(),
flags.bits(),
timerspec.as_ref(),
std::ptr::null_mut(),
Expand All @@ -159,7 +165,10 @@ impl TimerFd {
pub fn get(&self) -> Result<Option<Expiration>> {
let mut timerspec = TimerSpec::none();
Errno::result(unsafe {
libc::timerfd_gettime(self.fd, timerspec.as_mut())
libc::timerfd_gettime(
self.fd.as_fd().as_raw_fd(),
timerspec.as_mut(),
)
})
.map(|_| {
if timerspec.as_ref().it_interval.tv_sec == 0
Expand All @@ -179,7 +188,7 @@ impl TimerFd {
pub fn unset(&self) -> Result<()> {
Errno::result(unsafe {
libc::timerfd_settime(
self.fd,
self.fd.as_fd().as_raw_fd(),
TimerSetTimeFlags::empty().bits(),
TimerSpec::none().as_ref(),
std::ptr::null_mut(),
Expand All @@ -192,7 +201,7 @@ impl TimerFd {
///
/// Note: If the alarm is unset, then you will wait forever.
pub fn wait(&self) -> Result<()> {
while let Err(e) = read(self.fd, &mut [0u8; 8]) {
while let Err(e) = read(self.fd.as_fd().as_raw_fd(), &mut [0u8; 8]) {
if e != Errno::EINTR {
return Err(e);
}
Expand All @@ -201,14 +210,3 @@ impl TimerFd {
Ok(())
}
}

impl Drop for TimerFd {
fn drop(&mut self) {
if !std::thread::panicking() {
let result = Errno::result(unsafe { libc::close(self.fd) });
if let Err(Errno::EBADF) = result {
panic!("close of TimerFd encountered EBADF");
}
}
}
}

0 comments on commit f592678

Please sign in to comment.