Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (c) 2014 embedded brains GmbH & Co. KG
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #ifdef HAVE_CONFIG_H
0029 #include "config.h"
0030 #endif
0031 
0032 #include "tmacros.h"
0033 
0034 #include <rtems.h>
0035 #include <rtems/counter.h>
0036 #include <rtems/libcsupport.h>
0037 #include <rtems/score/profiling.h>
0038 #include <rtems/score/smpbarrier.h>
0039 #include <rtems/score/threadimpl.h>
0040 
0041 const char rtems_test_name[] = "SMPTHREADLIFE 1";
0042 
0043 #define CPU_COUNT 2
0044 
0045 typedef struct {
0046   volatile rtems_task_argument main_arg;
0047   volatile rtems_task_argument worker_arg;
0048   volatile bool terminated;
0049   SMP_barrier_Control barrier;
0050   SMP_barrier_State main_barrier_state;
0051   SMP_barrier_State worker_barrier_state;
0052   Thread_Control *delay_switch_for_executing;
0053   rtems_id worker_id;
0054 } test_context;
0055 
0056 static test_context test_instance = {
0057   .barrier = SMP_BARRIER_CONTROL_INITIALIZER,
0058   .main_barrier_state = SMP_BARRIER_STATE_INITIALIZER,
0059   .worker_barrier_state = SMP_BARRIER_STATE_INITIALIZER
0060 };
0061 
0062 static void barrier(test_context *ctx, SMP_barrier_State *state)
0063 {
0064   _SMP_barrier_Wait(&ctx->barrier, state, CPU_COUNT);
0065 }
0066 
0067 static void restart_extension(
0068   Thread_Control *executing,
0069   Thread_Control *restarted
0070 )
0071 {
0072   rtems_test_assert(executing == restarted);
0073 }
0074 
0075 static void delete_extension(
0076   Thread_Control *executing,
0077   Thread_Control *deleted
0078 )
0079 {
0080   rtems_test_assert(executing != deleted);
0081 }
0082 
0083 static void terminate_extension(Thread_Control *executing)
0084 {
0085   test_context *ctx = &test_instance;
0086 
0087   ctx->terminated = true;
0088 }
0089 
0090 static void switch_extension(Thread_Control *executing, Thread_Control *heir)
0091 {
0092   test_context *ctx = &test_instance;
0093 
0094   if (ctx->delay_switch_for_executing == executing) {
0095     ctx->delay_switch_for_executing = NULL;
0096 
0097     /* (A) */
0098     barrier(ctx, &ctx->worker_barrier_state);
0099 
0100     rtems_counter_delay_nanoseconds(100000000);
0101 
0102     /* Avoid bad profiling statisitics */
0103     _Profiling_Thread_dispatch_disable( _Per_CPU_Get(), 0 );
0104   }
0105 }
0106 
0107 static void worker_task(rtems_task_argument arg)
0108 {
0109   test_context *ctx = &test_instance;
0110 
0111   rtems_test_assert(arg == ctx->main_arg);
0112 
0113   ctx->worker_arg = arg;
0114 
0115   /* (B) */
0116   barrier(ctx, &ctx->worker_barrier_state);
0117 
0118   while (true) {
0119     /* Do nothing */
0120   }
0121 }
0122 
0123 static void test_restart(void)
0124 {
0125   test_context *ctx = &test_instance;
0126   rtems_status_code sc;
0127   rtems_id id;
0128   rtems_task_argument arg;
0129   rtems_resource_snapshot snapshot;
0130 
0131   rtems_resource_snapshot_take(&snapshot);
0132 
0133   sc = rtems_task_create(
0134     rtems_build_name('W', 'O', 'R', 'K'),
0135     1,
0136     RTEMS_MINIMUM_STACK_SIZE,
0137     RTEMS_DEFAULT_MODES,
0138     RTEMS_DEFAULT_ATTRIBUTES,
0139     &id
0140   );
0141   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0142 
0143   sc = rtems_task_start(id, worker_task, 0);
0144   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0145 
0146   /* (B) */
0147   barrier(ctx, &ctx->main_barrier_state);
0148 
0149   for (arg = 1; arg < 23; ++arg) {
0150     ctx->main_arg = arg;
0151     ctx->worker_arg = 0;
0152 
0153     sc = rtems_task_restart(id, arg);
0154     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0155 
0156     /* (B) */
0157     barrier(ctx, &ctx->main_barrier_state);
0158 
0159     rtems_test_assert(ctx->worker_arg == arg);
0160   }
0161 
0162   sc = rtems_task_delete(id);
0163   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0164 
0165   rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
0166 }
0167 
0168 static void test_delete(void)
0169 {
0170   test_context *ctx = &test_instance;
0171   rtems_status_code sc;
0172   rtems_id id;
0173   rtems_task_argument arg;
0174   rtems_resource_snapshot snapshot;
0175 
0176   rtems_resource_snapshot_take(&snapshot);
0177 
0178   for (arg = 31; arg < 57; ++arg) {
0179     ctx->main_arg = arg;
0180     ctx->worker_arg = 0;
0181     ctx->terminated = false;
0182 
0183     sc = rtems_task_create(
0184       rtems_build_name('W', 'O', 'R', 'K'),
0185       1,
0186       RTEMS_MINIMUM_STACK_SIZE,
0187       RTEMS_DEFAULT_MODES,
0188       RTEMS_DEFAULT_ATTRIBUTES,
0189       &id
0190     );
0191     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0192 
0193     sc = rtems_task_start(id, worker_task, arg);
0194     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0195 
0196     /* (B) */
0197     barrier(ctx, &ctx->main_barrier_state);
0198 
0199     rtems_test_assert(ctx->worker_arg == arg);
0200     rtems_test_assert(!ctx->terminated);
0201 
0202     sc = rtems_task_delete(id);
0203     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0204 
0205     rtems_test_assert(ctx->terminated);
0206 
0207     rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
0208   }
0209 }
0210 
0211 static void delay_ipi_task(rtems_task_argument variant)
0212 {
0213   test_context *ctx = &test_instance;
0214   ISR_Level level;
0215 
0216   _ISR_Local_disable(level);
0217 
0218   /* (C) */
0219   barrier(ctx, &ctx->worker_barrier_state);
0220 
0221   /*
0222    * Interrupts are disabled, so the inter-processor interrupt deleting us will
0223    * be delayed a bit.
0224    */
0225   rtems_counter_delay_nanoseconds(100000000);
0226 
0227   if (variant != 0) {
0228     _Thread_Dispatch_disable();
0229   }
0230 
0231   _ISR_Local_enable(level);
0232 
0233   /*
0234    * We get deleted as a side effect of enabling the thread life protection or
0235    * later if we enable the thread dispatching.
0236    */
0237   _Thread_Set_life_protection( THREAD_LIFE_PROTECTED );
0238 
0239   if (variant != 0) {
0240     _Thread_Dispatch_enable( _Per_CPU_Get() );
0241   }
0242 
0243   rtems_test_assert(0);
0244 }
0245 
0246 static void test_set_life_protection(rtems_task_argument variant)
0247 {
0248   test_context *ctx = &test_instance;
0249   rtems_status_code sc;
0250   rtems_id id;
0251   rtems_resource_snapshot snapshot;
0252 
0253   rtems_resource_snapshot_take(&snapshot);
0254 
0255   sc = rtems_task_create(
0256     rtems_build_name('D', 'E', 'L', 'Y'),
0257     1,
0258     RTEMS_MINIMUM_STACK_SIZE,
0259     RTEMS_DEFAULT_MODES,
0260     RTEMS_DEFAULT_ATTRIBUTES,
0261     &id
0262   );
0263   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0264 
0265   sc = rtems_task_start(id, delay_ipi_task, variant);
0266   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0267 
0268   /* (C) */
0269   barrier(ctx, &ctx->main_barrier_state);
0270 
0271   sc = rtems_task_delete(id);
0272   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0273 
0274   rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
0275 }
0276 
0277 static void delay_switch_task(rtems_task_argument arg)
0278 {
0279   test_context *ctx = &test_instance;
0280 
0281   ctx->delay_switch_for_executing = _Thread_Get_executing();
0282 
0283   /* (D) */
0284   barrier(ctx, &ctx->worker_barrier_state);
0285 
0286   rtems_task_exit();
0287 }
0288 
0289 static void test_wait_for_execution_stop(void)
0290 {
0291   test_context *ctx = &test_instance;
0292   rtems_status_code sc;
0293   rtems_id id;
0294   rtems_resource_snapshot snapshot;
0295 
0296   rtems_resource_snapshot_take(&snapshot);
0297 
0298   sc = rtems_task_create(
0299     rtems_build_name('S', 'W', 'I', 'T'),
0300     1,
0301     RTEMS_MINIMUM_STACK_SIZE,
0302     RTEMS_DEFAULT_MODES,
0303     RTEMS_DEFAULT_ATTRIBUTES,
0304     &id
0305   );
0306   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0307 
0308   sc = rtems_task_start(id, delay_switch_task, 0);
0309   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0310 
0311   /* (D) */
0312   barrier(ctx, &ctx->main_barrier_state);
0313 
0314   /* (A) */
0315   barrier(ctx, &ctx->main_barrier_state);
0316 
0317   sc = rtems_task_create(
0318     rtems_build_name('W', 'A', 'I', 'T'),
0319     1,
0320     RTEMS_MINIMUM_STACK_SIZE,
0321     RTEMS_DEFAULT_MODES,
0322     RTEMS_DEFAULT_ATTRIBUTES,
0323     &id
0324   );
0325   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0326 
0327   sc = rtems_task_delete(id);
0328   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0329 
0330   rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
0331 }
0332 
0333 typedef enum {
0334   TEST_OP_SUSPEND,
0335   TEST_OP_EVENT,
0336   TEST_OP_EVENT_SYSTEM
0337 } test_op;
0338 
0339 static void op_begin_suspend(void)
0340 {
0341   rtems_status_code sc;
0342 
0343   sc = rtems_task_suspend(RTEMS_SELF);
0344   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0345 }
0346 
0347 static void op_begin_event(void)
0348 {
0349   rtems_status_code sc;
0350   rtems_event_set events;
0351 
0352   events = 0;
0353   sc = rtems_event_receive(
0354     RTEMS_EVENT_0,
0355     RTEMS_EVENT_ALL | RTEMS_WAIT,
0356     RTEMS_NO_TIMEOUT,
0357     &events
0358   );
0359   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0360   rtems_test_assert(events == RTEMS_EVENT_0);
0361 }
0362 
0363 static void op_begin_event_system(void)
0364 {
0365   rtems_status_code sc;
0366   rtems_event_set events;
0367 
0368   events = 0;
0369   sc = rtems_event_system_receive(
0370     RTEMS_EVENT_0,
0371     RTEMS_EVENT_ALL | RTEMS_WAIT,
0372     RTEMS_NO_TIMEOUT,
0373     &events
0374   );
0375   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0376   rtems_test_assert(events == RTEMS_EVENT_0);
0377 }
0378 
0379 static void (*const test_ops_begin[])(void) = {
0380   op_begin_suspend,
0381   op_begin_event,
0382   op_begin_event_system
0383 };
0384 
0385 static void op_end_suspend(test_context *ctx)
0386 {
0387   rtems_status_code sc;
0388 
0389   sc = rtems_task_resume(ctx->worker_id);
0390   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0391 }
0392 
0393 static void op_end_event(test_context *ctx)
0394 {
0395   rtems_status_code sc;
0396 
0397   sc = rtems_event_send(ctx->worker_id, RTEMS_EVENT_0);
0398   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0399 }
0400 
0401 static void op_end_event_system(test_context *ctx)
0402 {
0403   rtems_status_code sc;
0404 
0405   sc = rtems_event_system_send(ctx->worker_id, RTEMS_EVENT_0);
0406   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0407 }
0408 
0409 static void (*const test_ops_end[])(test_context *) = {
0410   op_end_suspend,
0411   op_end_event,
0412   op_end_event_system
0413 };
0414 
0415 static void op_worker_task(rtems_task_argument arg)
0416 {
0417   test_context *ctx = &test_instance;
0418   test_op op = arg;
0419   Thread_Life_state previous_life_state;
0420 
0421   previous_life_state = _Thread_Set_life_protection(THREAD_LIFE_PROTECTED);
0422 
0423   /* (E) */
0424   barrier(ctx, &ctx->worker_barrier_state);
0425 
0426   /* (F) */
0427   barrier(ctx, &ctx->worker_barrier_state);
0428 
0429   (*test_ops_begin[op])();
0430 
0431   _Thread_Set_life_protection(previous_life_state);
0432   rtems_test_assert(0);
0433 }
0434 
0435 static void help_task(rtems_task_argument arg)
0436 {
0437   test_context *ctx = &test_instance;
0438   test_op op = arg;
0439 
0440   /* (F) */
0441   barrier(ctx, &ctx->main_barrier_state);
0442 
0443   rtems_counter_delay_nanoseconds(100000000);
0444 
0445   (*test_ops_end[op])(ctx);
0446 
0447   rtems_task_suspend(RTEMS_SELF);
0448   rtems_test_assert(0);
0449 }
0450 
0451 static void test_operation_with_delete_in_progress(test_op op)
0452 {
0453   test_context *ctx = &test_instance;
0454   rtems_status_code sc;
0455   rtems_id help_id;
0456   rtems_resource_snapshot snapshot;
0457 
0458   rtems_resource_snapshot_take(&snapshot);
0459 
0460   sc = rtems_task_create(
0461     rtems_build_name('W', 'O', 'R', 'K'),
0462     1,
0463     RTEMS_MINIMUM_STACK_SIZE,
0464     RTEMS_DEFAULT_MODES,
0465     RTEMS_DEFAULT_ATTRIBUTES,
0466     &ctx->worker_id
0467   );
0468   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0469 
0470   sc = rtems_task_start(ctx->worker_id, op_worker_task, op);
0471   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0472 
0473   /* (E) */
0474   barrier(ctx, &ctx->main_barrier_state);
0475 
0476   sc = rtems_task_create(
0477     rtems_build_name('H', 'E', 'L', 'P'),
0478     2,
0479     RTEMS_MINIMUM_STACK_SIZE,
0480     RTEMS_DEFAULT_MODES,
0481     RTEMS_DEFAULT_ATTRIBUTES,
0482     &help_id
0483   );
0484   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0485 
0486   sc = rtems_task_start(help_id, help_task, op);
0487   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0488 
0489   sc = rtems_task_delete(ctx->worker_id);
0490   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0491 
0492   sc = rtems_task_delete(help_id);
0493   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0494 
0495   rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
0496 }
0497 
0498 static void Init(rtems_task_argument arg)
0499 {
0500   TEST_BEGIN();
0501 
0502   if (rtems_scheduler_get_processor_maximum() >= CPU_COUNT) {
0503     test_restart();
0504     test_delete();
0505     test_set_life_protection(0);
0506     test_set_life_protection(1);
0507     test_wait_for_execution_stop();
0508     test_operation_with_delete_in_progress(TEST_OP_SUSPEND);
0509     test_operation_with_delete_in_progress(TEST_OP_EVENT);
0510     test_operation_with_delete_in_progress(TEST_OP_EVENT_SYSTEM);
0511   }
0512 
0513   TEST_END();
0514   rtems_test_exit(0);
0515 }
0516 
0517 #define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
0518 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0519 
0520 #define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT
0521 
0522 #define CONFIGURE_MAXIMUM_TASKS (CPU_COUNT + 1)
0523 
0524 #define CONFIGURE_INITIAL_EXTENSIONS \
0525   { \
0526     .thread_restart = restart_extension, \
0527     .thread_delete = delete_extension, \
0528     .thread_terminate = terminate_extension, \
0529     .thread_switch = switch_extension \
0530   }, \
0531   RTEMS_TEST_INITIAL_EXTENSION
0532 
0533 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0534 
0535 #define CONFIGURE_INIT
0536 
0537 #include <rtems/confdefs.h>