summaryrefslogblamecommitdiffstats
path: root/cpukit/include/rtems/score/coremuteximpl.h
blob: e04a91c563970e5b5b64ba363136698101980676 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14


        
                           









                                                           
                                         





                                    
                                  
                                      
                               
                                   
                                    





                  
                              

     
   
 

                                                                   


                                                   




                                                 



                                                 
                                                            
 
 




                                              




                                                                              





                                                           
                                                       

                                     

 
                                                                          

 





                                                  
                                              

                                     

 
                                                                 

 






                                                    



                                                           
                                           

 
   
                                        
  
                                                                       

             
                                                       







                                                
                                                    

 











                                                                        
                                      



                                            


                                              





                                                         




                                                
                                            

 








                                                                            




                                               
                                                          

 




                                                           



                                                           
                                              


                            






                                                               







                                                                       














                                                                        

                                                                
                                            

                                           











                                                                            
                                                  













                                                            
               
              
         



                 










                                                                           
                                                                    



                                              



                                 















                                                                   
                                                

                                                   
                                                  
 
                        



                                                            

                                       
          
              
                  

              


                           







                                                                          

                                                         
                                        



                                                            
                                                                              




                                   






                                                                                                                        







                                              
                                


      






                                                                  

                                                           

                                               

 
















                                                               

 






                                                       



                                                                       
                                              

 










                                                                             





                                                                  
                                 
                                   

                             
                                                                
 
                                                            

      
                                                            


                                                                  




                                                                      
                                            





                                                                
 
                                                             
                                                                    
                                           



                                      














                                                                                                                  



                                                              










                                                                             

                      
                                             






                                                                        
                                                                  














                                                                      
                                



                                



                 









                                                                                  





                                                                  



                                 















                                                                             
                                                
 








                                                                    





                                                                  


                                               
 
                            



                                                       
                                                    




                                     

     
                                   
                                                   
                               
                
                   




                                                                      

                                           


                           







                         
/**
 * @file
 *
 * @ingroup RTEMSScoreMutex
 *
 * @brief CORE Mutex Implementation
 */

/*
 *  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_COREMUTEXIMPL_H
#define _RTEMS_SCORE_COREMUTEXIMPL_H

#include <rtems/score/coremutex.h>
#include <rtems/score/chainimpl.h>
#include <rtems/score/schedulerimpl.h>
#include <rtems/score/status.h>
#include <rtems/score/threadimpl.h>
#include <rtems/score/threadqimpl.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @addtogroup RTEMSScoreMutex
 *
 * @{
 */

#define CORE_MUTEX_TQ_OPERATIONS &_Thread_queue_Operations_priority

#define CORE_MUTEX_TQ_PRIORITY_INHERIT_OPERATIONS \
  &_Thread_queue_Operations_priority_inherit

/**
 * @brief Initializes the mutex.
 *
 * @param[out] the_mutex The mutex to initialize.
 */
RTEMS_INLINE_ROUTINE void _CORE_mutex_Initialize(
  CORE_mutex_Control *the_mutex
)
{
  _Thread_queue_Object_initialize( &the_mutex->Wait_queue );
}

/**
 * @brief Destroys the mutex.
 *
 * @param[out] the_mutex the mutex to destroy.
 */
RTEMS_INLINE_ROUTINE void _CORE_mutex_Destroy( CORE_mutex_Control *the_mutex )
{
  _Thread_queue_Destroy( &the_mutex->Wait_queue );
}

/**
 * @brief Acquires the mutex critical.
 *
 * @param[in, out] the_mutex The mutex to acquire critical.
 * @param queue_context The queue context.
 */
RTEMS_INLINE_ROUTINE void _CORE_mutex_Acquire_critical(
  CORE_mutex_Control   *the_mutex,
  Thread_queue_Context *queue_context
)
{
  _Thread_queue_Acquire_critical( &the_mutex->Wait_queue, queue_context );
}

/**
 * @brief Releases the mutex.
 *
 * @param[in, out] the_mutex The mutex to release.
 * @param queue_context The queue context.
 */
