summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2013-02-26 22:24:47 +0100
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2013-02-28 18:23:35 +0100
commit8cd75c4d6b229bb4e3de9264466731e3a32e0133 (patch)
tree89d70f9cd3d4244182a61c5f36389d594aca602d
parentcc36b5a5e2e8df6e633bb767df84ac1e61c56bc3 (diff)
Add io_select_timeout to the io interface
This change fixes a problem that can occur with non-blocking (and also blocking for very short times) select/poll calls. The problem occurs because the timeout is implemented at the client side. For a non-blocking call, this means that (depending on the code path taken in the C library) the client could get a timeout without a full RPC round-trip to the server. Moving the implementation of the timeout to the servers guarantees a full round-trip, and correct results for non-blocking calls. The modifications in this change depend on the availability of the recently added pthread_hurd_cond_timedwait_np function in libpthread. * boot/boot.c (io_select_common): New static function. (S_io_select): Use io_select_common. (S_io_select_timeout): New function which makes use of io_select_common. * console-client/kbd-repeat.c (repeater_select): Add a timeout parameter. * console-client/pc-mouse.c (repeater_select): Likewise. * console-client/trans.c (io_select_common): New static function. (netfs_S_io_select): Use io_select_common. (netfs_S_io_select_timeout): New function which makes use of io_select_common. * console-client/trans.h (struct consnode): Add a timeout parameter. * hurd/io.defs (io_select_timeout): New MIG routine. * hurd/io_reply.defs (io_select_timeout_reply): New MIG simpleroutine. * hurd/io_request.defs (io_select_timeout_request): Likewise. * libdiskfs/io-select.c (diskfs_S_io_select_timeout): New function. * libnetfs/io-select.c (netfs_S_io_select_timeout): Likewise. * libpipe/pipe.c (pipe_pair_select): Add a timeout parameter. * libpipe/pipe.h (pipe_select_readable): Likewise. (pipe_select_writable): Likewise. (pipe_pair_select): Likewise. * libpipe/pq.h: Include <hurd/hurd_types.h>. * libtrivfs/io-select.c (trivfs_S_io_select_timeout): New function. * pfinet/glue-include/linux/sched.h: Include <errno.h>. (interruptible_sleep_on): Function removed, replaced with ... (interruptible_sleep_on_timeout): New function. (schedule): Update to use interruptible_sleep_on_timeout. (schedule_timeout): Likewise. * pfinet/io-ops.c (io_select_common): New static function. (S_io_select): Use io_select_common. (S_io_select_timeout): New function which makes use of io_select_common. * pfinet/tunnel.c (io_select_common): New static function. (trivfs_S_io_select): Use io_select_common. (trivfs_S_io_select_timeout): New function which makes use of io_select_common. * pflocal/connq.c (connq_listen): Replace noblock with a timeout parameter. * pflocal/connq.h: Include <hurd/hurd_types.h>. (connq_listen): Update declaration to replace noblock with a timeout parameter. * pflocal/io.c (io_select_common): New static function. (S_io_select): Use io_select_common. (S_io_select_timeout): New function which makes use of io_select_common. * pflocal/socket.c (S_socket_accept): Update call to connq_listen to match new declaration. * storeio/io.c (trivfs_S_io_select_timeout): New function. * term/ptyio.c (pty_io_select): Add a timeout parameter. * term/term.h (pty_io_select): Likewise. * term/users.c (io_select_common): New static function. (trivfs_S_io_select): Use io_select_common. (trivfs_S_io_select_timeout): New function which makes use of io_select_common. * trans/fifo.c (io_select_common): New static function. (trivfs_S_io_select): Use io_select_common. (trivfs_S_io_select_timeout): New function which makes use of io_select_common. * trans/firmlink.c (trivfs_S_io_select_timeout): New function. * trans/new-fifo.c (io_select_common): New static function. (trivfs_S_io_select): Use io_select_common. (trivfs_S_io_select_timeout): New function which makes use of io_select_common. * trans/null.c (trivfs_S_io_select_timeout): New function. * trans/streamio.c (io_select_common): New static function. (trivfs_S_io_select): Use io_select_common. (trivfs_S_io_select_timeout): New function which makes use of io_select_common.
-rw-r--r--boot/boot.c41
-rw-r--r--console-client/kbd-repeat.c13
-rw-r--r--console-client/pc-mouse.c13
-rw-r--r--console-client/trans.c26
-rw-r--r--console-client/trans.h5
-rw-r--r--hurd/io.defs11
-rw-r--r--hurd/io_reply.defs5
-rw-r--r--hurd/io_request.defs6
-rw-r--r--libdiskfs/io-select.c8
-rw-r--r--libnetfs/io-select.c10
-rw-r--r--libpipe/pipe.c16
-rw-r--r--libpipe/pipe.h34
-rw-r--r--libtrivfs/io-select.c10
-rw-r--r--pfinet/glue-include/linux/sched.h15
-rw-r--r--pfinet/io-ops.c44
-rw-r--r--pfinet/tunnel.c40
-rw-r--r--pflocal/connq.c17
-rw-r--r--pflocal/connq.h9
-rw-r--r--pflocal/io.c39
-rw-r--r--pflocal/socket.c4
-rw-r--r--storeio/io.c9
-rw-r--r--term/ptyio.c14
-rw-r--r--term/term.h3
-rw-r--r--term/users.c43
-rw-r--r--trans/fifo.c27
-rw-r--r--trans/firmlink.c9
-rw-r--r--trans/new-fifo.c27
-rw-r--r--trans/null.c9
-rw-r--r--trans/streamio.c36
29 files changed, 441 insertions, 102 deletions
diff --git a/boot/boot.c b/boot/boot.c
index fbbced77..0dbe1c20 100644
--- a/boot/boot.c
+++ b/boot/boot.c
@@ -1588,12 +1588,13 @@ S_io_get_icky_async_id (mach_port_t object,
return EOPNOTSUPP;
}
-kern_return_t
-S_io_select (mach_port_t object,
- mach_port_t reply_port,
- mach_msg_type_name_t reply_type,
- int *type)
+static kern_return_t
+io_select_common (mach_port_t object,
+ mach_port_t reply_port,
+ mach_msg_type_name_t reply_type,
+ struct timespec *tsp, int *type)
{
+ struct timeval tv, *tvp;
fd_set r, w, x;
int n;
@@ -1607,11 +1608,20 @@ S_io_select (mach_port_t object,
FD_SET (0, &w);
FD_SET (0, &x);
+ if (tsp == NULL)
+ tvp = NULL;
+ else
+ {
+ tv.tv_sec = tsp->tv_sec;
+ tv.tv_usec = tsp->tv_nsec / 1000;
+ tvp = &tv;
+ }
+
n = select (1,
(*type & SELECT_READ) ? &r : 0,
(*type & SELECT_WRITE) ? &w : 0,
(*type & SELECT_URG) ? &x : 0,
- 0);
+ tvp);
if (n < 0)
return errno;
@@ -1626,6 +1636,25 @@ S_io_select (mach_port_t object,
}
kern_return_t
+S_io_select (mach_port_t object,
+ mach_port_t reply_port,
+ mach_msg_type_name_t reply_type,
+ int *type)
+{
+ return io_select_common (object, reply_port, reply_type, NULL, type);
+}
+
+kern_return_t
+S_io_select_timeout (mach_port_t object,
+ mach_port_t reply_port,
+ mach_msg_type_name_t reply_type,
+ struct timespec ts,
+ int *type)
+{
+ return io_select_common (object, reply_port, reply_type, &ts, type);
+}
+
+kern_return_t
S_io_stat (mach_port_t object,
mach_port_t reply_port,
mach_msg_type_name_t reply_type,
diff --git a/console-client/kbd-repeat.c b/console-client/kbd-repeat.c
index 641520ca..d3a39d07 100644
--- a/console-client/kbd-repeat.c
+++ b/console-client/kbd-repeat.c
@@ -86,8 +86,11 @@ kbd_repeat_key (kd_event *key)
static error_t
repeater_select (struct protid *cred, mach_port_t reply,
- mach_msg_type_name_t replytype, int *type)
+ mach_msg_type_name_t replytype,
+ struct timespec *tsp, int *type)
{
+ error_t err;
+
if (!cred)
return EOPNOTSUPP;
@@ -109,12 +112,16 @@ repeater_select (struct protid *cred, mach_port_t reply,
}
ports_interrupt_self_on_port_death (cred, reply);
- if (pthread_hurd_cond_wait_np (&select_alert, &global_lock))
+ err = pthread_hurd_cond_timedwait_np (&select_alert, &global_lock, tsp);
+ if (err)
{
*type = 0;
pthread_mutex_unlock (&global_lock);
- return EINTR;
+ if (err == ETIMEDOUT)
+ err = 0;
+
+ return err;
}
}
}
diff --git a/console-client/pc-mouse.c b/console-client/pc-mouse.c
index 2cec2042..8be7ff1c 100644
--- a/console-client/pc-mouse.c
+++ b/console-client/pc-mouse.c
@@ -110,8 +110,11 @@ repeat_event (kd_event *evt)
static error_t
repeater_select (struct protid *cred, mach_port_t reply,
- mach_msg_type_name_t replytype, int *type)
+ mach_msg_type_name_t replytype,
+ struct timespec *tsp, int *type)
{
+ error_t err;
+
if (!cred)
return EOPNOTSUPP;
@@ -133,12 +136,16 @@ repeater_select (struct protid *cred, mach_port_t reply,
}
ports_interrupt_self_on_port_death (cred, reply);
- if (pthread_hurd_cond_wait_np (&select_alert, &global_lock))
+ err = pthread_hurd_cond_timedwait_np (&select_alert, &global_lock, tsp);
+ if (err)
{
*type = 0;
pthread_mutex_unlock (&global_lock);
- return EINTR;
+ if (err == ETIMEDOUT)
+ err = 0;
+
+ return err;
}
}
}
diff --git a/console-client/trans.c b/console-client/trans.c
index 67c84b4e..6949af5e 100644
--- a/console-client/trans.c
+++ b/console-client/trans.c
@@ -332,9 +332,10 @@ netfs_S_io_seek (struct protid *user, off_t offset,
}
-error_t
-netfs_S_io_select (struct protid *user, mach_port_t reply,
- mach_msg_type_name_t replytype, int *type)
+static error_t
+io_select_common (struct protid *user, mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ struct timespec *tsp, int *type)
{
struct node *np;
@@ -344,11 +345,28 @@ netfs_S_io_select (struct protid *user, mach_port_t reply,
np = user->po->np;
if (np->nn->node && np->nn->node->select)
- return np->nn->node->select (user, reply, replytype, type);
+ return np->nn->node->select (user, reply, replytype, tsp, type);
return EOPNOTSUPP;
}
+error_t
+netfs_S_io_select (struct protid *user, mach_port_t reply,
+ mach_msg_type_name_t replytype, int *type)
+{
+ return io_select_common (user, reply, replytype, NULL, type);
+}
+
+
+error_t
+netfs_S_io_select_timeout (struct protid *user, mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ struct timespec ts, int *type)
+{
+ return io_select_common (user, reply, replytype, &ts, type);
+}
+
+
/* Delete NAME in DIR (which is locked) for USER. */
error_t
netfs_attempt_unlink (struct iouser *user, struct node *dir,
diff --git a/console-client/trans.h b/console-client/trans.h
index f781e31f..9891cf3f 100644
--- a/console-client/trans.h
+++ b/console-client/trans.h
@@ -41,9 +41,10 @@ struct consnode
mach_msg_type_number_t datalen, off_t offset,
mach_msg_type_number_t *amount);
- /* This is exactly the same as io_select does. */
+ /* This is exactly the same as io_select{,_timeout} do. */
error_t (*select) (struct protid *user, mach_port_t reply,
- mach_msg_type_name_t replytype, int *type);
+ mach_msg_type_name_t replytype,
+ struct timespec *tsp, int *type);
/* Called when the node is opened. */
void (*open) (void);
diff --git a/hurd/io.defs b/hurd/io.defs
index 9119b05b..ba0b8077 100644
--- a/hurd/io.defs
+++ b/hurd/io.defs
@@ -320,3 +320,14 @@ routine io_identity (
on the specified object. */
routine io_revoke (
io_object: io_t RPTLAST);
+
+/* INTR */
+routine io_select_timeout (
+ io_object: io_t;
+#if defined (REPLY_PORTS) || defined (IO_SELECT_REPLY_PORT)
+ replyport reply: sreply_port_t;
+#else
+ ureplyport reply: mach_port_make_send_t;
+#endif
+ timeout: timespec_t;
+ inout select_type: int);
diff --git a/hurd/io_reply.defs b/hurd/io_reply.defs
index ffc4e752..eee68244 100644
--- a/hurd/io_reply.defs
+++ b/hurd/io_reply.defs
@@ -175,3 +175,8 @@ simpleroutine io_identity_reply (
simpleroutine io_revoke_reply (
reply: reply_port_t;
RETURN_CODE_ARG);
+
+simpleroutine io_select_timeout_reply (
+ reply: reply_port_t;
+ RETURN_CODE_ARG;
+ select_result: int);
diff --git a/hurd/io_request.defs b/hurd/io_request.defs
index a3e775aa..0d5e36dd 100644
--- a/hurd/io_request.defs
+++ b/hurd/io_request.defs
@@ -172,3 +172,9 @@ simpleroutine io_identity_request (
simpleroutine io_revoke_request (
io_object: io_t;
reply: reply_port_t);
+
+simpleroutine io_select_timeout_request (
+ io_object: io_t;
+ ureplyport reply: mach_port_make_send_t;
+ timeout: timespec_t;
+ select_type: int);
diff --git a/libdiskfs/io-select.c b/libdiskfs/io-select.c
index 07112f7b..ddac738f 100644
--- a/libdiskfs/io-select.c
+++ b/libdiskfs/io-select.c
@@ -30,3 +30,11 @@ diskfs_S_io_select (struct protid *cred,
*type &= ~SELECT_URG;
return 0;
}
+
+kern_return_t
+diskfs_S_io_select_timeout (struct protid *cred,
+ struct timespec ts,
+ int *type)
+{
+ return diskfs_S_io_select (cred, type);
+}
diff --git a/libnetfs/io-select.c b/libnetfs/io-select.c
index c72eba6b..63036145 100644
--- a/libnetfs/io-select.c
+++ b/libnetfs/io-select.c
@@ -34,3 +34,13 @@ netfs_S_io_select (struct protid *user,
*type &= ~SELECT_URG;
return 0;
}
+
+error_t
+netfs_S_io_select_timeout (struct protid *user,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ struct timespec ts,
+ int *type)
+{
+ return netfs_S_io_select (user, reply, replytype, type);
+}
diff --git a/libpipe/pipe.c b/libpipe/pipe.c
index dd306f60..1ddaf126 100644
--- a/libpipe/pipe.c
+++ b/libpipe/pipe.c
@@ -209,7 +209,7 @@ void _pipe_no_writers (struct pipe *pipe)
this function (unlike most pipe functions). */
error_t
pipe_pair_select (struct pipe *rpipe, struct pipe *wpipe,
- int *select_type, int data_only)
+ struct timespec *tsp, int *select_type, int data_only)
{
error_t err = 0;
@@ -218,13 +218,13 @@ pipe_pair_select (struct pipe *rpipe, struct pipe *wpipe,
if (*select_type == SELECT_READ)
{
pthread_mutex_lock (&rpipe->lock);
- err = pipe_select_readable (rpipe, data_only);
+ err = pipe_select_readable (rpipe, tsp, data_only);
pthread_mutex_unlock (&rpipe->lock);
}
else if (*select_type == SELECT_WRITE)
{
pthread_mutex_lock (&wpipe->lock);
- err = pipe_select_writable (wpipe);
+ err = pipe_select_writable (wpipe, tsp);
pthread_mutex_unlock (&wpipe->lock);
}
else
@@ -260,8 +260,8 @@ pipe_pair_select (struct pipe *rpipe, struct pipe *wpipe,
pthread_mutex_unlock (&rpipe->lock);
pthread_mutex_unlock (&wpipe->lock);
}
- if (pthread_hurd_cond_wait_np (&pending_select.cond, lock))
- err = EINTR;
+ err = pthread_hurd_cond_timedwait_np (&pending_select.cond, lock,
+ tsp);
if (rpipe != wpipe)
{
pthread_mutex_lock (&rpipe->lock);
@@ -295,6 +295,12 @@ pipe_pair_select (struct pipe *rpipe, struct pipe *wpipe,
pthread_mutex_unlock (lock);
}
+ if (err == ETIMEDOUT)
+ {
+ err = 0;
+ *select_type = 0;
+ }
+
return err;
}
diff --git a/libpipe/pipe.h b/libpipe/pipe.h
index b8e70681..040204d5 100644
--- a/libpipe/pipe.h
+++ b/libpipe/pipe.h
@@ -126,11 +126,12 @@ extern int pipe_is_readable (struct pipe *pipe, int data_only);
extern error_t pipe_wait_readable (struct pipe *pipe, int noblock, int data_only);
-extern error_t pipe_select_readable (struct pipe *pipe, int data_only);
+extern error_t pipe_select_readable (struct pipe *pipe, struct timespec *tsp,
+ int data_only);
extern error_t pipe_wait_writable (struct pipe *pipe, int noblock);
-extern error_t pipe_select_writable (struct pipe *pipe);
+extern error_t pipe_select_writable (struct pipe *pipe, struct timespec *tsp);
#if defined(__USE_EXTERN_INLINES) || defined(PIPE_DEFINE_EI)
@@ -188,12 +189,17 @@ pipe_wait_readable (struct pipe *pipe, int noblock, int data_only)
given a chance to read, and if there is still data available thereafter.
If DATA_ONLY is true, then `control' packets are ignored. */
PIPE_EI error_t
-pipe_select_readable (struct pipe *pipe, int data_only)
+pipe_select_readable (struct pipe *pipe, struct timespec *tsp, int data_only)
{
+ error_t err = 0;
while (! pipe_is_readable (pipe, data_only) && ! (pipe->flags & PIPE_BROKEN))
- if (pthread_hurd_cond_wait_np (&pipe->pending_read_selects, &pipe->lock))
- return EINTR;
- return 0;
+ {
+ err = pthread_hurd_cond_timedwait_np (&pipe->pending_read_selects,
+ &pipe->lock, tsp);
+ if (err)
+ break;
+ }
+ return err;
}
/* Block until data can be written to PIPE. If NOBLOCK is true, then
@@ -221,13 +227,18 @@ pipe_wait_writable (struct pipe *pipe, int noblock)
threads waiting using pipe_wait_writable have been woken and given a
chance to write, and if there is still space available thereafter. */
PIPE_EI error_t
-pipe_select_writable (struct pipe *pipe)
+pipe_select_writable (struct pipe *pipe, struct timespec *tsp)
{
size_t limit = pipe->write_limit;
+ error_t err = 0;
while (! (pipe->flags & PIPE_BROKEN) && pipe_readable (pipe, 1) >= limit)
- if (pthread_hurd_cond_wait_np (&pipe->pending_writes, &pipe->lock))
- return EINTR;
- return 0;
+ {
+ err = pthread_hurd_cond_timedwait_np (&pipe->pending_writes,
+ &pipe->lock, tsp);
+ if (err)
+ break;
+ }
+ return err;
}
#endif /* Use extern inlines. */
@@ -419,7 +430,8 @@ extern pthread_mutex_t pipe_multiple_lock;
waited for on RPIPE. Neither RPIPE or WPIPE should be locked when calling
this function (unlike most pipe functions). */
error_t pipe_pair_select (struct pipe *rpipe, struct pipe *wpipe,
- int *select_type, int data_only);
+ struct timespec *tsp, int *select_type,
+ int data_only);
/* ---------------------------------------------------------------- */
/* User-provided functions. */
diff --git a/libtrivfs/io-select.c b/libtrivfs/io-select.c
index 9df24d61..e44a8365 100644
--- a/libtrivfs/io-select.c
+++ b/libtrivfs/io-select.c
@@ -36,3 +36,13 @@ trivfs_S_io_select (struct trivfs_protid *cred,
assert (!trivfs_support_write);
return EOPNOTSUPP;
}
+
+kern_return_t
+trivfs_S_io_select_timeout (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ struct timespec ts,
+ int *seltype)
+{
+ return trivfs_S_io_select (cred, reply, replytype, seltype);
+}
diff --git a/pfinet/glue-include/linux/sched.h b/pfinet/glue-include/linux/sched.h
index aea6c47a..26ab10a8 100644
--- a/pfinet/glue-include/linux/sched.h
+++ b/pfinet/glue-include/linux/sched.h
@@ -8,6 +8,7 @@
#include <limits.h>
#include <assert.h>
#include <pthread.h>
+#include <errno.h>
#include "mapped-time.h"
@@ -92,12 +93,13 @@ capable(int cap)
extern pthread_mutex_t global_lock;
-static inline void
-interruptible_sleep_on (struct wait_queue **p)
+static inline int
+interruptible_sleep_on_timeout (struct wait_queue **p, struct timespec *tsp)
{
pthread_cond_t **condp = (void *) p, *c;
int isroot;
struct wait_queue **next_wait;
+ error_t err;
c = *condp;
if (c == 0)
@@ -111,12 +113,13 @@ interruptible_sleep_on (struct wait_queue **p)
isroot = current->isroot; /* This is our context that needs switched. */
next_wait = current->next_wait; /* This too, for multiple schedule calls. */
current->next_wait = 0;
- if (pthread_hurd_cond_wait_np (c, &global_lock))
+ err = pthread_hurd_cond_timedwait_np(c, &global_lock, tsp);
+ if (err == EINTR)
current->signal = 1; /* We got cancelled, mark it for later. */
current->isroot = isroot; /* Switch back to our context. */
current->next_wait = next_wait;
+ return (err == ETIMEDOUT);
}
-#define sleep_on interruptible_sleep_on
static inline void
wake_up_interruptible (struct wait_queue **p)
@@ -146,7 +149,7 @@ static inline void
schedule (void)
{
assert (current->next_wait);
- interruptible_sleep_on (current->next_wait);
+ interruptible_sleep_on_timeout (current->next_wait, NULL);
}
static inline void
@@ -171,7 +174,7 @@ schedule_timeout (long timeout)
timer.function = process_schedule_timeout;
add_timer (&timer);
- interruptible_sleep_on (&sleep);
+ interruptible_sleep_on_timeout (&sleep, NULL);
if (signal_pending (current))
{
/* We were canceled. */
diff --git a/pfinet/io-ops.c b/pfinet/io-ops.c
index 5f3b1e90..69bd93c5 100644
--- a/pfinet/io-ops.c
+++ b/pfinet/io-ops.c
@@ -251,14 +251,14 @@ S_io_clear_some_openmodes (struct sock_user *user,
return 0;
}
-error_t
-S_io_select (struct sock_user *user,
- mach_port_t reply,
- mach_msg_type_name_t reply_type,
- int *select_type)
+static error_t
+io_select_common (struct sock_user *user,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ struct timespec *tsp, int *select_type)
{
const int want = *select_type | POLLERR;
- int avail;
+ int avail, timedout;
int ret = 0;
if (!user)
@@ -281,9 +281,16 @@ S_io_select (struct sock_user *user,
do
{
- /* Block until we are woken or cancelled. */
- interruptible_sleep_on (user->sock->sk->sleep);
- if (signal_pending (current)) /* This means we were cancelled. */
+ /* Block until we time out, are woken or cancelled. */
+ timedout = interruptible_sleep_on_timeout (user->sock->sk->sleep,
+ tsp);
+ if (timedout)
+ {
+ __mutex_unlock (&global_lock);
+ *select_type = 0;
+ return 0;
+ }
+ else if (signal_pending (current)) /* This means we were cancelled. */
{
pthread_mutex_unlock (&global_lock);
return EINTR;
@@ -307,6 +314,25 @@ S_io_select (struct sock_user *user,
}
error_t
+S_io_select (struct sock_user *user,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int *select_type)
+{
+ return io_select_common (user, reply, reply_type, NULL, select_type);
+}
+
+error_t
+S_io_select_timeout (struct sock_user *user,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ struct timespec ts,
+ int *select_type)
+{
+ return io_select_common (user, reply, reply_type, &ts, select_type);
+}
+
+error_t
S_io_stat (struct sock_user *user,
struct stat *st)
{
diff --git a/pfinet/tunnel.c b/pfinet/tunnel.c
index 5d2544b2..4a6f616a 100644
--- a/pfinet/tunnel.c
+++ b/pfinet/tunnel.c
@@ -462,13 +462,14 @@ trivfs_S_io_readable (struct trivfs_protid *cred,
return the types that are then available. ID_TAG is returned as passed; it
is just for the convenience of the user in matching up reply messages with
specific requests sent. */
-error_t
-trivfs_S_io_select (struct trivfs_protid *cred,
- mach_port_t reply,
- mach_msg_type_name_t reply_type,
- int *type)
+static error_t
+io_select_common (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ struct timespec *tsp, int *type)
{
struct tunnel_device *tdev;
+ error_t err;
if (!cred)
return EOPNOTSUPP;
@@ -497,15 +498,40 @@ trivfs_S_io_select (struct trivfs_protid *cred,
ports_interrupt_self_on_port_death (cred, reply);
tdev->read_blocked = 1;
- if (pthread_hurd_cond_wait_np (&tdev->select_alert, &tdev->lock))
+ err = pthread_hurd_cond_timedwait_np (&tdev->select_alert, &tdev->lock,
+ tsp);
+ if (err)
{
*type = 0;
pthread_mutex_unlock (&tdev->lock);
- return EINTR;
+
+ if (err == ETIMEDOUT)
+ err = 0;
+
+ return err;
}
}
}
+error_t
+trivfs_S_io_select (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int *type)
+{
+ return io_select_common (cred, reply, reply_type, NULL, type);
+}
+
+error_t
+trivfs_S_io_select_timeout (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ struct timespec ts,
+ int *type)
+{
+ return io_select_common (cred, reply, reply_type, &ts, type);
+}
+
/* Change current read/write offset */
error_t
trivfs_S_io_seek (struct trivfs_protid *cred,
diff --git a/pflocal/connq.c b/pflocal/connq.c
index ab2b3a55..d88711e3 100644
--- a/pflocal/connq.c
+++ b/pflocal/connq.c
@@ -141,16 +141,19 @@ connq_destroy (struct connq *cq)
/* ---------------------------------------------------------------- */
/* Return a connection request on CQ. If SOCK is NULL, the request is
- left in the queue. If NOBLOCK is true, EWOULDBLOCK is returned
- when there are no immediate connections available. */
+ left in the queue. If TIMEOUT denotes a value of 0, EWOULDBLOCK is
+ returned when there are no immediate connections available.
+ Otherwise this value is used to limit the wait duration. If TIMEOUT
+ is NULL, the wait duration isn't bounded. */
error_t
-connq_listen (struct connq *cq, int noblock, struct sock **sock)
+connq_listen (struct connq *cq, struct timespec *tsp, struct sock **sock)
{
error_t err = 0;
pthread_mutex_lock (&cq->lock);
- if (noblock && cq->count == 0 && cq->num_connectors == 0)
+ if (tsp && tsp->tv_sec == 0 && tsp->tv_nsec == 0 && cq->count == 0
+ && cq->num_connectors == 0)
{
pthread_mutex_unlock (&cq->lock);
return EWOULDBLOCK;
@@ -176,12 +179,14 @@ connq_listen (struct connq *cq, int noblock, struct sock **sock)
pthread_cond_signal (&cq->connectors);
do
- if (pthread_hurd_cond_wait_np (&cq->listeners, &cq->lock))
+ {
+ err = pthread_hurd_cond_timedwait_np (&cq->listeners, &cq->lock, tsp);
+ if (err)
{
cq->num_listeners--;
- err = EINTR;
goto out;
}
+ }
while (cq->count == 0);
}
diff --git a/pflocal/connq.h b/pflocal/connq.h
index 9278d007..71583800 100644
--- a/pflocal/connq.h
+++ b/pflocal/connq.h
@@ -36,9 +36,12 @@ error_t connq_create (struct connq **cq);
void connq_destroy (struct connq *cq);
/* Return a connection request on CQ. If SOCK is NULL, the request is
- left in the queue. If NOBLOCK is true, EWOULDBLOCK is returned
- when there are no immediate connections available. */
-error_t connq_listen (struct connq *cq, int noblock, struct sock **sock);
+ left in the queue. If TIMEOUT denotes a value of 0, EWOULDBLOCK is
+ returned when there are no immediate connections available.
+ Otherwise this value is used to limit the wait duration. If TIMEOUT
+ is NULL, the wait duration isn't bounded. */
+error_t connq_listen (struct connq *cq, struct timespec *tsp,
+ struct sock **sock);
/* Try to connect SOCK with the socket listening on CQ. If NOBLOCK is
true, then return EWOULDBLOCK if there are no connections
diff --git a/pflocal/io.c b/pflocal/io.c
index 2301611e..0dec56e0 100644
--- a/pflocal/io.c
+++ b/pflocal/io.c
@@ -172,10 +172,10 @@ S_io_duplicate (struct sock_user *user,
/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
Block until one of the indicated types of i/o can be done "quickly", and
return the types that are then available. */
-error_t
-S_io_select (struct sock_user *user,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- int *select_type)
+static error_t
+io_select_common (struct sock_user *user,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ struct timespec *tsp, int *select_type)
{
error_t err = 0;
struct sock *sock;
@@ -199,16 +199,24 @@ S_io_select (struct sock_user *user,
if (*select_type & SELECT_READ)
{
+ struct timespec noblock = {0, 0};
+
/* Wait for a connect. Passing in NULL for SOCK means that
the request won't be dequeued. */
- if (connq_listen (sock->listen_queue, 1, NULL) == 0)
+ if (connq_listen (sock->listen_queue, &noblock, NULL) == 0)
/* We can satisfy this request immediately. */
return 0;
else
/* Gotta wait... */
{
ports_interrupt_self_on_port_death (user, reply);
- return connq_listen (sock->listen_queue, 0, NULL);
+ err = connq_listen (sock->listen_queue, tsp, NULL);
+ if (err == ETIMEDOUT)
+ {
+ *select_type = 0;
+ err = 0;
+ }
+ return err;
}
}
}
@@ -261,7 +269,7 @@ S_io_select (struct sock_user *user,
/* Wait for something to change. */
{
ports_interrupt_self_on_port_death (user, reply);
- err = pipe_pair_select (read_pipe, write_pipe, select_type, 1);
+ err = pipe_pair_select (read_pipe, write_pipe, tsp, select_type, 1);
}
if (valid & SELECT_READ)
@@ -272,6 +280,23 @@ S_io_select (struct sock_user *user,
return err;
}
+
+error_t
+S_io_select (struct sock_user *user,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ int *select_type)
+{
+ return io_select_common (user, reply, reply_type, NULL, select_type);
+}
+
+error_t
+S_io_select_timeout (struct sock_user *user,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ struct timespec ts,
+ int *select_type)
+{
+ return io_select_common (user, reply, reply_type, &ts, select_type);
+}
/* Return the current status of the object. Not all the fields of the
io_statuf_t are meaningful for all objects; however, the access and
diff --git a/pflocal/socket.c b/pflocal/socket.c
index 65da7487..ce1edd82 100644
--- a/pflocal/socket.c
+++ b/pflocal/socket.c
@@ -178,9 +178,11 @@ S_socket_accept (struct sock_user *user,
err = ensure_connq (sock);
if (!err)
{
+ struct timespec noblock = {0, 0};
struct sock *peer_sock;
- err = connq_listen (sock->listen_queue, sock->flags & SOCK_NONBLOCK,
+ err = connq_listen (sock->listen_queue,
+ (sock->flags & SOCK_NONBLOCK) ? &noblock : NULL,
&peer_sock);
if (!err)
{
diff --git a/storeio/io.c b/storeio/io.c
index 508df77a..c79f6ba3 100644
--- a/storeio/io.c
+++ b/storeio/io.c
@@ -161,6 +161,15 @@ trivfs_S_io_select (struct trivfs_protid *cred,
return 0;
}
+error_t
+trivfs_S_io_select_timeout (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ struct timespec ts,
+ int *type)
+{
+ return trivfs_S_io_select (cred, reply, reply_type, type);
+}
+
/* Truncate file. */
error_t
trivfs_S_file_set_size (struct trivfs_protid *cred,
diff --git a/term/ptyio.c b/term/ptyio.c
index 0f5ddb01..44a215bb 100644
--- a/term/ptyio.c
+++ b/term/ptyio.c
@@ -459,9 +459,10 @@ pty_io_readable (size_t *amt)
/* Validation has already been done by trivfs_S_io_select. */
error_t
pty_io_select (struct trivfs_protid *cred, mach_port_t reply,
- int *type)
+ struct timespec *tsp, int *type)
{
int avail = 0;
+ error_t err;
if (*type == 0)
return 0;
@@ -488,13 +489,18 @@ pty_io_select (struct trivfs_protid *cred, mach_port_t reply,
}
ports_interrupt_self_on_port_death (cred, reply);
-
pty_read_blocked = 1;
- if (pthread_hurd_cond_wait_np (&pty_select_wakeup, &global_lock))
+ err = pthread_hurd_cond_timedwait_np (&pty_select_wakeup, &global_lock,
+ tsp);
+ if (err)
{
*type = 0;
pthread_mutex_unlock (&global_lock);
- return EINTR;
+
+ if (err == ETIMEDOUT)
+ err = 0;
+
+ return err;
}
}
}
diff --git a/term/term.h b/term/term.h
index f154d4c0..df82b6c9 100644
--- a/term/term.h
+++ b/term/term.h
@@ -386,7 +386,8 @@ error_t pty_io_write (struct trivfs_protid *, char *,
error_t pty_io_read (struct trivfs_protid *, char **,
mach_msg_type_number_t *, mach_msg_type_number_t);
error_t pty_io_readable (size_t *);
-error_t pty_io_select (struct trivfs_protid *, mach_port_t, int *);
+error_t pty_io_select (struct trivfs_protid *, mach_port_t,
+ struct timespec *, int *);
error_t pty_open_hook (struct trivfs_control *, struct iouser *, int);
error_t pty_po_create_hook (struct trivfs_peropen *);
error_t pty_po_destroy_hook (struct trivfs_peropen *);
diff --git a/term/users.c b/term/users.c
index 9fc1dc23..529693e8 100644
--- a/term/users.c
+++ b/term/users.c
@@ -2002,17 +2002,17 @@ trivfs_S_io_async (struct trivfs_protid *cred,
return 0;
}
-error_t
-trivfs_S_io_select (struct trivfs_protid *cred,
- mach_port_t reply,
- mach_msg_type_name_t reply_type,
- int *type)
+static error_t
+io_select_common (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ struct timespec *tsp, int *type)
{
if (!cred)
return EOPNOTSUPP;
if (cred->pi.class == pty_class)
- return pty_io_select (cred, reply, type);
+ return pty_io_select (cred, reply, tsp, type);
if ((cred->po->openmodes & O_READ) == 0)
*type &= ~SELECT_READ;
@@ -2024,6 +2024,8 @@ trivfs_S_io_select (struct trivfs_protid *cred,
while (1)
{
int available = 0;
+ error_t err = 0;
+
if ((*type & SELECT_READ) && qsize (inputq))
available |= SELECT_READ;
if ((*type & SELECT_WRITE) && qavail (outputq))
@@ -2032,16 +2034,41 @@ trivfs_S_io_select (struct trivfs_protid *cred,
if (available == 0)
{
ports_interrupt_self_on_port_death (cred, reply);
- if (pthread_hurd_cond_wait_np (&select_alert, &global_lock) == 0)
+ err = pthread_hurd_cond_timedwait_np (&select_alert, &global_lock,
+ tsp);
+ if (!err)
continue;
}
*type = available;
pthread_mutex_unlock (&global_lock);
- return available ? 0 : EINTR;
+
+ if (err == ETIMEDOUT)
+ err = 0;
+
+ return err;
}
}
+error_t
+trivfs_S_io_select (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int *type)
+{
+ return io_select_common (cred, reply, reply_type, NULL, type);
+}
+
+error_t
+trivfs_S_io_select_timeout (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ struct timespec ts,
+ int *type)
+{
+ return io_select_common (cred, reply, reply_type, &ts, type);
+}
+
kern_return_t
trivfs_S_io_map (struct trivfs_protid *cred,
mach_port_t reply,
diff --git a/trans/fifo.c b/trans/fifo.c
index b40a50d1..e6fbd0e9 100644
--- a/trans/fifo.c
+++ b/trans/fifo.c
@@ -405,10 +405,10 @@ trivfs_S_io_seek (struct trivfs_protid *cred,
return the types that are then available. ID_TAG is returned as passed; it
is just for the convenience of the user in matching up reply messages with
specific requests sent. */
-error_t
-trivfs_S_io_select (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- int *select_type)
+static error_t
+io_select_common (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ struct timespec *tsp, int *select_type)
{
struct pipe *pipe;
error_t err = 0;
@@ -466,11 +466,28 @@ trivfs_S_io_select (struct trivfs_protid *cred,
/* Wait for something to change. */
{
ports_interrupt_self_on_port_death (cred, reply);
- err = pipe_pair_select (pipe, pipe, select_type, 1);
+ err = pipe_pair_select (pipe, pipe, tsp, select_type, 1);
}
return err;
}
+
+error_t
+trivfs_S_io_select (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ int *select_type)
+{
+ return io_select_common (cred, reply, reply_type, NULL, select_type);
+}
+
+error_t
+trivfs_S_io_select_timeout (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ struct timespec ts,
+ int *select_type)
+{
+ return io_select_common (cred, reply, reply_type, &ts, select_type);
+}
/* ---------------------------------------------------------------- */
diff --git a/trans/firmlink.c b/trans/firmlink.c
index 087e19d0..9c063c04 100644
--- a/trans/firmlink.c
+++ b/trans/firmlink.c
@@ -275,3 +275,12 @@ trivfs_S_io_select (struct trivfs_protid *cred,
{
return EOPNOTSUPP;
}
+
+error_t
+trivfs_S_io_select_timeout (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ struct timespec ts,
+ int *type)
+{
+ return trivfs_S_io_select (cred, reply, reply_type, type);
+}
diff --git a/trans/new-fifo.c b/trans/new-fifo.c
index 5cc44b58..dc3cc79e 100644
--- a/trans/new-fifo.c
+++ b/trans/new-fifo.c
@@ -591,10 +591,10 @@ trivfs_S_io_seek (struct trivfs_protid *cred,
return the types that are then available. ID_TAG is returned as passed; it
is just for the convenience of the user in matching up reply messages with
specific requests sent. */
-error_t
-trivfs_S_io_select (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- int *select_type)
+static error_t
+io_select_common (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ struct timespec *tsp, int *select_type)
{
struct pipe *pipe;
error_t err = 0;
@@ -652,11 +652,28 @@ trivfs_S_io_select (struct trivfs_protid *cred,
/* Wait for something to change. */
{
ports_interrupt_self_on_port_death (cred, reply);
- err = pipe_pair_select (pipe, pipe, select_type, 1);
+ err = pipe_pair_select (pipe, pipe, tsp, select_type, 1);
}
return err;
}
+
+error_t
+trivfs_S_io_select (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ int *select_type)
+{
+ return io_select_common (cred, reply, reply_type, NULL, select_type);
+}
+
+error_t
+trivfs_S_io_select_timeout (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ struct timespec ts,
+ int *select_type)
+{
+ return io_select_common (cred, reply, reply_type, &ts, select_type);
+}
/* ---------------------------------------------------------------- */
diff --git a/trans/null.c b/trans/null.c
index 9673a758..1f985b39 100644
--- a/trans/null.c
+++ b/trans/null.c
@@ -203,6 +203,15 @@ trivfs_S_io_select (struct trivfs_protid *cred,
*type &= ~SELECT_URG;
return 0;
}
+
+kern_return_t
+trivfs_S_io_select_timeout (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ struct timespec ts,
+ int *type)
+{
+ return trivfs_S_io_select (cred, reply, replytype, type);
+}
/* Write data to an IO object. If offset is -1, write at the object
maintained file pointer. If the object is not seekable, offset is
diff --git a/trans/streamio.c b/trans/streamio.c
index 60b5d59c..8ff3dc63 100644
--- a/trans/streamio.c
+++ b/trans/streamio.c
@@ -538,12 +538,14 @@ trivfs_S_io_seek (struct trivfs_protid *cred,
return ESPIPE;
}
-error_t
-trivfs_S_io_select (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- int *type)
+static error_t
+io_select_common (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ struct timespec *tsp,
+ int *type)
{
int available;
+ error_t err;
if (!cred)
return EOPNOTSUPP;
@@ -583,16 +585,38 @@ trivfs_S_io_select (struct trivfs_protid *cred,
}
ports_interrupt_self_on_port_death (cred, reply);
- if (pthread_hurd_cond_wait_np (&select_alert, &global_lock))
+ err = pthread_hurd_cond_timedwait_np (&select_alert, &global_lock, tsp);
+ if (err)
{
*type = 0;
pthread_mutex_unlock (&global_lock);
- return EINTR;
+
+ if (err == ETIMEDOUT)
+ err = 0;
+
+ return err;
}
}
}
error_t
+trivfs_S_io_select (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ int *type)
+{
+ return io_select_common (cred, reply, reply_type, NULL, type);
+}
+
+error_t
+trivfs_S_io_select_timeout (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ struct timespec ts,
+ int *type)
+{
+ return io_select_common (cred, reply, reply_type, &ts, type);
+}
+
+error_t
trivfs_S_file_set_size (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t reply_type,
off_t size)