Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSScoreUserExt
0007  *
0008  * @brief This header file provides interfaces of the
0009  *   @ref RTEMSScoreUserExt which are only used by the implementation.
0010  */
0011 
0012 /*
0013  *  COPYRIGHT (c) 1989-2009.
0014  *  On-Line Applications Research Corporation (OAR).
0015  *
0016  * Redistribution and use in source and binary forms, with or without
0017  * modification, are permitted provided that the following conditions
0018  * are met:
0019  * 1. Redistributions of source code must retain the above copyright
0020  *    notice, this list of conditions and the following disclaimer.
0021  * 2. Redistributions in binary form must reproduce the above copyright
0022  *    notice, this list of conditions and the following disclaimer in the
0023  *    documentation and/or other materials provided with the distribution.
0024  *
0025  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0026  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0027  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0028  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0029  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0030  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0031  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0032  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0033  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0034  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0035  * POSSIBILITY OF SUCH DAMAGE.
0036  */
0037 
0038 #ifndef _RTEMS_SCORE_USEREXTIMPL_H
0039 #define _RTEMS_SCORE_USEREXTIMPL_H
0040 
0041 #include <rtems/score/userextdata.h>
0042 #include <rtems/score/chainimpl.h>
0043 #include <rtems/score/isrlock.h>
0044 #include <rtems/score/thread.h>
0045 #include <rtems/score/percpu.h>
0046 
0047 #ifdef __cplusplus
0048 extern "C" {
0049 #endif
0050 
0051 /**
0052  * @addtogroup RTEMSScoreUserExt
0053  *
0054  * @{
0055  */
0056 
0057 /**
0058  * @brief Chain iterator for dynamic user extensions.
0059  *
0060  * Since user extensions may delete or restart the executing thread, we must
0061  * clean up registered iterators.
0062  *
0063  * @see _User_extensions_Iterate(), _User_extensions_Destroy_iterators() and
0064  *   Thread_Control::last_user_extensions_iterator.
0065  */
0066 typedef struct User_extensions_Iterator {
0067   Chain_Iterator                   Iterator;
0068   struct User_extensions_Iterator *previous;
0069 } User_extensions_Iterator;
0070 
0071 typedef struct {
0072   /**
0073    * @brief Active dynamically added user extensions.
0074    */
0075   Chain_Control Active;
0076 
0077   /**
0078    * @brief Chain iterator registration.
0079    */
0080   Chain_Iterator_registry Iterators;
0081 
0082 #if defined(RTEMS_SMP)
0083   /**
0084    * @brief Lock to protect User_extensions_List::Active and
0085    * User_extensions_List::Iterators.
0086    */
0087   ISR_lock_Control Lock;
0088 #endif
0089 } User_extensions_List;
0090 
0091 /**
0092  * @brief List of active extensions.
0093  */
0094 extern User_extensions_List _User_extensions_List;
0095 
0096 /**
0097  * @brief List of active task switch extensions.
0098  */
0099 extern Chain_Control _User_extensions_Switches_list;
0100 
0101 /**
0102  * @name Extension Maintainance
0103  *
0104  * @{
0105  */
0106 
0107 /**
0108  * @brief Initializes the user extensions handler.
0109  */
0110 void _User_extensions_Handler_initialization( void );
0111 
0112 /**
0113  * @brief Adds a user extension.
0114  *
0115  * @param extension The user extension to add.
0116  */
0117 void _User_extensions_Add_set(
0118   User_extensions_Control *extension
0119 );
0120 
0121 /**
0122  * @brief Adds a user extension.
0123  *
0124  * @param extension The user extension to add.
0125  */
0126 static inline void _User_extensions_Add_API_set(
0127   User_extensions_Control *extension
0128 )
0129 {
0130   _User_extensions_Add_set( extension );
0131 }
0132 
0133 /**
0134  * @brief Adds a user extension with the given extension table as callouts.
0135  *
0136  * @param[in, out] extension The user extension to add.
0137  * @param extension_table Is set as callouts for @a extension.
0138  */
0139 static inline void _User_extensions_Add_set_with_table(
0140   User_extensions_Control     *extension,
0141   const User_extensions_Table *extension_table
0142 )
0143 {
0144   extension->Callouts = *extension_table;
0145 
0146   _User_extensions_Add_set( extension );
0147 }
0148 
0149 /**
0150  * @brief Removes a user extension.
0151  *
0152  * @param extension The user extension to remove.
0153  */
0154 void _User_extensions_Remove_set(
0155   User_extensions_Control *extension
0156 );
0157 
0158 /**
0159  * @brief User extension visitor.
0160  *
0161  * @param[in, out] executing The currently executing thread.
0162  * @param[in, out] arg The argument passed to _User_extensions_Iterate().
0163  * @param[in] callouts The current callouts.
0164  */
0165 typedef void (*User_extensions_Visitor)(
0166   Thread_Control              *executing,
0167   void                        *arg,
0168   const User_extensions_Table *callouts
0169 );
0170 
0171 typedef struct {
0172   Thread_Control *created;
0173   bool            ok;
0174 } User_extensions_Thread_create_context;
0175 
0176 /**
0177  * @brief Creates a visitor.
0178  *
0179  * @param executing The currently executing thread.
0180  * @param[in, out] arg Is used as the thread create context for the operation.
0181  * @param callouts The user extension table for the operation.
0182  */
0183 void _User_extensions_Thread_create_visitor(
0184   Thread_Control              *executing,
0185   void                        *arg,
0186   const User_extensions_Table *callouts
0187 );
0188 
0189 /**
0190  * @brief Deletes a visitor.
0191  *
0192  * @param executing The currently executing thread.
0193  * @param[in, out] arg Parameter for the callout.
0194  * @param callouts The user extension table for the operation.
0195  */
0196 void _User_extensions_Thread_delete_visitor(
0197   Thread_Control              *executing,
0198   void                        *arg,
0199   const User_extensions_Table *callouts
0200 );
0201 
0202 /**
0203  * @brief Starts a visitor.
0204  *
0205  * @param executing The currently executing thread.
0206  * @param arg Parameter for the callout.
0207  * @param callouts The user extension table for the operation.
0208  */
0209 void _User_extensions_Thread_start_visitor(
0210   Thread_Control              *executing,
0211   void                        *arg,
0212   const User_extensions_Table *callouts
0213 );
0214 
0215 /**
0216  * @brief Restarts a visitor.
0217  *
0218  * @param executing The currently executing thread.
0219  * @param arg Parameter for the callout.
0220  * @param callouts The user extension table for the operation.
0221  */
0222 void _User_extensions_Thread_restart_visitor(
0223   Thread_Control              *executing,
0224   void                        *arg,
0225   const User_extensions_Table *callouts
0226 );
0227 
0228 /**
0229  * @brief Calls the begin function of the thread callout for the visitor.
0230  *
0231  * @param executing The currently executing thread.
0232  * @param arg This parameter is unused.
0233  * @param callouts The user extension table for the operation.
0234  */
0235 void _User_extensions_Thread_begin_visitor(
0236   Thread_Control              *executing,
0237   void                        *arg,
0238   const User_extensions_Table *callouts
0239 );
0240 
0241 /**
0242  * @brief Calls the exitted function of the thread callout for the visitor.
0243  *
0244  * @param executing The currently executing thread.
0245  * @param arg This parameter is unused.
0246  * @param callouts The user extension table for the operation.
0247  */
0248 void _User_extensions_Thread_exitted_visitor(
0249   Thread_Control              *executing,
0250   void                        *arg,
0251   const User_extensions_Table *callouts
0252 );
0253 
0254 typedef struct {
0255   Internal_errors_Source source;
0256   Internal_errors_t      error;
0257 } User_extensions_Fatal_context;
0258 
0259 /**
0260  * @brief Calls the fatal function of the thread callout for the visitor.
0261  *
0262  * @param executing The currently executing thread.
0263  * @param arg Is used as the user extension fatal context.
0264  * @param callouts The user extension table for the operation.
0265  */
0266 void _User_extensions_Fatal_visitor(
0267   Thread_Control              *executing,
0268   void                        *arg,
0269   const User_extensions_Table *callouts
0270 );
0271 
0272 /**
0273  * @brief Terminates a visitor.
0274  *
0275  * @param executing The currently executing thread.
0276  * @param arg This parameter is unused.
0277  * @param callouts The user extension table for the operation.
0278  */
0279 void _User_extensions_Thread_terminate_visitor(
0280   Thread_Control              *executing,
0281   void                        *arg,
0282   const User_extensions_Table *callouts
0283 );
0284 
0285 /**
0286  * @brief Iterates through all user extensions and calls the visitor for each.
0287  *
0288  * @param[in, out] arg The argument passed to the visitor.
0289  * @param visitor The visitor for each extension.
0290  * @param direction The iteration direction for dynamic extensions.
0291  */
0292 void _User_extensions_Iterate(
0293   void                     *arg,
0294   User_extensions_Visitor   visitor,
0295   Chain_Iterator_direction  direction
0296 );
0297 
0298 /** @} */
0299 
0300 /**
0301  * @name Extension Callout Dispatcher
0302  */
0303 /** @{ **/
0304 
0305 /**
0306  * @brief Creates a thread.
0307  *
0308  * @param[out] created The thread to create.
0309  *
0310  * @retval true The operation succeeded.
0311  * @retval false The operation failed.
0312  */
0313 static inline bool _User_extensions_Thread_create( Thread_Control *created )
0314 {
0315   User_extensions_Thread_create_context ctx = { created, true };
0316 
0317   _User_extensions_Iterate(
0318     &ctx,
0319     _User_extensions_Thread_create_visitor,
0320     CHAIN_ITERATOR_FORWARD
0321   );
0322 
0323   return ctx.ok;
0324 }
0325 
0326 /**
0327  * @brief Deletes a thread.
0328  *
0329  * @param[out] created The thread to delete.
0330  */
0331 static inline void _User_extensions_Thread_delete( Thread_Control *deleted )
0332 {
0333   _User_extensions_Iterate(
0334     deleted,
0335     _User_extensions_Thread_delete_visitor,
0336     CHAIN_ITERATOR_BACKWARD
0337   );
0338 }
0339 
0340 /**
0341  * @brief Starts a thread.
0342  *
0343  * @param created The thread to start.
0344  */
0345 static inline void _User_extensions_Thread_start( Thread_Control *started )
0346 {
0347   _User_extensions_Iterate(
0348     started,
0349     _User_extensions_Thread_start_visitor,
0350     CHAIN_ITERATOR_FORWARD
0351   );
0352 }
0353 
0354 /**
0355  * @brief Restarts a thread.
0356  *
0357  * @param created The thread to restart.
0358  */
0359 static inline void _User_extensions_Thread_restart( Thread_Control *restarted )
0360 {
0361   _User_extensions_Iterate(
0362     restarted,
0363     _User_extensions_Thread_restart_visitor,
0364     CHAIN_ITERATOR_FORWARD
0365   );
0366 }
0367 
0368 /**
0369  * @brief Begins a thread.
0370  *
0371  * @param created The thread to begin.
0372  */
0373 static inline void _User_extensions_Thread_begin( Thread_Control *executing )
0374 {
0375   _User_extensions_Iterate(
0376     executing,
0377     _User_extensions_Thread_begin_visitor,
0378     CHAIN_ITERATOR_FORWARD
0379   );
0380 }
0381 
0382 /**
0383  * @brief Switches the thread from the executing to the heir.
0384  *
0385  * @param executing The currently executing thread.
0386  * @param heir The thread that will switch with @a executing.
0387  */
0388 static inline void _User_extensions_Thread_switch(
0389   Thread_Control *executing,
0390   Thread_Control *heir
0391 )
0392 {
0393   const Chain_Control *chain;
0394   const Chain_Node    *tail;
0395   const Chain_Node    *node;
0396 
0397   chain = &_User_extensions_Switches_list;
0398   tail = _Chain_Immutable_tail( chain );
0399   node = _Chain_Immutable_first( chain );
0400 
0401   if ( node != tail ) {
0402 #if defined(RTEMS_SMP)
0403     ISR_lock_Context  lock_context;
0404     Per_CPU_Control  *cpu_self;
0405 
0406     cpu_self = _Per_CPU_Get();
0407 
0408     _ISR_lock_ISR_disable( &lock_context );
0409     _Per_CPU_Acquire( cpu_self, &lock_context );
0410 
0411     executing = cpu_self->ancestor;
0412     cpu_self->ancestor = heir;
0413     node = _Chain_Immutable_first( chain );
0414 
0415     /*
0416      * An executing thread equal to the heir thread may happen in two
0417      * situations.  Firstly, in case context switch extensions are created after
0418      * system initialization.  Secondly, during a thread self restart.
0419      */
0420     if ( executing != heir ) {
0421 #endif
0422 
0423     while ( node != tail ) {
0424       const User_extensions_Switch_control *extension;
0425 
0426       extension = (const User_extensions_Switch_control *) node;
0427       node = _Chain_Immutable_next( node );
0428       (*extension->thread_switch)( executing, heir );
0429     }
0430 
0431 #if defined(RTEMS_SMP)
0432     }
0433 
0434     _Per_CPU_Release( cpu_self, &lock_context );
0435     _ISR_lock_ISR_enable( &lock_context );
0436 #endif
0437   }
0438 }
0439 
0440 /**
0441  * @brief A user extension thread exitted.
0442  *
0443  * @param created The thread.
0444  */
0445 static inline void _User_extensions_Thread_exitted( Thread_Control *executing )
0446 {
0447   _User_extensions_Iterate(
0448     executing,
0449     _User_extensions_Thread_exitted_visitor,
0450     CHAIN_ITERATOR_FORWARD
0451   );
0452 }
0453 
0454 /**
0455  * @brief Forwards all visitors that there was a fatal failure.
0456  *
0457  * @param source The error source.
0458  * @param error The error.
0459  */
0460 static inline void _User_extensions_Fatal(
0461   Internal_errors_Source source,
0462   Internal_errors_t      error
0463 )
0464 {
0465   User_extensions_Fatal_context ctx = { source, error };
0466 
0467   _User_extensions_Iterate(
0468     &ctx,
0469     _User_extensions_Fatal_visitor,
0470     CHAIN_ITERATOR_FORWARD
0471   );
0472 }
0473 
0474 /**
0475  * @brief Terminates the executing thread.
0476  *
0477  * @param executing The currently executing thread.
0478  */
0479 static inline void _User_extensions_Thread_terminate(
0480   Thread_Control *executing
0481 )
0482 {
0483   _User_extensions_Iterate(
0484     executing,
0485     _User_extensions_Thread_terminate_visitor,
0486     CHAIN_ITERATOR_BACKWARD
0487   );
0488 }
0489 
0490 /**
0491  * @brief Disables interrupts and acquires the lock context.
0492  *
0493  * @param lock_context The lock context to acquire.
0494  */
0495 static inline void _User_extensions_Acquire( ISR_lock_Context *lock_context )
0496 {
0497   _ISR_lock_ISR_disable_and_acquire(
0498     &_User_extensions_List.Lock,
0499     lock_context
0500   );
0501 }
0502 
0503 /**
0504  * @brief Releases the lock context and enables interrupts.
0505  *
0506  * @param lock_context The lock context to release.
0507  */
0508 static inline void _User_extensions_Release( ISR_lock_Context *lock_context )
0509 {
0510   _ISR_lock_Release_and_ISR_enable(
0511     &_User_extensions_List.Lock,
0512     lock_context
0513   );
0514 }
0515 
0516 /**
0517  * @brief Destroys all user extension iterators of a thread.
0518  *
0519  * @param[in, out] the_thread The thread to destroy all user extension
0520  *      iterators of.
0521  */
0522 static inline void _User_extensions_Destroy_iterators(
0523   Thread_Control *the_thread
0524 )
0525 {
0526   ISR_lock_Context          lock_context;
0527   User_extensions_Iterator *iter;
0528 
0529   _User_extensions_Acquire( &lock_context );
0530 
0531   iter = the_thread->last_user_extensions_iterator;
0532 
0533   while ( iter != NULL ) {
0534     _Chain_Iterator_destroy( &iter->Iterator );
0535     iter = iter->previous;
0536   }
0537 
0538   _User_extensions_Release( &lock_context );
0539 }
0540 
0541 /** @} */
0542 
0543 /** @} */
0544 
0545 #ifdef __cplusplus
0546 }
0547 #endif
0548 
0549 #endif
0550 /* end of include file */