From cc18d7bec7b3c5515cb9e6cd9771d4b94309b3bd Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 30 Apr 2015 13:12:54 +0200 Subject: score: Fine grained locking for message queues Aggregate several critical sections into a bigger one. Sending and receiving messages is now protected by an ISR lock. Thread dispatching is only disabled in case a blocking operation is necessary. The message copy procedure is done inside the critical section (interrupts disabled). Thus this change may have a negative impact on the interrupt latency in case very large messages are transferred. Update #2273. --- cpukit/score/include/rtems/score/coremsgimpl.h | 121 ++++++++++++++++++++++--- 1 file changed, 109 insertions(+), 12 deletions(-) (limited to 'cpukit/score/include/rtems/score') diff --git a/cpukit/score/include/rtems/score/coremsgimpl.h b/cpukit/score/include/rtems/score/coremsgimpl.h index 1f6796905b..51b5f3780f 100644 --- a/cpukit/score/include/rtems/score/coremsgimpl.h +++ b/cpukit/score/include/rtems/score/coremsgimpl.h @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -172,11 +173,13 @@ void _CORE_message_queue_Close( * number of messages flushed from the queue is returned. * * @param[in] the_message_queue points to the message queue to flush + * @param[in] lock_context The lock context of the interrupt disable. * * @retval This method returns the number of message pending messages flushed. */ uint32_t _CORE_message_queue_Flush( - CORE_message_queue_Control *the_message_queue + CORE_message_queue_Control *the_message_queue, + ISR_lock_Context *lock_context ); #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API) @@ -215,6 +218,7 @@ uint32_t _CORE_message_queue_Flush( * a thread that is unblocked is actually a remote thread. * @param[out] count points to the variable that will contain the * number of tasks that are sent this message + * @param[in] lock_context The lock context of the interrupt disable. * @retval @a *count will contain the number of messages sent * @retval indication of the successful completion or reason for failure */ @@ -224,7 +228,8 @@ CORE_message_queue_Status _CORE_message_queue_Broadcast( size_t size, Objects_Id id, CORE_message_queue_API_mp_support_callout api_message_queue_mp_support, - uint32_t *count + uint32_t *count, + ISR_lock_Context *lock_context ); /** @@ -250,6 +255,7 @@ CORE_message_queue_Status _CORE_message_queue_Broadcast( * if the message queue is full. * @param[in] timeout is the maximum number of clock ticks that the calling * thread is willing to block if the message queue is full. + * @param[in] lock_context The lock context of the interrupt disable. * @retval indication of the successful completion or reason for failure */ CORE_message_queue_Status _CORE_message_queue_Submit( @@ -261,7 +267,8 @@ CORE_message_queue_Status _CORE_message_queue_Submit( CORE_message_queue_API_mp_support_callout api_message_queue_mp_support, CORE_message_queue_Submit_types submit_type, bool wait, - Watchdog_Interval timeout + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ); /** @@ -287,6 +294,7 @@ CORE_message_queue_Status _CORE_message_queue_Submit( * if the message queue is empty. * @param[in] timeout is the maximum number of clock ticks that the calling * thread is willing to block if the message queue is empty. + * @param[in] lock_context The lock context of the interrupt disable. * * @retval indication of the successful completion or reason for failure. * On success, the location pointed to @a size_p will contain the @@ -305,7 +313,8 @@ void _CORE_message_queue_Seize( void *buffer, size_t *size_p, bool wait, - Watchdog_Interval timeout + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ); /** @@ -338,8 +347,9 @@ RTEMS_INLINE_ROUTINE CORE_message_queue_Status _CORE_message_queue_Send( size_t size, Objects_Id id, CORE_message_queue_API_mp_support_callout api_message_queue_mp_support, - bool wait, - Watchdog_Interval timeout + bool wait, + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ) { return _CORE_message_queue_Submit( @@ -351,7 +361,8 @@ RTEMS_INLINE_ROUTINE CORE_message_queue_Status _CORE_message_queue_Send( api_message_queue_mp_support, CORE_MESSAGE_QUEUE_SEND_REQUEST, wait, /* sender may block */ - timeout /* timeout interval */ + timeout, /* timeout interval */ + lock_context ); } @@ -364,8 +375,9 @@ RTEMS_INLINE_ROUTINE CORE_message_queue_Status _CORE_message_queue_Urgent( size_t size, Objects_Id id, CORE_message_queue_API_mp_support_callout api_message_queue_mp_support, - bool wait, - Watchdog_Interval timeout + bool wait, + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ) { return _CORE_message_queue_Submit( @@ -377,10 +389,46 @@ RTEMS_INLINE_ROUTINE CORE_message_queue_Status _CORE_message_queue_Urgent( api_message_queue_mp_support, CORE_MESSAGE_QUEUE_URGENT_REQUEST, wait, /* sender may block */ - timeout /* timeout interval */ + timeout, /* timeout interval */ + lock_context ); } +RTEMS_INLINE_ROUTINE void _CORE_message_queue_Acquire( + CORE_message_queue_Control *the_message_queue, + ISR_lock_Context *lock_context +) +{ + _Thread_queue_Acquire( &the_message_queue->Wait_queue, lock_context ); +} + +RTEMS_INLINE_ROUTINE void _CORE_message_queue_Acquire_critical( + CORE_message_queue_Control *the_message_queue, + ISR_lock_Context *lock_context +) +{ + _Thread_queue_Acquire_critical( &the_message_queue->Wait_queue, lock_context ); + + #if defined(RTEMS_MULTIPROCESSING) + /* + * In case RTEMS_MULTIPROCESSING is enabled, then we have to prevent + * deletion of the executing thread after the thread queue operations. + */ + _Thread_Dispatch_disable(); + #endif +} + +RTEMS_INLINE_ROUTINE void _CORE_message_queue_Release( + CORE_message_queue_Control *the_message_queue, + ISR_lock_Context *lock_context +) +{ + _Thread_queue_Release( &the_message_queue->Wait_queue, lock_context ); + #if defined(RTEMS_MULTIPROCESSING) + _Thread_Dispatch_enable( _Per_CPU_Get() ); + #endif +} + /** * This routine copies the contents of the source message buffer * to the destination message buffer. @@ -404,7 +452,7 @@ _CORE_message_queue_Allocate_message_buffer ( ) { return (CORE_message_queue_Buffer_control *) - _Chain_Get( &the_message_queue->Inactive_messages ); + _Chain_Get_unprotected( &the_message_queue->Inactive_messages ); } /** @@ -416,7 +464,7 @@ RTEMS_INLINE_ROUTINE void _CORE_message_queue_Free_message_buffer ( CORE_message_queue_Buffer_control *the_message ) { - _Chain_Append( &the_message_queue->Inactive_messages, &the_message->Node ); + _Chain_Append_unprotected( &the_message_queue->Inactive_messages, &the_message->Node ); } /** @@ -510,6 +558,55 @@ RTEMS_INLINE_ROUTINE bool _CORE_message_queue_Is_priority( the_message_queue, the_handler, the_argument ) #endif +RTEMS_INLINE_ROUTINE Thread_Control *_CORE_message_queue_Dequeue_receiver( + CORE_message_queue_Control *the_message_queue, + const void *buffer, + size_t size, + CORE_message_queue_Submit_types submit_type, + ISR_lock_Context *lock_context +) +{ + Thread_Control *the_thread; + + /* + * If there are pending messages, then there can't be threads + * waiting for us to send them a message. + * + * NOTE: This check is critical because threads can block on + * send and receive and this ensures that we are broadcasting + * the message to threads waiting to receive -- not to send. + */ + if ( the_message_queue->number_of_pending_messages != 0 ) { + return NULL; + } + + /* + * There must be no pending messages if there is a thread waiting to + * receive a message. + */ + the_thread = _Thread_queue_First_locked( &the_message_queue->Wait_queue ); + if ( the_thread == NULL ) { + return NULL; + } + + *(size_t *) the_thread->Wait.return_argument = size; + the_thread->Wait.count = (uint32_t) submit_type; + + _CORE_message_queue_Copy_buffer( + buffer, + the_thread->Wait.return_argument_second.mutable_object, + size + ); + + _Thread_queue_Extract_critical( + &the_message_queue->Wait_queue, + the_thread, + lock_context + ); + + return the_thread; +} + /** @} */ #ifdef __cplusplus -- cgit v1.2.3