diff --git a/include/nuttx/signal.h b/include/nuttx/signal.h index 8d48adda23c..5e6d89f0889 100644 --- a/include/nuttx/signal.h +++ b/include/nuttx/signal.h @@ -315,8 +315,6 @@ int nxsig_kill(pid_t pid, int signo); * ****************************************************************************/ -int nxsig_timedwait(FAR const sigset_t *set, FAR struct siginfo *info, - FAR const struct timespec *timeout); int nxsig_timedwait(FAR const sigset_t *set, FAR struct siginfo *info, FAR const struct timespec *timeout); diff --git a/include/poll.h b/include/poll.h index 5c8748db3ab..b8152162270 100644 --- a/include/poll.h +++ b/include/poll.h @@ -44,6 +44,7 @@ #include #include +#include #include /**************************************************************************** @@ -153,6 +154,10 @@ extern "C" int poll(FAR struct pollfd *fds, nfds_t nfds, int timeout); +int ppoll(FAR struct pollfd *fds, nfds_t nfds, + FAR const struct timespec *timeout_ts, + FAR const sigset_t *sigmask); + #undef EXTERN #if defined(__cplusplus) } diff --git a/include/sys/select.h b/include/sys/select.h index df93cbc859e..3eb30aea952 100644 --- a/include/sys/select.h +++ b/include/sys/select.h @@ -43,6 +43,7 @@ #include #include +#include #include #if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0 @@ -123,6 +124,10 @@ struct timeval; int select(int nfds, FAR fd_set *readfds, FAR fd_set *writefds, FAR fd_set *exceptfds, FAR struct timeval *timeout); +int pselect(int nfds, FAR fd_set *readfds, FAR fd_set *writefds, + FAR fd_set *exceptfds, FAR const struct timespec *timeout, + FAR const sigset_t *sigmask); + #undef EXTERN #if defined(__cplusplus) } diff --git a/include/sys/syscall.h b/include/sys/syscall.h index 3beacfa62ba..8c0f911911b 100644 --- a/include/sys/syscall.h +++ b/include/sys/syscall.h @@ -298,7 +298,13 @@ # ifndef CONFIG_DISABLE_POLL # define SYS_poll __SYS_poll # define SYS_select (__SYS_poll + 1) -# define __SYS_ifindex (__SYS_poll + 2) +# ifndef CONFIG_DISABLE_SIGNALS +# define SYS_ppoll (__SYS_poll + 2) +# define SYS_pselect (__SYS_poll + 3) +# define __SYS_ifindex (__SYS_poll + 4) +# else +# define __SYS_ifindex (__SYS_poll + 2) +# endif # else # define __SYS_ifindex __SYS_poll # endif diff --git a/sched/signal/Make.defs b/sched/signal/Make.defs index 71499ccf0c6..ae2a94ab9f4 100644 --- a/sched/signal/Make.defs +++ b/sched/signal/Make.defs @@ -52,6 +52,10 @@ ifeq ($(CONFIG_SIG_EVTHREAD),y) CSRCS += sig_evthread.c endif +ifneq ($(CONFIG_DISABLE_POLL),y) +CSRCS += sig_ppoll.c sig_pselect.c +endif + # Include signal build support DEPPATH += --dep-path signal diff --git a/sched/signal/sig_ppoll.c b/sched/signal/sig_ppoll.c new file mode 100644 index 00000000000..e586af6c134 --- /dev/null +++ b/sched/signal/sig_ppoll.c @@ -0,0 +1,153 @@ +/**************************************************************************** + * sched/signal/sig_ppoll.c + * + * Copyright (C) 2018 Pinecone Inc. All rights reserved. + * Author: Xiang Xiao + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "sched/sched.h" +#include "signal/signal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ppoll + * + * Description: + * ppoll() waits for one of a set of file descriptors to become ready to + * perform I/O. If none of the events requested (and no error) has + * occurred for any of the file descriptors, then ppoll() blocks until + * one of the events occurs. + * + * Input Parameters: + * fds - List of structures describing file descriptors to be monitored + * nfds - The number of entries in the list + * timeout - Specifies an upper limit on the time for which ppoll() will + * block. A NULL pointer means an infinite timeout. + * sigmask - Replace the current signal mask temporarily during execution + * + * Returned Value: + * On success, the number of structures that have non-zero revents fields. + * A value of 0 indicates that the call timed out and no file descriptors + * were ready. On error, -1 is returned, and errno is set appropriately: + * + * EBADF - An invalid file descriptor was given in one of the sets. + * EFAULT - The fds address is invalid + * EINTR - A signal occurred before any requested event. + * EINVAL - The nfds value exceeds a system limit. + * ENOMEM - There was no space to allocate internal data structures. + * ENOSYS - One or more of the drivers supporting the file descriptor + * does not support the poll method. + * + ****************************************************************************/ + +int ppoll(FAR struct pollfd *fds, nfds_t nfds, + FAR const struct timespec *timeout_ts, + FAR const sigset_t *sigmask) +{ + FAR struct tcb_s *rtcb = this_task(); + sigset_t saved_sigprocmask; + irqstate_t flags; + int ret = ERROR; + + /* Several operations must be performed below: We must determine if any + * signal is pending and, if not, wait for the signal. Since signals can + * be posted from the interrupt level, there is a race condition that + * can only be eliminated by disabling interrupts! + */ + + flags = enter_critical_section(); + + /* Save a copy of the old sigprocmask and install + * the new (temporary) sigprocmask + */ + + saved_sigprocmask = rtcb->sigprocmask; + if (sigmask) + { + rtcb->sigprocmask = *sigmask; + } + + rtcb->sigwaitmask = NULL_SIGNAL_SET; + + /* Check if there is a pending signal corresponding to one of the + * signals that will be unblocked by the new sigprocmask. + */ + + if (nxsig_unmask_pendingsignal()) + { + /* Dispatching one or more of the signals is sufficient to cause + * us to not wait. Restore the original sigprocmask. + */ + + rtcb->sigprocmask = saved_sigprocmask; + leave_critical_section(flags); + set_errno(EINTR); + } + else + { + int timeout = -1; + + /* And call poll to do the real work */ + + if (timeout_ts) + { + timeout = timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000; + } + + ret = poll(fds, nfds, timeout); + + /* We are running again, restore the original sigprocmask */ + + rtcb->sigprocmask = saved_sigprocmask; + leave_critical_section(flags); + + /* Now, handle the (rare?) case where (a) a blocked signal was received + * while the task was suspended but (b) restoring the original + * sigprocmask will unblock the signal. + */ + + nxsig_unmask_pendingsignal(); + } + + return ret; +} + diff --git a/sched/signal/sig_pselect.c b/sched/signal/sig_pselect.c new file mode 100644 index 00000000000..b7f4187f828 --- /dev/null +++ b/sched/signal/sig_pselect.c @@ -0,0 +1,153 @@ +/**************************************************************************** + * sched/signal/sig_pselect.c + * + * Copyright (C) 2018 Pinecone Inc. All rights reserved. + * Author: Xiang Xiao + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "sched/sched.h" +#include "signal/signal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pselect + * + * Description: + * pselect() allows a program to monitor multiple file descriptors, waiting + * until one or more of the file descriptors become "ready" for some class + * of I/O operation (e.g., input possible). A file descriptor is + * considered ready if it is possible to perform the corresponding I/O + * operation (e.g., read(2)) without blocking. + * + * Input Parameters: + * nfds - the maximum fd number (+1) of any descriptor in any of the + * three sets. + * readfds - the set of descriptions to monitor for read-ready events + * writefds - the set of descriptions to monitor for write-ready events + * exceptfds - the set of descriptions to monitor for error events + * timeout - Return at this time if none of these events of interest + * occur. + * sigmask - Replace the current signal mask temporarily during execution + * + * Returned Value: + * 0: Timer expired + * >0: The number of bits set in the three sets of descriptors + * -1: An error occurred (errno will be set appropriately) + * + ****************************************************************************/ + +int pselect(int nfds, FAR fd_set *readfds, FAR fd_set *writefds, + FAR fd_set *exceptfds, FAR const struct timespec *timeout, + FAR const sigset_t *sigmask) +{ + FAR struct tcb_s *rtcb = this_task(); + sigset_t saved_sigprocmask; + irqstate_t flags; + int ret = ERROR; + + /* Several operations must be performed below: We must determine if any + * signal is pending and, if not, wait for the signal. Since signals can + * be posted from the interrupt level, there is a race condition that + * can only be eliminated by disabling interrupts! + */ + + flags = enter_critical_section(); + + /* Save a copy of the old sigprocmask and install + * the new (temporary) sigprocmask + */ + + saved_sigprocmask = rtcb->sigprocmask; + if (sigmask) + { + rtcb->sigprocmask = *sigmask; + } + + rtcb->sigwaitmask = NULL_SIGNAL_SET; + + /* Check if there is a pending signal corresponding to one of the + * signals that will be unblocked by the new sigprocmask. + */ + + if (nxsig_unmask_pendingsignal()) + { + /* Dispatching one or more of the signals is sufficient to cause + * us to not wait. Restore the original sigprocmask. + */ + + rtcb->sigprocmask = saved_sigprocmask; + leave_critical_section(flags); + set_errno(EINTR); + } + else + { + FAR struct timeval *timeval = NULL; + struct timeval timeval_buf; + + /* And call select to do the real work */ + + if (timeout) + { + timeval_buf.tv_sec = timeout->tv_sec; + timeval_buf.tv_usec = timeout->tv_nsec / 1000; + timeval = &timeval_buf; + } + + ret = select(nfds, readfds, writefds, exceptfds, timeval); + + /* We are running again, restore the original sigprocmask */ + + rtcb->sigprocmask = saved_sigprocmask; + leave_critical_section(flags); + + /* Now, handle the (rare?) case where (a) a blocked signal was received + * while the task was suspended but (b) restoring the original + * sigprocmask will unblock the signal. + */ + + nxsig_unmask_pendingsignal(); + } + + return ret; +} + diff --git a/syscall/syscall.csv b/syscall/syscall.csv index 13c365e9a00..86cd4cc2236 100644 --- a/syscall/syscall.csv +++ b/syscall/syscall.csv @@ -67,8 +67,10 @@ "pgalloc", "nuttx/arch.h", "defined(CONFIG_BUILD_KERNEL)", "uintptr_t", "uintptr_t", "unsigned int" "pipe2","nuttx/drivers/drivers.h","defined(CONFIG_PIPES) && CONFIG_DEV_PIPE_SIZE > 0","int","int [2]|int*","size_t" "poll","poll.h","!defined(CONFIG_DISABLE_POLL) && (CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0)","int","FAR struct pollfd*","nfds_t","int" +"ppoll","poll.h","!defined(CONFIG_DISABLE_SIGNALS) && !defined(CONFIG_DISABLE_POLL) && (CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0)","int","FAR struct pollfd*","nfds_t","FAR const struct timespec *","FAR const sigset_t *" "prctl","sys/prctl.h", "CONFIG_TASK_NAME_SIZE > 0","int","int","..." "pread","unistd.h","CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0","ssize_t","int","FAR void*","size_t","off_t" +"pselect","sys/select.h","!defined(CONFIG_DISABLE_SIGNALS) && !defined(CONFIG_DISABLE_POLL) && (CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0)","int","int","FAR fd_set*","FAR fd_set*","FAR fd_set*","FAR const struct timespec *","FAR const sigset_t *" "pwrite","unistd.h","CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0","ssize_t","int","FAR const void*","size_t","off_t" "posix_spawnp","spawn.h","!defined(CONFIG_BINFMT_DISABLE) && defined(CONFIG_LIBC_EXECFUNCS) && defined(CONFIG_LIB_ENVPATH)","int","FAR pid_t *","FAR const char *","FAR const posix_spawn_file_actions_t *","FAR const posix_spawnattr_t *","FAR char *const []|FAR char *const *","FAR char *const []|FAR char *const *" "posix_spawn","spawn.h","!defined(CONFIG_BINFMT_DISABLE) && defined(CONFIG_LIBC_EXECFUNCS) && !defined(CONFIG_LIB_ENVPATH)","int","FAR pid_t *","FAR const char *","FAR const posix_spawn_file_actions_t *","FAR const posix_spawnattr_t *","FAR char *const []|FAR char *const *","FAR char *const []|FAR char *const *" diff --git a/syscall/syscall_lookup.h b/syscall/syscall_lookup.h index 2ec407c024a..679d6c4c2ed 100644 --- a/syscall/syscall_lookup.h +++ b/syscall/syscall_lookup.h @@ -210,6 +210,8 @@ SYSCALL_LOOKUP(up_assert, 2, STUB_up_assert) # ifndef CONFIG_DISABLE_POLL SYSCALL_LOOKUP(poll, 3, STUB_poll) SYSCALL_LOOKUP(select, 5, STUB_select) + SYSCALL_LOOKUP(ppoll, 4, STUB_ppoll) + SYSCALL_LOOKUP(pselect, 6, STUB_pselect) # endif # ifdef CONFIG_NETDEV_IFINDEX SYSCALL_LOOKUP(if_indextoname, 2, STUB_if_indextoname) diff --git a/syscall/syscall_stublookup.c b/syscall/syscall_stublookup.c index e67506750b2..482faf5c1eb 100644 --- a/syscall/syscall_stublookup.c +++ b/syscall/syscall_stublookup.c @@ -205,6 +205,11 @@ uintptr_t STUB_poll(int nbr, uintptr_t parm1, uintptr_t parm2, uintptr_t parm3); uintptr_t STUB_select(int nbr, uintptr_t parm1, uintptr_t parm2, uintptr_t parm3, uintptr_t parm4, uintptr_t parm5); +uintptr_t STUB_ppoll(int nbr, uintptr_t parm1, uintptr_t parm2, + uintptr_t parm3, uintptr_t parm4); +uintptr_t STUB_pselect(int nbr, uintptr_t parm1, uintptr_t parm2, + uintptr_t parm3, uintptr_t parm4, uintptr_t parm5, + uintptr_t parm6); /* Asynchronous I/O */