source: rtems/cpukit/rtems/src/timerserver.c @ 115fb76

4.104.114.95
Last change on this file since 115fb76 was 115fb76, checked in by Joel Sherrill <joel.sherrill@…>, on 12/14/07 at 17:37:12

2007-12-14 Joel Sherrill <joel.sherrill@…>

  • posix/src/sleep.c, posix/src/usleep.c: Add copyright header.
  • rtems/src/ratemonreportstatistics.c, rtems/src/timerserver.c: Minor cleanup to improve testability and eliminate dead code.
  • Property mode set to 100644
File size: 9.4 KB
Line 
1/*
2 *  Timer Manager - rtems_timer_initiate_server directive along with
3 *      the Timer Server Body and support routines
4 *
5 *  COPYRIGHT (c) 1989-2002.
6 *  On-Line Applications Research Corporation (OAR).
7 *
8 *  The license and distribution terms for this file may be
9 *  found in the file LICENSE in this distribution or at
10 *  http://www.rtems.com/license/LICENSE.
11 *
12 *  $Id$
13 */
14
15#if HAVE_CONFIG_H
16#include "config.h"
17#endif
18
19#include <rtems/system.h>
20#include <rtems/rtems/status.h>
21#include <rtems/rtems/support.h>
22#include <rtems/score/object.h>
23#include <rtems/score/thread.h>
24#include <rtems/rtems/timer.h>
25#include <rtems/score/tod.h>
26#include <rtems/score/watchdog.h>
27
28#include <rtems/rtems/tasks.h>
29#include <rtems/rtems/support.h>
30#include <rtems/score/thread.h>
31
32/*
33 *  The following chains contain the list of interval timers that are
34 *  executed in the context of the Timer Server.
35 *
36 *  NOTE: These are prototyped in rtems/timer/timer.h but since we
37 *        do not actually use them until after the Timer Server is
38 *        initiated, we can actually declare them here and avoid forcing
39 *        them into the minimum footprint.
40 */
41
42Chain_Control _Timer_Ticks_chain;
43Chain_Control _Timer_Seconds_chain;
44
45/*
46 *  These variables keep track of the last time the Timer Server actually
47 *  processed the chain.
48 */
49
50Watchdog_Interval _Timer_Server_seconds_last_time;
51Watchdog_Interval _Timer_Server_ticks_last_time;
52
53/*
54 *  The timer used to control when the Timer Server wakes up to service
55 *  "when" timers.
56 */
57
58Watchdog_Control _Timer_Seconds_timer;
59
60/*PAGE
61 *
62 *  _Timer_Server_body
63 *
64 *  This is the server for task based timers.  This task executes whenever
65 *  a task-based timer should fire.  It services both "after" and "when"
66 *  timers.  It is not created automatically but must be created explicitly
67 *  by the application before task-based timers may be initiated.
68 *
69 *  Input parameters:
70 *    Ignored - the task argument is ignored
71 *
72 *  Output parameters:  NONE
73 */
74
75Thread _Timer_Server_body(
76  uint32_t   ignored
77)
78{
79  /*
80   *  Initialize the "last time" markers to indicate the timer that
81   *  the server was initiated.
82   */
83
84  _Timer_Server_ticks_last_time   = _Watchdog_Ticks_since_boot;
85  _Timer_Server_seconds_last_time = _TOD_Seconds_since_epoch;
86
87  _Thread_Disable_dispatch();
88  while(1) {
89
90    /*
91     *  Block until there is something to do.
92     */
93
94      _Thread_Set_state( _Timer_Server, STATES_DELAYING );
95      _Timer_Server_reset_ticks_timer();
96      _Timer_Server_reset_seconds_timer();
97    _Thread_Enable_dispatch();
98
99    /*
100     *  At this point, at least one of the timers this task relies
101     *  upon has fired.  Stop them both while we process any outstanding
102     *  timers.  Before we block, we will restart them.
103     */
104
105      _Timer_Server_stop_ticks_timer();
106      _Timer_Server_stop_seconds_timer();
107
108    /*
109     *  Disable dispatching while processing the timers since we want
110     *  to mimic the environment that non-task-based TSRs execute in.
111     *  This ensures that the primary difference is that _ISR_Nest_level
112     *  is 0 for task-based timers and non-zero for the others.
113     */
114
115    _Thread_Disable_dispatch();
116      _Timer_Server_process_ticks_chain();
117      _Timer_Server_process_seconds_chain();
118  }
119
120  return 0;   /* unreached - only to remove warnings */
121}
122
123/*PAGE
124 *
125 *  rtems_timer_initiate_server
126 *
127 *  This directive creates and starts the server for task-based timers.
128 *  It must be invoked before any task-based timers can be initiated.
129 *
130 *  Input parameters:
131 *    priority         - timer server priority
132 *    stack_size       - stack size in bytes
133 *    attribute_set    - timer server attributes
134 *
135 *  Output parameters:
136 *    RTEMS_SUCCESSFUL - if successful
137 *    error code       - if unsuccessful
138 */
139
140
141rtems_status_code rtems_timer_initiate_server(
142  uint32_t             priority,
143  uint32_t             stack_size,
144  rtems_attribute      attribute_set
145)
146{
147  rtems_id            id;
148  rtems_status_code   status;
149  rtems_task_priority _priority;
150
151  /*
152   *  Make sure the requested priority is valid.  The if is
153   *  structured so we check it is invalid before looking for
154   *  a specific invalid value as the default.
155   */
156
157  _priority = priority;
158  if ( !_RTEMS_tasks_Priority_is_valid( priority ) ) {
159    if ( priority != RTEMS_TIMER_SERVER_DEFAULT_PRIORITY )
160      return RTEMS_INVALID_PRIORITY;
161    _priority = 0;
162  }
163
164  /*
165   *  Just to make sure the test versus create/start operation are atomic.
166   */
167
168  _Thread_Disable_dispatch();
169
170  if ( _Timer_Server ) {
171    _Thread_Enable_dispatch();
172    return RTEMS_INCORRECT_STATE;
173  }
174
175  /*
176   *  Create the Timer Server with the name the name of "TIME".  The attribute
177   *  RTEMS_SYSTEM_TASK allows us to set a priority to 0 which will makes it
178   *  higher than any other task in the system.  It can be viewed as a low
179   *  priority interrupt.  It is also always NO_PREEMPT so it looks like
180   *  an interrupt to other tasks.
181   *
182   *  We allow the user to override the default priority because the Timer
183   *  Server can invoke TSRs which must adhere to language run-time or
184   *  other library rules.  For example, if using a TSR written in Ada the
185   *  Server should run at the same priority as the priority Ada task.
186   *  Otherwise, the priority ceiling for the mutex used to protect the
187   *  GNAT run-time is violated.
188   */
189
190  status = rtems_task_create(
191    rtems_build_name('T','I','M','E'),           /* "TIME" */
192    _priority,            /* create with priority 1 since 0 is illegal */
193    stack_size,           /* let user specify stack size */
194    RTEMS_NO_PREEMPT,     /* no preempt is like an interrupt */
195                          /* user may want floating point but we need */
196                          /*   system task specified for 0 priority */
197    attribute_set | RTEMS_SYSTEM_TASK,
198    &id                   /* get the id back */
199  );
200  if (status) {
201    _Thread_Enable_dispatch();
202    return status;
203  }
204
205  status = rtems_task_start(
206    id,                                    /* the id from create */
207    (rtems_task_entry) _Timer_Server_body, /* the timer server entry point */
208    0                                      /* there is no argument */
209  );
210  if (status) {
211    /*
212     *  One would expect a call to rtems_task_delete() here to clean up
213     *  but there is actually no way (in normal circumstances) that the
214     *  start can fail.  The id and starting address are known to be
215     *  be good.  If this service fails, something is weirdly wrong on the
216     *  target such as a stray write in an ISR or incorrect memory layout.
217     */
218    _Thread_Enable_dispatch();
219    return status;
220  }
221
222  /*
223   *  We work with the TCB pointer, not the ID, so we need to convert
224   *  to a TCB pointer from here out.
225   *
226   *  NOTE: Setting the pointer to the Timer Server TCB to a value other than
227   *        NULL indicates that task-based timer support is initialized.
228   */
229
230  _Timer_Server = (Thread_Control *)_Objects_Get_local_object(
231    &_RTEMS_tasks_Information,
232    _Objects_Get_index(id)
233  );
234
235  /*
236   *  Initialize the timer lists that the server will manage.
237   */
238
239  _Chain_Initialize_empty( &_Timer_Ticks_chain );
240  _Chain_Initialize_empty( &_Timer_Seconds_chain );
241
242  /*
243   *  Initialize the timers that will be used to control when the
244   *  Timer Server wakes up and services the task-based timers.
245   */
246
247  _Watchdog_Initialize( &_Timer_Server->Timer, _Thread_Delay_ended, id, NULL );
248  _Watchdog_Initialize( &_Timer_Seconds_timer, _Thread_Delay_ended, id, NULL );
249
250  _Thread_Enable_dispatch();
251  return RTEMS_SUCCESSFUL;
252}
253
254/*PAGE
255 *
256 *  _Timer_Server_process_ticks_chain
257 *
258 *  This routine is responsible for adjusting the list of task-based
259 *  interval timers to reflect the passage of time.
260 *
261 *  Input parameters:   NONE
262 *
263 *  Output parameters:  NONE
264 */
265
266void _Timer_Server_process_ticks_chain(void)
267{
268  Watchdog_Interval snapshot;
269  Watchdog_Interval ticks;
270
271  snapshot = _Watchdog_Ticks_since_boot;
272  if ( snapshot >= _Timer_Server_ticks_last_time )
273     ticks = snapshot - _Timer_Server_ticks_last_time;
274  else
275     ticks = (0xFFFFFFFF - _Timer_Server_ticks_last_time) + snapshot;
276
277  _Timer_Server_ticks_last_time = snapshot;
278  _Watchdog_Adjust( &_Timer_Ticks_chain, WATCHDOG_FORWARD, ticks );
279}
280
281/*PAGE
282 *
283 *  _Timer_Server_process_seconds_chain
284 *
285 *  This routine is responsible for adjusting the list of task-based
286 *  time of day timers to reflect the passage of time.
287 *
288 *  Input parameters:   NONE
289 *
290 *  Output parameters:  NONE
291 */
292
293void _Timer_Server_process_seconds_chain(void)
294{
295  Watchdog_Interval snapshot;
296  Watchdog_Interval ticks;
297
298  /*
299   *  Process the seconds chain.  Start by checking that the Time
300   *  of Day (TOD) has not been set backwards.  If it has then
301   *  we want to adjust the _Timer_Seconds_chain to indicate this.
302   */
303
304  snapshot =  _TOD_Seconds_since_epoch;
305  if ( snapshot > _Timer_Server_seconds_last_time ) {
306    /*
307     *  This path is for normal forward movement and cases where the
308     *  TOD has been set forward.
309     */
310
311    ticks = snapshot - _Timer_Server_seconds_last_time;
312    _Watchdog_Adjust( &_Timer_Seconds_chain, WATCHDOG_FORWARD, ticks );
313
314  } else if ( snapshot < _Timer_Server_seconds_last_time ) {
315     /*
316      *  The current TOD is before the last TOD which indicates that
317      *  TOD has been set backwards.
318      */
319
320     ticks = _Timer_Server_seconds_last_time - snapshot;
321     _Watchdog_Adjust( &_Timer_Seconds_chain, WATCHDOG_BACKWARD, ticks );
322  }
323  _Timer_Server_seconds_last_time = snapshot;
324}
Note: See TracBrowser for help on using the repository browser.