/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup RTEMSTestCaseRtemsEventReqSendReceive
*/
/*
* Copyright (C) 2020 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.
*/
/*
* This file is part of the RTEMS quality process and was automatically
* generated. If you find something that needs to be fixed or
* worded better please post a report or patch to an RTEMS mailing list
* or raise a bug report:
*
* https://www.rtems.org/bugs.html
*
* For information on updating and regenerating please refer to the How-To
* section in the Software Requirements Engineering chapter of the
* RTEMS Software Engineering manual. The manual is provided as a part of
* a release. For development sources please refer to the online
* documentation at:
*
* https://docs.rtems.org
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <rtems/score/threadimpl.h>
#include "tr-event-send-receive.h"
#include "tx-support.h"
#include <rtems/test.h>
/**
* @defgroup RTEMSTestCaseRtemsEventReqSendReceive \
* spec:/rtems/event/req/send-receive
*
* @ingroup RTEMSTestSuiteTestsuitesValidation0
*
* @{
*/
typedef struct {
uint16_t Skip : 1;
uint16_t Pre_Id_NA : 1;
uint16_t Pre_Send_NA : 1;
uint16_t Pre_ReceiverState_NA : 1;
uint16_t Pre_Satisfy_NA : 1;
uint16_t Post_SendStatus : 2;
uint16_t Post_ReceiveStatus : 3;
uint16_t Post_SenderPreemption : 2;
} RtemsEventReqSendReceive_Entry;
#define PRIO_OTHER UINT32_MAX
typedef enum {
SENDER_NONE,
SENDER_SELF,
SENDER_SELF_2,
SENDER_WORKER,
SENDER_INTERRUPT
} SenderTypes;
typedef enum {
RECEIVE_SKIP,
RECEIVE_NORMAL,
RECEIVE_INTERRUPT
} ReceiveTypes;
typedef enum {
RECEIVE_COND_UNKNOWN,
RECEIVE_COND_SATSIFIED,
RECEIVE_COND_UNSATISFIED
} ReceiveConditionStates;
/**
* @brief Test context for spec:/rtems/event/req/send-receive test case.
*/
typedef struct {
/**
* @brief This member defines the sender type to perform the event send
* action.
*/
SenderTypes sender_type;
/**
* @brief This member defines the sender task priority.
*/
rtems_task_priority sender_prio;
/**
* @brief This member defines the receiver ID used for the event send action.
*/
rtems_id receiver_id;
/**
* @brief This member defines the events to send for the event send action.
*/
rtems_event_set events_to_send;
/**
* @brief This member contains the status of the event send action.
*/
rtems_status_code send_status;
/**
* @brief This member contains the scheduler ID of the runner task.
*/
ReceiveTypes receive_type;
/**
* @brief This member defines the option set used for the event receive
* action.
*/
rtems_option receive_option_set;
/**
* @brief This member defines the timeout used for the event receive action.
*/
rtems_interval receive_timeout;
/**
* @brief This member contains the events received by the event receive
* action.
*/
rtems_event_set received_events;
/**
* @brief This member references the event set received by the event receive
* action or is NULL.
*/
rtems_event_set *received_events_parameter;
/**
* @brief This member contains the status of the event receive action.
*/
rtems_status_code receive_status;
/**
* @brief This member contains the event condition state of the receiver task
* after the event send action.
*/
ReceiveConditionStates receive_condition_state;
/**
* @brief This member contains the pending events after an event send action
* which did not satisify the event condition of the receiver.
*/
rtems_event_set unsatisfied_pending;
/**
* @brief This member contains the TCB of the runner task.
*/
Thread_Control *runner_thread;
/**
* @brief This member contains the ID of the runner task.
*/
rtems_id runner_id;
/**
* @brief This member contains the task ID of the worker task.
*/
rtems_id worker_id;
/**
* @brief This member contains the ID of the semaphore used to wake up the
* worker task.
*/
rtems_id worker_wakeup;
/**
* @brief This member contains the ID of the semaphore used to wake up the
* runner task.
*/
rtems_id runner_wakeup;
/**
* @brief This member contains the scheduler ID of scheduler used by the
* runner task.
*/
rtems_id runner_sched;
/**
* @brief This member contains the scheduler ID of another scheduler which is
* not used by the runner task.
*/
rtems_id other_sched;
/**
* @brief This member contains the thread switch log.
*/
T_thread_switch_log_4 thread_switch_log;
/**
* @brief This member contains a copy of the corresponding
* RtemsEventReqSendReceive_Run() parameter.
*/
rtems_status_code ( *send )( rtems_id, rtems_event_set );
/**
* @brief This member contains a copy of the corresponding
* RtemsEventReqSendReceive_Run() parameter.
*/
rtems_status_code ( *receive )( rtems_event_set, rtems_option, rtems_interval, rtems_event_set * );
/**
* @brief This member contains a copy of the corresponding
* RtemsEventReqSendReceive_Run() parameter.
*/
rtems_event_set ( *get_pending_events )( Thread_Control * );
/**
* @brief This member contains a copy of the corresponding
* RtemsEventReqSendReceive_Run() parameter.
*/
unsigned int wait_class;
/**
* @brief This member contains a copy of the corresponding
* RtemsEventReqSendReceive_Run() parameter.
*/
int waiting_for_event;
struct {
/**
* @brief This member defines the pre-condition indices for the next
* action.
*/
size_t pci[ 4 ];
/**
* @brief This member defines the pre-condition states for the next action.
*/
size_t pcs[ 4 ];
/**
* @brief If this member is true, then the test action loop is executed.
*/
bool in_action_loop;
/**
* @brief This member contains the next transition map index.
*/
size_t index;
/**
* @brief This member contains the current transition map entry.
*/
RtemsEventReqSendReceive_Entry entry;
/**
* @brief If this member is true, then the current transition variant
* should be skipped.
*/
bool skip;
} Map;
} RtemsEventReqSendReceive_Context;
static RtemsEventReqSendReceive_Context
RtemsEventReqSendReceive_Instance;
static const char * const RtemsEventReqSendReceive_PreDesc_Id[] = {
"InvId",
"Task",
"NA"
};
static const char * const RtemsEventReqSendReceive_PreDesc_Send[] = {
"Zero",
"Unrelated",
"Any",
"All",
"MixedAny",
"MixedAll",
"NA"
};
static const char * const RtemsEventReqSendReceive_PreDesc_ReceiverState[] = {
"InvAddr",
"NotWaiting",
"Poll",
"Timeout",
"Lower",
"Equal",
"Higher",
"Other",
"Intend",
"NA"
};
static const char * const RtemsEventReqSendReceive_PreDesc_Satisfy[] = {
"All",
"Any",
"NA"
};
static const char * const * const RtemsEventReqSendReceive_PreDesc[] = {
RtemsEventReqSendReceive_PreDesc_Id,
RtemsEventReqSendReceive_PreDesc_Send,
RtemsEventReqSendReceive_PreDesc_ReceiverState,
RtemsEventReqSendReceive_PreDesc_Satisfy,
NULL
};
#define INPUT_EVENTS ( RTEMS_EVENT_5 | RTEMS_EVENT_23 )
typedef RtemsEventReqSendReceive_Context Context;
static rtems_id CreateWakeupSema( void )
{
rtems_status_code sc;
rtems_id id;
sc = rtems_semaphore_create(
rtems_build_name( 'W', 'K', 'U', 'P' ),
0,
RTEMS_SIMPLE_BINARY_SEMAPHORE,
0,
&id
);
T_assert_rsc_success( sc );
return id;
}
static void DeleteWakeupSema( rtems_id id )
{
if ( id != 0 ) {
rtems_status_code sc;
sc = rtems_semaphore_delete( id );
T_rsc_success( sc );
}
}
static void Wait( rtems_id id )
{
rtems_status_code sc;
sc = rtems_semaphore_obtain( id, RTEMS_WAIT, RTEMS_NO_TIMEOUT );
T_quiet_rsc_success( sc );
}
static void Wakeup( rtems_id id )
{
rtems_status_code sc;
sc = rtems_semaphore_release( id );
T_quiet_rsc_success( sc );
}
static bool BlockedForEvent( Context *ctx, Thread_Wait_flags flags )
{
return flags == ( ctx->wait_class | THREAD_WAIT_STATE_BLOCKED );
}
static bool IntendsToBlockForEvent( Context *ctx, Thread_Wait_flags flags )
{
return flags == ( ctx->wait_class | THREAD_WAIT_STATE_INTEND_TO_BLOCK );
}
static bool IsReady( Context *ctx, Thread_Wait_flags flags )
{
return flags == THREAD_WAIT_STATE_READY;
}
static bool IsSatisfiedFlags( Context *ctx )
{
return IsReady(
ctx,
_Thread_Wait_flags_get( ctx->runner_thread )
);
}
static bool IsSatisfiedState( Context *ctx )
{
return ctx->runner_thread->current_state != ctx->waiting_for_event;
}
static void SendAction( Context *ctx )
{
T_thread_switch_log *log;
log = T_thread_switch_record_4( &ctx->thread_switch_log );
T_quiet_null( log );
ctx->send_status = ( *ctx->send )( ctx->receiver_id, ctx->events_to_send );
log = T_thread_switch_record( NULL );
T_quiet_eq_ptr( &log->header, &ctx->thread_switch_log.header );
}
static void Send(
Context *ctx,
bool ( *is_satsified )( Context * )
)
{
SendAction( ctx );
if ( ( *is_satsified )( ctx ) ) {
ctx->receive_condition_state = RECEIVE_COND_SATSIFIED;
} else {
rtems_status_code sc;
rtems_event_set pending;
rtems_event_set missing;
ctx->receive_condition_state = RECEIVE_COND_UNSATISFIED;
pending = ( *ctx->get_pending_events )( ctx->runner_thread );
ctx->unsatisfied_pending = pending;
missing = INPUT_EVENTS & ~ctx->events_to_send;
T_ne_u32( missing, 0 );
sc = ( *ctx->send )( ctx->runner_id, missing );
T_rsc_success( sc );
pending = ( *ctx->get_pending_events )( ctx->runner_thread );
T_eq_u32( pending, ctx->events_to_send & ~INPUT_EVENTS );
}
}
static void Worker( rtems_task_argument arg )
{
Context *ctx;
ctx = (Context *) arg;
while ( true ) {
rtems_status_code sc;
rtems_task_priority prio;
T_thread_switch_log *log;
Wait( ctx->worker_wakeup );
switch ( ctx->sender_prio ) {
case PRIO_NORMAL:
case PRIO_HIGH:
prio = SetSelfPriority( ctx->sender_prio );
T_eq_u32( prio, PRIO_LOW );
break;
case PRIO_OTHER:
log = T_thread_switch_record_4( &ctx->thread_switch_log );
T_null( log );
sc = rtems_task_set_scheduler(
RTEMS_SELF,
ctx->other_sched,
PRIO_LOW
);
T_rsc_success( sc );
/*
* Make sure the context switch to the IDLE thread on the previous
* CPU is recorded, otherwise the preemption check may sporadically
* fail on some targets.
*/
while (ctx->thread_switch_log.header.recorded < 2) {
RTEMS_COMPILER_MEMORY_BARRIER();
}
log = T_thread_switch_record( NULL );
T_eq_ptr( &log->header, &ctx->thread_switch_log.header );
break;
case PRIO_LOW:
break;
}
Send( ctx, IsSatisfiedState );
sc = rtems_task_set_scheduler(
RTEMS_SELF,
ctx->runner_sched,
PRIO_HIGH
);
T_rsc_success( sc );
Wakeup( ctx->runner_wakeup );
}
}
static rtems_event_set GetPendingEvents( Context *ctx )
{
rtems_event_set pending;
rtems_status_code sc;
sc = ( *ctx->receive )(
RTEMS_PENDING_EVENTS,
RTEMS_DEFAULT_OPTIONS,
0,
&pending
);
T_quiet_rsc_success( sc );
return pending;
}
static void RtemsEventReqSendReceive_Cleanup( Context *ctx );
static void InterruptPrepare( void *arg )
{
RtemsEventReqSendReceive_Cleanup( arg );
}
static void InterruptAction( void *arg )
{
Context *ctx;
ctx = arg;
ctx->receive_status = ( *ctx->receive )(
INPUT_EVENTS,
ctx->receive_option_set,
ctx->receive_timeout,
&ctx->received_events
);
T_quiet_rsc_success( ctx->receive_status );
}
static void InterruptContinue( Context *ctx )
{
rtems_status_code sc;
sc = ( *ctx->send )( ctx->receiver_id, INPUT_EVENTS );
T_quiet_rsc_success( sc );
}
static T_interrupt_test_state Interrupt( void *arg )
{
Context *ctx;
Thread_Wait_flags flags;
T_interrupt_test_state next_state;
T_interrupt_test_state previous_state;
ctx = arg;
flags = _Thread_Wait_flags_get( ctx->runner_thread );
if ( IntendsToBlockForEvent( ctx, flags ) ) {
next_state = T_INTERRUPT_TEST_DONE;
} else if ( BlockedForEvent( ctx, flags ) ) {
next_state = T_INTERRUPT_TEST_LATE;
} else {
next_state = T_INTERRUPT_TEST_EARLY;
}
previous_state = T_interrupt_test_change_state(
T_INTERRUPT_TEST_ACTION,
next_state
);
if ( previous_state == T_INTERRUPT_TEST_ACTION ) {
if ( next_state == T_INTERRUPT_TEST_DONE ) {
Send( ctx, IsSatisfiedFlags );
} else {
InterruptContinue( ctx );
}
}
return next_state;
}
static const T_interrupt_test_config InterruptConfig = {
.prepare = InterruptPrepare,
.action = InterruptAction,
.interrupt = Interrupt,
.max_iteration_count = 10000
};
static void RtemsEventReqSendReceive_Pre_Id_Prepare(
RtemsEventReqSendReceive_Context *ctx,
RtemsEventReqSendReceive_Pre_Id state
)
{
switch ( state ) {
case RtemsEventReqSendReceive_Pre_Id_InvId: {
/*
* While the id parameter of the send directive is not associated with a
* task.
*/
ctx->receiver_id = 0xffffffff;
ctx->sender_type = SENDER_SELF;
break;
}
case RtemsEventReqSendReceive_Pre_Id_Task: {
/*
* While the id parameter of the send directive is is associated with a
* task.
*/
ctx->receiver_id = ctx->runner_id;
break;
}
case RtemsEventReqSendReceive_Pre_Id_NA:
break;
}
}
static void RtemsEventReqSendReceive_Pre_Send_Prepare(
RtemsEventReqSendReceive_Context *ctx,
RtemsEventReqSendReceive_Pre_Send state
)
{
switch ( state ) {
case RtemsEventReqSendReceive_Pre_Send_Zero: {
/*
* While the event set sent is the empty.
*/
ctx->events_to_send = 0;
break;
}
case RtemsEventReqSendReceive_Pre_Send_Unrelated: {
/*
* While the event set sent is unrelated to the event receive condition.
*/
ctx->events_to_send = RTEMS_EVENT_7;
break;
}
case RtemsEventReqSendReceive_Pre_Send_Any: {
/*
* While the event set sent is contain at least one but not all events of
* the event receive condition.
*/
ctx->events_to_send = RTEMS_EVENT_5;
break;
}
case RtemsEventReqSendReceive_Pre_Send_All: {
/*
* While the event set sent is contain all events of the event receive
* condition.
*/
ctx->events_to_send = RTEMS_EVENT_5 | RTEMS_EVENT_23;
break;
}
case RtemsEventReqSendReceive_Pre_Send_MixedAny: {
/*
* While the event set sent is contain at least one but not all events of
* the event receive condition and at least one unrelated event.
*/
ctx->events_to_send = RTEMS_EVENT_5 | RTEMS_EVENT_7;
break;
}
case RtemsEventReqSendReceive_Pre_Send_MixedAll: {
/*
* While the event set sent is contain all events of the event receive
* condition and at least one unrelated event.
*/
ctx->events_to_send = RTEMS_EVENT_5 | RTEMS_EVENT_7 | RTEMS_EVENT_23;
break;
}
case RtemsEventReqSendReceive_Pre_Send_NA:
break;
}
}
static void RtemsEventReqSendReceive_Pre_ReceiverState_Prepare(
RtemsEventReqSendReceive_Context *ctx,
RtemsEventReqSendReceive_Pre_ReceiverState state
)
{
switch ( state ) {
case RtemsEventReqSendReceive_Pre_ReceiverState_InvAddr: {
/*
* While the receiver task calls the receive directive with the event set
* to receive parameter set to NULL.
*/
ctx->sender_type = SENDER_SELF;
ctx->receive_type = RECEIVE_NORMAL;
ctx->received_events_parameter = NULL;
break;
}
case RtemsEventReqSendReceive_Pre_ReceiverState_NotWaiting: {
/*
* While the receiver task is not waiting for events.
*/
ctx->sender_type = SENDER_SELF;
ctx->receive_type = RECEIVE_SKIP;
break;
}
case RtemsEventReqSendReceive_Pre_ReceiverState_Poll: {
/*
* While the receiver task polls for events.
*/
ctx->sender_type = SENDER_SELF;
ctx->receive_type = RECEIVE_NORMAL;
ctx->receive_option_set |= RTEMS_NO_WAIT;
break;
}
case RtemsEventReqSendReceive_Pre_ReceiverState_Timeout: {
/*
* While the receiver task waited for events with a timeout which
* occurred.
*/
ctx->sender_type = SENDER_SELF_2;
ctx->receive_type = RECEIVE_NORMAL;
ctx->receive_timeout = 1;
break;
}
case RtemsEventReqSendReceive_Pre_ReceiverState_Lower: {
/*
* While the receiver task is blocked waiting for events and the receiver
* task shall have a lower priority than the sender task.
*/
ctx->sender_type = SENDER_WORKER;
ctx->sender_prio = PRIO_HIGH;
ctx->receive_type = RECEIVE_NORMAL;
break;
}
case RtemsEventReqSendReceive_Pre_ReceiverState_Equal: {
/*
* While the receiver task is blocked waiting for events and the receiver
* task shall have a priority equal to the sender task.
*/
ctx->sender_type = SENDER_WORKER;
ctx->sender_prio = PRIO_NORMAL;
ctx->receive_type = RECEIVE_NORMAL;
break;
}
case RtemsEventReqSendReceive_Pre_ReceiverState_Higher: {
/*
* While the receiver task is blocked waiting for events and the receiver
* task shall have a higher priority than the sender task.
*/
ctx->sender_type = SENDER_WORKER;
ctx->sender_prio = PRIO_LOW;
ctx->receive_type = RECEIVE_NORMAL;
break;
}
case RtemsEventReqSendReceive_Pre_ReceiverState_Other: {
/*
* While the receiver task is blocked waiting for events and the receiver
* task shall be on another scheduler instance than the sender task.
*/
ctx->sender_type = SENDER_WORKER;
ctx->sender_prio = PRIO_OTHER;
ctx->receive_type = RECEIVE_NORMAL;
break;
}
case RtemsEventReqSendReceive_Pre_ReceiverState_Intend: {
/*
* While the receiver task intends to block for waiting for events.
*/
ctx->sender_type = SENDER_INTERRUPT;
ctx->receive_type = RECEIVE_INTERRUPT;
break;
}
case RtemsEventReqSendReceive_Pre_ReceiverState_NA:
break;
}
}
static void RtemsEventReqSendReceive_Pre_Satisfy_Prepare(
RtemsEventReqSendReceive_Context *ctx,
RtemsEventReqSendReceive_Pre_Satisfy state
)
{
switch ( state ) {
case RtemsEventReqSendReceive_Pre_Satisfy_All: {
/*
* While the receiver task is interested in all input events.
*/
ctx->receive_option_set |= RTEMS_EVENT_ALL;
break;
}
case RtemsEventReqSendReceive_Pre_Satisfy_Any: {
/*
* While the receiver task is interested in any input event.
*/
ctx->receive_option_set |= RTEMS_EVENT_ANY;
break;
}
case RtemsEventReqSendReceive_Pre_Satisfy_NA:
break;
}
}
static void RtemsEventReqSendReceive_Post_SendStatus_Check(
RtemsEventReqSendReceive_Context *ctx,
RtemsEventReqSendReceive_Post_SendStatus state
)
{
switch ( state ) {
case RtemsEventReqSendReceive_Post_SendStatus_Ok: {
/*
* The send event status shall be RTEMS_SUCCESSFUL.
*/
T_rsc_success( ctx->send_status );
break;
}
case RtemsEventReqSendReceive_Post_SendStatus_InvId: {
/*
* The send event status shall be RTEMS_INVALID_ID.
*/
T_rsc( ctx->send_status, RTEMS_INVALID_ID );
break;
}
case RtemsEventReqSendReceive_Post_SendStatus_NA:
break;
}
}
static void RtemsEventReqSendReceive_Post_ReceiveStatus_Check(
RtemsEventReqSendReceive_Context *ctx,
RtemsEventReqSendReceive_Post_ReceiveStatus state
)
{
switch ( state ) {
case RtemsEventReqSendReceive_Post_ReceiveStatus_None: {
/*
* The receiver task shall not have pending events.
*/
T_eq_int( ctx->receive_condition_state, RECEIVE_COND_UNKNOWN );
T_eq_u32( GetPendingEvents( ctx ), 0 );
break;
}
case RtemsEventReqSendReceive_Post_ReceiveStatus_Pending: {
/*
* The receiver task shall have all events sent pending.
*/
T_eq_int( ctx->receive_condition_state, RECEIVE_COND_UNKNOWN );
T_eq_u32( GetPendingEvents( ctx ), ctx->events_to_send );
break;
}
case RtemsEventReqSendReceive_Post_ReceiveStatus_Timeout: {
/*
* The receive event status shall be RTEMS_TIMEOUT. The receiver task
* shall have all events sent after the timeout pending.
*/
T_rsc( ctx->receive_status, RTEMS_TIMEOUT );
T_eq_int( ctx->receive_condition_state, RECEIVE_COND_UNKNOWN );
T_eq_u32( GetPendingEvents( ctx ), ctx->events_to_send );
break;
}
case RtemsEventReqSendReceive_Post_ReceiveStatus_Satisfied: {
/*
* The receive event status shall be RTEMS_SUCCESSFUL. The receiver task
* shall receive all events sent which are an element of the input
* events. The receiver task shall have all events sent which are not an
* element of the input events pending.
*/
T_rsc( ctx->receive_status, RTEMS_SUCCESSFUL );
if ( ctx->receive_type != RECEIVE_NORMAL ) {
T_eq_int( ctx->receive_condition_state, RECEIVE_COND_SATSIFIED );
}
T_eq_u32( ctx->received_events, ctx->events_to_send & INPUT_EVENTS );
T_eq_u32( GetPendingEvents( ctx ), ctx->events_to_send & ~INPUT_EVENTS );
break;
}
case RtemsEventReqSendReceive_Post_ReceiveStatus_Unsatisfied: {
/*
* The receive event status shall be RTEMS_UNSATISFIED. The receiver task
* shall have all events sent pending.
*/
T_rsc( ctx->receive_status, RTEMS_UNSATISFIED );
T_eq_int( ctx->receive_condition_state, RECEIVE_COND_UNKNOWN );
T_eq_u32( GetPendingEvents( ctx ), ctx->events_to_send );
break;
}
case RtemsEventReqSendReceive_Post_ReceiveStatus_Blocked: {
/*
* The receiver task shall remain blocked waiting for events after the
* directive call. The receiver task shall have all events sent pending.
*/
T_eq_int( ctx->receive_condition_state, RECEIVE_COND_UNSATISFIED );
T_eq_u32( ctx->unsatisfied_pending, ctx->events_to_send );
break;
}
case RtemsEventReqSendReceive_Post_ReceiveStatus_InvAddr: {
/*
* The receive event status shall be RTEMS_INVALID_ADDRESS. The receiver
* task shall have all events sent pending.
*/
T_rsc( ctx->receive_status, RTEMS_INVALID_ADDRESS );
T_eq_int( ctx->receive_condition_state, RECEIVE_COND_UNKNOWN );
T_eq_u32( GetPendingEvents( ctx ), ctx->events_to_send );
break;
}
case RtemsEventReqSendReceive_Post_ReceiveStatus_NA:
break;
}
}
static void RtemsEventReqSendReceive_Post_SenderPreemption_Check(
RtemsEventReqSendReceive_Context *ctx,
RtemsEventReqSendReceive_Post_SenderPreemption state
)
{
const T_thread_switch_log_4 *log;
size_t i;
log = &ctx->thread_switch_log;
switch ( state ) {
case RtemsEventReqSendReceive_Post_SenderPreemption_No: {
/*
* When the sender task calls the directive to send the events, the
* sender task shall not be preempted as a result of the call.
*/
/*
* There may be a thread switch to the runner thread if the sender thread
* was on another scheduler instance.
*/
T_le_sz( log->header.recorded, 1 );
for ( i = 0; i < log->header.recorded; ++i ) {
T_ne_u32( log->events[ i ].executing, ctx->worker_id );
T_eq_u32( log->events[ i ].heir, ctx->runner_id );
}
break;
}
case RtemsEventReqSendReceive_Post_SenderPreemption_Yes: {
/*
* When the sender task calls the directive to send the events, the
* sender task shall be preempted as a result of the call.
*/
T_eq_sz( log->header.recorded, 2 );
T_eq_u32( log->events[ 0 ].heir, ctx->runner_id );
T_eq_u32( log->events[ 1 ].heir, ctx->worker_id );
break;
}
case RtemsEventReqSendReceive_Post_SenderPreemption_NA:
break;
}
}
static void RtemsEventReqSendReceive_Setup(
RtemsEventReqSendReceive_Context *ctx
)
{
rtems_status_code sc;
ctx->runner_thread = _Thread_Get_executing();
ctx->runner_id = ctx->runner_thread->Object.id;
ctx->worker_wakeup = CreateWakeupSema();
ctx->runner_wakeup = CreateWakeupSema();
sc = rtems_task_get_scheduler( RTEMS_SELF, &ctx->runner_sched );
T_rsc_success( sc );
#if defined(RTEMS_SMP)
sc = rtems_scheduler_ident_by_processor( 1, &ctx->other_sched );
T_rsc_success( sc );
T_ne_u32( ctx->runner_sched, ctx->other_sched );
#endif
SetSelfPriority( PRIO_NORMAL );
ctx->worker_id = CreateTask( "WORK", PRIO_LOW );
StartTask( ctx->worker_id, Worker, ctx );
}
static void RtemsEventReqSendReceive_Setup_Wrap( void *arg )
{
RtemsEventReqSendReceive_Context *ctx;
ctx = arg;
ctx->Map.in_action_loop = false;
RtemsEventReqSendReceive_Setup( ctx );
}
static void RtemsEventReqSendReceive_Teardown(
RtemsEventReqSendReceive_Context *ctx
)
{
DeleteTask( ctx->worker_id );
DeleteWakeupSema( ctx->worker_wakeup );
DeleteWakeupSema( ctx->runner_wakeup );
RestoreRunnerPriority();
}
static void RtemsEventReqSendReceive_Teardown_Wrap( void *arg )
{
RtemsEventReqSendReceive_Context *ctx;
ctx = arg;
ctx->Map.in_action_loop = false;
RtemsEventReqSendReceive_Teardown( ctx );
}
static void RtemsEventReqSendReceive_Prepare(
RtemsEventReqSendReceive_Context *ctx
)
{
ctx->events_to_send = 0;
ctx->send_status = RTEMS_INCORRECT_STATE;
ctx->received_events = 0xffffffff;
ctx->received_events_parameter = &ctx->received_events;
ctx->receive_option_set = 0;
ctx->receive_timeout = RTEMS_NO_TIMEOUT;
ctx->sender_type = SENDER_NONE;
ctx->sender_prio = PRIO_NORMAL;
ctx->receive_type = RECEIVE_SKIP;
ctx->receive_condition_state = RECEIVE_COND_UNKNOWN;
ctx->unsatisfied_pending = 0xffffffff;
memset( &ctx->thread_switch_log, 0, sizeof( ctx->thread_switch_log ) );
T_eq_u32( GetPendingEvents( ctx ), 0 );
}
static void RtemsEventReqSendReceive_Action(
RtemsEventReqSendReceive_Context *ctx
)
{
if ( ctx->sender_type == SENDER_SELF ) {
SendAction( ctx );
} else if ( ctx->sender_type == SENDER_WORKER ) {
Wakeup( ctx->worker_wakeup );
}
if ( ctx->receive_type == RECEIVE_NORMAL ) {
ctx->receive_status = ( *ctx->receive )(
INPUT_EVENTS,
ctx->receive_option_set,
ctx->receive_timeout,
ctx->received_events_parameter
);
} else if ( ctx->receive_type == RECEIVE_INTERRUPT ) {
T_interrupt_test_state state;
state = T_interrupt_test( &InterruptConfig, ctx );
T_eq_int( state, T_INTERRUPT_TEST_DONE );
}
if ( ctx->sender_type == SENDER_SELF_2 ) {
SendAction( ctx );
} else if ( ctx->sender_type == SENDER_WORKER ) {
rtems_task_priority prio;
Wait( ctx->runner_wakeup );
prio = SetPriority( ctx->worker_id, PRIO_LOW );
T_eq_u32( prio, PRIO_HIGH );
}
}
static void RtemsEventReqSendReceive_Cleanup(
RtemsEventReqSendReceive_Context *ctx
)
{
rtems_status_code sc;
rtems_event_set events;
events = 0;
sc = ( *ctx->receive )(
RTEMS_ALL_EVENTS,
RTEMS_NO_WAIT | RTEMS_EVENT_ANY,
0,
&events
);
if ( sc == RTEMS_SUCCESSFUL ) {
T_quiet_ne_u32( events, 0 );
} else {
T_quiet_rsc( sc, RTEMS_UNSATISFIED );
T_quiet_eq_u32( events, 0 );
}
}
static const RtemsEventReqSendReceive_Entry
RtemsEventReqSendReceive_Entries[] = {
{ 0, 0, 1, 1, 1, RtemsEventReqSendReceive_Post_SendStatus_InvId,
RtemsEventReqSendReceive_Post_ReceiveStatus_None,
RtemsEventReqSendReceive_Post_SenderPreemption_No },
{ 0, 0, 0, 0, 1, RtemsEventReqSendReceive_Post_SendStatus_Ok,
RtemsEventReqSendReceive_Post_ReceiveStatus_Pending,
RtemsEventReqSendReceive_Post_SenderPreemption_No },
{ 0, 0, 0, 0, 0, RtemsEventReqSendReceive_Post_SendStatus_Ok,
RtemsEventReqSendReceive_Post_ReceiveStatus_Blocked,
RtemsEventReqSendReceive_Post_SenderPreemption_No },
{ 0, 0, 0, 0, 0, RtemsEventReqSendReceive_Post_SendStatus_Ok,
RtemsEventReqSendReceive_Post_ReceiveStatus_Satisfied,
RtemsEventReqSendReceive_Post_SenderPreemption_No },
{ 0, 0, 0, 0, 0, RtemsEventReqSendReceive_Post_SendStatus_Ok,
RtemsEventReqSendReceive_Post_ReceiveStatus_Timeout,
RtemsEventReqSendReceive_Post_SenderPreemption_No },
{ 0, 0, 0, 0, 0, RtemsEventReqSendReceive_Post_SendStatus_Ok,
RtemsEventReqSendReceive_Post_ReceiveStatus_Unsatisfied,
RtemsEventReqSendReceive_Post_SenderPreemption_No },
#if defined(RTEMS_SMP)
{ 0, 0, 0, 0, 0, RtemsEventReqSendReceive_Post_SendStatus_Ok,
RtemsEventReqSendReceive_Post_ReceiveStatus_Blocked,
RtemsEventReqSendReceive_Post_SenderPreemption_No },
#else
{ 1, 0, 0, 0, 0, RtemsEventReqSendReceive_Post_SendStatus_NA,
RtemsEventReqSendReceive_Post_ReceiveStatus_NA,
RtemsEventReqSendReceive_Post_SenderPreemption_NA },
#endif
{ 0, 0, 0, 0, 0, RtemsEventReqSendReceive_Post_SendStatus_Ok,
RtemsEventReqSendReceive_Post_ReceiveStatus_Satisfied,
RtemsEventReqSendReceive_Post_SenderPreemption_Yes },
#if defined(RTEMS_SMP)
{ 0, 0, 0, 0, 0, RtemsEventReqSendReceive_Post_SendStatus_Ok,
RtemsEventReqSendReceive_Post_ReceiveStatus_Satisfied,
RtemsEventReqSendReceive_Post_SenderPreemption_No }
#else
{ 1, 0, 0, 0, 0, RtemsEventReqSendReceive_Post_SendStatus_NA,
RtemsEventReqSendReceive_Post_ReceiveStatus_NA,
RtemsEventReqSendReceive_Post_SenderPreemption_NA }
#endif
};
static const uint8_t
RtemsEventReqSendReceive_Map[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 1, 5, 5, 4, 4, 2, 2, 2, 2, 2, 2, 6, 6, 2, 2, 1, 1, 1, 1,
5, 5, 4, 4, 2, 2, 2, 2, 2, 2, 6, 6, 2, 2, 1, 1, 1, 1, 5, 3, 4, 4, 2, 3, 2, 3,
2, 7, 6, 8, 2, 3, 1, 1, 1, 1, 3, 3, 4, 4, 3, 3, 3, 3, 7, 7, 8, 8, 3, 3, 1, 1,
1, 1, 5, 3, 4, 4, 2, 3, 2, 3, 2, 7, 6, 8, 2, 3, 1, 1, 1, 1, 3, 3, 4, 4, 3, 3,
3, 3, 7, 7, 8, 8, 3, 3
};
static size_t RtemsEventReqSendReceive_Scope( void *arg, char *buf, size_t n )
{
RtemsEventReqSendReceive_Context *ctx;
ctx = arg;
if ( ctx->Map.in_action_loop ) {
return T_get_scope(
RtemsEventReqSendReceive_PreDesc,
buf,
n,
ctx->Map.pcs
);
}
return 0;
}
static T_fixture RtemsEventReqSendReceive_Fixture = {
.setup = RtemsEventReqSendReceive_Setup_Wrap,
.stop = NULL,
.teardown = RtemsEventReqSendReceive_Teardown_Wrap,
.scope = RtemsEventReqSendReceive_Scope,
.initial_context = &RtemsEventReqSendReceive_Instance
};
static inline RtemsEventReqSendReceive_Entry RtemsEventReqSendReceive_PopEntry(
RtemsEventReqSendReceive_Context *ctx
)
{
size_t index;
index = ctx->Map.index;
ctx->Map.index = index + 1;
return RtemsEventReqSendReceive_Entries[
RtemsEventReqSendReceive_Map[ index ]
];
}
static void RtemsEventReqSendReceive_SetPreConditionStates(
RtemsEventReqSendReceive_Context *ctx
)
{
ctx->Map.pcs[ 0 ] = ctx->Map.pci[ 0 ];
if ( ctx->Map.entry.Pre_Send_NA ) {
ctx->Map.pcs[ 1 ] = RtemsEventReqSendReceive_Pre_Send_NA;
} else {
ctx->Map.pcs[ 1 ] = ctx->Map.pci[ 1 ];
}
if ( ctx->Map.entry.Pre_ReceiverState_NA ) {
ctx->Map.pcs[ 2 ] = RtemsEventReqSendReceive_Pre_ReceiverState_NA;
} else {
ctx->Map.pcs[ 2 ] = ctx->Map.pci[ 2 ];
}
if ( ctx->Map.entry.Pre_Satisfy_NA ) {
ctx->Map.pcs[ 3 ] = RtemsEventReqSendReceive_Pre_Satisfy_NA;
} else {
ctx->Map.pcs[ 3 ] = ctx->Map.pci[ 3 ];
}
}
static void RtemsEventReqSendReceive_TestVariant(
RtemsEventReqSendReceive_Context *ctx
)
{
RtemsEventReqSendReceive_Pre_Id_Prepare( ctx, ctx->Map.pcs[ 0 ] );
RtemsEventReqSendReceive_Pre_Send_Prepare( ctx, ctx->Map.pcs[ 1 ] );
RtemsEventReqSendReceive_Pre_ReceiverState_Prepare( ctx, ctx->Map.pcs[ 2 ] );
RtemsEventReqSendReceive_Pre_Satisfy_Prepare( ctx, ctx->Map.pcs[ 3 ] );
RtemsEventReqSendReceive_Action( ctx );
RtemsEventReqSendReceive_Post_SendStatus_Check(
ctx,
ctx->Map.entry.Post_SendStatus
);
RtemsEventReqSendReceive_Post_ReceiveStatus_Check(
ctx,
ctx->Map.entry.Post_ReceiveStatus
);
RtemsEventReqSendReceive_Post_SenderPreemption_Check(
ctx,
ctx->Map.entry.Post_SenderPreemption
);
}
static T_fixture_node RtemsEventReqSendReceive_Node;
void RtemsEventReqSendReceive_Run(
rtems_status_code ( *send )( rtems_id, rtems_event_set ),
rtems_status_code ( *receive )( rtems_event_set, rtems_option, rtems_interval, rtems_event_set * ),
rtems_event_set ( *get_pending_events )( Thread_Control * ),
unsigned int wait_class,
int waiting_for_event
)
{
RtemsEventReqSendReceive_Context *ctx;
ctx = &RtemsEventReqSendReceive_Instance;
ctx->send = send;
ctx->receive = receive;
ctx->get_pending_events = get_pending_events;
ctx->wait_class = wait_class;
ctx->waiting_for_event = waiting_for_event;
ctx = T_push_fixture(
&RtemsEventReqSendReceive_Node,
&RtemsEventReqSendReceive_Fixture
);
ctx->Map.in_action_loop = true;
ctx->Map.index = 0;
for (
ctx->Map.pci[ 0 ] = RtemsEventReqSendReceive_Pre_Id_InvId;
ctx->Map.pci[ 0 ] < RtemsEventReqSendReceive_Pre_Id_NA;
++ctx->Map.pci[ 0 ]
) {
for (
ctx->Map.pci[ 1 ] = RtemsEventReqSendReceive_Pre_Send_Zero;
ctx->Map.pci[ 1 ] < RtemsEventReqSendReceive_Pre_Send_NA;
++ctx->Map.pci[ 1 ]
) {
for (
ctx->Map.pci[ 2 ] = RtemsEventReqSendReceive_Pre_ReceiverState_InvAddr;
ctx->Map.pci[ 2 ] < RtemsEventReqSendReceive_Pre_ReceiverState_NA;
++ctx->Map.pci[ 2 ]
) {
for (
ctx->Map.pci[ 3 ] = RtemsEventReqSendReceive_Pre_Satisfy_All;
ctx->Map.pci[ 3 ] < RtemsEventReqSendReceive_Pre_Satisfy_NA;
++ctx->Map.pci[ 3 ]
) {
ctx->Map.entry = RtemsEventReqSendReceive_PopEntry( ctx );
if ( ctx->Map.entry.Skip ) {
continue;
}
RtemsEventReqSendReceive_SetPreConditionStates( ctx );
RtemsEventReqSendReceive_Prepare( ctx );
RtemsEventReqSendReceive_TestVariant( ctx );
RtemsEventReqSendReceive_Cleanup( ctx );
}
}
}
}
T_pop_fixture();
}
/** @} */