source: rtems/cpukit/rtems/src/timerserver.c @ 66cb142

5
Last change on this file since 66cb142 was 6c2b8a4b, checked in by Sebastian Huber <sebastian.huber@…>, on 11/29/17 at 05:23:27

score: Use self-contained API mutex

Use a self-contained recursive mutex for API_Mutex_Control. The API
mutexes are protected against asynchronous thread cancellation.

Add dedicated mutexes for libatomic and TOD.

Close #2629.
Close #2630.

  • Property mode set to 100644
File size: 6.8 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, 2017 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/onceimpl.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#if defined(RTEMS_SCORE_THREAD_ENABLE_RESOURCE_COUNT)
96  Thread_Control *executing = _Thread_Get_executing();
97#endif
98
99  while ( true ) {
100    ISR_lock_Context  lock_context;
101    rtems_event_set   events;
102
103    _Timer_server_Acquire( ts, &lock_context );
104
105    while ( true ) {
106      Watchdog_Control                  *the_watchdog;
107      Timer_Control                     *the_timer;
108      rtems_timer_service_routine_entry  routine;
109      Objects_Id                         id;
110      void                              *user_data;
111
112      the_watchdog = (Watchdog_Control *) _Chain_Get_unprotected( &ts->Pending );
113      if ( the_watchdog == NULL ) {
114        break;
115      }
116
117      _Assert( _Watchdog_Get_state( the_watchdog ) == WATCHDOG_PENDING );
118      _Watchdog_Set_state( the_watchdog, WATCHDOG_INACTIVE );
119      the_timer = RTEMS_CONTAINER_OF( the_watchdog, Timer_Control, Ticker );
120      routine = the_timer->routine;
121      id = the_timer->Object.id;
122      user_data = the_timer->user_data;
123
124      _Timer_server_Release( ts, &lock_context );
125
126      ( *routine )( id, user_data );
127#if defined(RTEMS_SCORE_THREAD_ENABLE_RESOURCE_COUNT)
128      _Assert( !_Thread_Owns_resources( executing ) );
129#endif
130
131      _Timer_server_Acquire( ts, &lock_context );
132    }
133
134    _Timer_server_Release( ts, &lock_context );
135
136    (void) rtems_event_system_receive(
137      RTEMS_EVENT_SYSTEM_SERVER,
138      RTEMS_EVENT_ALL | RTEMS_WAIT,
139      RTEMS_NO_TIMEOUT,
140      &events
141    );
142  }
143}
144
145static rtems_status_code _Timer_server_Initiate(
146  rtems_task_priority priority,
147  size_t              stack_size,
148  rtems_attribute     attribute_set
149)
150{
151  rtems_status_code     status;
152  rtems_id              id;
153  Timer_server_Control *ts;
154
155  /*
156   *  Just to make sure this is only called once.
157   */
158  if ( _Timer_server != NULL ) {
159    return RTEMS_INCORRECT_STATE;
160  }
161
162  if ( priority == RTEMS_TIMER_SERVER_DEFAULT_PRIORITY ) {
163    priority = PRIORITY_PSEUDO_ISR;
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  status = rtems_task_create(
181    rtems_build_name('T','I','M','E'),
182    priority,
183    stack_size,
184    rtems_configuration_is_smp_enabled() ?
185      RTEMS_DEFAULT_MODES : /* no preempt is not supported for SMP */
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
191  );
192  if (status != RTEMS_SUCCESSFUL) {
193    return status;
194  }
195
196  /*
197   *  Do all the data structure initialization before starting the
198   *  Timer Server so we do not have to have a critical section.
199   */
200
201  ts = &_Timer_server_Default;
202  _ISR_lock_Initialize( &ts->Lock, "Timer Server" );
203  _Chain_Initialize_empty( &ts->Pending );
204  ts->server_id = id;
205
206  /*
207   * The default timer server is now available.
208   */
209  _Timer_server = ts;
210
211  /*
212   *  Start the timer server
213   */
214  status = rtems_task_start(
215    id,
216    _Timer_server_Body,
217    (rtems_task_argument) ts
218  );
219  _Assert( status == RTEMS_SUCCESSFUL );
220
221  return status;
222}
223
224rtems_status_code rtems_timer_initiate_server(
225  rtems_task_priority priority,
226  size_t              stack_size,
227  rtems_attribute     attribute_set
228)
229{
230  rtems_status_code status;
231
232  _Once_Lock();
233  status = _Timer_server_Initiate( priority, stack_size, attribute_set );
234  _Once_Unlock();
235
236  return status;
237}
Note: See TracBrowser for help on using the repository browser.