diff options
Diffstat (limited to 'testsuites/validation/tx-thread-queue.c')
-rw-r--r-- | testsuites/validation/tx-thread-queue.c | 854 |
1 files changed, 854 insertions, 0 deletions
diff --git a/testsuites/validation/tx-thread-queue.c b/testsuites/validation/tx-thread-queue.c new file mode 100644 index 0000000000..1b0e8665c7 --- /dev/null +++ b/testsuites/validation/tx-thread-queue.c @@ -0,0 +1,854 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSTestSuites + * + * @brief This source file contains the implementation of the thread queue test + * support. + */ + +/* + * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tx-thread-queue.h" +#include "tx-support.h" +#include "ts-config.h" + +#include <rtems/score/threadimpl.h> +#include <rtems/rtems/semimpl.h> + +void TQSend( + TQContext *ctx, + TQWorkerKind worker, + rtems_event_set events +) +{ +#if defined( RTEMS_SMP ) + ctx->event_received[ worker ] = false; +#endif + + SendEvents( ctx->worker_id[ worker ], events ); +} + +void TQWaitForEventsReceived( const TQContext *ctx, TQWorkerKind worker ) +{ +#if defined( RTEMS_SMP ) + while ( !ctx->event_received[ worker ] ) { + /* Wait */ + } +#endif +} + +void TQWaitForExecutionStop( const TQContext *ctx, TQWorkerKind worker ) +{ +#if defined( RTEMS_SMP ) + WaitForExecutionStop( ctx->worker_id[ worker ] ); +#endif +} + +void TQSendAndWaitForExecutionStop( + TQContext *ctx, + TQWorkerKind worker, + rtems_event_set events +) +{ + TQSend( ctx, worker, events ); + +#if defined( RTEMS_SMP ) + TQWaitForEventsReceived( ctx, worker ); + WaitForExecutionStop( ctx->worker_id[ worker ] ); +#endif +} + +void TQWaitForIntendToBlock( const TQContext *ctx, TQWorkerKind worker ) +{ + const rtems_tcb *thread; + Thread_Wait_flags intend_to_block; + + thread = ctx->worker_tcb[ worker ]; + intend_to_block = THREAD_WAIT_CLASS_OBJECT | + THREAD_WAIT_STATE_INTEND_TO_BLOCK; + + while ( _Thread_Wait_flags_get_acquire( thread ) != intend_to_block ) { + /* Wait */ + } +} + +void TQSendAndWaitForIntendToBlock( + TQContext *ctx, + TQWorkerKind worker, + rtems_event_set events +) +{ + TQSend( ctx, worker, events ); + +#if defined( RTEMS_SMP ) + TQWaitForEventsReceived( ctx, worker ); + TQWaitForIntendToBlock( ctx, worker ); +#endif +} + +void TQSendAndWaitForExecutionStopOrIntendToBlock( + TQContext *ctx, + TQWorkerKind worker, + rtems_event_set events +) +{ +#if defined( RTEMS_SMP ) + const rtems_tcb *thread; + Thread_Wait_flags intend_to_block; +#endif + + TQSend( ctx, worker, events ); + +#if defined( RTEMS_SMP ) + TQWaitForEventsReceived( ctx, worker ); + thread = ctx->worker_tcb[ worker ]; + intend_to_block = THREAD_WAIT_CLASS_OBJECT | + THREAD_WAIT_STATE_INTEND_TO_BLOCK; + + while ( + _Thread_Is_executing_on_a_processor( thread ) && + _Thread_Wait_flags_get_acquire( thread ) != intend_to_block + ) { + /* Wait */ + } +#endif +} + +void TQSendAndSynchronizeRunner( + TQContext *ctx, + TQWorkerKind worker, + rtems_event_set events +) +{ + T_quiet_eq_u32( QueryPendingEvents() & TQ_EVENT_RUNNER_SYNC, 0 ); + TQSend( ctx, worker, events | TQ_EVENT_RUNNER_SYNC ); + TQSynchronizeRunner(); +} + +void TQClearDone( TQContext *ctx, TQWorkerKind worker ) +{ + ctx->done[ worker ] = false; +} + +void TQWaitForDone( const TQContext *ctx, TQWorkerKind worker ) +{ + while ( !ctx->done[ worker ] ) { + /* Wait */ + } +} + +void TQSynchronizeRunner( void ) +{ + ReceiveAllEvents( TQ_EVENT_RUNNER_SYNC ); +} + +void TQSynchronizeRunner2( void ) +{ + ReceiveAllEvents( TQ_EVENT_RUNNER_SYNC | TQ_EVENT_RUNNER_SYNC_2 ); +} + +void TQResetCounter( TQContext *ctx ) +{ + ctx->counter = 0; + memset( &ctx->worker_counter, 0, sizeof( ctx->worker_counter ) ); +} + +uint32_t TQGetCounter( const TQContext *ctx ) +{ + return ctx->counter; +} + +uint32_t TQGetWorkerCounter( const TQContext *ctx, TQWorkerKind worker ) +{ + return ctx->worker_counter[ worker ]; +} + +void TQMutexObtain( const TQContext *ctx, TQMutex mutex ) +{ + rtems_status_code sc; + + sc = rtems_semaphore_obtain( + ctx->mutex_id[ mutex ], + RTEMS_WAIT, + RTEMS_NO_TIMEOUT + ); + T_rsc_success( sc ); +} + +void TQMutexRelease( const TQContext *ctx, TQMutex mutex ) +{ + rtems_status_code sc; + + sc = rtems_semaphore_release( ctx->mutex_id[ mutex ] ); + T_rsc_success( sc ); +} + +void TQSetPriority( + const TQContext *ctx, + TQWorkerKind worker, + Priority priority +) +{ + SetPriority( ctx->worker_id[ worker ], priority ); +} + +Priority TQGetPriority( const TQContext *ctx, TQWorkerKind worker ) +{ + return GetPriority( ctx->worker_id[ worker ] ); +} + +void TQSetScheduler( + const TQContext *ctx, + TQWorkerKind worker, + rtems_id scheduler_id, + Priority priority +) +{ +#if defined( RTEMS_SMP ) + rtems_status_code sc; + + sc = rtems_task_set_scheduler( + ctx->worker_id[ worker ], + scheduler_id, + priority + ); + T_rsc_success( sc ); +#else + (void) scheduler_id; + SetPriority( ctx->worker_id[ worker ], priority ); +#endif +} + +static void Count( TQContext *ctx, TQWorkerKind worker ) +{ + unsigned int counter; + + counter = _Atomic_Fetch_add_uint( &ctx->counter, 1, ATOMIC_ORDER_RELAXED ); + ctx->worker_counter[ worker ] = counter + 1; +} + +static void Enqueue( TQContext *ctx, TQWorkerKind worker, TQWait wait ) +{ + ctx->status[ worker ] = TQEnqueue( ctx, wait ); + Count( ctx, worker ); +} + +static void ThreadQueueDeadlock( + rtems_fatal_source source, + rtems_fatal_code code, + void *arg +) +{ + TQContext *ctx; + + ctx = arg; + T_eq_int( source, INTERNAL_ERROR_CORE ); + T_eq_int( code, INTERNAL_ERROR_THREAD_QUEUE_DEADLOCK ); + SetFatalHandler( NULL, NULL ); + longjmp( ctx->before_enqueue, 1 ); +} + +static void Worker( rtems_task_argument arg, TQWorkerKind worker ) +{ + TQContext *ctx; + + ctx = (TQContext *) arg; + + while ( true ) { + rtems_event_set events; + + events = ReceiveAnyEvents(); + ctx->event_received[ worker ] = true; + + if ( ( events & TQ_EVENT_HELPER_A_SYNC ) != 0 ) { + SendEvents( ctx->worker_id[ TQ_HELPER_A ], TQ_EVENT_RUNNER_SYNC ); + } + + if ( ( events & TQ_EVENT_HELPER_B_SYNC ) != 0 ) { + SendEvents( ctx->worker_id[ TQ_HELPER_B ], TQ_EVENT_RUNNER_SYNC ); + } + + if ( ( events & TQ_EVENT_SCHEDULER_RECORD_START ) != 0 ) { + TQSchedulerRecordStart( ctx ); + } + + if ( ( events & TQ_EVENT_ENQUEUE_PREPARE ) != 0 ) { + TQEnqueuePrepare( ctx ); + } + + if ( ( events & TQ_EVENT_ENQUEUE ) != 0 ) { + Enqueue( ctx, worker, ctx->wait ); + } + + if ( ( events & TQ_EVENT_ENQUEUE_TIMED ) != 0 ) { + Enqueue( ctx, worker, TQ_WAIT_TIMED ); + } + + if ( ( events & TQ_EVENT_ENQUEUE_FATAL ) != 0 ) { + SetFatalHandler( ThreadQueueDeadlock, ctx ); + + if ( setjmp( ctx->before_enqueue ) == 0 ) { + ctx->status[ worker ] = STATUS_MINUS_ONE; + Enqueue( ctx, worker, ctx->wait ); + } else { + ctx->status[ worker ] = STATUS_DEADLOCK; + } + } + + if ( ( events & TQ_EVENT_TIMEOUT ) != 0 ) { + Per_CPU_Control *cpu_self; + + cpu_self = _Thread_Dispatch_disable(); + _Thread_Timeout( &ctx->worker_tcb[ worker ]->Timer.Watchdog ); + _Thread_Dispatch_direct( cpu_self ); + } + + if ( ( events & TQ_EVENT_FLUSH ) != 0 ) { + TQFlush( ctx ); + } + + if ( ( events & TQ_EVENT_ENQUEUE_DONE ) != 0 ) { + TQEnqueueDone( ctx ); + } + + if ( ( events & TQ_EVENT_SURRENDER ) != 0 ) { + Status_Control status; + + status = TQSurrender( ctx ); + T_eq_int( status, TQConvertStatus( ctx, STATUS_SUCCESSFUL ) ); + } + + if ( ( events & TQ_EVENT_MUTEX_A_OBTAIN ) != 0 ) { + TQMutexObtain( ctx, TQ_MUTEX_A ); + } + + if ( ( events & TQ_EVENT_MUTEX_A_RELEASE ) != 0 ) { + TQMutexRelease( ctx, TQ_MUTEX_A ); + } + + if ( ( events & TQ_EVENT_MUTEX_B_OBTAIN ) != 0 ) { + TQMutexObtain( ctx, TQ_MUTEX_B ); + } + + if ( ( events & TQ_EVENT_MUTEX_B_RELEASE ) != 0 ) { + TQMutexRelease( ctx, TQ_MUTEX_B ); + } + + if ( ( events & TQ_EVENT_MUTEX_C_OBTAIN ) != 0 ) { + TQMutexObtain( ctx, TQ_MUTEX_C ); + } + + if ( ( events & TQ_EVENT_MUTEX_C_RELEASE ) != 0 ) { + TQMutexRelease( ctx, TQ_MUTEX_C ); + } + + if ( ( events & TQ_EVENT_MUTEX_D_OBTAIN ) != 0 ) { + TQMutexObtain( ctx, TQ_MUTEX_D ); + } + + if ( ( events & TQ_EVENT_MUTEX_D_RELEASE ) != 0 ) { + TQMutexRelease( ctx, TQ_MUTEX_D ); + } + + if ( ( events & TQ_EVENT_MUTEX_NO_PROTOCOL_OBTAIN ) != 0 ) { + TQMutexObtain( ctx, TQ_MUTEX_NO_PROTOCOL ); + } + + if ( ( events & TQ_EVENT_MUTEX_NO_PROTOCOL_RELEASE ) != 0 ) { + TQMutexRelease( ctx, TQ_MUTEX_NO_PROTOCOL ); + } + + if ( ( events & TQ_EVENT_MUTEX_FIFO_OBTAIN ) != 0 ) { + TQMutexObtain( ctx, TQ_MUTEX_FIFO ); + } + + if ( ( events & TQ_EVENT_MUTEX_FIFO_RELEASE ) != 0 ) { + TQMutexRelease( ctx, TQ_MUTEX_FIFO ); + } + + if ( ( events & TQ_EVENT_PIN ) != 0 ) { + _Thread_Pin( _Thread_Get_executing() ); + } + + if ( ( events & TQ_EVENT_UNPIN ) != 0 ) { + Per_CPU_Control *cpu_self; + + cpu_self = _Thread_Dispatch_disable(); + _Thread_Unpin( _Thread_Get_executing(), cpu_self ); + _Thread_Dispatch_direct( cpu_self ); + } + + if ( ( events & TQ_EVENT_SCHEDULER_RECORD_STOP ) != 0 ) { + TQSchedulerRecordStop( ctx ); + } + + if ( ( events & TQ_EVENT_RUNNER_SYNC ) != 0 ) { + SendEvents( ctx->runner_id, TQ_EVENT_RUNNER_SYNC ); + } + + if ( ( events & TQ_EVENT_COUNT ) != 0 ) { + Count( ctx, worker ); + } + + if ( ( events & TQ_EVENT_BUSY_WAIT ) != 0 ) { + while ( ctx->busy_wait[ worker ] ) { + /* Wait */ + } + } + + if ( ( events & TQ_EVENT_RUNNER_SYNC_2 ) != 0 ) { + SendEvents( ctx->runner_id, TQ_EVENT_RUNNER_SYNC_2 ); + } + + ctx->done[ worker ] = true; + } +} + +static void BlockerA( rtems_task_argument arg ) +{ + Worker( arg, TQ_BLOCKER_A ); +} + +static void BlockerB( rtems_task_argument arg ) +{ + Worker( arg, TQ_BLOCKER_B ); +} + +static void BlockerC( rtems_task_argument arg ) +{ + Worker( arg, TQ_BLOCKER_C ); +} + +static void BlockerD( rtems_task_argument arg ) +{ + Worker( arg, TQ_BLOCKER_D ); +} + +static void BlockerE( rtems_task_argument arg ) +{ + Worker( arg, TQ_BLOCKER_E ); +} + +static void WorkerF( rtems_task_argument arg ) +{ + Worker( arg, TQ_WORKER_F ); +} + +static void HelperA( rtems_task_argument arg ) +{ + Worker( arg, TQ_HELPER_A ); +} + +static void HelperB( rtems_task_argument arg ) +{ + Worker( arg, TQ_HELPER_B ); +} + +static void HelperC( rtems_task_argument arg ) +{ + Worker( arg, TQ_HELPER_C ); +} + +void TQInitialize( TQContext *ctx ) +{ + rtems_status_code sc; + size_t i; + + ctx->runner_id = rtems_task_self(); + ctx->runner_tcb = GetThread( RTEMS_SELF ); + + /* + * Use a lower priority than all started worker tasks to make sure they wait + * for events. + */ + SetSelfPriority( PRIO_VERY_LOW ); + + for ( i = 0; i < RTEMS_ARRAY_SIZE( ctx->mutex_id ); ++i ) { + rtems_attribute attributes; + + attributes = RTEMS_BINARY_SEMAPHORE; + + if ( i == TQ_MUTEX_NO_PROTOCOL ) { + attributes |= RTEMS_PRIORITY; + } else if ( i == TQ_MUTEX_FIFO ) { + attributes |= RTEMS_FIFO; + } else { + attributes |= RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY; + } + + sc = rtems_semaphore_create( + rtems_build_name( 'M', 'T', 'X', 'A' + i ), + 1, + attributes, + 0, + &ctx->mutex_id[ i ] + ); + T_rsc_success( sc ); + } + + ctx->worker_id[ TQ_BLOCKER_A ] = CreateTask( "BLKA", PRIO_HIGH ); + StartTask( ctx->worker_id[ TQ_BLOCKER_A ], BlockerA, ctx ); + ctx->worker_id[ TQ_BLOCKER_B ] = CreateTask( "BLKB", PRIO_VERY_HIGH ); + StartTask( ctx->worker_id[ TQ_BLOCKER_B ], BlockerB, ctx ); + ctx->worker_id[ TQ_BLOCKER_C ] = CreateTask( "BLKC", PRIO_ULTRA_HIGH ); + StartTask( ctx->worker_id[ TQ_BLOCKER_C ], BlockerC, ctx ); + ctx->worker_id[ TQ_BLOCKER_D ] = CreateTask( "BLKD", PRIO_LOW ); + StartTask( ctx->worker_id[ TQ_BLOCKER_D ], BlockerD, ctx ); + ctx->worker_id[ TQ_BLOCKER_E ] = CreateTask( "BLKE", PRIO_LOW ); + StartTask( ctx->worker_id[ TQ_BLOCKER_E ], BlockerE, ctx ); + ctx->worker_id[ TQ_WORKER_F ] = CreateTask( "WRKF", PRIO_LOW ); + StartTask( ctx->worker_id[ TQ_WORKER_F ], WorkerF, ctx ); + ctx->worker_id[ TQ_HELPER_A ] = CreateTask( "HLPA", PRIO_LOW ); + StartTask( ctx->worker_id[ TQ_HELPER_A ], HelperA, ctx ); + ctx->worker_id[ TQ_HELPER_B ] = CreateTask( "HLPB", PRIO_LOW ); + StartTask( ctx->worker_id[ TQ_HELPER_B ], HelperB, ctx ); + ctx->worker_id[ TQ_HELPER_C ] = CreateTask( "HLPC", PRIO_LOW ); + StartTask( ctx->worker_id[ TQ_HELPER_C ], HelperC, ctx ); + + for (i = 0; i < RTEMS_ARRAY_SIZE( ctx->worker_tcb ); ++i) { + ctx->worker_tcb[ i ] = GetThread( ctx->worker_id[ i ] ); + } + + SetSelfPriority( PRIO_NORMAL ); +} + +void TQDestroy( TQContext *ctx ) +{ + size_t i; + + for ( i = 0; i < RTEMS_ARRAY_SIZE( ctx->worker_id ); ++i ) { + DeleteTask( ctx->worker_id[ i ] ); + } + + for ( i = 0; i < RTEMS_ARRAY_SIZE( ctx->mutex_id ); ++i ) { + if ( ctx->mutex_id[ i ] != 0 ) { + rtems_status_code sc; + + sc = rtems_semaphore_delete( ctx->mutex_id[ i ] ); + T_rsc_success( sc ); + } + } + + RestoreRunnerPriority(); +} + +void TQReset( TQContext *ctx ) +{ + rtems_id scheduler_id; + + scheduler_id = SCHEDULER_A_ID; + SetScheduler( ctx->runner_id, scheduler_id, PRIO_NORMAL ); + TQSetScheduler( ctx, TQ_BLOCKER_A, scheduler_id, PRIO_HIGH ); + TQSetScheduler( ctx, TQ_BLOCKER_B, scheduler_id, PRIO_VERY_HIGH ); + TQSetScheduler( ctx, TQ_BLOCKER_C, scheduler_id, PRIO_ULTRA_HIGH ); + TQSetScheduler( ctx, TQ_BLOCKER_D, scheduler_id, PRIO_LOW ); + TQSetScheduler( ctx, TQ_BLOCKER_E, scheduler_id, PRIO_LOW ); + TQSetScheduler( ctx, TQ_HELPER_A, scheduler_id, PRIO_LOW ); + TQSetScheduler( ctx, TQ_HELPER_B, scheduler_id, PRIO_LOW ); + TQSetScheduler( ctx, TQ_HELPER_C, scheduler_id, PRIO_LOW ); +} + +void TQSortMutexesByID( TQContext *ctx ) +{ + size_t i; + size_t n; + + n = 3; + + /* Bubble sort */ + for ( i = 1; i < n ; ++i ) { + size_t j; + + for ( j = 0; j < n - i; ++j ) { + if ( ctx->mutex_id[ j ] > ctx->mutex_id[ j + 1 ] ) { + rtems_id tmp; + + tmp = ctx->mutex_id[ j ]; + ctx->mutex_id[ j ] = ctx->mutex_id[ j + 1 ]; + ctx->mutex_id[ j + 1 ] = tmp; + } + } + } +} + +void TQGetProperties( TQContext *ctx, TQWorkerKind enqueued_worker ) +{ + ( *ctx->get_properties )( ctx, enqueued_worker ); +} + +Status_Control TQConvertStatus( TQContext *ctx, Status_Control status ) +{ + return ( *ctx->convert_status )( status ); +} + +void TQEnqueuePrepare( TQContext *ctx ) +{ + ( *ctx->enqueue_prepare )( ctx ); +} + +Status_Control TQEnqueue( TQContext *ctx, TQWait wait ) +{ + return ( *ctx->enqueue )( ctx, wait ); +} + +Status_Control TQEnqueueFatal( TQContext *ctx ) +{ + Status_Control status; + + SetFatalHandler( ThreadQueueDeadlock, ctx ); + status = STATUS_MINUS_ONE; + + if ( setjmp( ctx->before_enqueue ) == 0 ) { + status = TQEnqueue( ctx, ctx->wait ); + } else { + status = STATUS_DEADLOCK; + } + + return status; +} + +void TQEnqueueDone( TQContext *ctx ) +{ + ( *ctx->enqueue_done )( ctx ); +} + +Status_Control TQSurrender( TQContext *ctx ) +{ + return ( *ctx->surrender )( ctx ); +} + +void TQFlush( TQContext *ctx ) +{ + ( *ctx->flush )( ctx ); +} + +rtems_tcb *TQGetOwner( TQContext *ctx ) +{ + rtems_tcb *( *get_owner )( TQContext * ); + + get_owner = ctx->get_owner; + + if ( get_owner == NULL ) { + return NULL; + } + + return ( *get_owner )( ctx ); +} + +void TQSchedulerRecordStart( TQContext *ctx ) +{ + T_scheduler_log *log; + + log = T_scheduler_record_40( &ctx->scheduler_log ); + T_null( log ); +} + +void TQSchedulerRecordStop( TQContext *ctx ) +{ + T_scheduler_log *log; + + log = T_scheduler_record( NULL ); + T_eq_ptr( &log->header, &ctx->scheduler_log.header ); +} + +const T_scheduler_event *TQGetNextAny( TQContext *ctx, size_t *index ) +{ + return T_scheduler_next_any( + &ctx->scheduler_log.header, + index + ); +} + +const T_scheduler_event *TQGetNextBlock( TQContext *ctx, size_t *index ) +{ + return T_scheduler_next( + &ctx->scheduler_log.header, + T_SCHEDULER_BLOCK, + index + ); +} + +const T_scheduler_event *TQGetNextUnblock( TQContext *ctx, size_t *index ) +{ + return T_scheduler_next( + &ctx->scheduler_log.header, + T_SCHEDULER_UNBLOCK, + index + ); +} + +const T_scheduler_event *TQGetNextUpdatePriority( + TQContext *ctx, + size_t *index +) +{ + return T_scheduler_next( + &ctx->scheduler_log.header, + T_SCHEDULER_UPDATE_PRIORITY, + index + ); +} + +const T_scheduler_event *TQGetNextAskForHelp( + TQContext *ctx, + size_t *index +) +{ + return T_scheduler_next( + &ctx->scheduler_log.header, + T_SCHEDULER_ASK_FOR_HELP, + index + ); +} + +void TQDoNothing( TQContext *ctx ) +{ + (void) ctx; +} + +Status_Control TQDoNothingSuccessfully( TQContext *ctx ) +{ + (void) ctx; + + return STATUS_SUCCESSFUL; +} + +Status_Control TQConvertStatusClassic( Status_Control status ) +{ + return STATUS_BUILD( STATUS_GET_CLASSIC( status ), 0 ); +} + +Status_Control TQConvertStatusPOSIX( Status_Control status ) +{ + return STATUS_BUILD( 0, STATUS_GET_POSIX( status ) ); +} + +void TQEnqueuePrepareDefault( TQContext *ctx ) +{ + Status_Control status; + + status = TQEnqueue( ctx, TQ_NO_WAIT ); + T_eq_int( status, TQConvertStatus( ctx, STATUS_SUCCESSFUL ) ); +} + +void TQEnqueueDoneDefault( TQContext *ctx ) +{ + Status_Control status; + + status = TQSurrender( ctx ); + T_eq_int( status, TQConvertStatus( ctx, STATUS_SUCCESSFUL ) ); +} + +Status_Control TQEnqueueClassicSem( TQContext *ctx, TQWait wait ) +{ + rtems_status_code sc; + rtems_option option; + rtems_option timeout; + + switch ( wait ) { + case TQ_WAIT_FOREVER: + option = RTEMS_WAIT; + timeout = RTEMS_NO_TIMEOUT; + break; + case TQ_WAIT_TIMED: + option = RTEMS_WAIT; + timeout = UINT32_MAX; + break; + default: + option = RTEMS_NO_WAIT; + timeout = 0; + break; + } + + sc = rtems_semaphore_obtain( ctx->thread_queue_id, option, timeout ); + + return STATUS_BUILD( sc, 0 ); +} + +Status_Control TQSurrenderClassicSem( TQContext *ctx ) +{ + rtems_status_code sc; + + sc = rtems_semaphore_release( ctx->thread_queue_id ); + + return STATUS_BUILD( sc, 0 ); +} + +rtems_tcb *TQGetOwnerClassicSem( TQContext *ctx ) +{ + Semaphore_Control *semaphore; + Thread_queue_Context queue_context; + rtems_tcb *thread; + + semaphore = _Semaphore_Get( ctx->thread_queue_id, &queue_context ); + T_assert_not_null( semaphore ); + thread = semaphore->Core_control.Wait_queue.Queue.owner; + _ISR_lock_ISR_enable( &queue_context.Lock_context.Lock_context ); + + return thread; +} + +uint32_t TQSemGetCount( TQSemContext *ctx ) +{ + return ( *ctx->get_count )( ctx ); +} + +void TQSemSetCount( TQSemContext *ctx, uint32_t count ) +{ + ( *ctx->set_count )( ctx, count ); +} + +uint32_t TQSemGetCountClassic( TQSemContext *ctx ) +{ + Semaphore_Control *semaphore; + Thread_queue_Context queue_context; + uint32_t count; + + semaphore = _Semaphore_Get( ctx->base.thread_queue_id, &queue_context ); + T_assert_not_null( semaphore ); + count = semaphore->Core_control.Semaphore.count; + _ISR_lock_ISR_enable( &queue_context.Lock_context.Lock_context ); + + return count; +} + +void TQSemSetCountClassic( TQSemContext *ctx, uint32_t count ) +{ + Semaphore_Control *semaphore; + Thread_queue_Context queue_context; + + semaphore = _Semaphore_Get( ctx->base.thread_queue_id, &queue_context ); + T_assert_not_null( semaphore ); + semaphore->Core_control.Semaphore.count = count; + _ISR_lock_ISR_enable( &queue_context.Lock_context.Lock_context ); +} |