Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RtemsTaskReqWakeAfter
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/test-scheduler.h>
0057 #include <rtems/score/threaddispatch.h>
0058 #include <rtems/score/timecounter.h>
0059 
0060 #include "tx-support.h"
0061 
0062 #include <rtems/test.h>
0063 
0064 /**
0065  * @defgroup RtemsTaskReqWakeAfter spec:/rtems/task/req/wake-after
0066  *
0067  * @ingroup TestsuitesValidationNoClock0
0068  * @ingroup TestsuitesValidationOneCpu0
0069  *
0070  * @{
0071  */
0072 
0073 typedef enum {
0074   RtemsTaskReqWakeAfter_Pre_Ticks_Yield,
0075   RtemsTaskReqWakeAfter_Pre_Ticks_Interval,
0076   RtemsTaskReqWakeAfter_Pre_Ticks_NA
0077 } RtemsTaskReqWakeAfter_Pre_Ticks;
0078 
0079 typedef enum {
0080   RtemsTaskReqWakeAfter_Pre_Suspended_Yes,
0081   RtemsTaskReqWakeAfter_Pre_Suspended_No,
0082   RtemsTaskReqWakeAfter_Pre_Suspended_NA
0083 } RtemsTaskReqWakeAfter_Pre_Suspended;
0084 
0085 typedef enum {
0086   RtemsTaskReqWakeAfter_Post_Status_Ok,
0087   RtemsTaskReqWakeAfter_Post_Status_NA
0088 } RtemsTaskReqWakeAfter_Post_Status;
0089 
0090 typedef enum {
0091   RtemsTaskReqWakeAfter_Post_Timer_Inactive,
0092   RtemsTaskReqWakeAfter_Post_Timer_Ticks,
0093   RtemsTaskReqWakeAfter_Post_Timer_NA
0094 } RtemsTaskReqWakeAfter_Post_Timer;
0095 
0096 typedef enum {
0097   RtemsTaskReqWakeAfter_Post_Expire_Relative,
0098   RtemsTaskReqWakeAfter_Post_Expire_NA
0099 } RtemsTaskReqWakeAfter_Post_Expire;
0100 
0101 typedef enum {
0102   RtemsTaskReqWakeAfter_Post_Scheduler_Block,
0103   RtemsTaskReqWakeAfter_Post_Scheduler_Yield,
0104   RtemsTaskReqWakeAfter_Post_Scheduler_Nop,
0105   RtemsTaskReqWakeAfter_Post_Scheduler_NA
0106 } RtemsTaskReqWakeAfter_Post_Scheduler;
0107 
0108 typedef struct {
0109   uint16_t Skip : 1;
0110   uint16_t Pre_Ticks_NA : 1;
0111   uint16_t Pre_Suspended_NA : 1;
0112   uint16_t Post_Status : 1;
0113   uint16_t Post_Timer : 2;
0114   uint16_t Post_Expire : 1;
0115   uint16_t Post_Scheduler : 2;
0116 } RtemsTaskReqWakeAfter_Entry;
0117 
0118 /**
0119  * @brief Test context for spec:/rtems/task/req/wake-after test case.
0120  */
0121 typedef struct {
0122   /**
0123    * @brief This member provides the scheduler operation records.
0124    */
0125   T_scheduler_log_4 scheduler_log;
0126 
0127   /**
0128    * @brief This member contains the clock tick value before the
0129    *   rtems_task_wake_after() call.
0130    */
0131   uint64_t now;
0132 
0133   /**
0134    * @brief This member contains the worker task identifier.
0135    */
0136   rtems_id worker_id;
0137 
0138   /**
0139    * @brief If this member is true, then the worker shall be suspended during
0140    *   the rtems_task_wake_after() call.
0141    */
0142   bool suspended;
0143 
0144   /**
0145    * @brief This member contains the timer information of the worker task.
0146    */
0147   TaskTimerInfo timer_info;
0148 
0149   /**
0150    * @brief This member contains the return value of the
0151    *   rtems_task_wake_after() call.
0152    */
0153   rtems_status_code status;
0154 
0155   /**
0156    * @brief This member specifies the ``ticks`` parameter value.
0157    */
0158   rtems_interval ticks;
0159 
0160   struct {
0161     /**
0162      * @brief This member defines the pre-condition states for the next action.
0163      */
0164     size_t pcs[ 2 ];
0165 
0166     /**
0167      * @brief If this member is true, then the test action loop is executed.
0168      */
0169     bool in_action_loop;
0170 
0171     /**
0172      * @brief This member contains the next transition map index.
0173      */
0174     size_t index;
0175 
0176     /**
0177      * @brief This member contains the current transition map entry.
0178      */
0179     RtemsTaskReqWakeAfter_Entry entry;
0180 
0181     /**
0182      * @brief If this member is true, then the current transition variant
0183      *   should be skipped.
0184      */
0185     bool skip;
0186   } Map;
0187 } RtemsTaskReqWakeAfter_Context;
0188 
0189 static RtemsTaskReqWakeAfter_Context
0190   RtemsTaskReqWakeAfter_Instance;
0191 
0192 static const char * const RtemsTaskReqWakeAfter_PreDesc_Ticks[] = {
0193   "Yield",
0194   "Interval",
0195   "NA"
0196 };
0197 
0198 static const char * const RtemsTaskReqWakeAfter_PreDesc_Suspended[] = {
0199   "Yes",
0200   "No",
0201   "NA"
0202 };
0203 
0204 static const char * const * const RtemsTaskReqWakeAfter_PreDesc[] = {
0205   RtemsTaskReqWakeAfter_PreDesc_Ticks,
0206   RtemsTaskReqWakeAfter_PreDesc_Suspended,
0207   NULL
0208 };
0209 
0210 typedef RtemsTaskReqWakeAfter_Context Context;
0211 
0212 static void Worker( rtems_task_argument arg )
0213 {
0214   Context *ctx;
0215 
0216   ctx = (Context *) arg;
0217 
0218   while ( true ) {
0219     T_scheduler_log *log;
0220 
0221     SuspendSelf();
0222 
0223     ctx->now = rtems_clock_get_ticks_since_boot();
0224 
0225     if ( ctx->suspended ) {
0226       Per_CPU_Control *cpu_self;
0227 
0228       /*
0229        * The rtems_task_wake_after() disables thread dispatching to carry out
0230        * its operations. While thread dispatching is disabled, when an
0231        * interrupt suspends the calling task, the suspended task executes
0232        * until it enables thread dispatching.  We simulate this situation
0233        * with the code below.  Where the system was built with SMP support
0234        * enabled, other processors may suspend an executing task in parallel.
0235        * This case is also simulated by the code below.
0236        */
0237       cpu_self = _Thread_Dispatch_disable();
0238       SuspendSelf();
0239       cpu_self->dispatch_necessary = false;
0240       _Thread_Dispatch_enable( cpu_self );
0241     }
0242 
0243     log = T_scheduler_record_4( &ctx->scheduler_log );
0244     T_null( log );
0245 
0246     ctx->status = rtems_task_wake_after( ctx->ticks );
0247 
0248     (void) T_scheduler_record( NULL );
0249   }
0250 }
0251 
0252 static void RtemsTaskReqWakeAfter_Pre_Ticks_Prepare(
0253   RtemsTaskReqWakeAfter_Context  *ctx,
0254   RtemsTaskReqWakeAfter_Pre_Ticks state
0255 )
0256 {
0257   switch ( state ) {
0258     case RtemsTaskReqWakeAfter_Pre_Ticks_Yield: {
0259       /*
0260        * While the ``ticks`` parameter is equal to RTEMS_YIELD_PROCESSOR.
0261        */
0262       ctx->ticks = RTEMS_YIELD_PROCESSOR;
0263       break;
0264     }
0265 
0266     case RtemsTaskReqWakeAfter_Pre_Ticks_Interval: {
0267       /*
0268        * While the ``ticks`` parameter is not equal to RTEMS_YIELD_PROCESSOR.
0269        */
0270       ctx->ticks = UINT32_MAX;
0271       break;
0272     }
0273 
0274     case RtemsTaskReqWakeAfter_Pre_Ticks_NA:
0275       break;
0276   }
0277 }
0278 
0279 static void RtemsTaskReqWakeAfter_Pre_Suspended_Prepare(
0280   RtemsTaskReqWakeAfter_Context      *ctx,
0281   RtemsTaskReqWakeAfter_Pre_Suspended state
0282 )
0283 {
0284   switch ( state ) {
0285     case RtemsTaskReqWakeAfter_Pre_Suspended_Yes: {
0286       /*
0287        * While the calling task is suspended.
0288        */
0289       ctx->suspended = true;
0290       break;
0291     }
0292 
0293     case RtemsTaskReqWakeAfter_Pre_Suspended_No: {
0294       /*
0295        * While the calling task is not suspended.
0296        */
0297       ctx->suspended = false;
0298       break;
0299     }
0300 
0301     case RtemsTaskReqWakeAfter_Pre_Suspended_NA:
0302       break;
0303   }
0304 }
0305 
0306 static void RtemsTaskReqWakeAfter_Post_Status_Check(
0307   RtemsTaskReqWakeAfter_Context    *ctx,
0308   RtemsTaskReqWakeAfter_Post_Status state
0309 )
0310 {
0311   switch ( state ) {
0312     case RtemsTaskReqWakeAfter_Post_Status_Ok: {
0313       /*
0314        * The return status of rtems_task_wake_after() shall be
0315        * RTEMS_SUCCESSFUL.
0316        */
0317       T_rsc_success( ctx->status );
0318       break;
0319     }
0320 
0321     case RtemsTaskReqWakeAfter_Post_Status_NA:
0322       break;
0323   }
0324 }
0325 
0326 static void RtemsTaskReqWakeAfter_Post_Timer_Check(
0327   RtemsTaskReqWakeAfter_Context   *ctx,
0328   RtemsTaskReqWakeAfter_Post_Timer state
0329 )
0330 {
0331   switch ( state ) {
0332     case RtemsTaskReqWakeAfter_Post_Timer_Inactive: {
0333       /*
0334        * The timer of the calling task shall be inactive.
0335        */
0336       T_eq_int( ctx->timer_info.state, TASK_TIMER_INACTIVE );
0337       break;
0338     }
0339 
0340     case RtemsTaskReqWakeAfter_Post_Timer_Ticks: {
0341       /*
0342        * The timer of the calling task shall be active using the clock tick.
0343        */
0344       T_eq_int( ctx->timer_info.state, TASK_TIMER_TICKS );
0345       break;
0346     }
0347 
0348     case RtemsTaskReqWakeAfter_Post_Timer_NA:
0349       break;
0350   }
0351 }
0352 
0353 static void RtemsTaskReqWakeAfter_Post_Expire_Check(
0354   RtemsTaskReqWakeAfter_Context    *ctx,
0355   RtemsTaskReqWakeAfter_Post_Expire state
0356 )
0357 {
0358   switch ( state ) {
0359     case RtemsTaskReqWakeAfter_Post_Expire_Relative: {
0360       /*
0361        * The timer of the calling task shall expire at the time point specified
0362        * by the sum of the current clock tick and the interval specified by the
0363        * ``ticks`` parameter.
0364        */
0365       T_eq_u64( ctx->timer_info.expire_ticks, ctx->now + UINT32_MAX );
0366       break;
0367     }
0368 
0369     case RtemsTaskReqWakeAfter_Post_Expire_NA:
0370       break;
0371   }
0372 }
0373 
0374 static void RtemsTaskReqWakeAfter_Post_Scheduler_Check(
0375   RtemsTaskReqWakeAfter_Context       *ctx,
0376   RtemsTaskReqWakeAfter_Post_Scheduler state
0377 )
0378 {
0379   switch ( state ) {
0380     case RtemsTaskReqWakeAfter_Post_Scheduler_Block: {
0381       /*
0382        * The calling task shall be blocked by the scheduler exactly once by the
0383        * rtems_task_wake_after() call.
0384        */
0385       T_eq_sz( ctx->scheduler_log.header.recorded, 1 );
0386       T_eq_int(
0387         ctx->scheduler_log.events[ 0 ].operation,
0388         T_SCHEDULER_BLOCK
0389       );
0390       break;
0391     }
0392 
0393     case RtemsTaskReqWakeAfter_Post_Scheduler_Yield: {
0394       /*
0395        * The calling task shall yield by the scheduler exactly once by the
0396        * rtems_task_wake_after() call.
0397        */
0398       T_eq_sz( ctx->scheduler_log.header.recorded, 1 );
0399       T_eq_int(
0400         ctx->scheduler_log.events[ 0 ].operation,
0401         T_SCHEDULER_YIELD
0402       );
0403       break;
0404     }
0405 
0406     case RtemsTaskReqWakeAfter_Post_Scheduler_Nop: {
0407       /*
0408        * The calling task shall not carry out a scheduler operation through the
0409        * rtems_task_wake_after() call.
0410        */
0411       T_eq_sz( ctx->scheduler_log.header.recorded, 0 );
0412       break;
0413     }
0414 
0415     case RtemsTaskReqWakeAfter_Post_Scheduler_NA:
0416       break;
0417   }
0418 }
0419 
0420 static void RtemsTaskReqWakeAfter_Setup( RtemsTaskReqWakeAfter_Context *ctx )
0421 {
0422   SetSelfPriority( PRIO_NORMAL );
0423   ctx->worker_id = CreateTask( "WORK", PRIO_HIGH );
0424   StartTask( ctx->worker_id, Worker, ctx );
0425 }
0426 
0427 static void RtemsTaskReqWakeAfter_Setup_Wrap( void *arg )
0428 {
0429   RtemsTaskReqWakeAfter_Context *ctx;
0430 
0431   ctx = arg;
0432   ctx->Map.in_action_loop = false;
0433   RtemsTaskReqWakeAfter_Setup( ctx );
0434 }
0435 
0436 static void RtemsTaskReqWakeAfter_Teardown(
0437   RtemsTaskReqWakeAfter_Context *ctx
0438 )
0439 {
0440   DeleteTask( ctx->worker_id );
0441   RestoreRunnerPriority();
0442 }
0443 
0444 static void RtemsTaskReqWakeAfter_Teardown_Wrap( void *arg )
0445 {
0446   RtemsTaskReqWakeAfter_Context *ctx;
0447 
0448   ctx = arg;
0449   ctx->Map.in_action_loop = false;
0450   RtemsTaskReqWakeAfter_Teardown( ctx );
0451 }
0452 
0453 static void RtemsTaskReqWakeAfter_Prepare( RtemsTaskReqWakeAfter_Context *ctx )
0454 {
0455   ctx->status = RTEMS_NOT_IMPLEMENTED;
0456 }
0457 
0458 static void RtemsTaskReqWakeAfter_Action( RtemsTaskReqWakeAfter_Context *ctx )
0459 {
0460   ResumeTask( ctx->worker_id );
0461   (void) T_scheduler_record( NULL );
0462   GetTaskTimerInfo( ctx->worker_id, &ctx->timer_info );
0463 
0464   if ( ctx->suspended ) {
0465     ResumeTask( ctx->worker_id );
0466   }
0467 
0468   FinalClockTick();
0469 }
0470 
0471 static const RtemsTaskReqWakeAfter_Entry
0472 RtemsTaskReqWakeAfter_Entries[] = {
0473   { 0, 0, 0, RtemsTaskReqWakeAfter_Post_Status_Ok,
0474     RtemsTaskReqWakeAfter_Post_Timer_Inactive,
0475     RtemsTaskReqWakeAfter_Post_Expire_NA,
0476     RtemsTaskReqWakeAfter_Post_Scheduler_Nop },
0477   { 0, 0, 0, RtemsTaskReqWakeAfter_Post_Status_Ok,
0478     RtemsTaskReqWakeAfter_Post_Timer_Inactive,
0479     RtemsTaskReqWakeAfter_Post_Expire_NA,
0480     RtemsTaskReqWakeAfter_Post_Scheduler_Yield },
0481   { 0, 0, 0, RtemsTaskReqWakeAfter_Post_Status_Ok,
0482     RtemsTaskReqWakeAfter_Post_Timer_Ticks,
0483     RtemsTaskReqWakeAfter_Post_Expire_Relative,
0484     RtemsTaskReqWakeAfter_Post_Scheduler_Nop },
0485   { 0, 0, 0, RtemsTaskReqWakeAfter_Post_Status_Ok,
0486     RtemsTaskReqWakeAfter_Post_Timer_Ticks,
0487     RtemsTaskReqWakeAfter_Post_Expire_Relative,
0488     RtemsTaskReqWakeAfter_Post_Scheduler_Block }
0489 };
0490 
0491 static const uint8_t
0492 RtemsTaskReqWakeAfter_Map[] = {
0493   0, 1, 2, 3
0494 };
0495 
0496 static size_t RtemsTaskReqWakeAfter_Scope( void *arg, char *buf, size_t n )
0497 {
0498   RtemsTaskReqWakeAfter_Context *ctx;
0499 
0500   ctx = arg;
0501 
0502   if ( ctx->Map.in_action_loop ) {
0503     return T_get_scope( RtemsTaskReqWakeAfter_PreDesc, buf, n, ctx->Map.pcs );
0504   }
0505 
0506   return 0;
0507 }
0508 
0509 static T_fixture RtemsTaskReqWakeAfter_Fixture = {
0510   .setup = RtemsTaskReqWakeAfter_Setup_Wrap,
0511   .stop = NULL,
0512   .teardown = RtemsTaskReqWakeAfter_Teardown_Wrap,
0513   .scope = RtemsTaskReqWakeAfter_Scope,
0514   .initial_context = &RtemsTaskReqWakeAfter_Instance
0515 };
0516 
0517 static inline RtemsTaskReqWakeAfter_Entry RtemsTaskReqWakeAfter_PopEntry(
0518   RtemsTaskReqWakeAfter_Context *ctx
0519 )
0520 {
0521   size_t index;
0522 
0523   index = ctx->Map.index;
0524   ctx->Map.index = index + 1;
0525   return RtemsTaskReqWakeAfter_Entries[
0526     RtemsTaskReqWakeAfter_Map[ index ]
0527   ];
0528 }
0529 
0530 static void RtemsTaskReqWakeAfter_TestVariant(
0531   RtemsTaskReqWakeAfter_Context *ctx
0532 )
0533 {
0534   RtemsTaskReqWakeAfter_Pre_Ticks_Prepare( ctx, ctx->Map.pcs[ 0 ] );
0535   RtemsTaskReqWakeAfter_Pre_Suspended_Prepare( ctx, ctx->Map.pcs[ 1 ] );
0536   RtemsTaskReqWakeAfter_Action( ctx );
0537   RtemsTaskReqWakeAfter_Post_Status_Check( ctx, ctx->Map.entry.Post_Status );
0538   RtemsTaskReqWakeAfter_Post_Timer_Check( ctx, ctx->Map.entry.Post_Timer );
0539   RtemsTaskReqWakeAfter_Post_Expire_Check( ctx, ctx->Map.entry.Post_Expire );
0540   RtemsTaskReqWakeAfter_Post_Scheduler_Check(
0541     ctx,
0542     ctx->Map.entry.Post_Scheduler
0543   );
0544 }
0545 
0546 /**
0547  * @fn void T_case_body_RtemsTaskReqWakeAfter( void )
0548  */
0549 T_TEST_CASE_FIXTURE( RtemsTaskReqWakeAfter, &RtemsTaskReqWakeAfter_Fixture )
0550 {
0551   RtemsTaskReqWakeAfter_Context *ctx;
0552 
0553   ctx = T_fixture_context();
0554   ctx->Map.in_action_loop = true;
0555   ctx->Map.index = 0;
0556 
0557   for (
0558     ctx->Map.pcs[ 0 ] = RtemsTaskReqWakeAfter_Pre_Ticks_Yield;
0559     ctx->Map.pcs[ 0 ] < RtemsTaskReqWakeAfter_Pre_Ticks_NA;
0560     ++ctx->Map.pcs[ 0 ]
0561   ) {
0562     for (
0563       ctx->Map.pcs[ 1 ] = RtemsTaskReqWakeAfter_Pre_Suspended_Yes;
0564       ctx->Map.pcs[ 1 ] < RtemsTaskReqWakeAfter_Pre_Suspended_NA;
0565       ++ctx->Map.pcs[ 1 ]
0566     ) {
0567       ctx->Map.entry = RtemsTaskReqWakeAfter_PopEntry( ctx );
0568       RtemsTaskReqWakeAfter_Prepare( ctx );
0569       RtemsTaskReqWakeAfter_TestVariant( ctx );
0570     }
0571   }
0572 }
0573 
0574 /** @} */