From db525dc2ada7fbedf4e9d4fbb2bc8a10b951acab Mon Sep 17 00:00:00 2001 From: Theodore Dubois Date: Tue, 30 Oct 2018 16:59:12 -0700 Subject: [PATCH] Implement pselect --- kernel/calls.c | 1 + kernel/calls.h | 1 + kernel/poll.c | 20 ++++++++++++++++++++ kernel/signal.c | 37 +++++++++++++++++++++++-------------- kernel/signal.h | 1 + 5 files changed, 46 insertions(+), 14 deletions(-) diff --git a/kernel/calls.c b/kernel/calls.c index b01cfcea..6bf19e3a 100644 --- a/kernel/calls.c +++ b/kernel/calls.c @@ -122,6 +122,7 @@ syscall_t syscall_table[] = { [305] = (syscall_t) sys_readlinkat, [306] = (syscall_t) sys_fchmodat, [307] = (syscall_t) sys_faccessat, + [308] = (syscall_t) sys_pselect, [320] = (syscall_t) sys_utimensat, [324] = (syscall_t) sys_fallocate, [340] = (syscall_t) sys_prlimit, diff --git a/kernel/calls.h b/kernel/calls.h index 5c8f32f8..96984c28 100644 --- a/kernel/calls.h +++ b/kernel/calls.h @@ -190,6 +190,7 @@ struct pollfd_ { }; dword_t sys_poll(addr_t fds, dword_t nfds, dword_t timeout); dword_t sys_select(fd_t nfds, addr_t readfds_addr, addr_t writefds_addr, addr_t exceptfds_addr, addr_t timeout_addr); +dword_t sys_pselect(fd_t nfds, addr_t readfds_addr, addr_t writefds_addr, addr_t exceptfds_addr, addr_t timeout_addr, addr_t sigmask_addr); // misc dword_t sys_futex(addr_t uaddr, dword_t op, dword_t val); diff --git a/kernel/poll.c b/kernel/poll.c index 8b718660..2d67cdd0 100644 --- a/kernel/poll.c +++ b/kernel/poll.c @@ -134,3 +134,23 @@ dword_t sys_poll(addr_t fds, dword_t nfds, dword_t timeout) { return _EFAULT; return err; } + +dword_t sys_pselect(fd_t nfds, addr_t readfds_addr, addr_t writefds_addr, addr_t exceptfds_addr, addr_t timeout_addr, addr_t sigmask_addr) { + // a system call can only take 6 parameters, so the last two need to be passed as a pointer to a struct + struct { + addr_t mask_addr; + dword_t mask_size; + } sigmask; + if (user_get(sigmask_addr, sigmask)) + return _EFAULT; + if (sigmask.mask_size != sizeof(sigset_t_)) + return _EINVAL; + sigset_t_ mask, old_mask; + if (user_get(sigmask.mask_addr, mask)) + return _EFAULT; + + do_sigprocmask(SIG_SETMASK_, mask, &old_mask); + dword_t res = sys_select(nfds, readfds_addr, writefds_addr, exceptfds_addr, timeout_addr); + do_sigprocmask(SIG_SETMASK_, old_mask, NULL); + return res; +} diff --git a/kernel/signal.c b/kernel/signal.c index f9dec93b..430b82d3 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -213,22 +213,11 @@ dword_t sys_sigaction(dword_t signum, addr_t action_addr, addr_t oldaction_addr) return sys_rt_sigaction(signum, action_addr, oldaction_addr, 1); } -dword_t sys_rt_sigprocmask(dword_t how, addr_t set_addr, addr_t oldset_addr, dword_t size) { - if (size != sizeof(sigset_t_)) - return _EINVAL; - - sigset_t_ set; - if (user_get(set_addr, set)) - return _EFAULT; - STRACE("rt_sigprocmask(%s, 0x%llx, 0x%x, %d)", - how == SIG_BLOCK_ ? "SIG_BLOCK" : - how == SIG_UNBLOCK_ ? "SIG_UNBLOCK" : - how == SIG_SETMASK_ ? "SIG_SETMASK" : "??", - (long long) set, oldset_addr, size); - sigset_t_ oldset = current->blocked; - +int do_sigprocmask(dword_t how, sigset_t_ set, sigset_t_ *oldset_out) { struct sighand *sighand = current->sighand; lock(&sighand->lock); + sigset_t oldset = current->blocked; + if (how == SIG_BLOCK_) current->blocked |= set; else if (how == SIG_UNBLOCK_) @@ -245,7 +234,27 @@ dword_t sys_rt_sigprocmask(dword_t how, addr_t set_addr, addr_t oldset_addr, dwo current->pending |= current->queued & unblocked; current->queued &= ~unblocked; unlock(&sighand->lock); + if (oldset_out != NULL) + *oldset_out = current->blocked; + return 0; +} +dword_t sys_rt_sigprocmask(dword_t how, addr_t set_addr, addr_t oldset_addr, dword_t size) { + if (size != sizeof(sigset_t_)) + return _EINVAL; + + sigset_t_ set, oldset; + if (user_get(set_addr, set)) + return _EFAULT; + STRACE("rt_sigprocmask(%s, 0x%llx, 0x%x, %d)", + how == SIG_BLOCK_ ? "SIG_BLOCK" : + how == SIG_UNBLOCK_ ? "SIG_UNBLOCK" : + how == SIG_SETMASK_ ? "SIG_SETMASK" : "??", + (long long) set, oldset_addr, size); + + int err = do_sigprocmask(how, set, &oldset); + if (err < 0) + return err; if (oldset_addr != 0) if (user_put(oldset_addr, oldset)) return _EFAULT; diff --git a/kernel/signal.h b/kernel/signal.h index 7f87ed7e..654d7b98 100644 --- a/kernel/signal.h +++ b/kernel/signal.h @@ -81,6 +81,7 @@ dword_t sys_rt_sigreturn(dword_t sig); #define SIG_UNBLOCK_ 1 #define SIG_SETMASK_ 2 typedef uint64_t sigset_t_; +int do_sigprocmask(dword_t how, sigset_t_ set, sigset_t_ *oldset); dword_t sys_rt_sigprocmask(dword_t how, addr_t set, addr_t oldset, dword_t size); struct stack_t_ {