source: rtems/cpukit/rtems/src/timerserver.c @ 894d01c

4.104.114.84.9
Last change on this file since 894d01c was 894d01c, checked in by Joel Sherrill <joel.sherrill@…>, on Mar 29, 2002 at 3:32:18 PM

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

  • Per PR147 addressed problems when reseting and inserting a timer into a timer chain that did not honor time passage since the last time the timer server was scheduled and the new insertion.
  • include/rtems/rtems/timer.h, src/timerreset.c, src/timerserver.c, src/timerserverfireafter.c, src/timerserverfirewhen.c: Broke up the "reset server" routine into a set of very specific routines that allowed the server to be unscheduled, timer chains to be "synchronized" with the current time before inserting a new timer.
  • Property mode set to 100644
File size: 9.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
54Watchdog_Control _Timer_Seconds_timer;
55
56/*PAGE
57 *
58 *  _Timer_Server_body
59 *
60 *  This is the server for task based timers.  This task executes whenever
61 *  a task-based timer should fire.  It services both "after" and "when"
62 *  timers.  It is not created automatically but must be created explicitly
63 *  by the application before task-based timers may be initiated.
64 *
65 *  Input parameters:
66 *    Ignored - the task argument is ignored
67 *
68 *  Output parameters:  NONE
69 */
70
71Thread _Timer_Server_body(
72  unsigned32 ignored
73)
74{
75  /*
76   *  Initialize the "last time" markers to indicate the timer that
77   *  the server was initiated.
78   */
79
80  _Timer_Server_ticks_last_time   = _Watchdog_Ticks_since_boot;
81  _Timer_Server_seconds_last_time = _TOD_Seconds_since_epoch;
82
83  _Thread_Disable_dispatch();
84  while(1) {
85
86    /*
87     *  Block until there is something to do.
88     */
89
90      _Thread_Set_state( _Timer_Server, STATES_DELAYING );
91      _Timer_Server_reset_ticks_timer();
92      _Timer_Server_reset_seconds_timer();
93    _Thread_Enable_dispatch();
94
95    /*
96     *  At this point, at least one of the timers this task relies
97     *  upon has fired.  Stop them both while we process any outstanding
98     *  timers.  Before we block, we will restart them.
99     */
100 
101      _Timer_Server_stop_ticks_timer();
102      _Timer_Server_stop_seconds_timer();
103
104    /*
105     *  Disable dispatching while processing the timers since we want
106     *  to mimic the environment that non-task-based TSRs execute in.
107     *  This ensures that the primary difference is that _ISR_Nest_level
108     *  is 0 for task-based timers and non-zero for the others.
109     */
110
111    _Thread_Disable_dispatch();
112      _Timer_Server_process_ticks_chain();
113      _Timer_Server_process_seconds_chain();
114  }
115}
116
117/*PAGE
118 *
119 *  rtems_timer_initiate_server
120 *
121 *  This directive creates and starts the server for task-based timers.
122 *  It must be invoked before any task-based timers can be initiated.
123 *
124 *  Input parameters:
125 *    priority         - timer server priority
126 *    stack_size       - stack size in bytes
127 *    attribute_set    - timer server attributes
128 *
129 *  Output parameters:
130 *    RTEMS_SUCCESSFUL - if successful
131 *    error code       - if unsuccessful
132 */
133
134
135rtems_status_code rtems_timer_initiate_server(
136  unsigned32           priority,
137  unsigned32           stack_size,
138  rtems_attribute      attribute_set
139)
140{
141  rtems_id            id;
142  rtems_status_code   status;
143  rtems_task_priority _priority;
144
145  /*
146   *  Make sure the requested priority is valid.
147   */
148
149  _priority = priority;
150  if ( priority == RTEMS_TIMER_SERVER_DEFAULT_PRIORITY ) 
151    _priority = 0;
152  else if ( !_RTEMS_tasks_Priority_is_valid( priority ) )
153    return RTEMS_INVALID_PRIORITY;
154
155  /*
156   *  Just to make sure the test versus create/start operation are atomic.
157   */
158
159  _Thread_Disable_dispatch();
160
161  if ( _Timer_Server ) {
162    _Thread_Enable_dispatch();
163    return RTEMS_INCORRECT_STATE;
164  }
165
166  /*
167   *  Create the Timer Server with the name the name of "TIME".  The attribute
168   *  RTEMS_SYSTEM_TASK allows us to set a priority to 0 which will makes it
169   *  higher than any other task in the system.  It can be viewed as a low
170   *  priority interrupt.  It is also always NO_PREEMPT so it looks like
171   *  an interrupt to other tasks.
172   *
173   *  We allow the user to override the default priority because the Timer
174   *  Server can invoke TSRs which must adhere to language run-time or
175   *  other library rules.  For example, if using a TSR written in Ada the
176   *  Server should run at the same priority as the priority Ada task.
177   *  Otherwise, the priority ceiling for the mutex used to protect the
178   *  GNAT run-time is violated.
179   */
180
181  status = rtems_task_create(
182    0x4954454d,           /* "TIME" */
183    _priority,            /* create with priority 1 since 0 is illegal */
184    stack_size,           /* let user specify stack size */
185    RTEMS_NO_PREEMPT,     /* no preempt is like an interrupt */
186                          /* user may want floating point but we need */
187                          /*   system task specified for 0 priority */
188    attribute_set | RTEMS_SYSTEM_TASK,
189    &id                   /* get the id back */
190  );
191  if (status) {
192    _Thread_Enable_dispatch();
193    return status;
194  }
195
196  status = rtems_task_start(
197    id,                                    /* the id from create */
198    (rtems_task_entry) _Timer_Server_body, /* the timer server entry point */
199    0                                      /* there is no argument */
200  );
201  if (status) {
202    /*
203     *  One would expect a call to rtems_task_delete() here to clean up
204     *  but there is actually no way (in normal circumstances) that the
205     *  start can fail.  The id and starting address are known to be
206     *  be good.  If this service fails, something is weirdly wrong on the
207     *  target such as a stray write in an ISR or incorrect memory layout.
208     */
209    _Thread_Enable_dispatch();
210    return status;
211  }
212
213  /*
214   *  We work with the TCB pointer, not the ID, so we need to convert
215   *  to a TCB pointer from here out.
216   *
217   *  NOTE: Setting the pointer to the Timer Server TCB to a value other than
218   *        NULL indicates that task-based timer support is initialized.
219   */
220
221  _Timer_Server = (Thread_Control *)_Objects_Get_local_object(
222    &_RTEMS_tasks_Information,
223    _Objects_Get_index(id)
224  );
225
226  /*
227   *  Initialize the timer lists that the server will manage.
228   */
229
230  _Chain_Initialize_empty( &_Timer_Ticks_chain );
231  _Chain_Initialize_empty( &_Timer_Seconds_chain );
232
233  /*
234   *  Initialize the timers that will be used to control when the
235   *  Timer Server wakes up and services the task-based timers.
236   */
237
238  _Watchdog_Initialize( &_Timer_Server->Timer, _Thread_Delay_ended, id, NULL );
239  _Watchdog_Initialize( &_Timer_Seconds_timer, _Thread_Delay_ended, id, NULL );
240
241  _Thread_Enable_dispatch();
242  return RTEMS_SUCCESSFUL;
243}
244
245/*PAGE
246 *
247 *  _Timer_Server_process_ticks_chain
248 *
249 *  This routine is responsible for adjusting the list of task-based
250 *  interval timers to reflect the passage of time.
251 *
252 *  Input parameters:   NONE
253 *
254 *  Output parameters:  NONE
255 */
256
257void _Timer_Server_process_ticks_chain(void)
258{
259  Watchdog_Interval snapshot;
260  Watchdog_Interval ticks;
261
262  snapshot = _Watchdog_Ticks_since_boot;
263  if ( snapshot >= _Timer_Server_ticks_last_time )
264     ticks = snapshot - _Timer_Server_ticks_last_time;
265  else
266     ticks = (0xFFFFFFFF - _Timer_Server_ticks_last_time) + snapshot;
267 
268  _Timer_Server_ticks_last_time = snapshot;
269  _Watchdog_Adjust( &_Timer_Ticks_chain, WATCHDOG_FORWARD, ticks );
270}
271
272/*PAGE
273 *
274 *  _Timer_Server_process_seconds_chain
275 *
276 *  This routine is responsible for adjusting the list of task-based
277 *  time of day timers to reflect the passage of time.
278 *
279 *  Input parameters:   NONE
280 *
281 *  Output parameters:  NONE
282 */
283
284void _Timer_Server_process_seconds_chain(void)
285{
286  Watchdog_Interval snapshot;
287  Watchdog_Interval ticks;
288
289  /*
290   *  Process the seconds chain.  Start by checking that the Time
291   *  of Day (TOD) has not been set backwards.  If it has then
292   *  we want to adjust the _Timer_Seconds_chain to indicate this.
293   */
294
295  snapshot =  _TOD_Seconds_since_epoch;
296  if ( snapshot > _Timer_Server_seconds_last_time ) {
297    /*
298     *  This path is for normal forward movement and cases where the
299     *  TOD has been set forward.
300     */
301
302    ticks = snapshot - _Timer_Server_seconds_last_time;
303    _Watchdog_Adjust( &_Timer_Seconds_chain, WATCHDOG_FORWARD, ticks );
304
305  } else if ( snapshot < _Timer_Server_seconds_last_time ) { 
306     /*
307      *  The current TOD is before the last TOD which indicates that
308      *  TOD has been set backwards.
309      */
310
311     ticks = _Timer_Server_seconds_last_time - snapshot;
312     _Watchdog_Adjust( &_Timer_Seconds_chain, WATCHDOG_BACKWARD, ticks );
313  }
314  _Timer_Server_seconds_last_time = snapshot;
315}
316
Note: See TracBrowser for help on using the repository browser.