File indexing completed on 2025-05-11 08:24:21
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
0029 #ifdef HAVE_CONFIG_H
0030 #include "config.h"
0031 #endif
0032
0033 #include <rtems/test-info.h>
0034 #include <rtems/score/assert.h>
0035 #include <rtems.h>
0036
0037 static void stop_worker_timer(rtems_id timer_id, void *arg)
0038 {
0039 rtems_test_parallel_context *ctx = arg;
0040
0041 _Atomic_Store_ulong(&ctx->stop, 1, ATOMIC_ORDER_RELAXED);
0042 }
0043
0044 static void start_worker_stop_timer(
0045 rtems_test_parallel_context *ctx,
0046 rtems_interval duration
0047 )
0048 {
0049 rtems_status_code sc;
0050
0051 _Atomic_Store_ulong(&ctx->stop, 0, ATOMIC_ORDER_RELEASE);
0052
0053 sc = rtems_timer_fire_after(
0054 ctx->stop_worker_timer_id,
0055 duration,
0056 stop_worker_timer,
0057 ctx
0058 );
0059 _Assert(sc == RTEMS_SUCCESSFUL);
0060 (void) sc;
0061 }
0062
0063 static void run_tests(
0064 rtems_test_parallel_context *ctx,
0065 const rtems_test_parallel_job *jobs,
0066 size_t job_count
0067 )
0068 {
0069 SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER;
0070 size_t i;
0071
0072 _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
0073
0074 for (i = 0; i < job_count; ++i) {
0075 const rtems_test_parallel_job *job = &jobs[i];
0076 size_t n = rtems_scheduler_get_processor_maximum();
0077 size_t j = job->cascade ? 0 : rtems_scheduler_get_processor_maximum() - 1;
0078
0079 while (j < n) {
0080 size_t active_worker = j + 1;
0081 size_t worker_index;
0082 rtems_interrupt_level level;
0083
0084
0085
0086
0087
0088 rtems_interrupt_local_disable(level);
0089 _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
0090 worker_index = rtems_scheduler_get_processor();
0091 rtems_interrupt_local_enable(level);
0092
0093 _Assert(worker_index < ctx->worker_count);
0094
0095 if (rtems_test_parallel_is_master_worker(worker_index)) {
0096 rtems_interval duration = (*job->init)(ctx, job->arg, active_worker);
0097
0098 if (duration > 0) {
0099 start_worker_stop_timer(ctx, duration);
0100 }
0101 }
0102
0103 _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
0104
0105 if (worker_index <= j) {
0106 (*job->body)(ctx, job->arg, active_worker, worker_index);
0107 }
0108
0109 _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
0110
0111 if (rtems_test_parallel_is_master_worker(worker_index)) {
0112 (*job->fini)(ctx, job->arg, active_worker);
0113 }
0114
0115 _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
0116
0117 ++j;
0118 }
0119 }
0120 }
0121
0122 static void worker_task(rtems_task_argument arg)
0123 {
0124 rtems_test_parallel_context *ctx = (rtems_test_parallel_context *) arg;
0125 rtems_status_code sc;
0126
0127 (void) sc;
0128
0129 run_tests(ctx, ctx->jobs, ctx->job_count);
0130
0131 while (true) {
0132
0133 }
0134 }
0135
0136 void rtems_test_parallel(
0137 rtems_test_parallel_context *ctx,
0138 rtems_test_parallel_worker_setup worker_setup,
0139 const rtems_test_parallel_job *jobs,
0140 size_t job_count
0141 )
0142 {
0143 rtems_status_code sc;
0144 size_t worker_index;
0145 rtems_task_priority worker_priority;
0146
0147 _Atomic_Init_ulong(&ctx->stop, 0);
0148 _SMP_barrier_Control_initialize(&ctx->barrier);
0149 ctx->worker_count = rtems_scheduler_get_processor_maximum();
0150 ctx->worker_ids[0] = rtems_task_self();
0151 ctx->jobs = jobs;
0152 ctx->job_count = job_count;
0153
0154 if (RTEMS_ARRAY_SIZE(ctx->worker_ids) < ctx->worker_count) {
0155 rtems_fatal_error_occurred(0xdeadbeef);
0156 }
0157
0158 sc = rtems_task_set_priority(
0159 RTEMS_SELF,
0160 RTEMS_CURRENT_PRIORITY,
0161 &worker_priority
0162 );
0163 if (sc != RTEMS_SUCCESSFUL) {
0164 rtems_fatal_error_occurred(0xdeadbeef);
0165 }
0166
0167 sc = rtems_timer_create(
0168 rtems_build_name('S', 'T', 'O', 'P'),
0169 &ctx->stop_worker_timer_id
0170 );
0171 if (sc != RTEMS_SUCCESSFUL) {
0172 rtems_fatal_error_occurred(0xdeadbeef);
0173 }
0174
0175 for (worker_index = 1; worker_index < ctx->worker_count; ++worker_index) {
0176 rtems_id worker_id;
0177
0178 sc = rtems_task_create(
0179 rtems_build_name('W', 'O', 'R', 'K'),
0180 worker_priority,
0181 RTEMS_MINIMUM_STACK_SIZE,
0182 RTEMS_DEFAULT_MODES,
0183 RTEMS_DEFAULT_ATTRIBUTES,
0184 &worker_id
0185 );
0186 if (sc != RTEMS_SUCCESSFUL) {
0187 rtems_fatal_error_occurred(0xdeadbeef);
0188 }
0189
0190 ctx->worker_ids[worker_index] = worker_id;
0191
0192 if (worker_setup != NULL) {
0193 (*worker_setup)(ctx, worker_index, worker_id);
0194 }
0195
0196 sc = rtems_task_start(worker_id, worker_task, (rtems_task_argument) ctx);
0197 _Assert(sc == RTEMS_SUCCESSFUL);
0198 }
0199
0200 run_tests(ctx, jobs, job_count);
0201
0202 for (worker_index = 1; worker_index < ctx->worker_count; ++worker_index) {
0203 sc = rtems_task_delete(ctx->worker_ids[worker_index]);
0204 _Assert(sc == RTEMS_SUCCESSFUL);
0205 }
0206
0207 sc = rtems_timer_delete(ctx->stop_worker_timer_id);
0208 _Assert(sc == RTEMS_SUCCESSFUL);
0209 }