File indexing completed on 2025-05-11 08:24:43
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
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>