RTEMS_INLINE_ROUTINE void _CORE_mutex_Release(
  CORE_mutex_Control   *the_mutex,
  Thread_queue_Context *queue_context
)
{
  _Thread_queue_Release( &the_mutex->Wait_queue, queue_context );
}

/**
 * @brief Gets the owner of the mutex.
 *
 * @param the_mutex The mutex to get the owner from.
 *
 * @return The owner of the mutex.
 */
RTEMS_INLINE_ROUTINE Thread_Control *_CORE_mutex_Get_owner(
  const CORE_mutex_Control *the_mutex
)
{
  return the_mutex->Wait_queue.Queue.owner;
}

/**
 * @brief Checks if the mutex is locked.
 *
 * This routine returns true if the specified mutex is locked and false
 * otherwise.
 *
 * @param the_mutex The mutex to check if it is locked.
 *
 * @retval true The mutex is locked.
 * @retval false The mutex is not locked.
 */
RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_locked(
  const CORE_mutex_Control *the_mutex
)
{
  return _CORE_mutex_Get_owner( the_mutex ) != NULL;
}

/**
 * @brief Seize the mutex slowly.
 *
 * @param[in, out] the_mutex The mutex to seize.
 * @param operations The thread queue operations.
 * @param executing The calling thread.
 * @param wait Indicates whether the calling thread is willing to wait.
 * @param queue_context The thread queue context.
 *
 * @retval _Thread_Wait_get_status The status of the executing thread.
 * @retval STATUS_UNAVAILABLE The calling thread is not willing to wait.
 */
Status_Control _CORE_mutex_Seize_slow(
  CORE_mutex_Control            *the_mutex,
  const Thread_queue_Operations *operations,
  Thread_Control                *executing,
  bool                           wait,
  Thread_queue_Context          *queue_context
);

/**
 * @brief Sets the owner of the mutex.
 *
 * @param[out] the_mutex The mutex to set the owner from.
 * @param owner The new owner of the mutex.
 */
RTEMS_INLINE_ROUTINE void _CORE_mutex_Set_owner(
  CORE_mutex_Control *the_mutex,
  Thread_Control     *owner
)
{
  the_mutex->Wait_queue.Queue.owner = owner;
}

/**
 * @brief Checks if the the thread is the owner of the mutex.
 *
 * @param the_mutex The mutex to check the owner of.
 * @param the_thread The thread to check if it is the owner of @a the_mutex.
 *
 * @retval true @a the_thread is the owner of @a the_mutex.
 * @retval false @a the_thread is not the owner of @a the_mutex.
 */
RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_owner(
  const CORE_mutex_Control *the_mutex,
  const Thread_Control     *the_thread
)
{
  return _CORE_mutex_Get_owner( the_mutex ) == the_thread;
}

/**
 * @brief Initializes a recursive mutex.
 *
 * @param[out] the_mutex The recursive mutex to initialize.
 */
RTEMS_INLINE_ROUTINE void _CORE_recursive_mutex_Initialize(
  CORE_recursive_mutex_Control *the_mutex
)
{
  _CORE_mutex_Initialize( &the_mutex->Mutex );
  the_mutex->nest_level = 0;
}

/**
 * @brief Seizes the recursive mutex nested.
 *
 * @param[out] the_mutex The recursive mutex to seize nested.
 *
 * @return STATUS_SUCCESSFUL, this method is always successful.
 */
RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Seize_nested(
  CORE_recursive_mutex_Control *the_mutex
)
{
  ++the_mutex->nest_level;
  return STATUS_SUCCESSFUL;
}

/**
 * @brief Seizes the recursive mutex.
 *
 * @param[in, out] the_mutex The recursive mutex to seize.
 * @param operations The thread queue operations.
 * @param[out] executing The executing thread.
 * @param wait Indicates whether the calling thread is willing to wait.
 * @param nested Returns the status of a recursive mutex.
 * @param queue_context The thread queue context.
 *
 * @retval STATUS_SUCCESSFUL The owner of the mutex was NULL, successful
 *      seizing of the mutex.
 * @retval _Thread_Wait_get_status The status of the executing thread.
 * @retval STATUS_UNAVAILABLE The calling thread is not willing to wait.
 */
RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Seize(
  CORE_recursive_mutex_Control  *the_mutex,
  const Thread_queue_Operations *operations,
  Thread_Control                *executing,
  bool                           wait,
  Status_Control              ( *nested )( CORE_recursive_mutex_Control * ),
  Thread_queue_Context          *queue_context
)
{
  Thread_Control *owner;

  _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context );

  owner = _CORE_mutex_Get_owner( &the_mutex->Mutex );

  if ( owner == NULL ) {
    _CORE_mutex_Set_owner( &the_mutex->Mutex, executing );
    _Thread_Resource_count_increment( executing );
    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
    return STATUS_SUCCESSFUL;
  }

  if ( owner == executing ) {
    Status_Control status;

    status = ( *nested )( the_mutex );
    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
    return status;
  }

  return _CORE_mutex_Seize_slow(
    &the_mutex->Mutex,
    operations,
    executing,
    wait,
    queue_context
  );
}

/**
 * @brief Surrenders the recursive mutex.
 *
 * @param[in, out] the_mutex The recursive mutex to surrender.
 * @param operations The thread queue operations.
 * @param executing The executing thread.
 * @param queue_context the thread queue context.
 *
 * @retval STATUS_SUCCESSFUL @a the_mutex is successfully surrendered.
 * @retval STATUS_NOT_OWNER The executing thread does not own @a the_mutex.
 */
RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Surrender(
  CORE_recursive_mutex_Control  *the_mutex,
  const Thread_queue_Operations *operations,
  Thread_Control                *executing,
  Thread_queue_Context          *queue_context
)
{
  unsigned int        nest_level;
  Thread_queue_Heads *heads;

  _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context );

  if ( !_CORE_mutex_Is_owner( &the_mutex->Mutex, executing ) ) {
    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
    return STATUS_NOT_OWNER;
  }

  nest_level = the_mutex->nest_level;

  if ( nest_level > 0 ) {
    the_mutex->nest_level = nest_level - 1;
    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
    return STATUS_SUCCESSFUL;
  }

  _Thread_Resource_count_decrement( executing );
  _CORE_mutex_Set_owner( &the_mutex->Mutex, NULL );

  heads = the_mutex->Mutex.Wait_queue.Queue.heads;

  if ( heads == NULL ) {
    _CORE_mutex_Release( &the_mutex->Mutex, queue_context );
    return STATUS_SUCCESSFUL;
  }

  _Thread_queue_Surrender(
    &the_mutex->Mutex.Wait_queue.Queue,
    heads,
    executing,
    queue_context,
    operations
  );
  return STATUS_SUCCESSFUL;
}

/**
 * @brief initializes a ceiling mutex.
 *
 * @param[out] the_mutex The ceiling mutex to initialize.
 * @param scheduler The scheduler for the new ceiling mutex.
 *      Only needed if RTEMS_SMP is defined
 * @param priority_ceiling The priority ceiling for the initialized mutex.
 */
RTEMS_INLINE_ROUTINE void _CORE_ceiling_mutex_Initialize(
  CORE_ceiling_mutex_Control *the_mutex,
  const Scheduler_Control    *scheduler,
  Priority_Control            priority_ceiling
)
{
  _CORE_recursive_mutex_Initialize( &the_mutex->Recursive );
  _Priority_Node_initialize( &the_mutex->Priority_ceiling, priority_ceiling );
#if defined(RTEMS_SMP)
  the_mutex->scheduler = scheduler;
#endif
}

/**
 * @brief Gets the scheduler of the ceiling mutex.
 *
 * @param the_mutex The ceiling mutex to get the scheduler from.
 *
 * @return The scheduler of the mutex. If RTEMS_SMP is not defined, the first entry of the _Scheduler_Table is returned.
 */
RTEMS_INLINE_ROUTINE const Scheduler_Control *
_CORE_ceiling_mutex_Get_scheduler(
  const CORE_ceiling_mutex_Control *the_mutex
)
{
#if defined(RTEMS_SMP)
  return the_mutex->scheduler;
#else
  return &_Scheduler_Table[ 0 ];
#endif
}

