/* SPDX-License-Identifier: BSD-2-Clause */ /** * @file * * @ingroup RTEMSTestSuitesValidation * * @brief This header file provides the functions to test the * @ref RTEMSScoreThreadQueue. */ /* * Copyright (C) 2021 embedded brains GmbH & Co. KG * * 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. */ #ifndef _TX_THREAD_QUEUE_H #define _TX_THREAD_QUEUE_H #include "tx-support.h" #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * @addtogroup RTEMSTestSuitesValidation * * @{ */ typedef enum { TQ_NODE_ONLY, TQ_NODE_VITAL, TQ_NODE_DISPENSABLE } TQNodeKind; typedef enum { TQ_WAIT_STATE_BLOCKED, TQ_WAIT_STATE_INTEND_TO_BLOCK, TQ_WAIT_STATE_READY_AGAIN } TQWaitState; typedef enum { TQ_BLOCKER_A, TQ_BLOCKER_B, TQ_BLOCKER_C, TQ_BLOCKER_D, TQ_BLOCKER_E, TQ_WORKER_F, TQ_HELPER_A, TQ_HELPER_B, TQ_HELPER_C, TQ_WORKER_COUNT } TQWorkerKind; typedef enum { TQ_MUTEX_A, TQ_MUTEX_B, TQ_MUTEX_C, TQ_MUTEX_D, TQ_MUTEX_NO_PROTOCOL, TQ_MUTEX_FIFO, TQ_MUTEX_COUNT } TQMutex; typedef enum { TQ_FIFO, TQ_PRIORITY } TQDiscipline; typedef enum { TQ_NO_WAIT, TQ_WAIT_FOREVER, TQ_WAIT_TIMED } TQWait; typedef enum { TQ_DEADLOCK_STATUS, TQ_DEADLOCK_FATAL } TQDeadlock; typedef enum { TQ_EVENT_ENQUEUE_PREPARE = RTEMS_EVENT_0, TQ_EVENT_ENQUEUE = RTEMS_EVENT_1, TQ_EVENT_ENQUEUE_DONE = RTEMS_EVENT_2, TQ_EVENT_SURRENDER = RTEMS_EVENT_3, TQ_EVENT_RUNNER_SYNC = RTEMS_EVENT_4, TQ_EVENT_RUNNER_SYNC_2 = RTEMS_EVENT_5, TQ_EVENT_HELPER_A_SYNC = RTEMS_EVENT_6, TQ_EVENT_HELPER_B_SYNC = RTEMS_EVENT_7, TQ_EVENT_MUTEX_A_OBTAIN = RTEMS_EVENT_8, TQ_EVENT_MUTEX_A_RELEASE = RTEMS_EVENT_9, TQ_EVENT_MUTEX_B_OBTAIN = RTEMS_EVENT_10, TQ_EVENT_MUTEX_B_RELEASE = RTEMS_EVENT_11, TQ_EVENT_BUSY_WAIT = RTEMS_EVENT_12, TQ_EVENT_FLUSH_ALL = RTEMS_EVENT_13, TQ_EVENT_FLUSH_PARTIAL = RTEMS_EVENT_14, TQ_EVENT_SCHEDULER_RECORD_START = RTEMS_EVENT_15, TQ_EVENT_SCHEDULER_RECORD_STOP = RTEMS_EVENT_16, TQ_EVENT_TIMEOUT = RTEMS_EVENT_17, TQ_EVENT_MUTEX_NO_PROTOCOL_OBTAIN = RTEMS_EVENT_18, TQ_EVENT_MUTEX_NO_PROTOCOL_RELEASE = RTEMS_EVENT_19, TQ_EVENT_ENQUEUE_FATAL = RTEMS_EVENT_20, TQ_EVENT_MUTEX_C_OBTAIN = RTEMS_EVENT_21, TQ_EVENT_MUTEX_C_RELEASE = RTEMS_EVENT_22, TQ_EVENT_MUTEX_FIFO_OBTAIN = RTEMS_EVENT_23, TQ_EVENT_MUTEX_FIFO_RELEASE = RTEMS_EVENT_24, TQ_EVENT_ENQUEUE_TIMED = RTEMS_EVENT_25, TQ_EVENT_MUTEX_D_OBTAIN = RTEMS_EVENT_26, TQ_EVENT_MUTEX_D_RELEASE = RTEMS_EVENT_27, TQ_EVENT_PIN = RTEMS_EVENT_28, TQ_EVENT_UNPIN = RTEMS_EVENT_29, TQ_EVENT_COUNT = RTEMS_EVENT_30 } TQEvent; typedef enum { TQ_ENQUEUE_BLOCKS, TQ_ENQUEUE_STICKY } TQEnqueueVariant; typedef struct TQContext { /** * @brief This member defines the thread queue discipline. */ TQDiscipline discipline; /** * @brief This member defines the enqueue wait behaviour. * * If TQ_NO_WAIT is used, then no thread queue enqueue shall be performed. */ TQWait wait; /** * @brief This member defines the enqueue variant. */ TQEnqueueVariant enqueue_variant; /** * @brief This member defines the deadlock enqueue behaviour. */ TQDeadlock deadlock; /** * @brief This member contains the runner task identifier. */ rtems_id runner_id; /** * @brief This member contains a reference to the runner task control block. */ rtems_tcb *runner_tcb; /** * @brief This member contains the worker task identifiers. */ rtems_id worker_id[ TQ_WORKER_COUNT ]; /** * @brief This member contains references to the worker task control * blocks. */ rtems_tcb *worker_tcb[ TQ_WORKER_COUNT ]; /** * @brief When a worker received an event, the corresponding element shall be * set to true. */ volatile bool event_received[ TQ_WORKER_COUNT ]; /** * @brief If this member is true, then the worker shall busy wait on request. */ volatile bool busy_wait[ TQ_WORKER_COUNT ]; /** * @brief When a worker is done processing its current event set, the * corresponding element shall be set to true. */ volatile bool done[ TQ_WORKER_COUNT ]; /** * @brief This member provides the counter used for the worker counters. */ Atomic_Uint counter; /** * @brief When a worker returned from TQEnqueue() the counter is incremented * and stored in this member. */ uint32_t worker_counter[ TQ_WORKER_COUNT ]; /** * @brief This member contains the last return status of a TQEnqueue() of the * corresponding worker. */ Status_Control status[ TQ_WORKER_COUNT ]; union { /** * @brief This member contains the identifier of an object providing the * thread queue under test. */ rtems_id thread_queue_id; /** * @brief This member contains the reference to object containing the * thread queue under test. */ void *thread_queue_object; }; /** * @brief This member contains the identifier of priority inheritance * mutexes. */ rtems_id mutex_id[ TQ_MUTEX_COUNT ]; /** * @brief This member provides the scheduler log. */ T_scheduler_log_40 scheduler_log; /** * @brief This member provides the get properties handler. */ void ( *get_properties )( struct TQContext *, TQWorkerKind ); /** * @brief This member provides the status convert handler. */ Status_Control ( *convert_status )( Status_Control ); /** * @brief This this member specifies how many threads shall be enqueued. */ uint32_t how_many; /** * @brief This this member contains the count of the least recently flushed * threads. */ uint32_t flush_count; /** * @brief This this member provides a context to jump back to before the * enqueue. */ jmp_buf before_enqueue; /** * @brief This member provides the thread queue enqueue prepare handler. */ void ( *enqueue_prepare )( struct TQContext * ); /** * @brief This member provides the thread queue enqueue handler. */ Status_Control ( *enqueue )( struct TQContext *, TQWait ); /** * @brief This member provides the thread queue enqueue done handler. */ void ( *enqueue_done )( struct TQContext * ); /** * @brief This member provides the thread queue surrender handler. */ Status_Control ( *surrender )( struct TQContext * ); /** * @brief This member provides the thread queue flush handler. * * The second parameter specifies the count of enqueued threads. While the * third parameter is true, all enqueued threads shall be extracted, * otherwise the thread queue shall be partially flushed. The handler shall * return the count of flushed threads. */ uint32_t ( *flush )( struct TQContext *, uint32_t, bool ); /** * @brief This member provides the get owner handler. */ rtems_tcb *( *get_owner )( struct TQContext * ); } TQContext; void TQSend( TQContext *ctx, TQWorkerKind worker, rtems_event_set events ); void TQSendAndWaitForExecutionStop( TQContext *ctx, TQWorkerKind worker, rtems_event_set events ); void TQSendAndWaitForIntendToBlock( TQContext *ctx, TQWorkerKind worker, rtems_event_set events ); void TQSendAndWaitForExecutionStopOrIntendToBlock( TQContext *ctx, TQWorkerKind worker, rtems_event_set events ); void TQSendAndSynchronizeRunner( TQContext *ctx, TQWorkerKind worker, rtems_event_set events ); void TQWaitForEventsReceived( const TQContext *ctx, TQWorkerKind worker ); void TQWaitForIntendToBlock( const TQContext *ctx, TQWorkerKind worker ); void TQWaitForExecutionStop( const TQContext *ctx, TQWorkerKind worker ); void TQClearDone( TQContext *ctx, TQWorkerKind worker ); void TQWaitForDone( const TQContext *ctx, TQWorkerKind worker ); void TQSynchronizeRunner( void ); void TQSynchronizeRunner2( void ); void TQResetCounter( TQContext *ctx ); uint32_t TQGetCounter( const TQContext *ctx ); uint32_t TQGetWorkerCounter( const TQContext *ctx, TQWorkerKind worker ); void TQMutexObtain( const TQContext *ctx, TQMutex mutex ); void TQMutexRelease( const TQContext *ctx, TQMutex mutex ); void TQSetPriority( const TQContext *ctx, TQWorkerKind worker, Priority priority ); Priority TQGetPriority( const TQContext *ctx, TQWorkerKind worker ); void TQSetScheduler( const TQContext *ctx, TQWorkerKind worker, rtems_id scheduler_id, Priority priority ); void TQInitialize( TQContext *ctx ); void TQDestroy( TQContext *ctx ); void TQReset( TQContext *ctx ); void TQSortMutexesByID( TQContext *ctx ); void TQGetProperties( TQContext *ctx, TQWorkerKind enqueued_worker ); Status_Control TQConvertStatus( TQContext *ctx, Status_Control status ); void TQEnqueuePrepare( TQContext *ctx ); Status_Control TQEnqueue( TQContext *ctx, TQWait wait ); Status_Control TQEnqueueFatal( TQContext *ctx ); void TQEnqueueDone( TQContext *ctx ); Status_Control TQSurrender( TQContext *ctx ); void TQFlush( TQContext *ctx, bool flush_all ); rtems_tcb *TQGetOwner( TQContext *ctx ); void TQSchedulerRecordStart( TQContext *ctx ); void TQSchedulerRecordStop( TQContext *ctx ); const T_scheduler_event *TQGetNextAny( TQContext *ctx, size_t *index ); const T_scheduler_event *TQGetNextBlock( TQContext *ctx, size_t *index ); const T_scheduler_event *TQGetNextUnblock( TQContext *ctx, size_t *index ); const T_scheduler_event *TQGetNextUpdatePriority( TQContext *ctx, size_t *index ); const T_scheduler_event *TQGetNextAskForHelp( TQContext *ctx, size_t *index ); void TQDoNothing( TQContext *ctx ); Status_Control TQDoNothingSuccessfully( TQContext *ctx ); Status_Control TQConvertStatusClassic( Status_Control status ); Status_Control TQConvertStatusPOSIX( Status_Control status ); void TQEnqueuePrepareDefault( TQContext *ctx ); void TQEnqueueDoneDefault( TQContext *ctx ); Status_Control TQEnqueueClassicSem( TQContext *ctx, TQWait wait ); Status_Control TQSurrenderClassicSem( TQContext *ctx ); rtems_tcb *TQGetOwnerClassicSem( TQContext *ctx ); typedef enum { TQ_SEM_BINARY, TQ_SEM_COUNTING } TQSemVariant; typedef struct TQSemContext { /** * @brief This member contains the base thread queue test context. */ TQContext base; /** * @brief This member defines the semaphore variant. */ TQSemVariant variant; /** * @brief This member provides the semaphore get count handler. */ uint32_t ( *get_count )( struct TQSemContext * ); /** * @brief This member provides the semaphore set count handler. */ void ( *set_count )( struct TQSemContext *, uint32_t ); } TQSemContext; Status_Control TQSemSurrender( TQSemContext *ctx ); uint32_t TQSemGetCount( TQSemContext *ctx ); void TQSemSetCount( TQSemContext *ctx, uint32_t count ); Status_Control TQSemSurrenderClassic( TQSemContext *ctx ); uint32_t TQSemGetCountClassic( TQSemContext *ctx ); void TQSemSetCountClassic( TQSemContext *ctx, uint32_t count ); typedef enum { TQ_MTX_NO_PROTOCOL, TQ_MTX_PRIORITY_INHERIT, TQ_MTX_PRIORITY_CEILING, TQ_MTX_MRSP } TQMtxProtocol; typedef enum { TQ_MTX_RECURSIVE_ALLOWED, TQ_MTX_RECURSIVE_DEADLOCK, TQ_MTX_RECURSIVE_UNAVAILABLE } TQMtxRecursive; typedef enum { TQ_MTX_NO_OWNER_CHECK, TQ_MTX_CHECKS_OWNER } TQMtxOwnerCheck; typedef struct TQMtxContext { /** * @brief This member contains the base thread queue test context. */ TQContext base; /** * @brief This member defines the locking protocol. */ TQMtxProtocol protocol; /** * @brief This member defines the recursive seize behaviour. */ TQMtxRecursive recursive; /** * @brief This member defines the owner check behaviour. */ TQMtxOwnerCheck owner_check; /** * @brief This member defines the priority ceiling of the mutex. * * Use PRIO_INVALID to indicate that the mutex does not provide a priority * ceiling. */ rtems_task_priority priority_ceiling; } TQMtxContext; /** @} */ #ifdef __cplusplus } #endif #endif /* _TX_THREAD_QUEUE_H */