summaryrefslogtreecommitdiff
path: root/lib/util
diff options
context:
space:
mode:
Diffstat (limited to 'lib/util')
-rw-r--r--lib/util/select.c78
-rw-r--r--lib/util/select.h3
2 files changed, 81 insertions, 0 deletions
diff --git a/lib/util/select.c b/lib/util/select.c
index 61df649526..b40538c473 100644
--- a/lib/util/select.c
+++ b/lib/util/select.c
@@ -208,3 +208,81 @@ int sys_select_intr(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorf
return ret;
}
+
+/*
+ * sys_poll expects pollfd's to be a talloc'ed array.
+ *
+ * It expects the talloc_array_length(fds) >= num_fds+1 to give space
+ * to the signal pipe.
+ */
+
+int sys_poll(struct pollfd *fds, int num_fds, int timeout)
+{
+ int ret;
+
+ if (talloc_array_length(fds) < num_fds+1) {
+ errno = ENOSPC;
+ return -1;
+ }
+
+ if (initialised != sys_getpid()) {
+ if (pipe(select_pipe) == -1)
+ {
+ int saved_errno = errno;
+ DEBUG(0, ("sys_poll: pipe failed (%s)\n",
+ strerror(errno)));
+ errno = saved_errno;
+ return -1;
+ }
+
+ /*
+ * These next two lines seem to fix a bug with the Linux
+ * 2.0.x kernel (and probably other UNIXes as well) where
+ * the one byte read below can block even though the
+ * select returned that there is data in the pipe and
+ * the pipe_written variable was incremented. Thanks to
+ * HP for finding this one. JRA.
+ */
+
+ if(set_blocking(select_pipe[0],0)==-1)
+ smb_panic("select_pipe[0]: O_NONBLOCK failed");
+ if(set_blocking(select_pipe[1],0)==-1)
+ smb_panic("select_pipe[1]: O_NONBLOCK failed");
+
+ initialised = sys_getpid();
+ }
+
+ ZERO_STRUCT(fds[num_fds]);
+ fds[num_fds].fd = select_pipe[0];
+ fds[num_fds].events = POLLIN|POLLHUP;
+
+ errno = 0;
+ ret = poll(fds, num_fds+1, timeout);
+
+ if ((ret >= 0) && (fds[num_fds].revents & (POLLIN|POLLHUP|POLLERR))) {
+ char c;
+ int saved_errno = errno;
+
+ if (read(select_pipe[0], &c, 1) == 1) {
+ pipe_read += 1;
+
+ /* Mark Weaver <mark-clist@npsl.co.uk> pointed out a critical
+ fix to ensure we don't lose signals. We must always
+ return -1 when the select pipe is set, otherwise if another
+ fd is also ready (so ret == 2) then we used to eat the
+ byte in the pipe and lose the signal. JRA.
+ */
+ ret = -1;
+#if 0
+ /* JRA - we can use this to debug the signal messaging... */
+ DEBUG(0,("select got %u signal\n", (unsigned int)c));
+#endif
+ errno = EINTR;
+ } else {
+ ret -= 1;
+ errno = saved_errno;
+ }
+ }
+
+ return ret;
+}
diff --git a/lib/util/select.h b/lib/util/select.h
index 13c85ce0bf..795c8fa454 100644
--- a/lib/util/select.h
+++ b/lib/util/select.h
@@ -20,10 +20,13 @@
#ifndef _select_h_
#define _select_h_
+#include "system/select.h"
+
/* The following definitions come from lib/util/select.c */
void sys_select_signal(char c);
int sys_select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval);
int sys_select_intr(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tval);
+int sys_poll(struct pollfd *fds, int num_fds, int timeout);
#endif