source: rtems/cpukit/rtems/src/timerserver.c @ 6b5f22dc

Last change on this file since 6b5f22dc was 6b5f22dc, checked in by Sebastian Huber <sebastian.huber@…>, on 11/26/20 at 10:45:47

rtems: Canonicalize Doxygen @file comments

Use common phrases for the file brief descriptions.

Update #3706.

  • Property mode set to 100644
File size: 6.5 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup RTEMSImplClassicTimer
5 *
6 * @brief This source file contains the implementation of
7 *   rtems_timer_initiate_server().
8 */
9
10/*  COPYRIGHT (c) 1989-2008.
11 *  On-Line Applications Research Corporation (OAR).
12 *
13 *  Copyright (c) 2009, 2017 embedded brains GmbH.
14 *
15 *  The license and distribution terms for this file may be
16 *  found in the file LICENSE in this distribution or at
17 *  http://www.rtems.org/license/LICENSE.
18 */
19
20#ifdef HAVE_CONFIG_H
21#include "config.h"
22#endif
23
24#include <rtems.h>
25#include <rtems/rtems/timerimpl.h>
26#include <rtems/rtems/tasksimpl.h>
27#include <rtems/score/onceimpl.h>
28#include <rtems/score/todimpl.h>
29
30static Timer_server_Control _Timer_server_Default;
31
32static void _Timer_server_Acquire(
33  Timer_server_Control *ts,
34  ISR_lock_Context     *lock_context
35)
36{
37  _ISR_lock_ISR_disable_and_acquire( &ts->Lock, lock_context );
38}
39
40static void _Timer_server_Release(
41  Timer_server_Control *ts,
42  ISR_lock_Context     *lock_context
43)
44{
45  _ISR_lock_Release_and_ISR_enable( &ts->Lock, lock_context );
46}
47
48void _Timer_server_Routine_adaptor( Watchdog_Control *the_watchdog )
49{
50  Timer_Control        *the_timer;
51  ISR_lock_Context      lock_context;
52  Per_CPU_Control      *cpu;
53  Timer_server_Control *ts;
54  bool                  wakeup;
55
56  ts = _Timer_server;
57  _Assert( ts != NULL );
58  the_timer = RTEMS_CONTAINER_OF( the_watchdog, Timer_Control, Ticker );
59
60  _Timer_server_Acquire( ts, &lock_context );
61
62  _Assert( _Watchdog_Get_state( &the_timer->Ticker ) == WATCHDOG_INACTIVE );
63  _Watchdog_Set_state( &the_timer->Ticker, WATCHDOG_PENDING );
64  cpu = _Watchdog_Get_CPU( &the_timer->Ticker );
65  the_timer->stop_time = _Timer_Get_CPU_ticks( cpu );
66  wakeup = _Chain_Is_empty( &ts->Pending );
67  _Chain_Append_unprotected( &ts->Pending, &the_timer->Ticker.Node.Chain );
68
69  _Timer_server_Release( ts, &lock_context );
70
71  if ( wakeup ) {
72    (void) rtems_event_system_send( ts->server_id, RTEMS_EVENT_SYSTEM_SERVER );
73  }
74}
75
76/**
77 *  @brief Timer server body.
78 *
79 *  This is the server for task based timers.  This task executes whenever a
80 *  task-based timer should fire.  It services both "after" and "when" timers.
81 *  It is not created automatically but must be created explicitly by the
82 *  application before task-based timers may be initiated.  The parameter
83 *  @a arg points to the corresponding timer server control block.
84 */
85static rtems_task _Timer_server_Body(
86  rtems_task_argument arg
87)
88{
89  Timer_server_Control *ts = (Timer_server_Control *) arg;
90#if defined(RTEMS_SCORE_THREAD_ENABLE_RESOURCE_COUNT)
91  Thread_Control *executing = _Thread_Get_executing();
92#endif
93
94  while ( true ) {
95    ISR_lock_Context  lock_context;
96    rtems_event_set   events;
97
98    _Timer_server_Acquire( ts, &lock_context );
99
100    while ( true ) {
101      Watchdog_Control                  *the_watchdog;
102      Timer_Control                     *the_timer;
103      rtems_timer_service_routine_entry  routine;
104      Objects_Id                         id;
105      void                              *user_data;
106
107      the_watchdog = (Watchdog_Control *) _Chain_Get_unprotected( &ts->Pending );
108      if ( the_watchdog == NULL ) {
109        break;
110      }
111
112      _Assert( _Watchdog_Get_state( the_watchdog ) == WATCHDOG_PENDING );
113      _Watchdog_Set_state( the_watchdog, WATCHDOG_INACTIVE );
114      the_timer = RTEMS_CONTAINER_OF( the_watchdog, Timer_Control, Ticker );
115      routine = the_timer->routine;
116      id = the_timer->Object.id;
117      user_data = the_timer->user_data;
118
119      _Timer_server_Release( ts, &lock_context );
120
121      ( *routine )( id, user_data );
122#if defined(RTEMS_SCORE_THREAD_ENABLE_RESOURCE_COUNT)
123      _Assert( !_Thread_Owns_resources( executing ) );
124#endif
125
126      _Timer_server_Acquire( ts, &lock_context );
127    }
128
129    _Timer_server_Release( ts, &lock_context );
130
131    (void) rtems_event_system_receive(
132      RTEMS_EVENT_SYSTEM_SERVER,
133      RTEMS_EVENT_ALL | RTEMS_WAIT,
134      RTEMS_NO_TIMEOUT,
135      &events
136    );
137  }
138}
139
140static rtems_status_code _Timer_server_Initiate(
141  rtems_task_priority priority,
142  size_t              stack_size,
143  rtems_attribute     attribute_set
144)
145{
146  rtems_status_code     status;
147  rtems_id              id;
148  Timer_server_Control *ts;
149
150  /*
151   *  Just to make sure this is only called once.
152   */
153  if ( _Timer_server != NULL ) {
154    return RTEMS_INCORRECT_STATE;
155  }
156
157  if ( priority == RTEMS_TIMER_SERVER_DEFAULT_PRIORITY ) {
158    priority = PRIORITY_PSEUDO_ISR;
159  }
160
161  /*
162   *  Create the Timer Server with the name the name of "TIME".  The attribute
163   *  RTEMS_SYSTEM_TASK allows us to set a priority to 0 which will makes it
164   *  higher than any other task in the system.  It can be viewed as a low
165   *  priority interrupt.  It is also always NO_PREEMPT so it looks like
166   *  an interrupt to other tasks.
167   *
168   *  We allow the user to override the default priority because the Timer
169   *  Server can invoke TSRs which must adhere to language run-time or
170   *  other library rules.  For example, if using a TSR written in Ada the
171   *  Server should run at the same priority as the priority Ada task.
172   *  Otherwise, the priority ceiling for the mutex used to protect the
173   *  GNAT run-time is violated.
174   */
175  status = rtems_task_create(
176    rtems_build_name('T','I','M','E'),
177    priority,
178    stack_size,
179#ifdef RTEMS_SMP
180    RTEMS_DEFAULT_MODES, /* no preempt is not recommended for SMP */
181#else
182    RTEMS_NO_PREEMPT,    /* no preempt is like an interrupt */
183#endif
184    /* user may want floating point but we need */
185    /*   system task specified for 0 priority */
186    attribute_set | RTEMS_SYSTEM_TASK,
187    &id
188  );
189  if (status != RTEMS_SUCCESSFUL) {
190    return status;
191  }
192
193  /*
194   *  Do all the data structure initialization before starting the
195   *  Timer Server so we do not have to have a critical section.
196   */
197
198  ts = &_Timer_server_Default;
199  _ISR_lock_Initialize( &ts->Lock, "Timer Server" );
200  _Chain_Initialize_empty( &ts->Pending );
201  ts->server_id = id;
202
203  /*
204   * The default timer server is now available.
205   */
206  _Timer_server = ts;
207
208  /*
209   *  Start the timer server
210   */
211  status = rtems_task_start(
212    id,
213    _Timer_server_Body,
214    (rtems_task_argument) ts
215  );
216  _Assert( status == RTEMS_SUCCESSFUL );
217
218  return status;
219}
220
221rtems_status_code rtems_timer_initiate_server(
222  rtems_task_priority priority,
223  size_t              stack_size,
224  rtems_attribute     attribute_set
225)
226{
227  rtems_status_code status;
228  Thread_Life_state thread_life_state;
229
230  thread_life_state = _Once_Lock();
231  status = _Timer_server_Initiate( priority, stack_size, attribute_set );
232  _Once_Unlock( thread_life_state );
233
234  return status;
235}
Note: See TracBrowser for help on using the repository browser.