source: rtems/cpukit/libmisc/capture/capture.c @ 1af8634a

4.115
Last change on this file since 1af8634a was 1af8634a, checked in by Jennifer Averett <jennifer.averett@…>, on 04/11/14 at 15:18:20

capture: Update comment block style in capture engine.

Doxygen added and comment blocks standardized.

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