summaryrefslogblamecommitdiffstats
path: root/cpukit/include/rtems/score/userextimpl.h
blob: 8b456c072da4504d9a8e59880df90e2722b1bbfb (plain) (tree)
1
2
3
4
5
6


        
                             
  
                                    







                                                           
                                         




                                  
                                    
                                  

                                
                               





                  
                                

     


   































                                                                            

                                    
                                                  







                                                    

     

   


                                                  

                                                     




                                              



                                    




                                              






                                                       





                                                                           









                                                              




                                                 





















                                                                         






                                                                              





                                            






                                                              





                                            






                                                              





                                           






                                                              





                                             






                                                                         





                                           






                                                                           







                                             


                                






                                                                         





                                         






                                                              





                                               



                                                                              

                                                                   

                              


                                     





                                     
   
          
 







                                            



                                                                            




                                           



                




                                            



                                                                            

                                           


    




                                      



                                                                           

                                          


    




                                        



                                                                               

                                            


    




                                      



                                                                             

                                          


    





                                                             
                                                  

                            

 






                                          
 
                       
                      

                                   

                              
 

                                                
 


                                           
                            
                                                      
 
                                                                
                                           
                                                     

     
                      

                                                
      

   
 




                                          



                                                                               

                                            


    





                                                               

                                          


                              
                                                        
 


                                   
                          
    

 




                                                   





                                                     
                                              
                           


    




                                                            




                                                                             


    




                                                           







                                                                             





                                                                      


















                                                      








                  
                         
/**
 * @file
 *
 * @ingroup RTEMSScoreUserExt
 *
 * @brief User Extension Handler API
 */

/*
 *  COPYRIGHT (c) 1989-2009.
 *  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.
 */

#ifndef _RTEMS_SCORE_USEREXTIMPL_H
#define _RTEMS_SCORE_USEREXTIMPL_H

