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 ); }
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 ); }
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(); }
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; } }
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; }
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 ); }
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 ); }
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; }
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; }
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; }
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; }
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 ); }
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; }
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; }
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 }