[PATCH 1/2] unit: Test POSIX-specific message queue impl
Gedare Bloom
gedare at rtems.org
Thu Jul 20 17:10:17 UTC 2023
Minor nits.
On Thu, Jul 20, 2023 at 7:40 AM Sebastian Huber
<sebastian.huber at embedded-brains.de> wrote:
>
> From: Frank Kühndel <frank.kuehndel at embedded-brains.de>
>
> This unit test covers code paths of the Message Handler which are only
> reached by through POSIX message queue API.
>
> Update #3716.
> ---
> .../build/testsuites/unit/unit-no-clock-0.yml | 1 +
> testsuites/unit/tc-score-msgq.c | 452 ++++++++++++++++++
> 2 files changed, 453 insertions(+)
> create mode 100644 testsuites/unit/tc-score-msgq.c
>
> diff --git a/spec/build/testsuites/unit/unit-no-clock-0.yml b/spec/build/testsuites/unit/unit-no-clock-0.yml
> index 57cd279a7a..517b84284d 100644
> --- a/spec/build/testsuites/unit/unit-no-clock-0.yml
> +++ b/spec/build/testsuites/unit/unit-no-clock-0.yml
> @@ -12,6 +12,7 @@ ldflags: []
> links: []
> source:
> - testsuites/unit/tc-misaligned-builtin-memcpy.c
> +- testsuites/unit/tc-score-msgq.c
> - testsuites/unit/tc-score-rbtree.c
> - testsuites/unit/ts-unit-no-clock-0.c
> stlib: []
> diff --git a/testsuites/unit/tc-score-msgq.c b/testsuites/unit/tc-score-msgq.c
> new file mode 100644
> index 0000000000..c4baa6d53e
> --- /dev/null
> +++ b/testsuites/unit/tc-score-msgq.c
> @@ -0,0 +1,452 @@
> +/* SPDX-License-Identifier: BSD-2-Clause */
> +
> +/**
> + * @file
> + *
> + * @ingroup ScoreMsgqUnitMsgq
> + */
> +
> +/*
> + * Copyright (C) 2021 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.h>
> +#include <rtems/rtems/messageimpl.h>
> +#include <rtems/rtems/statusimpl.h>
> +#include <rtems/score/coremsgimpl.h>
> +
> +#include "../validation/tx-support.h"
> +
> +#include <rtems/test.h>
> +
> +/**
> + * @defgroup ScoreMsgqUnitMsgq spec:/score/msgq/unit/msgq
> + *
> + * @ingroup TestsuitesUnitNoClock0
> + *
> + * @brief Unit tests for the Message Queue Handler.
> + *
> + * Parts of the files ``cpukit/score/src/coremsginsert.c``,
> + * ``cpukit/score/src/coremsgseize.c``, and
> + * ``cpukit/score/src/coremsgsubmit.c`` are only executed by the POSIX API.
> + * Currently, the pre-qualified subset of RTEMS does not contain the POSIX API.
> + * This test exercises the code parts otherwise only reached by the POSIX API
> + * to achieve full code coverage.
> + *
> + * This test case performs the following actions:
> + *
> + * - Use _CORE_message_queue_Insert_message() to insert two messages into a
> + * message queue and use the POSIX message priority to define their order in
> + * the queue.
> + *
> + * - Check that _CORE_message_queue_Submit() was executed successfully.
> + *
> + * - Check that the messages are in right order in the message queue.
"in the right" or "in correct"
> + *
> + * - Submit three messages into a message queue which can only store two and
> + * have the third submit() blocked till a seize() occurs.
> + *
> + * - Check that the third _CORE_message_queue_Submit() did actually block
> + * till there was room for the message in the message queue.
> + *
> + * - Submit messages in the queue from within an ISR.
> + *
> + * - Check that the first two messages were successfully send.
sent
> + *
> + * - Check that trying to send the third message from ISR when the message
> + * queue was full was rejected.
> + *
> + * @{
> + */
> +
> +#define MAXIMUM_PENDING_MESSAGES 2
> +#define MAXIMUM_MESSAGE_SIZE 3
> +
> +static void WorkerTask( rtems_task_argument argument );
> +
> +/**
> + * @brief Test context for spec:/score/msgq/unit/msgq test case.
> + */
> +typedef struct {
> + /**
> + * @brief This member contains a valid ID of a message queue.
> + */
> + rtems_id message_queue_id;
> +
> + /**
> + * @brief This member is used as storage area for the message queue.
> + */
> + RTEMS_MESSAGE_QUEUE_BUFFER( MAXIMUM_MESSAGE_SIZE )
> + storage_area[ MAXIMUM_PENDING_MESSAGES];
> +
> + /**
> + * @brief This member contains the task identifier of the worker task.
> + */
> + rtems_id worker_id;
> +
> + /**
> + * @brief This member indicated whether the worker task is currently sending
> + * a message (``true``) or whether it is waiting to receive an event
> + * (``false``)..
extra period
> + */
> + bool is_worker_working;
> +
> + /**
> + * @brief This member contains the returned status code of the SendMessage()
> + * function.
> + */
> + rtems_status_code send_status;
> +} ScoreMsgqUnitMsgq_Context;
> +
> +static ScoreMsgqUnitMsgq_Context
> + ScoreMsgqUnitMsgq_Instance;
> +
> +#define EVENT_SEND RTEMS_EVENT_17
> +#define MESSAGE_CONTENT_LOW { 1, 2, 3 }
> +#define MESSAGE_CONTENT_HIGH { 4, 5 }
> +#define MESSAGE_PRIORITY_LOW 5
> +#define MESSAGE_PRIORITY_HIGH 7
> +#define DO_WAIT true
> +
> +typedef ScoreMsgqUnitMsgq_Context Context;
> +
> +/*
> + * This is a code fragment from rtems_message_queue_send() with the
> + * specialty that it uses a POSIX priority and the sender
> + * task will wait in case the queue is full.
> + */
> +static rtems_status_code SubmitMessage(
> + rtems_id id,
> + uint8_t *message,
> + size_t message_size,
> + unsigned int posix_piority
> +)
> +{
> + rtems_status_code status;
> + Thread_queue_Context queue_context;
> + Message_queue_Control *the_message_queue;
> +
> + T_assert_lt_uint( posix_piority, MQ_PRIO_MAX );
> +
> + the_message_queue = _Message_queue_Get(
> + id,
> + &queue_context
> + );
> + T_assert_not_null( the_message_queue );
> +
> + /* The next two calls are from _POSIX_Message_queue_Send_support() */
> + _Thread_queue_Context_set_enqueue_callout(
> + &queue_context,
> + _Thread_queue_Enqueue_do_nothing_extra
> + );
> + _Thread_queue_Context_set_timeout_argument( &queue_context, NULL, true );
> +
> + _CORE_message_queue_Acquire_critical(
> + &the_message_queue->message_queue,
> + &queue_context
> + );
> +
> + status = _CORE_message_queue_Submit(
> + &the_message_queue->message_queue,
> + _Thread_Executing,
> + message,
> + message_size,
> + (CORE_message_queue_Submit_types) ( posix_piority * -1 ),
> + DO_WAIT,
> + &queue_context
> + );
> +
> + return _Status_Get( status );
> +}
> +
> +static rtems_status_code ReceiveMessage(
> + rtems_id id,
> + void *buffer,
> + size_t *size
> +)
> +{
> + return rtems_message_queue_receive(
> + id,
> + buffer,
> + size,
> + RTEMS_LOCAL | RTEMS_NO_WAIT,
> + RTEMS_NO_TIMEOUT
> + );
> +}
> +
> +static rtems_status_code ReceiveOneMessages( Context *ctx )
> +{
> + uint8_t message_buffer[ MAXIMUM_MESSAGE_SIZE ];
> + size_t message_size;
> +
> + return ReceiveMessage(
> + ctx->message_queue_id,
> + &message_buffer,
> + &message_size
> + );
> +}
> +
> +static void SendMessage( Context *ctx )
> +{
> + uint8_t message[] = { 100, 101, 102 };
> + ctx->send_status = SubmitMessage(
> + ctx->message_queue_id,
> + message,
> + sizeof( message ),
> + MESSAGE_PRIORITY_LOW
> + );
> +}
> +
> +static void WorkerTask( rtems_task_argument argument )
> +{
> + Context *ctx = (Context *) argument;
> +
> + while ( true ) {
> + ctx->is_worker_working = false;
> + ReceiveAnyEvents();
> + ctx->is_worker_working = true;
> + SendMessage( ctx );
> + T_assert_rsc_success( ctx->send_status );
> + }
> +}
> +
> +static void WorkerSendMessage( Context *ctx )
> +{
> + SendEvents( ctx->worker_id, EVENT_SEND );
> +}
> +
> +static void ScoreMsgqUnitMsgq_Setup( ScoreMsgqUnitMsgq_Context *ctx )
> +{
> + 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 );
> +
> + SetSelfPriority( PRIO_NORMAL );
> +
> + ctx->worker_id = CreateTask( "WORK", PRIO_HIGH );
> + StartTask( ctx->worker_id, WorkerTask, ctx );
> +}
> +
> +static void ScoreMsgqUnitMsgq_Setup_Wrap( void *arg )
> +{
> + ScoreMsgqUnitMsgq_Context *ctx;
> +
> + ctx = arg;
> + ScoreMsgqUnitMsgq_Setup( ctx );
> +}
> +
> +static void ScoreMsgqUnitMsgq_Teardown( ScoreMsgqUnitMsgq_Context *ctx )
> +{
> + DeleteTask( ctx->worker_id );
> + RestoreRunnerPriority();
> + T_rsc_success( rtems_message_queue_delete( ctx->message_queue_id ) );
> +}
> +
> +static void ScoreMsgqUnitMsgq_Teardown_Wrap( void *arg )
> +{
> + ScoreMsgqUnitMsgq_Context *ctx;
> +
> + ctx = arg;
> + ScoreMsgqUnitMsgq_Teardown( ctx );
> +}
> +
> +static T_fixture ScoreMsgqUnitMsgq_Fixture = {
> + .setup = ScoreMsgqUnitMsgq_Setup_Wrap,
> + .stop = NULL,
> + .teardown = ScoreMsgqUnitMsgq_Teardown_Wrap,
> + .scope = NULL,
> + .initial_context = &ScoreMsgqUnitMsgq_Instance
> +};
> +
> +/**
> + * @brief Use _CORE_message_queue_Insert_message() to insert two messages into
> + * a message queue and use the POSIX message priority to define their order
> + * in the queue.
> + */
> +static void ScoreMsgqUnitMsgq_Action_0( ScoreMsgqUnitMsgq_Context *ctx )
> +{
> + rtems_status_code status_submit_low;
> + rtems_status_code status_submit_high;
> + rtems_status_code status_receive_low;
> + rtems_status_code status_receive_high;
> + uint8_t message_low[] = MESSAGE_CONTENT_LOW;
> + uint8_t message_high[] = MESSAGE_CONTENT_HIGH;
> + uint8_t message_buffer_low[ MAXIMUM_MESSAGE_SIZE ];
> + uint8_t message_buffer_high[ MAXIMUM_MESSAGE_SIZE ];
> + size_t message_size_low;
> + size_t message_size_high;
> +
> + status_submit_low = SubmitMessage(
> + ctx->message_queue_id,
> + message_low,
> + sizeof( message_low ),
> + MESSAGE_PRIORITY_LOW
> + );
> +
> + status_submit_high = SubmitMessage(
> + ctx->message_queue_id,
> + message_high,
> + sizeof( message_high ),
> + MESSAGE_PRIORITY_HIGH
> + );
> +
> + status_receive_high = ReceiveMessage(
> + ctx->message_queue_id,
> + &message_buffer_high,
> + &message_size_high
> + );
> +
> + status_receive_low = ReceiveMessage(
> + ctx->message_queue_id,
> + &message_buffer_low,
> + &message_size_low
> + );
> +
> + /*
> + * Check that _CORE_message_queue_Submit() was executed successfully.
> + */
> + T_rsc_success( status_submit_low );
> + T_rsc_success( status_submit_high );
> +
> + /*
> + * Check that the messages are in right order in the message queue.
> + */
> + T_rsc_success( status_receive_high );
> + T_eq_sz( message_size_high, sizeof( message_high ) );
> + T_eq_mem( message_buffer_high, message_high, message_size_high );
> +
> + T_rsc_success( status_receive_low );
> + T_eq_sz( message_size_low, sizeof( message_low ) );
> + T_eq_mem( message_buffer_low, message_low, message_size_low );
> +}
> +
> +/**
> + * @brief Submit three messages into a message queue which can only store two
> + * and have the third submit() blocked till a seize() occurs.
> + */
> +static void ScoreMsgqUnitMsgq_Action_1( ScoreMsgqUnitMsgq_Context *ctx )
> +{
> + bool is_worker_blocked_after_third_send;
> + bool is_worker_blocked_after_first_receive;
> +
> + WorkerSendMessage( ctx );
> + WorkerSendMessage( ctx );
> + WorkerSendMessage( ctx );
> + is_worker_blocked_after_third_send = ctx->is_worker_working;
> +
> + T_rsc_success( ReceiveOneMessages( ctx ) );
> + is_worker_blocked_after_first_receive = ctx->is_worker_working;
> +
> + T_rsc_success( ReceiveOneMessages( ctx ) );
> + T_rsc_success( ReceiveOneMessages( ctx ) );
> +
> + /*
> + * Check that the third _CORE_message_queue_Submit() did actually block till
> + * there was room for the message in the message queue.
> + */
> + T_true( is_worker_blocked_after_third_send );
> + T_true( !is_worker_blocked_after_first_receive );
> +}
> +
> +/**
> + * @brief Submit messages in the queue from within an ISR.
> + */
> +static void ScoreMsgqUnitMsgq_Action_2( ScoreMsgqUnitMsgq_Context *ctx )
> +{
> + rtems_status_code status_send_first_message;
> + rtems_status_code status_send_second_message;
> + rtems_status_code status_send_third_message;
> +
> + CallWithinISR( ( void (*)(void*) ) SendMessage, ctx );
> + status_send_first_message = ctx->send_status;
> + CallWithinISR( ( void (*)(void*) ) SendMessage, ctx );
> + status_send_second_message = ctx->send_status;
> + CallWithinISR( ( void (*)(void*) ) SendMessage, ctx );
> + status_send_third_message = ctx->send_status;
> +
> + T_rsc_success( ReceiveOneMessages( ctx ) );
> + T_rsc_success( ReceiveOneMessages( ctx ) );
> +
> + /*
> + * Check that the first two messages were successfully send.
> + */
> + T_assert_rsc_success( status_send_first_message );
> + T_assert_rsc_success( status_send_second_message );
> +
> + /*
> + * Check that trying to send the third message from ISR when the message
> + * queue was full was rejected.
> + */
> + T_rsc( status_send_third_message, STATUS_CLASSIC_INTERNAL_ERROR );
> +}
> +
> +/**
> + * @fn void T_case_body_ScoreMsgqUnitMsgq( void )
> + */
> +T_TEST_CASE_FIXTURE( ScoreMsgqUnitMsgq, &ScoreMsgqUnitMsgq_Fixture )
> +{
> + ScoreMsgqUnitMsgq_Context *ctx;
> +
> + ctx = T_fixture_context();
> +
> + ScoreMsgqUnitMsgq_Action_0( ctx );
> + ScoreMsgqUnitMsgq_Action_1( ctx );
> + ScoreMsgqUnitMsgq_Action_2( ctx );
> +}
> +
> +/** @} */
> --
> 2.35.3
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel
More information about the devel
mailing list