Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:22

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSImplClassicTimer
0007  *
0008  * @brief This source file contains the implementation of
0009  *   rtems_timer_initiate_server().
0010  */
0011 
0012 /*  COPYRIGHT (c) 1989-2008.
0013  *  On-Line Applications Research Corporation (OAR).
0014  *
0015  *  Copyright (C) 2009, 2017 embedded brains GmbH & Co. KG
0016  *
0017  * Redistribution and use in source and binary forms, with or without
0018  * modification, are permitted provided that the following conditions
0019  * are met:
0020  * 1. Redistributions of source code must retain the above copyright
0021  *    notice, this list of conditions and the following disclaimer.
0022  * 2. Redistributions in binary form must reproduce the above copyright
0023  *    notice, this list of conditions and the following disclaimer in the
0024  *    documentation and/or other materials provided with the distribution.
0025  *
0026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0027  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0028  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0029  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0030  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0031  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0032  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0033  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0034  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0035  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0036  * POSSIBILITY OF SUCH DAMAGE.
0037  */
0038 
0039 #ifdef HAVE_CONFIG_H
0040 #include "config.h"
0041 #endif
0042 
0043 #include <rtems.h>
0044 #include <rtems/rtems/timerimpl.h>
0045 #include <rtems/rtems/tasksimpl.h>
0046 #include <rtems/score/todimpl.h>
0047 
0048 static Timer_server_Control _Timer_server_Default;
0049 
0050 static void _Timer_server_Acquire(
0051   Timer_server_Control *ts,
0052   ISR_lock_Context     *lock_context
0053 )
0054 {
0055   _ISR_lock_ISR_disable_and_acquire( &ts->Lock, lock_context );
0056 }
0057 
0058 static void _Timer_server_Release(
0059   Timer_server_Control *ts,
0060   ISR_lock_Context     *lock_context
0061 )
0062 {
0063   _ISR_lock_Release_and_ISR_enable( &ts->Lock, lock_context );
0064 }
0065 
0066 void _Timer_server_Routine_adaptor( Watchdog_Control *the_watchdog )
0067 {
0068   Timer_Control        *the_timer;
0069   ISR_lock_Context      lock_context;
0070   Per_CPU_Control      *cpu;
0071   Timer_server_Control *ts;
0072   bool                  wakeup;
0073 
0074   ts = _Timer_server;
0075   _Assert( ts != NULL );
0076   the_timer = RTEMS_CONTAINER_OF( the_watchdog, Timer_Control, Ticker );
0077 
0078   _Timer_server_Acquire( ts, &lock_context );
0079 
0080   _Assert( _Watchdog_Get_state( &the_timer->Ticker ) == WATCHDOG_INACTIVE );
0081   _Watchdog_Set_state( &the_timer->Ticker, WATCHDOG_PENDING );
0082   cpu = _Watchdog_Get_CPU( &the_timer->Ticker );
0083   the_timer->stop_time = _Timer_Get_CPU_ticks( cpu );
0084   wakeup = _Chain_Is_empty( &ts->Pending );
0085   _Chain_Append_unprotected( &ts->Pending, &the_timer->Ticker.Node.Chain );
0086 
0087   _Timer_server_Release( ts, &lock_context );
0088 
0089   if ( wakeup ) {
0090     (void) rtems_event_system_send( ts->server_id, RTEMS_EVENT_SYSTEM_SERVER );
0091   }
0092 }
0093 
0094 /**
0095  *  @brief Timer server body.
0096  *
0097  *  This is the server for task based timers.  This task executes whenever a
0098  *  task-based timer should fire.  It services both "after" and "when" timers.
0099  *  It is not created automatically but must be created explicitly by the
0100  *  application before task-based timers may be initiated.  The parameter
0101  *  @a arg points to the corresponding timer server control block.
0102  */
0103 static rtems_task _Timer_server_Body(
0104   rtems_task_argument arg
0105 )
0106 {
0107   Timer_server_Control *ts = (Timer_server_Control *) arg;
0108 #if defined(RTEMS_SCORE_THREAD_ENABLE_RESOURCE_COUNT)
0109   Thread_Control *executing = _Thread_Get_executing();
0110 #endif
0111 
0112   while ( true ) {
0113     ISR_lock_Context  lock_context;
0114     rtems_event_set   events;
0115 
0116     _Timer_server_Acquire( ts, &lock_context );
0117 
0118     while ( true ) {
0119       Watchdog_Control                  *the_watchdog;
0120       Timer_Control                     *the_timer;
0121       rtems_timer_service_routine_entry  routine;
0122       Objects_Id                         id;
0123       void                              *user_data;
0124 
0125       the_watchdog = (Watchdog_Control *) _Chain_Get_unprotected( &ts->Pending );
0126       if ( the_watchdog == NULL ) {
0127         break;
0128       }
0129 
0130       _Assert( _Watchdog_Get_state( the_watchdog ) == WATCHDOG_PENDING );
0131       _Watchdog_Set_state( the_watchdog, WATCHDOG_INACTIVE );
0132       the_timer = RTEMS_CONTAINER_OF( the_watchdog, Timer_Control, Ticker );
0133       routine = the_timer->routine;
0134       id = the_timer->Object.id;
0135       user_data = the_timer->user_data;
0136 
0137       _Timer_server_Release( ts, &lock_context );
0138 
0139       ( *routine )( id, user_data );
0140 #if defined(RTEMS_SCORE_THREAD_ENABLE_RESOURCE_COUNT)
0141       _Assert( !_Thread_Owns_resources( executing ) );
0142 #endif
0143 
0144       _Timer_server_Acquire( ts, &lock_context );
0145     }
0146 
0147     _Timer_server_Release( ts, &lock_context );
0148 
0149     (void) rtems_event_system_receive(
0150       RTEMS_EVENT_SYSTEM_SERVER,
0151       RTEMS_EVENT_ALL | RTEMS_WAIT,
0152       RTEMS_NO_TIMEOUT,
0153       &events
0154     );
0155   }
0156 }
0157 
0158 static rtems_status_code _Timer_server_Initiate(
0159   rtems_task_priority priority,
0160   size_t              stack_size,
0161   rtems_attribute     attribute_set
0162 )
0163 {
0164   rtems_status_code     status;
0165   rtems_id              id;
0166   Timer_server_Control *ts;
0167 
0168   /*
0169    *  Just to make sure this is only called once.
0170    */
0171   if ( _Timer_server != NULL ) {
0172     return RTEMS_INCORRECT_STATE;
0173   }
0174 
0175   if ( priority == RTEMS_TIMER_SERVER_DEFAULT_PRIORITY ) {
0176     priority = PRIORITY_MINIMUM;
0177   }
0178 
0179   /*
0180    *  Create the Timer Server with the name the name of "TIME".  The attribute
0181    *  RTEMS_SYSTEM_TASK allows us to set a priority to 0 which will makes it
0182    *  higher than any other task in the system.  It can be viewed as a low
0183    *  priority interrupt.  It is also always NO_PREEMPT so it looks like
0184    *  an interrupt to other tasks.
0185    *
0186    *  We allow the user to override the default priority because the Timer
0187    *  Server can invoke TSRs which must adhere to language run-time or
0188    *  other library rules.  For example, if using a TSR written in Ada the
0189    *  Server should run at the same priority as the priority Ada task.
0190    *  Otherwise, the priority ceiling for the mutex used to protect the
0191    *  GNAT run-time is violated.
0192    */
0193   status = rtems_task_create(
0194     rtems_build_name('T','I','M','E'),
0195     priority,
0196     stack_size,
0197 #ifdef RTEMS_SMP
0198     RTEMS_DEFAULT_MODES, /* no preempt is not recommended for SMP */
0199 #else
0200     RTEMS_NO_PREEMPT,    /* no preempt is like an interrupt */
0201 #endif
0202     /* user may want floating point but we need */
0203     /*   system task specified for 0 priority */
0204     attribute_set | RTEMS_SYSTEM_TASK,
0205     &id
0206   );
0207   if (status != RTEMS_SUCCESSFUL) {
0208     return status;
0209   }
0210 
0211   /*
0212    *  Do all the data structure initialization before starting the
0213    *  Timer Server so we do not have to have a critical section.
0214    */
0215 
0216   ts = &_Timer_server_Default;
0217   _ISR_lock_Initialize( &ts->Lock, "Timer Server" );
0218   _Chain_Initialize_empty( &ts->Pending );
0219   ts->server_id = id;
0220 
0221   /*
0222    * The default timer server is now available.
0223    */
0224   _Timer_server = ts;
0225 
0226   /*
0227    *  Start the timer server
0228    */
0229   status = rtems_task_start(
0230     id,
0231     _Timer_server_Body,
0232     (rtems_task_argument) ts
0233   );
0234   _Assert( status == RTEMS_SUCCESSFUL );
0235 
0236   return status;
0237 }
0238 
0239 rtems_status_code rtems_timer_initiate_server(
0240   rtems_task_priority priority,
0241   size_t              stack_size,
0242   rtems_attribute     attribute_set
0243 )
0244 {
0245   rtems_status_code status;
0246 
0247   _Objects_Allocator_lock();
0248   status = _Timer_server_Initiate( priority, stack_size, attribute_set );
0249   _Objects_Allocator_unlock();
0250 
0251   return status;
0252 }