/**
 * @brief Sets the priority of the ceiling mutex.
 *
 * @param[out] the_mutex The ceiling mutex to set the priority of.
 * @param priority_ceiling The new priority ceiling of the mutex.
 * @param queue_context The thread queue context.
 */
RTEMS_INLINE_ROUTINE void _CORE_ceiling_mutex_Set_priority(
  CORE_ceiling_mutex_Control *the_mutex,
  Priority_Control            priority_ceiling,
  Thread_queue_Context       *queue_context
)
{
  Thread_Control *owner;

  owner = _CORE_mutex_Get_owner( &the_mutex->Recursive.Mutex );

  if ( owner != NULL ) {
    _Thread_Wait_acquire( owner, queue_context );
    _Thread_Priority_change(
      owner,
      &the_mutex->Priority_ceiling,
      priority_ceiling,
      false,
      queue_context
    );
    _Thread_Wait_release( owner, queue_context );
  } else {
    the_mutex->Priority_ceiling.priority = priority_ceiling;
  }
}

/**
 * @brief Gets the priority of the ceiling mutex.
 *
 * @param the_mutex The mutex to get the priority from.
 *
 * @return The priority ceiling of @a the_mutex.
 */
RTEMS_INLINE_ROUTINE Priority_Control _CORE_ceiling_mutex_Get_priority(
  const CORE_ceiling_mutex_Control *the_mutex
)
{
  return the_mutex->Priority_ceiling.priority;
}

/**
 * @brief Sets the owner of the ceiling mutex.
 *
 * @param[in, out] the_mutex The mutex to set the owner of.
 * @param owner The new owner of @a the_mutex.
 * @param queue_context The thread queue context.
 *
 * @retval STATUS_SUCCESSFUL The owner of the mutex was changed successfully.
 * @retval STATUS_MUTEX_CEILING_VIOLATED The owners wait priority
 *          is smaller than the priority of the ceiling mutex.
 */
RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Set_owner(
  CORE_ceiling_mutex_Control *the_mutex,
  Thread_Control             *owner,
  Thread_queue_Context       *queue_context
)
{
  ISR_lock_Context  lock_context;
  Scheduler_Node   *scheduler_node;
  Per_CPU_Control  *cpu_self;

  _Thread_Wait_acquire_default_critical( owner, &lock_context );

  scheduler_node = _Thread_Scheduler_get_home_node( owner );

  if (
    _Priority_Get_priority( &scheduler_node->Wait.Priority )
      < the_mutex->Priority_ceiling.priority
  ) {
    _Thread_Wait_release_default_critical( owner, &lock_context );
    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
    return STATUS_MUTEX_CEILING_VIOLATED;
  }

  _CORE_mutex_Set_owner( &the_mutex->Recursive.Mutex, owner );
  _Thread_Resource_count_increment( owner );
  _Thread_Priority_add(
    owner,
    &the_mutex->Priority_ceiling,
    queue_context
  );
  _Thread_Wait_release_default_critical( owner, &lock_context );

  cpu_self = _Thread_queue_Dispatch_disable( queue_context );
  _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
  _Thread_Priority_update( queue_context );
  _Thread_Dispatch_enable( cpu_self );
  return STATUS_SUCCESSFUL;
}

/**
 * @brief Seizes the ceiling mutex.
 *
 * @param[in, out] the_mutex The mutex to seize.
 * @param executing The executing thread.
 * @param wait Indicates whether the calling thread is willing to wait.
 * @param nested Function that returns the status of the recursive mutex
 * @param queue_context The thread queue context.
 *
 * @retval STATUS_SUCCESSFUL The owner of the mutex was changed successfully.
 * @retval STATUS_NOT_DEFINED If the scheduler of the executing thread is not equal to the owner of @a the_mutex .
 * @retval STATUS_MUTEX_CEILING_VIOLATED The owners wait priority
 *          is smaller than the priority of the ceiling mutex.
 * @retval other Return value of @a nested.
 */
RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Seize(
  CORE_ceiling_mutex_Control    *the_mutex,
  Thread_Control                *executing,
  bool                           wait,
  Status_Control              ( *nested )( CORE_recursive_mutex_Control * ),
  Thread_queue_Context          *queue_context
)
{
  Thread_Control *owner;

  _CORE_mutex_Acquire_critical( &the_mutex->Recursive.Mutex, queue_context );

  owner = _CORE_mutex_Get_owner( &the_mutex->Recursive.Mutex );

  if ( owner == NULL ) {
#if defined(RTEMS_SMP)
    if (
      _Thread_Scheduler_get_home( executing )
        != _CORE_ceiling_mutex_Get_scheduler( the_mutex )
    ) {
      _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
      return STATUS_NOT_DEFINED;
    }
#endif

    _Thread_queue_Context_clear_priority_updates( queue_context );
    return _CORE_ceiling_mutex_Set_owner(
      the_mutex,
      executing,
      queue_context
    );
  }

  if ( owner == executing ) {
    Status_Control status;

    status = ( *nested )( &the_mutex->Recursive );
    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
    return status;
  }

  return _CORE_mutex_Seize_slow(
    &the_mutex->Recursive.Mutex,
    CORE_MUTEX_TQ_OPERATIONS,
    executing,
    wait,
    queue_context
  );
}

/**
 * @brief Surrenders the ceiling mutex.
 *
 * @param[in, out] the_mutex The ceiling mutex to surrender.
 * @param executing The executing thread.
 * @param queue_context The thread queue context.
 *
 * @retval STATUS_SUCCESSFUL The ceiling mutex was successfullysurrendered.
 * @retval STATUS_NOT_OWNER The executing thread is not the owner of @a the_mutex.
 */
RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Surrender(
  CORE_ceiling_mutex_Control *the_mutex,
  Thread_Control             *executing,
  Thread_queue_Context       *queue_context
)
{
  unsigned int      nest_level;
  ISR_lock_Context  lock_context;
  Per_CPU_Control  *cpu_self;
  Thread_Control   *new_owner;

  _CORE_mutex_Acquire_critical( &the_mutex->Recursive.Mutex, queue_context );

  if ( !_CORE_mutex_Is_owner( &the_mutex->Recursive.Mutex, executing ) ) {
    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
    return STATUS_NOT_OWNER;
  }

  nest_level = the_mutex->Recursive.nest_level;

  if ( nest_level > 0 ) {
    the_mutex->Recursive.nest_level = nest_level - 1;
    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
    return STATUS_SUCCESSFUL;
  }

  _Thread_Resource_count_decrement( executing );

  _Thread_queue_Context_clear_priority_updates( queue_context );
  _Thread_Wait_acquire_default_critical( executing, &lock_context );
  _Thread_Priority_remove(
    executing,
    &the_mutex->Priority_ceiling,
    queue_context
  );
  _Thread_Wait_release_default_critical( executing, &lock_context );

  new_owner = _Thread_queue_First_locked(
    &the_mutex->Recursive.Mutex.Wait_queue,
    CORE_MUTEX_TQ_OPERATIONS
  );
  _CORE_mutex_Set_owner( &the_mutex->Recursive.Mutex, new_owner );

  cpu_self = _Thread_Dispatch_disable_critical(
    &queue_context->Lock_context.Lock_context
  );

  if ( new_owner != NULL ) {
#if defined(RTEMS_MULTIPROCESSING)
    if ( _Objects_Is_local_id( new_owner->Object.id ) )
#endif
    {
      _Thread_Resource_count_increment( new_owner );
      _Thread_Priority_add(
        new_owner,
        &the_mutex->Priority_ceiling,
        queue_context
      );
    }

    _Thread_queue_Extract_critical(
      &the_mutex->Recursive.Mutex.Wait_queue.Queue,
      CORE_MUTEX_TQ_OPERATIONS,
      new_owner,
      queue_context
    );
  } else {
    _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
  }

  _Thread_Priority_update( queue_context );
  _Thread_Dispatch_enable( cpu_self );
  return STATUS_SUCCESSFUL;
}

/** @} */

#ifdef __cplusplus
}
#endif

#endif
/* end of include file */