Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @brief RTEMS Performance Monitoring and Measurement Framework.
0007  *
0008  * This is the Capture Engine component.
0009  */
0010 
0011 /*
0012  * Copyright 2002, 2016 Chris Johns <chrisj@rtems.org>.
0013  * All rights reserved.
0014  *
0015  * COPYRIGHT (c) 1989-2014.
0016  * On-Line Applications Research Corporation (OAR).
0017  *
0018  * Redistribution and use in source and binary forms, with or without
0019  * modification, are permitted provided that the following conditions
0020  * are met:
0021  * 1. Redistributions of source code must retain the above copyright
0022  *    notice, this list of conditions and the following disclaimer.
0023  * 2. Redistributions in binary form must reproduce the above copyright
0024  *    notice, this list of conditions and the following disclaimer in the
0025  *    documentation and/or other materials provided with the distribution.
0026  *
0027  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0028  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0029  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0030  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0031  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0032  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0033  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0034  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0035  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0036  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0037  * POSSIBILITY OF SUCH DAMAGE.
0038  */
0039 
0040 #ifdef HAVE_CONFIG_H
0041 #include "config.h"
0042 #endif
0043 
0044 #include <stdlib.h>
0045 #include <string.h>
0046 
0047 #include <rtems/captureimpl.h>
0048 #include "capture_buffer.h"
0049 
0050 /*
0051  * These events are always recorded and are not part of the
0052  * watch filters.
0053  *
0054  * This feature has been disabled as it becomes confusing when
0055  * setting up filters and some event leak.
0056  */
0057 #if defined (RTEMS_CAPTURE_ENGINE_ALLOW_RELATED_EVENTS)
0058 #define RTEMS_CAPTURE_RECORD_EVENTS  (RTEMS_CAPTURE_CREATED_BY_EVENT | \
0059                                       RTEMS_CAPTURE_CREATED_EVENT | \
0060                                       RTEMS_CAPTURE_STARTED_BY_EVENT | \
0061                                       RTEMS_CAPTURE_STARTED_EVENT | \
0062                                       RTEMS_CAPTURE_RESTARTED_BY_EVENT | \
0063                                       RTEMS_CAPTURE_RESTARTED_EVENT | \
0064                                       RTEMS_CAPTURE_DELETED_BY_EVENT | \
0065                                       RTEMS_CAPTURE_DELETED_EVENT | \
0066                                       RTEMS_CAPTURE_BEGIN_EVENT | \
0067                                       RTEMS_CAPTURE_EXITTED_EVENT | \
0068                                       RTEMS_CAPTURE_TERMINATED_EVENT | \
0069                                       RTEMS_CAPTURE_AUTOGEN_ENTRY_EVENT | \
0070                                       RTEMS_CAPTURE_AUTOGEN_EXIT_EVENT)
0071 #else
0072 #define RTEMS_CAPTURE_RECORD_EVENTS  (0)
0073 #endif
0074 
0075 typedef struct {
0076   rtems_capture_buffer records;
0077   uint32_t             count;
0078   rtems_id             reader;
0079   rtems_interrupt_lock lock;
0080   uint32_t             flags;
0081 } rtems_capture_per_cpu_data;
0082 
0083 typedef struct {
0084   uint32_t                flags;
0085   rtems_capture_control*  controls;
0086   int                     extension_index;
0087   rtems_capture_timestamp timestamp;
0088   rtems_task_priority     ceiling;
0089   rtems_task_priority     floor;
0090   rtems_interrupt_lock    lock;
0091 } rtems_capture_global_data;
0092 
0093 static rtems_capture_per_cpu_data  *capture_per_cpu = NULL;
0094 
0095 static rtems_capture_global_data capture_global = {
0096   .lock = RTEMS_INTERRUPT_LOCK_INITIALIZER( "Capture" )
0097 };
0098 
0099 /*
0100  * RTEMS Capture Data.
0101  */
0102 #define capture_per_cpu_get( _cpu ) \
0103    ( &capture_per_cpu[ _cpu ] )
0104 
0105 #define capture_records_on_cpu( _cpu ) capture_per_cpu[ _cpu ].records
0106 #define capture_count_on_cpu( _cpu )   capture_per_cpu[ _cpu ].count
0107 #define capture_flags_on_cpu( _cpu )   capture_per_cpu[ _cpu ].flags
0108 #define capture_reader_on_cpu( _cpu )  capture_per_cpu[ _cpu ].reader
0109 #define capture_lock_on_cpu( _cpu )    capture_per_cpu[ _cpu ].lock
0110 
0111 #define capture_flags_global     capture_global.flags
0112 #define capture_controls         capture_global.controls
0113 #define capture_extension_index  capture_global.extension_index
0114 #define capture_timestamp        capture_global.timestamp
0115 #define capture_ceiling          capture_global.ceiling
0116 #define capture_floor            capture_global.floor
0117 #define capture_lock_global      capture_global.lock
0118 
0119 /*
0120  * RTEMS Event text.
0121  */
0122 static const char * const capture_event_text[] =
0123 {
0124   "CREATED_BY",
0125   "CREATED",
0126   "STARTED_BY",
0127   "STARTED",
0128   "RESTARTED_BY",
0129   "RESTARTED",
0130   "DELETED_BY",
0131   "DELETED",
0132   "TERMINATED",
0133   "BEGIN",
0134   "EXITTED",
0135   "SWITCHED_OUT",
0136   "SWITCHED_IN",
0137   "TIMESTAMP"
0138 };
0139 
0140 void rtems_capture_set_extension_index(int index)
0141 {
0142   capture_extension_index = index;
0143 }
0144 
0145 int  rtems_capture_get_extension_index(void)
0146 {
0147   return capture_extension_index;
0148 }
0149 
0150 uint32_t rtems_capture_get_flags(void)
0151 {
0152   return capture_flags_global;
0153 }
0154 
0155 void rtems_capture_set_flags(uint32_t mask)
0156 {
0157   capture_flags_global |= mask;
0158 }
0159 
0160 /*
0161  * This function returns the current time. If a handler is provided
0162  * by the user get the time from that.
0163  */
0164 void
0165 rtems_capture_get_time (rtems_capture_time* time)
0166 {
0167   if (capture_timestamp)
0168     capture_timestamp (time);
0169   else
0170   {
0171     *time = rtems_clock_get_uptime_nanoseconds ();
0172   }
0173 }
0174 
0175 /*
0176  * This function compares rtems_names. It protects the
0177  * capture engine from a change to the way names are supported
0178  * in RTEMS.
0179  */
0180 static inline bool
0181 rtems_capture_match_names (rtems_name lhs, rtems_name rhs)
0182 {
0183   return lhs == rhs;
0184 }
0185 
0186 /*
0187  * This function compares rtems_ids. It protects the
0188  * capture engine from a change to the way id are supported
0189  * in RTEMS.
0190  */
0191 static inline bool
0192 rtems_capture_match_ids (rtems_id lhs, rtems_id rhs)
0193 {
0194   return lhs == rhs;
0195 }
0196 
0197 /*
0198  * This function matches a name and/or id.
0199  */
0200 static inline bool
0201 rtems_capture_match_name_id (rtems_name lhs_name,
0202                              rtems_id   lhs_id,
0203                              rtems_name rhs_name,
0204                              rtems_id   rhs_id)
0205 {
0206   bool match_name;
0207 
0208   match_name = ((rtems_capture_task_api(lhs_id) != OBJECTS_POSIX_API) &&
0209                 (rtems_capture_task_api(rhs_id) != OBJECTS_POSIX_API));
0210 
0211   /*
0212    * The left hand side name or id could be 0 which means a wildcard.
0213    */
0214   if ((lhs_name == 0) && (lhs_id == rhs_id))
0215     return true;
0216   else if (match_name && ((lhs_id == 0) || (lhs_id == rhs_id)))
0217   {
0218     if (rtems_capture_match_names (lhs_name, rhs_name))
0219       return true;
0220   }
0221   return false;
0222 }
0223 
0224 /*
0225  * This function duplicates an rtems_names. It protects the
0226  * capture engine from a change to the way names are supported
0227  * in RTEMS.
0228  */
0229 static inline void
0230 rtems_capture_dup_name (rtems_name* dst, rtems_name src)
0231 {
0232   *dst = src;
0233 }
0234 
0235 /*
0236  * This function sees if a BY control is in the BY names. The use
0237  * of the valid_mask in this way assumes the number of trigger
0238  * tasks is the number of bits in uint32_t.
0239  */
0240 static inline bool
0241 rtems_capture_by_in_to (uint32_t               events,
0242                         rtems_tcb*             by,
0243                         rtems_capture_control* to)
0244 {
0245   uint32_t valid_mask = RTEMS_CAPTURE_CONTROL_FROM_MASK (0);
0246   uint32_t valid_remainder = 0xffffffff;
0247   int      i;
0248 
0249   for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
0250   {
0251     /*
0252      * If there are no more valid BY entries then
0253      * we are finished.
0254      */
0255     if ((valid_remainder & to->by_valid) == 0)
0256       break;
0257 
0258     /*
0259      * Is the froby entry valid and does its name or id match.
0260      */
0261     if ((valid_mask & to->by_valid) &&
0262         (to->by[i].trigger & events))
0263     {
0264       /*
0265        * We have the BY task on the right hand side so we
0266        * match with id's first then labels if the id's are
0267        * not set.
0268        */
0269       if (rtems_capture_match_name_id (to->by[i].name, to->by[i].id,
0270                                        rtems_capture_task_name( by ),
0271                                        by->Object.id))
0272         return 1;
0273     }
0274 
0275     valid_mask >>= 1;
0276     valid_remainder >>= 1;
0277   }
0278 
0279   return 0;
0280 }
0281 
0282 /*
0283  * This function searches for a trigger given a name.
0284  */
0285 static inline rtems_capture_control*
0286 rtems_capture_find_control (rtems_name name, rtems_id id)
0287 {
0288   rtems_capture_control* control;
0289   for (control = capture_controls; control != NULL; control = control->next)
0290     if (rtems_capture_match_name_id (name, id, control->name, control->id))
0291       break;
0292   return control;
0293 }
0294 
0295 /*
0296  * This function checks if a new control structure matches
0297  * the given task and sets the control if it does.
0298  */
0299 static bool
0300 rtems_capture_initialize_control (rtems_tcb *tcb, void *arg)
0301 {
0302   if (tcb->Capture.control == NULL)
0303   {
0304     rtems_name             name = rtems_build_name(0, 0, 0, 0);
0305     rtems_id               id;
0306     rtems_capture_control* control;
0307 
0308     /*
0309      * We need to scan the default control list to initialise
0310      * this control.
0311      */
0312     id = tcb->Object.id;
0313     if (rtems_capture_task_api (id) != OBJECTS_POSIX_API)
0314       rtems_object_get_classic_name (id, &name);
0315     for (control = capture_controls; control != NULL; control = control->next)
0316     {
0317       if (rtems_capture_match_name_id (control->name, control->id,
0318                                        name, id))
0319       {
0320         tcb->Capture.control = control;
0321         break;
0322       }
0323     }
0324   }
0325 
0326   return false;
0327 }
0328 
0329 static rtems_capture_control*
0330 rtems_capture_create_control (rtems_name name, rtems_id id)
0331 {
0332   rtems_interrupt_lock_context lock_context;
0333   rtems_capture_control*       control;
0334 
0335   if ((name == 0) && (id == 0))
0336     return NULL;
0337 
0338   control = rtems_capture_find_control (name, id);
0339 
0340   if (control == NULL)
0341   {
0342     control = malloc (sizeof (*control));
0343 
0344     if (!control)
0345     {
0346       capture_flags_global |= RTEMS_CAPTURE_NO_MEMORY;
0347       return NULL;
0348     }
0349 
0350     control->name          = name;
0351     control->id            = id;
0352     control->flags         = 0;
0353     control->to_triggers   = 0;
0354     control->from_triggers = 0;
0355     control->by_valid      = 0;
0356 
0357     memset (control->by, 0, sizeof (control->by));
0358 
0359     rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
0360 
0361     control->next    = capture_controls;
0362     capture_controls = control;
0363 
0364     _Thread_Iterate (rtems_capture_initialize_control, NULL);
0365 
0366     rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
0367   }
0368 
0369   return control;
0370 }
0371 
0372 void
0373 rtems_capture_record_lock (rtems_capture_record_lock_context* context)
0374 {
0375   rtems_capture_per_cpu_data* cpu;
0376   cpu = capture_per_cpu_get (rtems_scheduler_get_processor ());
0377   rtems_interrupt_lock_interrupt_disable (&context->lock_context);
0378   context->lock = &cpu->lock;
0379   rtems_interrupt_lock_acquire_isr (&cpu->lock, &context->lock_context);
0380 }
0381 
0382 void
0383 rtems_capture_record_unlock (rtems_capture_record_lock_context* context)
0384 {
0385   rtems_interrupt_lock_release (context->lock, &context->lock_context);
0386 }
0387 
0388 void*
0389 rtems_capture_record_open (rtems_tcb*                         tcb,
0390                            uint32_t                           events,
0391                            size_t                             size,
0392                            rtems_capture_record_lock_context* context)
0393 {
0394   rtems_capture_per_cpu_data* cpu;
0395   uint8_t*                    ptr;
0396 
0397   size += sizeof (rtems_capture_record);
0398 
0399   cpu = capture_per_cpu_get (rtems_scheduler_get_processor ());
0400 
0401   rtems_capture_record_lock (context);
0402 
0403   ptr = rtems_capture_buffer_allocate (&cpu->records, size);
0404   if (ptr != NULL)
0405   {
0406     rtems_capture_record in;
0407     rtems_capture_time time;
0408 
0409     ++cpu->count;
0410 
0411     if ((events & RTEMS_CAPTURE_RECORD_EVENTS) == 0)
0412       tcb->Capture.flags |= RTEMS_CAPTURE_TRACED;
0413 
0414     /*
0415      * Create a local copy then copy. The buffer maybe mis-aligned.
0416      */
0417     in.size    = size;
0418     in.task_id = tcb->Object.id;
0419     in.events  = (events |
0420                   rtems_capture_task_real_priority (tcb) |
0421                   (rtems_capture_task_curr_priority (tcb) << 8));
0422 
0423     rtems_capture_get_time (&time);
0424     in.time = time; /* need this since in is a packed struct */
0425 
0426     ptr = rtems_capture_record_append(ptr, &in, sizeof(in));
0427   }
0428   else
0429     cpu->flags |= RTEMS_CAPTURE_OVERFLOW;
0430 
0431   return ptr;
0432 }
0433 
0434 void
0435 rtems_capture_record_close (rtems_capture_record_lock_context* context)
0436 {
0437   rtems_capture_record_unlock (context);
0438 }
0439 
0440 void
0441 rtems_capture_initialize_task( rtems_tcb* tcb )
0442 {
0443   rtems_capture_control*       control;
0444   rtems_name                   name = rtems_build_name(0, 0, 0, 0);
0445   rtems_id                     id = rtems_capture_task_id (tcb);
0446   rtems_interrupt_lock_context lock_context;
0447 
0448   /*
0449    * We need to scan the default control list to initialize
0450    * this control if it is a new task.
0451    */
0452   if (rtems_capture_task_api (id) != OBJECTS_POSIX_API)
0453     rtems_object_get_classic_name (id, &name);
0454 
0455   rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
0456 
0457   if (tcb->Capture.control == NULL) {
0458     for (control = capture_controls; control != NULL; control = control->next)
0459       if (rtems_capture_match_name_id (control->name, control->id,
0460                                        name, id))
0461         tcb->Capture.control = control;
0462   }
0463 
0464   tcb->Capture.flags |= RTEMS_CAPTURE_INIT_TASK;
0465 
0466   rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
0467 }
0468 
0469 void rtems_capture_record_task (rtems_tcb* tcb)
0470 {
0471   rtems_name                        name = rtems_build_name (0, 0, 0, 0);
0472   rtems_id                          id = rtems_capture_task_id (tcb);
0473   rtems_capture_task_record         rec;
0474   void*                             ptr;
0475   rtems_interrupt_lock_context      lock_context;
0476   rtems_capture_record_lock_context rec_context;
0477 
0478   if (rtems_capture_task_api (id) != OBJECTS_POSIX_API)
0479     rtems_object_get_classic_name (id, &name);
0480 
0481   rec.name = name;
0482   rec.stack_size = tcb->Start.Initial_stack.size;
0483   rec.start_priority = rtems_capture_task_start_priority (tcb);
0484 
0485   rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
0486   tcb->Capture.flags |= RTEMS_CAPTURE_RECORD_TASK;
0487   rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
0488 
0489   /*
0490    *  Log the task information. The first time a task is seen a record is
0491    *  logged.  This record can be identified by a 0 in the event identifier.
0492    */
0493   ptr = rtems_capture_record_open (tcb, 0, sizeof(rec), &rec_context);
0494   if (ptr != NULL)
0495     rtems_capture_record_append(ptr, &rec, sizeof (rec));
0496   rtems_capture_record_close (&rec_context);
0497 }
0498 
0499 /*
0500  * This function indicates if data should be filtered from the
0501  * log.
0502  */
0503 bool rtems_capture_filter (rtems_tcb*  tcb, uint32_t events)
0504 {
0505   if (tcb &&
0506       ((capture_flags_global &
0507         (RTEMS_CAPTURE_TRIGGERED | RTEMS_CAPTURE_ONLY_MONITOR)) ==
0508        RTEMS_CAPTURE_TRIGGERED))
0509   {
0510     rtems_capture_control* control;
0511 
0512     control = tcb->Capture.control;
0513 
0514     /*
0515      * Capture the record if we have an event that is always
0516      * captured, or the task's real priority is greater than the
0517      * watch ceiling, and the global watch or task watch is enabled.
0518      */
0519     if ((events & RTEMS_CAPTURE_RECORD_EVENTS) ||
0520         ((rtems_capture_task_real_priority (tcb) >= capture_ceiling) &&
0521          (rtems_capture_task_real_priority (tcb) <= capture_floor) &&
0522          ((capture_flags_global & RTEMS_CAPTURE_GLOBAL_WATCH) ||
0523           (control && (control->flags & RTEMS_CAPTURE_WATCH)))))
0524     {
0525       return false;
0526     }
0527   }
0528 
0529   return true;
0530 }
0531 
0532 /*
0533  * See if we have triggered and if not see if this event is a
0534  * cause of a trigger.
0535  */
0536 bool
0537 rtems_capture_trigger_fired (rtems_tcb* ft, rtems_tcb* tt, uint32_t events)
0538 {
0539   /*
0540    * If we have not triggered then see if this is a trigger condition.
0541    */
0542   if (!(capture_flags_global & RTEMS_CAPTURE_TRIGGERED))
0543   {
0544     rtems_capture_control* fc = NULL;
0545     rtems_capture_control* tc = NULL;
0546     uint32_t               from_events = 0;
0547     uint32_t               to_events = 0;
0548     uint32_t               from_to_events = 0;
0549 
0550     if (ft)
0551     {
0552       fc = ft->Capture.control;
0553       if (fc)
0554         from_events = fc->from_triggers & events;
0555     }
0556 
0557     if (tt)
0558     {
0559       tc = tt->Capture.control;
0560       if (tc)
0561       {
0562         to_events = tc->to_triggers & events;
0563         if (ft && tc->by_valid)
0564           from_to_events = tc->by_triggers & events;
0565       }
0566     }
0567 
0568     /*
0569      * Check if we have any from or to events. These are the
0570      * from any or to any type triggers. All from/to triggers are
0571      * listed in the to's control with the from in the from list.
0572      *
0573      * The masking above means any flag set is a trigger.
0574      */
0575     if (from_events || to_events)
0576     {
0577       capture_flags_global |= RTEMS_CAPTURE_TRIGGERED;
0578       return true;
0579     }
0580 
0581     /*
0582      * Check the from->to events.
0583      */
0584     if (from_to_events)
0585     {
0586       if (rtems_capture_by_in_to (events, ft, tc))
0587       {
0588         capture_flags_global |= RTEMS_CAPTURE_TRIGGERED;
0589         return true;
0590       }
0591     }
0592 
0593     return false;
0594   }
0595 
0596   return true;
0597 }
0598 
0599 /*
0600  * This function initialises the realtime capture engine allocating the trace
0601  * buffer. It is assumed we have a working heap at stage of initialization.
0602  */
0603 rtems_status_code
0604 rtems_capture_open (uint32_t   size, rtems_capture_timestamp timestamp RTEMS_UNUSED)
0605 {
0606   rtems_status_code     sc = RTEMS_SUCCESSFUL;
0607   size_t                count;
0608   uint32_t              i;
0609   rtems_capture_buffer* buff;
0610 
0611   /*
0612    * See if the capture engine is already open.
0613    */
0614 
0615   if ((capture_flags_global & RTEMS_CAPTURE_INIT) == RTEMS_CAPTURE_INIT) {
0616     return RTEMS_RESOURCE_IN_USE;
0617   }
0618 
0619   count = rtems_scheduler_get_processor_maximum();
0620   if (capture_per_cpu == NULL) {
0621     capture_per_cpu = calloc( count, sizeof( *capture_per_cpu ) );
0622   }
0623 
0624   for (i=0; i<count; i++) {
0625     buff = &capture_records_on_cpu(i);
0626     rtems_capture_buffer_create( buff, size );
0627     if (buff->buffer == NULL) {
0628       sc = RTEMS_NO_MEMORY;
0629       break;
0630     }
0631 
0632     rtems_interrupt_lock_initialize(
0633       &capture_lock_on_cpu( i ),
0634       "Capture Per-CPU"
0635     );
0636   }
0637 
0638   capture_flags_global   = 0;
0639   capture_ceiling = 0;
0640   capture_floor   = 255;
0641   if (sc == RTEMS_SUCCESSFUL)
0642     sc = rtems_capture_user_extension_open();
0643 
0644   if (sc != RTEMS_SUCCESSFUL)
0645   {
0646     for (i=0; i<count; i++)
0647       rtems_capture_buffer_destroy( &capture_records_on_cpu(i));
0648   }  else {
0649     capture_flags_global |= RTEMS_CAPTURE_INIT;
0650   }
0651 
0652   return sc;
0653 }
0654 
0655 /*
0656  * This function shutdowns the capture engine and release any claimed
0657  * resources.  Capture control must be disabled prior to calling a close.
0658  */
0659 rtems_status_code
0660 rtems_capture_close (void)
0661 {
0662   rtems_interrupt_lock_context lock_context;
0663   rtems_capture_control*       control;
0664   rtems_status_code            sc;
0665   uint32_t                     cpu;
0666 
0667   rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
0668 
0669   if ((capture_flags_global & RTEMS_CAPTURE_INIT) != RTEMS_CAPTURE_INIT)
0670   {
0671     rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
0672     return RTEMS_SUCCESSFUL;
0673   }
0674 
0675   if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
0676   {
0677     rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
0678     return RTEMS_UNSATISFIED;
0679   }
0680 
0681   capture_flags_global &=
0682     ~(RTEMS_CAPTURE_ON | RTEMS_CAPTURE_ONLY_MONITOR | RTEMS_CAPTURE_INIT);
0683 
0684   rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
0685 
0686   /*
0687    * Delete the extension first. This means we are now able to
0688    * release the resources we have without them being used.
0689    */
0690 
0691   sc = rtems_capture_user_extension_close();
0692 
0693   if (sc != RTEMS_SUCCESSFUL)
0694     return sc;
0695 
0696   control = capture_controls;
0697 
0698   while (control)
0699   {
0700     rtems_capture_control* delete = control;
0701     control = control->next;
0702     free (delete);
0703   }
0704 
0705   capture_controls = NULL;
0706   for (cpu=0; cpu < rtems_scheduler_get_processor_maximum(); cpu++) {
0707     if (capture_records_on_cpu(cpu).buffer)
0708       rtems_capture_buffer_destroy( &capture_records_on_cpu(cpu) );
0709 
0710     rtems_interrupt_lock_destroy( &capture_lock_on_cpu( cpu ) );
0711   }
0712 
0713   free( capture_per_cpu );
0714   capture_per_cpu = NULL;
0715 
0716   return RTEMS_SUCCESSFUL;
0717 }
0718 
0719 rtems_status_code
0720 rtems_capture_set_control (bool enable)
0721 {
0722   rtems_interrupt_lock_context lock_context;
0723 
0724   rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
0725 
0726   if ((capture_flags_global & RTEMS_CAPTURE_INIT) != RTEMS_CAPTURE_INIT)
0727   {
0728     rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
0729     return RTEMS_UNSATISFIED;
0730   }
0731 
0732   if (enable)
0733     capture_flags_global |= RTEMS_CAPTURE_ON;
0734   else
0735     capture_flags_global &= ~RTEMS_CAPTURE_ON;
0736 
0737   rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
0738 
0739   return RTEMS_SUCCESSFUL;
0740 }
0741 
0742 /*
0743  * This function enable the monitor mode. When in the monitor mode
0744  * the tasks are monitored but no data is saved. This can be used
0745  * to profile the load on a system.
0746  */
0747 rtems_status_code
0748 rtems_capture_set_monitor (bool enable)
0749 {
0750   rtems_interrupt_lock_context lock_context;
0751 
0752   rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
0753 
0754   if ((capture_flags_global & RTEMS_CAPTURE_INIT) != RTEMS_CAPTURE_INIT)
0755   {
0756     rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
0757     return RTEMS_UNSATISFIED;
0758   }
0759 
0760   if (enable)
0761     capture_flags_global |= RTEMS_CAPTURE_ONLY_MONITOR;
0762   else
0763     capture_flags_global &= ~RTEMS_CAPTURE_ONLY_MONITOR;
0764 
0765   rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
0766 
0767   return RTEMS_SUCCESSFUL;
0768 }
0769 
0770 /*
0771  * This function clears the capture trace flag in the tcb.
0772  */
0773 static bool
0774 rtems_capture_flush_tcb (rtems_tcb *tcb, void *arg)
0775 {
0776   tcb->Capture.flags &= ~RTEMS_CAPTURE_TRACED;
0777   return false;
0778 }
0779 
0780 /*
0781  * This function flushes the capture buffer. The prime parameter allows the
0782  * capture engine to also be primed again.
0783  */
0784 rtems_status_code
0785 rtems_capture_flush (bool prime)
0786 {
0787   rtems_status_code sc = RTEMS_NOT_CONFIGURED;
0788   if (capture_per_cpu != NULL)
0789   {
0790     rtems_interrupt_lock_context lock_context_global;
0791     uint32_t                     cpu;
0792 
0793     rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context_global);
0794 
0795     if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
0796     {
0797       rtems_interrupt_lock_release (&capture_lock_global, &lock_context_global);
0798       return RTEMS_UNSATISFIED;
0799     }
0800 
0801     _Thread_Iterate (rtems_capture_flush_tcb, NULL);
0802 
0803     if (prime)
0804       capture_flags_global &= ~(RTEMS_CAPTURE_TRIGGERED | RTEMS_CAPTURE_OVERFLOW);
0805     else
0806       capture_flags_global &= ~RTEMS_CAPTURE_OVERFLOW;
0807 
0808     for (cpu=0; cpu < rtems_scheduler_get_processor_maximum(); cpu++) {
0809       RTEMS_INTERRUPT_LOCK_REFERENCE( lock, &(capture_lock_on_cpu( cpu )) )
0810       rtems_interrupt_lock_context lock_context_per_cpu;
0811 
0812       rtems_interrupt_lock_acquire (lock, &lock_context_per_cpu);
0813       capture_count_on_cpu(cpu) = 0;
0814       if (capture_records_on_cpu(cpu).buffer)
0815         rtems_capture_buffer_flush( &capture_records_on_cpu(cpu) );
0816       rtems_interrupt_lock_release (lock, &lock_context_per_cpu);
0817     }
0818 
0819     rtems_interrupt_lock_release (&capture_lock_global, &lock_context_global);
0820 
0821     sc = RTEMS_SUCCESSFUL;
0822   }
0823 
0824   return sc;
0825 }
0826 
0827 /*
0828  * This function defines a watch for a specific task given a name. A watch
0829  * causes it to be traced either in or out of context. The watch can be
0830  * optionally enabled or disabled with the set routine. It is disabled by
0831  * default.  A watch can only be defined when capture control is disabled
0832  */
0833 rtems_status_code
0834 rtems_capture_watch_add (rtems_name name, rtems_id id)
0835 {
0836   rtems_capture_control* control;
0837 
0838   if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
0839     return RTEMS_UNSATISFIED;
0840 
0841   if ((name == 0) && (id == 0))
0842     return RTEMS_UNSATISFIED;
0843 
0844   control = rtems_capture_find_control (name, id);
0845 
0846   if (control && !id)
0847     return RTEMS_TOO_MANY;
0848 
0849   if (!control)
0850     control = rtems_capture_create_control (name, id);
0851 
0852   if (!control)
0853     return RTEMS_NO_MEMORY;
0854 
0855   return RTEMS_SUCCESSFUL;
0856 }
0857 
0858 /*
0859  * This function removes a watch for a specific task given a name. The task
0860  * description will still exist if referenced by a trace record in the trace
0861  * buffer or a global watch is defined.  A watch can only be deleted when
0862  * capture control is disabled.
0863  */
0864 rtems_status_code
0865 rtems_capture_watch_del (rtems_name name, rtems_id id)
0866 {
0867   rtems_interrupt_lock_context lock_context;
0868   rtems_capture_control*       control;
0869   rtems_capture_control**      prev_control;
0870   bool                         found = false;
0871 
0872   if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
0873     return RTEMS_UNSATISFIED;
0874 
0875   /*
0876    * Should this test be for wildcards ?
0877    */
0878 
0879   for (prev_control = &capture_controls, control = capture_controls;
0880        control != NULL; )
0881   {
0882     if (rtems_capture_match_name_id (control->name, control->id, name, id))
0883     {
0884       rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
0885 
0886       *prev_control = control->next;
0887 
0888       rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
0889 
0890       free (control);
0891 
0892       control = *prev_control;
0893 
0894       found = true;
0895     }
0896     else
0897     {
0898       prev_control = &control->next;
0899       control      = control->next;
0900     }
0901   }
0902 
0903   if (found)
0904     return RTEMS_SUCCESSFUL;
0905 
0906   return RTEMS_INVALID_NAME;
0907 }
0908 
0909 /*
0910  * This function allows control of a watch. The watch can be enabled or
0911  * disabled.
0912  */
0913 rtems_status_code
0914 rtems_capture_watch_ctrl (rtems_name name, rtems_id id, bool enable)
0915 {
0916   rtems_interrupt_lock_context lock_context;
0917   rtems_capture_control*       control;
0918   bool                         found = false;
0919 
0920   if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
0921     return RTEMS_UNSATISFIED;
0922 
0923   /*
0924    * Find the control and then set the watch. It must exist before it can
0925    * be controlled.
0926    */
0927   for (control = capture_controls; control != NULL; control = control->next)
0928   {
0929     if (rtems_capture_match_name_id (control->name, control->id, name, id))
0930     {
0931       rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
0932 
0933       if (enable)
0934         control->flags |= RTEMS_CAPTURE_WATCH;
0935       else
0936         control->flags &= ~RTEMS_CAPTURE_WATCH;
0937 
0938       rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
0939 
0940       found = true;
0941     }
0942   }
0943 
0944   if (found)
0945     return RTEMS_SUCCESSFUL;
0946 
0947   return RTEMS_INVALID_NAME;
0948 }
0949 
0950 /*
0951  * This function allows control of a global watch. The watch can be enabled or
0952  * disabled. A global watch configures all tasks below the ceiling and above
0953  * the floor to be traced.
0954  */
0955 rtems_status_code
0956 rtems_capture_watch_global (bool enable)
0957 {
0958   rtems_interrupt_lock_context lock_context;
0959 
0960   rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
0961 
0962   /*
0963    * We need to keep specific and global watches separate so
0964    * a global enable/disable does not lose a specific watch.
0965    */
0966   if (enable)
0967     capture_flags_global |= RTEMS_CAPTURE_GLOBAL_WATCH;
0968   else
0969     capture_flags_global &= ~RTEMS_CAPTURE_GLOBAL_WATCH;
0970 
0971   rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
0972 
0973   return RTEMS_SUCCESSFUL;
0974 }
0975 
0976 /*
0977  * This function returns the global watch state.
0978  */
0979 bool
0980 rtems_capture_watch_global_on (void)
0981 {
0982   return capture_flags_global & RTEMS_CAPTURE_GLOBAL_WATCH ? 1 : 0;
0983 }
0984 
0985 /*
0986  * This function sets a watch ceiling. Tasks at or greating that the
0987  * ceiling priority are not watched. This is a simple way to monitor
0988  * an application and exclude system tasks running at a higher
0989  * priority level.
0990  */
0991 rtems_status_code
0992 rtems_capture_watch_ceiling (rtems_task_priority ceiling)
0993 {
0994   capture_ceiling = ceiling;
0995   return RTEMS_SUCCESSFUL;
0996 }
0997 
0998 /*
0999  * This function gets the watch ceiling.
1000  */
1001 rtems_task_priority
1002 rtems_capture_watch_get_ceiling (void)
1003 {
1004   return capture_ceiling;
1005 }
1006 
1007 /*
1008  * This function sets a watch floor. Tasks at or less that the
1009  * floor priority are not watched. This is a simple way to monitor
1010  * an application and exclude system tasks running at a lower
1011  * priority level.
1012  */
1013 rtems_status_code
1014 rtems_capture_watch_floor (rtems_task_priority floor)
1015 {
1016   capture_floor = floor;
1017   return RTEMS_SUCCESSFUL;
1018 }
1019 
1020 /*
1021  * This function gets the watch floor.
1022  */
1023 rtems_task_priority
1024 rtems_capture_watch_get_floor (void)
1025 {
1026   return capture_floor;
1027 }
1028 
1029 /*
1030  * Map the trigger to a bit mask.
1031  */
1032 static uint32_t
1033 rtems_capture_map_trigger (rtems_capture_trigger trigger)
1034 {
1035   /*
1036    * Transform the mode and trigger to a bit map.
1037    */
1038   switch (trigger)
1039   {
1040     case rtems_capture_switch:
1041       return RTEMS_CAPTURE_SWITCH;
1042     case rtems_capture_create:
1043       return RTEMS_CAPTURE_CREATE;
1044     case rtems_capture_start:
1045       return RTEMS_CAPTURE_START;
1046     case rtems_capture_restart:
1047       return RTEMS_CAPTURE_RESTART;
1048     case rtems_capture_delete:
1049       return RTEMS_CAPTURE_DELETE;
1050     case rtems_capture_begin:
1051       return RTEMS_CAPTURE_BEGIN;
1052     case rtems_capture_exitted:
1053       return RTEMS_CAPTURE_EXITTED;
1054     case rtems_capture_terminated:
1055       return RTEMS_CAPTURE_TERMINATED;
1056     default:
1057       break;
1058   }
1059   return 0;
1060 }
1061 
1062 /*
1063  * This function sets a trigger.
1064  *
1065  * This set trigger routine will create a capture control for the
1066  * target task. The task list is searched and any existing tasks
1067  * are linked to the new control.
1068  *
1069  * We can have a number of tasks that have the same name so we
1070  * search using names. This means a number of tasks can be
1071  * linked to single control.
1072  */
1073 rtems_status_code
1074 rtems_capture_set_trigger (rtems_name                 from_name,
1075                            rtems_id                   from_id,
1076                            rtems_name                 to_name,
1077                            rtems_id                   to_id,
1078                            rtems_capture_trigger_mode mode,
1079                            rtems_capture_trigger      trigger)
1080 {
1081   rtems_capture_control* control;
1082   uint32_t               flags;
1083 
1084   flags = rtems_capture_map_trigger (trigger);
1085 
1086   /*
1087    * The mode sets the opposite type of trigger. For example
1088    * FROM ANY means trigger when the event happens TO this
1089    * task. TO ANY means FROM this task.
1090    */
1091 
1092   if (mode == rtems_capture_to_any)
1093   {
1094     control = rtems_capture_create_control (from_name, from_id);
1095     if (control == NULL)
1096       return RTEMS_NO_MEMORY;
1097     control->from_triggers |= flags & RTEMS_CAPTURE_FROM_TRIGS;
1098   }
1099   else
1100   {
1101     control = rtems_capture_create_control (to_name, to_id);
1102     if (control == NULL)
1103       return RTEMS_NO_MEMORY;
1104     if (mode == rtems_capture_from_any)
1105       control->to_triggers |= flags;
1106     else
1107     {
1108       bool done = false;
1109       int  i;
1110 
1111       control->by_triggers |= flags;
1112 
1113       for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
1114       {
1115         if (rtems_capture_control_by_valid (control, i) &&
1116             ((control->by[i].name == from_name) ||
1117              (from_id && (control->by[i].id == from_id))))
1118         {
1119           control->by[i].trigger |= flags;
1120           done = true;
1121           break;
1122         }
1123       }
1124 
1125       if (!done)
1126       {
1127         for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
1128         {
1129           if (!rtems_capture_control_by_valid (control, i))
1130           {
1131             control->by_valid |= RTEMS_CAPTURE_CONTROL_FROM_MASK (i);
1132             control->by[i].name = from_name;
1133             control->by[i].id = from_id;
1134             control->by[i].trigger = flags;
1135             done = true;
1136             break;
1137           }
1138         }
1139       }
1140 
1141       if (!done)
1142         return RTEMS_TOO_MANY;
1143     }
1144   }
1145   return RTEMS_SUCCESSFUL;
1146 }
1147 
1148 /*
1149  * This function clear a trigger.
1150  */
1151 rtems_status_code
1152 rtems_capture_clear_trigger (rtems_name                 from_name,
1153                              rtems_id                   from_id,
1154                              rtems_name                 to_name,
1155                              rtems_id                   to_id,
1156                              rtems_capture_trigger_mode mode,
1157                              rtems_capture_trigger      trigger)
1158 {
1159   rtems_capture_control* control;
1160   uint32_t               flags;
1161 
1162   flags = rtems_capture_map_trigger (trigger);
1163 
1164   if (mode == rtems_capture_to_any)
1165   {
1166     control = rtems_capture_find_control (from_name, from_id);
1167     if (control == NULL)
1168     {
1169       if (from_id)
1170         return RTEMS_INVALID_ID;
1171       return RTEMS_INVALID_NAME;
1172     }
1173     control->from_triggers &= ~flags;
1174   }
1175   else
1176   {
1177     control = rtems_capture_find_control (to_name, to_id);
1178     if (control == NULL)
1179     {
1180       if (to_id)
1181         return RTEMS_INVALID_ID;
1182       return RTEMS_INVALID_NAME;
1183     }
1184     if (mode == rtems_capture_from_any)
1185       control->to_triggers &= ~flags;
1186     else
1187     {
1188       bool done = false;
1189       int  i;
1190 
1191       control->by_triggers &= ~flags;
1192 
1193       for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
1194       {
1195         if (rtems_capture_control_by_valid (control, i) &&
1196             ((control->by[i].name == from_name) ||
1197              (control->by[i].id == from_id)))
1198         {
1199           control->by[i].trigger &= ~trigger;
1200           if (control->by[i].trigger == 0)
1201             control->by_valid &= ~RTEMS_CAPTURE_CONTROL_FROM_MASK (i);
1202           done = true;
1203           break;
1204         }
1205       }
1206 
1207       if (!done)
1208       {
1209         if (from_id)
1210           return RTEMS_INVALID_ID;
1211         return RTEMS_INVALID_NAME;
1212       }
1213     }
1214   }
1215   return RTEMS_SUCCESSFUL;
1216 }
1217 
1218 static inline uint32_t
1219 rtems_capture_count_records (const void* records, size_t size)
1220 {
1221   const uint8_t* ptr = records;
1222   uint32_t       recs = 0;
1223   size_t         bytes = 0;
1224 
1225   while (bytes < size)
1226   {
1227     const rtems_capture_record* rec = (const rtems_capture_record*) ptr;
1228     recs++;
1229     ptr += rec->size;
1230     bytes += rec->size;
1231  }
1232 
1233  return recs;
1234 }
1235 
1236 /*
1237  * This function reads a number of records from the capture buffer.
1238  *
1239  * The function returns the number of record that is has that are
1240  * in a continous block of memory. If the number of available records
1241  * wrap then only those records are provided. This removes the need for
1242  * caller to be concerned about buffer wrappings. If the number of
1243  * requested records cannot be met due to the wrapping of the records
1244  * less than the specified number will be returned.
1245  *
1246  * The user must release the records. This is achieved with a call to
1247  * rtems_capture_release. Calls this function without a release will
1248  * result in at least the same number of records being released.
1249  */
1250 rtems_status_code
1251 rtems_capture_read (uint32_t cpu, size_t* read, const void** recs)
1252 {
1253   rtems_status_code sc = RTEMS_NOT_CONFIGURED;
1254   if (capture_per_cpu != NULL)
1255   {
1256     RTEMS_INTERRUPT_LOCK_REFERENCE (lock, &(capture_lock_on_cpu (cpu)))
1257     rtems_interrupt_lock_context lock_context;
1258     size_t                       recs_size = 0;
1259     rtems_capture_buffer*        records;
1260     uint32_t*                    flags;
1261 
1262     *read = 0;
1263     *recs = NULL;
1264 
1265     records = &(capture_records_on_cpu (cpu));
1266     flags = &(capture_flags_on_cpu (cpu));
1267 
1268     rtems_interrupt_lock_acquire (lock, &lock_context);
1269 
1270     /*
1271      * Only one reader is allowed.
1272      */
1273 
1274     if (*flags & RTEMS_CAPTURE_READER_ACTIVE)
1275     {
1276       rtems_interrupt_lock_release (lock, &lock_context);
1277       return RTEMS_RESOURCE_IN_USE;
1278     }
1279 
1280     if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
1281     {
1282       rtems_interrupt_lock_release (lock, &lock_context);
1283       return RTEMS_UNSATISFIED;
1284     }
1285 
1286     *flags |= RTEMS_CAPTURE_READER_ACTIVE;
1287 
1288     *recs = rtems_capture_buffer_peek( records, &recs_size );
1289 
1290     *read = rtems_capture_count_records( *recs, recs_size );
1291 
1292     rtems_interrupt_lock_release (lock, &lock_context);
1293 
1294     sc = RTEMS_SUCCESSFUL;
1295   }
1296 
1297   return sc;
1298 }
1299 
1300 /*
1301  * This function releases the requested number of record slots back
1302  * to the capture engine. The count must match the number read.
1303  */
1304 rtems_status_code
1305 rtems_capture_release (uint32_t cpu, uint32_t count)
1306 {
1307   rtems_status_code sc = RTEMS_NOT_CONFIGURED;
1308   if (capture_per_cpu != NULL)
1309   {
1310     rtems_interrupt_lock_context lock_context;
1311     uint8_t*                     ptr;
1312     rtems_capture_record*        rec;
1313     uint32_t                     counted;
1314     size_t                       ptr_size = 0;
1315     size_t                       rel_size = 0;
1316     RTEMS_INTERRUPT_LOCK_REFERENCE( lock, &(capture_lock_on_cpu( cpu )) )
1317     rtems_capture_buffer*        records = &(capture_records_on_cpu( cpu ));
1318     uint32_t*                    flags = &(capture_flags_on_cpu( cpu ));
1319     uint32_t*                    total = &(capture_count_on_cpu( cpu ));
1320 
1321     sc = RTEMS_SUCCESSFUL;
1322 
1323     rtems_interrupt_lock_acquire (lock, &lock_context);
1324 
1325     if (count > *total) {
1326       count = *total;
1327     }
1328 
1329     if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 ) {
1330       rtems_interrupt_lock_release (lock, &lock_context);
1331       return RTEMS_UNSATISFIED;
1332     }
1333 
1334     counted = count;
1335 
1336     ptr = rtems_capture_buffer_peek( records, &ptr_size );
1337     _Assert(ptr_size >= (count * sizeof(*rec) ));
1338 
1339     rel_size = 0;
1340     while (counted--) {
1341       rec = (rtems_capture_record*) ptr;
1342       rel_size += rec->size;
1343       _Assert( rel_size <= ptr_size );
1344       ptr += rec->size;
1345     }
1346 
1347     if (rel_size > ptr_size ) {
1348       sc = RTEMS_INVALID_NUMBER;
1349       rel_size = ptr_size;
1350     }
1351 
1352     *total -= count;
1353 
1354     if (count) {
1355       rtems_capture_buffer_free( records, rel_size );
1356     }
1357 
1358     *flags &= ~RTEMS_CAPTURE_READER_ACTIVE;
1359 
1360     rtems_interrupt_lock_release (lock, &lock_context);
1361   }
1362 
1363   return sc;
1364 }
1365 
1366 /*
1367  * This function returns a string for an event based on the bit in the
1368  * event. The functions takes the bit offset as a number not the bit
1369  * set in a bit map.
1370  */
1371 const char*
1372 rtems_capture_event_text (int event)
1373 {
1374   if ((event < RTEMS_CAPTURE_EVENT_START) || (event > RTEMS_CAPTURE_EVENT_END))
1375     return "invalid event id";
1376   return capture_event_text[event - RTEMS_CAPTURE_EVENT_START];
1377 }
1378 
1379 /*
1380  * This function returns the head of the list of control in the
1381  * capture engine.
1382  */
1383 rtems_capture_control*
1384 rtems_capture_get_control_list (void)
1385 {
1386   return capture_controls;
1387 }