summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNico Weber <thakis@chromium.org>2020-06-21 13:54:41 -0400
committerAndreas Kling <kling@serenityos.org>2020-06-22 16:00:20 +0200
commitd23e655c83b48d0ca6d8273a5de22644ec6db490 (patch)
tree856f5b78b7e7581b9f9e6566e7380b9c6d1b867d
parent29f509a2a09028950824742f7d23daa3d409ada3 (diff)
downloadserenity-d23e655c83b48d0ca6d8273a5de22644ec6db490.zip
LibC: Implement pselect
pselect() is similar() to select(), but it takes its timeout as timespec instead of as timeval, and it takes an additional sigmask parameter. Change the sys$select parameters to match pselect() and implement select() in terms of pselect().
-rw-r--r--Kernel/Process.cpp34
-rw-r--r--Kernel/Scheduler.cpp6
-rw-r--r--Kernel/Syscall.h3
-rw-r--r--Kernel/Thread.h4
-rw-r--r--Libraries/LibC/sys/select.cpp16
-rw-r--r--Libraries/LibC/sys/select.h2
6 files changed, 46 insertions, 19 deletions
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp
index f902679548..0177fbba6b 100644
--- a/Kernel/Process.cpp
+++ b/Kernel/Process.cpp
@@ -27,6 +27,7 @@
#include <AK/Demangle.h>
#include <AK/RefPtr.h>
#include <AK/ScopeGuard.h>
+#include <AK/ScopedValueRollback.h>
#include <AK/StdLibExtras.h>
#include <AK/StringBuilder.h>
#include <AK/Time.h>
@@ -2958,7 +2959,8 @@ int Process::sys$select(const Syscall::SC_select_params* params)
fd_set* readfds = params->readfds;
fd_set* writefds = params->writefds;
fd_set* exceptfds = params->exceptfds;
- timeval* timeout = params->timeout;
+ const timespec* timeout = params->timeout;
+ const sigset_t* sigmask = params->sigmask;
if (writefds && !validate_write_typed(writefds))
return -EFAULT;
@@ -2968,16 +2970,24 @@ int Process::sys$select(const Syscall::SC_select_params* params)
return -EFAULT;
if (timeout && !validate_read_typed(timeout))
return -EFAULT;
+ if (sigmask && !validate_read_typed(sigmask))
+ return -EFAULT;
if (nfds < 0)
return -EINVAL;
- timeval computed_timeout;
+ timespec computed_timeout;
bool select_has_timeout = false;
- if (timeout && (timeout->tv_sec || timeout->tv_usec)) {
- timeval_add(Scheduler::time_since_boot(), *timeout, computed_timeout);
+ 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, *timeout, computed_timeout);
select_has_timeout = true;
}
+ ScopedValueRollback scoped_sigmask(Thread::current->m_signal_mask);
+ if (sigmask)
+ Thread::current->m_signal_mask = *sigmask;
+
Thread::SelectBlocker::FDVector rfds;
Thread::SelectBlocker::FDVector wfds;
Thread::SelectBlocker::FDVector efds;
@@ -3061,18 +3071,20 @@ int Process::sys$poll(pollfd* fds, int nfds, int timeout)
wfds.append(fds[i].fd);
}
- timeval actual_timeout;
+ timespec actual_timeout;
bool has_timeout = false;
if (timeout >= 0) {
- // poll is in ms, we want s/us.
- struct timeval tvtimeout;
- tvtimeout.tv_sec = 0;
+ // poll is in ms, we want s/ns.
+ struct timespec tstimeout;
+ tstimeout.tv_sec = 0;
while (timeout >= 1000) {
- tvtimeout.tv_sec += 1;
+ tstimeout.tv_sec += 1;
timeout -= 1000;
}
- tvtimeout.tv_usec = timeout * 1000;
- timeval_add(Scheduler::time_since_boot(), tvtimeout, actual_timeout);
+ tstimeout.tv_nsec = timeout * 1000 * 1000;
+ timespec ts_since_boot;
+ timeval_to_timespec(Scheduler::time_since_boot(), ts_since_boot);
+ timespec_add(ts_since_boot, tstimeout, actual_timeout);
has_timeout = true;
}
diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp
index 76156bd283..730b2da773 100644
--- a/Kernel/Scheduler.cpp
+++ b/Kernel/Scheduler.cpp
@@ -210,8 +210,8 @@ bool Thread::SleepBlocker::should_unblock(Thread&, time_t, long)
return m_wakeup_time <= g_uptime;
}
-Thread::SelectBlocker::SelectBlocker(const timeval& tv, bool select_has_timeout, const FDVector& read_fds, const FDVector& write_fds, const FDVector& except_fds)
- : m_select_timeout(tv)
+Thread::SelectBlocker::SelectBlocker(const timespec& ts, bool select_has_timeout, const FDVector& read_fds, const FDVector& write_fds, const FDVector& except_fds)
+ : m_select_timeout(ts)
, m_select_has_timeout(select_has_timeout)
, m_select_read_fds(read_fds)
, m_select_write_fds(write_fds)
@@ -222,7 +222,7 @@ Thread::SelectBlocker::SelectBlocker(const timeval& tv, bool select_has_timeout,
bool Thread::SelectBlocker::should_unblock(Thread& thread, time_t now_sec, long now_usec)
{
if (m_select_has_timeout) {
- if (now_sec > m_select_timeout.tv_sec || (now_sec == m_select_timeout.tv_sec && now_usec >= m_select_timeout.tv_usec))
+ if (now_sec > m_select_timeout.tv_sec || (now_sec == m_select_timeout.tv_sec && now_usec * 1000 >= m_select_timeout.tv_nsec))
return true;
}
diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h
index e593aa985c..d1251d28fc 100644
--- a/Kernel/Syscall.h
+++ b/Kernel/Syscall.h
@@ -269,7 +269,8 @@ struct SC_select_params {
fd_set* readfds;
fd_set* writefds;
fd_set* exceptfds;
- struct timeval* timeout;
+ const struct timespec* timeout;
+ const u32* sigmask;
};
struct SC_clock_nanosleep_params {
diff --git a/Kernel/Thread.h b/Kernel/Thread.h
index d1959ddc63..983e06fed0 100644
--- a/Kernel/Thread.h
+++ b/Kernel/Thread.h
@@ -219,12 +219,12 @@ public:
class SelectBlocker final : public Blocker {
public:
typedef Vector<int, FD_SETSIZE> FDVector;
- SelectBlocker(const timeval& tv, bool select_has_timeout, const FDVector& read_fds, const FDVector& write_fds, const FDVector& except_fds);
+ SelectBlocker(const timespec& ts, bool select_has_timeout, const FDVector& read_fds, const FDVector& write_fds, const FDVector& except_fds);
virtual bool should_unblock(Thread&, time_t, long) override;
virtual const char* state_string() const override { return "Selecting"; }
private:
- timeval m_select_timeout;
+ timespec m_select_timeout;
bool m_select_has_timeout { false };
const FDVector& m_select_read_fds;
const FDVector& m_select_write_fds;
diff --git a/Libraries/LibC/sys/select.cpp b/Libraries/LibC/sys/select.cpp
index a9533d21ac..e4ff159ef4 100644
--- a/Libraries/LibC/sys/select.cpp
+++ b/Libraries/LibC/sys/select.cpp
@@ -28,12 +28,24 @@
#include <errno.h>
#include <stdio.h>
#include <sys/select.h>
+#include <sys/time.h>
extern "C" {
-int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout)
+int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, timeval* timeout_tv)
{
- Syscall::SC_select_params params { nfds, readfds, writefds, exceptfds, timeout };
+ timespec* timeout_ts = nullptr;
+ timespec timeout;
+ if (timeout_tv) {
+ timeout_ts = &timeout;
+ TIMEVAL_TO_TIMESPEC(timeout_tv, timeout_ts);
+ }
+ return pselect(nfds, readfds, writefds, exceptfds, timeout_ts, nullptr);
+}
+
+int pselect(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const timespec* timeout, const sigset_t* sigmask)
+{
+ Syscall::SC_select_params params { nfds, readfds, writefds, exceptfds, timeout, sigmask };
int rc = syscall(SC_select, &params);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
diff --git a/Libraries/LibC/sys/select.h b/Libraries/LibC/sys/select.h
index c32fdabb9b..9d451eb8ed 100644
--- a/Libraries/LibC/sys/select.h
+++ b/Libraries/LibC/sys/select.h
@@ -27,6 +27,7 @@
#pragma once
#include <fd_set.h>
+#include <signal.h>
#include <string.h>
#include <sys/cdefs.h>
#include <sys/types.h>
@@ -34,5 +35,6 @@
__BEGIN_DECLS
int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout);
+int pselect(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const struct timespec* timeout, const sigset_t* sigmask);
__END_DECLS