Changeset 7f4ee2b in rtems


Ignore:
Timestamp:
Apr 22, 2016, 12:37:13 PM (4 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
master
Children:
08aa94a
Parents:
f4c59d0
git-author:
Sebastian Huber <sebastian.huber@…> (04/22/16 12:37:13)
git-committer:
Sebastian Huber <sebastian.huber@…> (04/27/16 06:50:41)
Message:

posix: Avoid Giant lock for condition variables

Update #2555.

Location:
cpukit
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • cpukit/posix/include/rtems/posix/cond.h

    rf4c59d0 r7f4ee2b  
    4444   Objects_Control       Object;
    4545   Thread_queue_Control  Wait_queue;
    46    int                   process_shared;
    47    pthread_mutex_t       Mutex;
     46   pthread_mutex_t       mutex;
    4847}  POSIX_Condition_variables_Control;
    4948
  • cpukit/posix/include/rtems/posix/condimpl.h

    rf4c59d0 r7f4ee2b  
    2121#include <rtems/score/objectimpl.h>
    2222#include <rtems/score/threadqimpl.h>
    23 #include <rtems/score/watchdog.h>
     23
     24#include <errno.h>
    2425
    2526#ifdef __cplusplus
     
    4647extern const pthread_condattr_t _POSIX_Condition_variables_Default_attributes;
    4748
     49RTEMS_INLINE_ROUTINE void _POSIX_Condition_variables_Initialize(
     50  POSIX_Condition_variables_Control *the_cond
     51)
     52{
     53  _Thread_queue_Initialize( &the_cond->Wait_queue );
     54  the_cond->mutex = POSIX_CONDITION_VARIABLES_NO_MUTEX;
     55}
     56
     57RTEMS_INLINE_ROUTINE void _POSIX_Condition_variables_Destroy(
     58  POSIX_Condition_variables_Control *the_cond
     59)
     60{
     61  _Thread_queue_Destroy( &the_cond->Wait_queue );
     62}
     63
     64RTEMS_INLINE_ROUTINE void _POSIX_Condition_variables_Acquire_critical(
     65  POSIX_Condition_variables_Control *the_cond,
     66  ISR_lock_Context                  *lock_context
     67)
     68{
     69  _Thread_queue_Acquire_critical( &the_cond->Wait_queue, lock_context );
     70}
     71
     72RTEMS_INLINE_ROUTINE void _POSIX_Condition_variables_Release(
     73  POSIX_Condition_variables_Control *the_cond,
     74  ISR_lock_Context                  *lock_context
     75)
     76{
     77  _Thread_queue_Release( &the_cond->Wait_queue, lock_context );
     78}
     79
    4880/**
    4981 *  @brief POSIX Condition Variable Allocate
     
    69101)
    70102{
    71   _Thread_queue_Destroy( &the_condition_variable->Wait_queue );
    72103  _Objects_Free(
    73104    &_POSIX_Condition_variables_Information,
     
    76107}
    77108
    78 /**
    79  *  @brief POSIX Condition Variable Get
    80  *
    81  *  This function maps condition variable IDs to condition variable control
    82  *  blocks.  If ID corresponds to a local condition variable, then it returns
    83  *  the_condition variable control pointer which maps to ID and location
    84  *  is set to OBJECTS_LOCAL.  if the condition variable ID is global and
    85  *  resides on a remote node, then location is set to OBJECTS_REMOTE,
    86  *  and the_condition variable is undefined.  Otherwise, location is set
    87  *  to OBJECTS_ERROR and the_condition variable is undefined.
    88  */
    89 POSIX_Condition_variables_Control *_POSIX_Condition_variables_Get (
    90   pthread_cond_t    *cond,
    91   Objects_Locations *location
     109POSIX_Condition_variables_Control *_POSIX_Condition_variables_Get(
     110  pthread_cond_t   *cond,
     111  ISR_lock_Context *lock_context
    92112);
    93113
  • cpukit/posix/include/rtems/posix/muteximpl.h

    rf4c59d0 r7f4ee2b  
    132132);
    133133
     134RTEMS_INLINE_ROUTINE POSIX_Mutex_Control *_POSIX_Mutex_Get_no_protection(
     135  const pthread_mutex_t *mutex
     136)
     137{
     138  return (POSIX_Mutex_Control *) _Objects_Get_no_protection(
     139    (Objects_Id) *mutex,
     140    &_POSIX_Mutex_Information
     141  );
     142}
     143
    134144#ifdef __cplusplus
    135145}
  • cpukit/posix/src/condbroadcast.c

    rf4c59d0 r7f4ee2b  
    1919#endif
    2020
    21 #include <pthread.h>
    22 #include <errno.h>
    23 
    24 #include <rtems/system.h>
    25 #include <rtems/score/watchdog.h>
    2621#include <rtems/posix/condimpl.h>
    27 #include <rtems/posix/muteximpl.h>
    2822
    2923/**
  • cpukit/posix/src/conddestroy.c

    rf4c59d0 r7f4ee2b  
    1919#endif
    2020
    21 #include <pthread.h>
    22 #include <errno.h>
    23 
    24 #include <rtems/system.h>
    25 #include <rtems/score/watchdog.h>
    2621#include <rtems/posix/condimpl.h>
    27 #include <rtems/posix/muteximpl.h>
    2822
    2923/**
     
    3630{
    3731  POSIX_Condition_variables_Control *the_cond;
    38   Objects_Locations                  location;
     32  ISR_lock_Context                   lock_context;
    3933
    4034  _Objects_Allocator_lock();
    41   the_cond = _POSIX_Condition_variables_Get( cond, &location );
    42   switch ( location ) {
     35  the_cond = _POSIX_Condition_variables_Get( cond, &lock_context );
    4336
    44     case OBJECTS_LOCAL:
    45 
    46       if (
    47         _Thread_queue_First(
    48           &the_cond->Wait_queue,
    49           POSIX_CONDITION_VARIABLES_TQ_OPERATIONS
    50         )
    51       ) {
    52         _Objects_Put( &the_cond->Object );
    53         _Objects_Allocator_unlock();
    54         return EBUSY;
    55       }
    56 
    57       _Objects_Close(
    58         &_POSIX_Condition_variables_Information,
    59         &the_cond->Object
    60       );
    61       _Objects_Put( &the_cond->Object );
    62       _POSIX_Condition_variables_Free( the_cond );
    63       _Objects_Allocator_unlock();
    64       return 0;
    65 
    66 #if defined(RTEMS_MULTIPROCESSING)
    67     case OBJECTS_REMOTE:
    68 #endif
    69     case OBJECTS_ERROR:
    70       break;
     37  if ( the_cond == NULL ) {
     38    _Objects_Allocator_unlock();
     39    return EINVAL;
    7140  }
    7241
     42  _POSIX_Condition_variables_Acquire_critical( the_cond, &lock_context );
     43
     44  if ( !_Thread_queue_Is_empty( &the_cond->Wait_queue.Queue ) ) {
     45    _POSIX_Condition_variables_Release( the_cond, &lock_context );
     46    _Objects_Allocator_unlock();
     47    return EBUSY;
     48  }
     49
     50  _Objects_Close(
     51    &_POSIX_Condition_variables_Information,
     52    &the_cond->Object
     53  );
     54  _POSIX_Condition_variables_Release( the_cond, &lock_context );
     55  _POSIX_Condition_variables_Destroy( the_cond );
     56  _POSIX_Condition_variables_Free( the_cond );
    7357  _Objects_Allocator_unlock();
    74 
    75   return EINVAL;
     58  return 0;
    7659}
  • cpukit/posix/src/condget.c

    rf4c59d0 r7f4ee2b  
    1212#endif
    1313
    14 #include <pthread.h>
    15 #include <errno.h>
     14#include <rtems/posix/condimpl.h>
    1615
    17 #include <rtems/system.h>
    18 #include <rtems/score/watchdog.h>
    19 #include <rtems/posix/condimpl.h>
    20 #include <rtems/posix/muteximpl.h>
    21 
    22 POSIX_Condition_variables_Control *_POSIX_Condition_variables_Get (
    23   pthread_cond_t    *cond,
    24   Objects_Locations *location
     16static bool _POSIX_Condition_variables_Check_id_and_auto_init(
     17  pthread_cond_t *cond
    2518)
    2619{
    27   int status;
    28 
    29   if ( !cond ) {
    30     *location = OBJECTS_ERROR;
    31     return (POSIX_Condition_variables_Control *) 0;
     20  if ( cond == NULL ) {
     21    return false;
    3222  }
    3323
    3424  if ( *cond == PTHREAD_COND_INITIALIZER ) {
    35     /*
    36      *  Do an "auto-create" here.
    37      */
     25    int eno;
    3826
    39     status = pthread_cond_init( cond, 0 );
    40     if ( status ) {
    41       *location = OBJECTS_ERROR;
    42       return (POSIX_Condition_variables_Control *) 0;
     27    _Once_Lock();
     28
     29    if ( *cond == PTHREAD_COND_INITIALIZER ) {
     30      eno = pthread_cond_init( cond, NULL );
     31    } else {
     32      eno = 0;
     33    }
     34
     35    _Once_Unlock();
     36
     37    if ( eno != 0 ) {
     38      return false;
    4339    }
    4440  }
    4541
    46   /*
    47    *  Now call Objects_Get()
    48    */
    49   return (POSIX_Condition_variables_Control *)_Objects_Get(
     42  return true;
     43}
     44
     45POSIX_Condition_variables_Control *_POSIX_Condition_variables_Get(
     46  pthread_cond_t   *cond,
     47  ISR_lock_Context *lock_context
     48)
     49{
     50  if ( !_POSIX_Condition_variables_Check_id_and_auto_init( cond ) ) {
     51    return NULL;
     52  }
     53
     54  return (POSIX_Condition_variables_Control *) _Objects_Get_local(
     55    (Objects_Id) *cond,
    5056    &_POSIX_Condition_variables_Information,
    51     (Objects_Id) *cond,
    52     location
     57    lock_context
    5358  );
    5459}
    55 
  • cpukit/posix/src/condinit.c

    rf4c59d0 r7f4ee2b  
    1919#endif
    2020
    21 #include <pthread.h>
    22 #include <errno.h>
    23 
    24 #include <rtems/system.h>
    25 #include <rtems/score/watchdog.h>
    2621#include <rtems/posix/condimpl.h>
    27 #include <rtems/posix/muteximpl.h>
    2822
    2923/**
     
    5852  }
    5953
    60   the_cond->process_shared  = the_attr->process_shared;
    61 
    62   the_cond->Mutex = POSIX_CONDITION_VARIABLES_NO_MUTEX;
    63 
    64   _Thread_queue_Initialize( &the_cond->Wait_queue );
     54  _POSIX_Condition_variables_Initialize( the_cond );
    6555
    6656  _Objects_Open_u32(
  • cpukit/posix/src/condsignal.c

    rf4c59d0 r7f4ee2b  
    1919#endif
    2020
    21 #include <pthread.h>
    22 #include <errno.h>
    23 
    24 #include <rtems/system.h>
    25 #include <rtems/score/watchdog.h>
    2621#include <rtems/posix/condimpl.h>
    27 #include <rtems/posix/muteximpl.h>
    2822
    2923/**
  • cpukit/posix/src/condsignalsupp.c

    rf4c59d0 r7f4ee2b  
    1919#endif
    2020
    21 #include <pthread.h>
    22 #include <errno.h>
    23 
    24 #include <rtems/system.h>
    25 #include <rtems/score/watchdog.h>
    2621#include <rtems/posix/condimpl.h>
    27 #include <rtems/posix/muteximpl.h>
    2822
    2923/*
     
    3933)
    4034{
    41   POSIX_Condition_variables_Control          *the_cond;
    42   Objects_Locations                           location;
    43   Thread_Control                             *the_thread;
     35  Thread_Control *the_thread;
    4436
    45   the_cond = _POSIX_Condition_variables_Get( cond, &location );
    46   switch ( location ) {
     37  do {
     38    POSIX_Condition_variables_Control *the_cond;
     39    ISR_lock_Context                   lock_context;
    4740
    48     case OBJECTS_LOCAL:
    49       do {
    50         the_thread = _Thread_queue_Dequeue(
    51           &the_cond->Wait_queue,
    52           POSIX_CONDITION_VARIABLES_TQ_OPERATIONS,
    53           NULL,
    54           0
    55         );
    56         if ( !the_thread )
    57           the_cond->Mutex = POSIX_CONDITION_VARIABLES_NO_MUTEX;
    58       } while ( is_broadcast && the_thread );
     41    the_cond = _POSIX_Condition_variables_Get( cond, &lock_context );
    5942
    60       _Objects_Put( &the_cond->Object );
     43    if ( the_cond == NULL ) {
     44      return EINVAL;
     45    }
    6146
    62       return 0;
     47    _POSIX_Condition_variables_Acquire_critical( the_cond, &lock_context );
    6348
    64 #if defined(RTEMS_MULTIPROCESSING)
    65     case OBJECTS_REMOTE:
    66 #endif
    67     case OBJECTS_ERROR:
    68       break;
    69   }
     49    the_thread = _Thread_queue_First_locked(
     50      &the_cond->Wait_queue,
     51      POSIX_CONDITION_VARIABLES_TQ_OPERATIONS
     52    );
    7053
    71   return EINVAL;
     54    if ( the_thread != NULL ) {
     55      _Thread_queue_Extract_critical(
     56        &the_cond->Wait_queue.Queue,
     57        POSIX_CONDITION_VARIABLES_TQ_OPERATIONS,
     58        the_thread,
     59        NULL,
     60        0,
     61        &lock_context
     62      );
     63    } else {
     64      the_cond->mutex = POSIX_CONDITION_VARIABLES_NO_MUTEX;
     65      _POSIX_Condition_variables_Release( the_cond, &lock_context );
     66    }
     67  } while ( is_broadcast && the_thread != NULL );
     68
     69  return 0;
    7270}
  • cpukit/posix/src/condtimedwait.c

    rf4c59d0 r7f4ee2b  
    1919#endif
    2020
    21 #include <pthread.h>
    22 #include <errno.h>
    23 
    24 #include <rtems/system.h>
     21#include <rtems/posix/condimpl.h>
    2522#include <rtems/score/todimpl.h>
    26 #include <rtems/posix/condimpl.h>
    27 #include <rtems/posix/muteximpl.h>
    2823
    2924/*
  • cpukit/posix/src/condwait.c

    rf4c59d0 r7f4ee2b  
    1919#endif
    2020
    21 #include <pthread.h>
    22 #include <errno.h>
    23 
    24 #include <rtems/system.h>
    25 #include <rtems/score/watchdog.h>
    2621#include <rtems/posix/condimpl.h>
    27 #include <rtems/posix/muteximpl.h>
    2822
    2923/*
  • cpukit/posix/src/condwaitsupp.c

    rf4c59d0 r7f4ee2b  
    1919#endif
    2020
    21 #include <pthread.h>
    22 #include <errno.h>
    23 
    24 #include <rtems/system.h>
    25 #include <rtems/score/watchdog.h>
     21#include <rtems/posix/condimpl.h>
     22#include <rtems/posix/muteximpl.h>
     23#include <rtems/score/assert.h>
    2624#include <rtems/score/statesimpl.h>
    2725#include <rtems/score/threadimpl.h>
    28 #include <rtems/posix/condimpl.h>
    29 #include <rtems/posix/muteximpl.h>
    3026
    3127THREAD_WAIT_QUEUE_OBJECT_ASSERT(
     
    4238{
    4339  POSIX_Condition_variables_Control *the_cond;
    44   Objects_Locations                  location;
     40  POSIX_Mutex_Control               *the_mutex;
     41  ISR_lock_Context                   lock_context;
    4542  int                                status;
    4643  int                                mutex_status;
     44  CORE_mutex_Status                  core_mutex_status;
     45  Per_CPU_Control                   *cpu_self;
    4746  Thread_Control                    *executing;
    4847
    49   the_cond = _POSIX_Condition_variables_Get( cond, &location );
    50   switch ( location ) {
    51 
    52     case OBJECTS_LOCAL:
    53 
    54       if ( the_cond->Mutex && ( the_cond->Mutex != *mutex ) ) {
    55         _Objects_Put( &the_cond->Object );
    56         return EINVAL;
    57       }
    58 
    59 
    60       mutex_status = pthread_mutex_unlock( mutex );
    61       /*
    62        *  Historically, we ignored the return code since the behavior
    63        *  is undefined by POSIX. But GNU/Linux returns EPERM in this
    64        *  case, so we follow their lead.
    65        */
    66       if ( mutex_status ) {
    67         _Objects_Put( &the_cond->Object );
    68         return EPERM;
    69       }
    70 
    71       if ( !already_timedout ) {
    72         the_cond->Mutex = *mutex;
    73 
    74         executing = _Thread_Executing;
    75         executing->Wait.return_code = 0;
    76 
    77         _Thread_queue_Enqueue(
    78           &the_cond->Wait_queue,
    79           POSIX_CONDITION_VARIABLES_TQ_OPERATIONS,
    80           executing,
    81           STATES_WAITING_FOR_CONDITION_VARIABLE
    82             | STATES_INTERRUPTIBLE_BY_SIGNAL,
    83           timeout,
    84           ETIMEDOUT
    85         );
    86 
    87         _Objects_Put( &the_cond->Object );
    88 
    89         /*
    90          *  Switch ourself out because we blocked as a result of the
    91          *  _Thread_queue_Enqueue.
    92          */
    93 
    94         /*
    95          *  If the thread is interrupted, while in the thread queue, by
    96          *  a POSIX signal, then pthread_cond_wait returns spuriously,
    97          *  according to the POSIX standard. It means that pthread_cond_wait
    98          *  returns a success status, except for the fact that it was not
    99          *  woken up a pthread_cond_signal or a pthread_cond_broadcast.
    100          */
    101         status = executing->Wait.return_code;
    102         if ( status == EINTR )
    103           status = 0;
    104 
    105       } else {
    106         _Objects_Put( &the_cond->Object );
    107         status = ETIMEDOUT;
    108       }
    109 
    110       /*
    111        *  When we get here the dispatch disable level is 0.
    112        */
    113 
    114       mutex_status = pthread_mutex_lock( mutex );
    115       if ( mutex_status )
    116         return EINVAL;
    117 
    118       return status;
    119 
    120 #if defined(RTEMS_MULTIPROCESSING)
    121     case OBJECTS_REMOTE:
    122 #endif
    123     case OBJECTS_ERROR:
    124       break;
     48  if ( mutex == NULL ) {
     49    return EINVAL;
    12550  }
    12651
    127   return EINVAL;
     52  the_cond = _POSIX_Condition_variables_Get( cond, &lock_context );
     53
     54  if ( the_cond == NULL ) {
     55    return EINVAL;
     56  }
     57
     58  _POSIX_Condition_variables_Acquire_critical( the_cond, &lock_context );
     59
     60  if (
     61    the_cond->mutex != POSIX_CONDITION_VARIABLES_NO_MUTEX
     62      && the_cond->mutex != *mutex
     63  ) {
     64    _POSIX_Condition_variables_Release( the_cond, &lock_context );
     65    return EINVAL;
     66  }
     67
     68  the_cond->mutex = *mutex;
     69
     70  cpu_self = _Thread_Dispatch_disable_critical( &lock_context );
     71  executing = _Per_CPU_Get_executing( cpu_self );
     72
     73  /*
     74   *  Historically, we ignored the unlock status since the behavior
     75   *  is undefined by POSIX. But GNU/Linux returns EPERM in this
     76   *  case, so we follow their lead.
     77   */
     78
     79  the_mutex = _POSIX_Mutex_Get_no_protection( mutex );
     80  if (
     81    the_mutex == NULL
     82      || !_CORE_mutex_Is_owner( &the_mutex->Mutex, executing )
     83  ) {
     84    _POSIX_Condition_variables_Release( the_cond, &lock_context );
     85    _Thread_Dispatch_enable( cpu_self );
     86    return EPERM;
     87  }
     88
     89  if ( !already_timedout ) {
     90    executing->Wait.return_code = 0;
     91    _Thread_queue_Enqueue_critical(
     92      &the_cond->Wait_queue.Queue,
     93      POSIX_CONDITION_VARIABLES_TQ_OPERATIONS,
     94      executing,
     95      STATES_WAITING_FOR_CONDITION_VARIABLE,
     96      timeout,
     97      ETIMEDOUT,
     98      &lock_context
     99    );
     100  } else {
     101    _POSIX_Condition_variables_Release( the_cond, &lock_context );
     102    executing->Wait.return_code = ETIMEDOUT;
     103  }
     104
     105  _ISR_lock_ISR_disable( &lock_context );
     106  core_mutex_status = _CORE_mutex_Surrender(
     107    &the_mutex->Mutex,
     108    NULL,
     109    0,
     110    &lock_context
     111  );
     112  _Assert( core_mutex_status == CORE_MUTEX_STATUS_SUCCESSFUL );
     113  (void) core_mutex_status;
     114
     115  /*
     116   *  Switch ourself out because we blocked as a result of the
     117   *  _Thread_queue_Enqueue_critical().
     118   */
     119
     120  _Thread_Dispatch_enable( cpu_self );
     121
     122  status = (int) executing->Wait.return_code;
     123
     124  /*
     125   *  If the thread is interrupted, while in the thread queue, by
     126   *  a POSIX signal, then pthread_cond_wait returns spuriously,
     127   *  according to the POSIX standard. It means that pthread_cond_wait
     128   *  returns a success status, except for the fact that it was not
     129   *  woken up a pthread_cond_signal() or a pthread_cond_broadcast().
     130   */
     131
     132  if ( status == EINTR ) {
     133    status = 0;
     134  }
     135
     136  /*
     137   *  When we get here the dispatch disable level is 0.
     138   */
     139
     140  mutex_status = pthread_mutex_lock( mutex );
     141  if ( mutex_status != 0 ) {
     142    return EINVAL;
     143  }
     144
     145  return status;
    128146}
  • cpukit/score/include/rtems/score/coremuteximpl.h

    rf4c59d0 r7f4ee2b  
    386386}
    387387
     388RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_owner(
     389  const CORE_mutex_Control *the_mutex,
     390  const Thread_Control     *the_thread
     391)
     392{
     393  return the_mutex->holder == the_thread;
     394}
     395
    388396/**
    389397 * @brief Does core mutex use FIFO blocking.
Note: See TracChangeset for help on using the changeset viewer.