mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-21 00:06:34 +00:00
Support for timerfd-related syscalls
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
34048c8cbc
commit
1775bb0861
@ -303,11 +303,11 @@ provided by Linux on x86-64 architecture.
|
|||||||
| 280 | utimensat | ✅ |
|
| 280 | utimensat | ✅ |
|
||||||
| 281 | epoll_pwait | ✅ |
|
| 281 | epoll_pwait | ✅ |
|
||||||
| 282 | signalfd | ✅ |
|
| 282 | signalfd | ✅ |
|
||||||
| 283 | timerfd_create | ❌ |
|
| 283 | timerfd_create | ✅ |
|
||||||
| 284 | eventfd | ✅ |
|
| 284 | eventfd | ✅ |
|
||||||
| 285 | fallocate | ✅ |
|
| 285 | fallocate | ✅ |
|
||||||
| 286 | timerfd_settime | ❌ |
|
| 286 | timerfd_settime | ✅ |
|
||||||
| 287 | timerfd_gettime | ❌ |
|
| 287 | timerfd_gettime | ✅ |
|
||||||
| 288 | accept4 | ✅ |
|
| 288 | accept4 | ✅ |
|
||||||
| 289 | signalfd4 | ✅ |
|
| 289 | signalfd4 | ✅ |
|
||||||
| 290 | eventfd2 | ✅ |
|
| 290 | eventfd2 | ✅ |
|
||||||
|
@ -126,6 +126,9 @@ use crate::syscall::{
|
|||||||
tgkill::sys_tgkill,
|
tgkill::sys_tgkill,
|
||||||
timer_create::{sys_timer_create, sys_timer_delete},
|
timer_create::{sys_timer_create, sys_timer_delete},
|
||||||
timer_settime::{sys_timer_gettime, sys_timer_settime},
|
timer_settime::{sys_timer_gettime, sys_timer_settime},
|
||||||
|
timerfd_create::sys_timerfd_create,
|
||||||
|
timerfd_gettime::sys_timerfd_gettime,
|
||||||
|
timerfd_settime::sys_timerfd_settime,
|
||||||
truncate::{sys_ftruncate, sys_truncate},
|
truncate::{sys_ftruncate, sys_truncate},
|
||||||
umask::sys_umask,
|
umask::sys_umask,
|
||||||
umount::sys_umount,
|
umount::sys_umount,
|
||||||
@ -191,6 +194,7 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||||||
SYS_SYNC = 81 => sys_sync(args[..0]);
|
SYS_SYNC = 81 => sys_sync(args[..0]);
|
||||||
SYS_FSYNC = 82 => sys_fsync(args[..1]);
|
SYS_FSYNC = 82 => sys_fsync(args[..1]);
|
||||||
SYS_FDATASYNC = 83 => sys_fdatasync(args[..1]);
|
SYS_FDATASYNC = 83 => sys_fdatasync(args[..1]);
|
||||||
|
SYS_TIMERFD_CREATE = 85 => sys_timerfd_create(args[..2]);
|
||||||
SYS_CAPGET = 90 => sys_capget(args[..2]);
|
SYS_CAPGET = 90 => sys_capget(args[..2]);
|
||||||
SYS_CAPSET = 91 => sys_capset(args[..2]);
|
SYS_CAPSET = 91 => sys_capset(args[..2]);
|
||||||
SYS_EXIT = 93 => sys_exit(args[..1]);
|
SYS_EXIT = 93 => sys_exit(args[..1]);
|
||||||
@ -293,6 +297,8 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||||||
SYS_CLOCK_NANOSLEEP = 407 => sys_clock_nanosleep(args[..4]);
|
SYS_CLOCK_NANOSLEEP = 407 => sys_clock_nanosleep(args[..4]);
|
||||||
SYS_TIMER_GETTIME = 408 => sys_timer_gettime(args[..2]);
|
SYS_TIMER_GETTIME = 408 => sys_timer_gettime(args[..2]);
|
||||||
SYS_TIMER_SETTIME = 409 => sys_timer_settime(args[..4]);
|
SYS_TIMER_SETTIME = 409 => sys_timer_settime(args[..4]);
|
||||||
|
SYS_TIMERFD_GETTIME = 410 => sys_timerfd_gettime(args[..2]);
|
||||||
|
SYS_TIMERFD_SETTIME = 411 => sys_timerfd_settime(args[..4]);
|
||||||
SYS_UTIMENSAT = 412 => sys_utimensat(args[..4]);
|
SYS_UTIMENSAT = 412 => sys_utimensat(args[..4]);
|
||||||
SYS_SEMTIMEDOP = 420 => sys_semtimedop(args[..4]);
|
SYS_SEMTIMEDOP = 420 => sys_semtimedop(args[..4]);
|
||||||
SYS_CLONE3 = 435 => sys_clone3(args[..2], &user_ctx);
|
SYS_CLONE3 = 435 => sys_clone3(args[..2], &user_ctx);
|
||||||
|
@ -142,6 +142,9 @@ use crate::syscall::{
|
|||||||
time::sys_time,
|
time::sys_time,
|
||||||
timer_create::{sys_timer_create, sys_timer_delete},
|
timer_create::{sys_timer_create, sys_timer_delete},
|
||||||
timer_settime::{sys_timer_gettime, sys_timer_settime},
|
timer_settime::{sys_timer_gettime, sys_timer_settime},
|
||||||
|
timerfd_create::sys_timerfd_create,
|
||||||
|
timerfd_gettime::sys_timerfd_gettime,
|
||||||
|
timerfd_settime::sys_timerfd_settime,
|
||||||
truncate::{sys_ftruncate, sys_truncate},
|
truncate::{sys_ftruncate, sys_truncate},
|
||||||
umask::sys_umask,
|
umask::sys_umask,
|
||||||
umount::sys_umount,
|
umount::sys_umount,
|
||||||
@ -342,8 +345,11 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||||||
SYS_UTIMENSAT = 280 => sys_utimensat(args[..4]);
|
SYS_UTIMENSAT = 280 => sys_utimensat(args[..4]);
|
||||||
SYS_EPOLL_PWAIT = 281 => sys_epoll_pwait(args[..6]);
|
SYS_EPOLL_PWAIT = 281 => sys_epoll_pwait(args[..6]);
|
||||||
SYS_SIGNALFD = 282 => sys_signalfd(args[..3]);
|
SYS_SIGNALFD = 282 => sys_signalfd(args[..3]);
|
||||||
|
SYS_TIMERFD_CREATE = 283 => sys_timerfd_create(args[..2]);
|
||||||
SYS_EVENTFD = 284 => sys_eventfd(args[..1]);
|
SYS_EVENTFD = 284 => sys_eventfd(args[..1]);
|
||||||
SYS_FALLOCATE = 285 => sys_fallocate(args[..4]);
|
SYS_FALLOCATE = 285 => sys_fallocate(args[..4]);
|
||||||
|
SYS_TIMERFD_SETTIME = 286 => sys_timerfd_settime(args[..4]);
|
||||||
|
SYS_TIMERFD_GETTIME = 287 => sys_timerfd_gettime(args[..2]);
|
||||||
SYS_ACCEPT4 = 288 => sys_accept4(args[..4]);
|
SYS_ACCEPT4 = 288 => sys_accept4(args[..4]);
|
||||||
SYS_SIGNALFD4 = 289 => sys_signalfd4(args[..4]);
|
SYS_SIGNALFD4 = 289 => sys_signalfd4(args[..4]);
|
||||||
SYS_EVENTFD2 = 290 => sys_eventfd2(args[..2]);
|
SYS_EVENTFD2 = 290 => sys_eventfd2(args[..2]);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
//! The each sub module contains functions that handle real syscall logic.
|
//! The each sub module contains functions that handle real syscall logic.
|
||||||
pub use clock_gettime::ClockId;
|
pub use clock_gettime::ClockId;
|
||||||
use ostd::cpu::context::UserContext;
|
use ostd::cpu::context::UserContext;
|
||||||
|
pub use timer_create::create_timer;
|
||||||
|
|
||||||
use crate::{context::Context, cpu::LinuxAbi, prelude::*};
|
use crate::{context::Context, cpu::LinuxAbi, prelude::*};
|
||||||
|
|
||||||
@ -149,6 +150,9 @@ mod tgkill;
|
|||||||
mod time;
|
mod time;
|
||||||
mod timer_create;
|
mod timer_create;
|
||||||
mod timer_settime;
|
mod timer_settime;
|
||||||
|
mod timerfd_create;
|
||||||
|
mod timerfd_gettime;
|
||||||
|
mod timerfd_settime;
|
||||||
mod truncate;
|
mod truncate;
|
||||||
mod umask;
|
mod umask;
|
||||||
mod umount;
|
mod umount;
|
||||||
|
@ -21,6 +21,7 @@ use crate::{
|
|||||||
time::{
|
time::{
|
||||||
clockid_t,
|
clockid_t,
|
||||||
clocks::{BootTimeClock, MonotonicClock, RealTimeClock},
|
clocks::{BootTimeClock, MonotonicClock, RealTimeClock},
|
||||||
|
Timer,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -103,7 +104,31 @@ pub fn sys_timer_create(
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
let process_timer_manager = current_process.timer_manager();
|
let timer = create_timer(clockid, func, ctx)?;
|
||||||
|
|
||||||
|
let timer_id = current_process.timer_manager().add_posix_timer(timer);
|
||||||
|
ctx.user_space().write_val(timer_id_addr, &timer_id)?;
|
||||||
|
Ok(SyscallReturn::Return(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_timer_delete(timer_id: usize, _ctx: &Context) -> Result<SyscallReturn> {
|
||||||
|
let current_process = current!();
|
||||||
|
let Some(timer) = current_process.timer_manager().remove_posix_timer(timer_id) else {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "invalid timer ID");
|
||||||
|
};
|
||||||
|
|
||||||
|
timer.cancel();
|
||||||
|
Ok(SyscallReturn::Return(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a timer associated with the specified clock ID.
|
||||||
|
///
|
||||||
|
/// This timer will invoke the given callback function (`func`) when it expires.
|
||||||
|
pub fn create_timer<F>(clockid: clockid_t, func: F, ctx: &Context) -> Result<Arc<Timer>>
|
||||||
|
where
|
||||||
|
F: Fn() + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
let process_timer_manager = ctx.process.timer_manager();
|
||||||
let timer = if clockid >= 0 {
|
let timer = if clockid >= 0 {
|
||||||
let clock_id = ClockId::try_from(clockid)?;
|
let clock_id = ClockId::try_from(clockid)?;
|
||||||
match clock_id {
|
match clock_id {
|
||||||
@ -141,18 +166,5 @@ pub fn sys_timer_create(
|
|||||||
DynamicClockIdInfo::Fd(_) => unimplemented!(),
|
DynamicClockIdInfo::Fd(_) => unimplemented!(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Ok(timer)
|
||||||
let timer_id = process_timer_manager.add_posix_timer(timer);
|
|
||||||
ctx.user_space().write_val(timer_id_addr, &timer_id)?;
|
|
||||||
Ok(SyscallReturn::Return(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sys_timer_delete(timer_id: usize, _ctx: &Context) -> Result<SyscallReturn> {
|
|
||||||
let current_process = current!();
|
|
||||||
let Some(timer) = current_process.timer_manager().remove_posix_timer(timer_id) else {
|
|
||||||
return_errno_with_message!(Errno::EINVAL, "invalid timer ID");
|
|
||||||
};
|
|
||||||
|
|
||||||
timer.cancel();
|
|
||||||
Ok(SyscallReturn::Return(0))
|
|
||||||
}
|
}
|
||||||
|
31
kernel/src/syscall/timerfd_create.rs
Normal file
31
kernel/src/syscall/timerfd_create.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use super::SyscallReturn;
|
||||||
|
use crate::{
|
||||||
|
fs::file_table::FdFlags,
|
||||||
|
prelude::*,
|
||||||
|
time::{
|
||||||
|
clockid_t,
|
||||||
|
timerfd::{TFDFlags, TimerfdFile},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn sys_timerfd_create(clockid: clockid_t, flags: i32, ctx: &Context) -> Result<SyscallReturn> {
|
||||||
|
let flags = TFDFlags::from_bits(flags as u32)
|
||||||
|
.ok_or_else(|| Error::with_message(Errno::EINVAL, "unknown flags"))?;
|
||||||
|
|
||||||
|
let timerfd_file = TimerfdFile::new(clockid, flags, ctx)?;
|
||||||
|
|
||||||
|
let fd = {
|
||||||
|
let file_table = ctx.thread_local.borrow_file_table();
|
||||||
|
let mut file_table_locked = file_table.unwrap().write();
|
||||||
|
let fd_flags = if flags.contains(TFDFlags::TFD_CLOEXEC) {
|
||||||
|
FdFlags::CLOEXEC
|
||||||
|
} else {
|
||||||
|
FdFlags::empty()
|
||||||
|
};
|
||||||
|
file_table_locked.insert(Arc::new(timerfd_file), fd_flags)
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(SyscallReturn::Return(fd as _))
|
||||||
|
}
|
35
kernel/src/syscall/timerfd_gettime.rs
Normal file
35
kernel/src/syscall/timerfd_gettime.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use super::SyscallReturn;
|
||||||
|
use crate::{
|
||||||
|
fs::file_table::FileDesc,
|
||||||
|
prelude::*,
|
||||||
|
time::{itimerspec_t, timerfd::TimerfdFile, timespec_t},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn sys_timerfd_gettime(
|
||||||
|
fd: FileDesc,
|
||||||
|
itimerspec_addr: Vaddr,
|
||||||
|
ctx: &Context,
|
||||||
|
) -> Result<SyscallReturn> {
|
||||||
|
if itimerspec_addr == 0 {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "invalid pointer to return value");
|
||||||
|
}
|
||||||
|
|
||||||
|
let file_table = ctx.thread_local.borrow_file_table();
|
||||||
|
let file_table_locked = file_table.unwrap().read();
|
||||||
|
let timerfd_file = file_table_locked.get_file(fd as _)?;
|
||||||
|
let timerfd_file = timerfd_file
|
||||||
|
.downcast_ref::<TimerfdFile>()
|
||||||
|
.ok_or_else(|| Error::with_message(Errno::EINVAL, "the fd is not a timerfd"))?;
|
||||||
|
|
||||||
|
let interval = timespec_t::from(timerfd_file.timer().interval());
|
||||||
|
let remain = timespec_t::from(timerfd_file.timer().remain());
|
||||||
|
let itimerspec = itimerspec_t {
|
||||||
|
it_interval: interval,
|
||||||
|
it_value: remain,
|
||||||
|
};
|
||||||
|
ctx.user_space().write_val(itimerspec_addr, &itimerspec)?;
|
||||||
|
|
||||||
|
Ok(SyscallReturn::Return(0))
|
||||||
|
}
|
63
kernel/src/syscall/timerfd_settime.rs
Normal file
63
kernel/src/syscall/timerfd_settime.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use core::time::Duration;
|
||||||
|
|
||||||
|
use super::SyscallReturn;
|
||||||
|
use crate::{
|
||||||
|
fs::file_table::FileDesc,
|
||||||
|
prelude::*,
|
||||||
|
time::{itimerspec_t, timer::Timeout, timerfd::TimerfdFile, timespec_t, TIMER_ABSTIME},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn sys_timerfd_settime(
|
||||||
|
fd: FileDesc,
|
||||||
|
flags: i32,
|
||||||
|
new_itimerspec_addr: Vaddr,
|
||||||
|
old_itimerspec_addr: Vaddr,
|
||||||
|
ctx: &Context,
|
||||||
|
) -> Result<SyscallReturn> {
|
||||||
|
let file_table = ctx.thread_local.borrow_file_table();
|
||||||
|
let file_table_locked = file_table.unwrap().read();
|
||||||
|
let timerfd_file = file_table_locked.get_file(fd as _)?;
|
||||||
|
let timerfd_file = timerfd_file
|
||||||
|
.downcast_ref::<TimerfdFile>()
|
||||||
|
.ok_or_else(|| Error::with_message(Errno::EINVAL, "the fd is not a timerfd"))?;
|
||||||
|
|
||||||
|
let user_space = ctx.user_space();
|
||||||
|
let new_itimerspec = user_space.read_val::<itimerspec_t>(new_itimerspec_addr)?;
|
||||||
|
let interval = Duration::try_from(new_itimerspec.it_interval)?;
|
||||||
|
let expire_time = Duration::try_from(new_itimerspec.it_value)?;
|
||||||
|
|
||||||
|
let timer = timerfd_file.timer();
|
||||||
|
if old_itimerspec_addr > 0 {
|
||||||
|
let old_interval = timespec_t::from(timer.interval());
|
||||||
|
let remain = timespec_t::from(timer.remain());
|
||||||
|
let old_itimerspec = itimerspec_t {
|
||||||
|
it_interval: old_interval,
|
||||||
|
it_value: remain,
|
||||||
|
};
|
||||||
|
user_space.write_val(old_itimerspec_addr, &old_itimerspec)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.set_interval(interval);
|
||||||
|
timer.cancel();
|
||||||
|
// Clear `ticks` after cancel the timer to ensure that `ticks` is zero
|
||||||
|
// when the timer is rearmed.
|
||||||
|
timerfd_file.clear_ticks();
|
||||||
|
|
||||||
|
const TFD_TIMER_CANCEL_ON_SET: i32 = 2;
|
||||||
|
if expire_time != Duration::ZERO {
|
||||||
|
let timeout = if flags == 0 {
|
||||||
|
Timeout::After(expire_time)
|
||||||
|
} else if flags == TIMER_ABSTIME {
|
||||||
|
Timeout::When(expire_time)
|
||||||
|
} else if flags == TFD_TIMER_CANCEL_ON_SET {
|
||||||
|
unimplemented!()
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
timer.set_timeout(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(SyscallReturn::Return(0))
|
||||||
|
}
|
@ -14,6 +14,7 @@ pub mod clocks;
|
|||||||
mod core;
|
mod core;
|
||||||
mod softirq;
|
mod softirq;
|
||||||
mod system_time;
|
mod system_time;
|
||||||
|
pub mod timerfd;
|
||||||
pub mod wait;
|
pub mod wait;
|
||||||
|
|
||||||
pub type clockid_t = i32;
|
pub type clockid_t = i32;
|
||||||
|
168
kernel/src/time/timerfd.rs
Normal file
168
kernel/src/time/timerfd.rs
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use core::sync::atomic::{AtomicU64, Ordering};
|
||||||
|
|
||||||
|
use super::clockid_t;
|
||||||
|
use crate::{
|
||||||
|
events::IoEvents,
|
||||||
|
fs::{
|
||||||
|
file_handle::FileLike,
|
||||||
|
utils::{CreationFlags, InodeMode, InodeType, Metadata, StatusFlags},
|
||||||
|
},
|
||||||
|
prelude::*,
|
||||||
|
process::{
|
||||||
|
signal::{PollHandle, Pollable, Pollee},
|
||||||
|
Gid, Uid,
|
||||||
|
},
|
||||||
|
syscall::create_timer,
|
||||||
|
time::{clocks::RealTimeClock, Timer},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A file-like object representing a timer that can be used with file descriptors.
|
||||||
|
pub struct TimerfdFile {
|
||||||
|
timer: Arc<Timer>,
|
||||||
|
ticks: Arc<AtomicU64>,
|
||||||
|
pollee: Pollee,
|
||||||
|
flags: SpinLock<TFDFlags>,
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
/// The flags useds for timerfd-related operations.
|
||||||
|
pub struct TFDFlags: u32 {
|
||||||
|
const TFD_CLOEXEC = CreationFlags::O_CLOEXEC.bits();
|
||||||
|
const TFD_NONBLOCK = StatusFlags::O_NONBLOCK.bits();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TimerfdFile {
|
||||||
|
/// Creates a new `TimerfdFile` instance.
|
||||||
|
pub fn new(clockid: clockid_t, flags: TFDFlags, ctx: &Context) -> Result<Self> {
|
||||||
|
let ticks = Arc::new(AtomicU64::new(0));
|
||||||
|
let pollee = Pollee::new();
|
||||||
|
|
||||||
|
let timer = {
|
||||||
|
let ticks = ticks.clone();
|
||||||
|
let pollee = pollee.clone();
|
||||||
|
|
||||||
|
let expired_fn = move || {
|
||||||
|
ticks.fetch_add(1, Ordering::Release);
|
||||||
|
pollee.notify(IoEvents::IN);
|
||||||
|
};
|
||||||
|
create_timer(clockid, expired_fn, ctx)
|
||||||
|
}?;
|
||||||
|
|
||||||
|
Ok(TimerfdFile {
|
||||||
|
timer,
|
||||||
|
ticks,
|
||||||
|
pollee,
|
||||||
|
flags: SpinLock::new(flags),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the associated timer.
|
||||||
|
pub fn timer(&self) -> &Arc<Timer> {
|
||||||
|
&self.timer
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears the tick count.
|
||||||
|
pub fn clear_ticks(&self) {
|
||||||
|
self.ticks.store(0, Ordering::Release);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_nonblocking(&self) -> bool {
|
||||||
|
self.flags.lock().contains(TFDFlags::TFD_NONBLOCK)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_read(&self, writer: &mut VmWriter) -> Result<()> {
|
||||||
|
let ticks = self.ticks.fetch_and(0, Ordering::AcqRel);
|
||||||
|
|
||||||
|
if ticks == 0 {
|
||||||
|
return_errno_with_message!(Errno::EAGAIN, "the counter is zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.write_fallible(&mut ticks.as_bytes().into())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_io_events(&self) -> IoEvents {
|
||||||
|
let mut events = IoEvents::empty();
|
||||||
|
|
||||||
|
if self.ticks.load(Ordering::Acquire) != 0 {
|
||||||
|
events |= IoEvents::IN;
|
||||||
|
}
|
||||||
|
|
||||||
|
events
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pollable for TimerfdFile {
|
||||||
|
fn poll(&self, mask: IoEvents, poller: Option<&mut PollHandle>) -> IoEvents {
|
||||||
|
self.pollee
|
||||||
|
.poll_with(mask, poller, || self.check_io_events())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileLike for TimerfdFile {
|
||||||
|
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
|
||||||
|
let read_len = core::mem::size_of::<u64>();
|
||||||
|
|
||||||
|
if writer.avail() < read_len {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "buf len is less len u64 size");
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.is_nonblocking() {
|
||||||
|
self.try_read(writer)?;
|
||||||
|
} else {
|
||||||
|
self.wait_events(IoEvents::IN, None, || self.try_read(writer))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(read_len)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&self, _reader: &mut VmReader) -> Result<usize> {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "the file is not valid for writing");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn status_flags(&self) -> StatusFlags {
|
||||||
|
if self.is_nonblocking() {
|
||||||
|
StatusFlags::O_NONBLOCK
|
||||||
|
} else {
|
||||||
|
StatusFlags::empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_status_flags(&self, new_flags: StatusFlags) -> Result<()> {
|
||||||
|
let mut flags = self.flags.lock();
|
||||||
|
|
||||||
|
if new_flags.contains(StatusFlags::O_NONBLOCK) {
|
||||||
|
*flags |= TFDFlags::TFD_NONBLOCK;
|
||||||
|
} else {
|
||||||
|
*flags &= !TFDFlags::TFD_NONBLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn metadata(&self) -> Metadata {
|
||||||
|
// This is a dummy implementation.
|
||||||
|
// TODO: Add "anonymous inode fs" and link the file to it.
|
||||||
|
let now = RealTimeClock::get().read_time();
|
||||||
|
Metadata {
|
||||||
|
dev: 0,
|
||||||
|
ino: 0,
|
||||||
|
size: 0,
|
||||||
|
blk_size: 0,
|
||||||
|
blocks: 0,
|
||||||
|
atime: now,
|
||||||
|
mtime: now,
|
||||||
|
ctime: now,
|
||||||
|
type_: InodeType::NamedPipe,
|
||||||
|
mode: InodeMode::from_bits_truncate(0o200),
|
||||||
|
nlinks: 1,
|
||||||
|
uid: Uid::new_root(),
|
||||||
|
gid: Gid::new_root(),
|
||||||
|
rdev: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user