Ejemplo n.º 1
0
static void _Mutex_Acquire_slow(
  Mutex_Control        *mutex,
  Thread_Control       *owner,
  Thread_Control       *executing,
  ISR_Level             level,
  Thread_queue_Context *queue_context
)
{
  _Thread_queue_Context_set_thread_state(
    queue_context,
    STATES_WAITING_FOR_SYS_LOCK_MUTEX
  );
  _Thread_queue_Context_set_do_nothing_enqueue_callout( queue_context );
  _Thread_queue_Context_set_deadlock_callout(
    queue_context,
    _Thread_queue_Deadlock_fatal
  );
  _Thread_queue_Context_set_ISR_level( queue_context, level );
  _Thread_queue_Enqueue(
    &mutex->Queue.Queue,
    MUTEX_TQ_OPERATIONS,
    executing,
    queue_context
  );
}
Ejemplo n.º 2
0
void _CORE_barrier_Wait(
    CORE_barrier_Control                *the_barrier,
    Thread_Control                      *executing,
    Objects_Id                           id,
    bool                                 wait,
    Watchdog_Interval                    timeout,
    CORE_barrier_API_mp_support_callout  api_barrier_mp_support
)
{
    ISR_Level       level;

    executing->Wait.return_code = CORE_BARRIER_STATUS_SUCCESSFUL;
    _ISR_Disable( level );
    the_barrier->number_of_waiting_threads++;
    if ( _CORE_barrier_Is_automatic( &the_barrier->Attributes ) ) {
        if ( the_barrier->number_of_waiting_threads ==
                the_barrier->Attributes.maximum_count) {
            executing->Wait.return_code = CORE_BARRIER_STATUS_AUTOMATICALLY_RELEASED;
            _ISR_Enable( level );
            _CORE_barrier_Release( the_barrier, id, api_barrier_mp_support );
            return;
        }
    }

    _Thread_queue_Enter_critical_section( &the_barrier->Wait_queue );
    executing->Wait.queue          = &the_barrier->Wait_queue;
    executing->Wait.id             = id;
    _ISR_Enable( level );

    _Thread_queue_Enqueue( &the_barrier->Wait_queue, timeout );
}
Ejemplo n.º 3
0
void _CORE_mutex_Seize_interrupt_blocking(
  CORE_mutex_Control  *the_mutex,
  Watchdog_Interval    timeout
)
{
  Thread_Control   *executing;

  executing = _Thread_Executing;
  if ( _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) ) {
    if ( _Scheduler_Is_priority_higher_than(
         executing->current_priority,
         the_mutex->holder->current_priority)) {
      _Thread_Change_priority(
        the_mutex->holder,
        executing->current_priority,
        false
      );
    }
  }

  the_mutex->blocked_count++;
  _Thread_queue_Enqueue( &the_mutex->Wait_queue, timeout );

  _Thread_Enable_dispatch();
}
Ejemplo n.º 4
0
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
)
{
  if ( wait ) {
    _Thread_queue_Context_set_thread_state(
      queue_context,
      STATES_WAITING_FOR_MUTEX
    );
    _Thread_queue_Context_set_do_nothing_enqueue_callout( queue_context );
    _Thread_queue_Context_set_deadlock_callout(
      queue_context,
      _Thread_queue_Deadlock_status
    );
    _Thread_queue_Enqueue(
      &the_mutex->Wait_queue.Queue,
      operations,
      executing,
      queue_context
    );
    return _Thread_Wait_get_status( executing );
  } else {
    _CORE_mutex_Release( the_mutex, queue_context );
    return STATUS_UNAVAILABLE;
  }
}
Ejemplo n.º 5
0
uint32_t   _MPCI_Send_request_packet (
  uint32_t            destination,
  MP_packet_Prefix   *the_packet,
  States_Control      extra_state
)
{
  Thread_Control *executing = _Thread_Executing;

  the_packet->source_tid      = executing->Object.id;
  the_packet->source_priority = executing->current_priority;
  the_packet->to_convert =
     ( the_packet->to_convert - sizeof(MP_packet_Prefix) ) / sizeof(uint32_t);

  executing->Wait.id = the_packet->id;

  executing->Wait.queue = &_MPCI_Remote_blocked_threads;

  _Thread_Disable_dispatch();

    (*_MPCI_table->send_packet)( destination, the_packet );

    _Thread_queue_Enter_critical_section( &_MPCI_Remote_blocked_threads );

    /*
     *  See if we need a default timeout
     */

    if (the_packet->timeout == MPCI_DEFAULT_TIMEOUT)
        the_packet->timeout = _MPCI_table->default_timeout;

    _Thread_queue_Enqueue(
      &_MPCI_Remote_blocked_threads,
      executing,
      the_packet->timeout
    );

    executing->current_state =
      _States_Set( extra_state, executing->current_state );

  _Thread_Enable_dispatch();

  return executing->Wait.return_code;
}
Ejemplo n.º 6
0
void _CORE_semaphore_Seize(
  CORE_semaphore_Control *the_semaphore,
  Objects_Id              id,
  bool                    wait,
  Watchdog_Interval       timeout
)
{
  Thread_Control *executing;
  ISR_Level       level;

  executing = _Thread_Executing;
  executing->Wait.return_code = CORE_SEMAPHORE_STATUS_SUCCESSFUL;
  _ISR_Disable( level );
  if ( the_semaphore->count != 0 ) {
    the_semaphore->count -= 1;
    _ISR_Enable( level );
    return;
  }

  /*
   *  If the semaphore was not available and the caller was not willing
   *  to block, then return immediately with a status indicating that
   *  the semaphore was not available and the caller never blocked.
   */
  if ( !wait ) {
    _ISR_Enable( level );
    executing->Wait.return_code = CORE_SEMAPHORE_STATUS_UNSATISFIED_NOWAIT;
    return;
  }

  /*
   *  If the semaphore is not available and the caller is willing to
   *  block, then we now block the caller with optional timeout.
   */
  _Thread_queue_Enter_critical_section( &the_semaphore->Wait_queue );
  executing->Wait.queue = &the_semaphore->Wait_queue;
  executing->Wait.id    = id;
  _ISR_Enable( level );
  _Thread_queue_Enqueue( &the_semaphore->Wait_queue, timeout );
}
Ejemplo n.º 7
0
void _Thread_Join(
  Thread_Control       *the_thread,
  States_Control        waiting_for_join,
  Thread_Control       *executing,
  Thread_queue_Context *queue_context
)
{
  _Assert( the_thread != executing );
  _Assert( _Thread_State_is_owner( the_thread ) );

#if defined(RTEMS_POSIX_API)
  executing->Wait.return_argument = NULL;
#endif

  _Thread_queue_Context_set_thread_state( queue_context, waiting_for_join );
  _Thread_queue_Enqueue(
    &the_thread->Join_queue.Queue,
    THREAD_JOIN_TQ_OPERATIONS,
    executing,
    queue_context
  );
}
Ejemplo n.º 8
0
int _POSIX_Condition_variables_Wait_support(
  pthread_cond_t            *cond,
  pthread_mutex_t           *mutex,
  Watchdog_Interval          timeout,
  bool                       already_timedout
)
{
  POSIX_Condition_variables_Control          *the_cond;
  POSIX_Mutex_Control                        *the_mutex;
  Objects_Locations                           location;
  int                                         status;
  int                                         mutex_status;
  Thread_Control                             *executing;

  the_mutex = _POSIX_Mutex_Get( mutex, &location );
  if ( !the_mutex ) {
     return EINVAL;
  }

  _Objects_Put_without_thread_dispatch( &the_mutex->Object );

  the_cond = _POSIX_Condition_variables_Get( cond, &location );
  switch ( location ) {

    case OBJECTS_LOCAL:

      if ( the_cond->Mutex && ( the_cond->Mutex != *mutex ) ) {
        _Objects_Put( &the_cond->Object );
        return EINVAL;
      }


      mutex_status = pthread_mutex_unlock( mutex );
      /*
       *  Historically, we ignored the return code since the behavior
       *  is undefined by POSIX. But GNU/Linux returns EPERM in this
       *  case, so we follow their lead.
       */
      if ( mutex_status ) {
        _Objects_Put( &the_cond->Object );
        return EPERM;
      }

      if ( !already_timedout ) {
        the_cond->Mutex = *mutex;

        executing = _Thread_Executing;
        executing->Wait.return_code = 0;
        executing->Wait.id          = *cond;

        _Thread_queue_Enqueue(
          &the_cond->Wait_queue,
          executing,
          STATES_WAITING_FOR_CONDITION_VARIABLE
            | STATES_INTERRUPTIBLE_BY_SIGNAL,
          timeout,
          ETIMEDOUT
        );

        _Objects_Put( &the_cond->Object );

        /*
         *  Switch ourself out because we blocked as a result of the
         *  _Thread_queue_Enqueue.
         */

        /*
         *  If the thread is interrupted, while in the thread queue, by
         *  a POSIX signal, then pthread_cond_wait returns spuriously,
         *  according to the POSIX standard. It means that pthread_cond_wait
         *  returns a success status, except for the fact that it was not
         *  woken up a pthread_cond_signal or a pthread_cond_broadcast.
         */
        status = executing->Wait.return_code;
        if ( status == EINTR )
          status = 0;

      } else {
        _Objects_Put( &the_cond->Object );
        status = ETIMEDOUT;
      }

      /*
       *  When we get here the dispatch disable level is 0.
       */

      mutex_status = pthread_mutex_lock( mutex );
      if ( mutex_status )
        return EINVAL;

      return status;

#if defined(RTEMS_MULTIPROCESSING)
    case OBJECTS_REMOTE:
#endif
    case OBJECTS_ERROR:
      break;
  }

  return EINVAL;
}
int sigtimedwait(
  const sigset_t         *set,
  siginfo_t              *info,
  const struct timespec  *timeout
)
{
  Thread_Control    *the_thread;
  POSIX_API_Control *api;
  Watchdog_Interval  interval;
  siginfo_t          signal_information;
  siginfo_t         *the_info;
  int                signo;
  ISR_Level          level;

  /*
   *  Error check parameters before disabling interrupts.
   */
  if ( !set )
    rtems_set_errno_and_return_minus_one( EINVAL );

  /*  NOTE: This is very specifically a RELATIVE not ABSOLUTE time
   *        in the Open Group specification.
   */

  interval = 0;
  if ( timeout ) {

    if ( !_Timespec_Is_valid( timeout ) )
      rtems_set_errno_and_return_minus_one( EINVAL );

    interval = _Timespec_To_ticks( timeout );

    if ( !interval )
      rtems_set_errno_and_return_minus_one( EINVAL );
  }

  /*
   *  Initialize local variables.
   */

  the_info = ( info ) ? info : &signal_information;

  the_thread = _Thread_Executing;

  api = the_thread->API_Extensions[ THREAD_API_POSIX ];

  /*
   *  What if they are already pending?
   */

  /* API signals pending? */

  _ISR_Disable( level );
  if ( *set & api->signals_pending ) {
    /* XXX real info later */
    the_info->si_signo = _POSIX_signals_Get_highest( api->signals_pending );
    _POSIX_signals_Clear_signals(
      api,
      the_info->si_signo,
      the_info,
      false,
      false
    );
    _ISR_Enable( level );

    the_info->si_code = SI_USER;
    the_info->si_value.sival_int = 0;
    return the_info->si_signo;
  }

  /* Process pending signals? */

  if ( *set & _POSIX_signals_Pending ) {
    signo = _POSIX_signals_Get_highest( _POSIX_signals_Pending );
    _POSIX_signals_Clear_signals( api, signo, the_info, true, false );
    _ISR_Enable( level );

    the_info->si_signo = signo;
    the_info->si_code = SI_USER;
    the_info->si_value.sival_int = 0;
    return signo;
  }

  the_info->si_signo = -1;

  _Thread_Disable_dispatch();
    the_thread->Wait.queue           = &_POSIX_signals_Wait_queue;
    the_thread->Wait.return_code     = EINTR;
    the_thread->Wait.option          = *set;
    the_thread->Wait.return_argument = the_info;
    _Thread_queue_Enter_critical_section( &_POSIX_signals_Wait_queue );
    _ISR_Enable( level );
    _Thread_queue_Enqueue( &_POSIX_signals_Wait_queue, interval );
  _Thread_Enable_dispatch();

  /*
   * When the thread is set free by a signal, it is need to eliminate
   * the signal.
   */

  _POSIX_signals_Clear_signals( api, the_info->si_signo, the_info, false, false );
  errno = _Thread_Executing->Wait.return_code;
  return the_info->si_signo;
}
Ejemplo n.º 10
0
rtems_status_code rtems_region_get_segment(
  rtems_id           id,
  uintptr_t          size,
  rtems_option       option_set,
  rtems_interval     timeout,
  void              **segment
)
{
  rtems_status_code  status;
  Region_Control    *the_region;

  if ( segment == NULL ) {
    return RTEMS_INVALID_ADDRESS;
  }

  *segment = NULL;

  if ( size == 0 ) {
    return RTEMS_INVALID_SIZE;
  }

  the_region = _Region_Get_and_lock( id );

  if ( the_region == NULL ) {
    return RTEMS_INVALID_ID;
  }

  if ( size > the_region->maximum_segment_size ) {
    status = RTEMS_INVALID_SIZE;
  } else {
    void *the_segment;

    the_segment = _Region_Allocate_segment( the_region, size );

    if ( the_segment != NULL ) {
      *segment = the_segment;
      status = RTEMS_SUCCESSFUL;
    } else if ( _Options_Is_no_wait( option_set ) ) {
      status = RTEMS_UNSATISFIED;
    } else {
      Thread_queue_Context  queue_context;
      Thread_Control       *executing;

      _Thread_queue_Context_initialize( &queue_context );
      _Thread_queue_Acquire( &the_region->Wait_queue, &queue_context );

      executing  = _Thread_Executing;
      executing->Wait.count           = size;
      executing->Wait.return_argument = segment;

      /* FIXME: This is a home grown condition variable */
      _Thread_queue_Context_set_thread_state(
        &queue_context,
        STATES_WAITING_FOR_SEGMENT
      );
      _Thread_queue_Context_set_timeout_ticks( &queue_context, timeout );
      _Thread_queue_Context_set_enqueue_callout(
        &queue_context,
        _Region_Enqueue_callout
      );
      _Thread_queue_Enqueue(
        &the_region->Wait_queue.Queue,
        the_region->wait_operations,
        executing,
        &queue_context
      );
      return _Status_Get_after_wait( executing );
    }
  }

  _Region_Unlock( the_region );
  return status;
}
Ejemplo n.º 11
0
int _POSIX_Condition_variables_Wait_support(
  pthread_cond_t            *cond,
  pthread_mutex_t           *mutex,
  Watchdog_Interval          timeout,
  bool                       already_timedout
)
{
  register POSIX_Condition_variables_Control *the_cond;
  Objects_Locations                           location;
  int                                         status;
  int                                         mutex_status;

  if ( !_POSIX_Mutex_Get( mutex, &location ) ) {
     return EINVAL;
  }

  _Thread_Unnest_dispatch();

  the_cond = _POSIX_Condition_variables_Get( cond, &location );
  switch ( location ) {

    case OBJECTS_LOCAL:

      if ( the_cond->Mutex && ( the_cond->Mutex != *mutex ) ) {
        _Thread_Enable_dispatch();
        return EINVAL;
      }

      (void) pthread_mutex_unlock( mutex );
/* XXX ignore this for now  since behavior is undefined
      if ( mutex_status ) {
        _Thread_Enable_dispatch();
        return EINVAL;
      }
*/

      if ( !already_timedout ) {
        the_cond->Mutex = *mutex;

        _Thread_queue_Enter_critical_section( &the_cond->Wait_queue );
        _Thread_Executing->Wait.return_code = 0;
        _Thread_Executing->Wait.queue       = &the_cond->Wait_queue;
        _Thread_Executing->Wait.id          = *cond;

        _Thread_queue_Enqueue( &the_cond->Wait_queue, timeout );

        _Thread_Enable_dispatch();

        /*
         *  Switch ourself out because we blocked as a result of the
         *  _Thread_queue_Enqueue.
         */

        /*
         *  If the thread is interrupted, while in the thread queue, by
         *  a POSIX signal, then pthread_cond_wait returns spuriously,
         *  according to the POSIX standard. It means that pthread_cond_wait
         *  returns a success status, except for the fact that it was not
         *  woken up a pthread_cond_signal or a pthread_cond_broadcast.
         */
        status = _Thread_Executing->Wait.return_code;
        if ( status == EINTR )
          status = 0;

      } else {
        _Thread_Enable_dispatch();
        status = ETIMEDOUT;
      }

      /*
       *  When we get here the dispatch disable level is 0.
       */

      mutex_status = pthread_mutex_lock( mutex );
      if ( mutex_status )
        return EINVAL;

      return status;

#if defined(RTEMS_MULTIPROCESSING)
    case OBJECTS_REMOTE:
#endif
    case OBJECTS_ERROR:
      break;
  }

  return EINVAL;
}
Ejemplo n.º 12
0
int pthread_join(
  pthread_t   thread,
  void      **value_ptr
)
{
  register Thread_Control *the_thread;
  POSIX_API_Control       *api;
  Objects_Locations        location;
  void                    *return_pointer;

on_EINTR:
  the_thread = _Thread_Get( thread, &location );
  switch ( location ) {

    case OBJECTS_LOCAL:
      api = the_thread->API_Extensions[ THREAD_API_POSIX ];

      if ( api->detachstate == PTHREAD_CREATE_DETACHED ) {
        _Thread_Enable_dispatch();
        return EINVAL;
      }

      if ( _Thread_Is_executing( the_thread ) ) {
        _Thread_Enable_dispatch();
        return EDEADLK;
      }

      /*
       *  Put ourself on the threads join list
       */

      if ( the_thread->current_state ==
             (STATES_WAITING_FOR_JOIN_AT_EXIT | STATES_TRANSIENT) ) {
         return_pointer = the_thread->Wait.return_argument;
         _Thread_Clear_state(
           the_thread,
           (STATES_WAITING_FOR_JOIN_AT_EXIT | STATES_TRANSIENT)
         );
      } else {
	_Thread_Executing->Wait.return_argument = &return_pointer;
        _Thread_queue_Enter_critical_section( &api->Join_List );
        _Thread_queue_Enqueue( &api->Join_List, WATCHDOG_NO_TIMEOUT );
      }
      _Thread_Enable_dispatch();

      if ( _Thread_Executing->Wait.return_code == EINTR )
        goto on_EINTR;

      if ( value_ptr )
        *value_ptr = return_pointer;
      return 0;

#if defined(RTEMS_MULTIPROCESSING)
    case OBJECTS_REMOTE:
#endif
    case OBJECTS_ERROR:
      break;
  }

  return ESRCH;
}
Ejemplo n.º 13
0
void _CORE_message_queue_Seize(
  CORE_message_queue_Control      *the_message_queue,
  Thread_Control                  *executing,
  Objects_Id                       id,
  void                            *buffer,
  size_t                          *size_p,
  bool                             wait,
  Watchdog_Interval                timeout
)
{
  ISR_Level                          level;
  CORE_message_queue_Buffer_control *the_message;

  executing->Wait.return_code = CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL;
  _ISR_Disable( level );
  the_message = _CORE_message_queue_Get_pending_message( the_message_queue );
  if ( the_message != NULL ) {
    the_message_queue->number_of_pending_messages -= 1;
    _ISR_Enable( level );

    *size_p = the_message->Contents.size;
    executing->Wait.count =
      _CORE_message_queue_Get_message_priority( the_message );
    _CORE_message_queue_Copy_buffer(
      the_message->Contents.buffer,
      buffer,
      *size_p
    );

    #if !defined(RTEMS_SCORE_COREMSG_ENABLE_BLOCKING_SEND)
      /*
       *  There is not an API with blocking sends enabled.
       *  So return immediately.
       */
      _CORE_message_queue_Free_message_buffer(the_message_queue, the_message);
      return;
    #else
    {
      Thread_Control   *the_thread;

      /*
       *  There could be a thread waiting to send a message.  If there
       *  is not, then we can go ahead and free the buffer.
       *
       *  NOTE: If we note that the queue was not full before this receive,
       *  then we can avoid this dequeue.
       */
      the_thread = _Thread_queue_Dequeue( &the_message_queue->Wait_queue );
      if ( !the_thread ) {
        _CORE_message_queue_Free_message_buffer(
          the_message_queue,
          the_message
        );
        return;
      }

      /*
       *  There was a thread waiting to send a message.  This code
       *  puts the messages in the message queue on behalf of the
       *  waiting task.
       */
      _CORE_message_queue_Set_message_priority(
        the_message,
        the_thread->Wait.count
      );
      the_message->Contents.size = (size_t) the_thread->Wait.option;
      _CORE_message_queue_Copy_buffer(
        the_thread->Wait.return_argument_second.immutable_object,
        the_message->Contents.buffer,
        the_message->Contents.size
      );

      _CORE_message_queue_Insert_message(
         the_message_queue,
         the_message,
         _CORE_message_queue_Get_message_priority( the_message )
      );
      return;
    }
    #endif
  }

  if ( !wait ) {
    _ISR_Enable( level );
    executing->Wait.return_code = CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED_NOWAIT;
    return;
  }

  _Thread_queue_Enter_critical_section( &the_message_queue->Wait_queue );
  executing->Wait.queue = &the_message_queue->Wait_queue;
  executing->Wait.id = id;
  executing->Wait.return_argument_second.mutable_object = buffer;
  executing->Wait.return_argument = size_p;
  /* Wait.count will be filled in with the message priority */
  _ISR_Enable( level );

  _Thread_queue_Enqueue(
    &the_message_queue->Wait_queue,
    executing,
    STATES_WAITING_FOR_MESSAGE,
    timeout
  );
}
Ejemplo n.º 14
0
rtems_status_code rtems_region_get_segment(
  rtems_id           id,
  uintptr_t          size,
  rtems_option       option_set,
  rtems_interval     timeout,
  void              **segment
)
{
  Thread_Control     *executing;
  Objects_Locations   location;
  rtems_status_code   return_status;
  Region_Control     *the_region;
  void               *the_segment;

  if ( !segment )
    return RTEMS_INVALID_ADDRESS;

  *segment = NULL;

  if ( size == 0 )
    return RTEMS_INVALID_SIZE;

  _RTEMS_Lock_allocator();

    executing  = _Thread_Get_executing();
    the_region = _Region_Get( id, &location );
    switch ( location ) {

      case OBJECTS_LOCAL:
        if ( size > the_region->maximum_segment_size )
          return_status = RTEMS_INVALID_SIZE;

        else {
          _Region_Debug_Walk( the_region, 1 );

          the_segment = _Region_Allocate_segment( the_region, size );

          _Region_Debug_Walk( the_region, 2 );

          if ( the_segment ) {
            the_region->number_of_used_blocks += 1;
            *segment = the_segment;
            return_status = RTEMS_SUCCESSFUL;
          } else if ( _Options_Is_no_wait( option_set ) ) {
            return_status = RTEMS_UNSATISFIED;
          } else {
            /*
             *  Switch from using the memory allocation mutex to using a
             *  dispatching disabled critical section.  We have to do this
             *  because this thread is going to block.
             */
            /* FIXME: Lock order reversal */
            _Thread_Disable_dispatch();
            _RTEMS_Unlock_allocator();

            executing->Wait.queue           = &the_region->Wait_queue;
            executing->Wait.id              = id;
            executing->Wait.count           = size;
            executing->Wait.return_argument = segment;

            _Thread_queue_Enter_critical_section( &the_region->Wait_queue );

            _Thread_queue_Enqueue(
              &the_region->Wait_queue,
              executing,
              timeout
            );

            _Objects_Put( &the_region->Object );

            return (rtems_status_code) executing->Wait.return_code;
          }
        }
        break;

#if defined(RTEMS_MULTIPROCESSING)
      case OBJECTS_REMOTE:        /* this error cannot be returned */
        break;
#endif

      case OBJECTS_ERROR:
      default:
        return_status = RTEMS_INVALID_ID;
        break;
    }

  _RTEMS_Unlock_allocator();

  return return_status;
}
Ejemplo n.º 15
0
void _CORE_RWLock_Obtain_for_reading(
  CORE_RWLock_Control                 *the_rwlock,
  Thread_Control                      *executing,
  Objects_Id                           id,
  bool                                 wait,
  Watchdog_Interval                    timeout,
  CORE_RWLock_API_mp_support_callout   api_rwlock_mp_support
)
{
  ISR_Level       level;

  /*
   *  If unlocked, then OK to read.
   *  If locked for reading and no waiters, then OK to read.
   *  If any thread is waiting, then we wait.
   */

  _ISR_Disable( level );
    switch ( the_rwlock->current_state ) {
      case CORE_RWLOCK_UNLOCKED:
	the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_READING;
	the_rwlock->number_of_readers += 1;
	_ISR_Enable( level );
	executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL;
	return;

      case CORE_RWLOCK_LOCKED_FOR_READING: {
        Thread_Control *waiter;
        waiter = _Thread_queue_First( &the_rwlock->Wait_queue );
        if ( !waiter ) {
	  the_rwlock->number_of_readers += 1;
	  _ISR_Enable( level );
	  executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL;
          return;
        }
        break;
      }
      case CORE_RWLOCK_LOCKED_FOR_WRITING:
        break;
    }

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

    if ( !wait ) {
      _ISR_Enable( level );
      executing->Wait.return_code = CORE_RWLOCK_UNAVAILABLE;
      return;
    }

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

    _Thread_queue_Enter_critical_section( &the_rwlock->Wait_queue );
    executing->Wait.queue       = &the_rwlock->Wait_queue;
    executing->Wait.id          = id;
    executing->Wait.option      = CORE_RWLOCK_THREAD_WAITING_FOR_READ;
    executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL;
    _ISR_Enable( level );

    _Thread_queue_Enqueue(
       &the_rwlock->Wait_queue,
       executing,
       STATES_WAITING_FOR_RWLOCK,
       timeout
    );

    /* return to API level so it can dispatch and we block */
}
rtems_status_code rtems_region_get_segment(
  Objects_Id         id,
  uint32_t           size,
  rtems_option       option_set,
  rtems_interval     timeout,
  void              **segment
)
{
  register Region_Control *the_region;
  Objects_Locations        location;
  Thread_Control          *executing;
  void                    *the_segment;

  if ( !segment )
    return RTEMS_INVALID_ADDRESS;

  *segment = NULL;

  if ( size == 0 )
    return RTEMS_INVALID_SIZE;

  _RTEMS_Lock_allocator();
  executing  = _Thread_Executing;
  the_region = _Region_Get( id, &location );
  switch ( location ) {
    case OBJECTS_REMOTE:        /* this error cannot be returned */
      _RTEMS_Unlock_allocator();
      return RTEMS_INTERNAL_ERROR;

    case OBJECTS_ERROR:
      _RTEMS_Unlock_allocator();
      return RTEMS_INVALID_ID;

    case OBJECTS_LOCAL:
      if ( size > the_region->maximum_segment_size ) {
        _RTEMS_Unlock_allocator();
        return RTEMS_INVALID_SIZE;
      }

      _Region_Debug_Walk( the_region, 1 );

      the_segment = _Region_Allocate_segment( the_region, size );

      _Region_Debug_Walk( the_region, 2 );

      if ( the_segment ) {
        the_region->number_of_used_blocks += 1;
        _RTEMS_Unlock_allocator();
        *segment = the_segment;
        return RTEMS_SUCCESSFUL;
      }

      if ( _Options_Is_no_wait( option_set ) ) {
        _RTEMS_Unlock_allocator();
        return RTEMS_UNSATISFIED;
      }

      /*
       *  Switch from using the memory allocation mutex to using a
       *  dispatching disabled critical section.  We have to do this
       *  because this thread is going to block.
       */
      _Thread_Disable_dispatch();
      _RTEMS_Unlock_allocator();

      executing->Wait.queue           = &the_region->Wait_queue;
      executing->Wait.id              = id;
      executing->Wait.count           = size;
      executing->Wait.return_argument = segment;

      _Thread_queue_Enter_critical_section( &the_region->Wait_queue );

      _Thread_queue_Enqueue( &the_region->Wait_queue, timeout );

      _Thread_Enable_dispatch();

      return (rtems_status_code) executing->Wait.return_code;
  }

  return RTEMS_INTERNAL_ERROR;   /* unreached - only to remove warnings */
}
CORE_message_queue_Status _CORE_message_queue_Submit(
  CORE_message_queue_Control                *the_message_queue,
  void                                      *buffer,
  size_t                                     size,
  Objects_Id                                 id,
  CORE_message_queue_API_mp_support_callout  api_message_queue_mp_support,
  CORE_message_queue_Submit_types            submit_type,
  boolean                                    wait,
  Watchdog_Interval                          timeout
)
{
  ISR_Level                            level;
  CORE_message_queue_Buffer_control   *the_message;
  Thread_Control                      *the_thread;

  if ( size > the_message_queue->maximum_message_size ) {
    return CORE_MESSAGE_QUEUE_STATUS_INVALID_SIZE;
  }

  /*
   *  Is there a thread currently waiting on this message queue?
   */

  if ( the_message_queue->number_of_pending_messages == 0 ) {
    the_thread = _Thread_queue_Dequeue( &the_message_queue->Wait_queue );
    if ( the_thread ) {
      _CORE_message_queue_Copy_buffer(
        buffer,
        the_thread->Wait.return_argument,
        size
      );
      *(size_t *)the_thread->Wait.return_argument_1 = size;
      the_thread->Wait.count = submit_type;

#if defined(RTEMS_MULTIPROCESSING)
      if ( !_Objects_Is_local_id( the_thread->Object.id ) )
        (*api_message_queue_mp_support) ( the_thread, id );
#endif
      return CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL;
    }
  }

  /*
   *  No one waiting on the message queue at this time, so attempt to
   *  queue the message up for a future receive.
   */

  if ( the_message_queue->number_of_pending_messages <
       the_message_queue->maximum_pending_messages ) {

    the_message =
        _CORE_message_queue_Allocate_message_buffer( the_message_queue );

    /*
     *  NOTE: If the system is consistent, this error should never occur.
     */

    if ( !the_message ) {
      return CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED;
    }

    _CORE_message_queue_Copy_buffer(
      buffer,
      the_message->Contents.buffer,
      size
    );
    the_message->Contents.size = size;
    the_message->priority  = submit_type;

    _CORE_message_queue_Insert_message(
       the_message_queue,
       the_message,
       submit_type
    );
    return CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL;
  }

  /*
   *  No message buffers were available so we may need to return an
   *  overflow error or block the sender until the message is placed
   *  on the queue.
   */

  if ( !wait ) {
    return CORE_MESSAGE_QUEUE_STATUS_TOO_MANY;
  }

  /*
   *  Do NOT block on a send if the caller is in an ISR.  It is
   *  deadly to block in an ISR.
   */

  if ( _ISR_Is_in_progress() ) {
    return CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED;
  }

  /*
   *  WARNING!! executing should NOT be used prior to this point.
   *  Thus the unusual choice to open a new scope and declare
   *  it as a variable.  Doing this emphasizes how dangerous it
   *  would be to use this variable prior to here.
   */

  {
    Thread_Control  *executing = _Thread_Executing;

    _ISR_Disable( level );
    _Thread_queue_Enter_critical_section( &the_message_queue->Wait_queue );
    executing->Wait.queue              = &the_message_queue->Wait_queue;
    executing->Wait.id                 = id;
    executing->Wait.return_argument    = buffer;
    executing->Wait.option             = size;
    executing->Wait.count              = submit_type;
    _ISR_Enable( level );

    _Thread_queue_Enqueue( &the_message_queue->Wait_queue, timeout );
  }

  return CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED_WAIT;
}
Ejemplo n.º 18
0
Status_Control _CORE_message_queue_Submit(
  CORE_message_queue_Control       *the_message_queue,
  Thread_Control                   *executing,
  const void                       *buffer,
  size_t                            size,
  CORE_message_queue_Submit_types   submit_type,
  bool                              wait,
  Thread_queue_Context             *queue_context
)
{
  CORE_message_queue_Buffer_control *the_message;
  Thread_Control                    *the_thread;

  if ( size > the_message_queue->maximum_message_size ) {
    _CORE_message_queue_Release( the_message_queue, queue_context );
    return STATUS_MESSAGE_INVALID_SIZE;
  }

  /*
   *  Is there a thread currently waiting on this message queue?
   */

  the_thread = _CORE_message_queue_Dequeue_receiver(
    the_message_queue,
    buffer,
    size,
    submit_type,
    queue_context
  );
  if ( the_thread != NULL ) {
    return STATUS_SUCCESSFUL;
  }

  /*
   *  No one waiting on the message queue at this time, so attempt to
   *  queue the message up for a future receive.
   */
  the_message =
      _CORE_message_queue_Allocate_message_buffer( the_message_queue );
  if ( the_message ) {
    _CORE_message_queue_Insert_message(
      the_message_queue,
      the_message,
      buffer,
      size,
      submit_type
    );

#if defined(RTEMS_SCORE_COREMSG_ENABLE_NOTIFICATION)
    /*
     *  According to POSIX, does this happen before or after the message
     *  is actually enqueued.  It is logical to think afterwards, because
     *  the message is actually in the queue at this point.
     */
    if (
      the_message_queue->number_of_pending_messages == 1
        && the_message_queue->notify_handler != NULL
    ) {
      ( *the_message_queue->notify_handler )(
        the_message_queue,
        queue_context
      );
    } else {
      _CORE_message_queue_Release( the_message_queue, queue_context );
    }
#else
    _CORE_message_queue_Release( the_message_queue, queue_context );
#endif

    return STATUS_SUCCESSFUL;
  }

  #if !defined(RTEMS_SCORE_COREMSG_ENABLE_BLOCKING_SEND)
    _CORE_message_queue_Release( the_message_queue, queue_context );
    return STATUS_TOO_MANY;
  #else
    /*
     *  No message buffers were available so we may need to return an
     *  overflow error or block the sender until the message is placed
     *  on the queue.
     */
    if ( !wait ) {
      _CORE_message_queue_Release( the_message_queue, queue_context );
      return STATUS_TOO_MANY;
    }

    /*
     *  Do NOT block on a send if the caller is in an ISR.  It is
     *  deadly to block in an ISR.
     */
    if ( _ISR_Is_in_progress() ) {
      _CORE_message_queue_Release( the_message_queue, queue_context );
      return STATUS_MESSAGE_QUEUE_WAIT_IN_ISR;
    }

    /*
     *  WARNING!! executing should NOT be used prior to this point.
     *  Thus the unusual choice to open a new scope and declare
     *  it as a variable.  Doing this emphasizes how dangerous it
     *  would be to use this variable prior to here.
     */
    executing->Wait.return_argument_second.immutable_object = buffer;
    executing->Wait.option = (uint32_t) size;
    executing->Wait.count = submit_type;

    _Thread_queue_Context_set_thread_state(
      queue_context,
      STATES_WAITING_FOR_MESSAGE
    );
    _Thread_queue_Context_set_do_nothing_enqueue_callout( queue_context );
    _Thread_queue_Enqueue(
      &the_message_queue->Wait_queue.Queue,
      the_message_queue->operations,
      executing,
      queue_context
    );
    return _Thread_Wait_get_status( executing );
  #endif
}