Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSTestFrameworkImpl
0007  *
0008  * @brief This source file contains the implementation of the scheduler test
0009  *   support API.
0010  */
0011 
0012 /*
0013  * Copyright (C) 2021 embedded brains GmbH & Co. KG
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 #ifdef HAVE_CONFIG_H
0038 #include "config.h"
0039 #endif
0040 
0041 #include <rtems/test-scheduler.h>
0042 
0043 #include <rtems.h>
0044 #include <rtems/score/percpu.h>
0045 #include <rtems/score/schedulerimpl.h>
0046 
0047 typedef struct {
0048     RTEMS_INTERRUPT_LOCK_MEMBER(lock)
0049     T_scheduler_log *active;
0050     T_scheduler_event_handler handler;
0051     void *arg;
0052 } T_scheduler_context;
0053 
0054 static T_scheduler_context T_scheduler_instance = {
0055 #ifdef RTEMS_SMP
0056     .lock = RTEMS_INTERRUPT_LOCK_INITIALIZER("Test Scheduler"),
0057 #endif
0058     .active = NULL
0059 };
0060 
0061 void
0062 T_scheduler_set_event_handler(T_scheduler_event_handler handler, void *arg)
0063 {
0064     T_scheduler_context *ctx;
0065     rtems_interrupt_lock_context lock_context;
0066 
0067     ctx = &T_scheduler_instance;
0068 
0069     rtems_interrupt_lock_acquire(&ctx->lock, &lock_context);
0070     ctx->handler = handler;
0071     ctx->arg = arg;
0072     rtems_interrupt_lock_release(&ctx->lock, &lock_context);
0073 }
0074 
0075 static void
0076 T_scheduler_before_operation(T_scheduler_event *event)
0077 {
0078     T_scheduler_context *ctx;
0079     rtems_interrupt_lock_context lock_context;
0080     T_scheduler_log *log;
0081     T_scheduler_event_handler handler;
0082     void *arg;
0083     Per_CPU_Control *cpu_self;
0084 
0085     ctx = &T_scheduler_instance;
0086     log = ctx->active;
0087     handler = ctx->handler;
0088 
0089     if (log == NULL && handler == NULL) {
0090         return;
0091     }
0092 
0093     rtems_interrupt_lock_interrupt_disable(&lock_context);
0094     cpu_self = _Per_CPU_Get();
0095     event->cpu = _Per_CPU_Get_index( cpu_self );
0096 
0097     if (_Per_CPU_Is_ISR_in_progress(cpu_self)) {
0098         event->executing = NULL;
0099     } else {
0100         event->executing = _Per_CPU_Get_executing(cpu_self);
0101     }
0102 
0103     event->instant = T_now();
0104 
0105     rtems_interrupt_lock_acquire_isr(&ctx->lock, &lock_context);
0106     handler = ctx->handler;
0107     arg = ctx->arg;
0108     rtems_interrupt_lock_release(&ctx->lock, &lock_context);
0109 
0110     if (handler != NULL) {
0111         (*handler)(arg, event, T_SCHEDULER_BEFORE);
0112     }
0113 }
0114 
0115 static void
0116 T_scheduler_record_event(T_scheduler_event *event)
0117 {
0118     T_scheduler_context *ctx;
0119     rtems_interrupt_lock_context lock_context;
0120     T_scheduler_log *log;
0121     T_scheduler_event_handler handler;
0122 
0123     ctx = &T_scheduler_instance;
0124     log = ctx->active;
0125     handler = ctx->handler;
0126 
0127     if (log == NULL && handler == NULL) {
0128         return;
0129     }
0130 
0131     rtems_interrupt_lock_acquire(&ctx->lock, &lock_context);
0132 
0133 #ifdef RTEMS_SMP
0134     handler = ctx->handler;
0135 #endif
0136 
0137     if (handler != NULL) {
0138         void *arg;
0139 
0140         arg = ctx->arg;
0141 
0142         rtems_interrupt_lock_release(&ctx->lock, &lock_context);
0143         (*handler)(arg, event, T_SCHEDULER_AFTER);
0144         rtems_interrupt_lock_acquire(&ctx->lock, &lock_context);
0145     }
0146 
0147 #ifdef RTEMS_SMP
0148     log = ctx->active;
0149 #endif
0150 
0151     if (log != NULL) {
0152         size_t recorded;
0153 
0154         ++log->header.operations;
0155         recorded = log->header.recorded;
0156 
0157         if (recorded < log->header.capacity) {
0158             log->header.recorded = recorded + 1;
0159             log->events[recorded] = *event;
0160         }
0161     }
0162 
0163     rtems_interrupt_lock_release(&ctx->lock, &lock_context);
0164 }
0165 
0166 T_scheduler_log *
0167 T_scheduler_record(T_scheduler_log *log)
0168 {
0169     rtems_interrupt_lock_context lock_context;
0170     T_scheduler_log *previous;
0171     T_scheduler_context *ctx;
0172 
0173     if (log != NULL) {
0174         log->header.recorded = 0;
0175         log->header.operations = 0;
0176     }
0177 
0178     ctx = &T_scheduler_instance;
0179 
0180     rtems_interrupt_lock_acquire(&ctx->lock, &lock_context);
0181     previous = ctx->active;
0182     ctx->active = log;
0183     rtems_interrupt_lock_release(&ctx->lock, &lock_context);
0184 
0185     return previous;
0186 }
0187 
0188 T_scheduler_log *
0189 T_scheduler_record_2(T_scheduler_log_2 *log)
0190 {
0191     log->header.capacity = T_ARRAY_SIZE(log->events);
0192     return T_scheduler_record((T_scheduler_log *)log);
0193 }
0194 
0195 T_scheduler_log *
0196 T_scheduler_record_4(T_scheduler_log_4 *log)
0197 {
0198     log->header.capacity = T_ARRAY_SIZE(log->events);
0199     return T_scheduler_record((T_scheduler_log *)log);
0200 }
0201 
0202 T_scheduler_log *
0203 T_scheduler_record_10(T_scheduler_log_10 *log)
0204 {
0205     log->header.capacity = T_ARRAY_SIZE(log->events);
0206     return T_scheduler_record((T_scheduler_log *)log);
0207 }
0208 
0209 T_scheduler_log *
0210 T_scheduler_record_20(T_scheduler_log_20 *log)
0211 {
0212     log->header.capacity = T_ARRAY_SIZE(log->events);
0213     return T_scheduler_record((T_scheduler_log *)log);
0214 }
0215 
0216 T_scheduler_log *
0217 T_scheduler_record_40(T_scheduler_log_40 *log)
0218 {
0219     log->header.capacity = T_ARRAY_SIZE(log->events);
0220     return T_scheduler_record((T_scheduler_log *)log);
0221 }
0222 
0223 const T_scheduler_event T_scheduler_event_null;
0224 
0225 const T_scheduler_event *
0226 T_scheduler_next(T_scheduler_header *header, T_scheduler_operation operation,
0227     size_t *index)
0228 {
0229     T_scheduler_log *log;
0230     size_t i;
0231 
0232     log = (T_scheduler_log *)header;
0233 
0234     if (log == NULL) {
0235         return &T_scheduler_event_null;
0236     }
0237 
0238     i = *index;
0239 
0240     while (i < log->header.recorded) {
0241         if (operation == T_SCHEDULER_ANY ||
0242             operation == log->events[i].operation) {
0243             *index = i + 1;
0244             return &log->events[i];
0245         }
0246 
0247         ++i;
0248     }
0249 
0250     return &T_scheduler_event_null;
0251 }
0252 
0253 const T_scheduler_event *
0254 T_scheduler_next_any(T_scheduler_header *header, size_t *index)
0255 {
0256     return T_scheduler_next(header, T_SCHEDULER_ANY, index);
0257 }
0258 
0259 void
0260 T_scheduler_initialize(const Scheduler_Control *scheduler)
0261 {
0262     T_scheduler_event event = {
0263         .operation = T_SCHEDULER_INITIALIZE
0264     };
0265     const Scheduler_Operations *operations;
0266 
0267     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0268     T_scheduler_before_operation(&event);
0269     (*operations->initialize)(scheduler);
0270     T_scheduler_record_event(&event);
0271 }
0272 
0273 void
0274 T_scheduler_schedule(const Scheduler_Control *scheduler,
0275    Thread_Control *thread)
0276 {
0277     T_scheduler_event event = {
0278         .operation = T_SCHEDULER_SCHEDULE,
0279         .thread = thread
0280     };
0281     const Scheduler_Operations *operations;
0282 
0283     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0284     T_scheduler_before_operation(&event);
0285     (*operations->schedule)(scheduler, thread);
0286     T_scheduler_record_event(&event);
0287 }
0288 
0289 void
0290 T_scheduler_yield(const Scheduler_Control *scheduler, Thread_Control *thread,
0291     Scheduler_Node *node)
0292 {
0293     T_scheduler_event event = {
0294         .operation = T_SCHEDULER_YIELD,
0295         .thread = thread,
0296         .node = node
0297     };
0298     const Scheduler_Operations *operations;
0299 
0300     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0301     T_scheduler_before_operation(&event);
0302     (*operations->yield)(scheduler, thread, node);
0303     T_scheduler_record_event(&event);
0304 }
0305 
0306 void
0307 T_scheduler_block(const Scheduler_Control *scheduler, Thread_Control *thread,
0308     Scheduler_Node *node)
0309 {
0310     T_scheduler_event event = {
0311         .operation = T_SCHEDULER_BLOCK,
0312         .thread = thread,
0313         .node = node
0314     };
0315     const Scheduler_Operations *operations;
0316 
0317     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0318     T_scheduler_before_operation(&event);
0319     (*operations->block)(scheduler, thread, node);
0320     T_scheduler_record_event(&event);
0321 }
0322 
0323 void
0324 T_scheduler_unblock(const Scheduler_Control *scheduler, Thread_Control *thread,
0325     Scheduler_Node *node)
0326 {
0327     T_scheduler_event event = {
0328         .operation = T_SCHEDULER_UNBLOCK,
0329         .thread = thread,
0330         .node = node
0331     };
0332     const Scheduler_Operations *operations;
0333 
0334     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0335     T_scheduler_before_operation(&event);
0336     (*operations->unblock)(scheduler, thread, node);
0337     T_scheduler_record_event(&event);
0338 }
0339 
0340 void
0341 T_scheduler_update_priority(const Scheduler_Control *scheduler,
0342     Thread_Control *thread, Scheduler_Node *node)
0343 {
0344     T_scheduler_event event = {
0345         .operation = T_SCHEDULER_UPDATE_PRIORITY,
0346         .thread = thread,
0347         .node = node
0348     };
0349     const Scheduler_Operations *operations;
0350 
0351     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0352     T_scheduler_before_operation(&event);
0353     (*operations->update_priority)(scheduler, thread, node);
0354     T_scheduler_record_event(&event);
0355 }
0356 
0357 Priority_Control T_scheduler_map_priority(const Scheduler_Control *scheduler,
0358     Priority_Control priority)
0359 {
0360     T_scheduler_event event = {
0361         .operation = T_SCHEDULER_MAP_PRIORITY
0362     };
0363     const Scheduler_Operations *operations;
0364 
0365     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0366     event.map_unmap_priority.in = priority;
0367     T_scheduler_before_operation(&event);
0368     event.map_unmap_priority.out = (*operations->map_priority)(scheduler,
0369         priority);
0370     T_scheduler_record_event(&event);
0371     return event.map_unmap_priority.out;
0372 }
0373 
0374 Priority_Control T_scheduler_unmap_priority(const Scheduler_Control *scheduler,
0375     Priority_Control priority)
0376 {
0377     T_scheduler_event event = {
0378         .operation = T_SCHEDULER_UNMAP_PRIORITY
0379     };
0380     const Scheduler_Operations *operations;
0381 
0382     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0383     event.map_unmap_priority.in = priority;
0384     T_scheduler_before_operation(&event);
0385     event.map_unmap_priority.out = (*operations->unmap_priority)(scheduler,
0386         priority);
0387     T_scheduler_record_event(&event);
0388     return event.map_unmap_priority.out;
0389 }
0390 
0391 void
0392 T_scheduler_node_initialize(const Scheduler_Control *scheduler,
0393     Scheduler_Node *node, Thread_Control *thread, Priority_Control priority)
0394 {
0395     T_scheduler_event event = {
0396         .operation = T_SCHEDULER_NODE_INITIALIZE,
0397         .thread = thread,
0398         .node = node
0399     };
0400     const Scheduler_Operations *operations;
0401 
0402     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0403     T_scheduler_before_operation(&event);
0404     (*operations->node_initialize)(scheduler, node, thread, priority);
0405     T_scheduler_record_event(&event);
0406 }
0407 
0408 void
0409 T_scheduler_node_destroy(const Scheduler_Control *scheduler,
0410     Scheduler_Node *node)
0411 {
0412     T_scheduler_event event = {
0413         .operation = T_SCHEDULER_NODE_DESTROY,
0414         .node = node
0415     };
0416     const Scheduler_Operations *operations;
0417 
0418     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0419     T_scheduler_before_operation(&event);
0420     (*operations->node_destroy)(scheduler, node);
0421     T_scheduler_record_event(&event);
0422 }
0423 
0424 void
0425 T_scheduler_release_job(const Scheduler_Control *scheduler,
0426     Thread_Control *thread, Priority_Node *priority, uint64_t deadline,
0427     Thread_queue_Context *queue_context)
0428 {
0429     T_scheduler_event event = {
0430         .operation = T_SCHEDULER_RELEASE_JOB,
0431         .thread = thread
0432     };
0433     const Scheduler_Operations *operations;
0434 
0435     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0436     event.release_job.priority = priority;
0437     event.release_job.deadline = deadline;
0438     T_scheduler_before_operation(&event);
0439     (*operations->release_job)(scheduler, thread, priority, deadline, queue_context);
0440     T_scheduler_record_event(&event);
0441 }
0442 
0443 void
0444 T_scheduler_cancel_job(const Scheduler_Control *scheduler,
0445     Thread_Control *thread, Priority_Node *priority,
0446     Thread_queue_Context *queue_context)
0447 {
0448     T_scheduler_event event = {
0449         .operation = T_SCHEDULER_CANCEL_JOB,
0450         .thread = thread
0451     };
0452     const Scheduler_Operations *operations;
0453 
0454     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0455     event.cancel_job.priority = priority;
0456     T_scheduler_before_operation(&event);
0457     (*operations->cancel_job)(scheduler, thread, priority, queue_context);
0458     T_scheduler_record_event(&event);
0459 }
0460 
0461 void
0462 T_scheduler_start_idle(const Scheduler_Control *scheduler,
0463     Thread_Control *thread, Per_CPU_Control *cpu)
0464 {
0465     T_scheduler_event event = {
0466         .operation = T_SCHEDULER_START_IDLE,
0467         .thread = thread
0468     };
0469     const Scheduler_Operations *operations;
0470 
0471     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0472     T_scheduler_before_operation(&event);
0473     (*operations->start_idle)(scheduler, thread, cpu);
0474     T_scheduler_record_event(&event);
0475 }
0476 
0477 #ifdef RTEMS_SMP
0478 bool
0479 T_scheduler_ask_for_help(const Scheduler_Control *scheduler,
0480     Thread_Control *thread, Scheduler_Node *node)
0481 {
0482     T_scheduler_event event = {
0483         .operation = T_SCHEDULER_ASK_FOR_HELP,
0484         .thread = thread,
0485         .node = node
0486     };
0487     const Scheduler_Operations *operations;
0488 
0489     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0490     T_scheduler_before_operation(&event);
0491     event.ask_for_help.success = (*operations->ask_for_help)(scheduler,
0492         thread, node);
0493     T_scheduler_record_event(&event);
0494     return event.ask_for_help.success;
0495 }
0496 
0497 void
0498 T_scheduler_reconsider_help_request(const Scheduler_Control *scheduler,
0499     Thread_Control *thread, Scheduler_Node *node)
0500 {
0501     T_scheduler_event event = {
0502         .operation = T_SCHEDULER_RECONSIDER_HELP_REQUEST,
0503         .thread = thread,
0504         .node = node
0505     };
0506     const Scheduler_Operations *operations;
0507 
0508     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0509     T_scheduler_before_operation(&event);
0510     (*operations->reconsider_help_request)(scheduler, thread, node);
0511     T_scheduler_record_event(&event);
0512 }
0513 
0514 void
0515 T_scheduler_withdraw_node(const Scheduler_Control *scheduler,
0516     Thread_Control *thread, Scheduler_Node *node,
0517     Thread_Scheduler_state next_state)
0518 {
0519     T_scheduler_event event = {
0520         .operation = T_SCHEDULER_WITHDRAW_NODE,
0521         .thread = thread,
0522         .node = node
0523     };
0524     const Scheduler_Operations *operations;
0525 
0526     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0527     event.withdraw_node.next_state = next_state;
0528     T_scheduler_before_operation(&event);
0529     (*operations->withdraw_node)(scheduler, thread, node, next_state);
0530     T_scheduler_record_event(&event);
0531 }
0532 
0533 void
0534 T_scheduler_make_sticky(const Scheduler_Control *scheduler, Thread_Control *thread,
0535     Scheduler_Node *node)
0536 {
0537     T_scheduler_event event = {
0538         .operation = T_SCHEDULER_MAKE_STICKY,
0539         .thread = thread,
0540         .node = node
0541     };
0542     const Scheduler_Operations *operations;
0543 
0544     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0545     T_scheduler_before_operation(&event);
0546     (*operations->make_sticky)(scheduler, thread, node);
0547     T_scheduler_record_event(&event);
0548 }
0549 
0550 void
0551 T_scheduler_clean_sticky(const Scheduler_Control *scheduler, Thread_Control *thread,
0552     Scheduler_Node *node)
0553 {
0554     T_scheduler_event event = {
0555         .operation = T_SCHEDULER_CLEAN_STICKY,
0556         .thread = thread,
0557         .node = node
0558     };
0559     const Scheduler_Operations *operations;
0560 
0561     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0562     T_scheduler_before_operation(&event);
0563     (*operations->clean_sticky)(scheduler, thread, node);
0564     T_scheduler_record_event(&event);
0565 }
0566 
0567 void
0568 T_scheduler_pin(const Scheduler_Control *scheduler, Thread_Control *thread,
0569     Scheduler_Node *node, Per_CPU_Control *cpu)
0570 {
0571     T_scheduler_event event = {
0572         .operation = T_SCHEDULER_PIN,
0573         .thread = thread,
0574         .node = node
0575     };
0576     const Scheduler_Operations *operations;
0577 
0578     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0579     event.pin_unpin.cpu = cpu;
0580     T_scheduler_before_operation(&event);
0581     (*operations->pin)(scheduler, thread, node, cpu);
0582     T_scheduler_record_event(&event);
0583 }
0584 
0585 void
0586 T_scheduler_unpin(const Scheduler_Control *scheduler, Thread_Control *thread,
0587     Scheduler_Node *node, Per_CPU_Control *cpu)
0588 {
0589     T_scheduler_event event = {
0590         .operation = T_SCHEDULER_UNPIN,
0591         .thread = thread,
0592         .node = node
0593     };
0594     const Scheduler_Operations *operations;
0595 
0596     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0597     event.pin_unpin.cpu = cpu;
0598     T_scheduler_before_operation(&event);
0599     (*operations->unpin)(scheduler, thread, node, cpu);
0600     T_scheduler_record_event(&event);
0601 }
0602 
0603 void
0604 T_scheduler_add_processor(const Scheduler_Control *scheduler,
0605     Thread_Control *idle)
0606 {
0607     T_scheduler_event event = {
0608         .operation = T_SCHEDULER_ADD_PROCESSOR,
0609         .thread = idle
0610     };
0611     const Scheduler_Operations *operations;
0612 
0613     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0614     event.add_processor.idle = idle;
0615     T_scheduler_before_operation(&event);
0616     (*operations->add_processor)(scheduler, idle);
0617     T_scheduler_record_event(&event);
0618 }
0619 
0620 Thread_Control *
0621 T_scheduler_remove_processor(const Scheduler_Control *scheduler,
0622     Per_CPU_Control *cpu)
0623 {
0624     T_scheduler_event event = {
0625         .operation = T_SCHEDULER_REMOVE_PROCESSOR
0626     };
0627     const Scheduler_Operations *operations;
0628 
0629     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0630     event.remove_processor.cpu = cpu;
0631     T_scheduler_before_operation(&event);
0632     event.remove_processor.idle =
0633         (*operations->remove_processor)(scheduler, cpu);
0634     T_scheduler_record_event(&event);
0635     return event.remove_processor.idle;
0636 }
0637 
0638 Status_Control
0639 T_scheduler_set_affinity(const Scheduler_Control *scheduler,
0640     Thread_Control *thread, Scheduler_Node *node,
0641     const Processor_mask *affinity)
0642 {
0643     T_scheduler_event event = {
0644         .operation = T_SCHEDULER_SET_AFFINITY,
0645         .thread = thread,
0646         .node = node
0647     };
0648     const Scheduler_Operations *operations;
0649 
0650     operations = &T_scheduler_operations[_Scheduler_Get_index(scheduler)];
0651     event.set_affinity.affinity = *affinity;
0652     T_scheduler_before_operation(&event);
0653     event.set_affinity.status = (*operations->set_affinity)(scheduler,
0654         thread, node, affinity);
0655     T_scheduler_record_event(&event);
0656     return event.set_affinity.status;
0657 }
0658 #endif