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

4.104.114.84.95
Last change on this file since aebc8290 was aebc8290, checked in by Ralf Corsepius <ralf.corsepius@…>, on 07/20/02 at 09:18:37

2002-07-20 Ralf Corsepius <corsepiu@…>

  • capture/capture.c: include <string.h> for memset.
  • Property mode set to 100644
File size: 36.3 KB
RevLine 
[a923a82]1/*
2  ------------------------------------------------------------------------
3  $Id$
4  ------------------------------------------------------------------------
5 
6  Copyright Objective Design Systems Pty Ltd, 2002
7  All rights reserved Objective Design Systems Pty Ltd, 2002
8  Chris Johns (ccj@acm.org)
9
10  COPYRIGHT (c) 1989-1998.
11  On-Line Applications Research Corporation (OAR).
12
13  The license and distribution terms for this file may be
14  found in the file LICENSE in this distribution.
15
16  This software with is provided ``as is'' and with NO WARRANTY.
17 
18  ------------------------------------------------------------------------
19
20  RTEMS Performance Monitoring and Measurement Framework.
21
22  This is the Capture Engine component.
23
24*/
25
26#include <stdlib.h>
[aebc8290]27#include <string.h>
[a923a82]28
29#include "capture.h"
30#include <rtems/score/states.inl>
31#include <rtems/score/wkspace.h>
32#include <rtems/score/wkspace.inl>
33
34/*
35 * These events are always recorded and are not part of the
36 * watch filters.
37 */
38#define RTEMS_CAPTURE_RECORD_EVENTS  (RTEMS_CAPTURE_CREATED_BY_EVENT | \
39                                      RTEMS_CAPTURE_CREATED_EVENT | \
40                                      RTEMS_CAPTURE_STARTED_BY_EVENT | \
41                                      RTEMS_CAPTURE_STARTED_EVENT | \
42                                      RTEMS_CAPTURE_RESTARTED_BY_EVENT | \
43                                      RTEMS_CAPTURE_RESTARTED_EVENT | \
44                                      RTEMS_CAPTURE_DELETED_BY_EVENT | \
45                                      RTEMS_CAPTURE_DELETED_EVENT | \
46                                      RTEMS_CAPTURE_BEGIN_EVENT | \
47                                      RTEMS_CAPTURE_EXITTED_EVENT)
48
49/*
50 * Global capture flags.
51 */
52#define RTEMS_CAPTURE_ON             (1 << 0)
53#define RTEMS_CAPTURE_NO_MEMORY      (1 << 1)
54#define RTEMS_CAPTURE_OVERFLOW       (1 << 2)
55#define RTEMS_CAPTURE_TRIGGERED      (1 << 3)
56#define RTEMS_CAPTURE_READER_ACTIVE  (1 << 4)
57#define RTEMS_CAPTURE_READER_WAITING (1 << 5)
58#define RTEMS_CAPTURE_GLOBAL_WATCH   (1 << 6)
59
60/*
61 * RTEMS Capture Data.
62 */
63static rtems_capture_record_t*  capture_records;
64static rtems_unsigned32         capture_size;
65static rtems_unsigned32         capture_count;
66static rtems_capture_record_t*  capture_in;
67static rtems_unsigned32         capture_out;
68static rtems_unsigned32         capture_flags;
69static rtems_capture_task_t*    capture_tasks;
70static rtems_capture_control_t* capture_controls;
71static int                      capture_extension_index;
72static rtems_id                 capture_id;
73static rtems_capture_timestamp  capture_timestamp;
74static rtems_task_priority      capture_ceiling;
75static rtems_task_priority      capture_floor;
76static rtems_unsigned32         capture_tick_period;
77static rtems_id                 capture_reader;
78
79/*
80 * RTEMS Event text.
81 */
82static const char* capture_event_text[] =
83{
84  "CREATED_BY",
85  "CREATED",
86  "STARTED_BY",
87  "STARTED",
88  "RESTARTED_BY",
89  "RESTARTED",
90  "DELETED_BY",
91  "DELETED",
92  "BEGIN",
93  "EXITTED",
94  "SWITCHED_OUT",
95  "SWITCHED_IN",
96  "TIMESTAMP"
97};
98
99/*
100 * rtems_capture_get_time
101 *
102 *  DESCRIPTION:
103 *
104 * This function returns the current time. If a handler is provided
105 * by the user get the time from that.
106 */
107static inline void rtems_capture_get_time (rtems_unsigned32* ticks,
108                                           rtems_unsigned32* tick_offset)
109{
110  if (capture_timestamp)
111    capture_timestamp (ticks, tick_offset);
112  else
113  {
114    *ticks       = _Watchdog_Ticks_since_boot;
115    *tick_offset = 0;
116  }
117}
118
119/*
120 * rtems_capture_match_names
121 *
122 *  DESCRIPTION:
123 *
124 * This function compares rtems_names. It protects the
125 * capture engine from a change to the way names are supported
126 * in RTEMS.
127 *
128 */
129static inline rtems_boolean
130rtems_capture_match_names (rtems_name lhs, rtems_name rhs)
131{
132  return lhs == rhs;
133}
134
135/*
136 * rtems_capture_dup_name
137 *
138 *  DESCRIPTION:
139 *
140 * This function duplicates an rtems_names. It protects the
141 * cpature engine from a change to the way names are supported
142 * in RTEMS.
143 *
144 */
145static inline void
146rtems_capture_dup_name (rtems_name* dst, rtems_name src)
147{
148  *dst = src;
149}
150
151/*
152 * rtems_capture_name_in_group
153 *
154 *  DESCRIPTION:
155 *
156 * This function sees if a name is in a group of names.
157 *
158 */
159static inline rtems_boolean
160rtems_capture_name_in_group (rtems_name task, rtems_name* tasks)
161{
162  if (tasks)
163  {
164    int i;
165    for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
166      if (rtems_capture_match_names (task, *tasks++))
167        return 1;
168  }
169  return 0;
170}
171
172/*
173 * rtems_capture_match_name_id
174 *
175 *  DESCRIPTION:
176 *
177 * This function matches a name and/or id.
178 */
179static inline rtems_boolean
180rtems_capture_match_name_id (rtems_name lhs_name,
181                             rtems_id   lhs_id,
182                             rtems_name rhs_name,
183                             rtems_id   rhs_id)
184{
185  /*
186   * The left hand side name or id could be 0 which means a wildcard.
187   */
188  if ((lhs_name == 0) && (lhs_id == rhs_id))
189    return 1;
190  else if ((lhs_id == 0) || (lhs_id == rhs_id))
191  {
192    if (rtems_capture_match_names (lhs_name, rhs_name))
193      return 1;
194  }
195  return 0;
196}
197
198/*
199 * rtems_capture_init_stack_usage
200 *
201 *  DESCRIPTION:
202 *
203 * This function setups a stack so its usage can be monitored.
204 */
205static inline void
206rtems_capture_init_stack_usage (rtems_capture_task_t* task)
207{
208  if (task->tcb)
209  {
210    rtems_unsigned32* s;
211    rtems_unsigned32  i;
212
213    task->stack_size  = task->tcb->Start.Initial_stack.size;
214    task->stack_clean = task->stack_size;
215
216    s = task->tcb->Start.Initial_stack.area;
217
218    for (i = 0; i < (task->stack_size - 128); i += 4)
219      *(s++) = 0xdeaddead;
220  }
221}
222
223/*
224 * rtems_capture_find_control
225 *
226 *  DESCRIPTION:
227 *
228 * This function searches for a trigger given a name.
229 *
230 */
231static inline rtems_capture_control_t*
232rtems_capture_find_control (rtems_name name, rtems_id id)
233{
234  rtems_capture_control_t* control;
235 
236  for (control = capture_controls; control != NULL; control = control->next)
237    if (rtems_capture_match_name_id (name, id, control->name, control->id))
238      break;
239  return control;
240}
241
242/*
243 * rtems_capture_create_control
244 *
245 *  DESCRIPTION:
246 *
247 * This function creates a capture control for the capture engine.
248 *
249 */
250static inline rtems_capture_control_t*
251rtems_capture_create_control (rtems_name name, rtems_id id)
252{
253  rtems_interrupt_level    level;
254  rtems_capture_control_t* control;
255  rtems_capture_task_t*    task;
256
257  if ((name == 0) && (id == 0))
258    return NULL;
259
260  control = rtems_capture_find_control (name, id);
261 
262  if (control == NULL)
263  {
264    control = _Workspace_Allocate (sizeof (rtems_capture_control_t));
265
266    if (control == NULL)
267    {
268      capture_flags |= RTEMS_CAPTURE_NO_MEMORY;
269      return NULL;
270    }
271   
272    control->name  = name;
273    control->id    = id;
274    control->flags = 0;
275
276    memset (control->from,    0, sizeof (control->from));
277    memset (control->from_id, 0, sizeof (control->from_id));
278   
279    rtems_interrupt_disable (level);
280
281    control->next    = capture_controls;
282    capture_controls = control;
283
284    /*
285     * We need to scan the task list as set the control to the
286     * tasks.
287     */
288    for (task = capture_tasks; task != NULL; task = task->next)
289      if (rtems_capture_match_name_id (name, id, task->name, task->id))
290        task->control = control;
291
292    rtems_interrupt_enable (level);
293  }
294
295  return control;
296}
297
298/*
299 * rtems_capture_create_capture_task
300 *
301 *  DESCRIPTION:
302 *
303 * This function create the task control.
304 *
305 */
306static inline rtems_capture_task_t*
307rtems_capture_create_capture_task (rtems_tcb* new_task)
308{
309  rtems_interrupt_level    level;
310  rtems_capture_task_t*    task;
311  rtems_capture_control_t* control;
312
313  task = _Workspace_Allocate (sizeof (rtems_capture_task_t));
314
315  if (task == NULL)
316  {
317    capture_flags |= RTEMS_CAPTURE_NO_MEMORY;
318    return NULL;
319  }
320
321  rtems_capture_dup_name (&task->name, *((rtems_name*) new_task->Object.name));
322 
323  task->id               = new_task->Object.id;
324  task->flags            = 0;
325  task->in               = 0;
326  task->out              = 0;
327  task->tcb              = new_task;
328  task->ticks            = 0;
329  task->tick_offset      = 0;
330  task->ticks_in         = 0;
331  task->tick_offset_in   = 0;
332  task->control          = 0;
333  task->last_ticks       = 0;
334  task->last_tick_offset = 0;
335
336  task->tcb->extensions[capture_extension_index] = task;
337
338  task->start_priority = new_task->Start.initial_priority;
339  task->stack_size     = new_task->Start.Initial_stack.size;
340  task->stack_clean    = task->stack_size;
341
342  rtems_interrupt_disable (level);
343
344  task->next    = capture_tasks;
345  capture_tasks = task;
346
347  rtems_interrupt_enable (level);
348
349  /*
350   * We need to scan the default control list to initialise
351   * this control.
352   */
353
354  for (control = capture_controls; control != NULL; control = control->next)
355    if (rtems_capture_match_name_id (control->name, control->id,
356                                     task->name, task->id))
357      task->control = control;
358 
359  return task;
360}
361
362/*
363 * rtems_capture_record
364 *
365 *  DESCRIPTION:
366 *
367 * This function records a capture record into the capture buffer.
368 *
369 */
370static inline void
371rtems_capture_record (rtems_capture_task_t* task,
372                      rtems_unsigned32      events)
373{
374  /*
375   * Check the watch state if we have a task control, and
376   * the task's real priority is lower or equal to the ceiling.
377   */
378  if (task)
379  {
380    rtems_capture_control_t* control;
381
382    control = task->control;
383
384    /*
385     * Capure the record if we have an event that is always
386     * captured, or the task's real priority is greater than the
387     * watch ceiling, and the global watch or task watch is enabled.
388     */
389
390    if ((events & RTEMS_CAPTURE_RECORD_EVENTS) ||
391        ((task->tcb->real_priority >= capture_ceiling) &&
392         (task->tcb->real_priority <= capture_floor) &&
393         ((capture_flags & RTEMS_CAPTURE_GLOBAL_WATCH) ||
394          (control && (control->flags & RTEMS_CAPTURE_WATCH)))))
395    {
396      rtems_interrupt_level level;
397     
398      rtems_interrupt_disable (level);
399   
400      if (capture_count < capture_size)
401      {
402        capture_count++;
403        capture_in->task   = task;
404        capture_in->events = (events |
405                              (task->tcb->real_priority) |
406                              (task->tcb->current_priority << 8));
407
408        if ((events & RTEMS_CAPTURE_RECORD_EVENTS) == 0)
409          task->flags |= RTEMS_CAPTURE_TRACED;
410
411        rtems_capture_get_time (&capture_in->ticks, &capture_in->tick_offset);
412
413        if (capture_in == &capture_records[capture_size - 1])
414          capture_in = capture_records;
415        else
416          capture_in++;         
417      }
418      else
419        capture_flags |= RTEMS_CAPTURE_OVERFLOW;
420      rtems_interrupt_enable (level);
421    }
422  }
423}
424
425/*
426 * rtems_capture_create_task
427 *
428 *  DESCRIPTION:
429 *
430 * This function is called when a task is created.
431 *
432 */
433static rtems_boolean
434rtems_capture_create_task (rtems_tcb* current_task,
435                           rtems_tcb* new_task)
436{
437  rtems_capture_task_t* ct;
438  rtems_capture_task_t* nt;
439
440  ct = current_task->extensions[capture_extension_index];
441
442  /*
443   * The task ponters may not be known as the task may have
444   * been created before the capture engine was open. Add them.
445   */
446
447  if (ct == NULL)
448    ct = rtems_capture_create_capture_task (current_task);
449
450  /*
451   * Create the new task's capture control block.
452   */
453  nt = rtems_capture_create_capture_task (new_task);
454
455  /*
456   * If we are logging then record this fact.
457   */
458  rtems_capture_record (ct, RTEMS_CAPTURE_CREATED_BY_EVENT);
459  rtems_capture_record (nt, RTEMS_CAPTURE_CREATED_EVENT);
460
461  return 1 == 1;
462}
463
464/*
465 * rtems_capture_start_task
466 *
467 *  DESCRIPTION:
468 *
469 * This function is called when a task is started.
470 *
471 */
472static rtems_extension
473rtems_capture_start_task (rtems_tcb* current_task,
474                          rtems_tcb* started_task)
475{
476  /*
477   * Get the capture task control block so we can trace this
478   * event.
479   */
480  rtems_capture_task_t* ct;
481  rtems_capture_task_t* st;
482
483  ct = current_task->extensions[capture_extension_index];
484  st = started_task->extensions[capture_extension_index];
485
486  /*
487   * The task ponters may not be known as the task may have
488   * been created before the capture engine was open. Add them.
489   */
490
491  if (ct == NULL)
492    ct = rtems_capture_create_capture_task (current_task);
493
494  if (st == NULL)
495    st = rtems_capture_create_capture_task (started_task);
496
497  rtems_capture_record (ct, RTEMS_CAPTURE_STARTED_BY_EVENT);
498  rtems_capture_record (st, RTEMS_CAPTURE_STARTED_EVENT);
499 
500  rtems_capture_init_stack_usage (st);
501}
502
503/*
504 * rtems_capture_restart_task
505 *
506 *  DESCRIPTION:
507 *
508 * This function is called when a task is restarted.
509 *
510 */
511static rtems_extension
512rtems_capture_restart_task (rtems_tcb* current_task,
513                            rtems_tcb* restarted_task)
514{
515  /*
516   * Get the capture task control block so we can trace this
517   * event.
518   */
519  rtems_capture_task_t* ct;
520  rtems_capture_task_t* rt;
521
522  ct = current_task->extensions[capture_extension_index];
523  rt = restarted_task->extensions[capture_extension_index];
524
525  /*
526   * The task ponters may not be known as the task may have
527   * been created before the capture engine was open. Add them.
528   */
529
530  if (ct == NULL)
531    ct = rtems_capture_create_capture_task (current_task);
532
533  if (rt == NULL)
534    rt = rtems_capture_create_capture_task (restarted_task);
535
536  rtems_capture_record (ct, RTEMS_CAPTURE_RESTARTED_BY_EVENT);
537  rtems_capture_record (rt, RTEMS_CAPTURE_RESTARTED_EVENT);
538
539  rtems_capture_task_stack_usage (rt);
540  rtems_capture_init_stack_usage (rt);
541}
542
543/*
544 * rtems_capture_delete_task
545 *
546 *  DESCRIPTION:
547 *
548 * This function is called when a task is deleted.
549 *
550 */
551static rtems_extension
552rtems_capture_delete_task (rtems_tcb* current_task,
553                           rtems_tcb* deleted_task)
554{
555  /*
556   * Get the capture task control block so we can trace this
557   * event.
558   */
559  rtems_capture_task_t* ct;
560  rtems_capture_task_t* dt;
561
562  /*
563   * The task ponters may not be known as the task may have
564   * been created before the capture engine was open. Add them.
565   */
566
567  ct = current_task->extensions[capture_extension_index];
568  dt = deleted_task->extensions[capture_extension_index];
569
570  if (ct == NULL)
571    ct = rtems_capture_create_capture_task (current_task);
572
573  if (dt == NULL)
574    dt = rtems_capture_create_capture_task (deleted_task);
575
576  rtems_capture_record (ct, RTEMS_CAPTURE_DELETED_BY_EVENT);
577  rtems_capture_record (dt, RTEMS_CAPTURE_DELETED_EVENT);
578
579  rtems_capture_task_stack_usage (dt);
580
581  /*
582   * This task's tcb will be invalid.
583   */
584  dt->tcb = 0;
585}
586
587/*
588 * rtems_capture_begin_task
589 *
590 *  DESCRIPTION:
591 *
592 * This function is called when a task is begun.
593 *
594 */
595static rtems_extension
596rtems_capture_begin_task (rtems_tcb* begin_task)
597{
598  /*
599   * Get the capture task control block so we can trace this
600   * event.
601   */
602  rtems_capture_task_t* bt;
603
604  bt = begin_task->extensions[capture_extension_index];
605
606  /*
607   * The task ponters may not be known as the task may have
608   * been created before the capture engine was open. Add them.
609   */
610
611  if (bt == NULL)
612    bt = rtems_capture_create_capture_task (begin_task);
613
614  rtems_capture_record (bt, RTEMS_CAPTURE_BEGIN_EVENT);
615}
616
617/*
618 * rtems_capture_exitted_task
619 *
620 *  DESCRIPTION:
621 *
622 * This function is called when a task is exitted. That is
623 * returned rather than was deleted.
624 *
625 */
626static rtems_extension
627rtems_capture_exitted_task (rtems_tcb* exitted_task)
628{
629  /*
630   * Get the capture task control block so we can trace this
631   * event.
632   */
633  rtems_capture_task_t* et;
634
635  et = exitted_task->extensions[capture_extension_index];
636
637  /*
638   * The task ponters may not be known as the task may have
639   * been created before the capture engine was open. Add them.
640   */
641
642  if (et == NULL)
643    et = rtems_capture_create_capture_task (exitted_task);
644
645  rtems_capture_record (et, RTEMS_CAPTURE_EXITTED_EVENT);
646
647  rtems_capture_task_stack_usage (et);
648}
649
650/*
651 * rtems_capture_switch_task
652 *
653 *  DESCRIPTION:
654 *
655 * This function is called when a context is switched.
656 *
657 */
658static rtems_extension
659rtems_capture_switch_task (rtems_tcb* current_task,
660                           rtems_tcb* heir_task)
661{
662  /*
663   * Only perform context switch trace processing if tracing is
664   * enabled.
665   */
666  if (capture_flags & RTEMS_CAPTURE_ON)
667  {
668    rtems_unsigned32 ticks;
669    rtems_unsigned32 tick_offset;
670     
671    /*
672     * Get the cpature task control block so we can update the
673     * reference anbd perform any watch or trigger functions.
674     * The task ponters may not be known as the task may have
675     * been created before the capture engine was open. Add them.
676     */
677    rtems_capture_task_t* ct;
678    rtems_capture_task_t* ht;
679
680    if (_States_Is_transient (current_task->current_state))
681    {
682      rtems_id ct_id = current_task->Object.id;
683
684      for (ct = capture_tasks; ct; ct = ct->next)
685        if (ct->id == ct_id)
686          break;
687    }
688    else
689    {
690      ct = current_task->extensions[capture_extension_index];
691
692      if (ct == NULL)
693        ct = rtems_capture_create_capture_task (current_task);
694    }
695
696    ht = heir_task->extensions[capture_extension_index];
697
698    if (ht == NULL)
699      ht = rtems_capture_create_capture_task (heir_task);
700
701    /*
702     * Update the execution time. Assume the tick will not overflow
703     * for now. This may need to change.
704     */
705    rtems_capture_get_time (&ticks, &tick_offset);
706
707    /*
708     * We could end up with null pointers for both the current task
709     * and the heir task.
710     */
711
712    if (ht)
713    {
714      ht->in++;
715      ht->ticks_in       = ticks;
716      ht->tick_offset_in = tick_offset;
717    }
718 
719    if (ct)
720    {
721      ct->out++;
722      ct->ticks += ticks - ct->ticks_in;
723
724      if (capture_timestamp)
725      {
726        tick_offset += capture_tick_period - ct->tick_offset_in;
727 
728        if (tick_offset < capture_tick_period)
729          ct->tick_offset = tick_offset;
730        else
731        {
732          ct->ticks++;
733          ct->tick_offset = tick_offset - capture_tick_period;
734        }
735      }
736      else
737      {
738        ct->tick_offset += 100;
739      }
740    }
741
742    /*
743     * If we have not triggered then see if this is a trigger condition.
744     */
745    if (!(capture_flags & RTEMS_CAPTURE_TRIGGERED))
746    {
747      rtems_capture_control_t* cc = NULL;
748      rtems_capture_control_t* hc = NULL;
749
750      if (ct)
751      {
752        cc = ct->control;
753     
754        /*
755         * Check the current task for a TO_ANY trigger.
756         */
757        if (cc && (cc->flags & RTEMS_CAPTURE_TO_ANY))
758        {
759          capture_flags |= RTEMS_CAPTURE_TRIGGERED;
760          goto triggered;
761        }
762      }
763
764      if (ht)
765      {
766        hc = ht->control;
767
768        /*
769         * Check the next task for a FROM_ANY.
770         */
771        if (hc && (hc->flags & RTEMS_CAPTURE_FROM_ANY))
772        {
773          capture_flags |= RTEMS_CAPTURE_TRIGGERED;
774          goto triggered;
775        }
776      }
777
778      /*
779       * Check is the trigger is from the current task
780       * to the next task.
781       */
782      if (cc && hc && (hc->flags & RTEMS_CAPTURE_FROM_TO))
783        if (rtems_capture_name_in_group (cc->name, hc->from))
784        {
785          capture_flags |= RTEMS_CAPTURE_TRIGGERED;
786          goto triggered;
787        }
788    }
789    else
790    {
791triggered:
792
793      rtems_capture_record (ct, RTEMS_CAPTURE_SWITCHED_OUT_EVENT);
794      rtems_capture_record (ht, RTEMS_CAPTURE_SWITCHED_IN_EVENT);
795    }
796  }
797}
798
799/*
800 * rtems_capture_open
801 *
802 *  DESCRIPTION:
803 *
804 * This function initialises the realtime capture engine allocating the trace
805 * buffer. It is assumed we have a working heap at stage of initialisation.
806 *
807 */
808rtems_status_code
809rtems_capture_open (rtems_unsigned32 size, rtems_capture_timestamp timestamp)
810{
811  rtems_extensions_table capture_extensions;
812  rtems_name             name;
813  rtems_status_code      sc;
814
815  /*
816   * See if the capture engine is already open.
817   */
818
819  if (capture_records)
820    return RTEMS_RESOURCE_IN_USE;
821
822  capture_records = malloc (size * sizeof (rtems_capture_record_t));
823
824  if (capture_records == NULL)
825    return RTEMS_NO_MEMORY;
826
827  capture_size    = size;
828  capture_count   = 0;
829  capture_in      = capture_records;
830  capture_out     = 0;
831  capture_flags   = 0;
832  capture_tasks   = NULL;
833  capture_ceiling = 0;
834  capture_floor   = 255;
835
836  /*
837   * Create the extension table. This is copied so we
838   * can create it as a local.
839   */
840  capture_extensions.thread_create  = rtems_capture_create_task;
841  capture_extensions.thread_start   = rtems_capture_start_task;
842  capture_extensions.thread_restart = rtems_capture_restart_task;
843  capture_extensions.thread_delete  = rtems_capture_delete_task;
844  capture_extensions.thread_switch  = rtems_capture_switch_task;
845  capture_extensions.thread_begin   = rtems_capture_begin_task;
846  capture_extensions.thread_exitted = rtems_capture_exitted_task;
847  capture_extensions.fatal          = NULL;
848
849  /*
850   * Get the tick period from the BSP Configuration Table.
851   */
852  capture_tick_period = _Configuration_Table->microseconds_per_tick;
853 
854  /*
855   * Register the user extension handlers for the CAPture Engine.
856   */
857  name = rtems_build_name ('C', 'A', 'P', 'E');
858  sc   = rtems_extension_create (name, &capture_extensions, &capture_id);
859
860  if (sc != RTEMS_SUCCESSFUL)
861  {
862    capture_id = 0;
863    free (capture_records);
864    capture_records = NULL;
865  }
866  else
867  {
868    capture_extension_index = rtems_get_index (capture_id);;
869  }
870
871  /*
872   * Iterate over the list of existing tasks.
873   */
874
875  return sc;
876}
877
878/*
879 * rtems_capture_close
880 *
881 *  DESCRIPTION:
882 *
883 * This function shutdowns the capture engine and release any claimed
884 * resources.
885 */
886rtems_status_code
887rtems_capture_close ()
888{
889  rtems_interrupt_level    level;
890  rtems_capture_task_t*    task;
891  rtems_capture_control_t* control;
892  rtems_capture_record_t*  records;
893  rtems_status_code        sc;
894
895  rtems_interrupt_disable (level);
896
897  if (!capture_records)
898  {
899    rtems_interrupt_enable (level);
900    return RTEMS_SUCCESSFUL;
901  }
902
903  capture_flags &= ~RTEMS_CAPTURE_ON;
904
905  records = capture_records;
906  capture_records = NULL;
907
908  rtems_interrupt_enable (level);
909
910  /*
911   * Delete the extension first. This means we are now able to
912   * release the resources we have without them being used.
913   */
914
915  sc = rtems_extension_delete (capture_id);
916
917  if (sc != RTEMS_SUCCESSFUL)
918    return sc;
919
920  task = capture_tasks;
921 
922  while (task)
923  {
924    rtems_capture_task_t* delete = task;
925    task = task->next;
926    _Workspace_Free (delete);
927  }
928
929  capture_tasks = NULL;
930
931  control = capture_controls;
932 
933  while (control)
934  {
935    rtems_capture_control_t* delete = control;
936    control = control->next;
937    _Workspace_Free (delete);
938  }
939
940  capture_controls = NULL;
941
942  if (capture_records)
943  {
944    free (capture_records);
945    capture_records = NULL;
946  }
947
948  return RTEMS_SUCCESSFUL;
949}
950
951/*
952 * rtems_capture_control
953 *
954 *  DESCRIPTION:
955 *
956 * This function allows control of tracing at a global level.
957 */
958rtems_status_code
959rtems_capture_control (rtems_boolean enable)
960{
961  rtems_interrupt_level level;
962
963  rtems_interrupt_disable (level);
964
965  if (!capture_records)
966  {
967    rtems_interrupt_enable (level);
968    return RTEMS_UNSATISFIED;
969  }
970
971  if (enable)
972    capture_flags |= RTEMS_CAPTURE_ON;
973  else
974    capture_flags &= ~RTEMS_CAPTURE_ON;
975
976  rtems_interrupt_enable (level);
977
978  return RTEMS_SUCCESSFUL;
979}
980
981/*
982 * rtems_capture_flush
983 *
984 *  DESCRIPTION:
985 *
986 * This function flushes the capture buffer. The prime parameter allows the
987 * capture engine to also be primed again.
988 */
989rtems_status_code
990rtems_capture_flush (rtems_boolean prime)
991{
992  rtems_interrupt_level level;
993  rtems_capture_task_t* task;
994
995  rtems_interrupt_disable (level);
996
997  for (task = capture_tasks; task != NULL; task = task->next)
998    task->flags &= ~RTEMS_CAPTURE_TRACED;
999
1000  if (prime)
1001    capture_flags &= ~(RTEMS_CAPTURE_TRIGGERED | RTEMS_CAPTURE_OVERFLOW);
1002  else
1003    capture_flags &= ~RTEMS_CAPTURE_OVERFLOW;
1004
1005  capture_in     = capture_records;
1006  capture_out    = 0;
1007
1008  rtems_interrupt_enable (level);
1009
1010  return RTEMS_SUCCESSFUL;
1011}
1012
1013/*
1014 * rtems_capture_watch_add
1015 *
1016 *  DESCRIPTION:
1017 *
1018 * This function defines a watch for a specific task given a name. A watch
1019 * causes it to be traced either in or out of context. The watch can be
1020 * optionally enabled or disabled with the set routine. It is disabled by
1021 * default.
1022 */
1023rtems_status_code
1024rtems_capture_watch_add (rtems_name name, rtems_id id)
1025{
1026  rtems_capture_control_t* control;
1027
1028  if ((name == 0) && (id == 0))
1029    return RTEMS_UNSATISFIED;
1030
1031  control = rtems_capture_find_control (name, id);
1032
1033  if (control && !id)
1034    return RTEMS_TOO_MANY;
1035
1036  if (!control)
1037    control = rtems_capture_create_control (name, id);
1038
1039  if (!control)
1040    return RTEMS_NO_MEMORY;
1041
1042  return RTEMS_SUCCESSFUL;
1043}
1044
1045/*
1046 * rtems_capture_watch_del
1047 *
1048 *  DESCRIPTION:
1049 *
1050 * This function removes a watch for a specific task given a name. The task
1051 * description will still exist if referenced by a trace record in the trace
1052 * buffer or a global watch is defined.
1053 */
1054rtems_status_code
1055rtems_capture_watch_del (rtems_name name, rtems_id id)
1056{
1057  rtems_interrupt_level     level;
1058  rtems_capture_control_t*  control;
1059  rtems_capture_control_t** prev_control;
1060  rtems_capture_task_t*     task;
1061  rtems_boolean             found = 0;
1062
1063  /*
1064   * Should this test be for wildcards ?
1065   */
1066
1067  for (prev_control = &capture_controls, control = capture_controls;
1068       control != NULL; )
1069  {
1070    if (rtems_capture_match_name_id (name, id, control->name, control->id))
1071    {
1072      rtems_interrupt_disable (level);
1073     
1074      for (task = capture_tasks; task != NULL; task = task->next)
1075        if (task->control == control)
1076          task->control = 0;
1077
1078      *prev_control = control->next;
1079
1080      rtems_interrupt_enable (level);
1081
1082      _Workspace_Free (control);
1083
1084      control = *prev_control;
1085
1086      found = 1;
1087    }
1088    else
1089    {
1090      prev_control = &control->next;
1091      control      = control->next;
1092      }
1093  }
1094
1095  if (found)
1096    return RTEMS_SUCCESSFUL;
1097
1098  return RTEMS_INVALID_NAME;
1099}
1100
1101/*
1102 * rtems_capture_watch_set
1103 *
1104 *  DESCRIPTION:
1105 *
1106 * This function allows control of a watch. The watch can be enabled or
1107 * disabled.
1108 */
1109rtems_status_code
1110rtems_capture_watch_ctrl (rtems_name name, rtems_id id, rtems_boolean enable)
1111{
1112  rtems_interrupt_level    level;
1113  rtems_capture_control_t* control;
1114  rtems_boolean            found = 0;
1115 
1116  /*
1117   * Find the control and then set the watch. It must exist before it can
1118   * be controlled.
1119   */
1120  for (control = capture_controls; control != NULL; control = control->next)
1121  {
1122    if (rtems_capture_match_name_id (name, id, control->name, control->id))
1123    {
1124      rtems_interrupt_disable (level);
1125
1126      if (enable)
1127        control->flags |= RTEMS_CAPTURE_WATCH;
1128      else
1129        control->flags &= ~RTEMS_CAPTURE_WATCH;
1130
1131      rtems_interrupt_enable (level);
1132
1133      found = 1;
1134    }   
1135  }
1136
1137  if (found)
1138    return RTEMS_SUCCESSFUL;
1139
1140  return RTEMS_INVALID_NAME;
1141}
1142
1143/*
1144 * rtems_capture_watch_global
1145 *
1146 *  DESCRIPTION:
1147 *
1148 * This function allows control of a global watch. The watch can be enabled or
1149 * disabled. A global watch configures all tasks below the ceiling and above
1150 * the floor to be traced.
1151 */
1152rtems_status_code
1153rtems_capture_watch_global (rtems_boolean enable)
1154{
1155  rtems_interrupt_level level;
1156 
1157  rtems_interrupt_disable (level);
1158
1159  /*
1160   * We need to keep specific and global watches separate so
1161   * a global enable/disable does not lose a specific watch.
1162   */
1163  if (enable)
1164    capture_flags |= RTEMS_CAPTURE_GLOBAL_WATCH;
1165  else
1166    capture_flags &= ~RTEMS_CAPTURE_GLOBAL_WATCH;
1167
1168  rtems_interrupt_enable (level);
1169
1170  return RTEMS_SUCCESSFUL;
1171}
1172
1173/*
1174 * rtems_capture_watch_global_on
1175 *
1176 *  DESCRIPTION:
1177 *
1178 * This function returns the global watch state.
1179 */
1180rtems_boolean
1181rtems_capture_watch_global_on ()
1182{
1183  return capture_flags & RTEMS_CAPTURE_GLOBAL_WATCH ? 1 : 0;
1184}
1185
1186/*
1187 * rtems_capture_watch_ceiling
1188 *
1189 *  DESCRIPTION:
1190 *
1191 * This function sets a watch ceiling. Tasks at or greating that the
1192 * ceiling priority are not watched. This is a simple way to monitor
1193 * an application and exclude system tasks running at a higher
1194 * priority level.
1195 */
1196rtems_status_code
1197rtems_capture_watch_ceiling (rtems_task_priority ceiling)
1198{
1199  capture_ceiling = ceiling;
1200  return RTEMS_SUCCESSFUL;
1201}
1202
1203/*
1204 * rtems_capture_watch_get_ceiling
1205 *
1206 *  DESCRIPTION:
1207 *
1208 * This function gets the watch ceiling.
1209 */
1210rtems_task_priority
1211rtems_capture_watch_get_ceiling ()
1212{
1213  return capture_ceiling;
1214}
1215
1216/*
1217 * rtems_capture_watch_floor
1218 *
1219 *  DESCRIPTION:
1220 *
1221 * This function sets a watch floor. Tasks at or less that the
1222 * floor priority are not watched. This is a simple way to monitor
1223 * an application and exclude system tasks running at a lower
1224 * priority level.
1225 */
1226rtems_status_code
1227rtems_capture_watch_floor (rtems_task_priority floor)
1228{
1229  capture_floor = floor;
1230  return RTEMS_SUCCESSFUL;
1231}
1232
1233/*
1234 * rtems_capture_watch_get_floor
1235 *
1236 *  DESCRIPTION:
1237 *
1238 * This function gets the watch floor.
1239 */
1240rtems_task_priority
1241rtems_capture_watch_get_floor ()
1242{
1243  return capture_floor;
1244}
1245
1246/*
1247 * rtems_capture_set_trigger
1248 *
1249 *  DESCRIPTION:
1250 *
1251 * This function sets an edge trigger. Left is the left side of
1252 * the edge and right is right side of the edge. The trigger type
1253 * can be -
1254 *
1255 *  FROM_ANY : a switch from any task to the right side of the edge.
1256 *  TO_ANY   : a switch from the left side of the edge to any task.
1257 *  FROM_TO  : a switch from the left side of the edge to the right
1258 *             side of the edge.
1259 *
1260 * This set trigger routine will create a capture control for the
1261 * target task. The task list is searched and any existing tasks
1262 * are linked to the new control.
1263 *
1264 * We can have a number of tasks that have the same name so we
1265 * search using names. This means a number of tasks can be
1266 * linked to single control.
1267 */
1268rtems_status_code
1269rtems_capture_set_trigger (rtems_name              from,
1270                           rtems_id                from_id,
1271                           rtems_name              to,
1272                           rtems_id                to_id,
1273                           rtems_capture_trigger_t trigger)
1274{
1275  rtems_capture_control_t* control;
1276  int                      i;
1277 
1278  /*
1279   * Find the capture control blocks for the from and to
1280   * tasks.
1281   */
1282  if (trigger == rtems_capture_to_any)
1283  {
1284    control = rtems_capture_create_control (from, from_id);
1285    if (control == NULL)
1286      return RTEMS_NO_MEMORY;
1287    control->flags |= RTEMS_CAPTURE_TO_ANY;
1288  }
1289
1290  if ((trigger == rtems_capture_from_to) ||
1291      (trigger == rtems_capture_from_any))
1292  {
1293    control = rtems_capture_create_control (to, to_id);
1294    if (control == NULL)
1295      return RTEMS_NO_MEMORY;
1296   
1297    if (trigger == rtems_capture_from_any)
1298      control->flags |= RTEMS_CAPTURE_FROM_ANY;
1299    else
1300    {
1301      control->flags |= RTEMS_CAPTURE_FROM_TO;
1302      for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
1303      {
1304        if (control->from[i] == 0)
1305        {
1306          control->from[i]    = from;
1307          control->from_id[i] = from_id;
1308          break;
1309        }
1310      }
1311    }
1312  }
1313  return RTEMS_SUCCESSFUL;
1314}
1315
1316/*
1317 * rtems_capture_read
1318 *
1319 *  DESCRIPTION:
1320 *
1321 * This function reads a number of records from the capture buffer.
1322 * The user can optionally block and wait until the buffer as a
1323 * specific number of records available or a specific time has
1324 * elasped.
1325 *
1326 * The function returns the number of record that is has that are
1327 * in a continous block of memory. If the number of available records
1328 * wrap then only those records are provided. This removes the need for
1329 * caller to be concerned about buffer wrappings. If the number of
1330 * requested records cannot be met due to the wrapping of the records
1331 * less than the specified number will be returned.
1332 *
1333 * The user must release the records. This is achieved with a call to
1334 * rtems_capture_release. Calls this function without a release will
1335 * result in at least the same number of records being released.
1336 *
1337 * The 'threshold' parameter is the number of records that must be
1338 * captured before returning. If a timeout period is specified (non-0)
1339 * any captured records will be returned. These parameters stop
1340 * thrashing occuring for a small number of records, yet allows
1341 * a user configured latiency to be applied for single events.
1342 *
1343 * The 'timeout' parameter is in micro-seconds. A value of 0 will disable
1344 * the timeout.
1345 *
1346 */
1347rtems_status_code
1348rtems_capture_read (rtems_unsigned32         threshold,
1349                    rtems_unsigned32         timeout,
1350                    rtems_unsigned32*        read,
1351                    rtems_capture_record_t** recs)
1352{
1353  rtems_interrupt_level level;
1354  rtems_status_code     sc = RTEMS_SUCCESSFUL;
1355  rtems_unsigned32      count;
1356
1357  *read = 0;
1358  *recs = NULL;
1359
1360  rtems_interrupt_disable (level);
1361
1362  /*
1363   * Only one reader is allowed.
1364   */
1365
1366  if (capture_flags & RTEMS_CAPTURE_READER_ACTIVE)
1367  {
1368    rtems_interrupt_enable (level);
1369    return RTEMS_RESOURCE_IN_USE;
1370  }
1371
1372  capture_flags |= RTEMS_CAPTURE_READER_ACTIVE;
1373  *read = count = capture_count;
1374
1375  rtems_interrupt_enable (level);
1376
1377  *recs = &capture_records[capture_out];
1378
1379  for (;;)
1380  {
1381    /*
1382     * See if the count wraps the end of the record buffer.
1383     */
1384    if (count && ((capture_out + count) >= capture_size))
1385      *read = capture_size - capture_out;
1386     
1387    /*
1388     * Do we have a threshold and the current count has not wrapped
1389     * around the end of the capture record buffer ?
1390     */
1391    if ((*read == count) && threshold)
1392    {
1393      /*
1394       * Do we have enough records ?
1395       */
1396      if (*read < threshold)
1397      {
1398        rtems_event_set event_out;
1399
1400        rtems_task_ident (RTEMS_SELF, RTEMS_LOCAL, &capture_reader);
1401
1402        rtems_interrupt_disable (level);
1403         
1404        capture_flags |= RTEMS_CAPTURE_READER_WAITING;
1405
1406        rtems_interrupt_enable (level);
1407         
1408        sc = rtems_event_receive (RTEMS_EVENT_0,
1409                                  RTEMS_WAIT | RTEMS_EVENT_ANY,
1410                                  TOD_MICROSECONDS_TO_TICKS (timeout),
1411                                  &event_out);
1412
1413        /*
1414         * Let the user handle all other sorts of errors. This may
1415         * not be the best solution, but oh well, it will do for
1416         * now.
1417         */
1418        if ((sc != RTEMS_SUCCESSFUL) && (sc != RTEMS_TIMEOUT))
1419          break;
1420
1421        rtems_interrupt_disable (level);
1422
1423        *read = count = capture_count;
1424
1425        rtems_interrupt_enable (level);
1426
1427        continue;
1428      }
1429    }
1430
1431    /*
1432     * Always out if we reach here. To loop use continue.
1433     */
1434    break;
1435  }
1436
1437  rtems_interrupt_disable (level);
1438
1439  capture_flags &= ~RTEMS_CAPTURE_READER_ACTIVE;
1440
1441  rtems_interrupt_enable (level);
1442
1443  return sc;
1444}
1445
1446/*
1447 * rtems_capture_release
1448 *
1449 *  DESCRIPTION:
1450 *
1451 * This function releases the requested number of record slots back
1452 * to the capture engine. The count must match the number read.
1453 */
1454rtems_status_code
1455rtems_capture_release (rtems_unsigned32 count)
1456{
1457  rtems_interrupt_level level;
1458
1459  rtems_interrupt_disable (level);
1460
1461  if (count > capture_count)
1462    count = capture_count;
1463
1464  capture_count -= count;
1465
1466  capture_out = (capture_count + count) % capture_size;
1467
1468  rtems_interrupt_enable (level);
1469
1470  return RTEMS_SUCCESSFUL;
1471}
1472
1473/*
1474 * rtems_capture_tick_time
1475 *
1476 *  DESCRIPTION:
1477 *
1478 * This function returns the tick period in nano-seconds.
1479 */
1480rtems_unsigned32
1481rtems_capture_tick_time ()
1482{
1483  return capture_tick_period;
1484}
1485
1486/*
1487 * rtems_capture_event_text
1488 *
1489 *  DESCRIPTION:
1490 *
1491 * This function returns a string for an event based on the bit in the
1492 * event. The functions takes the bit offset as a number not the bit
1493 * set in a bit map.
1494 */
1495const char*
1496rtems_capture_event_text (int event)
1497{
1498  if ((event < RTEMS_CAPTURE_EVENT_START) || (event > RTEMS_CAPTURE_EVENT_END))
1499    return "invalid event id";
1500  return capture_event_text[event - RTEMS_CAPTURE_EVENT_START];
1501}
1502
1503/*
1504 * rtems_capture_get_task_list
1505 *
1506 *  DESCRIPTION:
1507 *
1508 * This function returns the head of the list of tasks that the
1509 * capture engine has detected.
1510 */
1511rtems_capture_task_t*
1512rtems_capture_get_task_list ()
1513{
1514  return capture_tasks;
1515}
1516
1517/*
1518 * rtems_capture_task_stack_usage
1519 *
1520 *  DESCRIPTION:
1521 *
1522 * This function updates the stack usage. The task control block
1523 * is updated.
1524 */
1525rtems_unsigned32
1526rtems_capture_task_stack_usage (rtems_capture_task_t* task)
1527{
1528  if (task->tcb)
1529  {
1530    rtems_unsigned32* st;
1531    rtems_unsigned32* s;
1532
1533    /*
1534     * @todo: Assumes all stacks move the same way.
1535     */
1536    st = task->tcb->Start.Initial_stack.area + task->stack_size;
1537    s  = task->tcb->Start.Initial_stack.area;
1538
1539    while (s < st)
1540    {
1541      if (*s != 0xdeaddead)
1542        break;
1543      s++;
1544    }
1545
1546    task->stack_clean =
1547      s - (rtems_unsigned32*) task->tcb->Start.Initial_stack.area;
1548  }
1549
1550  return task->stack_clean;
1551}
1552
1553/*
1554 * rtems_capture_get_control_list
1555 *
1556 *  DESCRIPTION:
1557 *
1558 * This function returns the head of the list of control in the
1559 * capture engine.
1560 */
1561rtems_capture_control_t*
1562rtems_capture_get_control_list ()
1563{
1564  return capture_controls;
1565}
1566
Note: See TracBrowser for help on using the repository browser.