Changeset 1fcac5a in rtems


Ignore:
Timestamp:
Jul 25, 2016, 2:35:37 PM (3 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
master
Children:
d79df38
Parents:
3a58dc8
git-author:
Sebastian Huber <sebastian.huber@…> (07/25/16 14:35:37)
git-committer:
Sebastian Huber <sebastian.huber@…> (07/27/16 08:55:30)
Message:

score: Turn thread lock into thread wait lock

The _Thread_Lock_acquire() function had a potentially infinite run-time
due to the lack of fairness at atomic operations level.

Update #2412.
Update #2556.
Update #2765.

Files:
20 edited

Legend:

Unmodified
Added
Removed
  • cpukit/libmisc/monitor/mon-task.c

    r3a58dc8 r1fcac5a  
    2121)
    2222{
    23     ISR_lock_Context  lock_context;
    24     void             *lock;
     23    Thread_queue_Context queue_context;
    2524
    26     lock = _Thread_Lock_acquire( rtems_thread, &lock_context );
     25    _Thread_Wait_acquire( rtems_thread, &queue_context );
    2726
    2827    canonical_task->state = rtems_thread->current_state;
     
    3130    canonical_task->wait_operations = rtems_thread->Wait.operations;
    3231
    33     _Thread_Lock_release( lock, &lock_context );
     32    _Thread_Wait_release( rtems_thread, &queue_context );
    3433}
    3534
  • cpukit/posix/src/pthreadgetschedparam.c

    r3a58dc8 r1fcac5a  
    3737{
    3838  Thread_Control          *the_thread;
    39   ISR_lock_Context         lock_context;
     39  Thread_queue_Context     queue_context;
    4040  POSIX_API_Control       *api;
    4141  const Scheduler_Control *scheduler;
     
    4646  }
    4747
    48   the_thread = _Thread_Get( thread, &lock_context );
     48  the_thread = _Thread_Get( thread, &queue_context.Lock_context );
    4949
    5050  if ( the_thread == NULL ) {
     
    5454  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
    5555
    56   _Thread_Lock_acquire_default_critical( the_thread, &lock_context );
     56  _Thread_Wait_acquire_critical( the_thread, &queue_context );
    5757
    5858  *policy = api->Attributes.schedpolicy;
     
    6262  priority = the_thread->real_priority;
    6363
    64   _Thread_Lock_release_default( the_thread, &lock_context );
     64  _Thread_Wait_release( the_thread, &queue_context );
    6565
    6666  param->sched_priority = _POSIX_Priority_From_core( scheduler, priority );
  • cpukit/rtems/include/rtems/rtems/ratemonimpl.h

    r3a58dc8 r1fcac5a  
    7474)
    7575{
    76   _Thread_Lock_acquire_default_critical( the_thread, lock_context );
     76  _Thread_Wait_acquire_default_critical( the_thread, lock_context );
    7777}
    7878
     
    8282)
    8383{
    84   _Thread_Lock_release_default( the_thread, lock_context );
     84  _Thread_Wait_release_default( the_thread, lock_context );
    8585}
    8686
  • cpukit/rtems/src/eventreceive.c

    r3a58dc8 r1fcac5a  
    3939    Event_Control     *event;
    4040
    41     executing = _Thread_Lock_acquire_default_for_executing( &lock_context );
     41    executing = _Thread_Wait_acquire_default_for_executing( &lock_context );
    4242    api = executing->API_Extensions[ THREAD_API_RTEMS ];
    4343    event = &api->Event;
     
    5757    } else {
    5858      *event_out = event->pending_events;
    59       _Thread_Lock_release_default( executing, &lock_context );
     59      _Thread_Wait_release_default( executing, &lock_context );
    6060      sc = RTEMS_SUCCESSFUL;
    6161    }
  • cpukit/rtems/src/eventseize.c

    r3a58dc8 r1fcac5a  
    5151    event->pending_events =
    5252      _Event_sets_Clear( pending_events, seized_events );
    53     _Thread_Lock_release_default( executing, lock_context );
     53    _Thread_Wait_release_default( executing, lock_context );
    5454    *event_out = seized_events;
    5555    return RTEMS_SUCCESSFUL;
     
    5757
    5858  if ( _Options_Is_no_wait( option_set ) ) {
    59     _Thread_Lock_release_default( executing, lock_context );
     59    _Thread_Wait_release_default( executing, lock_context );
    6060    *event_out = seized_events;
    6161    return RTEMS_UNSATISFIED;
     
    7979
    8080  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
    81   _Thread_Lock_release_default( executing, lock_context );
     81  _Thread_Wait_release_default( executing, lock_context );
    8282
    8383  if ( ticks ) {
  • cpukit/rtems/src/eventsurrender.c

    r3a58dc8 r1fcac5a  
    7878  bool            unblock;
    7979
    80   _Thread_Lock_acquire_default_critical( the_thread, lock_context );
     80  _Thread_Wait_acquire_default_critical( the_thread, lock_context );
    8181
    8282  _Event_sets_Post( event_in, &event->pending_events );
     
    117117
    118118    cpu_self = _Thread_Dispatch_disable_critical( lock_context );
    119     _Thread_Lock_release_default( the_thread, lock_context );
     119    _Thread_Wait_release_default( the_thread, lock_context );
    120120
    121121    _Thread_Timer_remove( the_thread );
     
    124124    _Thread_Dispatch_enable( cpu_self );
    125125  } else {
    126     _Thread_Lock_release_default( the_thread, lock_context );
     126    _Thread_Wait_release_default( the_thread, lock_context );
    127127  }
    128128
  • cpukit/rtems/src/systemeventreceive.c

    r3a58dc8 r1fcac5a  
    4545    Event_Control     *event;
    4646
    47     executing = _Thread_Lock_acquire_default_for_executing( &lock_context );
     47    executing = _Thread_Wait_acquire_default_for_executing( &lock_context );
    4848    api = executing->API_Extensions[ THREAD_API_RTEMS ];
    4949    event = &api->System_event;
     
    6363    } else {
    6464      *event_out = event->pending_events;
    65       _Thread_Lock_release_default( executing, &lock_context );
     65      _Thread_Wait_release_default( executing, &lock_context );
    6666      sc = RTEMS_SUCCESSFUL;
    6767    }
  • cpukit/rtems/src/tasksetscheduler.c

    r3a58dc8 r1fcac5a  
    2929  const Scheduler_Control *scheduler;
    3030  Thread_Control          *the_thread;
    31   ISR_lock_Context         lock_context;
    32   ISR_lock_Context         state_lock_context;
     31  Thread_queue_Context     queue_context;
     32  ISR_lock_Context         state_context;
    3333  Per_CPU_Control         *cpu_self;
    34   void                    *lock;
    3534  bool                     valid;
    3635  Priority_Control         core_priority;
     
    4645  }
    4746
    48   the_thread = _Thread_Get( task_id, &lock_context );
     47  the_thread = _Thread_Get( task_id, &queue_context.Lock_context );
    4948
    5049  if ( the_thread == NULL ) {
     
    5857  }
    5958
    60   cpu_self = _Thread_Dispatch_disable_critical( &lock_context );
    61   _ISR_lock_ISR_enable( &lock_context );
     59  cpu_self = _Thread_Dispatch_disable_critical( &queue_context.Lock_context );
    6260
    63   lock = _Thread_Lock_acquire( the_thread, &lock_context );
    64   _Thread_State_acquire_critical( the_thread, &state_lock_context );
     61  _Thread_Wait_acquire_critical( the_thread, &queue_context );
     62  _Thread_State_acquire_critical( the_thread, &state_context );
    6563
    6664  status = _Scheduler_Set( scheduler, the_thread, core_priority );
    6765
    68   _Thread_State_release_critical( the_thread, &state_lock_context );
    69   _Thread_Lock_release( lock, &lock_context );
     66  _Thread_State_release_critical( the_thread, &state_context );
     67  _Thread_Wait_release( the_thread, &queue_context );
    7068  _Thread_Dispatch_enable( cpu_self );
    7169  return _Status_Get( status );
  • cpukit/score/include/rtems/score/schedulerimpl.h

    r3a58dc8 r1fcac5a  
    824824  _SMP_sequence_lock_Write_end( &node->Priority.Lock, seq );
    825825#endif
     826}
     827
     828RTEMS_INLINE_ROUTINE void _Scheduler_Thread_set_priority(
     829  Thread_Control   *the_thread,
     830  Priority_Control  new_priority,
     831  bool              prepend_it
     832)
     833{
     834  Scheduler_Node *own_node;
     835
     836  own_node = _Scheduler_Thread_get_own_node( the_thread );
     837  _Scheduler_Node_set_priority( own_node, new_priority, prepend_it );
     838
     839  the_thread->current_priority = new_priority;
    826840}
    827841
  • cpukit/score/include/rtems/score/thread.h

    r3a58dc8 r1fcac5a  
    1212 *  On-Line Applications Research Corporation (OAR).
    1313 *
    14  *  Copyright (c) 2014 embedded brains GmbH.
     14 *  Copyright (c) 2014, 2016 embedded brains GmbH.
    1515 *
    1616 *  The license and distribution terms for this file may be
     
    289289
    290290  /**
    291    * @brief The current thread queue.
    292    *
    293    * In case this field is @c NULL, then the thread is not blocked on a thread
    294    * queue.  This field is protected by the thread lock.
    295    *
    296    * @see _Thread_Lock_set() and _Thread_Wait_set_queue().
    297    */
    298   Thread_queue_Queue *queue;
    299 
    300   /**
    301291   * @brief This field contains several flags used to control the wait class
    302292   * and state of a thread in case fine-grained locking is used.
     
    308298#endif
    309299
     300#if defined(RTEMS_SMP)
     301  /**
     302   * @brief Thread wait lock control block.
     303   *
     304   * Parts of the thread wait information are protected by the thread wait
     305   * default lock and additionally a thread queue lock in case the thread
     306   * is enqueued on a thread queue.
     307   *
     308   * The thread wait lock mechanism protects the following thread variables
     309   *  - POSIX_API_Control::Attributes,
     310   *  - Thread_Control::current_priority,
     311   *  - Thread_Control::Wait::Lock::Pending_requests,
     312   *  - Thread_Control::Wait::queue, and
     313   *  - Thread_Control::Wait::operations.
     314   *
     315   * @see _Thread_Wait_acquire(), _Thread_Wait_release(), _Thread_Wait_claim(),
     316   *   _Thread_Wait_restore_default() and _Thread_Wait_tranquilize().
     317   */
     318  struct {
     319    /**
     320     * @brief Thread wait default lock.
     321     */
     322    ISR_lock_Control Default;
     323
     324    /**
     325     * @brief The pending thread wait lock acquire or tranquilize requests in
     326     * case the thread is enqueued on a thread queue.
     327     */
     328    Chain_Control Pending_requests;
     329  } Lock;
     330#endif
     331
     332  /**
     333   * @brief The current thread queue.
     334   *
     335   * If this field is NULL the thread is not enqueued on a thread queue.  This
     336   * field is protected by the thread wait default lock.
     337   *
     338   * @see _Thread_Wait_claim().
     339   */
     340  Thread_queue_Queue *queue;
     341
    310342  /**
    311343   * @brief The current thread queue operations.
    312344   *
    313    * This field is protected by the thread lock.
    314    *
    315    * @see _Thread_Lock_set() and _Thread_Wait_set_operations().
     345   * This field is protected by the thread lock wait default lock.
     346   *
     347   * @see _Thread_Wait_claim().
    316348   */
    317349  const Thread_queue_Operations *operations;
     
    639671  void *        control;
    640672}Thread_Capture_control;
    641 
    642 #if defined(RTEMS_SMP)
    643 /**
    644  * @brief Thread lock control.
    645  *
    646  * The thread lock is either the default lock or the lock of the resource on
    647  * which the thread is currently blocked.  The generation number takes care
    648  * that the up to date lock is used.  Only resources using fine grained locking
    649  * provide their own lock.
    650  *
    651  * The thread lock protects the following thread variables
    652  *  - POSIX_API_Control::Attributes,
    653  *  - Thread_Control::current_priority,
    654  *  - Thread_Control::Wait::queue, and
    655  *  - Thread_Control::Wait::operations.
    656  *
    657  * @see _Thread_Lock_acquire(), _Thread_Lock_release(), _Thread_Lock_set() and
    658  * _Thread_Lock_restore_default().
    659  */
    660 typedef struct {
    661   /**
    662    * @brief The current thread lock.
    663    *
    664    * This is a plain ticket lock without SMP lock statistics support.  This
    665    * enables external libraries to use thread locks since they are independent
    666    * of the actual RTEMS build configuration, e.g. profiling enabled or
    667    * disabled.
    668    */
    669   union {
    670     /**
    671      * @brief The current thread lock as an atomic unsigned integer pointer value.
    672      */
    673     Atomic_Uintptr atomic;
    674 
    675     /**
    676      * @brief The current thread lock as a normal pointer.
    677      *
    678      * Only provided for debugging purposes.
    679      */
    680     SMP_ticket_lock_Control *normal;
    681   } current;
    682 
    683   /**
    684    * @brief The default thread lock in case the thread is not blocked on a
    685    * resource.
    686    */
    687   SMP_ticket_lock_Control Default;
    688 
    689 #if defined(RTEMS_PROFILING)
    690   /**
    691    * @brief The thread lock statistics.
    692    *
    693    * These statistics are used by the executing thread in case it acquires a
    694    * thread lock.  Thus the statistics are an aggregation of acquire and
    695    * release operations of different locks.
    696    */
    697   SMP_lock_Stats Stats;
    698 #endif
    699 } Thread_Lock_control;
    700 #endif
    701673
    702674/**
     
    771743     /*================= end of common block =================*/
    772744
    773 #if defined(RTEMS_SMP)
    774   /**
    775    * @brief Thread lock control.
    776    */
    777   Thread_Lock_control Lock;
    778 #endif
    779 
    780745#if defined(RTEMS_SMP) && defined(RTEMS_PROFILING)
    781746  /**
  • cpukit/score/include/rtems/score/threadimpl.h

    r3a58dc8 r1fcac5a  
    1212 *  On-Line Applications Research Corporation (OAR).
    1313 *
    14  *  Copyright (c) 2014-2015 embedded brains GmbH.
     14 *  Copyright (c) 2014, 2016 embedded brains GmbH.
    1515 *
    1616 *  The license and distribution terms for this file may be
     
    934934
    935935/**
    936  * @brief Acquires the default thread lock inside a critical section
     936 * @brief Acquires the thread wait default lock inside a critical section
    937937 * (interrupts disabled).
    938938 *
    939939 * @param[in] the_thread The thread.
    940940 * @param[in] lock_context The lock context used for the corresponding lock
    941  * release.
    942  *
    943  * @see _Thread_Lock_release_default().
    944  */
    945 RTEMS_INLINE_ROUTINE void _Thread_Lock_acquire_default_critical(
     941 *   release.
     942 *
     943 * @see _Thread_Wait_release_default_critical().
     944 */
     945RTEMS_INLINE_ROUTINE void _Thread_Wait_acquire_default_critical(
    946946  Thread_Control   *the_thread,
    947947  ISR_lock_Context *lock_context
    948948)
    949949{
    950   _Assert( _ISR_Get_level() != 0 );
    951 #if defined(RTEMS_SMP)
     950  _ISR_lock_Acquire( &the_thread->Wait.Lock.Default, lock_context );
     951}
     952
     953/**
     954 * @brief Acquires the thread wait default lock and returns the executing
     955 * thread.
     956 *
     957 * @param[in] lock_context The lock context used for the corresponding lock
     958 *   release.
     959 *
     960 * @return The executing thread.
     961 *
     962 * @see _Thread_Wait_release_default().
     963 */
     964RTEMS_INLINE_ROUTINE Thread_Control *_Thread_Wait_acquire_default_for_executing(
     965  ISR_lock_Context *lock_context
     966)
     967{
     968  Thread_Control *executing;
     969
     970  _ISR_lock_ISR_disable( lock_context );
     971  executing = _Thread_Executing;
     972  _Thread_Wait_acquire_default_critical( executing, lock_context );
     973
     974  return executing;
     975}
     976
     977/**
     978 * @brief Acquires the thread wait default lock and disables interrupts.
     979 *
     980 * @param[in] the_thread The thread.
     981 * @param[in] lock_context The lock context used for the corresponding lock
     982 *   release.
     983 *
     984 * @see _Thread_Wait_release_default().
     985 */
     986RTEMS_INLINE_ROUTINE void _Thread_Wait_acquire_default(
     987  Thread_Control   *the_thread,
     988  ISR_lock_Context *lock_context
     989)
     990{
     991  _ISR_lock_ISR_disable( lock_context );
     992  _Thread_Wait_acquire_default_critical( the_thread, lock_context );
     993}
     994
     995/**
     996 * @brief Releases the thread wait default lock inside a critical section
     997 * (interrupts disabled).
     998 *
     999 * The previous interrupt status is not restored.
     1000 *
     1001 * @param[in] the_thread The thread.
     1002 * @param[in] lock_context The lock context used for the corresponding lock
     1003 *   acquire.
     1004 */
     1005RTEMS_INLINE_ROUTINE void _Thread_Wait_release_default_critical(
     1006  Thread_Control   *the_thread,
     1007  ISR_lock_Context *lock_context
     1008)
     1009{
     1010  _ISR_lock_Release( &the_thread->Wait.Lock.Default, lock_context );
     1011}
     1012
     1013/**
     1014 * @brief Releases the thread wait default lock and restores the previous
     1015 * interrupt status.
     1016 *
     1017 * @param[in] the_thread The thread.
     1018 * @param[in] lock_context The lock context used for the corresponding lock
     1019 *   acquire.
     1020 */
     1021RTEMS_INLINE_ROUTINE void _Thread_Wait_release_default(
     1022  Thread_Control   *the_thread,
     1023  ISR_lock_Context *lock_context
     1024)
     1025{
     1026  _Thread_Wait_release_default_critical( the_thread, lock_context );
     1027  _ISR_lock_ISR_enable( lock_context );
     1028}
     1029
     1030#if defined(RTEMS_SMP)
     1031#define THREAD_QUEUE_CONTEXT_OF_REQUEST( node ) \
     1032  RTEMS_CONTAINER_OF( node, Thread_queue_Context, Wait.Gate.Node )
     1033
     1034RTEMS_INLINE_ROUTINE void _Thread_Wait_remove_request_locked(
     1035  Thread_Control       *the_thread,
     1036  Thread_queue_Context *queue_context
     1037)
     1038{
     1039  _Chain_Extract_unprotected( &queue_context->Wait.Gate.Node );
     1040
     1041  if ( !_Chain_Is_empty( &the_thread->Wait.Lock.Pending_requests ) ) {
     1042    Thread_queue_Context *first;
     1043
     1044    first = THREAD_QUEUE_CONTEXT_OF_REQUEST(
     1045      _Chain_First( &the_thread->Wait.Lock.Pending_requests )
     1046    );
     1047
     1048    _Thread_queue_Gate_open( &first->Wait.Gate );
     1049  }
     1050}
     1051
     1052RTEMS_INLINE_ROUTINE void _Thread_Wait_acquire_queue_critical(
     1053  SMP_ticket_lock_Control *queue_lock,
     1054  Thread_queue_Context    *queue_context
     1055)
     1056{
    9521057  _SMP_ticket_lock_Acquire(
    953     &the_thread->Lock.Default,
    954     &_Thread_Executing->Lock.Stats,
    955     &lock_context->Lock_context.Stats_context
     1058    queue_lock,
     1059    &_Thread_Executing->Potpourri_stats,
     1060    &queue_context->Lock_context.Lock_context.Stats_context
     1061  );
     1062}
     1063
     1064RTEMS_INLINE_ROUTINE void _Thread_Wait_release_queue_critical(
     1065  SMP_ticket_lock_Control *queue_lock,
     1066  Thread_queue_Context    *queue_context
     1067)
     1068{
     1069  _SMP_ticket_lock_Release(
     1070    queue_lock,
     1071    &queue_context->Lock_context.Lock_context.Stats_context
     1072  );
     1073}
     1074#endif
     1075
     1076/**
     1077 * @brief Acquires the thread wait lock inside a critical section (interrupts
     1078 * disabled).
     1079 *
     1080 * @param[in] the_thread The thread.
     1081 * @param[in] queue_context The thread queue context for the corresponding
     1082 *   _Thread_Wait_release_critical().
     1083 *
     1084 * @see _Thread_queue_Context_initialize().
     1085 */
     1086RTEMS_INLINE_ROUTINE void _Thread_Wait_acquire_critical(
     1087  Thread_Control       *the_thread,
     1088  Thread_queue_Context *queue_context
     1089)
     1090{
     1091#if defined(RTEMS_SMP)
     1092  Thread_queue_Queue *queue;
     1093
     1094  _Thread_Wait_acquire_default_critical(
     1095    the_thread,
     1096    &queue_context->Lock_context
     1097  );
     1098
     1099  queue = the_thread->Wait.queue;
     1100  queue_context->Wait.queue = queue;
     1101  queue_context->Wait.operations = the_thread->Wait.operations;
     1102
     1103  if ( queue != NULL ) {
     1104    queue_context->Wait.queue_lock = &queue->Lock;
     1105    _Chain_Initialize_node( &queue_context->Wait.Gate.Node );
     1106    _Chain_Append_unprotected(
     1107      &the_thread->Wait.Lock.Pending_requests,
     1108      &queue_context->Wait.Gate.Node
     1109    );
     1110    _Thread_Wait_release_default_critical(
     1111      the_thread,
     1112      &queue_context->Lock_context
     1113    );
     1114    _Thread_Wait_acquire_queue_critical( &queue->Lock, queue_context );
     1115  } else {
     1116    queue_context->Wait.queue_lock = NULL;
     1117  }
     1118#else
     1119  (void) the_thread;
     1120  (void) queue_context;
     1121#endif
     1122}
     1123
     1124/**
     1125 * @brief Acquires the thread wait default lock and disables interrupts.
     1126 *
     1127 * @param[in] the_thread The thread.
     1128 * @param[in] queue_context The thread queue context for the corresponding
     1129 *   _Thread_Wait_release().
     1130 */
     1131RTEMS_INLINE_ROUTINE void _Thread_Wait_acquire(
     1132  Thread_Control       *the_thread,
     1133  Thread_queue_Context *queue_context
     1134)
     1135{
     1136  _Thread_queue_Context_initialize( queue_context );
     1137  _ISR_lock_ISR_disable( &queue_context->Lock_context );
     1138  _Thread_Wait_acquire_critical( the_thread, queue_context );
     1139}
     1140
     1141/**
     1142 * @brief Releases the thread wait lock inside a critical section (interrupts
     1143 * disabled).
     1144 *
     1145 * The previous interrupt status is not restored.
     1146 *
     1147 * @param[in] the_thread The thread.
     1148 * @param[in] queue_context The thread queue context used for corresponding
     1149 *   _Thread_Wait_acquire_critical().
     1150 */
     1151RTEMS_INLINE_ROUTINE void _Thread_Wait_release_critical(
     1152  Thread_Control       *the_thread,
     1153  Thread_queue_Context *queue_context
     1154)
     1155{
     1156#if defined(RTEMS_SMP)
     1157  SMP_ticket_lock_Control *queue_lock;
     1158
     1159  queue_lock = queue_context->Wait.queue_lock;
     1160
     1161  if ( queue_lock != NULL ) {
     1162    _Thread_Wait_release_queue_critical( queue_lock, queue_context );
     1163    _Thread_Wait_acquire_default_critical(
     1164      the_thread,
     1165      &queue_context->Lock_context
     1166    );
     1167
     1168    _Thread_Wait_remove_request_locked( the_thread, queue_context );
     1169  }
     1170
     1171  _Thread_Wait_release_default_critical(
     1172    the_thread,
     1173    &queue_context->Lock_context
    9561174  );
    9571175#else
    9581176  (void) the_thread;
    959   (void) lock_context;
    960 #endif
    961 }
    962 
    963 /**
    964  * @brief Acquires the default thread lock and returns the executing thread.
    965  *
    966  * @param[in] lock_context The lock context used for the corresponding lock
    967  * release.
    968  *
    969  * @return The executing thread.
    970  *
    971  * @see _Thread_Lock_release_default().
    972  */
    973 RTEMS_INLINE_ROUTINE Thread_Control *_Thread_Lock_acquire_default_for_executing(
    974   ISR_lock_Context *lock_context
    975 )
    976 {
    977   Thread_Control *executing;
    978 
    979   _ISR_lock_ISR_disable( lock_context );
    980   executing = _Thread_Executing;
    981   _Thread_Lock_acquire_default_critical( executing, lock_context );
    982 
    983   return executing;
    984 }
    985 
    986 /**
    987  * @brief Acquires the default thread lock.
    988  *
    989  * @param[in] the_thread The thread.
    990  * @param[in] lock_context The lock context used for the corresponding lock
    991  * release.
    992  *
    993  * @see _Thread_Lock_release_default().
    994  */
    995 RTEMS_INLINE_ROUTINE void _Thread_Lock_acquire_default(
    996   Thread_Control   *the_thread,
    997   ISR_lock_Context *lock_context
    998 )
    999 {
    1000   _ISR_lock_ISR_disable( lock_context );
    1001   _Thread_Lock_acquire_default_critical( the_thread, lock_context );
    1002 }
    1003 
    1004 /**
    1005  * @brief Releases the thread lock inside a critical section (interrupts
    1006  * disabled).
    1007  *
    1008  * The previous interrupt status is not restored.
    1009  *
    1010  * @param[in] lock The lock.
    1011  * @param[in] lock_context The lock context used for the corresponding lock
    1012  * acquire.
    1013  */
    1014 RTEMS_INLINE_ROUTINE void _Thread_Lock_release_critical(
    1015   void             *lock,
    1016   ISR_lock_Context *lock_context
    1017 )
    1018 {
    1019 #if defined(RTEMS_SMP)
    1020   _SMP_ticket_lock_Release(
    1021     (SMP_ticket_lock_Control *) lock,
    1022     &lock_context->Lock_context.Stats_context
     1177  (void) queue_context;
     1178#endif
     1179}
     1180
     1181/**
     1182 * @brief Releases the thread wait lock and restores the previous interrupt
     1183 * status.
     1184 *
     1185 * @param[in] the_thread The thread.
     1186 * @param[in] queue_context The thread queue context used for corresponding
     1187 *   _Thread_Wait_acquire().
     1188 */
     1189RTEMS_INLINE_ROUTINE void _Thread_Wait_release(
     1190  Thread_Control       *the_thread,
     1191  Thread_queue_Context *queue_context
     1192)
     1193{
     1194  _Thread_Wait_release_critical( the_thread, queue_context );
     1195  _ISR_lock_ISR_enable( &queue_context->Lock_context );
     1196}
     1197
     1198/**
     1199 * @brief Claims the thread wait queue and operations.
     1200 *
     1201 * The caller must not be the owner of the default thread wait lock.  The
     1202 * caller must be the owner of the corresponding thread queue lock.
     1203 *
     1204 * @param[in] the_thread The thread.
     1205 * @param[in] queue The new thread queue.
     1206 * @param[in] operations The new thread operations.
     1207 *
     1208 * @see _Thread_Wait_restore_default().
     1209 */
     1210RTEMS_INLINE_ROUTINE void _Thread_Wait_claim(
     1211  Thread_Control                *the_thread,
     1212  Thread_queue_Queue            *queue,
     1213  const Thread_queue_Operations *operations
     1214)
     1215{
     1216  ISR_lock_Context lock_context;
     1217
     1218  _Thread_Wait_acquire_default_critical( the_thread, &lock_context );
     1219
     1220  _Assert( the_thread->Wait.queue == NULL );
     1221  the_thread->Wait.queue = queue;
     1222  the_thread->Wait.operations = operations;
     1223
     1224  _Thread_Wait_release_default_critical( the_thread, &lock_context );
     1225}
     1226
     1227/**
     1228 * @brief Removes a thread wait lock request.
     1229 *
     1230 * On SMP configurations, removes a thread wait lock request.
     1231 *
     1232 * On other configurations, this function does nothing.
     1233 *
     1234 * @param[in] the_thread The thread.
     1235 * @param[in] queue_context The thread queue context used for corresponding
     1236 *   _Thread_Wait_acquire().
     1237 */
     1238RTEMS_INLINE_ROUTINE void _Thread_Wait_remove_request(
     1239  Thread_Control       *the_thread,
     1240  Thread_queue_Context *queue_context
     1241)
     1242{
     1243#if defined(RTEMS_SMP)
     1244  ISR_lock_Context lock_context;
     1245
     1246  _Thread_Wait_acquire_default( the_thread, &lock_context );
     1247  _Thread_Wait_remove_request_locked( the_thread, queue_context );
     1248  _Thread_Wait_release_default( the_thread, &lock_context );
     1249#else
     1250  (void) the_thread;
     1251  (void) queue_context;
     1252#endif
     1253}
     1254
     1255/**
     1256 * @brief Restores the default thread wait queue and operations.
     1257 *
     1258 * The caller must be the owner of the current thread wait queue lock.
     1259 *
     1260 * On SMP configurations, the pending requests are updated to use the stale
     1261 * thread queue operations.
     1262 *
     1263 * @param[in] the_thread The thread.
     1264 *
     1265 * @see _Thread_Wait_claim().
     1266 */
     1267RTEMS_INLINE_ROUTINE void _Thread_Wait_restore_default(
     1268  Thread_Control *the_thread
     1269)
     1270{
     1271#if defined(RTEMS_SMP)
     1272  ISR_lock_Context  lock_context;
     1273  Chain_Node       *node;
     1274  const Chain_Node *tail;
     1275
     1276  _Thread_Wait_acquire_default_critical(
     1277    the_thread,
     1278    &lock_context
    10231279  );
    1024 #else
    1025   (void) lock;
    1026   (void) lock_context;
    1027 #endif
    1028 }
    1029 
    1030 /**
    1031  * @brief Releases the thread lock.
    1032  *
    1033  * @param[in] lock The lock returned by _Thread_Lock_acquire().
    1034  * @param[in] lock_context The lock context used for _Thread_Lock_acquire().
    1035  */
    1036 RTEMS_INLINE_ROUTINE void _Thread_Lock_release(
    1037   void             *lock,
    1038   ISR_lock_Context *lock_context
    1039 )
    1040 {
    1041   _Thread_Lock_release_critical( lock, lock_context );
    1042   _ISR_lock_ISR_enable( lock_context );
    1043 }
    1044 
    1045 /**
    1046  * @brief Releases the default thread lock inside a critical section
    1047  * (interrupts disabled).
    1048  *
    1049  * The previous interrupt status is not restored.
    1050  *
    1051  * @param[in] the_thread The thread.
    1052  * @param[in] lock_context The lock context used for the corresponding lock
    1053  * acquire.
    1054  */
    1055 RTEMS_INLINE_ROUTINE void _Thread_Lock_release_default_critical(
    1056   Thread_Control   *the_thread,
    1057   ISR_lock_Context *lock_context
    1058 )
    1059 {
    1060   _Thread_Lock_release_critical(
    1061 #if defined(RTEMS_SMP)
    1062     &the_thread->Lock.Default,
    1063 #else
    1064     NULL,
    1065 #endif
    1066     lock_context
     1280
     1281  node = _Chain_First( &the_thread->Wait.Lock.Pending_requests );
     1282  tail = _Chain_Immutable_tail( &the_thread->Wait.Lock.Pending_requests );
     1283
     1284  while ( node != tail ) {
     1285    Thread_queue_Context *queue_context;
     1286
     1287    queue_context = THREAD_QUEUE_CONTEXT_OF_REQUEST( node );
     1288    queue_context->Wait.queue = NULL;
     1289    queue_context->Wait.operations = &_Thread_queue_Operations_stale_queue;
     1290
     1291    node = _Chain_Next( node );
     1292  }
     1293#endif
     1294
     1295  the_thread->Wait.queue = NULL;
     1296  the_thread->Wait.operations = &_Thread_queue_Operations_default;
     1297
     1298#if defined(RTEMS_SMP)
     1299  _Thread_Wait_release_default_critical(
     1300    the_thread,
     1301    &lock_context
    10671302  );
    1068 }
    1069 
    1070 /**
    1071  * @brief Releases the default thread lock.
    1072  *
    1073  * @param[in] the_thread The thread.
    1074  * @param[in] lock_context The lock context used for the corresponding lock
    1075  * acquire.
    1076  */
    1077 RTEMS_INLINE_ROUTINE void _Thread_Lock_release_default(
    1078   Thread_Control   *the_thread,
    1079   ISR_lock_Context *lock_context
    1080 )
    1081 {
    1082   _Thread_Lock_release_default_critical( the_thread, lock_context );
    1083   _ISR_lock_ISR_enable( lock_context );
    1084 }
    1085 
    1086 /**
    1087  * @brief Acquires the thread lock.
    1088  *
    1089  * @param[in] the_thread The thread.
    1090  * @param[in] lock_context The lock context for _Thread_Lock_release().
    1091  *
    1092  * @return The lock required by _Thread_Lock_release().
    1093  */
    1094 RTEMS_INLINE_ROUTINE void *_Thread_Lock_acquire(
    1095   Thread_Control   *the_thread,
    1096   ISR_lock_Context *lock_context
    1097 )
    1098 {
    1099 #if defined(RTEMS_SMP)
    1100   SMP_ticket_lock_Control *lock_0;
    1101 
    1102   while ( true ) {
    1103     SMP_ticket_lock_Control *lock_1;
    1104 
    1105     _ISR_lock_ISR_disable( lock_context );
    1106 
    1107     /*
    1108      * We assume that a normal load of pointer is identical to a relaxed atomic
    1109      * load.  Here, we may read an out-of-date lock.  However, only the owner
    1110      * of this out-of-date lock is allowed to set a new one.  Thus, we read at
    1111      * least this new lock ...
    1112      */
    1113     lock_0 = (SMP_ticket_lock_Control *) _Atomic_Load_uintptr(
    1114       &the_thread->Lock.current.atomic,
    1115       ATOMIC_ORDER_RELAXED
     1303#endif
     1304}
     1305
     1306/**
     1307 * @brief Tranquilizes the thread after a wait a thread queue.
     1308 *
     1309 * After the violent blocking procedure this function makes the thread calm and
     1310 * peaceful again so that it can carry out its normal work.
     1311 *
     1312 * On SMP configurations, ensures that all pending thread wait lock requests
     1313 * completed before the thread is able to begin a new thread wait procedure.
     1314 *
     1315 * On other configurations, this function does nothing.
     1316 *
     1317 * @param[in] the_thread The thread.
     1318 */
     1319RTEMS_INLINE_ROUTINE void _Thread_Wait_tranquilize(
     1320  Thread_Control *the_thread
     1321)
     1322{
     1323#if defined(RTEMS_SMP)
     1324  Thread_queue_Context queue_context;
     1325
     1326  _Thread_queue_Context_initialize( &queue_context );
     1327  _Thread_Wait_acquire_default( the_thread, &queue_context.Lock_context );
     1328
     1329  if ( !_Chain_Is_empty( &the_thread->Wait.Lock.Pending_requests ) ) {
     1330    _Thread_queue_Gate_add(
     1331      &the_thread->Wait.Lock.Pending_requests,
     1332      &queue_context.Wait.Gate
    11161333    );
    1117 
    1118     _SMP_ticket_lock_Acquire(
    1119       lock_0,
    1120       &_Thread_Executing->Lock.Stats,
    1121       &lock_context->Lock_context.Stats_context
    1122     );
    1123 
    1124     /*
    1125      * We must use a load acquire here paired with the store release in
    1126      * _Thread_Lock_set_unprotected() to observe corresponding thread wait
    1127      * queue and thread wait operations.  It is important to do this after the
    1128      * lock acquire, since we may have the following scenario.
    1129      *
    1130      * - We read the default lock and try to acquire it.
    1131      * - The thread lock changes to a thread queue lock.
    1132      * - The thread lock is restored to the default lock.
    1133      * - We acquire the default lock and read it here again.
    1134      * - Now, we must read the restored default thread wait queue and thread
    1135      *   wait operations and this is not synchronized via the default thread
    1136      *   lock.
    1137      */
    1138     lock_1 = (SMP_ticket_lock_Control *) _Atomic_Load_uintptr(
    1139       &the_thread->Lock.current.atomic,
    1140       ATOMIC_ORDER_ACQUIRE
    1141     );
    1142 
    1143     /*
    1144      * ... here, and so on.
    1145      */
    1146     if ( lock_0 == lock_1 ) {
    1147       return lock_0;
    1148     }
    1149 
    1150     _Thread_Lock_release( lock_0, lock_context );
     1334    _Thread_Wait_release_default( the_thread, &queue_context.Lock_context );
     1335    _Thread_queue_Gate_wait( &queue_context.Wait.Gate );
     1336    _Thread_Wait_remove_request( the_thread, &queue_context );
     1337  } else {
     1338    _Thread_Wait_release_default( the_thread, &queue_context.Lock_context );
    11511339  }
    11521340#else
    1153   _ISR_Local_disable( lock_context->isr_level );
    1154 
    1155   return NULL;
    1156 #endif
    1157 }
    1158 
    1159 #if defined(RTEMS_SMP)
    1160 /*
    1161  * Internal function, use _Thread_Lock_set() or _Thread_Lock_restore_default()
    1162  * instead.
    1163  */
    1164 RTEMS_INLINE_ROUTINE void _Thread_Lock_set_unprotected(
    1165   Thread_Control          *the_thread,
    1166   SMP_ticket_lock_Control *new_lock
    1167 )
    1168 {
    1169   _Atomic_Store_uintptr(
    1170     &the_thread->Lock.current.atomic,
    1171     (uintptr_t) new_lock,
    1172     ATOMIC_ORDER_RELEASE
    1173   );
    1174 }
    1175 #endif
    1176 
    1177 /**
    1178  * @brief Sets a new thread lock.
    1179  *
    1180  * The caller must not be the owner of the default thread lock.  The caller
    1181  * must be the owner of the new lock.
    1182  *
    1183  * @param[in] the_thread The thread.
    1184  * @param[in] new_lock The new thread lock.
    1185  */
    1186 #if defined(RTEMS_SMP)
    1187 RTEMS_INLINE_ROUTINE void _Thread_Lock_set(
    1188   Thread_Control          *the_thread,
    1189   SMP_ticket_lock_Control *new_lock
    1190 )
    1191 {
    1192   ISR_lock_Context lock_context;
    1193 
    1194   _Thread_Lock_acquire_default_critical( the_thread, &lock_context );
    1195   _Assert( the_thread->Lock.current.normal == &the_thread->Lock.Default );
    1196   _Thread_Lock_set_unprotected( the_thread, new_lock );
    1197   _Thread_Lock_release_default_critical( the_thread, &lock_context );
    1198 }
    1199 #else
    1200 #define _Thread_Lock_set( the_thread, new_lock ) \
    1201   do { } while ( 0 )
    1202 #endif
    1203 
    1204 /**
    1205  * @brief Restores the default thread lock.
    1206  *
    1207  * The caller must be the owner of the current thread lock.
    1208  *
    1209  * @param[in] the_thread The thread.
    1210  */
    1211 #if defined(RTEMS_SMP)
    1212 RTEMS_INLINE_ROUTINE void _Thread_Lock_restore_default(
    1213   Thread_Control *the_thread
    1214 )
    1215 {
    1216   _Thread_Lock_set_unprotected( the_thread, &the_thread->Lock.Default );
    1217 }
    1218 #else
    1219 #define _Thread_Lock_restore_default( the_thread ) \
    1220   do { } while ( 0 )
    1221 #endif
     1341  (void) the_thread;
     1342#endif
     1343}
     1344
     1345/**
     1346 * @brief Cancels a thread wait on a thread queue.
     1347 *
     1348 * @param[in] the_thread The thread.
     1349 * @param[in] queue_context The thread queue context used for corresponding
     1350 *   _Thread_Wait_acquire().
     1351 */
     1352RTEMS_INLINE_ROUTINE void _Thread_Wait_cancel(
     1353  Thread_Control       *the_thread,
     1354  Thread_queue_Context *queue_context
     1355)
     1356{
     1357  _Thread_queue_Context_extract( queue_context, the_thread );
     1358
     1359#if defined(RTEMS_SMP)
     1360  if ( queue_context->Wait.queue != NULL ) {
     1361#endif
     1362    _Thread_Wait_restore_default( the_thread );
     1363#if defined(RTEMS_SMP)
     1364  }
     1365#endif
     1366}
    12221367
    12231368/**
     
    13891534
    13901535/**
    1391  * @brief Sets the thread queue.
    1392  *
    1393  * The caller must be the owner of the thread lock.
    1394  *
    1395  * @param[in] the_thread The thread.
    1396  * @param[in] new_queue The new queue.
    1397  *
    1398  * @see _Thread_Lock_set().
    1399  */
    1400 RTEMS_INLINE_ROUTINE void _Thread_Wait_set_queue(
    1401   Thread_Control     *the_thread,
    1402   Thread_queue_Queue *new_queue
    1403 )
    1404 {
    1405   the_thread->Wait.queue = new_queue;
    1406 }
    1407 
    1408 /**
    1409  * @brief Sets the thread queue operations.
    1410  *
    1411  * The caller must be the owner of the thread lock.
    1412  *
    1413  * @param[in] the_thread The thread.
    1414  * @param[in] new_operations The new queue operations.
    1415  *
    1416  * @see _Thread_Lock_set() and _Thread_Wait_restore_default_operations().
    1417  */
    1418 RTEMS_INLINE_ROUTINE void _Thread_Wait_set_operations(
    1419   Thread_Control                *the_thread,
    1420   const Thread_queue_Operations *new_operations
    1421 )
    1422 {
    1423   the_thread->Wait.operations = new_operations;
    1424 }
    1425 
    1426 /**
    1427  * @brief Restores the default thread queue operations.
    1428  *
    1429  * The caller must be the owner of the thread lock.
    1430  *
    1431  * @param[in] the_thread The thread.
    1432  *
    1433  * @see _Thread_Wait_set_operations().
    1434  */
    1435 RTEMS_INLINE_ROUTINE void _Thread_Wait_restore_default_operations(
    1436   Thread_Control *the_thread
    1437 )
    1438 {
    1439   the_thread->Wait.operations = &_Thread_queue_Operations_default;
    1440 }
    1441 
    1442 /**
    14431536 * @brief Returns the object identifier of the object containing the current
    14441537 * thread wait queue.
     
    15421635)
    15431636{
     1637  _Thread_Wait_tranquilize( the_thread );
    15441638  _Thread_Timer_remove( the_thread );
    15451639
  • cpukit/score/include/rtems/score/threadq.h

    r3a58dc8 r1fcac5a  
    4444typedef struct _Thread_Control Thread_Control;
    4545
     46typedef struct Thread_queue_Queue Thread_queue_Queue;
     47
     48typedef struct Thread_queue_Operations Thread_queue_Operations;
     49
    4650typedef struct Thread_queue_Path Thread_queue_Path;
    4751
     
    5458 *   _Objects_Is_local_id( the_proxy->Object.id ) is false.
    5559 * @param mp_id Object identifier of the object containing the thread queue.
     60 *
     61 * @see _Thread_queue_Context_set_MP_callout().
    5662 */
    5763typedef void ( *Thread_queue_MP_callout )(
     
    6167#endif
    6268
     69#if defined(RTEMS_SMP)
     70/**
     71 * @brief The thread queue gate is an SMP synchronization means.
     72 *
     73 * The gates are added to a list of requests.  A busy wait is performed to make
     74 * sure that preceding requests are carried out.  Each predecessor notifies its
     75 * successor about on request completion.
     76 *
     77 * @see _Thread_queue_Gate_add(), _Thread_queue_Gate_wait(), and
     78 *   _Thread_queue_Gate_open().
     79 */
     80typedef struct {
     81  Chain_Node Node;
     82
     83  Atomic_Uint go_ahead;
     84} Thread_queue_Gate;
     85#endif
     86
    6387/**
    6488 * @brief Thread queue context for the thread queue methods.
     
    106130  Thread_queue_MP_callout mp_callout;
    107131#endif
     132
     133#if defined(RTEMS_SMP)
     134  /**
     135   * @brief Data to support thread queue enqueue operations.
     136   */
     137  struct {
     138    /**
     139     * @brief Gate to synchronize thread wait lock requests.
     140     *
     141     * @see _Thread_Wait_acquire_critical() and _Thread_Wait_tranquilize().
     142     */
     143    Thread_queue_Gate Gate;
     144
     145    /**
     146     * @brief The thread queue lock in case the thread is blocked on a thread
     147     * queue at thread wait lock acquire time.
     148     */
     149    SMP_ticket_lock_Control *queue_lock;
     150
     151    /**
     152     * @brief The thread queue after thread wait lock acquire.
     153     *
     154     * In case the thread queue is NULL and the thread queue lock is non-NULL
     155     * in this context, then we have a stale thread queue.  This happens in
     156     * case the thread wait default is restored while we wait on the thread
     157     * queue lock, e.g. during a mutex ownership transfer.
     158     *
     159     * @see _Thread_Wait_restore_default().
     160     */
     161    Thread_queue_Queue *queue;
     162
     163    /**
     164     * @brief The thread queue operations after thread wait lock acquire.
     165     */
     166    const Thread_queue_Operations *operations;
     167  } Wait;
     168#endif
    108169} Thread_queue_Context;
     170
     171#if defined(RTEMS_SMP)
     172/**
     173 * @brief A thread queue link from one thread to another specified by the
     174 * thread queue owner and thread wait queue relationships.
     175 */
     176typedef struct {
     177  /**
     178   * @brief The owner of this thread queue link.
     179   */
     180  Thread_Control *owner;
     181
     182  /**
     183   * @brief The queue context used to acquire the thread wait lock of the
     184   * owner.
     185   */
     186  Thread_queue_Context Queue_context;
     187} Thread_queue_Link;
     188#endif
    109189
    110190/**
     
    192272#endif
    193273
    194 typedef struct {
     274struct Thread_queue_Queue {
    195275  /**
    196276   * @brief Lock to protect this thread queue.
     
    222302   */
    223303  Thread_Control *owner;
    224 } Thread_queue_Queue;
     304};
    225305
    226306/**
     
    229309 * @param[in] the_thread The thread.
    230310 * @param[in] new_priority The new priority value.
     311 * @param[in] prepend_it In case this is true, then the thread is prepended to
     312 *   its priority group in its scheduler instance, otherwise it is appended.
    231313 * @param[in] queue The actual thread queue.
    232314 *
     
    236318  Thread_Control     *the_thread,
    237319  Priority_Control    new_priority,
     320  bool                prepend_it,
    238321  Thread_queue_Queue *queue
    239322);
     
    248331 * @param[in] queue The actual thread queue.
    249332 * @param[in] the_thread The thread to enqueue on the queue.
    250  *
    251  * @see _Thread_Wait_set_operations().
    252333 */
    253334typedef void ( *Thread_queue_Enqueue_operation )(
     
    262343 * @param[in] queue The actual thread queue.
    263344 * @param[in] the_thread The thread to extract from the thread queue.
    264  *
    265  * @see _Thread_Wait_set_operations().
    266345 */
    267346typedef void ( *Thread_queue_Extract_operation )(
     
    278357 * @retval first The first thread of the thread queue according to the insert
    279358 * order.  This thread remains on the thread queue.
    280  *
    281  * @see _Thread_Wait_set_operations().
    282359 */
    283360typedef Thread_Control *( *Thread_queue_First_operation )(
     
    290367 * @see _Thread_wait_Set_operations().
    291368 */
    292 typedef struct {
     369struct Thread_queue_Operations {
    293370  /**
    294371   * @brief Thread queue priority change operation.
     
    321398   */
    322399  Thread_queue_First_operation first;
    323 } Thread_queue_Operations;
     400};
    324401
    325402/**
  • cpukit/score/include/rtems/score/threadqimpl.h

    r3a58dc8 r1fcac5a  
    2727#include <rtems/score/thread.h>
    2828
     29#if defined(RTEMS_DEBUG)
     30#include <string.h>
     31#endif
     32
    2933#ifdef __cplusplus
    3034extern "C" {
     
    4751 */
    4852struct Thread_queue_Path {
     53#if defined(RTEMS_SMP)
     54  /**
     55   * @brief The start of a thread queue path.
     56   */
     57  Thread_queue_Link Start;
     58#endif
     59
    4960  /**
    5061   * @brief A potential thread to update the priority via
     
    8596{
    8697#if defined(RTEMS_DEBUG)
     98  memset( queue_context, 0, sizeof( *queue_context ) );
    8799  queue_context->expected_thread_dispatch_disable_level = 0xdeadbeef;
    88 #if defined(RTEMS_MULTIPROCESSING)
    89   queue_context->mp_callout = NULL;
    90 #endif
    91100#else
    92101  (void) queue_context;
     
    186195    (void) queue_context; \
    187196  } while ( 0 )
     197#endif
     198
     199/**
     200 * @brief Gets the thread wait queue of the thread queue context.
     201 *
     202 * On SMP configurations, the value is stored in the thread queue context,
     203 * otherwise in the thread itself.
     204 *
     205 * @param queue_context The thread queue context.
     206 * @param the_thread The thread.
     207 */
     208#if defined(RTEMS_SMP)
     209#define _Thread_queue_Context_get_queue( queue_context, the_thread ) \
     210  ( queue_context )->Wait.queue
     211#else
     212#define _Thread_queue_Context_get_queue( queue_context, the_thread ) \
     213  ( the_thread )->Wait.queue
     214#endif
     215
     216/**
     217 * @brief Gets the thread wait operations of the thread queue context.
     218 *
     219 * On SMP configurations, the value is stored in the thread queue context,
     220 * otherwise in the thread itself.
     221 *
     222 * @param queue_context The thread queue context.
     223 * @param the_thread The thread.
     224 */
     225#if defined(RTEMS_SMP)
     226#define _Thread_queue_Context_get_operations( queue_context, the_thread ) \
     227  ( queue_context )->Wait.operations
     228#else
     229#define _Thread_queue_Context_get_operations( queue_context, the_thread ) \
     230  ( the_thread )->Wait.operations
     231#endif
     232
     233/**
     234 * @brief Thread priority change by means of the thread queue context.
     235 *
     236 * On SMP configurations, the used data is stored in the thread queue context,
     237 * otherwise in the thread itself.
     238 *
     239 * @param queue_context The thread queue context.
     240 * @param the_thread The thread.
     241 * @param new_priority The new thread priority.
     242 * @param prepend_it Prepend it to its priority group or not.
     243 */
     244#if defined(RTEMS_SMP)
     245#define _Thread_queue_Context_priority_change( \
     246    queue_context, \
     247    the_thread, \
     248    new_priority, \
     249    prepend_it \
     250  ) \
     251    ( *( queue_context )->Wait.operations->priority_change )( \
     252      the_thread, \
     253      new_priority, \
     254      prepend_it, \
     255      ( queue_context )->Wait.queue \
     256    )
     257#else
     258#define _Thread_queue_Context_priority_change( \
     259    queue_context, \
     260    the_thread, \
     261    new_priority, \
     262    prepend_it \
     263  ) \
     264    ( *( the_thread )->Wait.operations->priority_change )( \
     265      the_thread, \
     266      new_priority, \
     267      prepend_it, \
     268      ( the_thread )->Wait.queue \
     269    )
     270#endif
     271
     272/**
     273 * @brief Thread queue extract by means of the thread queue context.
     274 *
     275 * On SMP configurations, the used data is stored in the thread queue context,
     276 * otherwise in the thread itself.
     277 *
     278 * @param queue_context The thread queue context.
     279 * @param the_thread The thread.
     280 */
     281#if defined(RTEMS_SMP)
     282#define _Thread_queue_Context_extract( \
     283    queue_context, \
     284    the_thread \
     285  ) \
     286    ( *( queue_context )->Wait.operations->extract )( \
     287      ( queue_context )->Wait.queue, \
     288      the_thread \
     289    )
     290#else
     291#define _Thread_queue_Context_extract( \
     292    queue_context, \
     293    the_thread \
     294  ) \
     295    ( *( the_thread )->Wait.operations->extract )( \
     296      ( the_thread )->Wait.queue, \
     297      the_thread \
     298    )
     299#endif
     300
     301#if defined(RTEMS_SMP)
     302RTEMS_INLINE_ROUTINE void _Thread_queue_Gate_add(
     303  Chain_Control     *chain,
     304  Thread_queue_Gate *gate
     305)
     306{
     307  _Atomic_Store_uint( &gate->go_ahead, 0, ATOMIC_ORDER_RELAXED );
     308  _Chain_Append_unprotected( chain, &gate->Node );
     309}
     310
     311RTEMS_INLINE_ROUTINE void _Thread_queue_Gate_open(
     312  Thread_queue_Gate *gate
     313)
     314{
     315  _Atomic_Store_uint( &gate->go_ahead, 1, ATOMIC_ORDER_RELAXED );
     316}
     317
     318RTEMS_INLINE_ROUTINE void _Thread_queue_Gate_wait(
     319  Thread_queue_Gate *gate
     320)
     321{
     322  while ( _Atomic_Load_uint( &gate->go_ahead, ATOMIC_ORDER_RELAXED ) == 0 ) {
     323    /* Wait */
     324  }
     325}
    188326#endif
    189327
     
    9121050extern const Thread_queue_Operations _Thread_queue_Operations_priority_inherit;
    9131051
     1052#if defined(RTEMS_SMP)
     1053extern const Thread_queue_Operations _Thread_queue_Operations_stale_queue;
     1054#endif
     1055
    9141056/**@}*/
    9151057
  • cpukit/score/src/threadchangepriority.c

    r3a58dc8 r1fcac5a  
    2828  void                          *arg,
    2929  Thread_Change_priority_filter  filter,
    30   bool                           prepend_it
     30  bool                           prepend_it,
     31  Thread_queue_Context          *queue_context
    3132)
    3233{
     
    4647   */
    4748  if ( ( *filter )( the_thread, &new_priority, arg ) ) {
    48     Scheduler_Node *own_node;
    49 
    50     own_node = _Scheduler_Thread_get_own_node( the_thread );
    51     _Scheduler_Node_set_priority( own_node, new_priority, prepend_it );
    52 
    53     the_thread->current_priority = new_priority;
    54 
    55     ( *the_thread->Wait.operations->priority_change )(
     49    _Thread_queue_Context_priority_change(
     50      queue_context,
    5651      the_thread,
    5752      new_priority,
    58       the_thread->Wait.queue
     53      prepend_it
    5954    );
    6055  } else {
     
    7368)
    7469{
    75   ISR_lock_Context  lock_context;
    76   ISR_lock_Control *lock;
     70  Thread_queue_Context  queue_context;
     71  Thread_Control       *the_thread_to_update;
    7772
    78   lock = _Thread_Lock_acquire( the_thread, &lock_context );
    79   the_thread = _Thread_Apply_priority_locked(
     73  _Thread_Wait_acquire( the_thread, &queue_context );
     74  the_thread_to_update = _Thread_Apply_priority_locked(
    8075    the_thread,
    8176    new_priority,
    8277    arg,
    8378    filter,
    84     prepend_it
     79    prepend_it,
     80    &queue_context
    8581  );
    86   _Thread_Lock_release( lock, &lock_context );
    87   return the_thread;
     82  _Thread_Wait_release( the_thread, &queue_context );
     83  return the_thread_to_update;
    8884}
    8985
  • cpukit/score/src/threadinitialize.c

    r3a58dc8 r1fcac5a  
    183183  the_thread->Scheduler.own_node = scheduler_node;
    184184  _Resource_Node_initialize( &the_thread->Resource_node );
    185   _Atomic_Store_uintptr(
    186     &the_thread->Lock.current.atomic,
    187     (uintptr_t) &the_thread->Lock.Default,
    188     ATOMIC_ORDER_RELAXED
    189   );
    190   _SMP_ticket_lock_Initialize( &the_thread->Lock.Default );
    191   _SMP_lock_Stats_initialize( &the_thread->Lock.Stats, "Thread Lock" );
     185  _ISR_lock_Initialize(
     186    &the_thread->Wait.Lock.Default,
     187    "Thread Wait Default Lock"
     188  );
     189  _Chain_Initialize_empty( &the_thread->Wait.Lock.Pending_requests );
    192190  _SMP_lock_Stats_initialize( &the_thread->Potpourri_stats, "Thread Potpourri" );
    193191#endif
  • cpukit/score/src/threadqenqueue.c

    r3a58dc8 r1fcac5a  
    3535  (THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_READY_AGAIN)
    3636
     37static void _Thread_queue_Path_release( Thread_queue_Path *path )
     38{
     39#if defined(RTEMS_SMP)
     40  Thread_queue_Link *link;
     41
     42  link = &path->Start;
     43
     44  if ( link->owner != NULL ) {
     45    _Thread_Wait_release_critical( link->owner, &link->Queue_context );
     46  }
     47#else
     48  (void) path;
     49#endif
     50}
     51
     52static void _Thread_queue_Path_acquire(
     53  Thread_Control     *the_thread,
     54  Thread_queue_Queue *queue,
     55  Thread_queue_Path  *path
     56)
     57{
     58#if defined(RTEMS_SMP)
     59  Thread_Control     *owner;
     60  Thread_queue_Link  *link;
     61
     62  owner = queue->owner;
     63
     64  if ( owner == NULL ) {
     65    return;
     66  }
     67
     68  link = &path->Start;
     69  link->owner = owner;
     70
     71  _Thread_Wait_acquire_default_critical(
     72    owner,
     73    &link->Queue_context.Lock_context
     74  );
     75#else
     76  (void) the_thread;
     77  (void) queue;
     78  (void) path;
     79#endif
     80}
     81
    3782void _Thread_queue_Enqueue_critical(
    3883  Thread_queue_Queue            *queue,
     
    5398#endif
    5499
    55   _Thread_Lock_set( the_thread, &queue->Lock );
     100  _Thread_Wait_claim( the_thread, queue, operations );
     101
     102  _Thread_queue_Path_acquire( the_thread, queue, &path );
     103  ( *operations->enqueue )( queue, the_thread, &path );
     104  _Thread_queue_Path_release( &path );
    56105
    57106  the_thread->Wait.return_code = STATUS_SUCCESSFUL;
    58   _Thread_Wait_set_queue( the_thread, queue );
    59   _Thread_Wait_set_operations( the_thread, operations );
    60 
    61   ( *operations->enqueue )( queue, the_thread, &path );
    62 
    63107  _Thread_Wait_flags_set( the_thread, THREAD_QUEUE_INTEND_TO_BLOCK );
    64108  cpu_self = _Thread_Dispatch_disable_critical( &queue_context->Lock_context );
     
    174218  }
    175219
    176   _Thread_Wait_set_queue( the_thread, NULL );
    177   _Thread_Wait_restore_default_operations( the_thread );
    178   _Thread_Lock_restore_default( the_thread );
     220  _Thread_Wait_restore_default( the_thread );
    179221
    180222  return unblock;
     
    228270void _Thread_queue_Extract( Thread_Control *the_thread )
    229271{
    230   Thread_queue_Context  queue_context;
    231   void                 *lock;
    232   Thread_queue_Queue   *queue;
     272  Thread_queue_Context queue_context;
    233273
    234274  _Thread_queue_Context_initialize( &queue_context );
    235   lock = _Thread_Lock_acquire( the_thread, &queue_context.Lock_context );
    236 
    237   queue = the_thread->Wait.queue;
    238 
    239   if ( queue != NULL ) {
    240     _SMP_Assert( lock == &queue->Lock );
    241 
     275  _Thread_Wait_acquire( the_thread, &queue_context );
     276
     277  if (
     278    _Thread_queue_Context_get_queue( &queue_context, the_thread ) != NULL
     279  ) {
     280    bool unblock;
     281
     282    _Thread_Wait_remove_request( the_thread, &queue_context );
    242283    _Thread_queue_Context_set_MP_callout(
    243284      &queue_context,
    244285      _Thread_queue_MP_callout_do_nothing
    245286    );
    246     _Thread_queue_Extract_critical(
    247       queue,
    248       the_thread->Wait.operations,
     287    unblock = _Thread_queue_Extract_locked(
     288      _Thread_queue_Context_get_queue( &queue_context, the_thread ),
     289      _Thread_queue_Context_get_operations( &queue_context, the_thread ),
    249290      the_thread,
    250       &queue_context
     291      &queue_context.Lock_context
     292    );
     293    _Thread_queue_Unblock_critical(
     294      unblock,
     295      _Thread_queue_Context_get_queue( &queue_context, the_thread ),
     296      the_thread,
     297      &queue_context.Lock_context
    251298    );
    252299  } else {
    253     _Thread_Lock_release( lock, &queue_context.Lock_context );
     300    _Thread_Wait_release( the_thread, &queue_context );
    254301  }
    255302}
     
    274321
    275322  if ( the_thread != NULL ) {
    276     _SMP_Assert( the_thread->Lock.current.normal == &the_thread_queue->Queue.Lock );
    277 
    278323    _Thread_queue_Extract_critical(
    279324      &the_thread_queue->Queue,
  • cpukit/score/src/threadqops.c

    r3a58dc8 r1fcac5a  
    2323#include <rtems/score/schedulerimpl.h>
    2424
    25 static void _Thread_queue_Do_nothing_priority_change(
     25static void _Thread_queue_Default_priority_change(
    2626  Thread_Control     *the_thread,
    2727  Priority_Control    new_priority,
     28  bool                prepend_it,
    2829  Thread_queue_Queue *queue
    2930)
    3031{
     32  (void) queue;
     33
     34  _Scheduler_Thread_set_priority( the_thread, new_priority, prepend_it );
     35}
     36
     37static void _Thread_queue_Do_nothing_extract(
     38  Thread_queue_Queue *queue,
     39  Thread_Control    *the_thread
     40)
     41{
    3142  /* Do nothing */
    3243}
    3344
    34 static void _Thread_queue_Do_nothing_extract(
    35   Thread_queue_Queue *queue,
    36   Thread_Control    *the_thread
    37 )
    38 {
    39   /* Do nothing */
    40 }
     45#if defined(RTEMS_SMP)
     46static void _Thread_queue_Stale_queue_priority_change(
     47  Thread_Control     *the_thread,
     48  Priority_Control    new_priority,
     49  bool                prepend_it,
     50  Thread_queue_Queue *queue
     51)
     52{
     53  ISR_lock_Context lock_context;
     54
     55  (void) queue;
     56
     57  /*
     58   * This operation is used to change the priority in case we have a thread
     59   * queue context with a stale thread queue.  We own the thread queue lock of
     60   * the former thread queue.  In addition, we need the thread wait default
     61   * lock, see _Thread_Wait_restore_default().
     62   */
     63
     64  _Thread_Wait_acquire_default_critical( the_thread, &lock_context );
     65  _Scheduler_Thread_set_priority( the_thread, new_priority, prepend_it );
     66  _Thread_Wait_release_default_critical( the_thread, &lock_context );
     67}
     68#endif
    4169
    4270static Thread_queue_Heads *_Thread_queue_Queue_enqueue(
     
    191219  Thread_Control     *the_thread,
    192220  Priority_Control    new_priority,
     221  bool                prepend_it,
    193222  Thread_queue_Queue *queue
    194223)
     
    198227
    199228  _Assert( heads != NULL );
     229
     230  _Scheduler_Thread_set_priority( the_thread, new_priority, prepend_it );
    200231
    201232  priority_queue = _Thread_queue_Priority_queue( heads, the_thread );
     
    354385
    355386  if ( priority < owner->current_priority ) {
    356     Scheduler_Node *own_node;
    357 
    358387    path->update_priority = owner;
    359388
     
    361390    _Atomic_Fence( ATOMIC_ORDER_ACQ_REL );
    362391
    363     own_node = _Scheduler_Thread_get_own_node( owner );
    364     _Scheduler_Node_set_priority( own_node, priority, false );
    365 
    366     owner->current_priority = priority;
    367 
    368     ( *owner->Wait.operations->priority_change )(
     392    _Thread_queue_Context_priority_change(
     393      &path->Start.Queue_context,
    369394      owner,
    370395      priority,
    371       owner->Wait.queue
     396      false
    372397    );
    373398  } else {
     
    386411  if ( !_Chain_Has_only_one_node( &heads->Heads.Fifo ) ) {
    387412    const Scheduler_Control *scheduler;
    388     Scheduler_Node          *own_node;
    389413    Priority_Control         boost_priority;
    390414
     
    393417
    394418    scheduler = _Scheduler_Get_own( the_thread );
    395     own_node = _Scheduler_Thread_get_own_node( the_thread );
    396419    boost_priority = _Scheduler_Map_priority( scheduler, PRIORITY_PSEUDO_ISR );
    397     _Scheduler_Node_set_priority( own_node, boost_priority, false );
    398 
    399     the_thread->current_priority = boost_priority;
     420
     421    _Scheduler_Thread_set_priority( the_thread, boost_priority, false );
    400422  }
    401423}
     
    403425
    404426const Thread_queue_Operations _Thread_queue_Operations_default = {
    405   .priority_change = _Thread_queue_Do_nothing_priority_change,
     427  .priority_change = _Thread_queue_Default_priority_change,
    406428  .extract = _Thread_queue_Do_nothing_extract
    407429  /*
     
    413435
    414436const Thread_queue_Operations _Thread_queue_Operations_FIFO = {
    415   .priority_change = _Thread_queue_Do_nothing_priority_change,
     437  .priority_change = _Thread_queue_Default_priority_change,
    416438  .enqueue = _Thread_queue_FIFO_enqueue,
    417439  .extract = _Thread_queue_FIFO_extract,
     
    432454  .first = _Thread_queue_Priority_first
    433455};
     456
     457#if defined(RTEMS_SMP)
     458const Thread_queue_Operations _Thread_queue_Operations_stale_queue = {
     459  .priority_change = _Thread_queue_Stale_queue_priority_change,
     460  .extract = _Thread_queue_Do_nothing_extract
     461};
     462#endif
  • cpukit/score/src/threadrestart.c

    r3a58dc8 r1fcac5a  
    216216
    217217#if defined(RTEMS_SMP)
    218   _SMP_ticket_lock_Destroy( &the_thread->Lock.Default );
    219   _SMP_lock_Stats_destroy( &the_thread->Lock.Stats );
     218  _ISR_lock_Destroy( &the_thread->Wait.Lock.Default );
    220219  _SMP_lock_Stats_destroy( &the_thread->Potpourri_stats );
    221220#endif
  • cpukit/score/src/threadtimeout.c

    r3a58dc8 r1fcac5a  
    2323#include <rtems/score/status.h>
    2424
    25 static void _Thread_Do_timeout( Thread_Control *the_thread )
    26 {
    27   the_thread->Wait.return_code = STATUS_TIMEOUT;
    28   ( *the_thread->Wait.operations->extract )(
    29     the_thread->Wait.queue,
    30     the_thread
    31   );
    32   _Thread_Wait_set_queue( the_thread, NULL );
    33   _Thread_Wait_restore_default_operations( the_thread );
    34   _Thread_Lock_restore_default( the_thread );
    35 }
    36 
    3725void _Thread_Timeout( Watchdog_Control *watchdog )
    3826{
    39   Thread_Control    *the_thread;
    40   void              *thread_lock;
    41   ISR_lock_Context   lock_context;
    42   Thread_Wait_flags  wait_flags;
    43   bool               unblock;
     27  Thread_Control       *the_thread;
     28  Thread_queue_Context  queue_context;
     29  Thread_Wait_flags     wait_flags;
     30  bool                  unblock;
    4431
    4532  the_thread = RTEMS_CONTAINER_OF( watchdog, Thread_Control, Timer.Watchdog );
    46   thread_lock = _Thread_Lock_acquire( the_thread, &lock_context );
     33  _Thread_Wait_acquire( the_thread, &queue_context );
    4734
    4835  wait_flags = _Thread_Wait_flags_get( the_thread );
     
    5340    bool              success;
    5441
    55     _Thread_Do_timeout( the_thread );
     42    _Thread_Wait_cancel( the_thread, &queue_context );
     43
     44    the_thread->Wait.return_code = STATUS_TIMEOUT;
    5645
    5746    wait_class = wait_flags & THREAD_WAIT_CLASS_MASK;
     
    7766  }
    7867
    79   _Thread_Lock_release( thread_lock, &lock_context );
     68  _Thread_Wait_release( the_thread, &queue_context );
    8069
    8170  if ( unblock ) {
     71    _Thread_Wait_tranquilize( the_thread );
    8272    _Thread_Unblock( the_thread );
    8373
  • testsuites/sptests/spthreadq01/init.c

    r3a58dc8 r1fcac5a  
    6969static rtems_id get_wait_id(test_context *ctx)
    7070{
    71   ISR_lock_Context lock_context;
    72   void *lock;
     71  Thread_queue_Context queue_context;
    7372  rtems_id id;
    7473
    75   lock = _Thread_Lock_acquire(ctx->master, &lock_context);
     74  _Thread_Wait_acquire(ctx->master, &queue_context);
    7675  id = _Thread_Wait_get_id(ctx->master);
    77   _Thread_Lock_release(lock, &lock_context);
     76  _Thread_Wait_release(ctx->master, &queue_context);
    7877
    7978  return id;
Note: See TracChangeset for help on using the changeset viewer.