summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Perkin <jperkin@joyent.com>2014-11-25 05:11:37 +0000
committerJonathan Perkin <jperkin@joyent.com>2014-11-25 05:11:37 +0000
commitf54f2e6228e9c5cc433bae3d6fe5126b60ed1c2c (patch)
treeedc1b798e09afd7ecc5a129b96ad4e021c0918f4
parentd475fa1f47bda5aa1aac35d6d99d8fce29c3048e (diff)
downloadillumos-joyent-f54f2e6228e9c5cc433bae3d6fe5126b60ed1c2c.tar.gz
OS-3591 lxbrand implement ppoll
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/lx_brand.c4
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/poll_select.c16
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/signal.c148
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_poll.h8
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h1
5 files changed, 166 insertions, 11 deletions
diff --git a/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c b/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c
index 9bcf859180..02bbcb0b89 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c
@@ -1366,7 +1366,7 @@ static struct lx_sysent sysents[] = {
{"fchmodat", lx_fchmodat, 0, 4}, /* 268 */
{"faccessat", lx_faccessat, 0, 4}, /* 269 */
{"pselect6", lx_pselect6, 0, 6}, /* 270 */
- {"ppoll", NULL, NOSYS_NULL, 0}, /* 271 */
+ {"ppoll", lx_ppoll, 0, 5}, /* 271 */
{"unshare", NULL, NOSYS_NULL, 0}, /* 272 */
{"set_robust_list", NULL, NOSYS_NULL, 0}, /* 273 */
{"get_robust_list", NULL, NOSYS_NULL, 0}, /* 274 */
@@ -1731,7 +1731,7 @@ static struct lx_sysent sysents[] = {
{"fchmodat", lx_fchmodat, 0, 4}, /* 306 */
{"faccessat", lx_faccessat, 0, 4}, /* 307 */
{"pselect6", lx_pselect6, LX_SYS_EBPARG6, 6}, /* 308 */
- {"ppoll", NULL, NOSYS_NULL, 0}, /* 309 */
+ {"ppoll", lx_ppoll, 0, 5}, /* 309 */
{"unshare", NULL, NOSYS_NULL, 0}, /* 310 */
{"set_robust_list", NULL, NOSYS_NULL, 0}, /* 311 */
{"get_robust_list", NULL, NOSYS_NULL, 0}, /* 312 */
diff --git a/usr/src/lib/brand/lx/lx_brand/common/poll_select.c b/usr/src/lib/brand/lx/lx_brand/common/poll_select.c
index 1cebd1535d..a69c3bb56f 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/poll_select.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/poll_select.c
@@ -160,7 +160,7 @@ lx_poll(uintptr_t p1, uintptr_t p2, uintptr_t p3)
}
/*
- * Note: we are assuming that the Linux and Solaris pollfd
+ * Note: we are assuming that the Linux and Illumos pollfd
* structures are identical. Copy in the linux poll structure.
*/
fds_size = sizeof (struct pollfd) * nfds;
@@ -172,13 +172,13 @@ lx_poll(uintptr_t p1, uintptr_t p2, uintptr_t p3)
/*
* The poll system call modifies the poll structures passed in
- * so we'll need to make an exra copy of them.
+ * so we'll need to make an extra copy of them.
*/
sfds = (struct pollfd *)SAFE_ALLOCA(fds_size);
if (sfds == NULL)
return (-ENOMEM);
- /* Convert the Linux events bitmask into the Solaris equivalent. */
+ /* Convert the Linux events bitmask into the Illumos equivalent. */
for (i = 0; i < nfds; i++) {
/*
* If the caller is polling for an unsupported event, we
@@ -196,6 +196,8 @@ lx_poll(uintptr_t p1, uintptr_t p2, uintptr_t p3)
sfds[i].events |= POLLWRNORM;
if (lfds[i].events & LX_POLLWRBAND)
sfds[i].events |= POLLWRBAND;
+ if (lfds[i].events & LX_POLLRDHUP)
+ sfds[i].events |= POLLRDHUP;
sfds[i].revents = 0;
}
@@ -204,15 +206,17 @@ lx_poll(uintptr_t p1, uintptr_t p2, uintptr_t p3)
if ((rval = poll(sfds, nfds, (int)p3)) < 0)
return (-errno);
- /* Convert the Solaris revents bitmask into the Linux equivalent */
+ /* Convert the Illumos revents bitmask into the Linux equivalent */
for (i = 0; i < nfds; i++) {
revents = sfds[i].revents & LX_POLL_COMMON_EVENTS;
if (sfds[i].revents & POLLWRBAND)
revents |= LX_POLLWRBAND;
+ if (sfds[i].revents & POLLRDHUP)
+ revents |= LX_POLLRDHUP;
/*
- * Be carefull because on solaris POLLOUT and POLLWRNORM
- * are defined to the same values but on linux they
+ * Be careful because on Illumos POLLOUT and POLLWRNORM
+ * are defined to the same values but on Linux they
* are not.
*/
if (sfds[i].revents & POLLOUT) {
diff --git a/usr/src/lib/brand/lx/lx_brand/common/signal.c b/usr/src/lib/brand/lx/lx_brand/common/signal.c
index 46c1fc5612..79621d0f94 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/signal.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/signal.c
@@ -35,6 +35,7 @@
#include <sys/lx_brand.h>
#include <sys/lx_misc.h>
#include <sys/lx_debug.h>
+#include <sys/lx_poll.h>
#include <sys/lx_signal.h>
#include <sys/lx_sigstack.h>
#include <sys/lx_syscall.h>
@@ -42,6 +43,8 @@
#include <sys/syscall.h>
#include <assert.h>
#include <errno.h>
+#include <poll.h>
+#include <rctl.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
@@ -317,6 +320,12 @@ void (*libc_sigacthandler)(int, siginfo_t *, void*);
static lx_sighandlers_t lx_sighandlers;
/*
+ * Cache result of process.max-file-descriptor to avoid calling getrctl()
+ * for each lx_ppoll().
+ */
+static rlim_t maxfd = 0;
+
+/*
* stol_stack() and ltos_stack() convert between Illumos and Linux stack_t
* structures.
*
@@ -1967,6 +1976,145 @@ lx_siginit(void)
}
/*
+ * This code stongly resemebles lx_poll(), but is here to be able to take
+ * advantage of the Linux signal helper routines.
+ */
+long
+lx_ppoll(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5)
+{
+ struct pollfd *lfds, *sfds;
+ nfds_t nfds = (nfds_t)p2;
+ timespec_t ts, *tsp = NULL;
+ int fds_size, i, rval, revents;
+ lx_sigset_t lxsig, *lxsigp = NULL;
+ sigset_t sigset, *sp = NULL;
+ rctlblk_t *rblk;
+
+ lx_debug("\tppoll(0x%p, %d, 0x%p, 0x%p, %d)", p1, p2, p3, p4, p5);
+
+ if (p3 != NULL) {
+ if (uucopy((void *)p3, &ts, sizeof (ts)) != 0)
+ return (-errno);
+
+ tsp = &ts;
+ }
+
+ if (p4 != NULL) {
+ if (uucopy((void *)p4, &lxsig, sizeof (lxsig)) != 0)
+ return (-errno);
+
+ lxsigp = &lxsig;
+ if ((size_t)p5 != sizeof (lx_sigset_t))
+ return (-EINVAL);
+
+ if (lxsigp) {
+ if ((rval = ltos_sigset(lxsigp, &sigset)) != 0)
+ return (rval);
+
+ sp = &sigset;
+ }
+ }
+
+ /*
+ * Deal with the NULL fds[] case.
+ */
+ if (nfds == 0 || p1 == NULL) {
+ if ((rval = ppoll(NULL, 0, tsp, sp)) < 0)
+ return (-errno);
+
+ return (rval);
+ }
+
+ if (maxfd == 0) {
+ if ((rblk = (rctlblk_t *)SAFE_ALLOCA(rctlblk_size())) == NULL)
+ return (-ENOMEM);
+
+ if (getrctl("process.max-file-descriptor", NULL, rblk,
+ RCTL_FIRST) == -1)
+ return (-EINVAL);
+
+ maxfd = rctlblk_get_value(rblk);
+ }
+
+ if (nfds > maxfd)
+ return (-EINVAL);
+
+ /*
+ * Note: we are assuming that the Linux and Illumos pollfd
+ * structures are identical. Copy in the Linux poll structure.
+ */
+ fds_size = sizeof (struct pollfd) * nfds;
+ lfds = (struct pollfd *)SAFE_ALLOCA(fds_size);
+ if (lfds == NULL)
+ return (-ENOMEM);
+ if (uucopy((void *)p1, lfds, fds_size) != 0)
+ return (-errno);
+
+ /*
+ * The poll system call modifies the poll structures passed in
+ * so we'll need to make an extra copy of them.
+ */
+ sfds = (struct pollfd *)SAFE_ALLOCA(fds_size);
+ if (sfds == NULL)
+ return (-ENOMEM);
+
+ /* Convert the Linux events bitmask into the Illumos equivalent. */
+ for (i = 0; i < nfds; i++) {
+ /*
+ * If the caller is polling for an unsupported event, we
+ * have to bail out.
+ */
+ if (lfds[i].events & ~LX_POLL_SUPPORTED_EVENTS) {
+ lx_unsupported("unsupported poll events requested: "
+ "events=0x%x", lfds[i].events);
+ return (-ENOTSUP);
+ }
+
+ sfds[i].fd = lfds[i].fd;
+ sfds[i].events = lfds[i].events & LX_POLL_COMMON_EVENTS;
+ if (lfds[i].events & LX_POLLWRNORM)
+ sfds[i].events |= POLLWRNORM;
+ if (lfds[i].events & LX_POLLWRBAND)
+ sfds[i].events |= POLLWRBAND;
+ if (lfds[i].events & LX_POLLRDHUP)
+ sfds[i].events |= POLLRDHUP;
+ sfds[i].revents = 0;
+ }
+
+ if ((rval = ppoll(sfds, nfds, tsp, sp) < 0))
+ return (-errno);
+
+ /* Convert the Illumos revents bitmask into the Linux equivalent */
+ for (i = 0; i < nfds; i++) {
+ revents = sfds[i].revents & LX_POLL_COMMON_EVENTS;
+ if (sfds[i].revents & POLLWRBAND)
+ revents |= LX_POLLWRBAND;
+ if (sfds[i].revents & POLLRDHUP)
+ revents |= LX_POLLRDHUP;
+
+ /*
+ * Be careful because on Illumos POLLOUT and POLLWRNORM
+ * are defined to the same values but on Linux they
+ * are not.
+ */
+ if (sfds[i].revents & POLLOUT) {
+ if ((lfds[i].events & LX_POLLOUT) == 0)
+ revents &= ~LX_POLLOUT;
+ if (lfds[i].events & LX_POLLWRNORM)
+ revents |= LX_POLLWRNORM;
+ }
+
+ lfds[i].revents = revents;
+ }
+
+ /* Copy out the results */
+ if (uucopy(lfds, (void *)p1, fds_size) != 0)
+ return (-errno);
+
+ return (rval);
+}
+
+/*
* This code stongly resemebles lx_select(), but is here to be able to take
* advantage of the Linux signal helper routines.
*/
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_poll.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_poll.h
index cb5706fab2..99abdbbf46 100644
--- a/usr/src/lib/brand/lx/lx_brand/sys/lx_poll.h
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_poll.h
@@ -50,11 +50,13 @@ extern "C" {
/*
* These events differ between Linux and Solaris
*/
-#define LX_POLLWRNORM 0x100
-#define LX_POLLWRBAND 0x200
+#define LX_POLLWRNORM 0x0100
+#define LX_POLLWRBAND 0x0200
+#define LX_POLLRDHUP 0x2000
+
#define LX_POLL_SUPPORTED_EVENTS \
- (LX_POLL_COMMON_EVENTS | LX_POLLWRNORM | LX_POLLWRBAND)
+ (LX_POLL_COMMON_EVENTS | LX_POLLWRNORM | LX_POLLWRBAND | LX_POLLRDHUP)
#ifdef __cplusplus
}
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h
index f72e83b472..e336746d9b 100644
--- a/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h
@@ -114,6 +114,7 @@ extern long lx_select(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
extern long lx_pselect6(uintptr_t, uintptr_t, uintptr_t, uintptr_t,
uintptr_t, uintptr_t);
extern long lx_poll(uintptr_t, uintptr_t, uintptr_t);
+extern long lx_ppoll(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
extern long lx_epoll_ctl(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
extern long lx_oldgetrlimit(uintptr_t, uintptr_t);
extern long lx_getrlimit(uintptr_t, uintptr_t);