diff options
Diffstat (limited to 'testsuites/validation/tr-event-send-receive.c')
-rw-r--r-- | testsuites/validation/tr-event-send-receive.c | 1321 |
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(); +} + +/** @} */ |