Status_Control _CORE_RWLock_Seize_for_writing(
  CORE_RWLock_Control  *the_rwlock,
  Thread_Control       *executing,
  bool                  wait,
  Watchdog_Interval     timeout,
  Thread_queue_Context *queue_context
)
{
  /*
   *  If unlocked, then OK to read.
   *  Otherwise, we have to block.
   *  If locked for reading and no waiters, then OK to read.
   *  If any thread is waiting, then we wait.
   */

  _CORE_RWLock_Acquire_critical( the_rwlock, queue_context );

  switch ( the_rwlock->current_state ) {
    case CORE_RWLOCK_UNLOCKED:
      the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_WRITING;
      _CORE_RWLock_Release( the_rwlock, queue_context );
      return STATUS_SUCCESSFUL;

    case CORE_RWLOCK_LOCKED_FOR_READING:
    case CORE_RWLOCK_LOCKED_FOR_WRITING:
      break;
  }

  /*
   *  If the thread is not willing to wait, then return immediately.
   */

  if ( !wait ) {
    _CORE_RWLock_Release( the_rwlock, queue_context );
    return STATUS_UNAVAILABLE;
  }

  /*
   *  We need to wait to enter this critical section
   */

  executing->Wait.option = CORE_RWLOCK_THREAD_WAITING_FOR_WRITE;

  _Thread_queue_Context_set_expected_level( queue_context, 1 );
  _Thread_queue_Enqueue_critical(
     &the_rwlock->Wait_queue.Queue,
     CORE_RWLOCK_TQ_OPERATIONS,
     executing,
     STATES_WAITING_FOR_RWLOCK,
     timeout,
     queue_context
  );
  return _Thread_Wait_get_status( executing );
}
Exemplo n.º 2
0
Status_Control _CORE_RWLock_Surrender(
  CORE_RWLock_Control  *the_rwlock,
  Thread_queue_Context *queue_context
)
{
  /*
   *  If unlocked, then OK to read.
   *  Otherwise, we have to block.
   *  If locked for reading and no waiters, then OK to read.
   *  If any thread is waiting, then we wait.
   */

  _CORE_RWLock_Acquire_critical( the_rwlock, queue_context );

  if ( the_rwlock->current_state == CORE_RWLOCK_UNLOCKED){
    /* This is an error at the caller site */
    _CORE_RWLock_Release( the_rwlock, queue_context );
    return STATUS_SUCCESSFUL;
  }

  if ( the_rwlock->current_state == CORE_RWLOCK_LOCKED_FOR_READING ) {
    the_rwlock->number_of_readers -= 1;

    if ( the_rwlock->number_of_readers != 0 ) {
      /* must be unlocked again */
      _CORE_RWLock_Release( the_rwlock, queue_context );
      return STATUS_SUCCESSFUL;
    }
  }

  _Assert(
    the_rwlock->current_state == CORE_RWLOCK_LOCKED_FOR_WRITING
      || ( the_rwlock->current_state == CORE_RWLOCK_LOCKED_FOR_READING
        && the_rwlock->number_of_readers == 0 )
  );

  /*
   * Implicitly transition to "unlocked" and find another thread interested
   * in obtaining this rwlock.
   */
  the_rwlock->current_state = CORE_RWLOCK_UNLOCKED;

  _Thread_queue_Flush_critical(
    &the_rwlock->Wait_queue.Queue,
    CORE_RWLOCK_TQ_OPERATIONS,
    _CORE_RWLock_Flush_filter,
    queue_context
  );
  return STATUS_SUCCESSFUL;
}
Exemplo n.º 3
0
int pthread_rwlock_destroy(
  pthread_rwlock_t *rwlock
)
{
  POSIX_RWLock_Control *the_rwlock;
  ISR_lock_Context      lock_context;

  _Objects_Allocator_lock();
  the_rwlock = _POSIX_RWLock_Get( rwlock, &lock_context );

  if ( the_rwlock == NULL ) {
    _Objects_Allocator_unlock();
    return EINVAL;
  }

  _CORE_RWLock_Acquire_critical( &the_rwlock->RWLock, &lock_context );

  /*
   *  If there is at least one thread waiting, then do not delete it.
   */

  if ( !_Thread_queue_Is_empty( &the_rwlock->RWLock.Wait_queue.Queue ) ) {
    _CORE_RWLock_Release( &the_rwlock->RWLock, &lock_context );
    _Objects_Allocator_unlock();
    return EBUSY;
  }

  /*
   *  POSIX doesn't require behavior when it is locked.
   */

  _Objects_Close( &_POSIX_RWLock_Information, &the_rwlock->Object );
  _CORE_RWLock_Release( &the_rwlock->RWLock, &lock_context );
  _POSIX_RWLock_Free( the_rwlock );
  _Objects_Allocator_unlock();
  return 0;
}