summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kernel/Process.cpp41
-rw-r--r--Kernel/Process.h2
-rw-r--r--Kernel/Syscall.h8
-rw-r--r--Libraries/LibC/poll.cpp17
-rw-r--r--Libraries/LibC/poll.h6
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, &params);
__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