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) 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 <rtems.h>
0033 #include <rtems/libcsupport.h>
0034 #include <rtems/score/objectimpl.h>
0035 #include <rtems/score/threadimpl.h>
0036 
0037 #include "tmacros.h"
0038 
0039 const char rtems_test_name[] = "SMPMIGRATION 2";
0040 
0041 #define CPU_COUNT 32
0042 
0043 #define TASK_COUNT (CPU_COUNT + 1)
0044 
0045 #define PRIO_LOW 3
0046 
0047 #define PRIO_HIGH 2
0048 
0049 typedef struct {
0050   uint32_t value;
0051   uint32_t cache_line_separation[31];
0052 } test_counter;
0053 
0054 typedef struct {
0055   test_counter counters[TASK_COUNT];
0056   rtems_id scheduler_ids[CPU_COUNT];
0057   rtems_id task_ids[TASK_COUNT];
0058 } test_context;
0059 
0060 static test_context test_instance;
0061 
0062 static rtems_task_priority migration_task_prio(uint32_t task_index)
0063 {
0064   return task_index > 0 ? PRIO_LOW : PRIO_HIGH;
0065 }
0066 
0067 static void migration_task(rtems_task_argument arg)
0068 {
0069   test_context *ctx = &test_instance;
0070   uint32_t task_index = arg;
0071   rtems_task_priority prio = migration_task_prio(task_index);
0072   uint32_t cpu_count = rtems_scheduler_get_processor_maximum();
0073   uint32_t cpu_index = rtems_scheduler_get_processor();
0074 
0075   while (true) {
0076     rtems_status_code sc;
0077 
0078     cpu_index = (cpu_index + 1) % cpu_count;
0079 
0080     sc = rtems_task_set_scheduler(
0081       RTEMS_SELF,
0082       ctx->scheduler_ids[cpu_index],
0083       prio
0084     );
0085     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0086 
0087     ++ctx->counters[task_index].value;
0088 
0089     rtems_test_assert(cpu_index == rtems_scheduler_get_processor());
0090   }
0091 }
0092 
0093 static void test_migrations(test_context *ctx)
0094 {
0095   rtems_status_code sc;
0096   uint32_t cpu_count = rtems_scheduler_get_processor_maximum();
0097   uint32_t task_count = cpu_count + 1;
0098   uint32_t task_index;
0099 
0100   for (task_index = 0; task_index < task_count; ++task_index) {
0101     rtems_id task_id;
0102 
0103     sc = rtems_task_create(
0104       rtems_build_name('T', 'A', 'S', 'K'),
0105       255,
0106       RTEMS_MINIMUM_STACK_SIZE,
0107       RTEMS_DEFAULT_MODES,
0108       RTEMS_DEFAULT_ATTRIBUTES,
0109       &task_id
0110     );
0111     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0112 
0113     sc = rtems_task_set_scheduler(
0114       task_id,
0115       ctx->scheduler_ids[task_index % cpu_count],
0116       migration_task_prio(task_index)
0117     );
0118     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0119 
0120     sc = rtems_task_start(task_id, migration_task, task_index);
0121     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0122 
0123     ctx->task_ids[task_index] = task_id;
0124   }
0125 
0126   sc = rtems_task_wake_after(30 * rtems_clock_get_ticks_per_second());
0127   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0128 
0129   for (task_index = 0; task_index < task_count; ++task_index) {
0130     printf(
0131       "task %" PRIu32 " counter: %" PRIu32 "\n",
0132       task_index,
0133       ctx->counters[task_index].value
0134     );
0135 
0136     sc = rtems_task_delete(ctx->task_ids[task_index]);
0137     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0138   }
0139 }
0140 
0141 static void busy_loop_task(rtems_task_argument arg)
0142 {
0143   while (true) {
0144     /* Do nothing */
0145   }
0146 }
0147 
0148 static Thread_Control *get_thread_by_id(rtems_id task_id)
0149 {
0150   ISR_lock_Context lock_context;
0151   Thread_Control *thread;
0152 
0153   thread = _Thread_Get(task_id, &lock_context);
0154   rtems_test_assert(thread != NULL);
0155   _ISR_lock_ISR_enable(&lock_context);
0156 
0157   return thread;
0158 }
0159 
0160 static void test_double_migration(test_context *ctx)
0161 {
0162   uint32_t cpu_count = rtems_scheduler_get_processor_maximum();
0163 
0164   if (cpu_count >= 2) {
0165     rtems_status_code sc;
0166     rtems_id task_id;
0167     rtems_id scheduler_id;
0168     uint32_t cpu_self_index = 0;
0169     uint32_t cpu_other_index = 1;
0170     Per_CPU_Control *cpu_self = _Per_CPU_Get_by_index(cpu_self_index);
0171     Per_CPU_Control *cpu_other = _Per_CPU_Get_by_index(cpu_other_index);
0172     Per_CPU_Control *cpu_self_dispatch_disabled;
0173     Thread_Control *self;
0174     Thread_Control *other;
0175 
0176     sc = rtems_task_get_scheduler(RTEMS_SELF, &scheduler_id);
0177     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0178 
0179     rtems_test_assert(scheduler_id == ctx->scheduler_ids[cpu_self_index]);
0180 
0181     sc = rtems_task_create(
0182       rtems_build_name('T', 'A', 'S', 'K'),
0183       2,
0184       RTEMS_MINIMUM_STACK_SIZE,
0185       RTEMS_DEFAULT_MODES,
0186       RTEMS_DEFAULT_ATTRIBUTES,
0187       &task_id
0188     );
0189     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0190 
0191     other = get_thread_by_id(task_id);
0192 
0193     sc = rtems_task_set_scheduler(
0194       task_id,
0195       ctx->scheduler_ids[cpu_other_index],
0196       2
0197     );
0198     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0199 
0200     sc = rtems_task_start(task_id, busy_loop_task, 0);
0201     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0202 
0203     while (!_Thread_Is_executing_on_a_processor(other)) {
0204       /* Wait */
0205     }
0206 
0207     cpu_self_dispatch_disabled = _Thread_Dispatch_disable();
0208     rtems_test_assert(cpu_self == cpu_self_dispatch_disabled);
0209 
0210     self = _Thread_Executing;
0211 
0212     rtems_test_assert(cpu_self->executing == self);
0213     rtems_test_assert(cpu_self->heir == self);
0214     rtems_test_assert(!cpu_self->dispatch_necessary);
0215 
0216     rtems_test_assert(cpu_other->executing == other);
0217     rtems_test_assert(cpu_other->heir == other);
0218     rtems_test_assert(!cpu_other->dispatch_necessary);
0219 
0220     sc = rtems_task_set_scheduler(
0221       RTEMS_SELF,
0222       ctx->scheduler_ids[cpu_other_index],
0223       1
0224     );
0225     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0226 
0227     rtems_test_assert(cpu_self->executing == self);
0228     rtems_test_assert(cpu_self->heir != self);
0229     rtems_test_assert(cpu_self->dispatch_necessary);
0230 
0231     while (_Thread_Is_executing_on_a_processor(other)) {
0232       /* Wait */
0233     }
0234 
0235     rtems_test_assert(cpu_other->executing == self);
0236     rtems_test_assert(cpu_other->heir == self);
0237     rtems_test_assert(!cpu_other->dispatch_necessary);
0238 
0239     sc = rtems_task_set_scheduler(
0240       RTEMS_SELF,
0241       ctx->scheduler_ids[cpu_self_index],
0242       1
0243     );
0244     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0245 
0246     rtems_test_assert(cpu_self->executing == self);
0247     rtems_test_assert(cpu_self->heir == self);
0248     rtems_test_assert(cpu_self->dispatch_necessary);
0249 
0250     rtems_test_assert(cpu_other->heir == other);
0251 
0252     _Thread_Dispatch_enable(cpu_self_dispatch_disabled);
0253 
0254     while (!_Thread_Is_executing_on_a_processor(other)) {
0255       /* Wait */
0256     }
0257 
0258     sc = rtems_task_delete(task_id);
0259     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0260   }
0261 }
0262 
0263 static void init_scheduler_ids(test_context *ctx)
0264 {
0265   rtems_status_code sc;
0266   uint32_t cpu_count = rtems_scheduler_get_processor_maximum();
0267   uint32_t cpu_index;
0268 
0269   for (cpu_index = 0; cpu_index < cpu_count; ++cpu_index) {
0270     sc = rtems_scheduler_ident(cpu_index, &ctx->scheduler_ids[cpu_index]);
0271     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0272   }
0273 }
0274 
0275 static void Init(rtems_task_argument arg)
0276 {
0277   test_context *ctx = &test_instance;
0278   rtems_resource_snapshot snapshot;
0279 
0280   TEST_BEGIN();
0281 
0282   rtems_resource_snapshot_take(&snapshot);
0283 
0284   init_scheduler_ids(ctx);
0285   test_double_migration(ctx);
0286   test_migrations(ctx);
0287 
0288   rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
0289 
0290   TEST_END();
0291   rtems_test_exit(0);
0292 }
0293 
0294 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
0295 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0296 
0297 #define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT
0298 
0299 #define CONFIGURE_SCHEDULER_SIMPLE_SMP
0300 
0301 #include <rtems/scheduler.h>
0302 
0303 RTEMS_SCHEDULER_SIMPLE_SMP(0);
0304 RTEMS_SCHEDULER_SIMPLE_SMP(1);
0305 RTEMS_SCHEDULER_SIMPLE_SMP(2);
0306 RTEMS_SCHEDULER_SIMPLE_SMP(3);
0307 RTEMS_SCHEDULER_SIMPLE_SMP(4);
0308 RTEMS_SCHEDULER_SIMPLE_SMP(5);
0309 RTEMS_SCHEDULER_SIMPLE_SMP(6);
0310 RTEMS_SCHEDULER_SIMPLE_SMP(7);
0311 RTEMS_SCHEDULER_SIMPLE_SMP(8);
0312 RTEMS_SCHEDULER_SIMPLE_SMP(9);
0313 RTEMS_SCHEDULER_SIMPLE_SMP(10);
0314 RTEMS_SCHEDULER_SIMPLE_SMP(11);
0315 RTEMS_SCHEDULER_SIMPLE_SMP(12);
0316 RTEMS_SCHEDULER_SIMPLE_SMP(13);
0317 RTEMS_SCHEDULER_SIMPLE_SMP(14);
0318 RTEMS_SCHEDULER_SIMPLE_SMP(15);
0319 RTEMS_SCHEDULER_SIMPLE_SMP(16);
0320 RTEMS_SCHEDULER_SIMPLE_SMP(17);
0321 RTEMS_SCHEDULER_SIMPLE_SMP(18);
0322 RTEMS_SCHEDULER_SIMPLE_SMP(19);
0323 RTEMS_SCHEDULER_SIMPLE_SMP(20);
0324 RTEMS_SCHEDULER_SIMPLE_SMP(21);
0325 RTEMS_SCHEDULER_SIMPLE_SMP(22);
0326 RTEMS_SCHEDULER_SIMPLE_SMP(23);
0327 RTEMS_SCHEDULER_SIMPLE_SMP(24);
0328 RTEMS_SCHEDULER_SIMPLE_SMP(25);
0329 RTEMS_SCHEDULER_SIMPLE_SMP(26);
0330 RTEMS_SCHEDULER_SIMPLE_SMP(27);
0331 RTEMS_SCHEDULER_SIMPLE_SMP(28);
0332 RTEMS_SCHEDULER_SIMPLE_SMP(29);
0333 RTEMS_SCHEDULER_SIMPLE_SMP(30);
0334 RTEMS_SCHEDULER_SIMPLE_SMP(31);
0335 
0336 #define CONFIGURE_SCHEDULER_TABLE_ENTRIES \
0337   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(0, 0), \
0338   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(1, 1), \
0339   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(2, 2), \
0340   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(3, 3), \
0341   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(4, 4), \
0342   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(5, 5), \
0343   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(6, 6), \
0344   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(7, 7), \
0345   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(8, 8), \
0346   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(9, 9), \
0347   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(10, 10), \
0348   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(11, 11), \
0349   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(12, 12), \
0350   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(13, 13), \
0351   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(14, 14), \
0352   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(15, 15), \
0353   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(16, 16), \
0354   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(17, 17), \
0355   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(18, 18), \
0356   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(19, 19), \
0357   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(20, 20), \
0358   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(21, 21), \
0359   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(22, 22), \
0360   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(23, 23), \
0361   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(24, 24), \
0362   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(25, 25), \
0363   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(26, 26), \
0364   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(27, 27), \
0365   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(28, 28), \
0366   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(29, 29), \
0367   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(30, 30), \
0368   RTEMS_SCHEDULER_TABLE_SIMPLE_SMP(31, 31)
0369 
0370 #define CONFIGURE_SCHEDULER_ASSIGNMENTS \
0371   RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0372   RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0373   RTEMS_SCHEDULER_ASSIGN(2, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0374   RTEMS_SCHEDULER_ASSIGN(3, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0375   RTEMS_SCHEDULER_ASSIGN(4, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0376   RTEMS_SCHEDULER_ASSIGN(5, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0377   RTEMS_SCHEDULER_ASSIGN(6, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0378   RTEMS_SCHEDULER_ASSIGN(7, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0379   RTEMS_SCHEDULER_ASSIGN(8, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0380   RTEMS_SCHEDULER_ASSIGN(9, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0381   RTEMS_SCHEDULER_ASSIGN(10, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0382   RTEMS_SCHEDULER_ASSIGN(11, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0383   RTEMS_SCHEDULER_ASSIGN(12, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0384   RTEMS_SCHEDULER_ASSIGN(13, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0385   RTEMS_SCHEDULER_ASSIGN(14, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0386   RTEMS_SCHEDULER_ASSIGN(15, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0387   RTEMS_SCHEDULER_ASSIGN(16, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0388   RTEMS_SCHEDULER_ASSIGN(17, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0389   RTEMS_SCHEDULER_ASSIGN(18, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0390   RTEMS_SCHEDULER_ASSIGN(19, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0391   RTEMS_SCHEDULER_ASSIGN(20, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0392   RTEMS_SCHEDULER_ASSIGN(21, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0393   RTEMS_SCHEDULER_ASSIGN(22, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0394   RTEMS_SCHEDULER_ASSIGN(23, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0395   RTEMS_SCHEDULER_ASSIGN(24, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0396   RTEMS_SCHEDULER_ASSIGN(25, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0397   RTEMS_SCHEDULER_ASSIGN(26, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0398   RTEMS_SCHEDULER_ASSIGN(27, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0399   RTEMS_SCHEDULER_ASSIGN(28, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0400   RTEMS_SCHEDULER_ASSIGN(29, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0401   RTEMS_SCHEDULER_ASSIGN(30, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
0402   RTEMS_SCHEDULER_ASSIGN(31, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL)
0403 
0404 #define CONFIGURE_MAXIMUM_TASKS (1 + TASK_COUNT)
0405 
0406 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
0407 
0408 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0409 
0410 #define CONFIGURE_INIT
0411 
0412 #include <rtems/confdefs.h>