source: rtems/cpukit/rtems/src/timerserver.c @ e266d13

5
Last change on this file since e266d13 was 03b900d, checked in by Sebastian Huber <sebastian.huber@…>, on 02/18/16 at 07:36:26

score: Replace watchdog handler implementation

Use a red-black tree instead of delta chains.

Close #2344.
Update #2554.
Update #2555.
Close #2606.

  • Property mode set to 100644
File size: 6.9 KB
Line 
1/**
2 *  @file timerserver.c
3 *
4 *  Timer Manager - rtems_timer_initiate_server directive along with
5 *  the Timer Server Body and support routines
6 *
7 *  @note Data specific to the Timer Server is declared in this
8 *        file as the Timer Server so it does not have to be in the
9 *        minimum footprint.  It is only really required when
10 *        task-based timers are used.  Since task-based timers can
11 *        not be started until the server is initiated, this structure
12 *        does not have to be initialized until then.
13 */
14
15/*  COPYRIGHT (c) 1989-2008.
16 *  On-Line Applications Research Corporation (OAR).
17 *
18 *  Copyright (c) 2009, 2016 embedded brains GmbH.
19 *
20 *  The license and distribution terms for this file may be
21 *  found in the file LICENSE in this distribution or at
22 *  http://www.rtems.org/license/LICENSE.
23 */
24
25#if HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include <rtems.h>
30#include <rtems/rtems/timerimpl.h>
31#include <rtems/rtems/tasksimpl.h>
32#include <rtems/score/apimutex.h>
33#include <rtems/score/todimpl.h>
34
35static Timer_server_Control _Timer_server_Default;
36
37static void _Timer_server_Acquire(
38  Timer_server_Control *ts,
39  ISR_lock_Context     *lock_context
40)
41{
42  _ISR_lock_ISR_disable_and_acquire( &ts->Lock, lock_context );
43}
44
45static void _Timer_server_Release(
46  Timer_server_Control *ts,
47  ISR_lock_Context     *lock_context
48)
49{
50  _ISR_lock_Release_and_ISR_enable( &ts->Lock, lock_context );
51}
52
53void _Timer_server_Routine_adaptor( Watchdog_Control *the_watchdog )
54{
55  Timer_Control        *the_timer;
56  ISR_lock_Context      lock_context;
57  Per_CPU_Control      *cpu;
58  Timer_server_Control *ts;
59  bool                  wakeup;
60
61  ts = _Timer_server;
62  _Assert( ts != NULL );
63  the_timer = RTEMS_CONTAINER_OF( the_watchdog, Timer_Control, Ticker );
64
65  _Timer_server_Acquire( ts, &lock_context );
66
67  _Assert( _Watchdog_Get_state( &the_timer->Ticker ) == WATCHDOG_INACTIVE );
68  _Watchdog_Set_state( &the_timer->Ticker, WATCHDOG_PENDING );
69  cpu = _Watchdog_Get_CPU( &the_timer->Ticker );
70  the_timer->stop_time = _Timer_Get_CPU_ticks( cpu );
71  wakeup = _Chain_Is_empty( &ts->Pending );
72  _Chain_Append_unprotected( &ts->Pending, &the_timer->Ticker.Node.Chain );
73
74  _Timer_server_Release( ts, &lock_context );
75
76  if ( wakeup ) {
77    (void) rtems_event_system_send( ts->server_id, RTEMS_EVENT_SYSTEM_SERVER );
78  }
79}
80
81/**
82 *  @brief Timer server body.
83 *
84 *  This is the server for task based timers.  This task executes whenever a
85 *  task-based timer should fire.  It services both "after" and "when" timers.
86 *  It is not created automatically but must be created explicitly by the
87 *  application before task-based timers may be initiated.  The parameter
88 *  @a arg points to the corresponding timer server control block.
89 */
90static rtems_task _Timer_server_Body(
91  rtems_task_argument arg
92)
93{
94  Timer_server_Control *ts = (Timer_server_Control *) arg;
95
96  while ( true ) {
97    ISR_lock_Context  lock_context;
98    rtems_event_set   events;
99
100    _Timer_server_Acquire( ts, &lock_context );
101
102    while ( true ) {
103      Watchdog_Control                  *the_watchdog;
104      Timer_Control                     *the_timer;
105      rtems_timer_service_routine_entry  routine;
106      Objects_Id                         id;
107      void                              *user_data;
108
109      the_watchdog = (Watchdog_Control *) _Chain_Get_unprotected( &ts->Pending );
110      if ( the_watchdog == NULL ) {
111        break;
112      }
113
114      _Assert( _Watchdog_Get_state( the_watchdog ) == WATCHDOG_PENDING );
115      _Watchdog_Set_state( the_watchdog, WATCHDOG_INACTIVE );
116      the_timer = RTEMS_CONTAINER_OF( the_watchdog, Timer_Control, Ticker );
117      routine = the_timer->routine;
118      id = the_timer->Object.id;
119      user_data = the_timer->user_data;
120
121      _Timer_server_Release( ts, &lock_context );
122
123      ( *routine )( id, user_data );
124
125      _Timer_server_Acquire( ts, &lock_context );
126    }
127
128    _Timer_server_Release( ts, &lock_context );
129
130    (void) rtems_event_system_receive(
131      RTEMS_EVENT_SYSTEM_SERVER,
132      RTEMS_EVENT_ALL | RTEMS_WAIT,
133      RTEMS_NO_TIMEOUT,
134      &events
135    );
136  }
137}
138
139static rtems_status_code _Timer_server_Initiate(
140  rtems_task_priority priority,
141  size_t              stack_size,
142  rtems_attribute     attribute_set
143)
144{
145  rtems_status_code     status;
146  rtems_id              id;
147  Timer_server_Control *ts;
148
149  /*
150   *  Just to make sure this is only called once.
151   */
152  if ( _Timer_server != NULL ) {
153    return RTEMS_INCORRECT_STATE;
154  }
155
156  /*
157   *  Make sure the requested priority is valid.  The if is
158   *  structured so we check it is invalid before looking for
159   *  a specific invalid value as the default.
160   */
161  if ( !_RTEMS_tasks_Priority_is_valid( priority ) ) {
162    if ( priority != RTEMS_TIMER_SERVER_DEFAULT_PRIORITY )
163      return RTEMS_INVALID_PRIORITY;
164    priority = PRIORITY_PSEUDO_ISR;
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  status = rtems_task_create(
182    rtems_build_name('T','I','M','E'),
183    priority,
184    stack_size,
185    rtems_configuration_is_smp_enabled() ?
186      RTEMS_DEFAULT_MODES : /* no preempt is not supported for SMP */
187      RTEMS_NO_PREEMPT,   /* no preempt is like an interrupt */
188                          /* user may want floating point but we need */
189                          /*   system task specified for 0 priority */
190    attribute_set | RTEMS_SYSTEM_TASK,
191    &id
192  );
193  if (status != RTEMS_SUCCESSFUL) {
194    return status;
195  }
196
197  /*
198   *  Do all the data structure initialization before starting the
199   *  Timer Server so we do not have to have a critical section.
200   */
201
202  ts = &_Timer_server_Default;
203  _ISR_lock_Initialize( &ts->Lock, "Timer Server" );
204  _Chain_Initialize_empty( &ts->Pending );
205  ts->server_id = id;
206
207  /*
208   * The default timer server is now available.
209   */
210  _Timer_server = ts;
211
212  /*
213   *  Start the timer server
214   */
215  status = rtems_task_start(
216    id,
217    _Timer_server_Body,
218    (rtems_task_argument) ts
219  );
220  _Assert( status == RTEMS_SUCCESSFUL );
221
222  return status;
223}
224
225rtems_status_code rtems_timer_initiate_server(
226  rtems_task_priority priority,
227  size_t              stack_size,
228  rtems_attribute     attribute_set
229)
230{
231  rtems_status_code status;
232
233  _Once_Lock();
234  status = _Timer_server_Initiate( priority, stack_size, attribute_set );
235  _Once_Unlock();
236
237  return status;
238}
Note: See TracBrowser for help on using the repository browser.