source: rtems/cpukit/libmisc/capture/capture.c @ 77c4089

Last change on this file since 77c4089 was b9e230a2, checked in by Ralf Corsepius <ralf.corsepius@…>, on Jul 8, 2003 at 8:38:15 AM

2003-07-08 Ralf Corsepius <corsepiu@…>

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