Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (C) 2013, 2024 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 <rtems/score/smplock.h>
0033 #include <rtems/score/smplockmcs.h>
0034 #include <rtems/score/smplockseq.h>
0035 #include <rtems/test-info.h>
0036 #include <rtems.h>
0037 
0038 #include "tmacros.h"
0039 
0040 const char rtems_test_name[] = "SMPLOCK 1";
0041 
0042 #define TASK_PRIORITY 1
0043 
0044 #define CPU_COUNT 32
0045 
0046 #define TEST_COUNT 13
0047 
0048 typedef struct {
0049   rtems_test_parallel_context base;
0050   const char *test_sep;
0051   const char *counter_sep;
0052   unsigned long counter[TEST_COUNT];
0053   unsigned long local_counter[CPU_COUNT][TEST_COUNT][CPU_COUNT];
0054   SMP_lock_Control lock RTEMS_ALIGNED(CPU_CACHE_LINE_BYTES);
0055   Atomic_Uint flag RTEMS_ALIGNED(CPU_CACHE_LINE_BYTES);
0056   SMP_MCS_lock_Control mcs_lock RTEMS_ALIGNED(CPU_CACHE_LINE_BYTES);
0057 #if defined(RTEMS_PROFILING)
0058   SMP_lock_Stats mcs_stats;
0059 #endif
0060   SMP_sequence_lock_Control seq_lock RTEMS_ALIGNED(CPU_CACHE_LINE_BYTES);
0061   int a RTEMS_ALIGNED(CPU_CACHE_LINE_BYTES);
0062   int b RTEMS_ALIGNED(CPU_CACHE_LINE_BYTES);
0063 } test_context;
0064 
0065 static test_context test_instance = {
0066   .lock = SMP_LOCK_INITIALIZER("global ticket"),
0067 #if defined(RTEMS_PROFILING)
0068   .mcs_stats = SMP_LOCK_STATS_INITIALIZER("global MCS"),
0069 #endif
0070   .flag = ATOMIC_INITIALIZER_UINT(0),
0071   .mcs_lock = SMP_MCS_LOCK_INITIALIZER,
0072   .seq_lock = SMP_SEQUENCE_LOCK_INITIALIZER
0073 };
0074 
0075 static rtems_interval test_duration(void)
0076 {
0077   return rtems_clock_get_ticks_per_second();
0078 }
0079 
0080 static rtems_interval test_init(
0081   rtems_test_parallel_context *base,
0082   void *arg,
0083   size_t active_workers
0084 )
0085 {
0086   return test_duration();
0087 }
0088 
0089 static const rtems_test_parallel_job test_jobs[TEST_COUNT];
0090 
0091 static void test_fini(
0092   test_context *ctx,
0093   const char *lock_type,
0094   bool global_lock,
0095   const char *section_type,
0096   size_t test,
0097   size_t active_workers
0098 )
0099 {
0100   bool cascade = test_jobs[test].cascade;
0101   unsigned long sum = 0;
0102   const char *value_sep;
0103   size_t i;
0104 
0105   if (active_workers == 1 || !cascade) {
0106     printf(
0107       "%s{\n"
0108       "    \"lock-type\": \"%s\",\n"
0109       "    \"lock-object\": \"%s\",\n"
0110       "    \"section-type\": \"%s\",\n"
0111       "    \"results\": [",
0112       ctx->test_sep,
0113       lock_type,
0114       global_lock ? "global" : "local",
0115       section_type
0116     );
0117     ctx->test_sep = ", ";
0118     ctx->counter_sep = "\n      ";
0119   }
0120 
0121   printf(
0122     "%s{\n"
0123     "        \"counter\": [", ctx->counter_sep);
0124   ctx->counter_sep = "\n      }, ";
0125   value_sep = "";
0126 
0127   for (i = 0; i < active_workers; ++i) {
0128     unsigned long local_counter =
0129       ctx->local_counter[active_workers - 1][test][i];
0130 
0131     sum += local_counter;
0132 
0133     printf(
0134       "%s%lu",
0135       value_sep,
0136       local_counter
0137     );
0138     value_sep = ", ";
0139   }
0140 
0141   printf(
0142     "],\n"
0143     "        \"global-counter\": %lu,\n"
0144     "        \"sum-of-local-counter\": %lu",
0145     ctx->counter[test],
0146     sum
0147   );
0148 
0149   if (active_workers == rtems_scheduler_get_processor_maximum() || !cascade) {
0150     printf("\n      }\n    ]\n  }");
0151   }
0152 }
0153 
0154 static void test_0_body(
0155   rtems_test_parallel_context *base,
0156   void *arg,
0157   size_t active_workers,
0158   size_t worker_index
0159 )
0160 {
0161   test_context *ctx = (test_context *) base;
0162   size_t test = 0;
0163   unsigned long counter = 0;
0164   SMP_lock_Context lock_context;
0165 
0166   while (!rtems_test_parallel_stop_job(&ctx->base)) {
0167     _SMP_lock_Acquire(&ctx->lock, &lock_context);
0168     _SMP_lock_Release(&ctx->lock, &lock_context);
0169     ++counter;
0170   }
0171 
0172   ctx->local_counter[active_workers - 1][test][worker_index] = counter;
0173 }
0174 
0175 static void test_0_fini(
0176   rtems_test_parallel_context *base,
0177   void *arg,
0178   size_t active_workers
0179 )
0180 {
0181   test_context *ctx = (test_context *) base;
0182 
0183   test_fini(
0184     ctx,
0185     "Ticket Lock",
0186     true,
0187     "local counter",
0188     0,
0189     active_workers
0190   );
0191 }
0192 
0193 static void test_1_body(
0194   rtems_test_parallel_context *base,
0195   void *arg,
0196   size_t active_workers,
0197   size_t worker_index
0198 )
0199 {
0200   test_context *ctx = (test_context *) base;
0201   size_t test = 1;
0202   unsigned long counter = 0;
0203   SMP_MCS_lock_Context lock_context;
0204 
0205   while (!rtems_test_parallel_stop_job(&ctx->base)) {
0206     _SMP_MCS_lock_Acquire(&ctx->mcs_lock, &lock_context, &ctx->mcs_stats);
0207     _SMP_MCS_lock_Release(&ctx->mcs_lock, &lock_context);
0208     ++counter;
0209   }
0210 
0211   ctx->local_counter[active_workers - 1][test][worker_index] = counter;
0212 }
0213 
0214 static void test_1_fini(
0215   rtems_test_parallel_context *base,
0216   void *arg,
0217   size_t active_workers
0218 )
0219 {
0220   test_context *ctx = (test_context *) base;
0221 
0222   test_fini(
0223     ctx,
0224     "MCS Lock",
0225     true,
0226     "local counter",
0227     1,
0228     active_workers
0229   );
0230 }
0231 
0232 static void test_2_body(
0233   rtems_test_parallel_context *base,
0234   void *arg,
0235   size_t active_workers,
0236   size_t worker_index
0237 )
0238 {
0239   test_context *ctx = (test_context *) base;
0240   size_t test = 2;
0241   unsigned long counter = 0;
0242   SMP_lock_Context lock_context;
0243 
0244   while (!rtems_test_parallel_stop_job(&ctx->base)) {
0245     _SMP_lock_Acquire(&ctx->lock, &lock_context);
0246     ++ctx->counter[test];
0247     _SMP_lock_Release(&ctx->lock, &lock_context);
0248     ++counter;
0249   }
0250 
0251   ctx->local_counter[active_workers - 1][test][worker_index] = counter;
0252 }
0253 
0254 static void test_2_fini(
0255   rtems_test_parallel_context *base,
0256   void *arg,
0257   size_t active_workers
0258 )
0259 {
0260   test_context *ctx = (test_context *) base;
0261 
0262   test_fini(
0263     ctx,
0264     "Ticket Lock",
0265     true,
0266     "global counter",
0267     2,
0268     active_workers
0269   );
0270 }
0271 
0272 static void test_3_body(
0273   rtems_test_parallel_context *base,
0274   void *arg,
0275   size_t active_workers,
0276   size_t worker_index
0277 )
0278 {
0279   test_context *ctx = (test_context *) base;
0280   size_t test = 3;
0281   unsigned long counter = 0;
0282   SMP_MCS_lock_Context lock_context;
0283 
0284   while (!rtems_test_parallel_stop_job(&ctx->base)) {
0285     _SMP_MCS_lock_Acquire(&ctx->mcs_lock, &lock_context, &ctx->mcs_stats);
0286     ++ctx->counter[test];
0287     _SMP_MCS_lock_Release(&ctx->mcs_lock, &lock_context);
0288     ++counter;
0289   }
0290 
0291   ctx->local_counter[active_workers - 1][test][worker_index] = counter;
0292 }
0293 
0294 static void test_3_fini(
0295   rtems_test_parallel_context *base,
0296   void *arg,
0297   size_t active_workers
0298 )
0299 {
0300   test_context *ctx = (test_context *) base;
0301 
0302   test_fini(
0303     ctx,
0304     "MCS Lock",
0305     true,
0306     "global counter",
0307     3,
0308     active_workers
0309   );
0310 }
0311 
0312 static void test_4_body(
0313   rtems_test_parallel_context *base,
0314   void *arg,
0315   size_t active_workers,
0316   size_t worker_index
0317 )
0318 {
0319   test_context *ctx = (test_context *) base;
0320   size_t test = 4;
0321   unsigned long counter = 0;
0322   SMP_lock_Control lock;
0323   SMP_lock_Context lock_context;
0324 
0325   _SMP_lock_Initialize(&lock, "local");
0326 
0327   while (!rtems_test_parallel_stop_job(&ctx->base)) {
0328     _SMP_lock_Acquire(&lock, &lock_context);
0329     _SMP_lock_Release(&lock, &lock_context);
0330     ++counter;
0331   }
0332 
0333   _SMP_lock_Destroy(&lock);
0334 
0335   ctx->local_counter[active_workers - 1][test][worker_index] = counter;
0336 }
0337 
0338 static void test_4_fini(
0339   rtems_test_parallel_context *base,
0340   void *arg,
0341   size_t active_workers
0342 )
0343 {
0344   test_context *ctx = (test_context *) base;
0345 
0346   test_fini(
0347     ctx,
0348     "Ticket Lock",
0349     false,
0350     "local counter",
0351     4,
0352     active_workers
0353   );
0354 }
0355 
0356 static void test_5_body(
0357   rtems_test_parallel_context *base,
0358   void *arg,
0359   size_t active_workers,
0360   size_t worker_index
0361 )
0362 {
0363   test_context *ctx = (test_context *) base;
0364   size_t test = 5;
0365   unsigned long counter = 0;
0366 #if defined(RTEMS_PROFILING)
0367   SMP_lock_Stats stats;
0368 #endif
0369   SMP_MCS_lock_Control lock;
0370   SMP_MCS_lock_Context lock_context;
0371 
0372   _SMP_lock_Stats_initialize(&stats, "local");
0373   _SMP_MCS_lock_Initialize(&lock);
0374 
0375   while (!rtems_test_parallel_stop_job(&ctx->base)) {
0376     _SMP_MCS_lock_Acquire(&lock, &lock_context, &stats);
0377     _SMP_MCS_lock_Release(&lock, &lock_context);
0378     ++counter;
0379   }
0380 
0381   _SMP_MCS_lock_Destroy(&lock);
0382   _SMP_lock_Stats_destroy(&stats);
0383 
0384   ctx->local_counter[active_workers - 1][test][worker_index] = counter;
0385 }
0386 
0387 static void test_5_fini(
0388   rtems_test_parallel_context *base,
0389   void *arg,
0390   size_t active_workers
0391 )
0392 {
0393   test_context *ctx = (test_context *) base;
0394 
0395   test_fini(
0396     ctx,
0397     "MCS Lock",
0398     false,
0399     "local counter",
0400     5,
0401     active_workers
0402   );
0403 }
0404 
0405 static void test_6_body(
0406   rtems_test_parallel_context *base,
0407   void *arg,
0408   size_t active_workers,
0409   size_t worker_index
0410 )
0411 {
0412   test_context *ctx = (test_context *) base;
0413   size_t test = 6;
0414   unsigned long counter = 0;
0415   SMP_lock_Control lock;
0416   SMP_lock_Context lock_context;
0417 
0418   _SMP_lock_Initialize(&lock, "local");
0419 
0420   while (!rtems_test_parallel_stop_job(&ctx->base)) {
0421     _SMP_lock_Acquire(&lock, &lock_context);
0422 
0423     /* The counter value is not interesting, only the access to it */
0424     ++ctx->counter[test];
0425 
0426     _SMP_lock_Release(&lock, &lock_context);
0427     ++counter;
0428   }
0429 
0430   _SMP_lock_Destroy(&lock);
0431 
0432   ctx->local_counter[active_workers - 1][test][worker_index] = counter;
0433 }
0434 
0435 static void test_6_fini(
0436   rtems_test_parallel_context *base,
0437   void *arg,
0438   size_t active_workers
0439 )
0440 {
0441   test_context *ctx = (test_context *) base;
0442 
0443   test_fini(
0444     ctx,
0445     "Ticket Lock",
0446     false,
0447     "global counter",
0448     6,
0449     active_workers
0450   );
0451 }
0452 
0453 static void test_7_body(
0454   rtems_test_parallel_context *base,
0455   void *arg,
0456   size_t active_workers,
0457   size_t worker_index
0458 )
0459 {
0460   test_context *ctx = (test_context *) base;
0461   size_t test = 7;
0462   unsigned long counter = 0;
0463 #if defined(RTEMS_PROFILING)
0464   SMP_lock_Stats stats;
0465 #endif
0466   SMP_MCS_lock_Control lock;
0467   SMP_MCS_lock_Context lock_context;
0468 
0469   _SMP_lock_Stats_initialize(&stats, "local");
0470   _SMP_MCS_lock_Initialize(&lock);
0471 
0472   while (!rtems_test_parallel_stop_job(&ctx->base)) {
0473     _SMP_MCS_lock_Acquire(&lock, &lock_context, &stats);
0474 
0475     /* The counter value is not interesting, only the access to it */
0476     ++ctx->counter[test];
0477 
0478     _SMP_MCS_lock_Release(&lock, &lock_context);
0479     ++counter;
0480   }
0481 
0482   _SMP_MCS_lock_Destroy(&lock);
0483   _SMP_lock_Stats_destroy(&stats);
0484 
0485   ctx->local_counter[active_workers - 1][test][worker_index] = counter;
0486 }
0487 
0488 static void test_7_fini(
0489   rtems_test_parallel_context *base,
0490   void *arg,
0491   size_t active_workers
0492 )
0493 {
0494   test_context *ctx = (test_context *) base;
0495 
0496   test_fini(
0497     ctx,
0498     "MCS Lock",
0499     false,
0500     "global counter",
0501     7,
0502     active_workers
0503   );
0504 }
0505 
0506 static void busy_section(void)
0507 {
0508   int i;
0509 
0510   for (i = 0; i < 101; ++i) {
0511     RTEMS_COMPILER_MEMORY_BARRIER();
0512   }
0513 }
0514 
0515 static void test_8_body(
0516   rtems_test_parallel_context *base,
0517   void *arg,
0518   size_t active_workers,
0519   size_t worker_index
0520 )
0521 {
0522   test_context *ctx = (test_context *) base;
0523   size_t test = 8;
0524   unsigned long counter = 0;
0525   SMP_lock_Context lock_context;
0526 
0527   while (!rtems_test_parallel_stop_job(&ctx->base)) {
0528     _SMP_lock_Acquire(&ctx->lock, &lock_context);
0529     busy_section();
0530     _SMP_lock_Release(&ctx->lock, &lock_context);
0531     ++counter;
0532   }
0533 
0534   ctx->local_counter[active_workers - 1][test][worker_index] = counter;
0535 }
0536 
0537 static void test_8_fini(
0538   rtems_test_parallel_context *base,
0539   void *arg,
0540   size_t active_workers
0541 )
0542 {
0543   test_context *ctx = (test_context *) base;
0544 
0545   test_fini(
0546     ctx,
0547     "Ticket Lock",
0548     true,
0549     "busy loop",
0550     8,
0551     active_workers
0552   );
0553 }
0554 
0555 static void test_9_body(
0556   rtems_test_parallel_context *base,
0557   void *arg,
0558   size_t active_workers,
0559   size_t worker_index
0560 )
0561 {
0562   test_context *ctx = (test_context *) base;
0563   size_t test = 9;
0564   unsigned long counter = 0;
0565   SMP_MCS_lock_Context lock_context;
0566 
0567   while (!rtems_test_parallel_stop_job(&ctx->base)) {
0568     _SMP_MCS_lock_Acquire(&ctx->mcs_lock, &lock_context, &ctx->mcs_stats);
0569     busy_section();
0570     _SMP_MCS_lock_Release(&ctx->mcs_lock, &lock_context);
0571     ++counter;
0572   }
0573 
0574   ctx->local_counter[active_workers - 1][test][worker_index] = counter;
0575 }
0576 
0577 static void test_9_fini(
0578   rtems_test_parallel_context *base,
0579   void *arg,
0580   size_t active_workers
0581 )
0582 {
0583   test_context *ctx = (test_context *) base;
0584 
0585   test_fini(
0586     ctx,
0587     "MCS Lock",
0588     true,
0589     "busy loop",
0590     9,
0591     active_workers
0592   );
0593 }
0594 
0595 static void test_10_body(
0596   rtems_test_parallel_context *base,
0597   void *arg,
0598   size_t active_workers,
0599   size_t worker_index
0600 )
0601 {
0602   test_context *ctx = (test_context *) base;
0603   size_t test = 10;
0604   unsigned long counter = 0;
0605   unsigned long seq;
0606 
0607   if (rtems_test_parallel_is_master_worker(worker_index)) {
0608     while (!rtems_test_parallel_stop_job(&ctx->base)) {
0609       seq = _SMP_sequence_lock_Write_begin(&ctx->seq_lock);
0610 
0611       ctx->a = counter;
0612       ctx->b = counter;
0613 
0614       _SMP_sequence_lock_Write_end(&ctx->seq_lock, seq);
0615 
0616       ++counter;
0617     }
0618   } else {
0619     while (!rtems_test_parallel_stop_job(&ctx->base)) {
0620       unsigned long a;
0621       unsigned long b;
0622 
0623       do {
0624         seq = _SMP_sequence_lock_Read_begin(&ctx->seq_lock);
0625 
0626         a = ctx->a;
0627         b = ctx->b;
0628 
0629       } while (_SMP_sequence_lock_Read_retry(&ctx->seq_lock, seq));
0630 
0631       ++counter;
0632       rtems_test_assert(a == b);
0633     }
0634   }
0635 
0636   ctx->local_counter[active_workers - 1][test][worker_index] = counter;
0637 }
0638 
0639 static void test_10_fini(
0640   rtems_test_parallel_context *base,
0641   void *arg,
0642   size_t active_workers
0643 )
0644 {
0645   test_context *ctx = (test_context *) base;
0646 
0647   test_fini(
0648     ctx,
0649     "Sequence Lock",
0650     true,
0651     "two global counter",
0652     10,
0653     active_workers
0654   );
0655 }
0656 
0657 static void test_11_body(
0658   rtems_test_parallel_context *base,
0659   void *arg,
0660   size_t active_workers,
0661   size_t worker_index
0662 )
0663 {
0664   test_context *ctx = (test_context *) base;
0665   size_t test = 11;
0666   unsigned long counter = 0;
0667 
0668   while (!rtems_test_parallel_stop_job(&ctx->base)) {
0669     while (_Atomic_Exchange_uint(&ctx->flag, 1, ATOMIC_ORDER_ACQUIRE) != 0) {
0670       /* Wait */
0671     }
0672 
0673     _Atomic_Store_uint(&ctx->flag, 0, ATOMIC_ORDER_RELEASE);
0674     ++counter;
0675   }
0676 
0677   ctx->local_counter[active_workers - 1][test][worker_index] = counter;
0678 }
0679 
0680 static void test_11_fini(
0681   rtems_test_parallel_context *base,
0682   void *arg,
0683   size_t active_workers
0684 )
0685 {
0686   test_context *ctx = (test_context *) base;
0687 
0688   test_fini(
0689     ctx,
0690     "TAS Lock",
0691     true,
0692     "local counter",
0693     11,
0694     active_workers
0695   );
0696 }
0697 
0698 static void test_12_body(
0699   rtems_test_parallel_context *base,
0700   void *arg,
0701   size_t active_workers,
0702   size_t worker_index
0703 )
0704 {
0705   test_context *ctx = (test_context *) base;
0706   size_t test = 12;
0707   unsigned long counter = 0;
0708 
0709   while (!rtems_test_parallel_stop_job(&ctx->base)) {
0710     while (_Atomic_Exchange_uint(&ctx->flag, 1, ATOMIC_ORDER_ACQUIRE) != 0) {
0711       while (_Atomic_Load_uint(&ctx->flag, ATOMIC_ORDER_RELAXED) != 0) {
0712         /* Wait */
0713       }
0714     }
0715 
0716     _Atomic_Store_uint(&ctx->flag, 0, ATOMIC_ORDER_RELEASE);
0717     ++counter;
0718   }
0719 
0720   ctx->local_counter[active_workers - 1][test][worker_index] = counter;
0721 }
0722 
0723 static void test_12_fini(
0724   rtems_test_parallel_context *base,
0725   void *arg,
0726   size_t active_workers
0727 )
0728 {
0729   test_context *ctx = (test_context *) base;
0730 
0731   test_fini(
0732     ctx,
0733     "TTAS Lock",
0734     true,
0735     "local counter",
0736     12,
0737     active_workers
0738   );
0739 }
0740 
0741 static const rtems_test_parallel_job test_jobs[TEST_COUNT] = {
0742   {
0743     .init = test_init,
0744     .body = test_0_body,
0745     .fini = test_0_fini,
0746     .cascade = true
0747   }, {
0748     .init = test_init,
0749     .body = test_1_body,
0750     .fini = test_1_fini,
0751     .cascade = true
0752   }, {
0753     .init = test_init,
0754     .body = test_2_body,
0755     .fini = test_2_fini,
0756     .cascade = false
0757   }, {
0758     .init = test_init,
0759     .body = test_3_body,
0760     .fini = test_3_fini,
0761     .cascade = false
0762   }, {
0763     .init = test_init,
0764     .body = test_4_body,
0765     .fini = test_4_fini,
0766     .cascade = true
0767   }, {
0768     .init = test_init,
0769     .body = test_5_body,
0770     .fini = test_5_fini,
0771     .cascade = true
0772   }, {
0773     .init = test_init,
0774     .body = test_6_body,
0775     .fini = test_6_fini,
0776     .cascade = false
0777   }, {
0778     .init = test_init,
0779     .body = test_7_body,
0780     .fini = test_7_fini,
0781     .cascade = false
0782   }, {
0783     .init = test_init,
0784     .body = test_8_body,
0785     .fini = test_8_fini,
0786     .cascade = false
0787   }, {
0788     .init = test_init,
0789     .body = test_9_body,
0790     .fini = test_9_fini,
0791     .cascade = false
0792   }, {
0793     .init = test_init,
0794     .body = test_10_body,
0795     .fini = test_10_fini,
0796     .cascade = false
0797   }, {
0798     .init = test_init,
0799     .body = test_11_body,
0800     .fini = test_11_fini,
0801     .cascade = true
0802   }, {
0803     .init = test_init,
0804     .body = test_12_body,
0805     .fini = test_12_fini,
0806     .cascade = true
0807   }
0808 };
0809 
0810 static void test(void)
0811 {
0812   test_context *ctx = &test_instance;
0813 
0814   printf("*** BEGIN OF JSON DATA ***\n[\n  ");
0815   ctx->test_sep = "";
0816   rtems_test_parallel(&ctx->base, NULL, &test_jobs[0], TEST_COUNT);
0817   printf("\n]\n*** END OF JSON DATA ***\n");
0818 }
0819 
0820 static void Init(rtems_task_argument arg)
0821 {
0822   TEST_BEGIN();
0823 
0824   test();
0825 
0826   TEST_END();
0827   rtems_test_exit(0);
0828 }
0829 
0830 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
0831 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0832 
0833 #define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT
0834 
0835 #define CONFIGURE_MAXIMUM_TASKS CPU_COUNT
0836 
0837 #define CONFIGURE_MAXIMUM_SEMAPHORES 1
0838 
0839 #define CONFIGURE_MAXIMUM_TIMERS 1
0840 
0841 #define CONFIGURE_INIT_TASK_PRIORITY TASK_PRIORITY
0842 #define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
0843 #define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES
0844 
0845 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
0846 
0847 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0848 
0849 #define CONFIGURE_INIT
0850 
0851 #include <rtems/confdefs.h>