summaryrefslogtreecommitdiffstats
path: root/testsuites/validation/tr-event-send-receive.c
diff options
context:
space:
mode:
Diffstat (limited to 'testsuites/validation/tr-event-send-receive.c')
-rw-r--r--testsuites/validation/tr-event-send-receive.c1321
1 files changed, 1321 insertions, 0 deletions
diff --git a/testsuites/validation/tr-event-send-receive.c b/testsuites/validation/tr-event-send-receive.c
new file mode 100644
index 0000000000..85d0040615
--- /dev/null
+++ b/testsuites/validation/tr-event-send-receive.c
@@ -0,0 +1,1321 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup RtemsEventReqSendReceive
+ */
+
+/*
+ * Copyright (C) 2020 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.
+ */
+
+/*
+ * 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 RtemsEventReqSendReceive spec:/rtems/event/req/send-receive
+ *
+ * @ingroup TestsuitesValidation0
+ *
+ * @{
+ */
+
+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;
+
+static T_remark RtemsEventReqSendReceive_Remark = {
+ .next = NULL,
+ .remark = "RtemsEventReqSendReceive"
+};
+
+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_add_remark( &RtemsEventReqSendReceive_Remark );
+ T_pop_fixture();
+}
+
+/** @} */