Back to home page

LXR

 
 

    


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

0001 /*
0002  * Copyright (C) 2016, 2017 embedded brains GmbH & Co. KG
0003  *
0004  * The license and distribution terms for this file may be
0005  * found in the file LICENSE in this distribution or at
0006  * http://www.rtems.com/license/LICENSE.
0007  */
0008 
0009 #ifdef HAVE_CONFIG_H
0010 #include "config.h"
0011 #endif
0012 
0013 #include "tmacros.h"
0014 
0015 #include <assert.h>
0016 #include <limits.h>
0017 #include <stdlib.h>
0018 
0019 #include <bsp.h>
0020 
0021 #include <rtems/score/apimutex.h>
0022 #include <rtems/score/sysstate.h>
0023 #include <rtems/score/threaddispatch.h>
0024 
0025 const char rtems_test_name[] = "SPEXTENSIONS 1";
0026 
0027 static int counter;
0028 
0029 static int active_extensions = 2;
0030 
0031 static rtems_id master_task;
0032 
0033 static bool before_initialization(void)
0034 {
0035   return _System_state_Is_before_initialization(_System_state_Get());
0036 }
0037 
0038 static bool before_multitasking(void)
0039 {
0040   return _System_state_Is_before_multitasking(_System_state_Get());
0041 }
0042 
0043 static bool life_protected(void)
0044 {
0045   Thread_Control *executing;
0046 
0047   executing = _Thread_Get_executing();
0048 
0049   return executing == NULL
0050     || (executing->Life.state & THREAD_LIFE_PROTECTED) != 0;
0051 }
0052 
0053 static void assert_normal_thread_context(void)
0054 {
0055   assert(_Thread_Dispatch_is_enabled());
0056   assert(!_RTEMS_Allocator_is_owner());
0057   assert(!life_protected());
0058 }
0059 
0060 static void assert_life_protected_thread_context(void)
0061 {
0062   assert(_Thread_Dispatch_is_enabled() || before_multitasking());
0063   assert(!_RTEMS_Allocator_is_owner());
0064   assert(life_protected() || before_multitasking());
0065 }
0066 
0067 static void assert_allocator_protected_thread_context(void)
0068 {
0069   assert(
0070     _Thread_Dispatch_is_enabled() ||
0071     before_initialization() ||
0072     before_multitasking()
0073   );
0074   assert(_RTEMS_Allocator_is_owner());
0075   assert(life_protected());
0076 }
0077 
0078 static void assert_thread_dispatch_disabled_context(void)
0079 {
0080   assert(!_Thread_Dispatch_is_enabled());
0081   assert(!_RTEMS_Allocator_is_owner());
0082   assert(!life_protected());
0083 }
0084 
0085 static void assert_forward_order(int index)
0086 {
0087   assert((counter % active_extensions) == index);
0088   ++counter;
0089 }
0090 
0091 static void assert_reverse_order(int index)
0092 {
0093   assert((counter % active_extensions) == (active_extensions - 1 - index));
0094   ++counter;
0095 }
0096 
0097 static bool zero_thread_create(rtems_tcb *a, rtems_tcb *b)
0098 {
0099   assert_forward_order(0);
0100   assert_allocator_protected_thread_context();
0101   return true;
0102 }
0103 
0104 static void zero_thread_start(rtems_tcb *a, rtems_tcb *b)
0105 {
0106   assert_forward_order(0);
0107   assert_thread_dispatch_disabled_context();
0108 }
0109 
0110 static void zero_thread_restart(rtems_tcb *a, rtems_tcb *b)
0111 {
0112   assert_forward_order(0);
0113   assert_life_protected_thread_context();
0114 }
0115 
0116 static void zero_thread_delete(rtems_tcb *a, rtems_tcb *b)
0117 {
0118   assert_reverse_order(0);
0119   assert_allocator_protected_thread_context();
0120 }
0121 
0122 static void zero_thread_switch(rtems_tcb *a, rtems_tcb *b)
0123 {
0124   assert_forward_order(0);
0125 }
0126 
0127 static void zero_thread_begin(rtems_tcb *a)
0128 {
0129   assert_forward_order(0);
0130   assert_normal_thread_context();
0131 }
0132 
0133 static void zero_thread_exitted(rtems_tcb *a)
0134 {
0135   assert_forward_order(0);
0136   assert_normal_thread_context();
0137 }
0138 
0139 static void zero_fatal(
0140   rtems_fatal_source source,
0141   bool always_set_to_false,
0142   rtems_fatal_code code
0143 )
0144 {
0145   if (source == RTEMS_FATAL_SOURCE_EXIT) {
0146     assert_forward_order(0);
0147   }
0148 }
0149 
0150 static void zero_thread_terminate(rtems_tcb *a)
0151 {
0152   assert_reverse_order(0);
0153   assert_life_protected_thread_context();
0154 }
0155 
0156 static bool one_thread_create(rtems_tcb *a, rtems_tcb *b)
0157 {
0158   assert_forward_order(1);
0159   assert_allocator_protected_thread_context();
0160   return true;
0161 }
0162 
0163 static void one_thread_start(rtems_tcb *a, rtems_tcb *b)
0164 {
0165   assert_forward_order(1);
0166   assert_thread_dispatch_disabled_context();
0167 }
0168 
0169 static void one_thread_restart(rtems_tcb *a, rtems_tcb *b)
0170 {
0171   assert_forward_order(1);
0172   assert_life_protected_thread_context();
0173 }
0174 
0175 static void one_thread_delete(rtems_tcb *a, rtems_tcb *b)
0176 {
0177   assert_reverse_order(1);
0178   assert_allocator_protected_thread_context();
0179 }
0180 
0181 static void one_thread_switch(rtems_tcb *a, rtems_tcb *b)
0182 {
0183   assert_forward_order(1);
0184 }
0185 
0186 static void one_thread_begin(rtems_tcb *a)
0187 {
0188   assert_forward_order(1);
0189   assert_normal_thread_context();
0190 }
0191 
0192 static void one_thread_exitted(rtems_tcb *a)
0193 {
0194   assert_forward_order(1);
0195   assert_normal_thread_context();
0196 }
0197 
0198 static void one_fatal(
0199   rtems_fatal_source source,
0200   bool always_set_to_false,
0201   rtems_fatal_code code
0202 )
0203 {
0204   if (source == RTEMS_FATAL_SOURCE_EXIT) {
0205     assert_forward_order(1);
0206   }
0207 }
0208 
0209 static void one_thread_terminate(rtems_tcb *a)
0210 {
0211   assert_reverse_order(1);
0212   assert_life_protected_thread_context();
0213 }
0214 
0215 static bool two_thread_create(rtems_tcb *a, rtems_tcb *b)
0216 {
0217   assert_forward_order(2);
0218   assert_allocator_protected_thread_context();
0219   return true;
0220 }
0221 
0222 static void two_thread_start(rtems_tcb *a, rtems_tcb *b)
0223 {
0224   assert_forward_order(2);
0225   assert_thread_dispatch_disabled_context();
0226 }
0227 
0228 static void two_thread_restart(rtems_tcb *a, rtems_tcb *b)
0229 {
0230   assert_forward_order(2);
0231   assert_life_protected_thread_context();
0232 }
0233 
0234 static void two_thread_delete(rtems_tcb *a, rtems_tcb *b)
0235 {
0236   assert_reverse_order(2);
0237   assert_allocator_protected_thread_context();
0238 }
0239 
0240 static void two_thread_switch(rtems_tcb *a, rtems_tcb *b)
0241 {
0242   assert_forward_order(2);
0243 }
0244 
0245 static void two_thread_begin(rtems_tcb *a)
0246 {
0247   assert_forward_order(2);
0248   assert_normal_thread_context();
0249 }
0250 
0251 static void two_thread_exitted(rtems_tcb *a)
0252 {
0253   assert_forward_order(2);
0254   assert_normal_thread_context();
0255 }
0256 
0257 static void two_fatal(
0258   rtems_fatal_source source,
0259   bool always_set_to_false,
0260   rtems_fatal_code code
0261 )
0262 {
0263   if (source == RTEMS_FATAL_SOURCE_EXIT) {
0264     assert_forward_order(2);
0265   }
0266 }
0267 
0268 static void two_thread_terminate(rtems_tcb *a)
0269 {
0270   assert_reverse_order(2);
0271   assert_life_protected_thread_context();
0272 }
0273 
0274 static bool three_thread_create(rtems_tcb *a, rtems_tcb *b)
0275 {
0276   assert_forward_order(3);
0277   assert_allocator_protected_thread_context();
0278   return true;
0279 }
0280 
0281 static void three_thread_start(rtems_tcb *a, rtems_tcb *b)
0282 {
0283   assert_forward_order(3);
0284   assert_thread_dispatch_disabled_context();
0285 }
0286 
0287 static void three_thread_restart(rtems_tcb *a, rtems_tcb *b)
0288 {
0289   assert_forward_order(3);
0290   assert_life_protected_thread_context();
0291 }
0292 
0293 static void three_thread_delete(rtems_tcb *a, rtems_tcb *b)
0294 {
0295   assert_reverse_order(3);
0296   assert_allocator_protected_thread_context();
0297 }
0298 
0299 static void three_thread_switch(rtems_tcb *a, rtems_tcb *b)
0300 {
0301   assert_forward_order(3);
0302 }
0303 
0304 static void three_thread_begin(rtems_tcb *a)
0305 {
0306   assert_forward_order(3);
0307   assert_normal_thread_context();
0308 }
0309 
0310 static void three_thread_exitted(rtems_tcb *a)
0311 {
0312   assert_forward_order(3);
0313   assert_normal_thread_context();
0314 }
0315 
0316 static void three_fatal(
0317   rtems_fatal_source source,
0318   bool always_set_to_false,
0319   rtems_fatal_code code
0320 )
0321 {
0322   if (source == RTEMS_FATAL_SOURCE_EXIT) {
0323     assert_forward_order(3);
0324     assert(counter == 68);
0325     TEST_END();
0326   }
0327 }
0328 
0329 static void three_thread_terminate(rtems_tcb *a)
0330 {
0331   assert_reverse_order(3);
0332   assert_life_protected_thread_context();
0333 }
0334 
0335 #define ZERO \
0336   { \
0337     .thread_create = zero_thread_create, \
0338     .thread_start = zero_thread_start, \
0339     .thread_restart = zero_thread_restart, \
0340     .thread_delete = zero_thread_delete, \
0341     .thread_switch = zero_thread_switch, \
0342     .thread_begin = zero_thread_begin, \
0343     .thread_exitted = zero_thread_exitted, \
0344     .fatal = zero_fatal, \
0345     .thread_terminate = zero_thread_terminate \
0346   }
0347 
0348 #define ONE \
0349   { \
0350     .thread_create = one_thread_create, \
0351     .thread_start = one_thread_start, \
0352     .thread_restart = one_thread_restart, \
0353     .thread_delete = one_thread_delete, \
0354     .thread_switch = one_thread_switch, \
0355     .thread_begin = one_thread_begin, \
0356     .thread_exitted = one_thread_exitted, \
0357     .fatal = one_fatal, \
0358     .thread_terminate = one_thread_terminate \
0359   }
0360 
0361 static const rtems_extensions_table two = {
0362   .thread_create = two_thread_create,
0363   .thread_start = two_thread_start,
0364   .thread_restart = two_thread_restart,
0365   .thread_delete = two_thread_delete,
0366   .thread_switch = two_thread_switch,
0367   .thread_begin = two_thread_begin,
0368   .thread_exitted = two_thread_exitted,
0369   .fatal = two_fatal,
0370   .thread_terminate = two_thread_terminate
0371 };
0372 
0373 static const rtems_extensions_table three = {
0374   .thread_create = three_thread_create,
0375   .thread_start = three_thread_start,
0376   .thread_restart = three_thread_restart,
0377   .thread_delete = three_thread_delete,
0378   .thread_switch = three_thread_switch,
0379   .thread_begin = three_thread_begin,
0380   .thread_exitted = three_thread_exitted,
0381   .fatal = three_fatal,
0382   .thread_terminate = three_thread_terminate
0383 };
0384 
0385 static const rtems_extensions_table initial_test =
0386   RTEMS_TEST_INITIAL_EXTENSION;
0387 
0388 #ifdef BSP_INITIAL_EXTENSION
0389 static const rtems_extensions_table initial_bsp =
0390   BSP_INITIAL_EXTENSION;
0391 #endif
0392 
0393 static void wake_up_master(void)
0394 {
0395   rtems_status_code sc;
0396 
0397   sc = rtems_event_transient_send(master_task);
0398   assert(sc == RTEMS_SUCCESSFUL);
0399 }
0400 
0401 static void wait_for_worker(void)
0402 {
0403   rtems_status_code sc;
0404 
0405   sc = rtems_event_transient_receive(
0406     RTEMS_WAIT,
0407     RTEMS_NO_TIMEOUT
0408   );
0409   assert(sc == RTEMS_SUCCESSFUL);
0410 }
0411 
0412 static void worker(rtems_task_argument arg)
0413 {
0414   wake_up_master();
0415 
0416   (void) rtems_task_suspend(RTEMS_SELF);
0417   assert(false);
0418 }
0419 
0420 static void test(void)
0421 {
0422   rtems_status_code sc;
0423   rtems_id id;
0424 
0425   master_task = rtems_task_self();
0426 
0427   sc = rtems_extension_create(
0428     rtems_build_name('2', ' ', ' ', ' '),
0429     &two,
0430     &id
0431   );
0432   assert(sc == RTEMS_SUCCESSFUL);
0433 
0434   sc = rtems_extension_create(
0435     rtems_build_name('3', ' ', ' ', ' '),
0436     &three,
0437     &id
0438   );
0439   assert(sc == RTEMS_SUCCESSFUL);
0440 
0441   sc = rtems_extension_create(
0442     rtems_build_name('T', 'E', 'S', 'T'),
0443     &initial_test,
0444     &id
0445   );
0446   assert(sc == RTEMS_SUCCESSFUL);
0447 
0448 #ifdef BSP_INITIAL_EXTENSION
0449   sc = rtems_extension_create(
0450     rtems_build_name(' ', 'B', 'S', 'P'),
0451     &initial_bsp,
0452     &id
0453   );
0454   assert(sc == RTEMS_SUCCESSFUL);
0455 #undef BSP_INITIAL_EXTENSION
0456 #endif
0457 
0458   active_extensions = 4;
0459 
0460   /*
0461    * In SMP configurations, the context switch from the system initialization
0462    * context to the initialization task is visible to the context switch
0463    * extensions.
0464    *
0465    * In uniprocessor configurations, this is not the case and two counter
0466    * increments are missing.
0467    */
0468 #ifdef RTEMS_SMP
0469   assert(counter == 12);
0470 #else
0471   assert(counter == 10);
0472   counter = 12;
0473 #endif
0474 
0475   sc = rtems_task_create(
0476     rtems_build_name('W', 'O', 'R', 'K'),
0477     2,
0478     RTEMS_MINIMUM_STACK_SIZE,
0479     RTEMS_DEFAULT_MODES,
0480     RTEMS_DEFAULT_ATTRIBUTES,
0481     &id
0482   );
0483   assert(sc == RTEMS_SUCCESSFUL);
0484 
0485   sc = rtems_task_start(id, worker, 0);
0486   assert(sc == RTEMS_SUCCESSFUL);
0487 
0488   wait_for_worker();
0489 
0490   sc = rtems_task_restart(id, 0);
0491   assert(sc == RTEMS_SUCCESSFUL);
0492 
0493   wait_for_worker();
0494 
0495   sc = rtems_task_delete(id);
0496   assert(sc == RTEMS_SUCCESSFUL);
0497 
0498   /* Process zombies to trigger delete extensions */
0499   sc = rtems_task_create(
0500     rtems_build_name('N', 'U', 'L', 'L'),
0501     2,
0502     SIZE_MAX,
0503     RTEMS_DEFAULT_MODES,
0504     RTEMS_DEFAULT_ATTRIBUTES,
0505     &id
0506   );
0507   assert(sc == RTEMS_UNSATISFIED);
0508 }
0509 
0510 static void Init(rtems_task_argument arg)
0511 {
0512   TEST_BEGIN();
0513 
0514   test();
0515 
0516   exit(0);
0517 }
0518 
0519 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
0520 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0521 
0522 #define CONFIGURE_MAXIMUM_USER_EXTENSIONS 4
0523 
0524 #define CONFIGURE_MAXIMUM_TASKS 2
0525 
0526 #define CONFIGURE_INITIAL_EXTENSIONS ZERO, ONE
0527 
0528 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0529 
0530 #define CONFIGURE_INIT
0531 
0532 #include <rtems/confdefs.h>