source: rtems/c/src/exec/rtems/src/timerserver.c @ 1ad83eb

4.104.114.84.95
Last change on this file since 1ad83eb was 1ad83eb, checked in by Joel Sherrill <joel.sherrill@…>, on Jan 22, 2002 at 7:13:10 PM

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

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