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) 2016 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 <inttypes.h>
0033 #include <string.h>
0034 #include <stdio.h>
0035 
0036 #include <rtems.h>
0037 #include <rtems/libcsupport.h>
0038 
0039 #include "tmacros.h"
0040 
0041 const char rtems_test_name[] = "SMPMUTEX 2";
0042 
0043 #define MTX_PER_CPU 12
0044 
0045 #define WORKER_PER_CPU 4
0046 
0047 #define CPU_COUNT 32
0048 
0049 #define MTX_COUNT (CPU_COUNT * MTX_PER_CPU)
0050 
0051 #define WORKER_COUNT (CPU_COUNT * WORKER_PER_CPU)
0052 
0053 typedef struct {
0054   uint32_t obtain_counter;
0055   uint32_t deadlock_counter;
0056   uint32_t timeout_counter;
0057   uint32_t release_counter;
0058   uint32_t max_nest_level;
0059 } test_stats;
0060 
0061 typedef struct {
0062   uint32_t cpu_count;
0063   uint32_t mtx_count;
0064   rtems_id worker_ids[CPU_COUNT][WORKER_PER_CPU];
0065   rtems_id scheduler_ids[CPU_COUNT];
0066   rtems_id mtx_ids[MTX_COUNT];
0067   rtems_id counting_sem_id;
0068   volatile bool stop_worker[WORKER_COUNT];
0069   test_stats stats[WORKER_COUNT];
0070 } test_context;
0071 
0072 static test_context test_instance;
0073 
0074 static uint32_t simple_random(uint32_t v)
0075 {
0076   v *= 1664525;
0077   v += 1013904223;
0078 
0079   return v;
0080 }
0081 
0082 typedef struct {
0083   uint32_t guide;
0084   size_t mtx_stack[MTX_COUNT];
0085   bool mtx_owned[MTX_COUNT];
0086   size_t nest_level;
0087   test_stats stats;
0088 } worker_context;
0089 
0090 static void release(test_context *ctx, worker_context *wc, size_t nest_level)
0091 {
0092   rtems_status_code sc;
0093   size_t i;
0094 
0095   --wc->nest_level;
0096   ++wc->stats.release_counter;
0097 
0098   i = wc->mtx_stack[wc->nest_level];
0099   wc->mtx_owned[i] = false;
0100 
0101   sc = rtems_semaphore_release(ctx->mtx_ids[i]);
0102   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0103 }
0104 
0105 static void release_all(test_context *ctx, worker_context *wc)
0106 {
0107   while (wc->nest_level > 0) {
0108     release(ctx, wc, wc->nest_level);
0109   }
0110 }
0111 
0112 static void worker(rtems_task_argument index)
0113 {
0114   test_context *ctx;
0115   worker_context wc;
0116   rtems_status_code sc;
0117 
0118   ctx = &test_instance;
0119   memset(&wc, 0, sizeof(wc));
0120   wc.guide = index;
0121 
0122   while (!ctx->stop_worker[index]) {
0123     uint32_t action;
0124     uint32_t i;
0125 
0126     if (wc.nest_level < ctx->mtx_count) {
0127       action = (wc.guide >> 23) % 2;
0128     } else {
0129       action = UINT32_MAX;
0130     }
0131 
0132     i = (wc.guide >> 13) % ctx->mtx_count;
0133 
0134     switch (action) {
0135       case 0:
0136         if ( !wc.mtx_owned[i] ) {
0137           sc = rtems_semaphore_obtain(ctx->mtx_ids[i], RTEMS_WAIT, 1);
0138 
0139           if (sc == RTEMS_SUCCESSFUL) {
0140             wc.mtx_owned[i] = true;
0141             wc.mtx_stack[wc.nest_level] = i;
0142             ++wc.nest_level;
0143             ++wc.stats.obtain_counter;
0144 
0145             if (wc.nest_level > wc.stats.max_nest_level) {
0146               wc.stats.max_nest_level = wc.nest_level;
0147             }
0148           } else if (sc == RTEMS_INCORRECT_STATE) {
0149             ++wc.stats.deadlock_counter;
0150             release_all(ctx, &wc);
0151           } else if (sc == RTEMS_TIMEOUT) {
0152             ++wc.stats.timeout_counter;
0153             release_all(ctx, &wc);
0154           } else {
0155             rtems_test_assert(0);
0156           }
0157         }
0158 
0159         break;
0160       default:
0161         if (wc.nest_level > 0) {
0162           release(ctx, &wc, wc.nest_level);
0163         }
0164 
0165         break;
0166     }
0167 
0168     wc.guide = simple_random(wc.guide);
0169   }
0170 
0171   release_all(ctx, &wc);
0172 
0173   ctx->stats[index] = wc.stats;
0174 
0175   sc = rtems_semaphore_release(ctx->counting_sem_id);
0176   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0177 
0178   rtems_task_suspend(RTEMS_SELF);
0179   rtems_test_assert(0);
0180 }
0181 
0182 static void set_up(test_context *ctx)
0183 {
0184   rtems_status_code sc;
0185   uint32_t i;
0186 
0187   ctx->cpu_count = rtems_scheduler_get_processor_maximum();
0188   ctx->mtx_count = MTX_PER_CPU * ctx->cpu_count;
0189 
0190   sc = rtems_semaphore_create(
0191     rtems_build_name('S', 'Y', 'N', 'C'),
0192     0,
0193     RTEMS_COUNTING_SEMAPHORE,
0194     0,
0195     &ctx->counting_sem_id
0196   );
0197   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0198 
0199   for (i = 0; i < ctx->mtx_count; ++i) {
0200     sc = rtems_semaphore_create(
0201       rtems_build_name('M', 'U', 'T', 'X'),
0202       1,
0203       RTEMS_BINARY_SEMAPHORE
0204         | RTEMS_PRIORITY
0205         | RTEMS_INHERIT_PRIORITY,
0206       0,
0207       &ctx->mtx_ids[i]
0208     );
0209     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0210   }
0211 
0212   for (i = 0; i < ctx->cpu_count; ++i) {
0213     size_t j;
0214 
0215     sc = rtems_scheduler_ident(i, &ctx->scheduler_ids[i]);
0216     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0217 
0218     for (j = 0; j < WORKER_PER_CPU; ++j) {
0219       sc = rtems_task_create(
0220         rtems_build_name('W', 'O', 'R', 'K'),
0221         255,
0222         RTEMS_MINIMUM_STACK_SIZE,
0223         RTEMS_DEFAULT_MODES,
0224         RTEMS_DEFAULT_ATTRIBUTES,
0225         &ctx->worker_ids[i][j]
0226       );
0227       rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0228 
0229       sc = rtems_task_set_scheduler(
0230         ctx->worker_ids[i][j],
0231         ctx->scheduler_ids[i],
0232         2 + j
0233       );
0234       rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0235 
0236       sc = rtems_task_start(
0237         ctx->worker_ids[i][j],
0238         worker,
0239         i * WORKER_PER_CPU + j
0240       );
0241       rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0242     }
0243   }
0244 }
0245 
0246 static void run(test_context *ctx)
0247 {
0248   rtems_status_code sc;
0249   uint32_t i;
0250 
0251   sc = rtems_task_wake_after(10 * rtems_clock_get_ticks_per_second());
0252   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0253 
0254   for (i = 0; i < WORKER_PER_CPU * ctx->cpu_count; ++i) {
0255     ctx->stop_worker[i] = true;
0256   }
0257 
0258   for (i = 0; i < WORKER_PER_CPU * ctx->cpu_count; ++i) {
0259     sc = rtems_semaphore_obtain(
0260       ctx->counting_sem_id,
0261       RTEMS_WAIT,
0262       RTEMS_NO_TIMEOUT
0263     );
0264     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0265   }
0266 }
0267 
0268 static void tear_down(test_context *ctx)
0269 {
0270   rtems_status_code sc;
0271   uint32_t i;
0272 
0273   for (i = 0; i < ctx->cpu_count; ++i) {
0274     size_t j;
0275 
0276     for (j = 0; j < WORKER_PER_CPU; ++j) {
0277       sc = rtems_task_delete(ctx->worker_ids[i][j]);
0278       rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0279     }
0280   }
0281 
0282   for (i = 0; i < ctx->mtx_count; ++i) {
0283     sc = rtems_semaphore_delete(ctx->mtx_ids[i]);
0284     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0285   }
0286 
0287   sc = rtems_semaphore_delete(ctx->counting_sem_id);
0288   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0289 
0290   for (i = 0; i < WORKER_PER_CPU * ctx->cpu_count; ++i) {
0291     const test_stats *stats;
0292 
0293     stats = &ctx->stats[i];
0294 
0295     printf("worker[%" PRIu32 "][%" PRIu32 "]\n"
0296       "\tobtain counter   = %" PRIu32 "\n"
0297       "\tdeadlock counter = %" PRIu32 "\n"
0298       "\ttimeout counter  = %" PRIu32 "\n"
0299       "\trelease counter  = %" PRIu32 "\n"
0300       "\tmax nest level   = %" PRIu32 "\n",
0301       i / WORKER_PER_CPU,
0302       i % WORKER_PER_CPU,
0303       stats->obtain_counter,
0304       stats->deadlock_counter,
0305       stats->timeout_counter,
0306       stats->release_counter,
0307       stats->max_nest_level
0308     );
0309   }
0310 }
0311 
0312 static void Init(rtems_task_argument arg)
0313 {
0314   test_context *ctx;
0315   rtems_resource_snapshot snapshot;
0316 
0317   TEST_BEGIN();
0318   rtems_resource_snapshot_take(&snapshot);
0319   ctx = &test_instance;
0320 
0321   set_up(ctx);
0322   run(ctx);
0323   tear_down(ctx);
0324 
0325   rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
0326   TEST_END();
0327   rtems_test_exit(0);
0328 }
0329 
0330 #define CONFIGURE_MICROSECONDS_PER_TICK 1000
0331 
0332 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
0333 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0334 
0335 #define CONFIGURE_MAXIMUM_TASKS (1 + WORKER_COUNT)
0336 #define CONFIGURE_MAXIMUM_SEMAPHORES (1 + MTX_COUNT)
0337 
0338 #define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT
0339 
0340 #define CONFIGURE_SCHEDULER_SIMPLE_SMP
0341 
0342 #include <rtems/scheduler.h>
0343 
0344 RTEMS_SCHEDULER_SIMPLE_SMP(0);
0345 RTEMS_SCHEDULER_SIMPLE_SMP(1);
0346 RTEMS_SCHEDULER_SIMPLE_SMP(2);
0347 RTEMS_SCHEDULER_SIMPLE_SMP(3);
0348 RTEMS_SCHEDULER_SIMPLE_SMP(4);
0349 RTEMS_SCHEDULER_SIMPLE_SMP(5);
0350 RTEMS_SCHEDULER_SIMPLE_SMP(6);
0351 RTEMS_SCHEDULER_SIMPLE_SMP(7);
0352 RTEMS_SCHEDULER_SIMPLE_SMP(8);
0353 RTEMS_SCHEDULER_SIMPLE_SMP(9);
0354 RTEMS_SCHEDULER_SIMPLE_SMP(10);
0355 RTEMS_SCHEDULER_SIMPLE_SMP(11);
0356 RTEMS_SCHEDULER_SIMPLE_SMP(12);
0357 RTEMS_SCHEDULER_SIMPLE_SMP(13);
0358 RTEMS_SCHEDULER_SIMPLE_SMP(14);
0359 RTEMS_SCHEDULER_SIMPLE_SMP(15);
0360 RTEMS_SCHEDULER_SIMPLE_SMP(16);
0361 RTEMS_SCHEDULER_SIMPLE_SMP(17);
0362 RTEMS_SCHEDULER_SIMPLE_SMP(18);
0363 RTEMS_SCHEDULER_SIMPLE_SMP(19);
0364 RTEMS_SCHEDULER_SIMPLE_SMP(20);
0365 RTEMS_SCHEDULER_SIMPLE_SMP(21);
0366 RTEMS_SCHEDULER_SIMPLE_SMP(22);
0367 RTEMS_SCHEDULER_SIMPLE_SMP(23);
0368 RTEMS_SCHEDULER_SIMPLE_SMP(24);
0369 RTEMS_SCHEDULER_SIMPLE_SMP(25);
0370 RTEMS_SCHEDULER_SIMPLE_SMP(26);
0371 RTEMS_SCHEDULER_SIMPLE_SMP(27);
0372 RTEMS_SCHEDULER_SIMPLE_SMP(28);
0373 RTEMS_SCHEDULER_SIMPLE_SMP(29);
0374 RTEMS_SCHEDULER_SIMPLE_SMP(30);
0375 RTEMS_SCHEDULER_SIMPLE_SMP(31);
0376 
0377 #define CONFIGURE_SCHEDULER_TABLE_ENTRIES \
0378   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(0, 0), \
0379   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(1, 1), \
0380   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(2, 2), \
0381   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(3, 3), \
0382   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(4, 4), \
0383   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(5, 5), \
0384   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(6, 6), \
0385   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(7, 7), \
0386   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(8, 8), \
0387   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(9, 9), \
0388   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(10, 10), \
0389   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(11, 11), \
0390   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(12, 12), \
0391   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(13, 13), \
0392   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(14, 14), \
0393   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(15, 15), \
0394   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(16, 16), \
0395   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(17, 17), \
0396   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(18, 18), \
0397   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(19, 19), \
0398   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(20, 20), \
0399   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(21, 21), \
0400   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(22, 22), \
0401   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(23, 23), \
0402   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(24, 24), \
0403   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(25, 25), \
0404   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(26, 26), \
0405   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(27, 27), \
0406   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(28, 28), \
0407   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(29, 29), \
0408   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(30, 30), \
0409   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(31, 31)
0410 
0411 #define CONFIGURE_SCHEDULER_ASSIGNMENTS \
0412   RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \
0413   RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0414   RTEMS_SCHEDULER_ASSIGN(2, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0415   RTEMS_SCHEDULER_ASSIGN(3, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0416   RTEMS_SCHEDULER_ASSIGN(4, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0417   RTEMS_SCHEDULER_ASSIGN(5, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0418   RTEMS_SCHEDULER_ASSIGN(6, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0419   RTEMS_SCHEDULER_ASSIGN(7, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0420   RTEMS_SCHEDULER_ASSIGN(8, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0421   RTEMS_SCHEDULER_ASSIGN(9, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0422   RTEMS_SCHEDULER_ASSIGN(10, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0423   RTEMS_SCHEDULER_ASSIGN(11, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0424   RTEMS_SCHEDULER_ASSIGN(12, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0425   RTEMS_SCHEDULER_ASSIGN(13, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0426   RTEMS_SCHEDULER_ASSIGN(14, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0427   RTEMS_SCHEDULER_ASSIGN(15, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0428   RTEMS_SCHEDULER_ASSIGN(16, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0429   RTEMS_SCHEDULER_ASSIGN(17, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0430   RTEMS_SCHEDULER_ASSIGN(18, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0431   RTEMS_SCHEDULER_ASSIGN(19, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0432   RTEMS_SCHEDULER_ASSIGN(20, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0433   RTEMS_SCHEDULER_ASSIGN(21, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0434   RTEMS_SCHEDULER_ASSIGN(22, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0435   RTEMS_SCHEDULER_ASSIGN(23, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0436   RTEMS_SCHEDULER_ASSIGN(24, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0437   RTEMS_SCHEDULER_ASSIGN(25, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0438   RTEMS_SCHEDULER_ASSIGN(26, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0439   RTEMS_SCHEDULER_ASSIGN(27, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0440   RTEMS_SCHEDULER_ASSIGN(28, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0441   RTEMS_SCHEDULER_ASSIGN(29, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0442   RTEMS_SCHEDULER_ASSIGN(30, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0443   RTEMS_SCHEDULER_ASSIGN(31, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL)
0444 
0445 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
0446 
0447 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0448 
0449 #define CONFIGURE_INIT
0450 
0451 #include <rtems/confdefs.h>