#include <rtems/score/userextdata.h>
#include <rtems/score/chainimpl.h>
#include <rtems/score/isrlock.h>
#include <rtems/score/thread.h>
#include <rtems/score/percpu.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @addtogroup RTEMSScoreUserExt
 *
 * @{
 */

/**
 * @brief Chain iterator for dynamic user extensions.
 *
 * Since user extensions may delete or restart the executing thread, we must
 * clean up registered iterators.
 *
 * @see _User_extensions_Iterate(), _User_extensions_Destroy_iterators() and
 *   Thread_Control::last_user_extensions_iterator.
 */
typedef struct User_extensions_Iterator {
  Chain_Iterator                   Iterator;
  struct User_extensions_Iterator *previous;
} User_extensions_Iterator;

typedef struct {
  /**
   * @brief Active dynamically added user extensions.
   */
  Chain_Control Active;

  /**
   * @brief Chain iterator registration.
   */
  Chain_Iterator_registry Iterators;

  /**
   * @brief Lock to protect User_extensions_List::Active and
   * User_extensions_List::Iterators.
   */
  ISR_LOCK_MEMBER( Lock )
} User_extensions_List;

/**
 * @brief List of active extensions.
 */
extern User_extensions_List _User_extensions_List;

/**
 * @brief List of active task switch extensions.
 */
extern Chain_Control _User_extensions_Switches_list;

/**
 * @name Extension Maintainance
 *
 * @{
 */

/**
 * @brief Initializes the user extensions handler.
 */
void _User_extensions_Handler_initialization( void );

/**
 * @brief Adds a user extension.
 *
 * @param extension The user extension to add.
 */
void _User_extensions_Add_set(
  User_extensions_Control *extension
);

/**
 * @brief Adds a user extension.
 *
 * @param extension The user extension to add.
 */
RTEMS_INLINE_ROUTINE void _User_extensions_Add_API_set(
  User_extensions_Control *extension
)
{
  _User_extensions_Add_set( extension );
}

/**
 * @brief Adds a user extension with the given extension table as callouts.
 *
 * @param[in, out] extension The user extension to add.
 * @param extension_table Is set as callouts for @a extension.
 */
RTEMS_INLINE_ROUTINE void _User_extensions_Add_set_with_table(
  User_extensions_Control     *extension,
  const User_extensions_Table *extension_table
)
{
  extension->Callouts = *extension_table;

  _User_extensions_Add_set( extension );
}

/**
 * @brief Removes a user extension.
 *
 * @param extension The user extension to remove.
 */
void _User_extensions_Remove_set(
  User_extensions_Control *extension
);

/**
 * @brief User extension visitor.
 *
 * @param[in, out] executing The currently executing thread.
 * @param[in, out] arg The argument passed to _User_extensions_Iterate().
 * @param[in] callouts The current callouts.
 */
typedef void (*User_extensions_Visitor)(
  Thread_Control              *executing,
  void                        *arg,
  const User_extensions_Table *callouts
);

typedef struct {
  Thread_Control *created;
  bool            ok;
} User_extensions_Thread_create_context;

/**
 * @brief Creates a visitor.
 *
 * @param executing The currently executing thread.
 * @param[in, out] arg Is used as the thread create context for the operation.
 * @param callouts The user extension table for the operation.
 */
void _User_extensions_Thread_create_visitor(
  Thread_Control              *executing,
  void                        *arg,
  const User_extensions_Table *callouts
);

/**
 * @brief Deletes a visitor.
 *
 * @param executing The currently executing thread.
 * @param[in, out] arg Parameter for the callout.
 * @param callouts The user extension table for the operation.
 */
void _User_extensions_Thread_delete_visitor(
  Thread_Control              *executing,
  void                        *arg,
  const User_extensions_Table *callouts
);

/**
 * @brief Starts a visitor.
 *
 * @param executing The currently executing thread.
 * @param arg Parameter for the callout.
 * @param callouts The user extension table for the operation.
 */
void _User_extensions_Thread_start_visitor(
  Thread_Control              *executing,
  void                        *arg,
  const User_extensions_Table *callouts
);

/**
 * @brief Restarts a visitor.
 *
 * @param executing The currently executing thread.
 * @param arg Parameter for the callout.
 * @param callouts The user extension table for the operation.
 */
void _User_extensions_Thread_restart_visitor(
  Thread_Control              *executing,
  void                        *arg,
  const User_extensions_Table *callouts
);

/**
 * @brief Calls the begin function of the thread callout for the visitor.
 *
 * @param executing The currently executing thread.
 * @param arg This parameter is unused.
 * @param callouts The user extension table for the operation.
 */
void _User_extensions_Thread_begin_visitor(
  Thread_Control              *executing,
  void                        *arg,
  const User_extensions_Table *callouts
);

/**
 * @brief Calls the exitted function of the thread callout for the visitor.
 *
 * @param executing The currently executing thread.
 * @param arg This parameter is unused.
 * @param callouts The user extension table for the operation.
 */
void _User_extensions_Thread_exitted_visitor(
  Thread_Control              *executing,
  void                        *arg,
  const User_extensions_Table *callouts
);

typedef struct {
  Internal_errors_Source source;
  Internal_errors_t      error;
} User_extensions_Fatal_context;

/**
 * @brief Calls the fatal function of the thread callout for the visitor.
 *
 * @param executing The currently executing thread.
 * @param arg Is used as the user extension fatal context.
 * @param callouts The user extension table for the operation.
 */
void _User_extensions_Fatal_visitor(
  Thread_Control              *executing,
  void                        *arg,
  const User_extensions_Table *callouts
);

/**
 * @brief Terminates a visitor.
 *
 * @param executing The currently executing thread.
 * @param arg This parameter is unused.
 * @param callouts The user extension table for the operation.
 */
void _User_extensions_Thread_terminate_visitor(
  Thread_Control              *executing,
  void                        *arg,
  const User_extensions_Table *callouts
);

/**
 * @brief Iterates through all user extensions and calls the visitor for each.
 *
 * @param[in, out] arg The argument passed to the visitor.
 * @param visitor The visitor for each extension.
 * @param direction The iteration direction for dynamic extensions.
 */
void _User_extensions_Iterate(
  void                     *arg,
  User_extensions_Visitor   visitor,
  Chain_Iterator_direction  direction
);

/** @} */

/**
 * @name Extension Callout Dispatcher
 */
/** @{ **/

/**
 * @brief Creates a thread.
 *
 * @param[out] created The thread to create.
 *
 * @retval true The operation succeeded.
 * @retval false The operation failed.
 */
static inline bool _User_extensions_Thread_create( Thread_Control *created )
{
  User_extensions_Thread_create_context ctx = { created, true };

  _User_extensions_Iterate(
    &ctx,
    _User_extensions_Thread_create_visitor,
    CHAIN_ITERATOR_FORWARD
  );

  return ctx.ok;
}

/**
 * @brief Deletes a thread.
 *
 * @param[out] created The thread to delete.
 */
static inline void _User_extensions_Thread_delete( Thread_Control *deleted )
{
  _User_extensions_Iterate(
    deleted,
    _User_extensions_Thread_delete_visitor,
    CHAIN_ITERATOR_BACKWARD
  );
}

/**
 * @brief Starts a thread.
 *
 * @param created The thread to start.
 */
static inline void _User_extensions_Thread_start( Thread_Control *started )
{
  _User_extensions_Iterate(
    started,
    _User_extensions_Thread_start_visitor,
    CHAIN_ITERATOR_FORWARD
  );
}

/**
 * @brief Restarts a thread.
 *
 * @param created The thread to restart.
 */
static inline void _User_extensions_Thread_restart( Thread_Control *restarted )
{
  _User_extensions_Iterate(
    restarted,
    _User_extensions_Thread_restart_visitor,
    CHAIN_ITERATOR_FORWARD
  );
}

/**
 * @brief Begins a thread.
 *
 * @param created The thread to begin.
 */
static inline void _User_extensions_Thread_begin( Thread_Control *executing )
{
  _User_extensions_Iterate(
    executing,
    _User_extensions_Thread_begin_visitor,
    CHAIN_ITERATOR_FORWARD
  );
}

/**
 * @brief Switches the thread from the executing to the heir.
 *
 * @param executing The currently executing thread.
 * @param heir The thread that will switch with @a executing.
 */
static inline void _User_extensions_Thread_switch(
  Thread_Control *executing,
  Thread_Control *heir
)
{
  const Chain_Control *chain;
  const Chain_Node    *tail;
  const Chain_Node    *node;

  chain = &_User_extensions_Switches_list;
  tail = _Chain_Immutable_tail( chain );
  node = _Chain_Immutable_first( chain );

  if ( node != tail ) {
#if defined(RTEMS_SMP)
    ISR_lock_Context  lock_context;
    Per_CPU_Control  *cpu_self;

    cpu_self = _Per_CPU_Get();

    _ISR_lock_ISR_disable( &lock_context );
    _Per_CPU_Acquire( cpu_self, &lock_context );

    node = _Chain_Immutable_first( chain );
#endif

    while ( node != tail ) {
      const User_extensions_Switch_control *extension;

      extension = (const User_extensions_Switch_control *) node;
      node = _Chain_Immutable_next( node );
      (*extension->thread_switch)( executing, heir );
    }

#if defined(RTEMS_SMP)
    _Per_CPU_Release( cpu_self, &lock_context );
    _ISR_lock_ISR_enable( &lock_context );
#endif
  }
}

/**
 * @brief A user extension thread exitted.
 *
 * @param created The thread.
 */
static inline void _User_extensions_Thread_exitted( Thread_Control *executing )
{
  _User_extensions_Iterate(
    executing,
    _User_extensions_Thread_exitted_visitor,
    CHAIN_ITERATOR_FORWARD
  );
}

/**
 * @brief Forwards all visitors that there was a fatal failure.
 *
 * @param source The error source.
 * @param error The error.
 */
static inline void _User_extensions_Fatal(
  Internal_errors_Source source,
  Internal_errors_t      error
)
{
  User_extensions_Fatal_context ctx = { source, error };

  _User_extensions_Iterate(
    &ctx,
    _User_extensions_Fatal_visitor,
    CHAIN_ITERATOR_FORWARD
  );
}

/**
 * @brief Terminates the executing thread.
 *
 * @param executing The currently executing thread.
 */
static inline void _User_extensions_Thread_terminate(
  Thread_Control *executing
)
{
  _User_extensions_Iterate(
    executing,
    _User_extensions_Thread_terminate_visitor,
    CHAIN_ITERATOR_BACKWARD
  );
}

/**
 * @brief Disables interrupts and acquires the lock context.
 *
 * @param lock_context The lock context to acquire.
 */
static inline void _User_extensions_Acquire( ISR_lock_Context *lock_context )
{
  _ISR_lock_ISR_disable_and_acquire(
    &_User_extensions_List.Lock,
    lock_context
  );
}

/**
 * @brief Releases the lock context and enables interrupts.
 *
 * @param lock_context The lock context to release.
 */
static inline void _User_extensions_Release( ISR_lock_Context *lock_context )
{
  _ISR_lock_Release_and_ISR_enable(
    &_User_extensions_List.Lock,
    lock_context
  );
}

/**
 * @brief Destroys all user extension iterators of a thread.
 *
 * @param[in, out] the_thread The thread to destroy all user extension
 *      iterators of.
 */
static inline void _User_extensions_Destroy_iterators(
  Thread_Control *the_thread
)
{
  ISR_lock_Context          lock_context;
  User_extensions_Iterator *iter;

  _User_extensions_Acquire( &lock_context );

  iter = the_thread->last_user_extensions_iterator;

  while ( iter != NULL ) {
    _Chain_Iterator_destroy( &iter->Iterator );
    iter = iter->previous;
  }

  _User_extensions_Release( &lock_context );
}

/** @} */

/** @} */

#ifdef __cplusplus
}
#endif

#endif
/* end of include file */