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

Last change on this file since b3b6d21e was b3b6d21e, checked in by Joel Sherrill <joel@…>, on 02/16/22 at 22:28:59

cpukit/rtems/src/[s-z]*.c: Change license to BSD-2

Updates #3053.

  • Property mode set to 100644
File size: 7.6 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @ingroup RTEMSImplClassicTimer
7 *
8 * @brief This source file contains the implementation of
9 *   rtems_timer_initiate_server().
10 */
11
12/*  COPYRIGHT (c) 1989-2008.
13 *  On-Line Applications Research Corporation (OAR).
14 *
15 *  Copyright (c) 2009, 2017 embedded brains GmbH.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 * 1. Redistributions of source code must retain the above copyright
21 *    notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 *    notice, this list of conditions and the following disclaimer in the
24 *    documentation and/or other materials provided with the distribution.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39#ifdef HAVE_CONFIG_H
40#include "config.h"
41#endif
42
43#include <rtems.h>
44#include <rtems/rtems/timerimpl.h>
45#include <rtems/rtems/tasksimpl.h>
46#include <rtems/score/todimpl.h>
47
48static Timer_server_Control _Timer_server_Default;
49
50static void _Timer_server_Acquire(
51  Timer_server_Control *ts,
52  ISR_lock_Context     *lock_context
53)
54{
55  _ISR_lock_ISR_disable_and_acquire( &ts->Lock, lock_context );
56}
57
58static void _Timer_server_Release(
59  Timer_server_Control *ts,
60  ISR_lock_Context     *lock_context
61)
62{
63  _ISR_lock_Release_and_ISR_enable( &ts->Lock, lock_context );
64}
65
66void _Timer_server_Routine_adaptor( Watchdog_Control *the_watchdog )
67{
68  Timer_Control        *the_timer;
69  ISR_lock_Context      lock_context;
70  Per_CPU_Control      *cpu;
71  Timer_server_Control *ts;
72  bool                  wakeup;
73
74  ts = _Timer_server;
75  _Assert( ts != NULL );
76  the_timer = RTEMS_CONTAINER_OF( the_watchdog, Timer_Control, Ticker );
77
78  _Timer_server_Acquire( ts, &lock_context );
79
80  _Assert( _Watchdog_Get_state( &the_timer->Ticker ) == WATCHDOG_INACTIVE );
81  _Watchdog_Set_state( &the_timer->Ticker, WATCHDOG_PENDING );
82  cpu = _Watchdog_Get_CPU( &the_timer->Ticker );
83  the_timer->stop_time = _Timer_Get_CPU_ticks( cpu );
84  wakeup = _Chain_Is_empty( &ts->Pending );
85  _Chain_Append_unprotected( &ts->Pending, &the_timer->Ticker.Node.Chain );
86
87  _Timer_server_Release( ts, &lock_context );
88
89  if ( wakeup ) {
90    (void) rtems_event_system_send( ts->server_id, RTEMS_EVENT_SYSTEM_SERVER );
91  }
92}
93
94/**
95 *  @brief Timer server body.
96 *
97 *  This is the server for task based timers.  This task executes whenever a
98 *  task-based timer should fire.  It services both "after" and "when" timers.
99 *  It is not created automatically but must be created explicitly by the
100 *  application before task-based timers may be initiated.  The parameter
101 *  @a arg points to the corresponding timer server control block.
102 */
103static rtems_task _Timer_server_Body(
104  rtems_task_argument arg
105)
106{
107  Timer_server_Control *ts = (Timer_server_Control *) arg;
108#if defined(RTEMS_SCORE_THREAD_ENABLE_RESOURCE_COUNT)
109  Thread_Control *executing = _Thread_Get_executing();
110#endif
111
112  while ( true ) {
113    ISR_lock_Context  lock_context;
114    rtems_event_set   events;
115
116    _Timer_server_Acquire( ts, &lock_context );
117
118    while ( true ) {
119      Watchdog_Control                  *the_watchdog;
120      Timer_Control                     *the_timer;
121      rtems_timer_service_routine_entry  routine;
122      Objects_Id                         id;
123      void                              *user_data;
124
125      the_watchdog = (Watchdog_Control *) _Chain_Get_unprotected( &ts->Pending );
126      if ( the_watchdog == NULL ) {
127        break;
128      }
129
130      _Assert( _Watchdog_Get_state( the_watchdog ) == WATCHDOG_PENDING );
131      _Watchdog_Set_state( the_watchdog, WATCHDOG_INACTIVE );
132      the_timer = RTEMS_CONTAINER_OF( the_watchdog, Timer_Control, Ticker );
133      routine = the_timer->routine;
134      id = the_timer->Object.id;
135      user_data = the_timer->user_data;
136
137      _Timer_server_Release( ts, &lock_context );
138
139      ( *routine )( id, user_data );
140#if defined(RTEMS_SCORE_THREAD_ENABLE_RESOURCE_COUNT)
141      _Assert( !_Thread_Owns_resources( executing ) );
142#endif
143
144      _Timer_server_Acquire( ts, &lock_context );
145    }
146
147    _Timer_server_Release( ts, &lock_context );
148
149    (void) rtems_event_system_receive(
150      RTEMS_EVENT_SYSTEM_SERVER,
151      RTEMS_EVENT_ALL | RTEMS_WAIT,
152      RTEMS_NO_TIMEOUT,
153      &events
154    );
155  }
156}
157
158static rtems_status_code _Timer_server_Initiate(
159  rtems_task_priority priority,
160  size_t              stack_size,
161  rtems_attribute     attribute_set
162)
163{
164  rtems_status_code     status;
165  rtems_id              id;
166  Timer_server_Control *ts;
167
168  /*
169   *  Just to make sure this is only called once.
170   */
171  if ( _Timer_server != NULL ) {
172    return RTEMS_INCORRECT_STATE;
173  }
174
175  if ( priority == RTEMS_TIMER_SERVER_DEFAULT_PRIORITY ) {
176    priority = PRIORITY_PSEUDO_ISR;
177  }
178
179  /*
180   *  Create the Timer Server with the name the name of "TIME".  The attribute
181   *  RTEMS_SYSTEM_TASK allows us to set a priority to 0 which will makes it
182   *  higher than any other task in the system.  It can be viewed as a low
183   *  priority interrupt.  It is also always NO_PREEMPT so it looks like
184   *  an interrupt to other tasks.
185   *
186   *  We allow the user to override the default priority because the Timer
187   *  Server can invoke TSRs which must adhere to language run-time or
188   *  other library rules.  For example, if using a TSR written in Ada the
189   *  Server should run at the same priority as the priority Ada task.
190   *  Otherwise, the priority ceiling for the mutex used to protect the
191   *  GNAT run-time is violated.
192   */
193  status = rtems_task_create(
194    rtems_build_name('T','I','M','E'),
195    priority,
196    stack_size,
197#ifdef RTEMS_SMP
198    RTEMS_DEFAULT_MODES, /* no preempt is not recommended for SMP */
199#else
200    RTEMS_NO_PREEMPT,    /* no preempt is like an interrupt */
201#endif
202    /* user may want floating point but we need */
203    /*   system task specified for 0 priority */
204    attribute_set | RTEMS_SYSTEM_TASK,
205    &id
206  );
207  if (status != RTEMS_SUCCESSFUL) {
208    return status;
209  }
210
211  /*
212   *  Do all the data structure initialization before starting the
213   *  Timer Server so we do not have to have a critical section.
214   */
215
216  ts = &_Timer_server_Default;
217  _ISR_lock_Initialize( &ts->Lock, "Timer Server" );
218  _Chain_Initialize_empty( &ts->Pending );
219  ts->server_id = id;
220
221  /*
222   * The default timer server is now available.
223   */
224  _Timer_server = ts;
225
226  /*
227   *  Start the timer server
228   */
229  status = rtems_task_start(
230    id,
231    _Timer_server_Body,
232    (rtems_task_argument) ts
233  );
234  _Assert( status == RTEMS_SUCCESSFUL );
235
236  return status;
237}
238
239rtems_status_code rtems_timer_initiate_server(
240  rtems_task_priority priority,
241  size_t              stack_size,
242  rtems_attribute     attribute_set
243)
244{
245  rtems_status_code status;
246
247  _Objects_Allocator_lock();
248  status = _Timer_server_Initiate( priority, stack_size, attribute_set );
249  _Objects_Allocator_unlock();
250
251  return status;
252}
Note: See TracBrowser for help on using the repository browser.