source: rtems/cpukit/libmisc/capture/capture.c @ 78b867e2

4.10
Last change on this file since 78b867e2 was 78b867e2, checked in by Gedare Bloom <gedare@…>, on 12/21/17 at 16:49:30

score: replace current and real priority with priority node

Encapsulate the current_priority and real_priority fields of
the thread control block with a Thread_Priority_node struct.
Propagate modifications throughout the tree where the two
fields are directly accessed.

Updates #3359.

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