diff --git a/sys/amd64/linux32/linux32_dummy.c b/sys/amd64/linux32/linux32_dummy.c index 411c4d5..e0b2414 100644 --- a/sys/amd64/linux32/linux32_dummy.c +++ b/sys/amd64/linux32/linux32_dummy.c @@ -103,7 +103,6 @@ DUMMY(inotify_rm_watch); /* linux 2.6.16: */ DUMMY(migrate_pages); DUMMY(pselect6); -DUMMY(ppoll); DUMMY(unshare); /* linux 2.6.17: */ DUMMY(splice); diff --git a/sys/amd64/linux32/syscalls.master b/sys/amd64/linux32/syscalls.master index c3a10af..326666a 100644 --- a/sys/amd64/linux32/syscalls.master +++ b/sys/amd64/linux32/syscalls.master @@ -505,7 +505,8 @@ l_mode_t mode); } 307 AUE_FACCESSAT STD { int linux_faccessat(l_int dfd, const char *filename, l_int amode, int flag); } 308 AUE_NULL STD { int linux_pselect6(void); } -309 AUE_NULL STD { int linux_ppoll(void); } +309 AUE_POLL STD { int linux_ppoll(struct pollfd *fds, unsigned int nfds, \ + struct l_timespec *timeout_ts, l_uintptr_t *sigmask); } 310 AUE_NULL STD { int linux_unshare(void); } ; linux 2.6.17: 311 AUE_NULL STD { int linux_set_robust_list(struct linux_robust_list_head *head, \ diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index ff5e8a2..a372b79 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include @@ -567,6 +568,109 @@ select_out: } int +linux_ppoll(struct thread *td, struct linux_ppoll_args *pargs) +{ + struct l_timespec lts; + struct timeval tv, *tvp, tv0, tv1; + struct poll_args pa; + sigset_t usigmask, *usigmaskp; + l_sigset_t lsigmask; + int error, retval, mss, msns; + + /* Get the time */ + if (pargs->timeout_ts != NULL) + { + error = copyin(pargs->timeout_ts, <s, sizeof(lts)); + if (error != 0) + return (error); + + TIMESPEC_TO_TIMEVAL(&tv, <s); + if (itimerfix(&tv)) + return (EINVAL); + + /* Mark the time before the call */ + microtime(&tv0); + tvp = &tv; + } else + tvp = NULL; + + /* Get the sigmask */ + if (pargs->sigmask != NULL) { + error = copyin(pargs->sigmask, &lsigmask, sizeof(lsigmask)); + if (error) + return (error); + linux_to_bsd_sigset(&lsigmask, &usigmask); + usigmaskp = &usigmask; + } else + usigmaskp = NULL; + + /* Set the sigmask */ + error = kern_sigprocmask (td, SIG_SETMASK, usigmaskp, &td->td_oldsigmask, 0); + if (error) + return (error); + + pa.fds = pargs->fds; + pa.nfds = pargs->nfds; + + /* Linux's ppoll allows NULL timeout which is translated to FreeBSD's INFTIM (-1) */ + if (tvp==NULL) + pa.timeout = INFTIM; + else + { + mss = tvp->tv_sec * 1000; + msns = tvp->tv_usec / 1000; + + /* + * Handling the multiplication and addition overflow. + * If it happens, assing pa.timeout the INT_MAX value + */ + if (mss/1000 == tvp->tv_sec) { + pa.timeout = mss + msns; + if ( pa.timeout < 0) + pa.timeout = INT_MAX; + } else + pa.timeout = INT_MAX; + } + + /* + * Ensure that the td_oldsigmask is restored by ast() + * when returns to user mode and that the TDP_OLDMASK + * is cleared + */ + td->td_pflags |= TDP_OLDMASK; + thread_lock(td); + td->td_flags |= TDF_ASTPENDING; + thread_unlock(td); + + /* call sys_poll */ + retval = sys_poll(td, &pa); + + if (retval == 0 && pargs->timeout_ts) { + if (td->td_retval[0]) { + /* + * Compute how much time was left of the timeout, + * by subtracting the current time and the time + * before we started the call, and subtracting + * that result from the user-supplied value. + */ + microtime(&tv1); + timevalsub(&tv1, &tv0); + timevalsub(&tv, &tv1); + if (tv.tv_sec < 0) + timevalclear(&tv); + } else + timevalclear(&tv); + + TIMEVAL_TO_TIMESPEC(&tv, <s); + + error = copyout(<s, pargs->timeout_ts, sizeof(lts)); + if (error) + return (error); + } + return retval; +} + +int linux_mremap(struct thread *td, struct linux_mremap_args *args) { struct munmap_args /* {