SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause copyrights: - Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) enabled-by: true functional-type: action links: - role: interface-function uid: ../if/flush - role: interface-function uid: ../if/get-number-pending post-conditions: - name: Status states: - name: Ok test-code: | T_rsc_success( ctx->status ); text: | The return status of the called directive (${../if/flush:/name} or ${../if/get-number-pending:/name}) shall be ${../../status/if/successful:/name} - name: InvId test-code: | T_rsc( ctx->status, RTEMS_INVALID_ID ); text: | The return status of the called directive (${../if/flush:/name} or ${../if/get-number-pending:/name}) shall be ${../../status/if/invalid-id:/name}. - name: InvAddr test-code: | T_rsc( ctx->status, RTEMS_INVALID_ADDRESS ); text: | The return status of the called directive (${../if/flush:/name} or ${../if/get-number-pending:/name}) shall be ${../../status/if/invalid-address:/name}. test-epilogue: null test-prologue: null - name: Count states: - name: Zero test-code: | T_eq_u32( ctx->count, 0 ); text: | The value of the object referenced by the ${../if/flush:/params[1]/name} parameter shall be 0 after the return of the ${../if/flush:/name} or ${../if/get-number-pending:/name} call. - name: Set test-code: | T_eq_u32( ctx->count, NUMBER_OF_PENDING_MESSAGES ); text: | The ${../if/get-number-pending:/name} directive shall set the value of the object referenced by the ${../if/get-number-pending:/params[1]/name} parameter to the number of messages present in the ${/glossary/messagequeue:/term} at a point in time during the single execution of the ${../if/get-number-pending:/name} directive. The ${../if/flush:/name} directive shall set the value of the object referenced by the ${../if/flush:/params[1]/name} parameter to the number of messages it removed from the ${/glossary/messagequeue:/term} during the single execution of the ${../if/flush:/name} directive. - name: Nop test-code: | T_eq_u32( ctx->count, UINT8_MAX ); text: | The value of the object referenced by the ${../if/flush:/params[1]/name} parameter in past call to ${../if/flush:/name} or ${../if/get-number-pending:/name} shall not be accessed by the ${../if/flush:/name} or ${../if/get-number-pending:/name} call (see also ${../glossary/nop:/term}). test-epilogue: null test-prologue: null - name: MsgQueue states: - name: Empty test-code: | PopMessage( ctx, CheckForNoMessage ); text: | The ${/glossary/messagequeue:/term} shall contain no messages after the last call to ${../if/flush:/params[0]/name}. - name: Nop test-code: | ctx->check_msgq_unchanged( ctx ); text: | Objects referenced by the ${../if/flush:/params[0]/name} parameter in the past call to ${../if/flush:/name} or ${../if/get-number-pending:/name} shall not be changed by that call (see also ${../glossary/nop:/term}). test-epilogue: null test-prologue: null - name: Receivers states: - name: Nop test-code: | size_t i; for ( i = 0; i < NUMBER_OF_WORKERS; ++i ) { T_rsc( ctx->receive_status[i], RTEMS_TIMEOUT ); } text: | The ${../glossary/receiver:/plural} waiting for a message at the ${/glossary/messagequeue:/term} shall not be affected by the call to the ${../if/flush:/name} or ${../if/get-number-pending:/name} directive. test-epilogue: null test-prologue: null pre-conditions: - name: Count states: - name: Valid test-code: | ctx->count_param = &ctx->count; text: | While the ${../if/flush:/params[1]/name} parameter references an ``uint32_t`` object. - name: 'Null' test-code: | ctx->count_param = NULL; text: | While the ${../if/flush:/params[1]/name} parameter is ${/c/if/null:/name}. test-epilogue: null test-prologue: null - name: Id states: - name: Valid test-code: | ctx->id_param = ctx->message_queue_id; text: | While the ${../if/flush:/params[0]/name} parameter is valid. - name: Invalid test-code: | ctx->id_param = RTEMS_ID_NONE; text: | While the ${../if/flush:/params[0]/name} parameter is invalid. test-epilogue: null test-prologue: null - name: MsgQueue states: - name: Empty test-code: | /* Message queue is already empty. */ ctx->check_msgq_unchanged = CheckForNoMessageInQueue; text: | While there is no message in the ${/glossary/messagequeue:/term}. - name: Several test-code: | uint32_t i; for ( i = 0; i < NUMBER_OF_PENDING_MESSAGES; ++i ) { SendMsg( ctx ); } ctx->check_msgq_unchanged = CheckForSeveralMessagesInQueue; text: | While there are messages in the ${/glossary/messagequeue:/term}. test-epilogue: null test-prologue: null - name: Receivers states: - name: Waiting test-code: | size_t i; for ( i = 0; i < NUMBER_OF_WORKERS; ++i ) { SendEvents( ctx->worker_id[i], EVENT_RECEIVE ); } text: | While one or more ${../glossary/receiver:/plural} are waiting to receive a message. - name: None test-code: | /* There is already no receiver waiting. */ text: | While no ${../glossary/receiver:/term} is waiting to receive a message. test-epilogue: null test-prologue: null - name: Directive states: - name: Flush test-code: | ctx->action = rtems_message_queue_flush; text: | While the directive ${../if/flush:/name} is called. - name: Pending test-code: | ctx->action = rtems_message_queue_get_number_pending; text: | While the directive ${../if/get-number-pending:/name} is called. test-epilogue: null test-prologue: null - name: Storage states: - name: Nop test-code: | /* Only a requirement text. */ text: | While the memory area to which a pointer is provided as member ${../if/config:/definition[3]/default/name} of type ${../if/config:/name} when the ${/glossary/messagequeue:/term} is constructed by ${../if/construct:/name} is altered only by the ${/glossary/rtems:/term} operating system. test-epilogue: null test-prologue: null rationale: null references: [] requirement-type: functional skip-reasons: NoWait: | The ${/glossary/messagequeue:/term} must be empty for an ${../glossary/receiver:/term} to wait for a message. test-action: | ctx->status = (ctx->action)( ctx->id_param, ctx->count_param ); FinalClockTick(); test-brief: null test-cleanup: | T_rsc_success( rtems_message_queue_delete( ctx->message_queue_id ) ); test-context: - brief: | This member contains a valid ${/glossary/id:/term} of a ${/glossary/messagequeue:/term}. description: null member: | rtems_id message_queue_id - brief: | This member is used as storage area for the ${/glossary/messagequeue:/term}. description: null member: | RTEMS_MESSAGE_QUEUE_BUFFER( MAXIMUM_MESSAGE_SIZE ) storage_area[ MAXIMUM_PENDING_MESSAGES ] - brief: | This member contains the returned ${/glossary/statuscode:/plural} of the receivers. description: null member: | rtems_status_code receive_status[ NUMBER_OF_WORKERS ] - brief: | This member specifies the directive to be called as action. description: | This is either ${../if/flush:/name} or ${../if/get-number-pending:/name}. member: rtems_status_code (*action)( rtems_id id, uint32_t *count ) - brief: | This member specifies the ${../if/flush:/params[0]/name} parameter of the action. description: null member: | rtems_id id_param - brief: | This member specifies the ${../if/flush:/params[1]/name} parameter of the action. description: null member: | uint32_t *count_param - brief: | This member contains the returned ${/glossary/statuscode:/term} of the action. description: null member: | rtems_status_code status - brief: | This member contains the value returned in parameter ${../if/flush:/params[1]/name} of the action. description: null member: | uint32_t count - brief: | This member contains the ${/glossary/task:/term} identifiers of the worker ${/glossary/task:/plural}. description: null member: | rtems_id worker_id[ NUMBER_OF_WORKERS ] - brief: | This member contains a pointer to a function which is executed to check that the action has not changed the content of the ${/glossary/messagequeue:/term}. description: null member: | void (*check_msgq_unchanged)( void *ctx_in ) test-context-support: | #define MAXIMUM_PENDING_MESSAGES 3 #define MAXIMUM_MESSAGE_SIZE 5 #define NUMBER_OF_WORKERS 3 test-description: null test-header: null test-includes: - rtems.h test-local-includes: - tx-support.h test-prepare: | rtems_status_code status; rtems_message_queue_config config = { .name = rtems_build_name( 'M', 'S', 'G', 'Q' ), .maximum_pending_messages = MAXIMUM_PENDING_MESSAGES, .maximum_message_size = MAXIMUM_MESSAGE_SIZE, .storage_area = ctx->storage_area, .storage_size = sizeof( ctx->storage_area ), .storage_free = NULL, .attributes = RTEMS_DEFAULT_ATTRIBUTES }; status = rtems_message_queue_construct( &config, &ctx->message_queue_id ); T_rsc_success( status ); ctx->count = UINT8_MAX; test-setup: brief: null code: | size_t i; SetSelfPriority( PRIO_NORMAL ); for ( i = 0; i < NUMBER_OF_WORKERS; ++i ) { ctx->worker_id[i] = CreateTask( "WORK", PRIO_HIGH ); StartTask( ctx->worker_id[i], WorkerTask, ctx ); } description: null test-stop: null test-support: | typedef ${.:/test-context-type} Context; static const uint32_t NUMBER_OF_PENDING_MESSAGES = 2; static const rtems_interval TIMEOUT_TICKS = 1; static const rtems_event_set EVENT_RECEIVE = RTEMS_EVENT_17; static const uint8_t queued_message[] = { 200, 201, 202 }; static void Receive( Context *ctx, size_t worker_index ) { size_t size; uint8_t buffer[ MAXIMUM_MESSAGE_SIZE ]; ctx->receive_status[worker_index] = rtems_message_queue_receive( ctx->message_queue_id, buffer, &size, RTEMS_WAIT, TIMEOUT_TICKS ); } static void WorkerTask( rtems_task_argument argument ) { static size_t worker_number = 0; size_t worker_index = worker_number++; Context *ctx = (Context *) argument; while ( true ) { ReceiveAnyEvents(); Receive( ctx, worker_index ); } } static void CheckForNoMessage( Context *ctx, rtems_status_code status, uint8_t *message_buffer, size_t message_size ) { (void) ctx; (void) message_buffer; (void) message_size; T_rsc( status, RTEMS_UNSATISFIED ); } static void CheckForQueuedMessage( Context *ctx, rtems_status_code status, uint8_t *message_buffer, size_t message_size ) { (void) ctx; T_rsc_success( status ); T_eq_u32( message_size, sizeof( queued_message ) ); T_eq_mem( message_buffer, queued_message, sizeof( queued_message ) ); } static void PopMessage( Context *ctx, void (*check_fn)( Context *ctx, rtems_status_code status, uint8_t *message_buffer, size_t message_size ) ) { rtems_status_code status; uint8_t message_buffer[ MAXIMUM_MESSAGE_SIZE ]; size_t message_size; status = rtems_message_queue_receive( ctx->message_queue_id, &message_buffer, &message_size, RTEMS_LOCAL | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT ); check_fn( ctx, status, message_buffer, message_size ); } static void CheckForNoMessageInQueue( void *ctx_in ) { Context *ctx = ctx_in; PopMessage( ctx, CheckForNoMessage ); } static void CheckForSeveralMessagesInQueue( void *ctx_in ) { Context *ctx = ctx_in; uint32_t i; for ( i = 0; i < NUMBER_OF_PENDING_MESSAGES; ++i ) { PopMessage( ctx, CheckForQueuedMessage ); } PopMessage( ctx, CheckForNoMessage ); } static void SendMsg( Context *ctx ) { rtems_status_code status; status = rtems_message_queue_send( ctx->message_queue_id, queued_message, sizeof( queued_message ) ); T_rsc_success( status ); } test-target: testsuites/validation/tc-message-flush-pending.c test-teardown: brief: null code: | size_t i; for ( i = 0; i < NUMBER_OF_WORKERS; ++i ) { DeleteTask( ctx->worker_id[i] ); } RestoreRunnerPriority(); description: null text: ${.:text-template} transition-map: # ---- Ok Case ---- - enabled-by: true post-conditions: Status: Ok Count: - if: pre-conditions: MsgQueue: Several then: Set - else: Zero MsgQueue: - if: pre-conditions: Directive: Flush then: Empty - else: Nop Receivers: - if: pre-conditions: Receivers: Waiting then: Nop - else: N/A pre-conditions: Count: - Valid Id: - Valid MsgQueue: all Receivers: all Directive: all Storage: all # ---- InvAddr: Count ---- - enabled-by: true post-conditions: Status: InvAddr Count: Nop MsgQueue: Nop Receivers: - if: pre-conditions: Receivers: Waiting then: Nop - else: N/A pre-conditions: Count: - 'Null' Id: all MsgQueue: all Receivers: all Directive: all Storage: all # ---- InvId ---- - enabled-by: true post-conditions: Status: InvId Count: Nop MsgQueue: Nop Receivers: - if: pre-conditions: Receivers: Waiting then: Nop - else: N/A RecSize: - if: pre-conditions: Receivers: Waiting then: Nop - else: N/A RecBuffer: - if: pre-conditions: Receivers: Waiting then: Nop - else: N/A pre-conditions: Count: - Valid Id: - Invalid MsgQueue: all Receivers: all Directive: all Storage: all # ---- Impossible Cases ---- - enabled-by: true post-conditions: NoWait pre-conditions: Count: all Id: all MsgQueue: - Several Receivers: - Waiting Directive: all Storage: all type: requirement