diff options
| author | Jonathan Perkin <jperkin@joyent.com> | 2014-11-25 05:11:37 +0000 |
|---|---|---|
| committer | Jonathan Perkin <jperkin@joyent.com> | 2014-11-25 05:11:37 +0000 |
| commit | f54f2e6228e9c5cc433bae3d6fe5126b60ed1c2c (patch) | |
| tree | edc1b798e09afd7ecc5a129b96ad4e021c0918f4 | |
| parent | d475fa1f47bda5aa1aac35d6d99d8fce29c3048e (diff) | |
| download | illumos-joyent-f54f2e6228e9c5cc433bae3d6fe5126b60ed1c2c.tar.gz | |
OS-3591 lxbrand implement ppoll
| -rw-r--r-- | usr/src/lib/brand/lx/lx_brand/common/lx_brand.c | 4 | ||||
| -rw-r--r-- | usr/src/lib/brand/lx/lx_brand/common/poll_select.c | 16 | ||||
| -rw-r--r-- | usr/src/lib/brand/lx/lx_brand/common/signal.c | 148 | ||||
| -rw-r--r-- | usr/src/lib/brand/lx/lx_brand/sys/lx_poll.h | 8 | ||||
| -rw-r--r-- | usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h | 1 |
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); |
