Skip to content

Commit

Permalink
LibC: Implement pselect
Browse files Browse the repository at this point in the history
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().
  • Loading branch information
nico authored and awesomekling committed Jun 22, 2020
1 parent 29f509a commit d23e655
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 19 deletions.
34 changes: 23 additions & 11 deletions Kernel/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down
6 changes: 3 additions & 3 deletions Kernel/Scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
}

Expand Down
3 changes: 2 additions & 1 deletion Kernel/Syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions Kernel/Thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,12 @@ class Thread {
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;
Expand Down
16 changes: 14 additions & 2 deletions Libraries/LibC/sys/select.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 2 additions & 0 deletions Libraries/LibC/sys/select.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@
#pragma once

#include <fd_set.h>
#include <signal.h>
#include <string.h>
#include <sys/cdefs.h>
#include <sys/types.h>

__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

0 comments on commit d23e655

Please sign in to comment.