From 125f248231c173a038ed9fc00832e0b3d221ad43 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 16 Nov 2016 16:39:43 +0100 Subject: score: Add thread queue enqueue callout Replace the expected thread dispatch disable level with a thread queue enqueue callout. This enables the use of _Thread_Dispatch_direct() in the thread queue enqueue procedure. This avoids impossible exection paths, e.g. Per_CPU_Control::dispatch_necessary is always true. --- cpukit/score/src/condition.c | 151 ++++++++++++++++--------------- cpukit/score/src/corebarrierwait.c | 2 +- cpukit/score/src/coremsgseize.c | 2 +- cpukit/score/src/coremsgsubmit.c | 2 +- cpukit/score/src/coremutexseize.c | 2 +- cpukit/score/src/corerwlockobtainread.c | 2 +- cpukit/score/src/corerwlockobtainwrite.c | 2 +- cpukit/score/src/futex.c | 2 +- cpukit/score/src/mpci.c | 66 ++++++++------ cpukit/score/src/mutex.c | 2 +- cpukit/score/src/semaphore.c | 2 +- cpukit/score/src/threadqenqueue.c | 22 ++--- cpukit/score/src/threadrestart.c | 35 +++++-- 13 files changed, 164 insertions(+), 128 deletions(-) (limited to 'cpukit/score/src') diff --git a/cpukit/score/src/condition.c b/cpukit/score/src/condition.c index 36ef98949b..917f11934e 100644 --- a/cpukit/score/src/condition.c +++ b/cpukit/score/src/condition.c @@ -80,31 +80,48 @@ static void _Condition_Queue_release( ); } -static Per_CPU_Control *_Condition_Do_wait( +typedef struct { + Thread_queue_Context Base; + struct _Mutex_Control *mutex; +} Condition_Enqueue_context; + +static void _Condition_Enqueue_callout( + Thread_queue_Queue *queue, + Thread_Control *the_thread, + Thread_queue_Context *queue_context +) +{ + Condition_Enqueue_context *context; + + context = (Condition_Enqueue_context *) queue_context; + _Mutex_Release( context->mutex ); +} + +static Thread_Control *_Condition_Do_wait( struct _Condition_Control *_condition, - Thread_queue_Context *queue_context + struct _Mutex_Control *_mutex, + Condition_Enqueue_context *context ) { Condition_Control *condition; Thread_Control *executing; - Per_CPU_Control *cpu_self; + context->mutex = _mutex; condition = _Condition_Get( _condition ); - executing = _Condition_Queue_acquire_critical( condition, queue_context ); - cpu_self = _Thread_Dispatch_disable_critical( - &queue_context->Lock_context.Lock_context + executing = _Condition_Queue_acquire_critical( condition, &context->Base ); + _Thread_queue_Context_set_enqueue_callout( + &context->Base, + _Condition_Enqueue_callout ); - - _Thread_queue_Context_set_expected_level( queue_context, 2 ); _Thread_queue_Enqueue_critical( &condition->Queue.Queue, CONDITION_TQ_OPERATIONS, executing, STATES_WAITING_FOR_SYS_LOCK_CONDITION, - queue_context + &context->Base ); - return cpu_self; + return executing; } void _Condition_Wait( @@ -112,19 +129,12 @@ void _Condition_Wait( struct _Mutex_Control *_mutex ) { - Thread_queue_Context queue_context; - Per_CPU_Control *cpu_self; - - _Thread_queue_Context_initialize( &queue_context ); - _ISR_lock_ISR_disable( &queue_context.Lock_context.Lock_context ); - _Thread_queue_Context_set_no_timeout( &queue_context ); - cpu_self = _Condition_Do_wait( - _condition, - &queue_context - ); + Condition_Enqueue_context context; - _Mutex_Release( _mutex ); - _Thread_Dispatch_enable( cpu_self ); + _Thread_queue_Context_initialize( &context.Base ); + _ISR_lock_ISR_disable( &context.Base.Lock_context.Lock_context ); + _Thread_queue_Context_set_no_timeout( &context.Base ); + _Condition_Do_wait( _condition, _mutex, &context ); _Mutex_Acquire( _mutex ); } @@ -134,57 +144,59 @@ int _Condition_Wait_timed( const struct timespec *abstime ) { - Thread_queue_Context queue_context; - Per_CPU_Control *cpu_self; - Thread_Control *executing; - int eno; - Watchdog_Interval ticks; + Condition_Enqueue_context context; + Thread_Control *executing; + int eno; + Watchdog_Interval ticks; - _Thread_queue_Context_initialize( &queue_context ); - _ISR_lock_ISR_disable( &queue_context.Lock_context.Lock_context ); + _Thread_queue_Context_initialize( &context.Base ); + _ISR_lock_ISR_disable( &context.Base.Lock_context.Lock_context ); switch ( _TOD_Absolute_timeout_to_ticks( abstime, CLOCK_REALTIME, &ticks ) ) { case TOD_ABSOLUTE_TIMEOUT_INVALID: - _ISR_lock_ISR_enable( &queue_context.Lock_context.Lock_context ); + _ISR_lock_ISR_enable( &context.Base.Lock_context.Lock_context ); return EINVAL; case TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST: case TOD_ABSOLUTE_TIMEOUT_IS_NOW: - _ISR_lock_ISR_enable( &queue_context.Lock_context.Lock_context ); + _ISR_lock_ISR_enable( &context.Base.Lock_context.Lock_context ); return ETIMEDOUT; default: break; } - _Thread_queue_Context_set_relative_timeout( &queue_context, ticks ); - cpu_self = _Condition_Do_wait( _condition, &queue_context ); - - _Mutex_Release( _mutex ); - executing = cpu_self->executing; - _Thread_Dispatch_enable( cpu_self ); + _Thread_queue_Context_set_relative_timeout( &context.Base, ticks ); + executing = _Condition_Do_wait( _condition, _mutex, &context ); eno = STATUS_GET_POSIX( _Thread_Wait_get_status( executing ) ); _Mutex_Acquire( _mutex ); return eno; } -void _Condition_Wait_recursive( - struct _Condition_Control *_condition, +static unsigned int _Condition_Unnest_mutex( struct _Mutex_recursive_Control *_mutex ) { - Thread_queue_Context queue_context; - Per_CPU_Control *cpu_self; - unsigned int nest_level; - - _Thread_queue_Context_initialize( &queue_context ); - _ISR_lock_ISR_disable( &queue_context.Lock_context.Lock_context ); - _Thread_queue_Context_set_no_timeout( &queue_context ); - cpu_self = _Condition_Do_wait( _condition, &queue_context ); + unsigned int nest_level; nest_level = _mutex->_nest_level; _mutex->_nest_level = 0; - _Mutex_recursive_Release( _mutex ); - _Thread_Dispatch_enable( cpu_self ); + + return nest_level; +} + +void _Condition_Wait_recursive( + struct _Condition_Control *_condition, + struct _Mutex_recursive_Control *_mutex +) +{ + Condition_Enqueue_context context; + unsigned int nest_level; + + _Thread_queue_Context_initialize( &context.Base ); + _ISR_lock_ISR_disable( &context.Base.Lock_context.Lock_context ); + _Thread_queue_Context_set_no_timeout( &context.Base ); + nest_level = _Condition_Unnest_mutex( _mutex ); + _Condition_Do_wait( _condition, &_mutex->_Mutex, &context ); _Mutex_recursive_Acquire( _mutex ); _mutex->_nest_level = nest_level; } @@ -195,36 +207,29 @@ int _Condition_Wait_recursive_timed( const struct timespec *abstime ) { - Thread_queue_Context queue_context; - Per_CPU_Control *cpu_self; - Thread_Control *executing; - int eno; - unsigned int nest_level; - Watchdog_Interval ticks; + Condition_Enqueue_context context; + Thread_Control *executing; + int eno; + unsigned int nest_level; + Watchdog_Interval ticks; - _Thread_queue_Context_initialize( &queue_context ); - _ISR_lock_ISR_disable( &queue_context.Lock_context.Lock_context ); + _Thread_queue_Context_initialize( &context.Base ); + _ISR_lock_ISR_disable( &context.Base.Lock_context.Lock_context ); switch ( _TOD_Absolute_timeout_to_ticks( abstime, CLOCK_REALTIME, &ticks ) ) { case TOD_ABSOLUTE_TIMEOUT_INVALID: - _ISR_lock_ISR_enable( &queue_context.Lock_context.Lock_context ); + _ISR_lock_ISR_enable( &context.Base.Lock_context.Lock_context ); return EINVAL; case TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST: case TOD_ABSOLUTE_TIMEOUT_IS_NOW: - _ISR_lock_ISR_enable( &queue_context.Lock_context.Lock_context ); + _ISR_lock_ISR_enable( &context.Base.Lock_context.Lock_context ); return ETIMEDOUT; default: break; } - - _Thread_queue_Context_set_relative_timeout( &queue_context, ticks ); - cpu_self = _Condition_Do_wait( _condition, &queue_context ); - - nest_level = _mutex->_nest_level; - _mutex->_nest_level = 0; - _Mutex_recursive_Release( _mutex ); - executing = cpu_self->executing; - _Thread_Dispatch_enable( cpu_self ); + _Thread_queue_Context_set_relative_timeout( &context.Base, ticks ); + nest_level = _Condition_Unnest_mutex( _mutex ); + executing = _Condition_Do_wait( _condition, &_mutex->_Mutex, &context ); eno = STATUS_GET_POSIX( _Thread_Wait_get_status( executing ) ); _Mutex_recursive_Acquire( _mutex ); _mutex->_nest_level = nest_level; @@ -235,7 +240,7 @@ int _Condition_Wait_recursive_timed( typedef struct { Thread_queue_Context Base; int count; -} Condition_Context; +} Condition_Flush_context; static Thread_Control *_Condition_Flush_filter( Thread_Control *the_thread, @@ -243,9 +248,9 @@ static Thread_Control *_Condition_Flush_filter( Thread_queue_Context *queue_context ) { - Condition_Context *context; + Condition_Flush_context *context; - context = (Condition_Context *) queue_context; + context = (Condition_Flush_context *) queue_context; if ( context->count <= 0 ) { return NULL; @@ -258,8 +263,8 @@ static Thread_Control *_Condition_Flush_filter( static void _Condition_Wake( struct _Condition_Control *_condition, int count ) { - Condition_Control *condition; - Condition_Context context; + Condition_Control *condition; + Condition_Flush_context context; condition = _Condition_Get( _condition ); _Thread_queue_Context_initialize( &context.Base ); diff --git a/cpukit/score/src/corebarrierwait.c b/cpukit/score/src/corebarrierwait.c index 7e46c93670..05f78760cd 100644 --- a/cpukit/score/src/corebarrierwait.c +++ b/cpukit/score/src/corebarrierwait.c @@ -44,7 +44,7 @@ Status_Control _CORE_barrier_Seize( return STATUS_BARRIER_AUTOMATICALLY_RELEASED; } else { the_barrier->number_of_waiting_threads = number_of_waiting_threads; - _Thread_queue_Context_set_expected_level( queue_context, 1 ); + _Thread_queue_Context_set_do_nothing_enqueue_callout( queue_context ); _Thread_queue_Enqueue_critical( &the_barrier->Wait_queue.Queue, CORE_BARRIER_TQ_OPERATIONS, diff --git a/cpukit/score/src/coremsgseize.c b/cpukit/score/src/coremsgseize.c index d86afd08de..6c98b9558c 100644 --- a/cpukit/score/src/coremsgseize.c +++ b/cpukit/score/src/coremsgseize.c @@ -113,7 +113,7 @@ Status_Control _CORE_message_queue_Seize( executing->Wait.return_argument = size_p; /* Wait.count will be filled in with the message priority */ - _Thread_queue_Context_set_expected_level( queue_context, 1 ); + _Thread_queue_Context_set_do_nothing_enqueue_callout( queue_context ); _Thread_queue_Enqueue_critical( &the_message_queue->Wait_queue.Queue, the_message_queue->operations, diff --git a/cpukit/score/src/coremsgsubmit.c b/cpukit/score/src/coremsgsubmit.c index 97b43823c3..330f43c13e 100644 --- a/cpukit/score/src/coremsgsubmit.c +++ b/cpukit/score/src/coremsgsubmit.c @@ -131,7 +131,7 @@ Status_Control _CORE_message_queue_Submit( executing->Wait.option = (uint32_t) size; executing->Wait.count = submit_type; - _Thread_queue_Context_set_expected_level( queue_context, 1 ); + _Thread_queue_Context_set_do_nothing_enqueue_callout( queue_context ); _Thread_queue_Enqueue_critical( &the_message_queue->Wait_queue.Queue, the_message_queue->operations, diff --git a/cpukit/score/src/coremutexseize.c b/cpukit/score/src/coremutexseize.c index 01a5ffb9a5..7e54381864 100644 --- a/cpukit/score/src/coremutexseize.c +++ b/cpukit/score/src/coremutexseize.c @@ -32,7 +32,7 @@ Status_Control _CORE_mutex_Seize_slow( ) { if ( wait ) { - _Thread_queue_Context_set_expected_level( queue_context, 1 ); + _Thread_queue_Context_set_do_nothing_enqueue_callout( queue_context ); _Thread_queue_Context_set_deadlock_callout( queue_context, _Thread_queue_Deadlock_status diff --git a/cpukit/score/src/corerwlockobtainread.c b/cpukit/score/src/corerwlockobtainread.c index 09b26afd27..4444afcfa5 100644 --- a/cpukit/score/src/corerwlockobtainread.c +++ b/cpukit/score/src/corerwlockobtainread.c @@ -78,7 +78,7 @@ Status_Control _CORE_RWLock_Seize_for_reading( executing->Wait.option = CORE_RWLOCK_THREAD_WAITING_FOR_READ; - _Thread_queue_Context_set_expected_level( queue_context, 1 ); + _Thread_queue_Context_set_do_nothing_enqueue_callout( queue_context ); _Thread_queue_Enqueue_critical( &the_rwlock->Wait_queue.Queue, CORE_RWLOCK_TQ_OPERATIONS, diff --git a/cpukit/score/src/corerwlockobtainwrite.c b/cpukit/score/src/corerwlockobtainwrite.c index 9aac5e7ef7..0e4290ea27 100644 --- a/cpukit/score/src/corerwlockobtainwrite.c +++ b/cpukit/score/src/corerwlockobtainwrite.c @@ -66,7 +66,7 @@ Status_Control _CORE_RWLock_Seize_for_writing( executing->Wait.option = CORE_RWLOCK_THREAD_WAITING_FOR_WRITE; - _Thread_queue_Context_set_expected_level( queue_context, 1 ); + _Thread_queue_Context_set_do_nothing_enqueue_callout( queue_context ); _Thread_queue_Enqueue_critical( &the_rwlock->Wait_queue.Queue, CORE_RWLOCK_TQ_OPERATIONS, diff --git a/cpukit/score/src/futex.c b/cpukit/score/src/futex.c index 38c3be4857..d99accb539 100644 --- a/cpukit/score/src/futex.c +++ b/cpukit/score/src/futex.c @@ -92,7 +92,7 @@ int _Futex_Wait( struct _Futex_Control *_futex, int *uaddr, int val ) executing = _Futex_Queue_acquire_critical( futex, &queue_context ); if ( *uaddr == val ) { - _Thread_queue_Context_set_expected_level( &queue_context, 1 ); + _Thread_queue_Context_set_do_nothing_enqueue_callout( &queue_context ); _Thread_queue_Context_set_no_timeout( &queue_context ); _Thread_queue_Context_set_ISR_level( &queue_context, level ); _Thread_queue_Enqueue_critical( diff --git a/cpukit/score/src/mpci.c b/cpukit/score/src/mpci.c index 451592c8d5..533050085e 100644 --- a/cpukit/score/src/mpci.c +++ b/cpukit/score/src/mpci.c @@ -226,47 +226,59 @@ void _MPCI_Send_process_packet ( (*_MPCI_table->send_packet)( destination, the_packet ); } +static void _MPCI_Enqueue_callout( + Thread_queue_Queue *queue, + Thread_Control *the_thread, + Thread_queue_Context *queue_context +) +{ + _Thread_Dispatch_unnest( _Per_CPU_Get() ); +} + Status_Control _MPCI_Send_request_packet( uint32_t destination, MP_packet_Prefix *the_packet, States_Control extra_state ) { - Per_CPU_Control *cpu_self; - Thread_Control *executing; - - cpu_self = _Thread_Dispatch_disable(); - - executing = _Per_CPU_Get_executing( cpu_self ); + Per_CPU_Control *cpu_self; + Thread_queue_Context queue_context; + Thread_Control *executing; - the_packet->source_tid = executing->Object.id; - the_packet->source_priority = _Thread_Get_priority( executing ); - the_packet->to_convert = - ( the_packet->to_convert - sizeof(MP_packet_Prefix) ) / sizeof(uint32_t); + /* + * See if we need a default timeout + */ - executing->Wait.remote_id = the_packet->id; + if (the_packet->timeout == MPCI_DEFAULT_TIMEOUT) + the_packet->timeout = _MPCI_table->default_timeout; - (*_MPCI_table->send_packet)( destination, the_packet ); + _Thread_queue_Context_initialize( &queue_context ); + _Thread_queue_Context_set_enqueue_callout( + &queue_context, + _MPCI_Enqueue_callout + ); + _Thread_queue_Context_set_relative_timeout( &queue_context, the_packet->timeout ); - /* - * See if we need a default timeout - */ + cpu_self = _Thread_Dispatch_disable(); - if (the_packet->timeout == MPCI_DEFAULT_TIMEOUT) - the_packet->timeout = _MPCI_table->default_timeout; + executing = _Per_CPU_Get_executing( cpu_self ); + executing->Wait.remote_id = the_packet->id; - _Thread_queue_Enqueue( - &_MPCI_Remote_blocked_threads, - &_Thread_queue_Operations_FIFO, - executing, - STATES_WAITING_FOR_RPC_REPLY | extra_state, - the_packet->timeout, - WATCHDOG_RELATIVE, - 2 - ); + the_packet->source_tid = executing->Object.id; + the_packet->source_priority = _Thread_Get_priority( executing ); + the_packet->to_convert = + ( the_packet->to_convert - sizeof(MP_packet_Prefix) ) / sizeof(uint32_t); - _Thread_Dispatch_enable( cpu_self ); + (*_MPCI_table->send_packet)( destination, the_packet ); + _Thread_queue_Acquire( &_MPCI_Remote_blocked_threads, &queue_context ); + _Thread_queue_Enqueue_critical( + &_MPCI_Remote_blocked_threads.Queue, + &_Thread_queue_Operations_FIFO, + executing, + STATES_WAITING_FOR_RPC_REPLY | extra_state, + &queue_context + ); return _Thread_Wait_get_status( executing ); } diff --git a/cpukit/score/src/mutex.c b/cpukit/score/src/mutex.c index 4e1d9ceae4..344d7877c2 100644 --- a/cpukit/score/src/mutex.c +++ b/cpukit/score/src/mutex.c @@ -109,7 +109,7 @@ static void _Mutex_Acquire_slow( Thread_queue_Context *queue_context ) { - _Thread_queue_Context_set_expected_level( queue_context, 1 ); + _Thread_queue_Context_set_do_nothing_enqueue_callout( queue_context ); _Thread_queue_Context_set_deadlock_callout( queue_context, _Thread_queue_Deadlock_fatal diff --git a/cpukit/score/src/semaphore.c b/cpukit/score/src/semaphore.c index 29acef4fe1..db5e079dd3 100644 --- a/cpukit/score/src/semaphore.c +++ b/cpukit/score/src/semaphore.c @@ -103,7 +103,7 @@ void _Semaphore_Wait( struct _Semaphore_Control *_sem ) sem->count = count - 1; _Semaphore_Queue_release( sem, level, &queue_context ); } else { - _Thread_queue_Context_set_expected_level( &queue_context, 1 ); + _Thread_queue_Context_set_do_nothing_enqueue_callout( &queue_context ); _Thread_queue_Context_set_no_timeout( &queue_context ); _Thread_queue_Context_set_ISR_level( &queue_context, level ); _Thread_queue_Enqueue_critical( diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c index 84d1765462..ce0e80c6f2 100644 --- a/cpukit/score/src/threadqenqueue.c +++ b/cpukit/score/src/threadqenqueue.c @@ -356,6 +356,15 @@ bool _Thread_queue_Path_acquire_critical( return true; } +void _Thread_queue_Enqueue_do_nothing( + Thread_queue_Queue *queue, + Thread_Control *the_thread, + Thread_queue_Context *queue_context +) +{ + /* Do nothing */ +} + void _Thread_queue_Deadlock_status( Thread_Control *the_thread ) { the_thread->Wait.return_code = STATUS_DEADLOCK; @@ -442,16 +451,7 @@ void _Thread_queue_Enqueue_critical( ); _Thread_queue_Queue_release( queue, &queue_context->Lock_context.Lock_context ); - if ( - cpu_self->thread_dispatch_disable_level - != queue_context->expected_thread_dispatch_disable_level - ) { - _Terminate( - INTERNAL_ERROR_CORE, - false, - INTERNAL_ERROR_THREAD_QUEUE_ENQUEUE_FROM_BAD_STATE - ); - } + ( *queue_context->enqueue_callout )( queue, the_thread, queue_context ); /* * Set the blocking state for this thread queue in the thread. @@ -482,7 +482,7 @@ void _Thread_queue_Enqueue_critical( } _Thread_Priority_update( queue_context ); - _Thread_Dispatch_enable( cpu_self ); + _Thread_Dispatch_direct( cpu_self ); } #if defined(RTEMS_SMP) diff --git a/cpukit/score/src/threadrestart.c b/cpukit/score/src/threadrestart.c index a5ed837dfd..46c8e4d979 100644 --- a/cpukit/score/src/threadrestart.c +++ b/cpukit/score/src/threadrestart.c @@ -514,21 +514,40 @@ void _Thread_Cancel( _Thread_Dispatch_enable( cpu_self ); } -void _Thread_Close( Thread_Control *the_thread, Thread_Control *executing ) +static void _Thread_Close_enqueue_callout( + Thread_queue_Queue *queue, + Thread_Control *the_thread, + Thread_queue_Context *queue_context +) { - Thread_queue_Context queue_context; + Thread_Close_context *context; + + context = (Thread_Close_context *) queue_context; + _Thread_Cancel( context->cancel, the_thread, NULL ); +} - _Thread_queue_Context_initialize( &queue_context ); - _Thread_queue_Context_set_expected_level( &queue_context, 2 ); - _Thread_queue_Context_set_no_timeout( &queue_context ); - _Thread_State_acquire( the_thread, &queue_context.Lock_context.Lock_context ); +void _Thread_Close( + Thread_Control *the_thread, + Thread_Control *executing, + Thread_Close_context *context +) +{ + context->cancel = the_thread; + _Thread_queue_Context_set_enqueue_callout( + &context->Base, + _Thread_Close_enqueue_callout + ); + _Thread_queue_Context_set_no_timeout( &context->Base ); + _Thread_State_acquire_critical( + the_thread, + &context->Base.Lock_context.Lock_context + ); _Thread_Join( the_thread, STATES_WAITING_FOR_JOIN, executing, - &queue_context + &context->Base ); - _Thread_Cancel( the_thread, executing, NULL ); } void _Thread_Exit( -- cgit v1.2.3