diff --git a/TODO b/TODO index 51155d4abe1..a69b474fa16 100644 --- a/TODO +++ b/TODO @@ -13,7 +13,7 @@ nuttx/: (1) SMP (1) Memory Management (mm/) (0) Power Management (drivers/pm) - (4) Signals (sched/signal, arch/) + (3) Signals (sched/signal, arch/) (2) pthreads (sched/pthread) (0) Message Queues (sched/mqueue) (8) Kernel/Protected Build @@ -486,26 +486,6 @@ o Signals (sched/signal, arch/) Status: Open Priority: Low. Even if there are only 31 usable signals, that is still a lot. - Title: IMPLEMENT clock_nanosleep() - Description: NuttX currently supports only nanosleep(), not clock_nanosleep(). - clock_nanosleep() permits you to use either CLOCK_REALTIME, CLOCK_MONOTONIC, - or any other clock that may be available. It also permits you to use - a delay to an absolute time rather than a relative delay from the - current time. - - One would think that adding support for clock_nanosleep() should be - simple since it is equivalent to nanosleep() with clock_id == - CLOCK_REALTIME and with flags == 0. However it is not because there - is an underlying assumption that nanosleep uses CLOCK_REALTIME and - logic like the POSIX timer interfaces. The NuttX nanosleep does not - use CLOCK_REALTIME. It uses the system timer directly. Being able to - switch clocks would require a complete redesign of the existing logic - and the redesign would probably not be as compact or robust as the - existing implementation. - Status: Open - Priority: I consider this low priority at least for now and have no immediate - plans to implement clock_nanosleep(). - o pthreads (sched/pthreads) ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/include/sys/syscall.h b/include/sys/syscall.h index 8e6bd759415..9708993d195 100644 --- a/include/sys/syscall.h +++ b/include/sys/syscall.h @@ -227,7 +227,7 @@ # define SYS_sigsuspend (__SYS_signals+5) # define SYS_sigtimedwait (__SYS_signals+6) # define SYS_sigwaitinfo (__SYS_signals+7) -# define SYS_nanosleep (__SYS_signals+8) +# define SYS_clock_nanosleep (__SYS_signals+8) # define __SYS_clock (__SYS_signals+9) #else # define __SYS_clock __SYS_signals diff --git a/include/time.h b/include/time.h index f5243570137..8c92a3b1910 100644 --- a/include/time.h +++ b/include/time.h @@ -1,7 +1,7 @@ /******************************************************************************** * include/time.h * - * Copyright (C) 2007-2011, 2013-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2011, 2013-2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -90,15 +90,17 @@ # define CLOCK_MONOTONIC 1 #endif -/* This is a flag that may be passed to the timer_settime() function */ +/* This is a flag that may be passed to the timer_settime() and + * clock_nanosleep() functions. + */ #define TIMER_ABSTIME 1 #ifndef CONFIG_LIBC_LOCALTIME /* Local time is the same as gmtime in this implementation */ -# define localtime(c) gmtime(c) -# define localtime_r(c,r) gmtime_r(c,r) +# define localtime(c) gmtime(c) +# define localtime_r(c,r) gmtime_r(c,r) #endif /******************************************************************************** @@ -231,6 +233,9 @@ int timer_settime(timer_t timerid, int flags, int timer_gettime(timer_t timerid, FAR struct itimerspec *value); int timer_getoverrun(timer_t timerid); +int clock_nanosleep(clockid_t clockid, int flags, + FAR const struct timespec *rqtp, + FAR struct timespec *rmtp); int nanosleep(FAR const struct timespec *rqtp, FAR struct timespec *rmtp); #ifdef CONFIG_LIBC_LOCALTIME diff --git a/libc/time/Make.defs b/libc/time/Make.defs index 68e62436871..f72fd4f99f1 100644 --- a/libc/time/Make.defs +++ b/libc/time/Make.defs @@ -39,6 +39,10 @@ CSRCS += lib_strftime.c lib_calendar2utc.c lib_daysbeforemonth.c CSRCS += lib_gettimeofday.c lib_isleapyear.c lib_settimeofday.c lib_time.c CSRCS += lib_difftime.c +ifndef CONFIG_DISABLE_SIGNALS +CSRCS += lib_nanosleep.c +endif + ifdef CONFIG_LIBC_LOCALTIME CSRCS += lib_localtime.c lib_asctime.c lib_asctimer.c lib_ctime.c CSRCS += lib_ctimer.c diff --git a/libc/time/lib_nanosleep.c b/libc/time/lib_nanosleep.c new file mode 100644 index 00000000000..ad728de5b8c --- /dev/null +++ b/libc/time/lib_nanosleep.c @@ -0,0 +1,104 @@ +/**************************************************************************** + * libc/time/nanosleep.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nanosleep + * + * Description: + * The nanosleep() function causes the current thread to be suspended from + * execution until either the time interval specified by the rqtp argument + * has elapsed or a signal is delivered to the calling thread and its + * action is to invoke a signal-catching function or to terminate the + * process. The suspension time may be longer than requested because the + * argument value is rounded up to an integer multiple of the sleep + * resolution or because of the scheduling of other activity by the + * system. But, except for the case of being interrupted by a signal, the + * suspension time will not be less than the time specified by rqtp, as + * measured by the system clock, CLOCK_REALTIME. + * + * The use of the nanosleep() function has no effect on the action or + * blockage of any signal. + * + * Parameters: + * rqtp - The amount of time to be suspended from execution. + * rmtp - If the rmtp argument is non-NULL, the timespec structure + * referenced by it is updated to contain the amount of time + * remaining in the interval (the requested time minus the time + * actually slept) + * + * Returned Value: + * If the nanosleep() function returns because the requested time has + * elapsed, its return value is zero. + * + * If the nanosleep() function returns because it has been interrupted by + * a signal, the function returns a value of -1 and sets errno to indicate + * the interruption. If the rmtp argument is non-NULL, the timespec + * structure referenced by it is updated to contain the amount of time + * remaining in the interval (the requested time minus the time actually + * slept). If the rmtp argument is NULL, the remaining time is not + * returned. + * + * If nanosleep() fails, it returns a value of -1 and sets errno to + * indicate the error. The nanosleep() function will fail if: + * + * EINTR - The nanosleep() function was interrupted by a signal. + * EINVAL - The rqtp argument specified a nanosecond value less than + * zero or greater than or equal to 1000 million. + * ENOSYS - The nanosleep() function is not supported by this + * implementation. + * + ****************************************************************************/ + +int nanosleep(FAR const struct timespec *rqtp, FAR struct timespec *rmtp) +{ + /* Calling clock_nanosleep() with the value TIMER_ABSTIME not set in the + * flags argument and with a clock_id of CLOCK_REALTIME is equivalent t + * calling nanosleep() with the same rqtp and rmtp arguments. + */ + + return clock_nanosleep(CLOCK_REALTIME, 0, rqtp, rmtp); +} diff --git a/libc/unistd/lib_sleep.c b/libc/unistd/lib_sleep.c index cb188a9329a..b8a747b5684 100644 --- a/libc/unistd/lib_sleep.c +++ b/libc/unistd/lib_sleep.c @@ -1,7 +1,8 @@ /**************************************************************************** * lib/lib_sleep.c * - * Copyright (C) 2007, 2009, 2012-2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 2012-2013, 2017 Gregory Nutt. All rights + * reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -117,14 +118,14 @@ unsigned int sleep(unsigned int seconds) if (seconds > 0) { - /* Let nanosleep() do all of the work. */ + /* Let clock_nanosleep() do all of the work. */ rqtp.tv_sec = seconds; rqtp.tv_nsec = 0; - ret = nanosleep(&rqtp, &rmtp); + ret = clock_nanosleep(CLOCK_REALTIME, 0, &rqtp, &rmtp); - /* nanosleep() should only fail if it was interrupted by a signal, + /* clock_nanosleep() should only fail if it was interrupted by a signal, * but we treat all errors the same, */ diff --git a/libc/unistd/lib_usleep.c b/libc/unistd/lib_usleep.c index 4e3d4cdb0c4..8e6d8040e35 100644 --- a/libc/unistd/lib_usleep.c +++ b/libc/unistd/lib_usleep.c @@ -1,7 +1,8 @@ /**************************************************************************** * lib/lib_usleep.c * - * Copyright (C) 2007, 2009, 2012-2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 2012-2013, 2017 Gregory Nutt. All rights + * reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -114,13 +115,13 @@ int usleep(useconds_t usec) if (usec) { - /* Let nanosleep() do all of the work. */ + /* Let clock_nanosleep() do all of the work. */ sec = usec / 1000000; rqtp.tv_sec = sec; rqtp.tv_nsec = (usec - (sec * 1000000)) * 1000; - ret = nanosleep(&rqtp, NULL); + ret = clock_nanosleep(CLOCK_REALTIME, 0, &rqtp, NULL); } return ret; diff --git a/sched/signal/sig_nanosleep.c b/sched/signal/sig_nanosleep.c index 6fdb51ae453..86c731d235d 100644 --- a/sched/signal/sig_nanosleep.c +++ b/sched/signal/sig_nanosleep.c @@ -199,35 +199,60 @@ int nxsig_nanosleep(FAR const struct timespec *rqtp, } /**************************************************************************** - * Name: nanosleep + * Name: clock_nanosleep * * Description: - * The nanosleep() function causes the current thread to be suspended from - * execution until either the time interval specified by the rqtp argument - * has elapsed or a signal is delivered to the calling thread and its - * action is to invoke a signal-catching function or to terminate the - * process. The suspension time may be longer than requested because the - * argument value is rounded up to an integer multiple of the sleep - * resolution or because of the scheduling of other activity by the - * system. But, except for the case of being interrupted by a signal, the - * suspension time will not be less than the time specified by rqtp, as - * measured by the system clock, CLOCK_REALTIME. + * If the flag TIMER_ABSTIME is not set in the flags argument, the + * clock_nanosleep() function will cause the current thread to be suspended + * from execution until either the time interval specified by the rqtp + * argument has elapsed, or a signal is delivered to the calling thread + * and its action is to invoke a signal-catching function, or the process + * is terminated. The clock used to measure the time will be the clock + * specified by clock_id. * - * The use of the nanosleep() function has no effect on the action or - * blockage of any signal. + * If the flag TIMER_ABSTIME is set in the flags argument, the + * clock_nanosleep() function will cause the current thread to be + * suspended from execution until either the time value of the clock + * specified by clock_id reaches the absolute time specified by the rqtp + * argument, or a signal is delivered to the calling thread and its action + * is to invoke a signal-catching function, or the process is terminated. If, + * at the time of the call, the time value specified by rqtp is less than + * or equal to the time value of the specified clock, then clock_nanosleep() + * will return immediately and the calling process will not be suspended. + * + * The suspension time caused by this function may be longer than requested + * because the argument value is rounded up to an integer multiple of the + * sleep resolution, or because of the scheduling of other activity by the + * system. But, except for the case of being interrupted by a signal, the + * suspension time for the relative clock_nanosleep() function (that is, + * with the TIMER_ABSTIME flag not set) will not be less than the time + * interval specified by rqtp, as measured by the corresponding clock. The + * suspension for the absolute clock_nanosleep() function (that is, with + * the TIMER_ABSTIME flag set) will be in effect at least until the value + * of the corresponding clock reaches the absolute time specified by rqtp, + * except for the case of being interrupted by a signal. + * + * The use of the clock_nanosleep() function will have no effect on the + * action or blockage of any signal. + * + * The clock_nanosleep() function will fail if the clock_id argument refers + * to the CPU-time clock of the calling thread. It is unspecified whether + * clock_id values of other CPU-time clocks are allowed. * * Parameters: - * rqtp - The amount of time to be suspended from execution. - * rmtp - If the rmtp argument is non-NULL, the timespec structure - * referenced by it is updated to contain the amount of time - * remaining in the interval (the requested time minus the time - * actually slept) + * clockid - The clock to use to interpret the absolute time + * flags - Open flags. TIMER_ABSTIME is the only supported flag. + * rqtp - The amount of time to be suspended from execution. + * rmtp - If the rmtp argument is non-NULL, the timespec structure + * referenced by it is updated to contain the amount of time + * remaining in the interval (the requested time minus the time + * actually slept) * * Returned Value: - * If the nanosleep() function returns because the requested time has + * If the clock_nanosleep() function returns because the requested time has * elapsed, its return value is zero. * - * If the nanosleep() function returns because it has been interrupted by + * If the clock_nanosleep() function returns because it has been interrupted by * a signal, the function returns a value of -1 and sets errno to indicate * the interruption. If the rmtp argument is non-NULL, the timespec * structure referenced by it is updated to contain the amount of time @@ -235,28 +260,66 @@ int nxsig_nanosleep(FAR const struct timespec *rqtp, * slept). If the rmtp argument is NULL, the remaining time is not * returned. * - * If nanosleep() fails, it returns a value of -1 and sets errno to - * indicate the error. The nanosleep() function will fail if: + * If clock_nanosleep() fails, it returns a value of -1 and sets errno to + * indicate the error. The clock_nanosleep() function will fail if: * - * EINTR - The nanosleep() function was interrupted by a signal. + * EINTR - The clock_nanosleep() function was interrupted by a signal. * EINVAL - The rqtp argument specified a nanosecond value less than * zero or greater than or equal to 1000 million. - * ENOSYS - The nanosleep() function is not supported by this + * ENOSYS - The clock_nanosleep() function is not supported by this * implementation. * ****************************************************************************/ -int nanosleep(FAR const struct timespec *rqtp, FAR struct timespec *rmtp) +int clock_nanosleep(clockid_t clockid, int flags, + FAR const struct timespec *rqtp, + FAR struct timespec *rmtp) { int ret; - /* nanosleep() is a cancellation point */ + /* clock_nanosleep() is a cancellation point */ (void)enter_cancellation_point(); - /* Just a wrapper around nxsig_nanosleep() */ + /* Check if absolute time is selected */ + + if ((flags & TIMER_ABSTIME) != 0) + { + struct timespec reltime; + struct timespec now; + irqstate_t irqstate; + + /* Calculate the relative time delay. We need to enter a critical + * section early to assure the relative time is valid from this + * point in time. + */ + + irqstate = enter_critical_section(); + ret = clock_gettime(clockid, &now); + if (ret >= 0) + { + clock_timespec_subtract(rqtp, &now, &reltime); + } + + /* Now that we have the relative time, the remaining operations are + * equivalent to nxsig_nanosleep(). + */ + + ret = nxsig_nanosleep(&reltime, rmtp); + leave_critical_section(irqstate); + } + else + { + /* In the relative time case, clock_nanosleep() is equivalent to + * nanosleep. In this case, it is a paper thin wrapper around + * nxsig_nanosleep(). + */ + + ret = nxsig_nanosleep(rqtp, rmtp); + } + + /* Check if nxsig_nanosleep() succeeded */ - ret = nxsig_nanosleep(rqtp, rmtp); if (ret < 0) { set_errno(-ret); diff --git a/syscall/syscall.csv b/syscall/syscall.csv index 22e1f0490ae..efd9ce73b48 100644 --- a/syscall/syscall.csv +++ b/syscall/syscall.csv @@ -11,6 +11,7 @@ "clearenv","stdlib.h","!defined(CONFIG_DISABLE_ENVIRON)","int" "clock_getres","time.h","","int","clockid_t","struct timespec*" "clock_gettime","time.h","","int","clockid_t","struct timespec*" +"clock_nanosleep","time.h","!defined(CONFIG_DISABLE_SIGNALS)","int","clockid_t","int","FAR const struct timespec *", "FAR struct timespec*" "clock_settime","time.h","","int","clockid_t","const struct timespec*" "clock_systimer","nuttx/clock.h","!defined(__HAVE_KERNEL_GLOBALS)","systime_t" "close","unistd.h","CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0","int","int" @@ -55,7 +56,6 @@ "mq_timedsend","mqueue.h","!defined(CONFIG_DISABLE_MQUEUE)","int","mqd_t","const char*","size_t","int","const struct timespec*" "mq_unlink","mqueue.h","!defined(CONFIG_DISABLE_MQUEUE)","int","const char*" "on_exit","stdlib.h","defined(CONFIG_SCHED_ONEXIT)","int","CODE void (*)(int, FAR void *)","FAR void *" -"nanosleep","time.h","!defined(CONFIG_DISABLE_SIGNALS)","int","FAR const struct timespec *", "FAR struct timespec*" "open","fcntl.h","CONFIG_NFILE_DESCRIPTORS > 0","int","const char*","int","..." "opendir","dirent.h","CONFIG_NFILE_DESCRIPTORS > 0","FAR DIR*","FAR const char*" "pgalloc", "nuttx/arch.h", "defined(CONFIG_BUILD_KERNEL)", "uintptr_t", "uintptr_t", "unsigned int" diff --git a/syscall/syscall_lookup.h b/syscall/syscall_lookup.h index 7153313de40..54b9a8ccddc 100644 --- a/syscall/syscall_lookup.h +++ b/syscall/syscall_lookup.h @@ -157,7 +157,7 @@ SYSCALL_LOOKUP(up_assert, 2, STUB_up_assert) SYSCALL_LOOKUP(sigsuspend, 1, STUB_sigsuspend) SYSCALL_LOOKUP(sigtimedwait, 3, STUB_sigtimedwait) SYSCALL_LOOKUP(sigwaitinfo, 2, STUB_sigwaitinfo) - SYSCALL_LOOKUP(nanosleep, 2, STUB_nanosleep) + SYSCALL_LOOKUP(clock_nanosleep, 4, STUB_clock_nanosleep) #endif /* The following are only defined if the system clock is enabled in the diff --git a/syscall/syscall_stublookup.c b/syscall/syscall_stublookup.c index d58ae5c103d..9a366f28abc 100644 --- a/syscall/syscall_stublookup.c +++ b/syscall/syscall_stublookup.c @@ -153,7 +153,8 @@ uintptr_t STUB_sigsuspend(int nbr, uintptr_t parm1); uintptr_t STUB_sigtimedwait(int nbr, uintptr_t parm1, uintptr_t parm2, uintptr_t parm3); uintptr_t STUB_sigwaitinfo(int nbr, uintptr_t parm1, uintptr_t parm2); -uintptr_t STUB_nanosleep(int nbr, uintptr_t parm1, uintptr_t parm2); +uintptr_t STUB_clock_nanosleep(int nbr, uintptr_t parm1, uintptr_t parm2, + uintptr_t parm3, uintptr_t parm4); /* The following are only defined if the system clock is enabled in the * NuttX configuration.