Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:50

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup ScoreMsgqUnitMsgq
0007  */
0008 
0009 /*
0010  * Copyright (C) 2021 embedded brains GmbH & Co. KG
0011  *
0012  * Redistribution and use in source and binary forms, with or without
0013  * modification, are permitted provided that the following conditions
0014  * are met:
0015  * 1. Redistributions of source code must retain the above copyright
0016  *    notice, this list of conditions and the following disclaimer.
0017  * 2. Redistributions in binary form must reproduce the above copyright
0018  *    notice, this list of conditions and the following disclaimer in the
0019  *    documentation and/or other materials provided with the distribution.
0020  *
0021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0025  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0026  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0027  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0030  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0031  * POSSIBILITY OF SUCH DAMAGE.
0032  */
0033 
0034 /*
0035  * This file is part of the RTEMS quality process and was automatically
0036  * generated.  If you find something that needs to be fixed or
0037  * worded better please post a report or patch to an RTEMS mailing list
0038  * or raise a bug report:
0039  *
0040  * https://www.rtems.org/bugs.html
0041  *
0042  * For information on updating and regenerating please refer to the How-To
0043  * section in the Software Requirements Engineering chapter of the
0044  * RTEMS Software Engineering manual.  The manual is provided as a part of
0045  * a release.  For development sources please refer to the online
0046  * documentation at:
0047  *
0048  * https://docs.rtems.org
0049  */
0050 
0051 #ifdef HAVE_CONFIG_H
0052 #include "config.h"
0053 #endif
0054 
0055 #include <rtems.h>
0056 #include <rtems/rtems/messageimpl.h>
0057 #include <rtems/rtems/statusimpl.h>
0058 #include <rtems/score/coremsgimpl.h>
0059 
0060 #include "../validation/tx-support.h"
0061 
0062 #include <rtems/test.h>
0063 
0064 /**
0065  * @defgroup ScoreMsgqUnitMsgq spec:/score/msgq/unit/msgq
0066  *
0067  * @ingroup TestsuitesUnitNoClock0
0068  *
0069  * @brief Unit tests for the Message Queue Handler.
0070  *
0071  * Parts of the files ``cpukit/score/src/coremsginsert.c``,
0072  * ``cpukit/score/src/coremsgseize.c``, and
0073  * ``cpukit/score/src/coremsgsubmit.c`` are only executed by the POSIX API.
0074  * Currently, the pre-qualified subset of RTEMS does not contain the POSIX API.
0075  * This test exercises the code parts otherwise only reached by the POSIX API
0076  * to achieve full code coverage.
0077  *
0078  * This test case performs the following actions:
0079  *
0080  * - Use _CORE_message_queue_Insert_message() to insert two messages into a
0081  *   message queue and use the POSIX message priority to define their order in
0082  *   the queue.
0083  *
0084  *   - Check that _CORE_message_queue_Submit() was executed successfully.
0085  *
0086  *   - Check that the messages are in the right order in the message queue.
0087  *
0088  * - Submit three messages into a message queue which can only store two and
0089  *   have the third submit() blocked till a seize() occurs.
0090  *
0091  *   - Check that the third _CORE_message_queue_Submit() did actually block
0092  *     till there was room for the message in the message queue.
0093  *
0094  * - Submit messages in the queue from within an ISR.
0095  *
0096  *   - Check that the first two messages were successfully send.
0097  *
0098  *   - Check that trying to send the third message from ISR when the message
0099  *     queue was full was rejected.
0100  *
0101  * @{
0102  */
0103 
0104 #define MAXIMUM_PENDING_MESSAGES 2
0105 #define MAXIMUM_MESSAGE_SIZE 3
0106 
0107 static void WorkerTask( rtems_task_argument argument );
0108 
0109 /**
0110  * @brief Test context for spec:/score/msgq/unit/msgq test case.
0111  */
0112 typedef struct {
0113   /**
0114    * @brief This member contains a valid ID of a message queue.
0115    */
0116   rtems_id message_queue_id;
0117 
0118   /**
0119    * @brief This member is used as storage area for the message queue.
0120    */
0121   RTEMS_MESSAGE_QUEUE_BUFFER( MAXIMUM_MESSAGE_SIZE )
0122     storage_area[ MAXIMUM_PENDING_MESSAGES];
0123 
0124   /**
0125    * @brief This member contains the task identifier of the worker task.
0126    */
0127   rtems_id worker_id;
0128 
0129   /**
0130    * @brief This member indicated whether the worker task is currently sending
0131    *   a message (``true``) or whether it is waiting to receive an event
0132    *   (``false``).
0133    */
0134   bool is_worker_working;
0135 
0136   /**
0137    * @brief This member contains the returned status code of the SendMessage()
0138    *   function.
0139    */
0140   rtems_status_code send_status;
0141 } ScoreMsgqUnitMsgq_Context;
0142 
0143 static ScoreMsgqUnitMsgq_Context
0144   ScoreMsgqUnitMsgq_Instance;
0145 
0146 #define EVENT_SEND RTEMS_EVENT_17
0147 #define MESSAGE_CONTENT_LOW { 1, 2, 3 }
0148 #define MESSAGE_CONTENT_HIGH { 4, 5 }
0149 #define MESSAGE_PRIORITY_LOW 5
0150 #define MESSAGE_PRIORITY_HIGH 7
0151 #define DO_WAIT true
0152 
0153 typedef ScoreMsgqUnitMsgq_Context Context;
0154 
0155 /*
0156  * This is a code fragment from rtems_message_queue_send() with the
0157  * specialty that it uses a POSIX priority and the sender
0158  * task will wait in case the queue is full.
0159  */
0160 static rtems_status_code SubmitMessage(
0161   rtems_id id,
0162   uint8_t *message,
0163   size_t message_size,
0164   unsigned int posix_piority
0165 )
0166 {
0167   rtems_status_code status;
0168   Thread_queue_Context queue_context;
0169   Message_queue_Control *the_message_queue;
0170 
0171   T_assert_lt_uint( posix_piority, MQ_PRIO_MAX );
0172 
0173   the_message_queue = _Message_queue_Get(
0174     id,
0175     &queue_context
0176   );
0177   T_assert_not_null( the_message_queue );
0178 
0179   /* The next two calls are from _POSIX_Message_queue_Send_support() */
0180   _Thread_queue_Context_set_enqueue_callout(
0181     &queue_context,
0182     _Thread_queue_Enqueue_do_nothing_extra
0183   );
0184   _Thread_queue_Context_set_timeout_argument( &queue_context, NULL, true );
0185 
0186   _CORE_message_queue_Acquire_critical(
0187     &the_message_queue->message_queue,
0188     &queue_context
0189   );
0190 
0191   status = _CORE_message_queue_Submit(
0192     &the_message_queue->message_queue,
0193     _Thread_Executing,
0194     message,
0195     message_size,
0196     (CORE_message_queue_Submit_types) ( posix_piority * -1 ),
0197     DO_WAIT,
0198     &queue_context
0199   );
0200 
0201   return _Status_Get( status );
0202 }
0203 
0204 static rtems_status_code ReceiveMessage(
0205   rtems_id id,
0206   void *buffer,
0207   size_t *size
0208 )
0209 {
0210   return rtems_message_queue_receive(
0211     id,
0212     buffer,
0213     size,
0214     RTEMS_LOCAL | RTEMS_NO_WAIT,
0215     RTEMS_NO_TIMEOUT
0216   );
0217 }
0218 
0219 static rtems_status_code ReceiveOneMessages( Context *ctx )
0220 {
0221   uint8_t message_buffer[ MAXIMUM_MESSAGE_SIZE ];
0222   size_t message_size;
0223 
0224   return ReceiveMessage(
0225     ctx->message_queue_id,
0226     &message_buffer,
0227     &message_size
0228   );
0229 }
0230 
0231 static void SendMessage( Context *ctx )
0232 {
0233   uint8_t message[] = { 100, 101, 102 };
0234   ctx->send_status = SubmitMessage(
0235     ctx->message_queue_id,
0236     message,
0237     sizeof( message ),
0238     MESSAGE_PRIORITY_LOW
0239   );
0240 }
0241 
0242 static void WorkerTask( rtems_task_argument argument )
0243 {
0244   Context *ctx = (Context *) argument;
0245 
0246   while ( true ) {
0247     ctx->is_worker_working = false;
0248     ReceiveAnyEvents();
0249     ctx->is_worker_working = true;
0250     SendMessage( ctx );
0251     T_assert_rsc_success( ctx->send_status );
0252   }
0253 }
0254 
0255 static void WorkerSendMessage( Context *ctx )
0256 {
0257   SendEvents( ctx->worker_id, EVENT_SEND );
0258 }
0259 
0260 static void ScoreMsgqUnitMsgq_Setup( ScoreMsgqUnitMsgq_Context *ctx )
0261 {
0262   rtems_status_code status;
0263   rtems_message_queue_config config = {
0264     .name                     = rtems_build_name( 'M', 'S', 'G', 'Q' ),
0265     .maximum_pending_messages = MAXIMUM_PENDING_MESSAGES,
0266     .maximum_message_size     = MAXIMUM_MESSAGE_SIZE,
0267     .storage_area             = ctx->storage_area,
0268     .storage_size             = sizeof( ctx->storage_area ),
0269     .storage_free             = NULL,
0270     .attributes               = RTEMS_DEFAULT_ATTRIBUTES
0271   };
0272 
0273   status = rtems_message_queue_construct(
0274     &config,
0275     &ctx->message_queue_id
0276   );
0277   T_rsc_success( status );
0278 
0279   SetSelfPriority( PRIO_NORMAL );
0280 
0281   ctx->worker_id = CreateTask( "WORK", PRIO_HIGH );
0282   StartTask( ctx->worker_id, WorkerTask, ctx );
0283 }
0284 
0285 static void ScoreMsgqUnitMsgq_Setup_Wrap( void *arg )
0286 {
0287   ScoreMsgqUnitMsgq_Context *ctx;
0288 
0289   ctx = arg;
0290   ScoreMsgqUnitMsgq_Setup( ctx );
0291 }
0292 
0293 static void ScoreMsgqUnitMsgq_Teardown( ScoreMsgqUnitMsgq_Context *ctx )
0294 {
0295   DeleteTask( ctx->worker_id );
0296   RestoreRunnerPriority();
0297   T_rsc_success( rtems_message_queue_delete( ctx->message_queue_id ) );
0298 }
0299 
0300 static void ScoreMsgqUnitMsgq_Teardown_Wrap( void *arg )
0301 {
0302   ScoreMsgqUnitMsgq_Context *ctx;
0303 
0304   ctx = arg;
0305   ScoreMsgqUnitMsgq_Teardown( ctx );
0306 }
0307 
0308 static T_fixture ScoreMsgqUnitMsgq_Fixture = {
0309   .setup = ScoreMsgqUnitMsgq_Setup_Wrap,
0310   .stop = NULL,
0311   .teardown = ScoreMsgqUnitMsgq_Teardown_Wrap,
0312   .scope = NULL,
0313   .initial_context = &ScoreMsgqUnitMsgq_Instance
0314 };
0315 
0316 /**
0317  * @brief Use _CORE_message_queue_Insert_message() to insert two messages into
0318  *   a message queue and use the POSIX message priority to define their order
0319  *   in the queue.
0320  */
0321 static void ScoreMsgqUnitMsgq_Action_0( ScoreMsgqUnitMsgq_Context *ctx )
0322 {
0323   rtems_status_code status_submit_low;
0324   rtems_status_code status_submit_high;
0325   rtems_status_code status_receive_low;
0326   rtems_status_code status_receive_high;
0327   uint8_t message_low[] = MESSAGE_CONTENT_LOW;
0328   uint8_t message_high[] = MESSAGE_CONTENT_HIGH;
0329   uint8_t message_buffer_low[ MAXIMUM_MESSAGE_SIZE ];
0330   uint8_t message_buffer_high[ MAXIMUM_MESSAGE_SIZE ];
0331   size_t message_size_low;
0332   size_t message_size_high;
0333 
0334   status_submit_low = SubmitMessage(
0335     ctx->message_queue_id,
0336     message_low,
0337     sizeof( message_low ),
0338     MESSAGE_PRIORITY_LOW
0339   );
0340 
0341   status_submit_high = SubmitMessage(
0342     ctx->message_queue_id,
0343     message_high,
0344     sizeof( message_high ),
0345     MESSAGE_PRIORITY_HIGH
0346   );
0347 
0348   status_receive_high = ReceiveMessage(
0349     ctx->message_queue_id,
0350     &message_buffer_high,
0351     &message_size_high
0352   );
0353 
0354   status_receive_low = ReceiveMessage(
0355     ctx->message_queue_id,
0356     &message_buffer_low,
0357     &message_size_low
0358   );
0359 
0360   /*
0361    * Check that _CORE_message_queue_Submit() was executed successfully.
0362    */
0363   T_rsc_success( status_submit_low );
0364   T_rsc_success( status_submit_high );
0365 
0366   /*
0367    * Check that the messages are in the right order in the message queue.
0368    */
0369   T_rsc_success( status_receive_high );
0370   T_eq_sz( message_size_high, sizeof( message_high ) );
0371   T_eq_mem( message_buffer_high, message_high, message_size_high );
0372 
0373   T_rsc_success( status_receive_low );
0374   T_eq_sz( message_size_low, sizeof( message_low ) );
0375   T_eq_mem( message_buffer_low, message_low, message_size_low );
0376 }
0377 
0378 /**
0379  * @brief Submit three messages into a message queue which can only store two
0380  *   and have the third submit() blocked till a seize() occurs.
0381  */
0382 static void ScoreMsgqUnitMsgq_Action_1( ScoreMsgqUnitMsgq_Context *ctx )
0383 {
0384   bool is_worker_blocked_after_third_send;
0385   bool is_worker_blocked_after_first_receive;
0386 
0387   WorkerSendMessage( ctx );
0388   WorkerSendMessage( ctx );
0389   WorkerSendMessage( ctx );
0390   is_worker_blocked_after_third_send = ctx->is_worker_working;
0391 
0392   T_rsc_success( ReceiveOneMessages( ctx ) );
0393   is_worker_blocked_after_first_receive = ctx->is_worker_working;
0394 
0395   T_rsc_success( ReceiveOneMessages( ctx ) );
0396   T_rsc_success( ReceiveOneMessages( ctx ) );
0397 
0398   /*
0399    * Check that the third _CORE_message_queue_Submit() did actually block till
0400    * there was room for the message in the message queue.
0401    */
0402   T_true( is_worker_blocked_after_third_send );
0403   T_true( !is_worker_blocked_after_first_receive );
0404 }
0405 
0406 /**
0407  * @brief Submit messages in the queue from within an ISR.
0408  */
0409 static void ScoreMsgqUnitMsgq_Action_2( ScoreMsgqUnitMsgq_Context *ctx )
0410 {
0411   rtems_status_code status_send_first_message;
0412   rtems_status_code status_send_second_message;
0413   rtems_status_code status_send_third_message;
0414 
0415   CallWithinISR( ( void (*)(void*) ) SendMessage, ctx );
0416   status_send_first_message = ctx->send_status;
0417   CallWithinISR( ( void (*)(void*) ) SendMessage, ctx );
0418   status_send_second_message = ctx->send_status;
0419   CallWithinISR( ( void (*)(void*) ) SendMessage, ctx );
0420   status_send_third_message = ctx->send_status;
0421 
0422   T_rsc_success( ReceiveOneMessages( ctx ) );
0423   T_rsc_success( ReceiveOneMessages( ctx ) );
0424 
0425   /*
0426    * Check that the first two messages were successfully send.
0427    */
0428   T_assert_rsc_success( status_send_first_message );
0429   T_assert_rsc_success( status_send_second_message );
0430 
0431   /*
0432    * Check that trying to send the third message from ISR when the message
0433    * queue was full was rejected.
0434    */
0435   T_rsc( status_send_third_message, STATUS_CLASSIC_INTERNAL_ERROR );
0436 }
0437 
0438 /**
0439  * @fn void T_case_body_ScoreMsgqUnitMsgq( void )
0440  */
0441 T_TEST_CASE_FIXTURE( ScoreMsgqUnitMsgq, &ScoreMsgqUnitMsgq_Fixture )
0442 {
0443   ScoreMsgqUnitMsgq_Context *ctx;
0444 
0445   ctx = T_fixture_context();
0446 
0447   ScoreMsgqUnitMsgq_Action_0( ctx );
0448   ScoreMsgqUnitMsgq_Action_1( ctx );
0449   ScoreMsgqUnitMsgq_Action_2( ctx );
0450 }
0451 
0452 /** @} */