/* SPDX-License-Identifier: BSD-2-Clause */ /** * @file * * @ingroup RTEMSTestCaseRtemsModelEventsMgr1 */ /* * Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) * Trinity College Dublin (http://www.tcd.ie) * * 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 was automatically generated. Do not edit it manually. * Please have a look at * * https://docs.rtems.org/branches/master/eng/req/howto.html * * for information how to maintain and re-generate this file. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "tr-model-events-mgr.h" #include typedef enum { PRIO_HIGH = 1, PRIO_NORMAL, PRIO_LOW, PRIO_OTHER } Priorities; typedef struct { rtems_status_code ( *send )( rtems_id, rtems_event_set ); // copy of the // corresponding RtemsModelEventsMgr1_Run() parameter rtems_status_code ( *receive ) ( rtems_event_set, rtems_option , rtems_interval, rtems_event_set * ); // copy of the // corresponding RtemsModelEventsMgr1_Run() parameter rtems_event_set ( *get_pending_events )( Thread_Control * ); // copy of the // corresponding RtemsModelEventsMgr1_Run() parameter unsigned int wait_class; // copy of the corresponding // RtemsModelEventsMgr1_Run() parameter int waiting_for_event; // copy of the corresponding // RtemsModelEventsMgr1_Run() parameter rtems_id receiver_id; // receiver ID used for the event send action. rtems_event_set events_to_send; // events to send for the event send action rtems_status_code send_status; // status of the event send action. rtems_option receive_option_set; // option set used for the event receive action rtems_interval receive_timeout; // timeout used for the event receive action rtems_event_set received_events; // events received by the event receive action rtems_status_code receive_status; // status of the event receive action rtems_event_set unsatisfied_pending; // pending events after an event send action // which did not satsify the event condition of the receiver Thread_Control *runner_thread; // TCB of the runner task rtems_id runner_id; // ID of the runner task rtems_id worker_id; // task ID of the worker task rtems_id worker_wakeup; // ID of the semaphore used to wake up the worker task rtems_id runner_wakeup; // ID of the semaphore used to wake up the runner task rtems_id runner_sched; // scheduler ID of scheduler used by the runner task rtems_id other_sched; // scheduler ID of another scheduler // which is not used by the runner task T_thread_switch_log_4 thread_switch_log; // thread switch log } RtemsModelEventsMgr1_Context; static RtemsModelEventsMgr1_Context RtemsModelEventsMgr1_Instance; static const char PromelaModelEventsMgr[] = "/PML-EventsMgr1"; #define INPUT_EVENTS ( RTEMS_EVENT_5 | RTEMS_EVENT_23 ) #define WORKER_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES #define MAX_TLS_SIZE RTEMS_ALIGN_UP( 64, RTEMS_TASK_STORAGE_ALIGNMENT ) typedef RtemsModelEventsMgr1_Context Context; RTEMS_ALIGNED( RTEMS_TASK_STORAGE_ALIGNMENT ) static char WorkerStorage[ RTEMS_TASK_STORAGE_SIZE( MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, WORKER_ATTRIBUTES ) ]; static const rtems_task_config WorkerConfig = { .name = rtems_build_name( 'W', 'O', 'R', 'K' ), .initial_priority = PRIO_LOW, .storage_area = WorkerStorage, .storage_size = sizeof( WorkerStorage ), .maximum_thread_local_storage_size = MAX_TLS_SIZE, .initial_modes = RTEMS_DEFAULT_MODES, .attributes = WORKER_ATTRIBUTES }; 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 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 rtems_option mergeopts( bool wait, bool wantall ) { rtems_option opts; if ( wait ) { opts = RTEMS_WAIT; } else { opts = RTEMS_NO_WAIT; } ; if ( wantall ) { opts |= RTEMS_EVENT_ALL; } else { opts |= RTEMS_EVENT_ANY; } ; return opts; } /* * Here we need a mapping from model "task numbers/names" to thread Id's here * Promela Process 3 corresponds to Task 0 (Worker), doing Send * Promela Process 4 corresponds to Task 1 (Runner), doing Receive */ static rtems_id mapid( Context *ctx, int pid ) { rtems_id mapped_id; switch ( pid ) { case 0 : mapped_id = ctx->worker_id ; break; case 1 : mapped_id = ctx->runner_id; break; default : mapped_id = 0xffffffff; break; } return mapped_id; } static void checkTaskIs( rtems_id expected_id ) { rtems_id own_id; own_id = _Thread_Get_executing()->Object.id; T_eq_u32( own_id, expected_id ); } static void initialise_pending( rtems_event_set pending[], int max ) { int i; for( i=0; i < max; i++ ) { pending[i] = 0; } } static void initialise_semaphore( Context *ctx, rtems_id semaphore[] ) { semaphore[0] = ctx->worker_wakeup; semaphore[1] = ctx->runner_wakeup; } /* =============================================== */ // @@@ 0 NAME Event_Manager_TestGen // @@@ 0 DEF NO_OF_EVENTS 4 #define NO_OF_EVENTS 4 // @@@ 0 DEF EVTS_NONE 0 #define EVTS_NONE 0 // @@@ 0 DEF EVTS_PENDING 0 #define EVTS_PENDING 0 // @@@ 0 DEF EVT_0 1 #define EVT_0 1 // @@@ 0 DEF EVT_1 2 #define EVT_1 2 // @@@ 0 DEF EVT_2 4 #define EVT_2 4 // @@@ 0 DEF EVT_3 8 #define EVT_3 8 // @@@ 0 DEF NO_TIMEOUT 0 #define NO_TIMEOUT 0 // @@@ 0 DEF TASK_MAX 2 #define TASK_MAX 2 // @@@ 0 DEF BAD_ID 2 #define BAD_ID 2 // @@@ 0 DEF SEMA_MAX 2 #define SEMA_MAX 2 // @@@ 0 DEF RC_OK RTEMS_SUCCESSFUL #define RC_OK RTEMS_SUCCESSFUL // @@@ 0 DEF RC_InvId RTEMS_INVALID_ID #define RC_InvId RTEMS_INVALID_ID // @@@ 0 DEF RC_InvAddr RTEMS_INVALID_ADDRESS #define RC_InvAddr RTEMS_INVALID_ADDRESS // @@@ 0 DEF RC_Unsat RTEMS_UNSATISFIED #define RC_Unsat RTEMS_UNSATISFIED // @@@ 0 DEF RC_Timeout RTEMS_TIMEOUT #define RC_Timeout RTEMS_TIMEOUT // @@@ 0 DCLARRAY EvtSet pending TASK_MAX static rtems_event_set pending[TASK_MAX]; // @@@ 0 DECL byte sendrc 0 static rtems_status_code sendrc = 0; // @@@ 0 DECL byte recrc 0 static rtems_status_code recrc = 0; // @@@ 0 DECL byte recout 0 static rtems_event_set recout = 0; // @@@ 0 DCLARRAY Semaphore semaphore SEMA_MAX static rtems_id semaphore[SEMA_MAX]; /* ===== TEST CODE SEGMENT 0 =====*/ static void TestSegment0( Context* ctx ) { /* Test Name is defined in the Test Case code (tc-model-events-mgr.c) */ T_log(T_NORMAL,"@@@ 0 INIT"); initialise_pending( pending, TASK_MAX ); initialise_semaphore( ctx, semaphore ); } /* ===== TEST CODE SEGMENT 3 =====*/ static void TestSegment3( Context* ctx ) { T_log(T_NORMAL,"@@@ 3 TASK Worker"); checkTaskIs( ctx->worker_id ); T_log(T_NORMAL,"@@@ 3 WAIT 0"); Wait( semaphore[0] ); T_log(T_NORMAL,"@@@ 3 CALL event_send 0 1 14 sendrc"); T_log( T_NORMAL, "Calling Send(%d,%d)", mapid( ctx, 1), 14 ); sendrc = ( *ctx->send )( mapid( ctx, 1 ), 14 ); T_log( T_NORMAL, "Returned 0x%x from Send", sendrc ); T_log(T_NORMAL,"@@@ 3 SCALAR sendrc 0"); T_rsc_success( sendrc ); T_log(T_NORMAL,"@@@ 3 SIGNAL 1"); Wakeup( semaphore[1] ); T_log(T_NORMAL,"@@@ 3 STATE 0 Zombie"); /* Code to check that Task 0 has terminated */ } /* ===== TEST CODE SEGMENT 4 =====*/ static void TestSegment4( Context* ctx ) { T_log(T_NORMAL,"@@@ 4 TASK Runner"); checkTaskIs( ctx->runner_id ); T_log(T_NORMAL,"@@@ 4 SIGNAL 0"); Wakeup( semaphore[0] ); T_log(T_NORMAL,"@@@ 4 WAIT 1"); Wait( semaphore[1] ); T_log(T_NORMAL,"@@@ 4 SCALAR pending 1 14"); pending[1] = GetPendingEvents( ctx ); T_eq_int( pending[1], 14 ); T_log(T_NORMAL,"@@@ 4 CALL event_receive 6 1 1 0 recout recrc"); T_log( T_NORMAL, "Calling Receive(%d,%d,%d,%d)", 6, mergeopts( 1, 1 ) ,0 ,&recout ); recrc = ( *ctx->receive )( 6, mergeopts( 1, 1 ), 0, &recout ); T_log( T_NORMAL, "Returned 0x%x from Receive", recrc ); T_log(T_NORMAL,"@@@ 4 SCALAR recrc 0"); T_rsc_success( recrc ); T_log(T_NORMAL,"@@@ 4 SCALAR recout 6"); T_eq_int( recout, 6 ); T_log(T_NORMAL,"@@@ 4 SCALAR pending 1 8"); pending[1] = GetPendingEvents( ctx ); T_eq_int( pending[1], 8 ); T_log(T_NORMAL,"@@@ 4 SIGNAL 0"); Wakeup( semaphore[0] ); T_log(T_NORMAL,"@@@ 4 STATE 1 Zombie"); /* Code to check that Task 1 has terminated */ } /* =============================================== */ static void Worker( rtems_task_argument arg ) { Context *ctx; ctx = (Context *) arg; T_log( T_NORMAL, "Worker Running" ); TestSegment3( ctx ); T_log( T_NORMAL, "Worker finished" ); rtems_task_exit(); } static void Runner( RtemsModelEventsMgr1_Context *ctx ) { T_log( T_NORMAL, "Runner running" ); TestSegment4( ctx ); T_log( T_NORMAL, "Runner finished" ); } static void RtemsModelEventsMgr1_Setup( RtemsModelEventsMgr1_Context *ctx ) { rtems_status_code sc; rtems_task_priority prio; T_log( T_NORMAL, "Runner Setup" ); memset( ctx, 0, sizeof( *ctx ) ); 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 prio = 0; sc = rtems_task_set_priority( RTEMS_SELF, PRIO_NORMAL, &prio ); T_rsc_success( sc ); T_eq_u32( prio, PRIO_HIGH ); sc = rtems_task_construct( &WorkerConfig, &ctx->worker_id ); T_log( T_NORMAL, "Construct Worker, sc = %x", sc ); T_assert_rsc_success( sc ); T_log( T_NORMAL, "Starting Worker..." ); sc = rtems_task_start( ctx->worker_id, Worker, (rtems_task_argument) ctx ); T_log( T_NORMAL, "Started Worker, sc = %x", sc ); T_assert_rsc_success( sc ); } static void RtemsModelEventsMgr1_Setup_Wrap( void *arg ) { RtemsModelEventsMgr1_Context *ctx; ctx = arg; RtemsModelEventsMgr1_Setup( ctx ); } static void RtemsModelEventsMgr1_Teardown( RtemsModelEventsMgr1_Context *ctx ) { rtems_status_code sc; rtems_task_priority prio; T_log( T_NORMAL, "Runner Teardown" ); prio = 0; sc = rtems_task_set_priority( RTEMS_SELF, PRIO_HIGH, &prio ); T_rsc_success( sc ); T_eq_u32( prio, PRIO_NORMAL ); if ( ctx->worker_id != 0 ) { sc = rtems_task_delete( ctx->worker_id ); T_rsc_success( sc ); } DeleteWakeupSema( ctx->worker_wakeup ); DeleteWakeupSema( ctx->runner_wakeup ); } static void RtemsModelEventsMgr1_Teardown_Wrap( void *arg ) { RtemsModelEventsMgr1_Context *ctx; ctx = arg; RtemsModelEventsMgr1_Teardown( ctx ); } static size_t RtemsModelEventsMgr1_Scope( void *arg, char *buf, size_t n ) { size_t pme_size; pme_size = strlen(PromelaModelEventsMgr); return T_str_copy(buf, PromelaModelEventsMgr, pme_size); } static T_fixture RtemsModelEventsMgr1_Fixture = { .setup = RtemsModelEventsMgr1_Setup_Wrap, .stop = NULL, .teardown = RtemsModelEventsMgr1_Teardown_Wrap, .scope = RtemsModelEventsMgr1_Scope, .initial_context = &RtemsModelEventsMgr1_Instance }; static void RtemsModelEventsMgr1_Cleanup( RtemsModelEventsMgr1_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 T_fixture_node RtemsModelEventsMgr1_Node; void RtemsModelEventsMgr1_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 ) { RtemsModelEventsMgr1_Context *ctx; T_set_verbosity( T_NORMAL ); T_log( T_NORMAL, "Runner Invoked" ); T_log( T_NORMAL, "Runner Wait Class: %d", wait_class ); T_log( T_NORMAL, "Runner WaitForEvent: %d", waiting_for_event ); T_log( T_NORMAL, "Pushing Test Fixture..." ); ctx = T_push_fixture( &RtemsModelEventsMgr1_Node, &RtemsModelEventsMgr1_Fixture ); T_log( T_NORMAL, "Test Fixture Pushed" ); 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; // RtemsModelEventsMgr1_Prepare( ctx ); ctx->events_to_send = 0; ctx->send_status = RTEMS_INCORRECT_STATE; ctx->received_events = 0xffffffff; ctx->receive_option_set = 0; ctx->receive_timeout = RTEMS_NO_TIMEOUT; ctx->unsatisfied_pending = 0xffffffff; memset( &ctx->thread_switch_log, 0, sizeof( ctx->thread_switch_log ) ); T_eq_u32( GetPendingEvents( ctx ), 0 ); _Thread_Wait_flags_set( ctx->runner_thread, THREAD_WAIT_FLAGS_INITIAL ); TestSegment0( ctx ); Runner( ctx ); RtemsModelEventsMgr1_Cleanup( ctx ); T_log( T_NORMAL, "Run Pop Fixture" ); T_pop_fixture(); } /** @} */