Implement ppoll(2) timeouts.
This commit is contained in:
parent
0045f18c81
commit
802c12e64a
|
@ -25,14 +25,17 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <errno.h>
|
#include <timespec.h>
|
||||||
|
|
||||||
|
#include <sortix/clock.h>
|
||||||
#include <sortix/poll.h>
|
#include <sortix/poll.h>
|
||||||
#include <sortix/sigset.h>
|
#include <sortix/sigset.h>
|
||||||
#include <sortix/timespec.h>
|
#include <sortix/timespec.h>
|
||||||
|
|
||||||
|
#include <sortix/kernel/clock.h>
|
||||||
#include <sortix/kernel/copy.h>
|
#include <sortix/kernel/copy.h>
|
||||||
#include <sortix/kernel/descriptor.h>
|
#include <sortix/kernel/descriptor.h>
|
||||||
#include <sortix/kernel/ioctx.h>
|
#include <sortix/kernel/ioctx.h>
|
||||||
|
@ -41,6 +44,8 @@
|
||||||
#include <sortix/kernel/poll.h>
|
#include <sortix/kernel/poll.h>
|
||||||
#include <sortix/kernel/process.h>
|
#include <sortix/kernel/process.h>
|
||||||
#include <sortix/kernel/syscall.h>
|
#include <sortix/kernel/syscall.h>
|
||||||
|
#include <sortix/kernel/time.h>
|
||||||
|
#include <sortix/kernel/timer.h>
|
||||||
|
|
||||||
#include "poll.h"
|
#include "poll.h"
|
||||||
|
|
||||||
|
@ -177,6 +182,21 @@ static bool FetchTimespec(struct timespec* dest, const struct timespec* user)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct poll_timeout
|
||||||
|
{
|
||||||
|
kthread_mutex_t* wake_mutex;
|
||||||
|
kthread_cond_t* wake_cond;
|
||||||
|
bool* woken;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void poll_timeout_callback(Clock*, Timer*, void* ctx)
|
||||||
|
{
|
||||||
|
struct poll_timeout* pts = (struct poll_timeout*) ctx;
|
||||||
|
ScopedLock lock(pts->wake_mutex);
|
||||||
|
*pts->woken = true;
|
||||||
|
kthread_cond_signal(pts->wake_cond);
|
||||||
|
}
|
||||||
|
|
||||||
int sys_ppoll(struct pollfd* user_fds, size_t nfds,
|
int sys_ppoll(struct pollfd* user_fds, size_t nfds,
|
||||||
const struct timespec* user_timeout_ts,
|
const struct timespec* user_timeout_ts,
|
||||||
const sigset_t* user_sigmask)
|
const sigset_t* user_sigmask)
|
||||||
|
@ -187,7 +207,7 @@ int sys_ppoll(struct pollfd* user_fds, size_t nfds,
|
||||||
if ( !FetchTimespec(&timeout_ts, user_timeout_ts) )
|
if ( !FetchTimespec(&timeout_ts, user_timeout_ts) )
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if ( 0 < timeout_ts.tv_sec || timeout_ts.tv_nsec || user_sigmask )
|
if ( user_sigmask )
|
||||||
return errno = ENOSYS, -1;
|
return errno = ENOSYS, -1;
|
||||||
|
|
||||||
struct pollfd* fds = CopyFdsFromUser(user_fds, nfds);
|
struct pollfd* fds = CopyFdsFromUser(user_fds, nfds);
|
||||||
|
@ -205,9 +225,23 @@ int sys_ppoll(struct pollfd* user_fds, size_t nfds,
|
||||||
|
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
bool self_woken = false;
|
bool self_woken = false;
|
||||||
volatile bool remote_woken = false;
|
bool remote_woken = false;
|
||||||
bool unexpected_error = false;
|
bool unexpected_error = false;
|
||||||
|
|
||||||
|
Timer timer;
|
||||||
|
struct poll_timeout pts;
|
||||||
|
if ( timespec_le(timespec_make(0, 1), timeout_ts) )
|
||||||
|
{
|
||||||
|
timer.Attach(Time::GetClock(CLOCK_MONOTONIC));
|
||||||
|
struct itimerspec its;
|
||||||
|
its.it_interval = timespec_nul();
|
||||||
|
its.it_value = timeout_ts;
|
||||||
|
pts.wake_mutex = &wakeup_mutex;
|
||||||
|
pts.wake_cond = &wakeup_cond;
|
||||||
|
pts.woken = &remote_woken;
|
||||||
|
timer.Set(&its, NULL, 0, poll_timeout_callback, &pts);
|
||||||
|
}
|
||||||
|
|
||||||
size_t reqs;
|
size_t reqs;
|
||||||
for ( reqs = 0; !unexpected_error && reqs < nfds; )
|
for ( reqs = 0; !unexpected_error && reqs < nfds; )
|
||||||
{
|
{
|
||||||
|
@ -229,7 +263,7 @@ int sys_ppoll(struct pollfd* user_fds, size_t nfds,
|
||||||
node->revents = 0;
|
node->revents = 0;
|
||||||
node->wake_mutex = &wakeup_mutex;
|
node->wake_mutex = &wakeup_mutex;
|
||||||
node->wake_cond = &wakeup_cond;
|
node->wake_cond = &wakeup_cond;
|
||||||
node->woken = (bool*) &remote_woken;
|
node->woken = &remote_woken;
|
||||||
reqs++;
|
reqs++;
|
||||||
// TODO: How should errors be handled?
|
// TODO: How should errors be handled?
|
||||||
if ( desc->poll(&ctx, node) == 0 )
|
if ( desc->poll(&ctx, node) == 0 )
|
||||||
|
@ -240,7 +274,7 @@ int sys_ppoll(struct pollfd* user_fds, size_t nfds,
|
||||||
unexpected_error = self_woken = true;
|
unexpected_error = self_woken = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( timeout_ts.tv_sec == 0 )
|
if ( timeout_ts.tv_sec == 0 && timeout_ts.tv_nsec == 0 )
|
||||||
self_woken = true;
|
self_woken = true;
|
||||||
|
|
||||||
while ( !(self_woken || remote_woken) )
|
while ( !(self_woken || remote_woken) )
|
||||||
|
@ -256,6 +290,12 @@ int sys_ppoll(struct pollfd* user_fds, size_t nfds,
|
||||||
if ( 0 <= fds[i].fd )
|
if ( 0 <= fds[i].fd )
|
||||||
nodes[i].Cancel();
|
nodes[i].Cancel();
|
||||||
|
|
||||||
|
if ( timespec_le(timespec_make(0, 1), timeout_ts) )
|
||||||
|
{
|
||||||
|
timer.Cancel();
|
||||||
|
timer.Detach();
|
||||||
|
}
|
||||||
|
|
||||||
if ( !unexpected_error )
|
if ( !unexpected_error )
|
||||||
{
|
{
|
||||||
int num_events = 0;
|
int num_events = 0;
|
||||||
|
|
Loading…
Reference in New Issue