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 thread switch
0009  *   recorder.
0010  */
0011 
0012 /*
0013  * Copyright (C) 2020 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.h>
0042 
0043 #include <rtems.h>
0044 #include <rtems/score/percpu.h>
0045 #include <rtems/score/smp.h>
0046 #include <rtems/score/thread.h>
0047 #include <rtems/score/userextimpl.h>
0048 
0049 typedef struct {
0050     RTEMS_INTERRUPT_LOCK_MEMBER(lock)
0051     T_thread_switch_log *active;
0052     User_extensions_Control ext;
0053     T_destructor dtor;
0054 } T_thread_switch_context;
0055 
0056 static void T_thread_switch_recorder(Thread_Control *, Thread_Control *);
0057 
0058 static T_thread_switch_context T_thread_switch_instance = {
0059 #ifdef RTEMS_SMP
0060     .lock = RTEMS_INTERRUPT_LOCK_INITIALIZER("Test Thread Switches"),
0061 #endif
0062     .ext = {
0063         .Callouts = {
0064             .thread_switch = T_thread_switch_recorder
0065         }
0066     }
0067 };
0068 
0069 static void
0070 T_thread_switch_destroy(T_destructor *dtor)
0071 {
0072     T_thread_switch_context *ctx;
0073 
0074     ctx = RTEMS_CONTAINER_OF(dtor, T_thread_switch_context, dtor);
0075     _User_extensions_Remove_set(&ctx->ext);
0076     _Chain_Set_off_chain(&ctx->ext.Node);
0077 }
0078 
0079 static void
0080 T_thread_switch_recorder(Thread_Control *executing, Thread_Control *heir)
0081 {
0082     rtems_interrupt_lock_context lock_context;
0083     T_thread_switch_context *ctx;
0084     T_thread_switch_log *log;
0085 
0086     ctx = &T_thread_switch_instance;
0087 
0088 #ifdef RTEMS_SMP
0089     if (ctx->active == NULL) {
0090         return;
0091     }
0092 #endif
0093 
0094     rtems_interrupt_lock_acquire_isr(&ctx->lock, &lock_context);
0095     log = ctx->active;
0096 
0097     if (log != NULL) {
0098         size_t recorded;
0099 
0100         ++log->header.switches;
0101         recorded = log->header.recorded;
0102 
0103         if (recorded < log->header.capacity) {
0104             log->header.recorded = recorded + 1;
0105             log->events[recorded].executing = executing->Object.id;
0106             log->events[recorded].heir = heir->Object.id;
0107             log->events[recorded].cpu =
0108                 _SMP_Get_current_processor();
0109             log->events[recorded].instant = T_now();
0110         }
0111     }
0112 
0113     rtems_interrupt_lock_release_isr(&ctx->lock, &lock_context);
0114 }
0115 
0116 T_thread_switch_log *
0117 T_thread_switch_record(T_thread_switch_log *log)
0118 {
0119     rtems_interrupt_lock_context lock_context;
0120     T_thread_switch_log *previous;
0121     T_thread_switch_context *ctx;
0122 
0123     ctx = &T_thread_switch_instance;
0124 
0125     if (_Chain_Is_node_off_chain(&ctx->ext.Node)) {
0126         _User_extensions_Add_set(&ctx->ext);
0127         T_add_destructor(&ctx->dtor, T_thread_switch_destroy);
0128     }
0129 
0130     if (log != NULL) {
0131         log->header.recorded = 0;
0132         log->header.switches = 0;
0133     }
0134 
0135     rtems_interrupt_lock_acquire(&ctx->lock, &lock_context);
0136     previous = ctx->active;
0137     ctx->active = log;
0138     rtems_interrupt_lock_release(&ctx->lock, &lock_context);
0139 
0140     return previous;
0141 }
0142 
0143 T_thread_switch_log *
0144 T_thread_switch_record_2(T_thread_switch_log_2 *log)
0145 {
0146     log->header.capacity = T_ARRAY_SIZE(log->events);
0147     return T_thread_switch_record((T_thread_switch_log *)log);
0148 }
0149 
0150 T_thread_switch_log *
0151 T_thread_switch_record_4(T_thread_switch_log_4 *log)
0152 {
0153     log->header.capacity = T_ARRAY_SIZE(log->events);
0154     return T_thread_switch_record((T_thread_switch_log *)log);
0155 }
0156 
0157 T_thread_switch_log *
0158 T_thread_switch_record_10(T_thread_switch_log_10 *log)
0159 {
0160     log->header.capacity = T_ARRAY_SIZE(log->events);
0161     return T_thread_switch_record((T_thread_switch_log *)log);
0162 }