/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup RTEMSTestSuites
*
* @brief This header file provides the support functions for the validation
* test cases.
*/
/*
* 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.
*/
#ifndef _TX_SUPPORT_H
#define _TX_SUPPORT_H
#include <rtems.h>
#include <rtems/irq-extension.h>
#include <rtems/score/atomic.h>
#include <rtems/score/threadq.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup RTEMSTestSuites
*
* @{
*/
typedef enum {
PRIO_PSEUDO_ISR,
PRIO_VERY_ULTRA_HIGH,
PRIO_ULTRA_HIGH,
PRIO_VERY_HIGH,
PRIO_HIGH,
PRIO_NORMAL,
PRIO_LOW,
PRIO_VERY_LOW,
PRIO_ULTRA_LOW
} Priority;
/**
* @brief This constants represents the default priority of the runner task.
*/
#define PRIO_DEFAULT 1
/**
* @brief This constants represents an invalid RTEMS task priority value.
*
* It should be an invalid priority value which is not equal to
* RTEMS_CURRENT_PRIORITY and RTEMS_TIMER_SERVER_DEFAULT_PRIORITY.
*/
#define PRIO_INVALID 0xfffffffe
/**
* @brief This constants represents a priority which is close to the priority
* of the idle thread.
*
* It may be used for the runner thread together with PRIO_FLEXIBLE for worker
* threads.
*/
#define PRIO_NEARLY_IDLE 126
/**
* @brief This constants represents a priority with a wider range of higher and
* lower priorities around it.
*
* It may be used for the worker threads together with PRIO_NEARLY_IDLE for the
* runner thread.
*/
#define PRIO_FLEXIBLE 64
/**
* @brief This constants represents an invalid RTEMS object identifier.
*/
#define INVALID_ID 0xfffffffd
/**
* @brief This constants represents an object name for tests.
*/
#define OBJECT_NAME rtems_build_name( 'T', 'E', 'S', 'T' )
#define CreateTask( name, priority ) \
DoCreateTask( \
rtems_build_name( name[ 0 ], name[ 1 ], name[ 2 ], name[ 3 ] ), \
priority \
)
#define SCHEDULER_A_ID 0xf010001
#define SCHEDULER_B_ID 0xf010002
#define SCHEDULER_C_ID 0xf010003
#define SCHEDULER_D_ID 0xf010004
rtems_id DoCreateTask( rtems_name name, rtems_task_priority priority );
void StartTask( rtems_id id, rtems_task_entry entry, void *arg );
void DeleteTask( rtems_id id );
void SuspendTask( rtems_id id );
void SuspendSelf( void );
void ResumeTask( rtems_id id );
bool IsTaskSuspended( rtems_id id );
rtems_event_set QueryPendingEvents( void );
rtems_event_set PollAnyEvents( void );
rtems_event_set ReceiveAnyEvents( void );
rtems_event_set ReceiveAnyEventsTimed( rtems_interval ticks );
void ReceiveAllEvents( rtems_event_set events );
void SendEvents( rtems_id id, rtems_event_set events );
rtems_mode GetMode( void );
rtems_mode SetMode( rtems_mode set, rtems_mode mask );
rtems_task_priority GetPriority( rtems_id id );
rtems_task_priority GetPriorityByScheduler(
rtems_id task_id,
rtems_id scheduler_id
);
rtems_task_priority SetPriority( rtems_id id, rtems_task_priority priority );
rtems_task_priority GetSelfPriority( void );
rtems_task_priority SetSelfPriority( rtems_task_priority priority );
rtems_task_priority SetSelfPriorityNoYield( rtems_task_priority priority );
rtems_id GetScheduler( rtems_id id );
rtems_id GetSelfScheduler( void );
void SetScheduler(
rtems_id task_id,
rtems_id scheduler_id,
rtems_task_priority priority
);
void SetSelfScheduler( rtems_id scheduler_id, rtems_task_priority priority );
void GetAffinity( rtems_id id, cpu_set_t *set );
void GetSelfAffinity( cpu_set_t *set );
void SetAffinity( rtems_id id, const cpu_set_t *set );
void SetSelfAffinity( const cpu_set_t *set );
void SetAffinityOne( rtems_id id, uint32_t cpu_index );
void SetSelfAffinityOne( uint32_t cpu_index );
void SetAffinityAll( rtems_id id );
void SetSelfAffinityAll( void );
void Yield( void );
void YieldTask( rtems_id id );
void AddProcessor( rtems_id scheduler_id, uint32_t cpu_index );
void RemoveProcessor( rtems_id scheduler_id, uint32_t cpu_index );
rtems_id CreateMutex( void );
rtems_id CreateMutexNoProtocol( void );
rtems_id CreateMutexFIFO( void );
bool IsMutexOwner( rtems_id id );
void DeleteMutex( rtems_id id );
void ObtainMutex( rtems_id id );
void ObtainMutexTimed( rtems_id id, rtems_interval ticks );
void ObtainMutexDeadlock( rtems_id id );
void ReleaseMutex( rtems_id id );
struct Thread_queue_Queue;
struct Thread_queue_Queue *GetMutexThreadQueue( rtems_id id );
void RestoreRunnerASR( void );
void RestoreRunnerMode( void );
void RestoreRunnerPriority( void );
struct _Thread_Control;
struct _Thread_Control *GetThread( rtems_id id );
struct _Thread_Control *GetExecuting( void );
void KillZombies( void );
void WaitForExecutionStop( rtems_id task_id );
void WaitForIntendToBlock( rtems_id task_id );
void WaitForHeir( uint32_t cpu_index, rtems_id task_id );
void WaitForNextTask( uint32_t cpu_index, rtems_id task_id );
typedef enum {
TASK_TIMER_INVALID,
TASK_TIMER_INACTIVE,
TASK_TIMER_TICKS,
TASK_TIMER_REALTIME,
TASK_TIMER_MONOTONIC
} TaskTimerState;
typedef struct {
TaskTimerState state;
uint64_t expire_ticks;
struct timespec expire_timespec;
} TaskTimerInfo;
void GetTaskTimerInfo( rtems_id id, TaskTimerInfo *info );
void GetTaskTimerInfoByThread(
struct _Thread_Control *thread,
TaskTimerInfo *info
);
void ClockTick( void );
/**
* @brief Simulates a clock tick with the final expire time point of
* UINT64_MAX for all clocks.
*
* This function does not update the clock ticks counter.
*/
void FinalClockTick( void );
/**
* @brief Simulates a single clock tick using the software timecounter.
*
* In contrast to ClockTick(), this function updates also CLOCK_MONOTONIC and
* CLOCK_REALTIME to the next software timecounter clock tick time point.
*
* This function is designed for test suites not having a clock driver.
*/
void TimecounterTick( void );
typedef uint32_t ( *GetTimecountHandler )( void );
/**
* @brief Sets the get timecount handler.
*
* Using this function will replace the timecounter of the clock driver.
*
* @return Returns the previous get timecount handler.
*/
GetTimecountHandler SetGetTimecountHandler( GetTimecountHandler handler );
/**
* @brief This constant represents the fake frequency of the software
* timecounter.
*/
#define SOFTWARE_TIMECOUNTER_FREQUENCY 1000000
/**
* @brief Gets the software timecount counter value.
*
* @return Returns the current software timecounter counter value.
*/
uint32_t GetTimecountCounter( void );
/**
* @brief Sets and gets the software timecount counter value.
*
* @param counter is the new software timecounter counter value.
*
* @return Returns the previous software timecounter counter value.
*/
uint32_t SetTimecountCounter( uint32_t counter );
/**
* @brief Return the task id of the timer server task
*
* This function is an attempt to avoid using RTEMS internal global
* _Timer_server throughout the validation test code.
*
* @return Returns the task id of the timer server task, if
* rtems_timer_initiate_server() has been invoked before,
* otherwise - if the timer server task does not exist -
* RTEMS_INVALID_ID is returned.
*/
rtems_id GetTimerServerTaskId( void );
/**
* @brief Undo the effects of rtems_timer_initiate_server()
*
* If rtems_timer_initiate_server() was never called before,
* nothing is done.
*
* If rtems_timer_initiate_server() was called before, the
* created thread and other resources are freed so that
* rtems_timer_initiate_server() can be called again.
* There should be no pending timers which are not yet executed
* by the server task. Naturally, there should be no
* timer server timers scheduled for execution.
*
* @return Returns true, if rtems_timer_initiate_server() has been
* invoked before and the timer server task has indeed been deleted,
* otherwise false.
*/
bool DeleteTimerServer( void );
typedef struct {
struct {
const void *begin;
void *free_begin;
const void *end;
} areas[ 2 ];
size_t count;
} MemoryContext;
void MemorySave( MemoryContext *ctx );
void MemoryRestore( const MemoryContext *ctx );
/**
* @brief Fails a dynamic memory allocation when the counter reaches zero.
*
* This function initializes an internal counter which is decremented before
* each dynamic memory allocation though the rtems_malloc() directive. When
* the counter decrements from one to zero, the allocation fails and NULL will
* be returned.
*
* @param counter is the initial counter value.
*/
void MemoryAllocationFailWhen( uint32_t counter );
typedef struct {
Chain_Node node;
void ( *handler )( void * );
void *arg;
Atomic_Uint done;
} CallWithinISRRequest;
void CallWithinISR( void ( *handler )( void * ), void *arg );
void CallWithinISRSubmit( CallWithinISRRequest *request );
void CallWithinISRWait( const CallWithinISRRequest *request );
typedef struct {
Thread_queue_Operations tq_ops;
const Thread_queue_Operations *wrapped_ops;
Thread_queue_Control thread_queue;
CallWithinISRRequest isr_request;
} WrapThreadQueueContext;
void WrapThreadQueueInitialize(
WrapThreadQueueContext *ctx,
void ( *handler )( void * ),
void *arg
);
void WrapThreadQueueExtract(
WrapThreadQueueContext *ctx,
struct _Thread_Control *thread
);
void WrapThreadQueueExtractDirect(
WrapThreadQueueContext *ctx,
Thread_Control *thread
);
void WrapThreadQueueDestroy( WrapThreadQueueContext *ctx );
struct Per_CPU_Control;
void SetPreemptionIntervention(
struct Per_CPU_Control *cpu,
void ( *handler )( void * ),
void *arg
);
rtems_vector_number GetValidInterruptVectorNumber(
const rtems_interrupt_attributes *required
);
rtems_vector_number GetTestableInterruptVector(
const rtems_interrupt_attributes *required
);
bool HasInterruptVectorEntriesInstalled( rtems_vector_number vector );
/**
* @brief Get the clock and context of a timer from RTEMS internal data.
*
* With exception of TIMER_DORMANT, the return values are bits or-ed together.
*
* @param id The timer ID.
*
* @retval TIMER_DORMANT Either the id argument is invalid or the timer has
* never been used before.
* @return The TIMER_CLASS_BIT_ON_TASK is set, if the timer server routine
* was or will be executed in task context, otherwise it was or will be
* executed in interrupt context.
*
* The TIMER_CLASS_BIT_TIME_OF_DAY is set, if the clock used is or was the
* ${/glossary/clock-realtime:/term}, otherwise the
* ${/glossary/clock-tick:/term} based clock is or was used.
*/
Timer_Classes GetTimerClass( rtems_id id );
/**
* @brief This structure provides data used by RTEMS to schedule a timer
* service routine.
*/
typedef struct {
/**
* @brief This member contains a reference to the timer service routine.
*/
rtems_timer_service_routine_entry routine;
/**
* @brief This member contains a reference to the user data to be provided
* to the timer service routine.
*/
void *user_data;
/**
* @brief This member contains the timer interval in ticks or seconds.
*/
Watchdog_Interval interval;
} Timer_Scheduling_Data;
/**
* @brief Get data related to scheduling a timer service routine
* from RTEMS internal structures.
*
* @param id The timer ID.
* @param[out] data If the reference is not NULL, the data retrieved from
* internal RTEMS structures is stored here.
*/
void GetTimerSchedulingData(
rtems_id id,
Timer_Scheduling_Data *data
);
/**
* @brief The various states of a timer.
*/
typedef enum {
TIMER_INVALID,
TIMER_INACTIVE,
TIMER_SCHEDULED,
TIMER_PENDING
} Timer_States;
/**
* @brief Get the state of a timer from RTEMS internal data.
*
* @param id The timer ID.
*
* @retval TIMER_INVALID The id argument is invalid.
* @retval TIMER_INACTIVE The timer is not scheduled (i.e. it is
* new, run off, or canceled).
* @retval TIMER_SCHEDULED The timer is scheduled.
* @retval TIMER_PENDING The timer is pending.
*/
Timer_States GetTimerState( rtems_id id );
/**
* @brief Mark the realtime clock as never set.
*
* This function manipulates RTEMS internal data structures to undo the
* effect of rtems_clock_set(). If the clock is not set, the function has no
* effect.
*/
void UnsetClock( void );
void FatalInitialExtension(
rtems_fatal_source source,
bool always_set_to_false,
rtems_fatal_code code
);
typedef void ( *FatalHandler )(
rtems_fatal_source source,
rtems_fatal_code code,
void *arg
);
void SetFatalHandler( FatalHandler fatal, void *arg );
void SetTaskSwitchExtension( rtems_task_switch_extension task_switch );
typedef struct {
uint32_t fatal;
uint32_t thread_begin;
uint32_t thread_create;
uint32_t thread_delete;
uint32_t thread_exitted;
uint32_t thread_restart;
uint32_t thread_start;
uint32_t thread_switch;
uint32_t thread_terminate;
} ExtensionCalls;
void ClearExtensionCalls( ExtensionCalls *calls );
void CopyExtensionCalls( const ExtensionCalls *from, ExtensionCalls *to );
void SetIORelaxHandler( void ( *handler )( void * ), void *arg );
void StartDelayThreadDispatch( uint32_t cpu_index );
void StopDelayThreadDispatch( uint32_t cpu_index );
bool AreInterruptsEnabled( void );
bool IsWhiteSpaceOnly( const char *s );
bool IsEqualIgnoreWhiteSpace( const char *a, const char *b );
#if defined(RTEMS_SMP)
bool TicketLockIsAvailable( const SMP_ticket_lock_Control *lock );
void TicketLockWaitForOwned( const SMP_ticket_lock_Control *lock );
void TicketLockWaitForOthers(
const SMP_ticket_lock_Control *lock,
unsigned int others
);
static inline bool ISRLockIsAvailable( const ISR_lock_Control *lock )
{
return TicketLockIsAvailable( &lock->Lock.Ticket_lock );
}
static inline void ISRLockWaitForOwned( const ISR_lock_Control *lock )
{
TicketLockWaitForOwned( &lock->Lock.Ticket_lock );
}
static inline void ISRLockWaitForOthers(
const ISR_lock_Control *lock,
unsigned int others
)
{
TicketLockWaitForOthers( &lock->Lock.Ticket_lock, others );
}
#endif
void *IdleBody( uintptr_t ignored );
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* _TX_SUPPORT_H */