source: rtems/cpukit/libmisc/capture/capture.c @ df23f464

5
Last change on this file since df23f464 was df23f464, checked in by Sebastian Huber <sebastian.huber@…>, on 05/12/16 at 11:08:49

capture: Fix use of per-processor data

Get the current processor index only once and with interrupts disabled.

Close #2707.

  • Property mode set to 100644
File size: 35.1 KB
Line 
1/*
2  ------------------------------------------------------------------------
3
4  Copyright Objective Design Systems Pty Ltd, 2002
5  All rights reserved Objective Design Systems Pty Ltd, 2002
6  Chris Johns (ccj@acm.org)
7
8  COPYRIGHT (c) 1989-2014.
9  On-Line Applications Research Corporation (OAR).
10
11  The license and distribution terms for this file may be
12  found in the file LICENSE in this distribution.
13
14  This software with is provided ``as is'' and with NO WARRANTY.
15
16  ------------------------------------------------------------------------
17
18  RTEMS Performance Monitoring and Measurement Framework.
19
20  This is the Capture Engine component.
21
22*/
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include <stdlib.h>
29#include <string.h>
30
31#include "captureimpl.h"
32#include "capture_buffer.h"
33
34/*
35 * These events are always recorded and are not part of the
36 * watch filters.
37 *
38 * This feature has been disabled as it becomes confusing when
39 * setting up filters and some event leak.
40 */
41#if defined (RTEMS_CAPTURE_ENGINE_ALLOW_RELATED_EVENTS)
42#define RTEMS_CAPTURE_RECORD_EVENTS  (RTEMS_CAPTURE_CREATED_BY_EVENT | \
43                                      RTEMS_CAPTURE_CREATED_EVENT | \
44                                      RTEMS_CAPTURE_STARTED_BY_EVENT | \
45                                      RTEMS_CAPTURE_STARTED_EVENT | \
46                                      RTEMS_CAPTURE_RESTARTED_BY_EVENT | \
47                                      RTEMS_CAPTURE_RESTARTED_EVENT | \
48                                      RTEMS_CAPTURE_DELETED_BY_EVENT | \
49                                      RTEMS_CAPTURE_DELETED_EVENT | \
50                                      RTEMS_CAPTURE_BEGIN_EVENT | \
51                                      RTEMS_CAPTURE_EXITTED_EVENT | \
52                                      RTEMS_CAPTURE_TERMINATED_EVENT | \
53                                      RTEMS_CAPTURE_AUTOGEN_ENTRY_EVENT | \
54                                      RTEMS_CAPTURE_AUTOGEN_EXIT_EVENT)
55#else
56#define RTEMS_CAPTURE_RECORD_EVENTS  (0)
57#endif
58
59typedef struct {
60  rtems_capture_buffer_t   records;
61  uint32_t                 count;
62  rtems_id                 reader;
63  rtems_interrupt_lock     lock;
64  uint32_t                 flags;
65} rtems_capture_per_cpu_data;
66
67typedef struct {
68  uint32_t                 flags;
69  rtems_capture_control_t* controls;
70  int                      extension_index;
71  rtems_capture_timestamp  timestamp;
72  rtems_task_priority      ceiling;
73  rtems_task_priority      floor;
74  rtems_interrupt_lock     lock;
75} rtems_capture_global_data;
76
77static rtems_capture_per_cpu_data  *capture_per_cpu = NULL;
78
79static rtems_capture_global_data capture_global = {
80  .lock = RTEMS_INTERRUPT_LOCK_INITIALIZER( "Capture" )
81};
82
83/*
84 * RTEMS Capture Data.
85 */
86#define capture_per_cpu_get( _cpu ) \
87   ( &capture_per_cpu[ _cpu ] )
88
89#define capture_records_on_cpu( _cpu ) capture_per_cpu[ _cpu ].records
90#define capture_count_on_cpu( _cpu )   capture_per_cpu[ _cpu ].count
91#define capture_flags_on_cpu( _cpu )   capture_per_cpu[ _cpu ].flags
92#define capture_reader_on_cpu( _cpu )  capture_per_cpu[ _cpu ].reader
93#define capture_lock_on_cpu( _cpu )    capture_per_cpu[ _cpu ].lock
94
95#define capture_flags_global     capture_global.flags
96#define capture_controls         capture_global.controls
97#define capture_extension_index  capture_global.extension_index
98#define capture_timestamp        capture_global.timestamp
99#define capture_ceiling          capture_global.ceiling
100#define capture_floor            capture_global.floor
101#define capture_lock_global      capture_global.lock
102
103/*
104 * RTEMS Event text.
105 */
106static const char * const capture_event_text[] =
107{
108  "CREATED_BY",
109  "CREATED",
110  "STARTED_BY",
111  "STARTED",
112  "RESTARTED_BY",
113  "RESTARTED",
114  "DELETED_BY",
115  "DELETED",
116  "TERMINATED",
117  "BEGIN",
118  "EXITTED",
119  "SWITCHED_OUT",
120  "SWITCHED_IN",
121  "TIMESTAMP"
122};
123
124void rtems_capture_set_extension_index(int index)
125{
126  capture_extension_index = index;
127}
128
129int  rtems_capture_get_extension_index(void)
130{
131  return capture_extension_index;
132}
133
134uint32_t rtems_capture_get_flags(void)
135{
136  return capture_flags_global;
137}
138
139void rtems_capture_set_flags(uint32_t mask)
140{
141  capture_flags_global |= mask;
142}
143
144/*
145 * This function returns the current time. If a handler is provided
146 * by the user get the time from that.
147 */
148void
149rtems_capture_get_time (rtems_capture_time_t* time)
150{
151  if (capture_timestamp)
152    capture_timestamp (time);
153  else
154  {
155    *time = rtems_clock_get_uptime_nanoseconds ();
156  }
157}
158
159/*
160 * This function compares rtems_names. It protects the
161 * capture engine from a change to the way names are supported
162 * in RTEMS.
163 */
164static inline bool
165rtems_capture_match_names (rtems_name lhs, rtems_name rhs)
166{
167  return lhs == rhs;
168}
169
170/*
171 * This function compares rtems_ids. It protects the
172 * capture engine from a change to the way id are supported
173 * in RTEMS.
174 */
175static inline bool
176rtems_capture_match_ids (rtems_id lhs, rtems_id rhs)
177{
178  return lhs == rhs;
179}
180
181/*
182 * This function matches a name and/or id.
183 */
184static inline bool
185rtems_capture_match_name_id (rtems_name lhs_name,
186                             rtems_id   lhs_id,
187                             rtems_name rhs_name,
188                             rtems_id   rhs_id)
189{
190  /*
191   * The left hand side name or id could be 0 which means a wildcard.
192   */
193  if ((lhs_name == 0) && (lhs_id == rhs_id))
194    return 1;
195  else if ((lhs_id == 0) || (lhs_id == rhs_id))
196  {
197    if (rtems_capture_match_names (lhs_name, rhs_name))
198      return 1;
199  }
200  return 0;
201}
202
203/*
204 * This function duplicates an rtems_names. It protects the
205 * capture engine from a change to the way names are supported
206 * in RTEMS.
207 */
208static inline void
209rtems_capture_dup_name (rtems_name* dst, rtems_name src)
210{
211  *dst = src;
212}
213
214/*
215 * This function sees if a BY control is in the BY names. The use
216 * of the valid_mask in this way assumes the number of trigger
217 * tasks is the number of bits in uint32_t.
218 */
219static inline bool
220rtems_capture_by_in_to (uint32_t                 events,
221                        rtems_tcb*               by,
222                        rtems_capture_control_t* to)
223{
224  uint32_t valid_mask = RTEMS_CAPTURE_CONTROL_FROM_MASK (0);
225  uint32_t valid_remainder = 0xffffffff;
226  int      i;
227
228  for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
229  {
230    /*
231     * If there are no more valid BY entries then
232     * we are finished.
233     */
234    if ((valid_remainder & to->by_valid) == 0)
235      break;
236
237    /*
238     * Is the froby entry valid and does its name or id match.
239     */
240    if ((valid_mask & to->by_valid) &&
241        (to->by[i].trigger & events))
242    {
243      /*
244       * We have the BY task on the right hand side so we
245       * match with id's first then labels if the id's are
246       * not set.
247       */
248      if (rtems_capture_match_name_id (to->by[i].name, to->by[i].id,
249                                       rtems_capture_task_name( by ),
250                                       by->Object.id))
251        return 1;
252    }
253
254    valid_mask >>= 1;
255    valid_remainder >>= 1;
256  }
257
258  return 0;
259}
260
261/*
262 * This function searches for a trigger given a name.
263 */
264static inline rtems_capture_control_t*
265rtems_capture_find_control (rtems_name name, rtems_id id)
266{
267  rtems_capture_control_t* control;
268
269  for (control = capture_controls; control != NULL; control = control->next)
270    if (rtems_capture_match_name_id (name, id, control->name, control->id))
271      break;
272  return control;
273}
274
275/*
276 * This function checks if a new control structure matches
277 * the given task and sets the control if it does.
278 */
279static void
280rtems_capture_initialize_control (rtems_tcb *tcb)
281{
282  rtems_name                   name;
283  rtems_capture_control_t*     control;
284
285  /*
286   * We need to scan the default control list to initialise
287   * this control.
288   */
289  rtems_object_get_classic_name( tcb->Object.id, &name );
290  control = capture_controls;
291  if (rtems_capture_match_name_id (control->name, control->id,
292                                   name, tcb->Object.id))
293    tcb->Capture.control = control;
294}
295
296/*
297 * This function creates a capture control for the capture engine.
298 */
299static inline rtems_capture_control_t*
300rtems_capture_create_control (rtems_name name, rtems_id id)
301{
302  rtems_interrupt_lock_context lock_context;
303  rtems_capture_control_t*     control;
304
305  if ((name == 0) && (id == 0))
306    return NULL;
307
308  control = rtems_capture_find_control (name, id);
309
310  if (control == NULL)
311  {
312    control = malloc( sizeof (*control));
313
314    if (!control)
315    {
316      capture_flags_global |= RTEMS_CAPTURE_NO_MEMORY;
317      return NULL;
318    }
319
320    control->name          = name;
321    control->id            = id;
322    control->flags         = 0;
323    control->to_triggers   = 0;
324    control->from_triggers = 0;
325    control->by_valid      = 0;
326
327    memset (control->by, 0, sizeof (control->by));
328
329    rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
330
331    control->next    = capture_controls;
332    capture_controls = control;
333    rtems_iterate_over_all_threads (rtems_capture_initialize_control);
334
335    rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
336  }
337
338  return control;
339}
340
341void rtems_capture_initialize_task( rtems_tcb* tcb )
342{
343  rtems_capture_control_t*     control;
344  rtems_name                   name;
345  rtems_interrupt_lock_context lock_context;
346
347  /*
348   * We need to scan the default control list to initialize
349   * this control if it is a new task.
350   */
351
352  rtems_object_get_classic_name( tcb->Object.id, &name );
353
354  rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
355  if (tcb->Capture.control == NULL) {
356    for (control = capture_controls; control != NULL; control = control->next)
357      if (rtems_capture_match_name_id (control->name, control->id,
358                                       name, tcb->Object.id))
359        tcb->Capture.control = control;
360  }
361
362  tcb->Capture.flags |= RTEMS_CAPTURE_INIT_TASK;
363  rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
364}
365
366void rtems_capture_record_task( rtems_tcb* tcb )
367{
368  rtems_capture_task_record_t rec;
369  void*                       ptr;
370  rtems_interrupt_lock_context lock_context;
371
372  rtems_object_get_classic_name( tcb->Object.id, &rec.name );
373
374  rec.stack_size = tcb->Start.Initial_stack.size;
375  rec.start_priority = _RTEMS_tasks_Priority_from_Core(
376    tcb->Start.initial_priority
377  );
378
379  rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
380  tcb->Capture.flags |= RTEMS_CAPTURE_RECORD_TASK;
381  rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
382
383  /*
384   *  Log the task information. The first time a task is
385   *  seen a record is logged.  This record can be identified
386   *  by a 0 in the event identifier.
387   */
388  rtems_capture_begin_add_record (tcb, 0, sizeof(rec), &ptr);
389  ptr = rtems_capture_append_to_record(
390    ptr,
391    &rec.name,
392    sizeof( rec.name )
393  );
394  ptr = rtems_capture_append_to_record(
395    ptr,
396    &rec.start_priority,
397    sizeof( rec.start_priority)
398  );
399  ptr = rtems_capture_append_to_record(
400    ptr,
401    &rec.stack_size,
402    sizeof( rec.stack_size)
403  );
404  rtems_capture_end_add_record ( ptr );
405}
406
407/*
408 * This function indicates if data should be filtered from the
409 * log.
410 */
411bool rtems_capture_filter( rtems_tcb*            tcb,
412                           uint32_t              events)
413{
414  if (tcb &&
415      ((capture_flags_global &
416        (RTEMS_CAPTURE_TRIGGERED | RTEMS_CAPTURE_ONLY_MONITOR)) ==
417       RTEMS_CAPTURE_TRIGGERED))
418  {
419    rtems_capture_control_t* control;
420
421    control = tcb->Capture.control;
422
423    /*
424     * Capture the record if we have an event that is always
425     * captured, or the task's real priority is greater than the
426     * watch ceiling, and the global watch or task watch is enabled.
427     */
428    if ((events & RTEMS_CAPTURE_RECORD_EVENTS) ||
429        ((tcb->real_priority >= capture_ceiling) &&
430         (tcb->real_priority <= capture_floor) &&
431         ((capture_flags_global & RTEMS_CAPTURE_GLOBAL_WATCH) ||
432          (control && (control->flags & RTEMS_CAPTURE_WATCH)))))
433    {
434      return false;
435    }
436  }
437
438  return true;
439}
440
441/*
442 * This function records a capture record into the capture buffer.
443 */
444void *
445rtems_capture_record_open (rtems_tcb*                      tcb,
446                           uint32_t                        events,
447                           size_t                          size,
448                           rtems_capture_record_context_t* context)
449{
450  rtems_capture_per_cpu_data* per_cpu;
451  uint8_t*                    ptr;
452  rtems_capture_record_t*     capture_in;
453
454  rtems_interrupt_lock_interrupt_disable (&context->lock_context);
455  per_cpu = capture_per_cpu_get (rtems_get_current_processor ());
456  context->lock = &per_cpu->lock;
457  rtems_interrupt_lock_acquire_isr (&per_cpu->lock, &context->lock_context);
458
459  ptr = rtems_capture_buffer_allocate (&per_cpu->records, size);
460  capture_in = (rtems_capture_record_t *) ptr;
461  if ( capture_in )
462  {
463    ++per_cpu->count;
464    capture_in->size    = size;
465    capture_in->task_id = tcb->Object.id;
466    capture_in->events  = (events |
467                          (tcb->real_priority) |
468                          (tcb->current_priority << 8));
469
470    if ((events & RTEMS_CAPTURE_RECORD_EVENTS) == 0)
471      tcb->Capture.flags |= RTEMS_CAPTURE_TRACED;
472
473    rtems_capture_get_time (&capture_in->time);
474
475    ptr = ptr + sizeof(*capture_in);
476  }
477  else
478    per_cpu->flags |= RTEMS_CAPTURE_OVERFLOW;
479
480  return ptr;
481}
482
483void rtems_capture_record_close( void *rec, rtems_capture_record_context_t* context)
484{
485  rtems_interrupt_lock_release (context->lock, &context->lock_context);
486}
487
488/*
489 * See if we have triggered and if not see if this event is a
490 * cause of a trigger.
491 */
492bool
493rtems_capture_trigger (rtems_tcb* ft,
494                       rtems_tcb* tt,
495                       uint32_t   events)
496{
497  /*
498   * If we have not triggered then see if this is a trigger condition.
499   */
500  if (!(capture_flags_global & RTEMS_CAPTURE_TRIGGERED))
501  {
502    rtems_capture_control_t* fc = NULL;
503    rtems_capture_control_t* tc = NULL;
504    uint32_t                 from_events = 0;
505    uint32_t                 to_events = 0;
506    uint32_t                 from_to_events = 0;
507
508    if (ft)
509    {
510      fc = ft->Capture.control;
511      if (fc)
512        from_events = fc->from_triggers & events;
513    }
514
515    if (tt)
516    {
517      tc = tt->Capture.control;
518      if (tc)
519      {
520        to_events = tc->to_triggers & events;
521        if (ft && tc->by_valid)
522          from_to_events = tc->by_triggers & events;
523      }
524    }
525
526    /*
527     * Check if we have any from or to events. These are the
528     * from any or to any type triggers. All from/to triggers are
529     * listed in the to's control with the from in the from list.
530     *
531     * The masking above means any flag set is a trigger.
532     */
533    if (from_events || to_events)
534    {
535      capture_flags_global |= RTEMS_CAPTURE_TRIGGERED;
536      return 1;
537    }
538
539    /*
540     * Check the from->to events.
541     */
542    if (from_to_events)
543    {
544      if (rtems_capture_by_in_to (events, ft, tc))
545      {
546        capture_flags_global |= RTEMS_CAPTURE_TRIGGERED;
547        return 1;
548      }
549    }
550
551    return 0;
552  }
553
554  return 1;
555}
556
557/*
558 * This function initialises the realtime capture engine allocating the trace
559 * buffer. It is assumed we have a working heap at stage of initialization.
560 */
561rtems_status_code
562rtems_capture_open (uint32_t   size, rtems_capture_timestamp timestamp RTEMS_UNUSED)
563{
564  rtems_status_code       sc = RTEMS_SUCCESSFUL;
565  size_t                  count;
566  uint32_t                i;
567  rtems_capture_buffer_t* buff;
568
569  /*
570   * See if the capture engine is already open.
571   */
572
573  if ((capture_flags_global & RTEMS_CAPTURE_INIT) == RTEMS_CAPTURE_INIT) {
574    return RTEMS_RESOURCE_IN_USE;
575  }
576
577  count = rtems_get_processor_count();
578  if (capture_per_cpu == NULL) {
579    capture_per_cpu = calloc( count, sizeof( *capture_per_cpu ) );
580  }
581
582  for (i=0; i<count; i++) {
583    buff = &capture_records_on_cpu(i);
584    rtems_capture_buffer_create( buff, size );
585    if (buff->buffer == NULL) {
586      sc = RTEMS_NO_MEMORY;
587      break;
588    }
589
590    rtems_interrupt_lock_initialize(
591      &capture_lock_on_cpu( i ),
592      "Capture Per-CPU"
593    );
594  }
595
596  capture_flags_global   = 0;
597  capture_ceiling = 0;
598  capture_floor   = 255;
599  if (sc == RTEMS_SUCCESSFUL)
600    sc = rtems_capture_user_extension_open();
601
602  if (sc != RTEMS_SUCCESSFUL)
603  {
604    for (i=0; i<count; i++)
605      rtems_capture_buffer_destroy( &capture_records_on_cpu(i));
606  }  else {
607    capture_flags_global |= RTEMS_CAPTURE_INIT;
608  }
609
610  return sc;
611}
612
613/*
614 * This function shutdowns the capture engine and release any claimed
615 * resources.  Capture control must be disabled prior to calling a close.
616 */
617rtems_status_code
618rtems_capture_close (void)
619{
620  rtems_interrupt_lock_context lock_context;
621  rtems_capture_control_t*     control;
622  rtems_status_code            sc;
623  uint32_t                     cpu;
624
625  rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
626
627  if ((capture_flags_global & RTEMS_CAPTURE_INIT) != RTEMS_CAPTURE_INIT)
628  {
629    rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
630    return RTEMS_SUCCESSFUL;
631  }
632
633  if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
634  {
635    rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
636    return RTEMS_UNSATISFIED;
637  }
638
639  capture_flags_global &=
640    ~(RTEMS_CAPTURE_ON | RTEMS_CAPTURE_ONLY_MONITOR | RTEMS_CAPTURE_INIT);
641
642  rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
643
644  /*
645   * Delete the extension first. This means we are now able to
646   * release the resources we have without them being used.
647   */
648
649  sc = rtems_capture_user_extension_close();
650
651  if (sc != RTEMS_SUCCESSFUL)
652    return sc;
653
654  control = capture_controls;
655
656  while (control)
657  {
658    rtems_capture_control_t* delete = control;
659    control = control->next;
660    free (delete);
661  }
662
663  capture_controls = NULL;
664  for (cpu=0; cpu < rtems_get_processor_count(); cpu++) {
665    if (capture_records_on_cpu(cpu).buffer)
666      rtems_capture_buffer_destroy( &capture_records_on_cpu(cpu) );
667
668    rtems_interrupt_lock_destroy( &capture_lock_on_cpu( cpu ) );
669  }
670
671  free( capture_per_cpu );
672  capture_per_cpu = NULL;
673
674  return RTEMS_SUCCESSFUL;
675}
676
677rtems_status_code
678rtems_capture_control (bool enable)
679{
680  rtems_interrupt_lock_context lock_context;
681
682  rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
683
684  if ((capture_flags_global & RTEMS_CAPTURE_INIT) != RTEMS_CAPTURE_INIT)
685  {
686    rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
687    return RTEMS_UNSATISFIED;
688  }
689
690  if (enable)
691    capture_flags_global |= RTEMS_CAPTURE_ON;
692  else
693    capture_flags_global &= ~RTEMS_CAPTURE_ON;
694
695  rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
696
697  return RTEMS_SUCCESSFUL;
698}
699
700/*
701 * This function enable the monitor mode. When in the monitor mode
702 * the tasks are monitored but no data is saved. This can be used
703 * to profile the load on a system.
704 */
705rtems_status_code
706rtems_capture_monitor (bool enable)
707{
708  rtems_interrupt_lock_context lock_context;
709
710  rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
711
712  if ((capture_flags_global & RTEMS_CAPTURE_INIT) != RTEMS_CAPTURE_INIT)
713  {
714    rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
715    return RTEMS_UNSATISFIED;
716  }
717
718  if (enable)
719    capture_flags_global |= RTEMS_CAPTURE_ONLY_MONITOR;
720  else
721    capture_flags_global &= ~RTEMS_CAPTURE_ONLY_MONITOR;
722
723  rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
724
725  return RTEMS_SUCCESSFUL;
726}
727
728/*
729 * This function clears the capture trace flag in the tcb.
730 */
731static void
732rtems_capture_flush_tcb (rtems_tcb *tcb)
733{
734  tcb->Capture.flags &= ~RTEMS_CAPTURE_TRACED;
735}
736
737/*
738 * This function flushes the capture buffer. The prime parameter allows the
739 * capture engine to also be primed again.
740 */
741rtems_status_code
742rtems_capture_flush (bool prime)
743{
744  rtems_interrupt_lock_context lock_context_global;
745  uint32_t                     cpu;
746
747  rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context_global);
748
749  if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
750  {
751    rtems_interrupt_lock_release (&capture_lock_global, &lock_context_global);
752    return RTEMS_UNSATISFIED;
753  }
754
755  rtems_iterate_over_all_threads (rtems_capture_flush_tcb);
756
757  if (prime)
758    capture_flags_global &= ~(RTEMS_CAPTURE_TRIGGERED | RTEMS_CAPTURE_OVERFLOW);
759  else
760    capture_flags_global &= ~RTEMS_CAPTURE_OVERFLOW;
761
762  for (cpu=0; cpu < rtems_get_processor_count(); cpu++) {
763    RTEMS_INTERRUPT_LOCK_REFERENCE( lock, &(capture_lock_on_cpu( cpu )) )
764    rtems_interrupt_lock_context lock_context_per_cpu;
765
766    rtems_interrupt_lock_acquire (lock, &lock_context_per_cpu);
767    capture_count_on_cpu(cpu) = 0;
768    if (capture_records_on_cpu(cpu).buffer)
769      rtems_capture_buffer_flush( &capture_records_on_cpu(cpu) );
770    rtems_interrupt_lock_release (lock, &lock_context_per_cpu);
771  }
772
773  rtems_interrupt_lock_release (&capture_lock_global, &lock_context_global);
774
775  return RTEMS_SUCCESSFUL;
776}
777
778/*
779 * This function defines a watch for a specific task given a name. A watch
780 * causes it to be traced either in or out of context. The watch can be
781 * optionally enabled or disabled with the set routine. It is disabled by
782 * default.  A watch can only be defined when capture control is disabled
783 */
784rtems_status_code
785rtems_capture_watch_add (rtems_name name, rtems_id id)
786{
787  rtems_capture_control_t* control;
788
789  if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
790    return RTEMS_UNSATISFIED;
791
792  if ((name == 0) && (id == 0))
793    return RTEMS_UNSATISFIED;
794
795  control = rtems_capture_find_control (name, id);
796
797  if (control && !id)
798    return RTEMS_TOO_MANY;
799
800  if (!control)
801    control = rtems_capture_create_control (name, id);
802
803  if (!control)
804    return RTEMS_NO_MEMORY;
805
806  return RTEMS_SUCCESSFUL;
807}
808
809/*
810 * This function removes a watch for a specific task given a name. The task
811 * description will still exist if referenced by a trace record in the trace
812 * buffer or a global watch is defined.  A watch can only be deleted when
813 * capture control is disabled.
814 */
815rtems_status_code
816rtems_capture_watch_del (rtems_name name, rtems_id id)
817{
818  rtems_interrupt_lock_context lock_context;
819  rtems_capture_control_t*     control;
820  rtems_capture_control_t**    prev_control;
821  bool                         found = false;
822
823  if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
824    return RTEMS_UNSATISFIED;
825
826  /*
827   * Should this test be for wildcards ?
828   */
829
830  for (prev_control = &capture_controls, control = capture_controls;
831       control != NULL; )
832  {
833    if (rtems_capture_match_name_id (control->name, control->id, name, id))
834    {
835      rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
836
837      *prev_control = control->next;
838
839      rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
840
841      free (control);
842
843      control = *prev_control;
844
845      found = true;
846    }
847    else
848    {
849      prev_control = &control->next;
850      control      = control->next;
851    }
852  }
853
854  if (found)
855    return RTEMS_SUCCESSFUL;
856
857  return RTEMS_INVALID_NAME;
858}
859
860/*
861 * This function allows control of a watch. The watch can be enabled or
862 * disabled.
863 */
864rtems_status_code
865rtems_capture_watch_ctrl (rtems_name name, rtems_id id, bool enable)
866{
867  rtems_interrupt_lock_context lock_context;
868  rtems_capture_control_t*     control;
869  bool                         found = false;
870
871  if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
872    return RTEMS_UNSATISFIED;
873
874  /*
875   * Find the control and then set the watch. It must exist before it can
876   * be controlled.
877   */
878  for (control = capture_controls; control != NULL; control = control->next)
879  {
880    if (rtems_capture_match_name_id (control->name, control->id, name, id))
881    {
882      rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
883
884      if (enable)
885        control->flags |= RTEMS_CAPTURE_WATCH;
886      else
887        control->flags &= ~RTEMS_CAPTURE_WATCH;
888
889      rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
890
891      found = true;
892    }
893  }
894
895  if (found)
896    return RTEMS_SUCCESSFUL;
897
898  return RTEMS_INVALID_NAME;
899}
900
901/*
902 * This function allows control of a global watch. The watch can be enabled or
903 * disabled. A global watch configures all tasks below the ceiling and above
904 * the floor to be traced.
905 */
906rtems_status_code
907rtems_capture_watch_global (bool enable)
908{
909  rtems_interrupt_lock_context lock_context;
910
911  rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
912
913  /*
914   * We need to keep specific and global watches separate so
915   * a global enable/disable does not lose a specific watch.
916   */
917  if (enable)
918    capture_flags_global |= RTEMS_CAPTURE_GLOBAL_WATCH;
919  else
920    capture_flags_global &= ~RTEMS_CAPTURE_GLOBAL_WATCH;
921
922  rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
923
924  return RTEMS_SUCCESSFUL;
925}
926
927/*
928 * This function returns the global watch state.
929 */
930bool
931rtems_capture_watch_global_on (void)
932{
933  return capture_flags_global & RTEMS_CAPTURE_GLOBAL_WATCH ? 1 : 0;
934}
935
936/*
937 * This function sets a watch ceiling. Tasks at or greating that the
938 * ceiling priority are not watched. This is a simple way to monitor
939 * an application and exclude system tasks running at a higher
940 * priority level.
941 */
942rtems_status_code
943rtems_capture_watch_ceiling (rtems_task_priority ceiling)
944{
945  capture_ceiling = ceiling;
946  return RTEMS_SUCCESSFUL;
947}
948
949/*
950 * This function gets the watch ceiling.
951 */
952rtems_task_priority
953rtems_capture_watch_get_ceiling (void)
954{
955  return capture_ceiling;
956}
957
958/*
959 * This function sets a watch floor. Tasks at or less that the
960 * floor priority are not watched. This is a simple way to monitor
961 * an application and exclude system tasks running at a lower
962 * priority level.
963 */
964rtems_status_code
965rtems_capture_watch_floor (rtems_task_priority floor)
966{
967  capture_floor = floor;
968  return RTEMS_SUCCESSFUL;
969}
970
971/*
972 * This function gets the watch floor.
973 */
974rtems_task_priority
975rtems_capture_watch_get_floor (void)
976{
977  return capture_floor;
978}
979
980/*
981 * Map the trigger to a bit mask.
982 */
983static uint32_t
984rtems_capture_map_trigger (rtems_capture_trigger_t trigger)
985{
986  /*
987   * Transform the mode and trigger to a bit map.
988   */
989  switch (trigger)
990  {
991    case rtems_capture_switch:
992      return RTEMS_CAPTURE_SWITCH;
993    case rtems_capture_create:
994      return RTEMS_CAPTURE_CREATE;
995    case rtems_capture_start:
996      return RTEMS_CAPTURE_START;
997    case rtems_capture_restart:
998      return RTEMS_CAPTURE_RESTART;
999    case rtems_capture_delete:
1000      return RTEMS_CAPTURE_DELETE;
1001    case rtems_capture_begin:
1002      return RTEMS_CAPTURE_BEGIN;
1003    case rtems_capture_exitted:
1004      return RTEMS_CAPTURE_EXITTED;
1005    case rtems_capture_terminated:
1006      return RTEMS_CAPTURE_TERMINATED;
1007    default:
1008      break;
1009  }
1010  return 0;
1011}
1012
1013/*
1014 * This function sets a trigger.
1015 *
1016 * This set trigger routine will create a capture control for the
1017 * target task. The task list is searched and any existing tasks
1018 * are linked to the new control.
1019 *
1020 * We can have a number of tasks that have the same name so we
1021 * search using names. This means a number of tasks can be
1022 * linked to single control.
1023 */
1024rtems_status_code
1025rtems_capture_set_trigger (rtems_name                   from_name,
1026                           rtems_id                     from_id,
1027                           rtems_name                   to_name,
1028                           rtems_id                     to_id,
1029                           rtems_capture_trigger_mode_t mode,
1030                           rtems_capture_trigger_t      trigger)
1031{
1032  rtems_capture_control_t* control;
1033  uint32_t                 flags;
1034
1035  flags = rtems_capture_map_trigger (trigger);
1036
1037  /*
1038   * The mode sets the opposite type of trigger. For example
1039   * FROM ANY means trigger when the event happens TO this
1040   * task. TO ANY means FROM this task.
1041   */
1042
1043  if (mode == rtems_capture_to_any)
1044  {
1045    control = rtems_capture_create_control (from_name, from_id);
1046    if (control == NULL)
1047      return RTEMS_NO_MEMORY;
1048    control->from_triggers |= flags & RTEMS_CAPTURE_FROM_TRIGS;
1049  }
1050  else
1051  {
1052    control = rtems_capture_create_control (to_name, to_id);
1053    if (control == NULL)
1054      return RTEMS_NO_MEMORY;
1055    if (mode == rtems_capture_from_any)
1056      control->to_triggers |= flags;
1057    else
1058    {
1059      bool done = false;
1060      int  i;
1061
1062      control->by_triggers |= flags;
1063
1064      for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
1065      {
1066        if (rtems_capture_control_by_valid (control, i) &&
1067            ((control->by[i].name == from_name) ||
1068             (from_id && (control->by[i].id == from_id))))
1069        {
1070          control->by[i].trigger |= flags;
1071          done = true;
1072          break;
1073        }
1074      }
1075
1076      if (!done)
1077      {
1078        for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
1079        {
1080          if (!rtems_capture_control_by_valid (control, i))
1081          {
1082            control->by_valid |= RTEMS_CAPTURE_CONTROL_FROM_MASK (i);
1083            control->by[i].name = from_name;
1084            control->by[i].id = from_id;
1085            control->by[i].trigger = flags;
1086            done = true;
1087            break;
1088          }
1089        }
1090      }
1091
1092      if (!done)
1093        return RTEMS_TOO_MANY;
1094    }
1095  }
1096  return RTEMS_SUCCESSFUL;
1097}
1098
1099/*
1100 * This function clear a trigger.
1101 */
1102rtems_status_code
1103rtems_capture_clear_trigger (rtems_name                   from_name,
1104                             rtems_id                     from_id,
1105                             rtems_name                   to_name,
1106                             rtems_id                     to_id,
1107                             rtems_capture_trigger_mode_t mode,
1108                             rtems_capture_trigger_t      trigger)
1109{
1110  rtems_capture_control_t* control;
1111  uint32_t                 flags;
1112
1113  flags = rtems_capture_map_trigger (trigger);
1114
1115  if (mode == rtems_capture_to_any)
1116  {
1117    control = rtems_capture_find_control (from_name, from_id);
1118    if (control == NULL)
1119    {
1120      if (from_id)
1121        return RTEMS_INVALID_ID;
1122      return RTEMS_INVALID_NAME;
1123    }
1124    control->from_triggers &= ~flags;
1125  }
1126  else
1127  {
1128    control = rtems_capture_find_control (to_name, to_id);
1129    if (control == NULL)
1130    {
1131      if (to_id)
1132        return RTEMS_INVALID_ID;
1133      return RTEMS_INVALID_NAME;
1134    }
1135    if (mode == rtems_capture_from_any)
1136      control->to_triggers &= ~flags;
1137    else
1138    {
1139      bool done = false;
1140      int  i;
1141
1142      control->by_triggers &= ~flags;
1143
1144      for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
1145      {
1146        if (rtems_capture_control_by_valid (control, i) &&
1147            ((control->by[i].name == from_name) ||
1148             (control->by[i].id == from_id)))
1149        {
1150          control->by[i].trigger &= ~trigger;
1151          if (control->by[i].trigger == 0)
1152            control->by_valid &= ~RTEMS_CAPTURE_CONTROL_FROM_MASK (i);
1153          done = true;
1154          break;
1155        }
1156      }
1157
1158      if (!done)
1159      {
1160        if (from_id)
1161          return RTEMS_INVALID_ID;
1162        return RTEMS_INVALID_NAME;
1163      }
1164    }
1165  }
1166  return RTEMS_SUCCESSFUL;
1167}
1168
1169static inline uint32_t rtems_capture_count_records( void* recs, size_t size )
1170{
1171  rtems_capture_record_t* rec;
1172  uint8_t*                ptr = recs;
1173  uint32_t                rec_count = 0;
1174  size_t                  byte_count = 0;
1175
1176
1177 while (byte_count < size) {
1178    rec = (rtems_capture_record_t*) ptr;
1179    rec_count++;
1180    _Assert( rec->size >= sizeof(*rec) );
1181    ptr += rec->size;
1182    byte_count += rec->size;
1183 };
1184
1185 return rec_count;
1186}
1187
1188/*
1189 * This function reads a number of records from the capture buffer.
1190 *
1191 * The function returns the number of record that is has that are
1192 * in a continous block of memory. If the number of available records
1193 * wrap then only those records are provided. This removes the need for
1194 * caller to be concerned about buffer wrappings. If the number of
1195 * requested records cannot be met due to the wrapping of the records
1196 * less than the specified number will be returned.
1197 *
1198 * The user must release the records. This is achieved with a call to
1199 * rtems_capture_release. Calls this function without a release will
1200 * result in at least the same number of records being released.
1201 */
1202rtems_status_code
1203rtems_capture_read (uint32_t                 cpu,
1204                    uint32_t*                read,
1205                    rtems_capture_record_t** recs)
1206{
1207  rtems_interrupt_lock_context lock_context;
1208  rtems_status_code            sc = RTEMS_SUCCESSFUL;
1209  size_t                       recs_size = 0;
1210  RTEMS_INTERRUPT_LOCK_REFERENCE( lock, &(capture_lock_on_cpu( cpu )) )
1211  rtems_capture_buffer_t*      records = &(capture_records_on_cpu( cpu ));
1212  uint32_t*                    flags = &(capture_flags_on_cpu( cpu ));
1213
1214  *read = 0;
1215  *recs = NULL;
1216
1217  rtems_interrupt_lock_acquire (lock, &lock_context);
1218
1219  /*
1220   * Only one reader is allowed.
1221   */
1222
1223  if (*flags & RTEMS_CAPTURE_READER_ACTIVE)
1224  {
1225    rtems_interrupt_lock_release (lock, &lock_context);
1226    return RTEMS_RESOURCE_IN_USE;
1227  }
1228
1229  if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
1230  {
1231    rtems_interrupt_lock_release (lock, &lock_context);
1232    return RTEMS_UNSATISFIED;
1233  }
1234
1235  *flags |= RTEMS_CAPTURE_READER_ACTIVE;
1236
1237  *recs = rtems_capture_buffer_peek( records, &recs_size );
1238
1239  *read = rtems_capture_count_records( *recs, recs_size );
1240
1241  rtems_interrupt_lock_release (lock, &lock_context);
1242
1243  return sc;
1244}
1245
1246/*
1247 * This function releases the requested number of record slots back
1248 * to the capture engine. The count must match the number read.
1249 */
1250rtems_status_code
1251rtems_capture_release (uint32_t cpu, uint32_t count)
1252{
1253  rtems_interrupt_lock_context lock_context;
1254  uint8_t*                     ptr;
1255  rtems_capture_record_t*      rec;
1256  uint32_t                     counted;
1257  size_t                       ptr_size = 0;
1258  size_t                       rel_size = 0;
1259  rtems_status_code            ret_val = RTEMS_SUCCESSFUL;
1260  RTEMS_INTERRUPT_LOCK_REFERENCE( lock, &(capture_lock_on_cpu( cpu )) )
1261  rtems_capture_buffer_t*      records = &(capture_records_on_cpu( cpu ));
1262  uint32_t*                    flags = &(capture_flags_on_cpu( cpu ));
1263  uint32_t*                    total = &(capture_count_on_cpu( cpu ));
1264
1265  rtems_interrupt_lock_acquire (lock, &lock_context);
1266
1267  if (count > *total) {
1268    count = *total;
1269  }
1270
1271  if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 ) {
1272    rtems_interrupt_lock_release (lock, &lock_context);
1273    return RTEMS_UNSATISFIED;
1274  }
1275
1276  counted = count;
1277
1278  ptr = rtems_capture_buffer_peek( records, &ptr_size );
1279  _Assert(ptr_size >= (count * sizeof(*rec) ));
1280
1281  rel_size = 0;
1282  while (counted--) {
1283    rec = (rtems_capture_record_t*) ptr;
1284    rel_size += rec->size;
1285    _Assert( rel_size <= ptr_size );
1286    ptr += rec->size;
1287  }
1288
1289  if (rel_size > ptr_size ) {
1290    ret_val = RTEMS_INVALID_NUMBER;
1291    rel_size = ptr_size;
1292  }
1293
1294  *total -= count;
1295
1296  if (count) {
1297    rtems_capture_buffer_free( records, rel_size );
1298  }
1299
1300  *flags &= ~RTEMS_CAPTURE_READER_ACTIVE;
1301
1302  rtems_interrupt_lock_release (lock, &lock_context);
1303
1304  return ret_val;
1305}
1306
1307/*
1308 * This function returns the current time. If a handler is provided
1309 * by the user get the time from that.
1310 */
1311void
1312rtems_capture_time (rtems_capture_time_t* uptime)
1313{
1314  rtems_capture_get_time(uptime);
1315}
1316
1317/*
1318 * This function returns a string for an event based on the bit in the
1319 * event. The functions takes the bit offset as a number not the bit
1320 * set in a bit map.
1321 */
1322const char*
1323rtems_capture_event_text (int event)
1324{
1325  if ((event < RTEMS_CAPTURE_EVENT_START) || (event > RTEMS_CAPTURE_EVENT_END))
1326    return "invalid event id";
1327  return capture_event_text[event - RTEMS_CAPTURE_EVENT_START];
1328}
1329
1330/*
1331 * This function returns the head of the list of control in the
1332 * capture engine.
1333 */
1334rtems_capture_control_t*
1335rtems_capture_get_control_list (void)
1336{
1337  return capture_controls;
1338}
Note: See TracBrowser for help on using the repository browser.