Skip to content

Commit

Permalink
OS-3591 lxbrand implement ppoll
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonathan Perkin committed Nov 25, 2014
1 parent d475fa1 commit f54f2e6
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 11 deletions.
4 changes: 2 additions & 2 deletions usr/src/lib/brand/lx/lx_brand/common/lx_brand.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */
Expand Down
16 changes: 10 additions & 6 deletions usr/src/lib/brand/lx/lx_brand/common/poll_select.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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;
}

Expand All @@ -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) {
Expand Down
148 changes: 148 additions & 0 deletions usr/src/lib/brand/lx/lx_brand/common/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,16 @@
#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>
#include <sys/lx_thread.h>
#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>
Expand Down Expand Up @@ -316,6 +319,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.
Expand Down Expand Up @@ -1966,6 +1975,145 @@ lx_siginit(void)
return (0);
}

/*
* 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.
Expand Down
8 changes: 5 additions & 3 deletions usr/src/lib/brand/lx/lx_brand/sys/lx_poll.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
1 change: 1 addition & 0 deletions usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit f54f2e6

Please sign in to comment.