[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