source: rtems/c/src/exec/rtems/src/timerserver.c @ 422289e

4.104.114.84.95
Last change on this file since 422289e was 422289e, checked in by Joel Sherrill <joel.sherrill@…>, on Jan 29, 2002 at 6:18:14 PM

2001-01-29 Joel Sherrill <joel@…>

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