source: rtems/cpukit/libmisc/capture/capture.c @ 03c9f24

5
Last change on this file since 03c9f24 was 03c9f24, checked in by Sebastian Huber <sebastian.huber@…>, on 04/05/19 at 06:03:12

rtems: Add rtems_scheduler_get_processor()

Add rtems_scheduler_get_processor() as a replacement for
rtems_get_current_processor(). The rtems_get_current_processor() is a
bit orphaned. Adopt it by the Scheduler Manager. This is in line with
the glibc sched_getcpu() function.

Deprecate rtems_get_current_processor().

Update #3731.

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