mirror of
https://github.com/RGBCube/serenity
synced 2025-05-23 18:05:08 +00:00
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().
This commit is contained in:
parent
29f509a2a0
commit
d23e655c83
6 changed files with 46 additions and 19 deletions
|
@ -27,6 +27,7 @@
|
||||||
#include <AK/Demangle.h>
|
#include <AK/Demangle.h>
|
||||||
#include <AK/RefPtr.h>
|
#include <AK/RefPtr.h>
|
||||||
#include <AK/ScopeGuard.h>
|
#include <AK/ScopeGuard.h>
|
||||||
|
#include <AK/ScopedValueRollback.h>
|
||||||
#include <AK/StdLibExtras.h>
|
#include <AK/StdLibExtras.h>
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
#include <AK/Time.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* readfds = params->readfds;
|
||||||
fd_set* writefds = params->writefds;
|
fd_set* writefds = params->writefds;
|
||||||
fd_set* exceptfds = params->exceptfds;
|
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))
|
if (writefds && !validate_write_typed(writefds))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
@ -2968,16 +2970,24 @@ int Process::sys$select(const Syscall::SC_select_params* params)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (timeout && !validate_read_typed(timeout))
|
if (timeout && !validate_read_typed(timeout))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
if (sigmask && !validate_read_typed(sigmask))
|
||||||
|
return -EFAULT;
|
||||||
if (nfds < 0)
|
if (nfds < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
timeval computed_timeout;
|
timespec computed_timeout;
|
||||||
bool select_has_timeout = false;
|
bool select_has_timeout = false;
|
||||||
if (timeout && (timeout->tv_sec || timeout->tv_usec)) {
|
if (timeout && (timeout->tv_sec || timeout->tv_nsec)) {
|
||||||
timeval_add(Scheduler::time_since_boot(), *timeout, computed_timeout);
|
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;
|
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 rfds;
|
||||||
Thread::SelectBlocker::FDVector wfds;
|
Thread::SelectBlocker::FDVector wfds;
|
||||||
Thread::SelectBlocker::FDVector efds;
|
Thread::SelectBlocker::FDVector efds;
|
||||||
|
@ -3061,18 +3071,20 @@ int Process::sys$poll(pollfd* fds, int nfds, int timeout)
|
||||||
wfds.append(fds[i].fd);
|
wfds.append(fds[i].fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
timeval actual_timeout;
|
timespec actual_timeout;
|
||||||
bool has_timeout = false;
|
bool has_timeout = false;
|
||||||
if (timeout >= 0) {
|
if (timeout >= 0) {
|
||||||
// poll is in ms, we want s/us.
|
// poll is in ms, we want s/ns.
|
||||||
struct timeval tvtimeout;
|
struct timespec tstimeout;
|
||||||
tvtimeout.tv_sec = 0;
|
tstimeout.tv_sec = 0;
|
||||||
while (timeout >= 1000) {
|
while (timeout >= 1000) {
|
||||||
tvtimeout.tv_sec += 1;
|
tstimeout.tv_sec += 1;
|
||||||
timeout -= 1000;
|
timeout -= 1000;
|
||||||
}
|
}
|
||||||
tvtimeout.tv_usec = timeout * 1000;
|
tstimeout.tv_nsec = timeout * 1000 * 1000;
|
||||||
timeval_add(Scheduler::time_since_boot(), tvtimeout, actual_timeout);
|
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;
|
has_timeout = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -210,8 +210,8 @@ bool Thread::SleepBlocker::should_unblock(Thread&, time_t, long)
|
||||||
return m_wakeup_time <= g_uptime;
|
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)
|
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(tv)
|
: m_select_timeout(ts)
|
||||||
, m_select_has_timeout(select_has_timeout)
|
, m_select_has_timeout(select_has_timeout)
|
||||||
, m_select_read_fds(read_fds)
|
, m_select_read_fds(read_fds)
|
||||||
, m_select_write_fds(write_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)
|
bool Thread::SelectBlocker::should_unblock(Thread& thread, time_t now_sec, long now_usec)
|
||||||
{
|
{
|
||||||
if (m_select_has_timeout) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -269,7 +269,8 @@ struct SC_select_params {
|
||||||
fd_set* readfds;
|
fd_set* readfds;
|
||||||
fd_set* writefds;
|
fd_set* writefds;
|
||||||
fd_set* exceptfds;
|
fd_set* exceptfds;
|
||||||
struct timeval* timeout;
|
const struct timespec* timeout;
|
||||||
|
const u32* sigmask;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SC_clock_nanosleep_params {
|
struct SC_clock_nanosleep_params {
|
||||||
|
|
|
@ -219,12 +219,12 @@ public:
|
||||||
class SelectBlocker final : public Blocker {
|
class SelectBlocker final : public Blocker {
|
||||||
public:
|
public:
|
||||||
typedef Vector<int, FD_SETSIZE> FDVector;
|
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 bool should_unblock(Thread&, time_t, long) override;
|
||||||
virtual const char* state_string() const override { return "Selecting"; }
|
virtual const char* state_string() const override { return "Selecting"; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
timeval m_select_timeout;
|
timespec m_select_timeout;
|
||||||
bool m_select_has_timeout { false };
|
bool m_select_has_timeout { false };
|
||||||
const FDVector& m_select_read_fds;
|
const FDVector& m_select_read_fds;
|
||||||
const FDVector& m_select_write_fds;
|
const FDVector& m_select_write_fds;
|
||||||
|
|
|
@ -28,12 +28,24 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
extern "C" {
|
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, ¶ms);
|
int rc = syscall(SC_select, ¶ms);
|
||||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <fd_set.h>
|
#include <fd_set.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@ -34,5 +35,6 @@
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
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, 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
|
__END_DECLS
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue