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 definition of ::_Timer_server and the
0009  *   implementation of _Timer_Routine_adaptor(), _Timer_Fire(),
0010  *   _Timer_Fire_after(), _Timer_Fire_when(), _Timer_Cancel(), and the Timer
0011  *   Manager system initialization.
0012  */
0013 
0014 /*
0015  *  COPYRIGHT (c) 1989-2002.
0016  *  On-Line Applications Research Corporation (OAR).
0017  *
0018  * Redistribution and use in source and binary forms, with or without
0019  * modification, are permitted provided that the following conditions
0020  * are met:
0021  * 1. Redistributions of source code must retain the above copyright
0022  *    notice, this list of conditions and the following disclaimer.
0023  * 2. Redistributions in binary form must reproduce the above copyright
0024  *    notice, this list of conditions and the following disclaimer in the
0025  *    documentation and/or other materials provided with the distribution.
0026  *
0027  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0028  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0029  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0030  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0031  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0032  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0033  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0034  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0035  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0036  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0037  * POSSIBILITY OF SUCH DAMAGE.
0038  */
0039 
0040 #ifdef HAVE_CONFIG_H
0041 #include "config.h"
0042 #endif
0043 
0044 #include <rtems/rtems/timerimpl.h>
0045 #include <rtems/rtems/clockimpl.h>
0046 #include <rtems/rtems/status.h>
0047 #include <rtems/rtems/support.h>
0048 #include <rtems/score/assert.h>
0049 #include <rtems/score/chainimpl.h>
0050 #include <rtems/score/thread.h>
0051 #include <rtems/score/todimpl.h>
0052 #include <rtems/score/watchdogimpl.h>
0053 #include <rtems/sysinit.h>
0054 
0055 RTEMS_STATIC_ASSERT(
0056   PER_CPU_WATCHDOG_REALTIME == TIMER_CLASS_BIT_TIME_OF_DAY,
0057   TIMER_CLASS_BIT_TIME_OF_DAY
0058 );
0059 
0060 Timer_server_Control *volatile _Timer_server;
0061 
0062 void _Timer_Routine_adaptor( Watchdog_Control *the_watchdog )
0063 {
0064   Timer_Control   *the_timer;
0065   Per_CPU_Control *cpu;
0066 
0067   the_timer = RTEMS_CONTAINER_OF( the_watchdog, Timer_Control, Ticker );
0068   cpu = _Watchdog_Get_CPU( &the_timer->Ticker );
0069   the_timer->stop_time = _Timer_Get_CPU_ticks( cpu );
0070 
0071   ( *the_timer->routine )( the_timer->Object.id, the_timer->user_data );
0072 }
0073 
0074 rtems_status_code _Timer_Fire(
0075   rtems_id                           id,
0076   rtems_interval                     interval,
0077   rtems_timer_service_routine_entry  routine,
0078   void                              *user_data,
0079   Timer_Classes                      the_class,
0080   Watchdog_Service_routine_entry     adaptor
0081 )
0082 {
0083   Timer_Control    *the_timer;
0084   ISR_lock_Context  lock_context;
0085 
0086   the_timer = _Timer_Get( id, &lock_context );
0087   if ( the_timer != NULL ) {
0088     Per_CPU_Control *cpu;
0089 
0090     cpu = _Timer_Acquire_critical( the_timer, &lock_context );
0091     _Timer_Cancel( cpu, the_timer );
0092     _Watchdog_Initialize( &the_timer->Ticker, adaptor );
0093     the_timer->the_class = the_class;
0094     the_timer->routine = routine;
0095     the_timer->user_data = user_data;
0096     the_timer->initial = interval;
0097     the_timer->start_time = _Timer_Get_CPU_ticks( cpu );
0098 
0099     if ( _Timer_Is_interval_class( the_class ) ) {
0100       _Watchdog_Insert(
0101         &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_TICKS ],
0102         &the_timer->Ticker,
0103         cpu->Watchdog.ticks + interval
0104       );
0105     } else {
0106       _Watchdog_Insert(
0107         &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_REALTIME ],
0108         &the_timer->Ticker,
0109         _Watchdog_Ticks_from_seconds( interval )
0110       );
0111     }
0112 
0113     _Timer_Release( cpu, &lock_context );
0114     return RTEMS_SUCCESSFUL;
0115   }
0116 
0117   return RTEMS_INVALID_ID;
0118 }
0119 
0120 rtems_status_code _Timer_Fire_after(
0121   rtems_id                           id,
0122   rtems_interval                     ticks,
0123   rtems_timer_service_routine_entry  routine,
0124   void                              *user_data,
0125   Timer_Classes                      the_class,
0126   Watchdog_Service_routine_entry     adaptor
0127 )
0128 {
0129   if ( ticks == 0 )
0130     return RTEMS_INVALID_NUMBER;
0131 
0132   if ( !routine )
0133     return RTEMS_INVALID_ADDRESS;
0134 
0135   return _Timer_Fire(
0136     id,
0137     ticks,
0138     routine,
0139     user_data,
0140     the_class,
0141     adaptor
0142   );
0143 }
0144 
0145 rtems_status_code _Timer_Fire_when(
0146   rtems_id                           id,
0147   const rtems_time_of_day           *wall_time,
0148   rtems_timer_service_routine_entry  routine,
0149   void                              *user_data,
0150   Timer_Classes                      the_class,
0151   Watchdog_Service_routine_entry     adaptor
0152 )
0153 {
0154   rtems_status_code status;
0155   rtems_interval    seconds;
0156 
0157   if ( !_TOD_Is_set() )
0158     return RTEMS_NOT_DEFINED;
0159 
0160   if ( !routine )
0161     return RTEMS_INVALID_ADDRESS;
0162 
0163   status = _TOD_Validate( wall_time, TOD_ENABLE_TICKS_VALIDATION );
0164 
0165   if ( status != RTEMS_SUCCESSFUL ) {
0166     return status;
0167   }
0168 
0169   seconds = _TOD_To_seconds( wall_time );
0170   if ( seconds <= _TOD_Seconds_since_epoch() )
0171     return RTEMS_INVALID_CLOCK;
0172 
0173   return _Timer_Fire(
0174     id,
0175     seconds,
0176     routine,
0177     user_data,
0178     the_class,
0179     adaptor
0180   );
0181 }
0182 
0183 void _Timer_Cancel( Per_CPU_Control *cpu, Timer_Control *the_timer )
0184 {
0185   Timer_Classes the_class;
0186 
0187   the_class = the_timer->the_class;
0188 
0189   if ( _Watchdog_Is_scheduled( &the_timer->Ticker ) ) {
0190     the_timer->stop_time = _Timer_Get_CPU_ticks( cpu );
0191     _Watchdog_Remove(
0192       &cpu->Watchdog.Header[ _Timer_Watchdog_header_index( the_class ) ],
0193       &the_timer->Ticker
0194     );
0195   } else if ( _Timer_Is_on_task_class( the_class ) ) {
0196     Timer_server_Control *timer_server;
0197     ISR_lock_Context      lock_context;
0198 
0199     timer_server = _Timer_server;
0200     _Assert( timer_server != NULL );
0201     _Timer_server_Acquire_critical( timer_server, &lock_context );
0202 
0203     if ( _Watchdog_Get_state( &the_timer->Ticker ) == WATCHDOG_PENDING ) {
0204       _Watchdog_Set_state( &the_timer->Ticker, WATCHDOG_INACTIVE );
0205       _Chain_Extract_unprotected( &the_timer->Ticker.Node.Chain );
0206     }
0207 
0208     _Timer_server_Release_critical( timer_server, &lock_context );
0209   }
0210 }
0211 
0212 rtems_status_code rtems_timer_create(
0213   rtems_name  name,
0214   rtems_id   *id
0215 )
0216 {
0217   Timer_Control *the_timer;
0218 
0219   if ( !rtems_is_name_valid( name ) )
0220     return RTEMS_INVALID_NAME;
0221 
0222   if ( !id )
0223     return RTEMS_INVALID_ADDRESS;
0224 
0225   the_timer = _Timer_Allocate();
0226 
0227   if ( !the_timer ) {
0228     _Objects_Allocator_unlock();
0229     return RTEMS_TOO_MANY;
0230   }
0231 
0232   the_timer->the_class = TIMER_DORMANT;
0233   _Watchdog_Preinitialize( &the_timer->Ticker, _Per_CPU_Get_snapshot() );
0234 
0235   *id = _Objects_Open_u32(
0236     &_Timer_Information,
0237     &the_timer->Object,
0238     name
0239   );
0240   _Objects_Allocator_unlock();
0241   return RTEMS_SUCCESSFUL;
0242 }
0243 
0244 static void _Timer_Manager_initialization( void )
0245 {
0246   _Objects_Initialize_information( &_Timer_Information );
0247 }
0248 
0249 RTEMS_SYSINIT_ITEM(
0250   _Timer_Manager_initialization,
0251   RTEMS_SYSINIT_CLASSIC_TIMER,
0252   RTEMS_SYSINIT_ORDER_MIDDLE
0253 );