summaryrefslogblamecommitdiffstats
path: root/cpukit/rtems/src/timercreate.c
blob: a3ece5cc4d563ba4827b29ec7a8bb067de914bbf (plain) (tree)
1
2
3
4
5
6
7
8
9
   
        
  





                                                                             


   
                            
                                                    


                                                           
                                         

   
                    


                   
                                  
                                  

                                
                               
                                  
                               
                                
                                     
                          
 
                    
                                                           


                             

                                             
                                                             
 

                             
 


                                                                        
 











                                                                        

















                                                              
                                                        




                                      
                                                           
                           
                                                




                                         
   
 
























































































                                                                          

 
                                     

                   






                                     


                                 


                                
                                



                                       
                                                                         
 
                          

                        
        
    
                              

                          










                                                         
/**
 * @file
 *
 * @ingroup RTEMSImplClassicTimer
 *
 * @brief This source file contains the definition of ::_Timer_server and the
 *   implementation of _Timer_Routine_adaptor(), _Timer_Fire(),
 *   _Timer_Fire_after(), _Timer_Fire_when(), _Timer_Cancel(), and the Timer
 *   Manager system initialization.
 */

/*
 *  COPYRIGHT (c) 1989-2002.
 *  On-Line Applications Research Corporation (OAR).
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.org/license/LICENSE.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <rtems/rtems/timerimpl.h>
#include <rtems/rtems/clockimpl.h>
#include <rtems/rtems/status.h>
#include <rtems/rtems/support.h>
#include <rtems/score/assert.h>
#include <rtems/score/chainimpl.h>
#include <rtems/score/thread.h>
#include <rtems/score/todimpl.h>
#include <rtems/score/watchdogimpl.h>
#include <rtems/sysinit.h>

RTEMS_STATIC_ASSERT(
  PER_CPU_WATCHDOG_REALTIME == TIMER_CLASS_BIT_TIME_OF_DAY,
  TIMER_CLASS_BIT_TIME_OF_DAY
);

Timer_server_Control *volatile _Timer_server;

void _Timer_Routine_adaptor( Watchdog_Control *the_watchdog )
{
  Timer_Control   *the_timer;
  Per_CPU_Control *cpu;

  the_timer = RTEMS_CONTAINER_OF( the_watchdog, Timer_Control, Ticker );
  cpu = _Watchdog_Get_CPU( &the_timer->Ticker );
  the_timer->stop_time = _Timer_Get_CPU_ticks( cpu );

  ( *the_timer->routine )( the_timer->Object.id, the_timer->user_data );
}

rtems_status_code _Timer_Fire(
  rtems_id                           id,
  rtems_interval                     interval,
  rtems_timer_service_routine_entry  routine,
  void                              *user_data,
  Timer_Classes                      the_class,
  Watchdog_Service_routine_entry     adaptor
)
{
  Timer_Control    *the_timer;
  ISR_lock_Context  lock_context;

  the_timer = _Timer_Get( id, &lock_context );
  if ( the_timer != NULL ) {
    Per_CPU_Control *cpu;

    cpu = _Timer_Acquire_critical( the_timer, &lock_context );
    _Timer_Cancel( cpu, the_timer );
    _Watchdog_Initialize( &the_timer->Ticker, adaptor );
    the_timer->the_class = the_class;
    the_timer->routine = routine;
    the_timer->user_data = user_data;
    the_timer->initial = interval;
    the_timer->start_time = _Timer_Get_CPU_ticks( cpu );

    if ( _Timer_Is_interval_class( the_class ) ) {
      _Watchdog_Insert(
        &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_TICKS ],
        &the_timer->Ticker,
        cpu->Watchdog.ticks + interval
      );
    } else {
      _Watchdog_Insert(
        &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_REALTIME ],
        &the_timer->Ticker,
        _Watchdog_Ticks_from_seconds( interval )
      );
    }

    _Timer_Release( cpu, &lock_context );
    return RTEMS_SUCCESSFUL;
  }

  return RTEMS_INVALID_ID;
}

rtems_status_code _Timer_Fire_after(
  rtems_id                           id,
  rtems_interval                     ticks,
  rtems_timer_service_routine_entry  routine,
  void                              *user_data,
  Timer_Classes                      the_class,
  Watchdog_Service_routine_entry     adaptor
)
{
  if ( ticks == 0 )
    return RTEMS_INVALID_NUMBER;

  if ( !routine )
    return RTEMS_INVALID_ADDRESS;

  return _Timer_Fire(
    id,
    ticks,
    routine,
    user_data,
    the_class,
    adaptor
  );
}

rtems_status_code _Timer_Fire_when(
  rtems_id                           id,
  const rtems_time_of_day           *wall_time,
  rtems_timer_service_routine_entry  routine,
  void                              *user_data,
  Timer_Classes                      the_class,
  Watchdog_Service_routine_entry     adaptor
)
{
  rtems_interval seconds;

  if ( !_TOD_Is_set() )
    return RTEMS_NOT_DEFINED;

  if ( !routine )
    return RTEMS_INVALID_ADDRESS;

  if ( !_TOD_Validate( wall_time ) )
    return RTEMS_INVALID_CLOCK;

  seconds = _TOD_To_seconds( wall_time );
  if ( seconds <= _TOD_Seconds_since_epoch() )
    return RTEMS_INVALID_CLOCK;

  return _Timer_Fire(
    id,
    seconds,
    routine,
    user_data,
    the_class,
    adaptor
  );
}

void _Timer_Cancel( Per_CPU_Control *cpu, Timer_Control *the_timer )
{
  Timer_Classes the_class;

  the_class = the_timer->the_class;

  if ( _Watchdog_Is_scheduled( &the_timer->Ticker ) ) {
    the_timer->stop_time = _Timer_Get_CPU_ticks( cpu );
    _Watchdog_Remove(
      &cpu->Watchdog.Header[ _Timer_Watchdog_header_index( the_class ) ],
      &the_timer->Ticker
    );
  } else if ( _Timer_Is_on_task_class( the_class ) ) {
    Timer_server_Control *timer_server;
    ISR_lock_Context      lock_context;

    timer_server = _Timer_server;
    _Assert( timer_server != NULL );
    _Timer_server_Acquire_critical( timer_server, &lock_context );

    if ( _Watchdog_Get_state( &the_timer->Ticker ) == WATCHDOG_PENDING ) {
      _Watchdog_Set_state( &the_timer->Ticker, WATCHDOG_INACTIVE );
      _Chain_Extract_unprotected( &the_timer->Ticker.Node.Chain );
    }

    _Timer_server_Release_critical( timer_server, &lock_context );
  }
}

rtems_status_code rtems_timer_create(
  rtems_name  name,
  rtems_id   *id
)
{
  Timer_Control *the_timer;

  if ( !rtems_is_name_valid( name ) )
    return RTEMS_INVALID_NAME;

  if ( !id )
    return RTEMS_INVALID_ADDRESS;

  the_timer = _Timer_Allocate();

  if ( !the_timer ) {
    _Objects_Allocator_unlock();
    return RTEMS_TOO_MANY;
  }

  the_timer->the_class = TIMER_DORMANT;
  _Watchdog_Preinitialize( &the_timer->Ticker, _Per_CPU_Get_snapshot() );

  *id = _Objects_Open_u32(
    &_Timer_Information,
    &the_timer->Object,
    name
  );
  _Objects_Allocator_unlock();
  return RTEMS_SUCCESSFUL;
}

static void _Timer_Manager_initialization( void )
{
  _Objects_Initialize_information( &_Timer_Information );
}

RTEMS_SYSINIT_ITEM(
  _Timer_Manager_initialization,
  RTEMS_SYSINIT_CLASSIC_TIMER,
  RTEMS_SYSINIT_ORDER_MIDDLE
);