diff options
-rw-r--r-- | Kernel/Process.cpp | 41 | ||||
-rw-r--r-- | Kernel/Process.h | 2 | ||||
-rw-r--r-- | Kernel/Syscall.h | 8 | ||||
-rw-r--r-- | Libraries/LibC/poll.cpp | 17 | ||||
-rw-r--r-- | Libraries/LibC/poll.h | 6 |
5 files changed, 55 insertions, 19 deletions
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 2f302fcec6..80ea2e8de6 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -3055,18 +3055,33 @@ int Process::sys$select(const Syscall::SC_select_params* params) return marked_fd_count; } -int Process::sys$poll(pollfd* fds, int nfds, int timeout) +int Process::sys$poll(const Syscall::SC_poll_params* params) { REQUIRE_PROMISE(stdio); - if (!validate_read_typed(fds)) + // FIXME: Return -EINVAL if timeout is invalid. + if (!validate_read_typed(params)) return -EFAULT; SmapDisabler disabler; + pollfd* fds = params->fds; + unsigned nfds = params->nfds; + const timespec* timeout = params->timeout; + const sigset_t* sigmask = params->sigmask; + + if (fds && !validate_read_typed(fds, nfds)) + return -EFAULT; + if (timeout && !validate_read_typed(timeout)) + return -EFAULT; + if (sigmask && !validate_read_typed(sigmask)) + return -EFAULT; + if (!validate_read_typed(fds)) + return -EFAULT; + Thread::SelectBlocker::FDVector rfds; Thread::SelectBlocker::FDVector wfds; - for (int i = 0; i < nfds; ++i) { + for (unsigned i = 0; i < nfds; ++i) { if (fds[i].events & POLLIN) rfds.append(fds[i].fd); if (fds[i].events & POLLOUT) @@ -3075,33 +3090,29 @@ int Process::sys$poll(pollfd* fds, int nfds, int timeout) timespec actual_timeout; bool has_timeout = false; - if (timeout >= 0) { - // poll is in ms, we want s/ns. - struct timespec tstimeout; - tstimeout.tv_sec = 0; - while (timeout >= 1000) { - tstimeout.tv_sec += 1; - timeout -= 1000; - } - tstimeout.tv_nsec = timeout * 1000 * 1000; + if (timeout && (timeout->tv_sec || timeout->tv_nsec)) { timespec ts_since_boot; timeval_to_timespec(Scheduler::time_since_boot(), ts_since_boot); - timespec_add(ts_since_boot, tstimeout, actual_timeout); + timespec_add(ts_since_boot, *timeout, actual_timeout); has_timeout = true; } + ScopedValueRollback scoped_sigmask(Thread::current->m_signal_mask); + if (sigmask) + Thread::current->m_signal_mask = *sigmask; + #if defined(DEBUG_IO) || defined(DEBUG_POLL_SELECT) dbg() << "polling on (read:" << rfds.size() << ", write:" << wfds.size() << "), timeout=" << timeout; #endif - if (has_timeout || timeout < 0) { + if (!timeout || has_timeout) { if (Thread::current->block<Thread::SelectBlocker>(actual_timeout, has_timeout, rfds, wfds, Thread::SelectBlocker::FDVector()) != Thread::BlockResult::WokeNormally) return -EINTR; } int fds_with_revents = 0; - for (int i = 0; i < nfds; ++i) { + for (unsigned i = 0; i < nfds; ++i) { auto description = file_description(fds[i].fd); if (!description) { fds[i].revents = POLLNVAL; diff --git a/Kernel/Process.h b/Kernel/Process.h index ec9aeb3201..0dfc939343 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -217,7 +217,7 @@ public: int sys$minherit(void*, size_t, int inherit); int sys$purge(int mode); int sys$select(const Syscall::SC_select_params*); - int sys$poll(pollfd*, int nfds, int timeout); + int sys$poll(const Syscall::SC_poll_params*); ssize_t sys$get_dir_entries(int fd, void*, ssize_t); int sys$getcwd(char*, ssize_t); int sys$chdir(const char*, size_t); diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index d1251d28fc..c07fdffe70 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -35,6 +35,7 @@ constexpr int syscall_vector = 0x82; extern "C" { +struct pollfd; struct timeval; struct timespec; struct sockaddr; @@ -273,6 +274,13 @@ struct SC_select_params { const u32* sigmask; }; +struct SC_poll_params { + struct pollfd* fds; + unsigned nfds; + const struct timespec* timeout; + const u32* sigmask; +}; + struct SC_clock_nanosleep_params { int clock_id; int flags; diff --git a/Libraries/LibC/poll.cpp b/Libraries/LibC/poll.cpp index 46f2fdf49f..256c4528f4 100644 --- a/Libraries/LibC/poll.cpp +++ b/Libraries/LibC/poll.cpp @@ -27,12 +27,25 @@ #include <Kernel/Syscall.h> #include <errno.h> #include <poll.h> +#include <sys/time.h> extern "C" { -int poll(struct pollfd* fds, int nfds, int timeout) +int poll(pollfd* fds, nfds_t nfds, int timeout_ms) { - int rc = syscall(SC_poll, fds, nfds, timeout); + timespec timeout; + timespec* timeout_ts = &timeout; + if (timeout_ms < 0) + timeout_ts = nullptr; + else + timeout = { timeout_ms / 1000, (timeout_ms % 1000) * 1'000'000 }; + return ppoll(fds, nfds, timeout_ts, nullptr); +} + +int ppoll(pollfd* fds, nfds_t nfds, const timespec* timeout, const sigset_t* sigmask) +{ + Syscall::SC_poll_params params { fds, nfds, timeout, sigmask }; + int rc = syscall(SC_poll, ¶ms); __RETURN_WITH_ERRNO(rc, rc, -1); } } diff --git a/Libraries/LibC/poll.h b/Libraries/LibC/poll.h index 051357249a..af0ff254c5 100644 --- a/Libraries/LibC/poll.h +++ b/Libraries/LibC/poll.h @@ -26,6 +26,7 @@ #pragma once +#include <signal.h> #include <sys/cdefs.h> __BEGIN_DECLS @@ -43,6 +44,9 @@ struct pollfd { short revents; }; -int poll(struct pollfd* fds, int nfds, int timeout); +typedef unsigned nfds_t; + +int poll(struct pollfd* fds, nfds_t nfds, int timeout); +int ppoll(struct pollfd* fds, nfds_t nfds, const struct timespec* timeout, const sigset_t* sigmask); __END_DECLS |