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 RTEMSScoreMRSP
0007  *
0008  * @brief This header file provides interfaces of the
0009  *   @ref RTEMSScoreMRSP which are only used by the implementation.
0010  */
0011 
0012 /*
0013  * Copyright (C) 2014, 2019 embedded brains GmbH & Co. KG
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 #ifndef _RTEMS_SCORE_MRSPIMPL_H
0038 #define _RTEMS_SCORE_MRSPIMPL_H
0039 
0040 #include <rtems/score/mrsp.h>
0041 
0042 #if defined(RTEMS_SMP)
0043 
0044 #include <rtems/score/assert.h>
0045 #include <rtems/score/status.h>
0046 #include <rtems/score/threadqimpl.h>
0047 #include <rtems/score/watchdogimpl.h>
0048 
0049 #ifdef __cplusplus
0050 extern "C" {
0051 #endif /* __cplusplus */
0052 
0053 /**
0054  * @addtogroup RTEMSScoreMRSP
0055  *
0056  * @{
0057  */
0058 
0059 #define MRSP_TQ_OPERATIONS &_Thread_queue_Operations_priority_inherit
0060 
0061 /**
0062  * @brief Acquires critical accordingt to MrsP.
0063  *
0064  * @param mrsp The MrsP control for the operation.
0065  * @param queue_context The thread queue context.
0066  */
0067 static inline void _MRSP_Acquire_critical(
0068   MRSP_Control         *mrsp,
0069   Thread_queue_Context *queue_context
0070 )
0071 {
0072   _Thread_queue_Acquire_critical( &mrsp->Wait_queue, queue_context );
0073 }
0074 
0075 /**
0076  * @brief Releases according to MrsP.
0077  *
0078  * @param mrsp The MrsP control for the operation.
0079  * @param queue_context The thread queue context.
0080  */
0081 static inline void _MRSP_Release(
0082   MRSP_Control         *mrsp,
0083   Thread_queue_Context *queue_context
0084 )
0085 {
0086   _Thread_queue_Release( &mrsp->Wait_queue, queue_context );
0087 }
0088 
0089 /**
0090  * @brief Gets owner of the MrsP control.
0091  *
0092  * @param mrsp The MrsP control to get the owner from.
0093  *
0094  * @return The owner of the Mrsp control.
0095  */
0096 static inline Thread_Control *_MRSP_Get_owner(
0097   const MRSP_Control *mrsp
0098 )
0099 {
0100   return mrsp->Wait_queue.Queue.owner;
0101 }
0102 
0103 /**
0104  * @brief Sets owner of the MrsP control.
0105  *
0106  * @param[out] mrsp The MrsP control to set the owner of.
0107  * @param owner The desired new owner for @a mrsp.
0108  */
0109 static inline void _MRSP_Set_owner(
0110   MRSP_Control   *mrsp,
0111   Thread_Control *owner
0112 )
0113 {
0114   mrsp->Wait_queue.Queue.owner = owner;
0115 }
0116 
0117 /**
0118  * @brief Gets priority of the MrsP control.
0119  *
0120  * @param mrsp The mrsp to get the priority from.
0121  * @param scheduler The corresponding scheduler.
0122  *
0123  * @return The priority of the MrsP control.
0124  */
0125 static inline Priority_Control _MRSP_Get_priority(
0126   const MRSP_Control      *mrsp,
0127   const Scheduler_Control *scheduler
0128 )
0129 {
0130   uint32_t scheduler_index;
0131 
0132   scheduler_index = _Scheduler_Get_index( scheduler );
0133   _Assert( scheduler_index < _Scheduler_Count );
0134   return mrsp->ceiling_priorities[ scheduler_index ];
0135 }
0136 
0137 /**
0138  * @brief Sets priority of the MrsP control
0139  *
0140  * @param[out] mrsp The MrsP control to set the priority of.
0141  * @param schedulger The corresponding scheduler.
0142  * @param new_priority The new priority for the MrsP control
0143  */
0144 static inline void _MRSP_Set_priority(
0145   MRSP_Control            *mrsp,
0146   const Scheduler_Control *scheduler,
0147   Priority_Control         new_priority
0148 )
0149 {
0150   uint32_t scheduler_index;
0151 
0152   scheduler_index = _Scheduler_Get_index( scheduler );
0153   _Assert( scheduler_index < _Scheduler_Count );
0154   mrsp->ceiling_priorities[ scheduler_index ] = new_priority;
0155 }
0156 
0157 /**
0158  * @brief Adds the priority to the given thread.
0159  *
0160  * @param mrsp The MrsP control for the operation.
0161  * @param[in, out] thread The thread to add the priority node to.
0162  * @param[out] priority_node The priority node to initialize and add to
0163  *      the thread.
0164  * @param queue_context The thread queue context.
0165  *
0166  * @retval STATUS_SUCCESSFUL The operation succeeded.
0167  * @retval STATUS_MUTEX_CEILING_VIOLATED The wait priority of the thread
0168  *      exceeds the ceiling priority.
0169  */
0170 static inline Status_Control _MRSP_Raise_priority(
0171   MRSP_Control         *mrsp,
0172   Thread_Control       *thread,
0173   Priority_Node        *priority_node,
0174   Thread_queue_Context *queue_context
0175 )
0176 {
0177   Status_Control           status;
0178   ISR_lock_Context         lock_context;
0179   const Scheduler_Control *scheduler;
0180   Priority_Control         ceiling_priority;
0181   Scheduler_Node          *scheduler_node;
0182 
0183   _Thread_queue_Context_clear_priority_updates( queue_context );
0184   _Thread_Wait_acquire_default_critical( thread, &lock_context );
0185 
0186   scheduler = _Thread_Scheduler_get_home( thread );
0187   scheduler_node = _Thread_Scheduler_get_home_node( thread );
0188   ceiling_priority = _MRSP_Get_priority( mrsp, scheduler );
0189 
0190   if (
0191     ceiling_priority
0192       <= _Priority_Get_priority( &scheduler_node->Wait.Priority )
0193   ) {
0194     _Priority_Node_initialize( priority_node, ceiling_priority );
0195     _Thread_Priority_add( thread, priority_node, queue_context );
0196     status = STATUS_SUCCESSFUL;
0197   } else {
0198     status = STATUS_MUTEX_CEILING_VIOLATED;
0199   }
0200 
0201   _Thread_Wait_release_default_critical( thread, &lock_context );
0202   return status;
0203 }
0204 
0205 /**
0206  * @brief Removes the priority from the given thread.
0207  *
0208  * @param[in, out] The thread to remove the priority from.
0209  * @param priority_node The priority node to remove from the thread
0210  * @param queue_context The thread queue context.
0211  */
0212 static inline void _MRSP_Remove_priority(
0213   Thread_Control       *thread,
0214   Priority_Node        *priority_node,
0215   Thread_queue_Context *queue_context
0216 )
0217 {
0218   ISR_lock_Context lock_context;
0219 
0220   _Thread_queue_Context_clear_priority_updates( queue_context );
0221   _Thread_Wait_acquire_default_critical( thread, &lock_context );
0222   _Thread_Priority_remove( thread, priority_node, queue_context );
0223   _Thread_Wait_release_default_critical( thread, &lock_context );
0224 }
0225 
0226 /**
0227  * @brief Replaces the given priority node with the ceiling priority of
0228  *      the MrsP control.
0229  *
0230  * @param mrsp The mrsp control for the operation.
0231  * @param[out] thread The thread to replace the priorities.
0232  * @param ceiling_priority The node to be replaced.
0233  */
0234 static inline void _MRSP_Replace_priority(
0235   MRSP_Control   *mrsp,
0236   Thread_Control *thread,
0237   Priority_Node  *ceiling_priority
0238 )
0239 {
0240   ISR_lock_Context lock_context;
0241 
0242   _Thread_Wait_acquire_default( thread, &lock_context );
0243   _Thread_Priority_replace( 
0244     thread,
0245     ceiling_priority,
0246     &mrsp->Ceiling_priority
0247   );
0248   _Thread_Wait_release_default( thread, &lock_context );
0249 }
0250 
0251 /**
0252  * @brief Claims ownership of the MrsP control.
0253  *
0254  * @param mrsp The MrsP control to claim the ownership of.
0255  * @param[in, out] executing The currently executing thread.
0256  * @param queue_context The thread queue context.
0257  *
0258  * @retval STATUS_SUCCESSFUL The operation succeeded.
0259  * @retval STATUS_MUTEX_CEILING_VIOLATED The wait priority of the executing
0260  *      thread exceeds the ceiling priority.
0261  */
0262 static inline Status_Control _MRSP_Claim_ownership(
0263   MRSP_Control         *mrsp,
0264   Thread_Control       *executing,
0265   Thread_queue_Context *queue_context
0266 )
0267 {
0268   Status_Control   status;
0269   Per_CPU_Control *cpu_self;
0270 
0271   status = _MRSP_Raise_priority(
0272     mrsp,
0273     executing,
0274     &mrsp->Ceiling_priority,
0275     queue_context
0276   );
0277 
0278   if ( status != STATUS_SUCCESSFUL ) {
0279     _MRSP_Release( mrsp, queue_context );
0280     return status;
0281   }
0282 
0283   _MRSP_Set_owner( mrsp, executing );
0284   cpu_self = _Thread_queue_Dispatch_disable( queue_context );
0285   _MRSP_Release( mrsp, queue_context );
0286   _Thread_Priority_update_and_make_sticky( executing );
0287   _Thread_Dispatch_enable( cpu_self );
0288   return STATUS_SUCCESSFUL;
0289 }
0290 
0291 /**
0292  * @brief Initializes a MrsP control.
0293  *
0294  * @param[out] mrsp The MrsP control that is initialized.
0295  * @param scheduler The scheduler for the operation.
0296  * @param ceiling_priority
0297  * @param executing The currently executing thread.  Ignored in this method.
0298  * @param initially_locked Indicates whether the MrsP control shall be initally
0299  *      locked. If it is initially locked, this method returns STATUS_INVALID_NUMBER.
0300  *
0301  * @retval STATUS_SUCCESSFUL The operation succeeded.
0302  * @retval STATUS_INVALID_NUMBER The MrsP control is initially locked.
0303  * @retval STATUS_NO_MEMORY There is not enough memory to allocate.
0304  */
0305 static inline Status_Control _MRSP_Initialize(
0306   MRSP_Control            *mrsp,
0307   const Scheduler_Control *scheduler,
0308   Priority_Control         ceiling_priority,
0309   Thread_Control          *executing,
0310   bool                     initially_locked
0311 )
0312 {
0313   Thread_queue_Context queue_context;
0314   ISR_Level            level;
0315   size_t               scheduler_count;
0316   size_t               i;
0317   Status_Control       status;
0318 
0319   scheduler_count = _Scheduler_Count;
0320 
0321   for ( i = 0 ; i < scheduler_count ; ++i ) {
0322     const Scheduler_Control *scheduler_of_index;
0323 
0324     scheduler_of_index = &_Scheduler_Table[ i ];
0325 
0326     if ( scheduler != scheduler_of_index ) {
0327       mrsp->ceiling_priorities[ i ] =
0328         _Scheduler_Map_priority( scheduler_of_index, 0 );
0329     } else {
0330       mrsp->ceiling_priorities[ i ] = ceiling_priority;
0331     }
0332   }
0333 
0334   _Thread_queue_Object_initialize( &mrsp->Wait_queue );
0335 
0336   if ( !initially_locked ) {
0337     return STATUS_SUCCESSFUL;
0338   }
0339 
0340   _Thread_queue_Context_initialize( &queue_context );
0341   _Thread_queue_Context_ISR_disable( &queue_context, level );
0342   _Thread_queue_Context_set_ISR_level( &queue_context, level );
0343   _MRSP_Acquire_critical( mrsp, &queue_context );
0344   status = _MRSP_Claim_ownership( mrsp, executing, &queue_context );
0345 
0346   if ( status != STATUS_SUCCESSFUL ) {
0347     _Thread_queue_Destroy( &mrsp->Wait_queue );
0348   }
0349 
0350   return status;
0351 }
0352 
0353 /**
0354  * @brief Waits for the ownership of the MrsP control.
0355  *
0356  * @param[in, out] mrsp The MrsP control to get the ownership of.
0357  * @param[in, out] executing The currently executing thread.
0358  * @param queue_context the thread queue context.
0359  *
0360  * @retval STATUS_SUCCESSFUL The operation succeeded.
0361  * @retval STATUS_MUTEX_CEILING_VIOLATED The wait priority of the
0362  *      currently executing thread exceeds the ceiling priority.
0363  * @retval STATUS_DEADLOCK A deadlock occurred.
0364  * @retval STATUS_TIMEOUT A timeout occurred.
0365  */
0366 static inline Status_Control _MRSP_Wait_for_ownership(
0367   MRSP_Control         *mrsp,
0368   Thread_Control       *executing,
0369   Thread_queue_Context *queue_context
0370 )
0371 {
0372   Status_Control status;
0373   Priority_Node  ceiling_priority;
0374 
0375   status = _MRSP_Raise_priority(
0376     mrsp,
0377     executing,
0378     &ceiling_priority,
0379     queue_context
0380   );
0381 
0382   if ( status != STATUS_SUCCESSFUL ) {
0383     _MRSP_Release( mrsp, queue_context );
0384     return status;
0385   }
0386 
0387   _Thread_queue_Context_set_deadlock_callout(
0388     queue_context,
0389     _Thread_queue_Deadlock_status
0390   );
0391   status = _Thread_queue_Enqueue_sticky(
0392     &mrsp->Wait_queue.Queue,
0393     MRSP_TQ_OPERATIONS,
0394     executing,
0395     queue_context
0396   );
0397 
0398   if ( status == STATUS_SUCCESSFUL ) {
0399     _MRSP_Replace_priority( mrsp, executing, &ceiling_priority );
0400   } else {
0401     Per_CPU_Control *cpu_self;
0402 
0403     _ISR_lock_ISR_disable( &queue_context->Lock_context.Lock_context );
0404     _MRSP_Remove_priority( executing, &ceiling_priority, queue_context );
0405     cpu_self = _Thread_Dispatch_disable_critical(
0406       &queue_context->Lock_context.Lock_context
0407     );
0408     _ISR_lock_ISR_enable( &queue_context->Lock_context.Lock_context );
0409 
0410     if ( status != STATUS_DEADLOCK ) {
0411       _Thread_Priority_update_and_clean_sticky( executing );
0412     } else {
0413       _Thread_Priority_update_ignore_sticky( executing );
0414     }
0415 
0416     _Thread_Dispatch_enable( cpu_self );
0417   }
0418 
0419   return status;
0420 }
0421 
0422 /**
0423  * @brief Seizes the MrsP mutex.
0424  *
0425  * @param[in, out] mrsp is the MrsP mutex to seize.
0426  *
0427  * @param[in, out] executing is the currently executing thread.
0428  *
0429  * @param wait shall be true, if the executing thread is willing to wait,
0430  *   otherwise it shall be false.
0431  *
0432  * @param[in, out] queue_context is the thread queue context.
0433  *
0434  * @retval STATUS_SUCCESSFUL The requested operation was successful.
0435  *
0436  * @retval STATUS_UNAVAILABLE Seizing the mutex was not immmediately possible.
0437  *
0438  * @retval STATUS_DEADLOCK The executing thread was already the owner of
0439  *   the mutex.
0440  *
0441  * @retval STATUS_MUTEX_CEILING_VIOLATED The current priority of the executing
0442  *   thread exceeds the ceiling priority of the mutex.
0443  */
0444 static inline Status_Control _MRSP_Seize(
0445   MRSP_Control         *mrsp,
0446   Thread_Control       *executing,
0447   bool                  wait,
0448   Thread_queue_Context *queue_context
0449 )
0450 {
0451   Status_Control  status;
0452   Thread_Control *owner;
0453 
0454   _MRSP_Acquire_critical( mrsp, queue_context );
0455 
0456   owner = _MRSP_Get_owner( mrsp );
0457 
0458   if ( owner == NULL ) {
0459     status = _MRSP_Claim_ownership( mrsp, executing, queue_context );
0460   } else if ( owner == executing ) {
0461     _MRSP_Release( mrsp, queue_context );
0462     status = STATUS_DEADLOCK;
0463   } else if ( wait ) {
0464     status = _MRSP_Wait_for_ownership( mrsp, executing, queue_context );
0465   } else {
0466     _MRSP_Release( mrsp, queue_context );
0467     status = STATUS_UNAVAILABLE;
0468   }
0469 
0470   return status;
0471 }
0472 
0473 /**
0474  * @brief Surrenders the MrsP control.
0475  *
0476  * @param[in, out] mrsp The MrsP control to surrender the control of.
0477  * @param[in, out] executing The currently executing thread.
0478  * @param queue_context The thread queue context.
0479  *
0480  * @retval STATUS_SUCCESSFUL The operation succeeded.
0481  * @retval STATUS_NOT_OWNER The executing thread does not own the MrsP control.
0482  */
0483 static inline Status_Control _MRSP_Surrender(
0484   MRSP_Control         *mrsp,
0485   Thread_Control       *executing,
0486   Thread_queue_Context *queue_context
0487 )
0488 {
0489   Thread_queue_Heads *heads;
0490 
0491   if ( _MRSP_Get_owner( mrsp ) != executing ) {
0492     _ISR_lock_ISR_enable( &queue_context->Lock_context.Lock_context );
0493     return STATUS_NOT_OWNER;
0494   }
0495 
0496   _MRSP_Acquire_critical( mrsp, queue_context );
0497 
0498   _MRSP_Set_owner( mrsp, NULL );
0499   _MRSP_Remove_priority( executing, &mrsp->Ceiling_priority, queue_context );
0500 
0501   heads = mrsp->Wait_queue.Queue.heads;
0502 
0503   if ( heads == NULL ) {
0504     Per_CPU_Control *cpu_self;
0505 
0506     cpu_self = _Thread_Dispatch_disable_critical(
0507       &queue_context->Lock_context.Lock_context
0508     );
0509     _MRSP_Release( mrsp, queue_context );
0510     _Thread_Priority_update_and_clean_sticky( executing );
0511     _Thread_Dispatch_enable( cpu_self );
0512     return STATUS_SUCCESSFUL;
0513   }
0514 
0515   _Thread_queue_Surrender_sticky(
0516     &mrsp->Wait_queue.Queue,
0517     heads,
0518     executing,
0519     queue_context,
0520     MRSP_TQ_OPERATIONS
0521   );
0522   return STATUS_SUCCESSFUL;
0523 }
0524 
0525 /**
0526  * @brief Checks if the MrsP control can be destroyed.
0527  *
0528  * @param mrsp The MrsP control for the operation.
0529  *
0530  * @retval STATUS_SUCCESSFUL The MrsP is currently not used
0531  *      and can be destroyed.
0532  * @retval STATUS_RESOURCE_IN_USE The MrsP control is in use,
0533  *      it cannot be destroyed.
0534  */
0535 static inline Status_Control _MRSP_Can_destroy( MRSP_Control *mrsp )
0536 {
0537   if ( _MRSP_Get_owner( mrsp ) != NULL ) {
0538     return STATUS_RESOURCE_IN_USE;
0539   }
0540 
0541   return STATUS_SUCCESSFUL;
0542 }
0543 
0544 /**
0545  * @brief Destroys the MrsP control
0546  *
0547  * @param[in, out] The mrsp that is about to be destroyed.
0548  * @param queue_context The thread queue context.
0549  */
0550 static inline void _MRSP_Destroy(
0551   MRSP_Control         *mrsp,
0552   Thread_queue_Context *queue_context
0553 )
0554 {
0555   _MRSP_Release( mrsp, queue_context );
0556   _Thread_queue_Destroy( &mrsp->Wait_queue );
0557 }
0558 
0559 /** @} */
0560 
0561 #ifdef __cplusplus
0562 }
0563 #endif /* __cplusplus */
0564 
0565 #endif /* RTEMS_SMP */
0566 
0567 #endif /* _RTEMS_SCORE_MRSPIMPL_H */