source: rtems/cpukit/libmisc/capture/capture.c @ 721fe34

4.11
Last change on this file since 721fe34 was 721fe34, checked in by Joel Sherrill <joel.sherrill@…>, on May 31, 2012 at 8:34:36 PM

Fix C files which had two semi-colons at EOL

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