source: rtems/cpukit/posix/src/timersettime.c @ bb9f09f

Last change on this file since bb9f09f was bb9f09f, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 31, 2016 at 12:07:34 PM

posix: Fix timer interval

Do not overwrite timer interval with initial interval in
_POSIX_Timer_Insert().

Close #2798.

  • Property mode set to 100644
File size: 5.4 KB
Line 
1/**
2 * @file
3 *
4 * @brief Function Arms or Disarms the Timer Identified by timerid
5 * @ingroup POSIXAPI
6 */
7
8/*
9 *  14.2.4 Per-Process Timers, P1003.1b-1993, p. 267
10 *
11 *  COPYRIGHT (c) 1989-2008.
12 *  On-Line Applications Research Corporation (OAR).
13 *
14 *  The license and distribution terms for this file may be
15 *  found in the file LICENSE in this distribution or at
16 *  http://www.rtems.org/license/LICENSE.
17 */
18
19#if HAVE_CONFIG_H
20#include "config.h"
21#endif
22
23#include <time.h>
24#include <errno.h>
25
26#include <rtems/posix/ptimer.h>
27#include <rtems/posix/timerimpl.h>
28#include <rtems/score/todimpl.h>
29#include <rtems/score/watchdogimpl.h>
30#include <rtems/seterr.h>
31
32static void _POSIX_Timer_Insert(
33  POSIX_Timer_Control *ptimer,
34  Per_CPU_Control     *cpu,
35  Watchdog_Interval    ticks
36)
37{
38  /* The state really did not change but just to be safe */
39  ptimer->state = POSIX_TIMER_STATE_CREATE_RUN;
40
41  /* Store the time when the timer was started again */
42  _TOD_Get_as_timespec( &ptimer->time );
43
44  _Watchdog_Insert(
45    &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ],
46    &ptimer->Timer,
47    cpu->Watchdog.ticks + ticks
48  );
49}
50
51/*
52 *  This is the operation that is run when a timer expires
53 */
54void _POSIX_Timer_TSR( Watchdog_Control *the_watchdog )
55{
56  POSIX_Timer_Control *ptimer;
57  ISR_lock_Context     lock_context;
58  Per_CPU_Control     *cpu;
59
60  ptimer = RTEMS_CONTAINER_OF( the_watchdog, POSIX_Timer_Control, Timer );
61  _ISR_lock_ISR_disable( &lock_context );
62  cpu = _POSIX_Timer_Acquire_critical( ptimer, &lock_context );
63
64  /* Increment the number of expirations. */
65  ptimer->overrun = ptimer->overrun + 1;
66
67  /* The timer must be reprogrammed */
68  if ( ( ptimer->timer_data.it_interval.tv_sec  != 0 ) ||
69       ( ptimer->timer_data.it_interval.tv_nsec != 0 ) ) {
70    _POSIX_Timer_Insert( ptimer, cpu, ptimer->ticks );
71  } else {
72   /* Indicates that the timer is stopped */
73   ptimer->state = POSIX_TIMER_STATE_CREATE_STOP;
74  }
75
76  _POSIX_Timer_Release( cpu, &lock_context );
77
78  /*
79   * The sending of the signal to the process running the handling function
80   * specified for that signal is simulated
81   */
82
83  if ( pthread_kill ( ptimer->thread_id, ptimer->inf.sigev_signo ) ) {
84    _Assert( FALSE );
85    /*
86     * TODO: What if an error happens at run-time? This should never
87     *       occur because the timer should be canceled if the thread
88     *       is deleted. This method is being invoked from the Clock
89     *       Tick ISR so even if we decide to take action on an error,
90     *       we don't have many options. We shouldn't shut the system down.
91     */
92  }
93
94  /* After the signal handler returns, the count of expirations of the
95   * timer must be set to 0.
96   */
97  ptimer->overrun = 0;
98}
99
100int timer_settime(
101  timer_t                  timerid,
102  int                      flags,
103  const struct itimerspec *__restrict value,
104  struct itimerspec       *__restrict ovalue
105)
106{
107  POSIX_Timer_Control *ptimer;
108  ISR_lock_Context     lock_context;
109  uint32_t             initial_period;
110  struct itimerspec    normalize;
111
112  if ( !value )
113    rtems_set_errno_and_return_minus_one( EINVAL );
114
115  /*
116   * First, it verifies if the structure "value" is correct   
117   * if the number of nanoseconds is not correct return EINVAL
118   */
119  if ( !_Timespec_Is_valid( &(value->it_value) ) ) {
120    rtems_set_errno_and_return_minus_one( EINVAL );
121  }
122  if ( !_Timespec_Is_valid( &(value->it_interval) ) ) {
123    rtems_set_errno_and_return_minus_one( EINVAL );
124  }
125
126  if ( flags != TIMER_ABSTIME && flags != POSIX_TIMER_RELATIVE ) {
127    rtems_set_errno_and_return_minus_one( EINVAL );
128  }
129
130  normalize = *value;
131
132  /* Convert absolute to relative time */
133  if (flags == TIMER_ABSTIME) {
134    struct timespec now;
135    _TOD_Get_as_timespec( &now );
136    /* Check for seconds in the past */
137    if ( _Timespec_Greater_than( &now, &normalize.it_value ) )
138      rtems_set_errno_and_return_minus_one( EINVAL );
139    _Timespec_Subtract( &now, &normalize.it_value, &normalize.it_value );
140  }
141
142  /* If the function reaches this point, then it will be necessary to do
143   * something with the structure of times of the timer: to stop, start
144   * or start it again
145   */
146
147  ptimer = _POSIX_Timer_Get( timerid, &lock_context );
148  if ( ptimer != NULL ) {
149    Per_CPU_Control *cpu;
150
151    cpu = _POSIX_Timer_Acquire_critical( ptimer, &lock_context );
152
153    /* Stop the timer */
154    _Watchdog_Remove(
155      &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ],
156      &ptimer->Timer
157    );
158
159    /* First, it verifies if the timer must be stopped */
160    if ( normalize.it_value.tv_sec == 0 && normalize.it_value.tv_nsec == 0 ) {
161      /* The old data of the timer are returned */
162      if ( ovalue )
163        *ovalue = ptimer->timer_data;
164      /* The new data are set */
165      ptimer->timer_data = normalize;
166      /* Indicates that the timer is created and stopped */
167      ptimer->state = POSIX_TIMER_STATE_CREATE_STOP;
168      /* Returns with success */
169      _POSIX_Timer_Release( cpu, &lock_context );
170      return 0;
171    }
172
173    /* Convert from seconds and nanoseconds to ticks */
174    ptimer->ticks  = _Timespec_To_ticks( &value->it_interval );
175    initial_period = _Timespec_To_ticks( &normalize.it_value );
176
177    _POSIX_Timer_Insert( ptimer, cpu, initial_period );
178
179    /*
180     * The timer has been started and is running.  So we return the
181     * old ones in "ovalue"
182     */
183    if ( ovalue )
184      *ovalue = ptimer->timer_data;
185    ptimer->timer_data = normalize;
186    _POSIX_Timer_Release( cpu, &lock_context );
187    return 0;
188  }
189
190  rtems_set_errno_and_return_minus_one( EINVAL );
191}
Note: See TracBrowser for help on using the repository browser.