diff --git a/kernel/calls.c b/kernel/calls.c index 7d1e46e0..3f692718 100644 --- a/kernel/calls.c +++ b/kernel/calls.c @@ -185,6 +185,7 @@ syscall_t syscall_table[] = { [322] = (syscall_t) sys_timerfd_create, [323] = (syscall_t) sys_eventfd, [324] = (syscall_t) sys_fallocate, + [325] = (syscall_t) sys_timerfd_settime, [328] = (syscall_t) sys_eventfd2, [329] = (syscall_t) sys_epoll_create, [330] = (syscall_t) sys_dup3, diff --git a/kernel/resource.c b/kernel/resource.c index fae6d597..d46a4681 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -10,6 +10,7 @@ #endif #include +#include #include "kernel/calls.h" static bool resource_valid(int resource) { diff --git a/kernel/time.c b/kernel/time.c index 394d7771..ef1185a8 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -240,6 +240,44 @@ fd_t sys_timerfd_create(int_t clockid, int_t flags) { return f_install(fd, flags); } +int_t sys_timerfd_settime(fd_t f, int_t flags, addr_t new_value_addr, addr_t old_value_addr) { + STRACE("timerfd_settime(%d, %d, %#x, %#x)", f, flags, new_value_addr, old_value_addr); + struct fd *fd = f_get(f); + if (fd == NULL) + return _EBADF; + if (fd->ops != &timerfd_ops) + return _EINVAL; + struct itimerspec_ value; + if (user_get(new_value_addr, value)) + return _EFAULT; + + struct timer_spec spec = { + .value.tv_sec = value.value.sec, + .value.tv_nsec = value.value.nsec, + .interval.tv_sec = value.interval.sec, + .interval.tv_nsec = value.interval.nsec, + }; + struct timer_spec old_spec; + lock(&fd->lock); + int err = timer_set(fd->timerfd.timer, spec, &old_spec); + unlock(&fd->lock); + if (err < 0) + return err; + + if (old_value_addr) { + struct itimerspec_ old_value = { + .value.sec = old_spec.value.tv_sec, + .value.nsec = old_spec.value.tv_nsec, + .interval.sec = old_spec.interval.tv_sec, + .interval.nsec = old_spec.interval.tv_nsec, + }; + if (user_put(old_value_addr, old_value)) + return _EFAULT; + } + + return 0; +} + static ssize_t timerfd_read(struct fd *fd, void *buf, size_t bufsize) { if (bufsize < sizeof(uint64_t)) return _EINVAL; @@ -260,7 +298,7 @@ static ssize_t timerfd_read(struct fd *fd, void *buf, size_t bufsize) { static int timerfd_poll(struct fd *fd) { int res = 0; lock(&fd->lock); - if (fd->timerfd.expirations == 0) + if (fd->timerfd.expirations != 0) res |= POLL_READ; unlock(&fd->lock); return res; diff --git a/kernel/time.h b/kernel/time.h index 79f89b4d..fdff632e 100644 --- a/kernel/time.h +++ b/kernel/time.h @@ -36,6 +36,11 @@ struct itimerval_ { struct timeval_ value; }; +struct itimerspec_ { + struct timespec_ interval; + struct timespec_ value; +}; + struct tms_ { clock_t_ tms_utime; /* user time */ clock_t_ tms_stime; /* system time */ @@ -51,5 +56,6 @@ dword_t sys_gettimeofday(addr_t tv, addr_t tz); dword_t sys_settimeofday(addr_t tv, addr_t tz); fd_t sys_timerfd_create(int_t clockid, int_t flags); +int_t sys_timerfd_settime(fd_t f, int_t flags, addr_t new_value_addr, addr_t old_value_addr); #endif