123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379 |
- /****************************************************************************
- * sched/timer/timer_settime.c
- *
- * Copyright (C) 2007-2010, 2013-2016, 2018 Gregory Nutt. All rights
- * reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * 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 <nuttx/config.h>
- #include <stdint.h>
- #include <time.h>
- #include <string.h>
- #include <errno.h>
- #include <nuttx/irq.h>
- #include "clock/clock.h"
- #include "timer/timer.h"
- #ifndef CONFIG_DISABLE_POSIX_TIMERS
- /****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
- static inline void timer_signotify(FAR struct posix_timer_s *timer);
- static inline void timer_restart(FAR struct posix_timer_s *timer,
- wdparm_t itimer);
- static void timer_timeout(int argc, wdparm_t itimer);
- /****************************************************************************
- * Private Functions
- ****************************************************************************/
- /****************************************************************************
- * Name: timer_signotify
- *
- * Description:
- * This function basically re-implements nxsig_queue() so that the si_code
- * can be correctly set to SI_TIMER
- *
- * Input Parameters:
- * timer - A reference to the POSIX timer that just timed out
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * This function executes in the context of the watchod timer interrupt.
- *
- ****************************************************************************/
- static inline void timer_signotify(FAR struct posix_timer_s *timer)
- {
- DEBUGVERIFY(nxsig_notification(timer->pt_owner, &timer->pt_event,
- SI_TIMER, &timer->pt_work));
- }
- /****************************************************************************
- * Name: timer_restart
- *
- * Description:
- * If a periodic timer has been selected, then restart the watchdog.
- *
- * Input Parameters:
- * timer - A reference to the POSIX timer that just timed out
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * This function executes in the context of the watchdog timer interrupt.
- *
- ****************************************************************************/
- static inline void timer_restart(FAR struct posix_timer_s *timer,
- wdparm_t itimer)
- {
- /* If this is a repetitive timer, then restart the watchdog */
- if (timer->pt_delay)
- {
- timer->pt_last = timer->pt_delay;
- (void)wd_start(timer->pt_wdog, timer->pt_delay,
- (wdentry_t)timer_timeout, 1, itimer);
- }
- }
- /****************************************************************************
- * Name: timer_timeout
- *
- * Description:
- * This function is called if the timeout elapses before the condition is
- * signaled.
- *
- * Input Parameters:
- * argc - the number of arguments (should be 1)
- * itimer - A reference to the POSIX timer that just timed out
- * signo - The signal to use to wake up the task
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * This function executes in the context of the watchod timer interrupt.
- *
- ****************************************************************************/
- static void timer_timeout(int argc, wdparm_t itimer)
- {
- #ifndef CONFIG_CAN_PASS_STRUCTS
- /* On many small machines, pointers are encoded and cannot be simply cast
- * from wdparm_t to struct tcb_s *. The following union works around this
- * (see wdogparm_t).
- */
- union
- {
- FAR struct posix_timer_s *timer;
- wdparm_t itimer;
- } u;
- u.itimer = itimer;
- /* Send the specified signal to the specified task. Increment the
- * reference count on the timer first so that will not be deleted until
- * after the signal handler returns.
- */
- u.timer->pt_crefs++;
- timer_signotify(u.timer);
- /* Release the reference. timer_release will return nonzero if the timer
- * was not deleted.
- */
- if (timer_release(u.timer))
- {
- /* If this is a repetitive timer, then restart the watchdog */
- timer_restart(u.timer, itimer);
- }
- #else
- FAR struct posix_timer_s *timer = (FAR struct posix_timer_s *)itimer;
- /* Send the specified signal to the specified task. Increment the
- * reference count on the timer first so that will not be deleted until
- * after the signal handler returns.
- */
- timer->pt_crefs++;
- timer_signotify(timer);
- /* Release the reference. timer_release will return nonzero if the timer
- * was not deleted.
- */
- if (timer_release(timer))
- {
- /* If this is a repetitive timer, the restart the watchdog */
- timer_restart(timer, itimer);
- }
- #endif
- }
- /****************************************************************************
- * Public Functions
- ****************************************************************************/
- /****************************************************************************
- * Name: timer_settime
- *
- * Description:
- * The timer_settime() function sets the time until the next expiration of
- * the timer specified by timerid from the it_value member of the value
- * argument and arm the timer if the it_value member of value is non-zero.
- * If the specified timer was already armed when timer_settime() is
- * called, this call will reset the time until next expiration to the
- * value specified. If the it_value member of value is zero, the timer
- * will be disarmed. The effect of disarming or resetting a timer with
- * pending expiration notifications is unspecified.
- *
- * If the flag TIMER_ABSTIME is not set in the argument flags,
- * timer_settime() will behave as if the time until next expiration is set
- * to be equal to the interval specified by the it_value member of value.
- * That is, the timer will expire in it_value nanoseconds from when the
- * call is made. If the flag TIMER_ABSTIME is set in the argument flags,
- * timer_settime() will behave as if the time until next expiration is set
- * to be equal to the difference between the absolute time specified by
- * the it_value member of value and the current value of the clock
- * associated with timerid. That is, the timer will expire when the clock
- * reaches the value specified by the it_value member of value. If the
- * specified time has already passed, the function will succeed and the
- * expiration notification will be made.
- *
- * The reload value of the timer will be set to the value specified by the
- * it_interval member of value. When a timer is armed with a non-zero
- * it_interval, a periodic (or repetitive) timer is specified.
- *
- * Time values that are between two consecutive non-negative integer
- * multiples of the resolution of the specified timer will be rounded up
- * to the larger multiple of the resolution. Quantization error will not
- * cause the timer to expire earlier than the rounded time value.
- *
- * If the argument ovalue is not NULL, the timer_settime() function will
- * store, in the location referenced by ovalue, a value representing the
- * previous amount of time before the timer would have expired, or zero if
- * the timer was disarmed, together with the previous timer reload value.
- * Timers will not expire before their scheduled time.
- *
- * Input Parameters:
- * timerid - The pre-thread timer, previously created by the call to
- * timer_create(), to be be set.
- * flags - Specifies characteristics of the timer (see above)
- * value - Specifies the timer value to set
- * ovalue - A location in which to return the time remaining from the
- * previous timer setting. (ignored)
- *
- * Returned Value:
- * If the timer_settime() succeeds, a value of 0 (OK) will be returned.
- * If an error occurs, the value -1 (ERROR) will be returned, and errno set
- * to indicate the error.
- *
- * EINVAL - The timerid argument does not correspond to an ID returned by
- * timer_create() but not yet deleted by timer_delete().
- * EINVAL - A value structure specified a nanosecond value less than zero or
- * greater than or equal to 1000 million, and the it_value member of that
- * structure did not specify zero seconds and nanoseconds.
- *
- * Assumptions:
- *
- ****************************************************************************/
- int timer_settime(timer_t timerid, int flags,
- FAR const struct itimerspec *value,
- FAR struct itimerspec *ovalue)
- {
- FAR struct posix_timer_s *timer = (FAR struct posix_timer_s *)timerid;
- irqstate_t intflags;
- sclock_t delay;
- int ret = OK;
- /* Some sanity checks */
- if (!timer || !value)
- {
- set_errno(EINVAL);
- return ERROR;
- }
- /* Disarm the timer (in case the timer was already armed when timer_settime()
- * is called).
- */
- (void)wd_cancel(timer->pt_wdog);
- /* Cancel any pending notification */
- nxsig_cancel_notification(&timer->pt_work);
- /* If the it_value member of value is zero, the timer will not be re-armed */
- if (value->it_value.tv_sec <= 0 && value->it_value.tv_nsec <= 0)
- {
- return OK;
- }
- /* Setup up any repetitive timer */
- if (value->it_interval.tv_sec > 0 || value->it_interval.tv_nsec > 0)
- {
- (void)clock_time2ticks(&value->it_interval, &delay);
- /* REVISIT: Should pt_delay be sclock_t? */
- timer->pt_delay = (int)delay;
- }
- else
- {
- timer->pt_delay = 0;
- }
- /* We need to disable timer interrupts through the following section so
- * that the system timer is stable.
- */
- intflags = enter_critical_section();
- /* Check if abstime is selected */
- if ((flags & TIMER_ABSTIME) != 0)
- {
- /* Calculate a delay corresponding to the absolute time in 'value'.
- * NOTE: We have internal knowledge the clock_abstime2ticks only
- * returns an error if clockid != CLOCK_REALTIME.
- */
- (void)clock_abstime2ticks(CLOCK_REALTIME, &value->it_value, &delay);
- }
- else
- {
- /* Calculate a delay assuming that 'value' holds the relative time
- * to wait. We have internal knowledge that clock_time2ticks always
- * returns success.
- */
- (void)clock_time2ticks(&value->it_value, &delay);
- }
- /* If the time is in the past or now, then set up the next interval
- * instead (assuming a repetitive timer).
- */
- if (delay <= 0)
- {
- delay = timer->pt_delay;
- }
- /* Then start the watchdog */
- if (delay > 0)
- {
- /* REVISIT: Should pt_last be sclock_t? Should wd_start delay be
- * sclock_t?
- */
- timer->pt_last = delay;
- ret = wd_start(timer->pt_wdog, delay, (wdentry_t)timer_timeout,
- 1, (uint32_t)((wdparm_t)timer));
- if (ret < 0)
- {
- set_errno(-ret);
- ret = ERROR;
- }
- else
- {
- ret = OK;
- }
- }
- leave_critical_section(intflags);
- return ret;
- }
- #endif /* CONFIG_DISABLE_POSIX_TIMERS */
|