mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-16 12:55:26 +08:00
Fixed many warnings for unused parameters. Some cases were a simple matter of adding "(void) param" at the beginning of the function, while others required ensuring that addition was inside the proper conditional section. Found with GCC's warning -Wunused-paramter.
1083 lines
22 KiB
C
1083 lines
22 KiB
C
/* SPDX-License-Identifier: BSD-2-Clause */
|
|
|
|
/**
|
|
* @file
|
|
*
|
|
* @ingroup RTEMSTestSuitesValidation
|
|
*
|
|
* @brief This source file contains the implementation of support functions for
|
|
* the validation test cases.
|
|
*/
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "tx-support.h"
|
|
#include "ts-config.h"
|
|
|
|
#include <rtems/test.h>
|
|
#include <rtems/score/percpu.h>
|
|
#include <rtems/score/smpimpl.h>
|
|
#include <rtems/score/threaddispatch.h>
|
|
#include <rtems/score/threadimpl.h>
|
|
#include <rtems/rtems/semimpl.h>
|
|
|
|
#include <string.h>
|
|
|
|
rtems_id DoCreateTask( rtems_name name, rtems_task_priority priority )
|
|
{
|
|
rtems_status_code sc;
|
|
rtems_id id;
|
|
|
|
sc = rtems_task_create(
|
|
name,
|
|
priority,
|
|
TEST_MINIMUM_STACK_SIZE,
|
|
RTEMS_DEFAULT_MODES,
|
|
RTEMS_DEFAULT_ATTRIBUTES,
|
|
&id
|
|
);
|
|
T_assert_rsc_success( sc );
|
|
|
|
return id;
|
|
}
|
|
|
|
void StartTask( rtems_id id, rtems_task_entry entry, void *arg )
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_task_start( id, entry, (rtems_task_argument) arg);
|
|
T_assert_rsc_success( sc );
|
|
}
|
|
|
|
void DeleteTask( rtems_id id )
|
|
{
|
|
if ( id != 0 ) {
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_task_delete( id );
|
|
T_quiet_rsc_success( sc );
|
|
}
|
|
}
|
|
|
|
void SuspendTask( rtems_id id )
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_task_suspend( id );
|
|
T_quiet_rsc_success( sc );
|
|
}
|
|
|
|
void SuspendSelf( void )
|
|
{
|
|
SuspendTask( RTEMS_SELF );
|
|
}
|
|
|
|
void ResumeTask( rtems_id id )
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_task_resume( id );
|
|
T_quiet_rsc_success( sc );
|
|
}
|
|
|
|
bool IsTaskSuspended( rtems_id id )
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_task_is_suspended( id );
|
|
T_quiet_true( sc == RTEMS_SUCCESSFUL || sc == RTEMS_ALREADY_SUSPENDED );
|
|
|
|
return sc == RTEMS_ALREADY_SUSPENDED;
|
|
}
|
|
|
|
rtems_event_set QueryPendingEvents( void )
|
|
{
|
|
rtems_status_code sc;
|
|
rtems_event_set events;
|
|
|
|
events = 0;
|
|
sc = rtems_event_receive(
|
|
RTEMS_PENDING_EVENTS,
|
|
RTEMS_EVENT_ALL | RTEMS_NO_WAIT,
|
|
0,
|
|
&events
|
|
);
|
|
T_quiet_rsc_success( sc );
|
|
|
|
return events;
|
|
}
|
|
|
|
rtems_event_set PollAnyEvents( void )
|
|
{
|
|
rtems_event_set events;
|
|
|
|
events = 0;
|
|
(void) rtems_event_receive(
|
|
RTEMS_ALL_EVENTS,
|
|
RTEMS_EVENT_ANY | RTEMS_NO_WAIT,
|
|
0,
|
|
&events
|
|
);
|
|
|
|
return events;
|
|
}
|
|
|
|
rtems_event_set ReceiveAnyEvents( void )
|
|
{
|
|
return ReceiveAnyEventsTimed( RTEMS_NO_TIMEOUT );
|
|
}
|
|
|
|
rtems_event_set ReceiveAnyEventsTimed( rtems_interval ticks )
|
|
{
|
|
rtems_event_set events;
|
|
|
|
events = 0;
|
|
(void) rtems_event_receive(
|
|
RTEMS_ALL_EVENTS,
|
|
RTEMS_EVENT_ANY | RTEMS_WAIT,
|
|
ticks,
|
|
&events
|
|
);
|
|
|
|
return events;
|
|
}
|
|
|
|
void ReceiveAllEvents( rtems_event_set events )
|
|
{
|
|
rtems_status_code sc;
|
|
rtems_event_set received;
|
|
|
|
received = 0;
|
|
sc = rtems_event_receive(
|
|
events,
|
|
RTEMS_EVENT_ALL | RTEMS_WAIT,
|
|
RTEMS_NO_TIMEOUT,
|
|
&received
|
|
);
|
|
T_quiet_rsc_success( sc );
|
|
T_quiet_eq_u32( received, events );
|
|
}
|
|
|
|
void SendEvents( rtems_id id, rtems_event_set events )
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_event_send( id, events );
|
|
T_quiet_rsc_success( sc );
|
|
}
|
|
|
|
rtems_mode GetMode( void )
|
|
{
|
|
return SetMode( RTEMS_DEFAULT_MODES, RTEMS_CURRENT_MODE );
|
|
}
|
|
|
|
rtems_mode SetMode( rtems_mode set, rtems_mode mask )
|
|
{
|
|
rtems_status_code sc;
|
|
rtems_mode previous;
|
|
|
|
sc = rtems_task_mode( set, mask, &previous );
|
|
T_quiet_rsc_success( sc );
|
|
|
|
return previous;
|
|
}
|
|
|
|
rtems_task_priority GetPriority( rtems_id id )
|
|
{
|
|
return SetPriority( id, RTEMS_CURRENT_PRIORITY );
|
|
}
|
|
|
|
rtems_task_priority GetPriorityByScheduler(
|
|
rtems_id task_id,
|
|
rtems_id scheduler_id
|
|
)
|
|
{
|
|
rtems_status_code sc;
|
|
rtems_task_priority priority;
|
|
|
|
priority = PRIO_INVALID;
|
|
sc = rtems_task_get_priority( task_id, scheduler_id, &priority );
|
|
|
|
if ( sc != RTEMS_SUCCESSFUL ) {
|
|
return PRIO_INVALID;
|
|
}
|
|
|
|
return priority;
|
|
}
|
|
|
|
rtems_task_priority SetPriority( rtems_id id, rtems_task_priority priority )
|
|
{
|
|
rtems_status_code sc;
|
|
rtems_task_priority previous;
|
|
|
|
previous = PRIO_INVALID;
|
|
sc = rtems_task_set_priority( id, priority, &previous );
|
|
T_quiet_rsc_success( sc );
|
|
|
|
return previous;
|
|
}
|
|
|
|
rtems_task_priority GetSelfPriority( void )
|
|
{
|
|
return SetPriority( RTEMS_SELF, RTEMS_CURRENT_PRIORITY );
|
|
}
|
|
|
|
rtems_task_priority SetSelfPriority( rtems_task_priority priority )
|
|
{
|
|
return SetPriority( RTEMS_SELF, priority );
|
|
}
|
|
|
|
rtems_task_priority SetSelfPriorityNoYield( rtems_task_priority priority )
|
|
{
|
|
rtems_status_code sc;
|
|
rtems_id id;
|
|
|
|
/*
|
|
* If the priority is lowered, then this sequence ensures that we do not
|
|
* carry out an implicit yield.
|
|
*/
|
|
|
|
sc = rtems_semaphore_create(
|
|
rtems_build_name( 'T', 'E', 'M', 'P' ),
|
|
0,
|
|
RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_PRIORITY_CEILING,
|
|
1,
|
|
&id
|
|
);
|
|
T_quiet_rsc_success( sc );
|
|
|
|
priority = SetSelfPriority( priority );
|
|
ReleaseMutex( id );
|
|
DeleteMutex( id );
|
|
|
|
return priority;
|
|
}
|
|
|
|
rtems_id GetScheduler( rtems_id id )
|
|
{
|
|
rtems_status_code sc;
|
|
rtems_id scheduler_id;
|
|
|
|
scheduler_id = 0xffffffff;
|
|
sc = rtems_task_get_scheduler( id, &scheduler_id );
|
|
T_quiet_rsc_success( sc );
|
|
|
|
return scheduler_id;
|
|
}
|
|
|
|
rtems_id GetSelfScheduler( void )
|
|
{
|
|
return GetScheduler( RTEMS_SELF );
|
|
}
|
|
|
|
void SetScheduler(
|
|
rtems_id task_id,
|
|
rtems_id scheduler_id,
|
|
rtems_task_priority priority
|
|
)
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_task_set_scheduler( task_id, scheduler_id, priority );
|
|
T_quiet_rsc_success( sc );
|
|
}
|
|
|
|
void SetSelfScheduler( rtems_id scheduler_id, rtems_task_priority priority )
|
|
{
|
|
SetScheduler( RTEMS_SELF, scheduler_id, priority );
|
|
}
|
|
|
|
void GetAffinity( rtems_id id, cpu_set_t *set )
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
CPU_ZERO( set );
|
|
sc = rtems_task_get_affinity( id, sizeof( *set ), set );
|
|
T_quiet_rsc_success( sc );
|
|
}
|
|
|
|
void GetSelfAffinity( cpu_set_t *set )
|
|
{
|
|
GetAffinity( RTEMS_SELF, set );
|
|
}
|
|
|
|
void SetAffinity( rtems_id id, const cpu_set_t *set )
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_task_set_affinity( id, sizeof( *set ), set );
|
|
T_quiet_rsc_success( sc );
|
|
}
|
|
|
|
void SetSelfAffinity( const cpu_set_t *set )
|
|
{
|
|
SetAffinity( RTEMS_SELF, set );
|
|
}
|
|
|
|
void SetAffinityOne( rtems_id id, uint32_t cpu_index )
|
|
{
|
|
cpu_set_t set;
|
|
|
|
CPU_ZERO( &set );
|
|
CPU_SET( (int) cpu_index, &set );
|
|
SetAffinity( id, &set );
|
|
}
|
|
|
|
void SetSelfAffinityOne( uint32_t cpu_index )
|
|
{
|
|
SetAffinityOne( RTEMS_SELF, cpu_index );
|
|
}
|
|
|
|
void SetAffinityAll( rtems_id id )
|
|
{
|
|
cpu_set_t set;
|
|
|
|
CPU_FILL( &set );
|
|
SetAffinity( id, &set );
|
|
}
|
|
|
|
void SetSelfAffinityAll( void )
|
|
{
|
|
SetAffinityAll( RTEMS_SELF );
|
|
}
|
|
|
|
void Yield( void )
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_task_wake_after( RTEMS_YIELD_PROCESSOR );
|
|
T_quiet_rsc_success( sc );
|
|
}
|
|
|
|
void YieldTask( rtems_id id )
|
|
{
|
|
Thread_Control *the_thread;
|
|
ISR_lock_Context lock_context;
|
|
Per_CPU_Control *cpu_self;
|
|
|
|
the_thread = _Thread_Get( id, &lock_context );
|
|
|
|
if ( the_thread == NULL ) {
|
|
return;
|
|
}
|
|
|
|
cpu_self = _Thread_Dispatch_disable_critical( &lock_context );
|
|
_ISR_lock_ISR_enable( &lock_context);
|
|
_Thread_Yield( the_thread );
|
|
_Thread_Dispatch_direct( cpu_self );
|
|
}
|
|
|
|
void AddProcessor( rtems_id scheduler_id, uint32_t cpu_index )
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_scheduler_add_processor( scheduler_id, cpu_index );
|
|
T_quiet_rsc_success( sc );
|
|
}
|
|
|
|
void RemoveProcessor( rtems_id scheduler_id, uint32_t cpu_index )
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_scheduler_remove_processor( scheduler_id, cpu_index );
|
|
T_quiet_rsc_success( sc );
|
|
}
|
|
|
|
rtems_id CreateMutex( void )
|
|
{
|
|
rtems_status_code sc;
|
|
rtems_id id;
|
|
|
|
id = INVALID_ID;
|
|
sc = rtems_semaphore_create(
|
|
rtems_build_name( 'M', 'U', 'T', 'X' ),
|
|
1,
|
|
RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY,
|
|
0,
|
|
&id
|
|
);
|
|
T_rsc_success( sc );
|
|
|
|
return id;
|
|
}
|
|
|
|
rtems_id CreateMutexNoProtocol( void )
|
|
{
|
|
rtems_status_code sc;
|
|
rtems_id id;
|
|
|
|
id = INVALID_ID;
|
|
sc = rtems_semaphore_create(
|
|
rtems_build_name( 'M', 'U', 'T', 'X' ),
|
|
1,
|
|
RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY,
|
|
0,
|
|
&id
|
|
);
|
|
T_rsc_success( sc );
|
|
|
|
return id;
|
|
}
|
|
|
|
rtems_id CreateMutexFIFO( void )
|
|
{
|
|
rtems_status_code sc;
|
|
rtems_id id;
|
|
|
|
id = INVALID_ID;
|
|
sc = rtems_semaphore_create(
|
|
rtems_build_name( 'M', 'U', 'T', 'X' ),
|
|
1,
|
|
RTEMS_BINARY_SEMAPHORE | RTEMS_FIFO,
|
|
0,
|
|
&id
|
|
);
|
|
T_rsc_success( sc );
|
|
|
|
return id;
|
|
}
|
|
|
|
void DeleteMutex( rtems_id id )
|
|
{
|
|
if ( id != INVALID_ID ) {
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_semaphore_delete( id );
|
|
T_rsc_success( sc );
|
|
}
|
|
}
|
|
|
|
bool IsMutexOwner( rtems_id id )
|
|
{
|
|
Semaphore_Control *the_semaphore;
|
|
Thread_queue_Context queue_context;
|
|
|
|
the_semaphore = _Semaphore_Get( id, &queue_context );
|
|
if ( the_semaphore == NULL ) {
|
|
return false;
|
|
}
|
|
|
|
_ISR_lock_ISR_enable( &queue_context.Lock_context.Lock_context );
|
|
return the_semaphore->Core_control.Wait_queue.Queue.owner ==
|
|
_Thread_Get_executing();
|
|
}
|
|
|
|
void ObtainMutex( rtems_id id )
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_semaphore_obtain( id, RTEMS_WAIT, RTEMS_NO_TIMEOUT );
|
|
T_rsc_success( sc );
|
|
}
|
|
|
|
void ObtainMutexTimed( rtems_id id, rtems_interval ticks )
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_semaphore_obtain( id, RTEMS_WAIT, ticks );
|
|
T_rsc_success( sc );
|
|
}
|
|
|
|
void ObtainMutexDeadlock( rtems_id id )
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_semaphore_obtain( id, RTEMS_WAIT, RTEMS_NO_TIMEOUT );
|
|
T_rsc( sc, RTEMS_INCORRECT_STATE );
|
|
}
|
|
|
|
void ReleaseMutex( rtems_id id )
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_semaphore_release( id );
|
|
T_rsc_success( sc );
|
|
}
|
|
|
|
Thread_queue_Queue *GetMutexThreadQueue( rtems_id id )
|
|
{
|
|
Semaphore_Control *the_semaphore;
|
|
Thread_queue_Context queue_context;
|
|
|
|
the_semaphore = _Semaphore_Get( id, &queue_context );
|
|
if ( the_semaphore == NULL ) {
|
|
return NULL;
|
|
}
|
|
|
|
_ISR_lock_ISR_enable( &queue_context.Lock_context.Lock_context );
|
|
return &the_semaphore->Core_control.Wait_queue.Queue;
|
|
}
|
|
|
|
void RestoreRunnerASR( void )
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_signal_catch( NULL, RTEMS_DEFAULT_MODES );
|
|
T_quiet_rsc_success( sc );
|
|
}
|
|
|
|
void RestoreRunnerMode( void )
|
|
{
|
|
rtems_status_code sc;
|
|
rtems_mode mode;
|
|
|
|
sc = rtems_task_mode( RTEMS_DEFAULT_MODES, RTEMS_ALL_MODE_MASKS, &mode );
|
|
T_quiet_rsc_success( sc );
|
|
}
|
|
|
|
void RestoreRunnerPriority( void )
|
|
{
|
|
SetSelfPriority( 1 );
|
|
}
|
|
|
|
void RestoreRunnerScheduler( void )
|
|
{
|
|
SetSelfScheduler( SCHEDULER_A_ID, 1 );
|
|
}
|
|
|
|
Thread_Control *GetThread( rtems_id id )
|
|
{
|
|
Thread_Control *the_thread;
|
|
ISR_lock_Context lock_context;
|
|
|
|
the_thread = _Thread_Get( id, &lock_context );
|
|
|
|
if ( the_thread == NULL ) {
|
|
return NULL;
|
|
}
|
|
|
|
_ISR_lock_ISR_enable( &lock_context);
|
|
return the_thread;
|
|
}
|
|
|
|
Thread_Control *GetExecuting( void )
|
|
{
|
|
return _Thread_Get_executing();
|
|
}
|
|
|
|
void KillZombies( void )
|
|
{
|
|
_RTEMS_Lock_allocator();
|
|
_Thread_Kill_zombies();
|
|
_RTEMS_Unlock_allocator();
|
|
}
|
|
|
|
void WaitForExecutionStop( rtems_id task_id )
|
|
{
|
|
#if defined( RTEMS_SMP )
|
|
Thread_Control *the_thread;
|
|
|
|
the_thread = GetThread( task_id );
|
|
T_assert_not_null( the_thread );
|
|
|
|
while ( _Thread_Is_executing_on_a_processor( the_thread ) ) {
|
|
/* Wait */
|
|
}
|
|
#else
|
|
(void) task_id;
|
|
#endif
|
|
}
|
|
|
|
void WaitForIntendToBlock( rtems_id task_id )
|
|
{
|
|
#if defined( RTEMS_SMP )
|
|
Thread_Control *the_thread;
|
|
Thread_Wait_flags intend_to_block;
|
|
|
|
the_thread = GetThread( task_id );
|
|
T_assert_not_null( the_thread );
|
|
|
|
intend_to_block = THREAD_WAIT_CLASS_OBJECT |
|
|
THREAD_WAIT_STATE_INTEND_TO_BLOCK;
|
|
|
|
while ( _Thread_Wait_flags_get_acquire( the_thread ) != intend_to_block ) {
|
|
/* Wait */
|
|
}
|
|
#else
|
|
(void) task_id;
|
|
#endif
|
|
}
|
|
|
|
void WaitForHeir( uint32_t cpu_index, rtems_id task_id )
|
|
{
|
|
Per_CPU_Control *cpu;
|
|
|
|
cpu = _Per_CPU_Get_by_index( cpu_index );
|
|
|
|
while ( cpu->heir->Object.id != task_id ) {
|
|
RTEMS_COMPILER_MEMORY_BARRIER();
|
|
}
|
|
}
|
|
|
|
void WaitForNextTask( uint32_t cpu_index, rtems_id task_id )
|
|
{
|
|
Per_CPU_Control *cpu;
|
|
|
|
cpu = _Per_CPU_Get_by_index( cpu_index );
|
|
|
|
while ( cpu->heir->Object.id == task_id ) {
|
|
RTEMS_COMPILER_MEMORY_BARRIER();
|
|
}
|
|
|
|
while ( cpu->thread_dispatch_disable_level != 0 ) {
|
|
RTEMS_COMPILER_MEMORY_BARRIER();
|
|
}
|
|
}
|
|
|
|
void GetTaskTimerInfo( rtems_id id, TaskTimerInfo *info )
|
|
{
|
|
GetTaskTimerInfoByThread( GetThread( id ), info );
|
|
}
|
|
|
|
void GetTaskTimerInfoByThread(
|
|
struct _Thread_Control *thread,
|
|
TaskTimerInfo *info
|
|
)
|
|
{
|
|
info->expire_ticks = 0;
|
|
info->expire_timespec.tv_sec = -1;
|
|
info->expire_timespec.tv_nsec = -1;
|
|
|
|
if ( thread != NULL ) {
|
|
ISR_lock_Context lock_context;
|
|
ISR_lock_Context lock_context_2;
|
|
Per_CPU_Control *cpu;
|
|
|
|
_ISR_lock_ISR_disable_and_acquire( &thread->Timer.Lock, &lock_context );
|
|
info->expire_ticks = thread->Timer.Watchdog.expire;
|
|
#if defined( RTEMS_SMP )
|
|
cpu = thread->Timer.Watchdog.cpu;
|
|
#else
|
|
cpu = _Per_CPU_Get();
|
|
#endif
|
|
_Watchdog_Per_CPU_acquire_critical( cpu, &lock_context_2 );
|
|
|
|
if ( _Watchdog_Is_scheduled( &thread->Timer.Watchdog ) ) {
|
|
const Watchdog_Header *hdr;
|
|
|
|
hdr = thread->Timer.header;
|
|
|
|
if ( hdr == &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_TICKS ] ) {
|
|
info->state = TASK_TIMER_TICKS;
|
|
} else {
|
|
_Watchdog_Ticks_to_timespec(
|
|
info->expire_ticks,
|
|
&info->expire_timespec
|
|
);
|
|
|
|
if ( hdr == &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_REALTIME ] ) {
|
|
info->state = TASK_TIMER_REALTIME;
|
|
} else {
|
|
T_quiet_eq_ptr(
|
|
hdr,
|
|
&cpu->Watchdog.Header[ PER_CPU_WATCHDOG_MONOTONIC ]
|
|
);
|
|
info->state = TASK_TIMER_MONOTONIC;
|
|
}
|
|
}
|
|
} else {
|
|
info->state = TASK_TIMER_INACTIVE;
|
|
}
|
|
|
|
_Watchdog_Per_CPU_release_critical( cpu, &lock_context_2 );
|
|
_ISR_lock_Release_and_ISR_enable( &thread->Timer.Lock, &lock_context );
|
|
} else {
|
|
info->state = TASK_TIMER_INVALID;
|
|
}
|
|
}
|
|
|
|
#if defined( RTEMS_SMP )
|
|
static void DoWatchdogTick( void *arg )
|
|
{
|
|
(void) arg;
|
|
_Watchdog_Tick( _Per_CPU_Get() );
|
|
}
|
|
#endif
|
|
|
|
void ClockTick( void )
|
|
{
|
|
Per_CPU_Control *cpu_self;
|
|
|
|
cpu_self = _Thread_Dispatch_disable();
|
|
#if defined( RTEMS_SMP )
|
|
DoWatchdogTick( NULL );
|
|
_SMP_Othercast_action( DoWatchdogTick, NULL );
|
|
#else
|
|
_Watchdog_Tick( cpu_self );
|
|
#endif
|
|
_Thread_Dispatch_enable( cpu_self );
|
|
}
|
|
|
|
static void FinalWatchdogTick( Per_CPU_Control *cpu )
|
|
{
|
|
ISR_lock_Context lock_context;
|
|
Watchdog_Header *header;
|
|
Watchdog_Control *first;
|
|
|
|
_ISR_lock_ISR_disable_and_acquire( &cpu->Watchdog.Lock, &lock_context );
|
|
|
|
header = &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_TICKS ];
|
|
first = _Watchdog_Header_first( header );
|
|
|
|
if ( first != NULL ) {
|
|
_Watchdog_Tickle(
|
|
header,
|
|
first,
|
|
UINT64_MAX,
|
|
&cpu->Watchdog.Lock,
|
|
&lock_context
|
|
);
|
|
}
|
|
|
|
header = &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_MONOTONIC ];
|
|
first = _Watchdog_Header_first( header );
|
|
|
|
if ( first != NULL ) {
|
|
_Watchdog_Tickle(
|
|
header,
|
|
first,
|
|
UINT64_MAX,
|
|
&cpu->Watchdog.Lock,
|
|
&lock_context
|
|
);
|
|
}
|
|
|
|
header = &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_REALTIME ];
|
|
first = _Watchdog_Header_first( header );
|
|
|
|
if ( first != NULL ) {
|
|
_Watchdog_Tickle(
|
|
header,
|
|
first,
|
|
UINT64_MAX,
|
|
&cpu->Watchdog.Lock,
|
|
&lock_context
|
|
);
|
|
}
|
|
|
|
_ISR_lock_Release_and_ISR_enable( &cpu->Watchdog.Lock, &lock_context );
|
|
}
|
|
|
|
#if defined( RTEMS_SMP )
|
|
static void DoFinalWatchdogTick( void *arg )
|
|
{
|
|
(void) arg;
|
|
FinalWatchdogTick( _Per_CPU_Get() );
|
|
}
|
|
#endif
|
|
|
|
void FinalClockTick( void )
|
|
{
|
|
Per_CPU_Control *cpu_self;
|
|
|
|
cpu_self = _Thread_Dispatch_disable();
|
|
#if defined( RTEMS_SMP )
|
|
DoFinalWatchdogTick( NULL );
|
|
_SMP_Othercast_action( DoFinalWatchdogTick, NULL );
|
|
#else
|
|
FinalWatchdogTick( cpu_self );
|
|
#endif
|
|
_Thread_Dispatch_enable( cpu_self );
|
|
}
|
|
|
|
static FatalHandler fatal_handler;
|
|
|
|
static void *fatal_arg;
|
|
|
|
void FatalInitialExtension(
|
|
rtems_fatal_source source,
|
|
bool always_set_to_false,
|
|
rtems_fatal_code code
|
|
)
|
|
{
|
|
FatalHandler fatal;
|
|
|
|
T_quiet_false( always_set_to_false );
|
|
fatal = fatal_handler;
|
|
|
|
if ( fatal != NULL ) {
|
|
( *fatal )( source, code, fatal_arg );
|
|
}
|
|
}
|
|
|
|
void SetFatalHandler( FatalHandler fatal, void *arg )
|
|
{
|
|
fatal_handler = fatal;
|
|
fatal_arg = arg;
|
|
}
|
|
|
|
static rtems_id task_switch_id;
|
|
|
|
static rtems_task_switch_extension task_switch_extension;
|
|
|
|
static void TaskSwitchExtension( rtems_tcb *executing, rtems_tcb *heir )
|
|
{
|
|
( *task_switch_extension )( executing, heir );
|
|
}
|
|
|
|
void SetTaskSwitchExtension( rtems_task_switch_extension task_switch )
|
|
{
|
|
rtems_task_switch_extension last;
|
|
rtems_status_code sc;
|
|
|
|
last = task_switch_extension;
|
|
|
|
if ( task_switch == NULL ) {
|
|
if ( last != NULL ) {
|
|
sc = rtems_extension_delete( task_switch_id );
|
|
T_quiet_rsc_success( sc );
|
|
|
|
task_switch_extension = NULL;
|
|
}
|
|
} else {
|
|
task_switch_extension = task_switch;
|
|
|
|
if ( last == NULL ) {
|
|
rtems_extensions_table table = {
|
|
.thread_switch = TaskSwitchExtension
|
|
};
|
|
|
|
sc = rtems_extension_create(
|
|
rtems_build_name( 'T', 'S', 'W', 'I' ),
|
|
&table,
|
|
&task_switch_id
|
|
);
|
|
T_quiet_rsc_success( sc );
|
|
}
|
|
}
|
|
}
|
|
|
|
void ClearExtensionCalls( ExtensionCalls *calls )
|
|
{
|
|
memset( calls, 0, sizeof( *calls ) );
|
|
}
|
|
|
|
void CopyExtensionCalls( const ExtensionCalls *from, ExtensionCalls *to )
|
|
{
|
|
memcpy( to, from, sizeof( *to ) );
|
|
}
|
|
|
|
#if defined(RTEMS_SMP)
|
|
static volatile bool delay_thread_dispatch;
|
|
|
|
static void DelayThreadDispatchHandler( void *arg )
|
|
{
|
|
(void) arg;
|
|
|
|
while ( delay_thread_dispatch ) {
|
|
/* Wait */
|
|
}
|
|
}
|
|
|
|
static const Per_CPU_Job_context delay_thread_dispatch_context = {
|
|
.handler = DelayThreadDispatchHandler
|
|
};
|
|
|
|
static Per_CPU_Job delay_thread_dispatch_job = {
|
|
.context = &delay_thread_dispatch_context
|
|
};
|
|
#endif
|
|
|
|
void StartDelayThreadDispatch( uint32_t cpu_index )
|
|
{
|
|
#if defined(RTEMS_SMP)
|
|
if ( rtems_configuration_get_maximum_processors() > cpu_index ) {
|
|
delay_thread_dispatch = true;
|
|
_Per_CPU_Submit_job(
|
|
_Per_CPU_Get_by_index( cpu_index ),
|
|
&delay_thread_dispatch_job
|
|
);
|
|
}
|
|
#else
|
|
(void) cpu_index;
|
|
#endif
|
|
}
|
|
|
|
void StopDelayThreadDispatch( uint32_t cpu_index )
|
|
{
|
|
#if defined(RTEMS_SMP)
|
|
if ( rtems_configuration_get_maximum_processors() > cpu_index ) {
|
|
Per_CPU_Control *cpu_self;
|
|
|
|
cpu_self = _Thread_Dispatch_disable();
|
|
delay_thread_dispatch = false;
|
|
_Per_CPU_Wait_for_job(
|
|
_Per_CPU_Get_by_index( cpu_index ),
|
|
&delay_thread_dispatch_job
|
|
);
|
|
_Thread_Dispatch_enable( cpu_self );
|
|
}
|
|
#else
|
|
(void) cpu_index;
|
|
#endif
|
|
}
|
|
|
|
bool AreInterruptsEnabled( void )
|
|
{
|
|
return _ISR_Get_level() == 0;
|
|
}
|
|
|
|
static bool IsWhiteSpace( char c )
|
|
{
|
|
return c == ' ' || c == '\t';
|
|
}
|
|
|
|
bool IsWhiteSpaceOnly( const char *s )
|
|
{
|
|
char c;
|
|
|
|
while ( ( c = *s ) != '\0' ) {
|
|
if ( !IsWhiteSpace( c ) ) {
|
|
return false;
|
|
}
|
|
|
|
++s;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static const char *EatWhiteSpace( const char *s )
|
|
{
|
|
char c;
|
|
|
|
while ( ( c = *s ) != '\0' ) {
|
|
if ( !IsWhiteSpace( c ) ) {
|
|
break;
|
|
}
|
|
|
|
++s;
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
bool IsEqualIgnoreWhiteSpace( const char *a, const char *b )
|
|
{
|
|
while ( true ) {
|
|
a = EatWhiteSpace( a );
|
|
b = EatWhiteSpace( b );
|
|
|
|
if ( *a != *b ) {
|
|
return false;
|
|
}
|
|
|
|
if ( *a == '\0' ) {
|
|
return true;
|
|
}
|
|
|
|
++a;
|
|
++b;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#if defined(RTEMS_SMP)
|
|
bool TicketLockIsAvailable( const SMP_ticket_lock_Control *lock )
|
|
{
|
|
unsigned int now_serving;
|
|
unsigned int next_ticket;
|
|
|
|
now_serving = _Atomic_Load_uint( &lock->now_serving, ATOMIC_ORDER_RELAXED );
|
|
next_ticket = _Atomic_Load_uint( &lock->next_ticket, ATOMIC_ORDER_RELAXED );
|
|
|
|
return now_serving == next_ticket;
|
|
}
|
|
|
|
void TicketLockWaitForOwned( const SMP_ticket_lock_Control *lock )
|
|
{
|
|
while ( TicketLockIsAvailable( lock ) ) {
|
|
/* Wait */
|
|
}
|
|
}
|
|
|
|
void TicketLockWaitForOthers(
|
|
const SMP_ticket_lock_Control *lock,
|
|
unsigned int others
|
|
)
|
|
{
|
|
unsigned int expected;
|
|
unsigned int actual;
|
|
|
|
expected = _Atomic_Load_uint( &lock->now_serving, ATOMIC_ORDER_RELAXED );
|
|
expected += others + 1;
|
|
|
|
do {
|
|
actual = _Atomic_Load_uint( &lock->next_ticket, ATOMIC_ORDER_RELAXED );
|
|
} while ( expected != actual );
|
|
}
|
|
|
|
void TicketLockGetState(
|
|
const SMP_ticket_lock_Control *lock,
|
|
TicketLockState *state
|
|
)
|
|
{
|
|
state->lock = lock;
|
|
state->next_ticket =
|
|
_Atomic_Load_uint( &lock->next_ticket, ATOMIC_ORDER_RELAXED );
|
|
}
|
|
|
|
void TicketLockWaitForAcquires(
|
|
const TicketLockState *state,
|
|
unsigned int acquire_count
|
|
)
|
|
{
|
|
const SMP_ticket_lock_Control *lock;
|
|
unsigned int expected;
|
|
unsigned int actual;
|
|
|
|
lock = state->lock;
|
|
expected = state->next_ticket + acquire_count;
|
|
|
|
do {
|
|
actual = _Atomic_Load_uint( &lock->next_ticket, ATOMIC_ORDER_RELAXED );
|
|
} while ( expected != actual );
|
|
}
|
|
|
|
void TicketLockWaitForReleases(
|
|
const TicketLockState *state,
|
|
unsigned int release_count
|
|
)
|
|
{
|
|
const SMP_ticket_lock_Control *lock;
|
|
unsigned int expected;
|
|
unsigned int actual;
|
|
|
|
lock = state->lock;
|
|
expected = state->next_ticket + release_count;
|
|
|
|
do {
|
|
actual = _Atomic_Load_uint( &lock->now_serving, ATOMIC_ORDER_RELAXED );
|
|
} while ( expected != actual );
|
|
}
|
|
|
|
#endif
|