@@ -9101,6 +9101,126 @@ IMPL(pipe2)
target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
}
+static struct pollfd *get_pollfd(abi_ulong nfds, abi_ulong target_addr,
+ struct target_pollfd **ptfd, abi_long *err)
+{
+ struct target_pollfd *target_pfd;
+ struct pollfd *pfd;
+ abi_ulong i;
+
+ if (nfds > (INT_MAX / sizeof(struct target_pollfd))) {
+ *err = -TARGET_EINVAL;
+ return NULL;
+ }
+ pfd = g_try_new(struct pollfd, nfds);
+ if (pfd == NULL) {
+ *err = -TARGET_ENOMEM;
+ return NULL;
+ }
+
+ *ptfd = target_pfd = lock_user(VERIFY_WRITE, target_addr,
+ sizeof(struct target_pollfd) * nfds, 1);
+ if (!target_pfd) {
+ *err = -TARGET_EFAULT;
+ g_free(pfd);
+ return NULL;
+ }
+
+ for (i = 0; i < nfds; i++) {
+ pfd[i].fd = tswap32(target_pfd[i].fd);
+ pfd[i].events = tswap16(target_pfd[i].events);
+ }
+
+ *err = 0;
+ return pfd;
+}
+
+static abi_long put_pollfd(abi_ulong nfds, abi_ulong target_addr,
+ struct pollfd *pfd,
+ struct target_pollfd *target_pfd, abi_long ret)
+{
+ if (!is_error(ret)) {
+ abi_ulong i;
+ for (i = 0; i < nfds; i++) {
+ target_pfd[i].revents = tswap16(pfd[i].revents);
+ }
+ }
+ unlock_user(target_pfd, target_addr, sizeof(struct target_pollfd) * nfds);
+ g_free(pfd);
+ return ret;
+}
+
+#ifdef TARGET_NR_poll
+IMPL(poll)
+{
+ struct timespec ts, *pts;
+ struct target_pollfd *target_pfd;
+ struct pollfd *pfd;
+ abi_long ret;
+
+ if (arg3 >= 0) {
+ /* Convert ms to secs, ns */
+ ts.tv_sec = arg3 / 1000;
+ ts.tv_nsec = (arg3 % 1000) * 1000000LL;
+ pts = &ts;
+ } else {
+ /* -ve poll() timeout means "infinite" */
+ pts = NULL;
+ }
+
+ pfd = get_pollfd(arg2, arg1, &target_pfd, &ret);
+ if (pfd == NULL) {
+ return ret;
+ }
+ ret = safe_ppoll(pfd, arg2, pts, NULL, 0);
+ return put_pollfd(arg2, arg1, pfd, target_pfd, get_errno(ret));
+}
+#endif
+
+IMPL(ppoll)
+{
+ struct timespec ts;
+ sigset_t set;
+ struct target_pollfd *target_pfd;
+ struct pollfd *pfd;
+ abi_long ret;
+
+ if (arg3) {
+ if (target_to_host_timespec(&ts, arg3)) {
+ return -TARGET_EFAULT;
+ }
+ }
+
+ if (arg4) {
+ target_sigset_t *target_set;
+ if (arg5 != sizeof(target_sigset_t)) {
+ return -TARGET_EINVAL;
+ }
+ target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
+ if (!target_set) {
+ return -TARGET_EFAULT;
+ }
+ target_to_host_sigset(&set, target_set);
+ unlock_user(target_set, arg4, 0);
+ }
+
+ pfd = get_pollfd(arg2, arg1, &target_pfd, &ret);
+ if (pfd == NULL) {
+ return ret;
+ }
+ ret = safe_ppoll(pfd, arg2, arg3 ? &ts : NULL,
+ arg4 ? &set : NULL, SIGSET_T_SIZE);
+ ret = put_pollfd(arg2, arg1, pfd, target_pfd, get_errno(ret));
+
+ if (!is_error(ret) && arg3) {
+ abi_long err = host_to_target_timespec(arg3, &ts);
+ if (err) {
+ return err;
+ }
+ }
+ return ret;
+}
+
IMPL(pselect6)
{
abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
@@ -10649,114 +10769,6 @@ static abi_long do_syscall1(void *cpu_env, unsigned num, abi_long arg1,
void *p;
switch(num) {
-#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
-# ifdef TARGET_NR_poll
- case TARGET_NR_poll:
-# endif
-# ifdef TARGET_NR_ppoll
- case TARGET_NR_ppoll:
-# endif
- {
- struct target_pollfd *target_pfd;
- unsigned int nfds = arg2;
- struct pollfd *pfd;
- unsigned int i;
-
- pfd = NULL;
- target_pfd = NULL;
- if (nfds) {
- if (nfds > (INT_MAX / sizeof(struct target_pollfd))) {
- return -TARGET_EINVAL;
- }
-
- target_pfd = lock_user(VERIFY_WRITE, arg1,
- sizeof(struct target_pollfd) * nfds, 1);
- if (!target_pfd) {
- return -TARGET_EFAULT;
- }
-
- pfd = alloca(sizeof(struct pollfd) * nfds);
- for (i = 0; i < nfds; i++) {
- pfd[i].fd = tswap32(target_pfd[i].fd);
- pfd[i].events = tswap16(target_pfd[i].events);
- }
- }
-
- switch (num) {
-# ifdef TARGET_NR_ppoll
- case TARGET_NR_ppoll:
- {
- struct timespec _timeout_ts, *timeout_ts = &_timeout_ts;
- target_sigset_t *target_set;
- sigset_t _set, *set = &_set;
-
- if (arg3) {
- if (target_to_host_timespec(timeout_ts, arg3)) {
- unlock_user(target_pfd, arg1, 0);
- return -TARGET_EFAULT;
- }
- } else {
- timeout_ts = NULL;
- }
-
- if (arg4) {
- if (arg5 != sizeof(target_sigset_t)) {
- unlock_user(target_pfd, arg1, 0);
- return -TARGET_EINVAL;
- }
-
- target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
- if (!target_set) {
- unlock_user(target_pfd, arg1, 0);
- return -TARGET_EFAULT;
- }
- target_to_host_sigset(set, target_set);
- } else {
- set = NULL;
- }
-
- ret = get_errno(safe_ppoll(pfd, nfds, timeout_ts,
- set, SIGSET_T_SIZE));
-
- if (!is_error(ret) && arg3) {
- host_to_target_timespec(arg3, timeout_ts);
- }
- if (arg4) {
- unlock_user(target_set, arg4, 0);
- }
- return ret;
- }
-# endif
-# ifdef TARGET_NR_poll
- case TARGET_NR_poll:
- {
- struct timespec ts, *pts;
-
- if (arg3 >= 0) {
- /* Convert ms to secs, ns */
- ts.tv_sec = arg3 / 1000;
- ts.tv_nsec = (arg3 % 1000) * 1000000LL;
- pts = &ts;
- } else {
- /* -ve poll() timeout means "infinite" */
- pts = NULL;
- }
- return get_errno(safe_ppoll(pfd, nfds, pts, NULL, 0));
- }
-# endif
- default:
- g_assert_not_reached();
- }
-
- if (!is_error(ret)) {
- for(i = 0; i < nfds; i++) {
- target_pfd[i].revents = tswap16(pfd[i].revents);
- }
- }
- unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
- }
- return ret;
-#endif
case TARGET_NR_flock:
/* NOTE: the flock constant seems to be the same for every
Linux platform */
@@ -13060,6 +13072,10 @@ static impl_fn *syscall_table(unsigned num)
SYSCALL(pipe);
#endif
SYSCALL(pipe2);
+#ifdef TARGET_NR_poll
+ SYSCALL(poll);
+#endif
+ SYSCALL(ppoll);
SYSCALL(pselect6);
SYSCALL(read);
#ifdef TARGET_NR_readlink
All targets define ppoll; remove the ifdef. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/syscall.c | 232 +++++++++++++++++++++++-------------------- 1 file changed, 124 insertions(+), 108 deletions(-) -- 2.17.1