source: rtems/cpukit/libmisc/capture/capture.c @ 6dad79f

4.104.115
Last change on this file since 6dad79f was 6dad79f, checked in by Joel Sherrill <joel.sherrill@…>, on 09/11/09 at 14:53:40

2009-09-11 Joel Sherrill <joel.sherrill@…>

  • libmisc/capture/capture.c: Use public API to obtain object name.
  • 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-2008.
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->real_priority >= capture_ceiling) &&
535         (task->tcb->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->real_priority) |
549                              (task->tcb->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 rtems_extension
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 rtems_extension
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 rtems_extension
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 rtems_extension
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 rtems_extension
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 rtems_extension
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    if (_States_Is_transient (current_task->current_state))
913    {
914      rtems_id ct_id = current_task->Object.id;
915
916      for (ct = capture_tasks; ct; ct = ct->forw)
917        if (ct->id == ct_id)
918          break;
919    }
920    else
921    {
922      ct = current_task->extensions[capture_extension_index];
923
924      if (ct == NULL)
925        ct = rtems_capture_create_capture_task (current_task);
926    }
927
928    ht = heir_task->extensions[capture_extension_index];
929
930    if (ht == NULL)
931      ht = rtems_capture_create_capture_task (heir_task);
932
933    /*
934     * Update the execution time. Assume the tick will not overflow
935     * for now. This may need to change.
936     */
937    rtems_capture_get_time (&ticks, &tick_offset);
938
939    /*
940     * We could end up with null pointers for both the current task
941     * and the heir task.
942     */
943
944    if (ht)
945    {
946      ht->in++;
947      ht->ticks_in       = ticks;
948      ht->tick_offset_in = tick_offset;
949    }
950
951    if (ct)
952    {
953      ct->out++;
954      ct->ticks += ticks - ct->ticks_in;
955
956      if (capture_timestamp)
957      {
958        tick_offset += capture_tick_period - ct->tick_offset_in;
959
960        if (tick_offset < capture_tick_period)
961          ct->tick_offset = tick_offset;
962        else
963        {
964          ct->ticks++;
965          ct->tick_offset = tick_offset - capture_tick_period;
966        }
967      }
968      else
969      {
970        ct->tick_offset += 100;
971      }
972    }
973
974    if (rtems_capture_trigger (ct, ht, RTEMS_CAPTURE_SWITCH))
975    {
976      rtems_capture_record (ct, RTEMS_CAPTURE_SWITCHED_OUT_EVENT);
977      rtems_capture_record (ht, RTEMS_CAPTURE_SWITCHED_IN_EVENT);
978    }
979  }
980}
981
982/*
983 * rtems_capture_open
984 *
985 *  DESCRIPTION:
986 *
987 * This function initialises the realtime capture engine allocating the trace
988 * buffer. It is assumed we have a working heap at stage of initialisation.
989 *
990 */
991rtems_status_code
992rtems_capture_open (uint32_t   size, rtems_capture_timestamp timestamp __attribute__((unused)))
993{
994  rtems_extensions_table capture_extensions;
995  rtems_name             name;
996  rtems_status_code      sc;
997
998  /*
999   * See if the capture engine is already open.
1000   */
1001
1002  if (capture_records)
1003    return RTEMS_RESOURCE_IN_USE;
1004
1005  capture_records = malloc (size * sizeof (rtems_capture_record_t));
1006
1007  if (capture_records == NULL)
1008    return RTEMS_NO_MEMORY;
1009
1010  capture_size    = size;
1011  capture_count   = 0;
1012  capture_in      = capture_records;
1013  capture_out     = 0;
1014  capture_flags   = 0;
1015  capture_tasks   = NULL;
1016  capture_ceiling = 0;
1017  capture_floor   = 255;
1018
1019  /*
1020   * Create the extension table. This is copied so we
1021   * can create it as a local.
1022   */
1023  capture_extensions.thread_create  = rtems_capture_create_task;
1024  capture_extensions.thread_start   = rtems_capture_start_task;
1025  capture_extensions.thread_restart = rtems_capture_restart_task;
1026  capture_extensions.thread_delete  = rtems_capture_delete_task;
1027  capture_extensions.thread_switch  = rtems_capture_switch_task;
1028  capture_extensions.thread_begin   = rtems_capture_begin_task;
1029  capture_extensions.thread_exitted = rtems_capture_exitted_task;
1030  capture_extensions.fatal          = NULL;
1031
1032  /*
1033   * Get the tick period from the BSP Configuration Table.
1034   */
1035  capture_tick_period = Configuration.microseconds_per_tick;
1036
1037  /*
1038   * Register the user extension handlers for the CAPture Engine.
1039   */
1040  name = rtems_build_name ('C', 'A', 'P', 'E');
1041  sc   = rtems_extension_create (name, &capture_extensions, &capture_id);
1042
1043  if (sc != RTEMS_SUCCESSFUL)
1044  {
1045    capture_id = 0;
1046    free (capture_records);
1047    capture_records = NULL;
1048  }
1049  else
1050  {
1051    capture_extension_index = rtems_object_id_get_index (capture_id);;
1052  }
1053
1054  /*
1055   * Iterate over the list of existing tasks.
1056   */
1057
1058  return sc;
1059}
1060
1061/*
1062 * rtems_capture_close
1063 *
1064 *  DESCRIPTION:
1065 *
1066 * This function shutdowns the capture engine and release any claimed
1067 * resources.
1068 */
1069rtems_status_code
1070rtems_capture_close (void)
1071{
1072  rtems_interrupt_level    level;
1073  rtems_capture_task_t*    task;
1074  rtems_capture_control_t* control;
1075  rtems_capture_record_t*  records;
1076  rtems_status_code        sc;
1077
1078  rtems_interrupt_disable (level);
1079
1080  if (!capture_records)
1081  {
1082    rtems_interrupt_enable (level);
1083    return RTEMS_SUCCESSFUL;
1084  }
1085
1086  capture_flags &= ~(RTEMS_CAPTURE_ON | RTEMS_CAPTURE_ONLY_MONITOR);
1087
1088  records = capture_records;
1089  capture_records = NULL;
1090
1091  rtems_interrupt_enable (level);
1092
1093  /*
1094   * Delete the extension first. This means we are now able to
1095   * release the resources we have without them being used.
1096   */
1097
1098  sc = rtems_extension_delete (capture_id);
1099
1100  if (sc != RTEMS_SUCCESSFUL)
1101    return sc;
1102
1103  task = capture_tasks;
1104
1105  while (task)
1106  {
1107    rtems_capture_task_t* delete = task;
1108    task = task->forw;
1109    _Workspace_Free (delete);
1110  }
1111
1112  capture_tasks = NULL;
1113
1114  control = capture_controls;
1115
1116  while (control)
1117  {
1118    rtems_capture_control_t* delete = control;
1119    control = control->next;
1120    _Workspace_Free (delete);
1121  }
1122
1123  capture_controls = NULL;
1124
1125  if (capture_records)
1126  {
1127    free (capture_records);
1128    capture_records = NULL;
1129  }
1130
1131  return RTEMS_SUCCESSFUL;
1132}
1133
1134/*
1135 * rtems_capture_control
1136 *
1137 *  DESCRIPTION:
1138 *
1139 * This function allows control of tracing at a global level.
1140 */
1141rtems_status_code
1142rtems_capture_control (bool enable)
1143{
1144  rtems_interrupt_level level;
1145
1146  rtems_interrupt_disable (level);
1147
1148  if (!capture_records)
1149  {
1150    rtems_interrupt_enable (level);
1151    return RTEMS_UNSATISFIED;
1152  }
1153
1154  if (enable)
1155    capture_flags |= RTEMS_CAPTURE_ON;
1156  else
1157    capture_flags &= ~RTEMS_CAPTURE_ON;
1158
1159  rtems_interrupt_enable (level);
1160
1161  return RTEMS_SUCCESSFUL;
1162}
1163
1164/*
1165 * rtems_capture_monitor
1166 *
1167 *  DESCRIPTION:
1168 *
1169 * This function enable the monitor mode. When in the monitor mode
1170 * the tasks are monitored but no data is saved. This can be used
1171 * to profile the load on a system.
1172 */
1173rtems_status_code
1174rtems_capture_monitor (bool enable)
1175{
1176  rtems_interrupt_level level;
1177
1178  rtems_interrupt_disable (level);
1179
1180  if (!capture_records)
1181  {
1182    rtems_interrupt_enable (level);
1183    return RTEMS_UNSATISFIED;
1184  }
1185
1186  if (enable)
1187    capture_flags |= RTEMS_CAPTURE_ONLY_MONITOR;
1188  else
1189    capture_flags &= ~RTEMS_CAPTURE_ONLY_MONITOR;
1190
1191  rtems_interrupt_enable (level);
1192
1193  return RTEMS_SUCCESSFUL;
1194}
1195
1196/*
1197 * rtems_capture_flush
1198 *
1199 *  DESCRIPTION:
1200 *
1201 * This function flushes the capture buffer. The prime parameter allows the
1202 * capture engine to also be primed again.
1203 */
1204rtems_status_code
1205rtems_capture_flush (bool prime)
1206{
1207  rtems_interrupt_level level;
1208  rtems_capture_task_t* task;
1209
1210  rtems_interrupt_disable (level);
1211
1212  for (task = capture_tasks; task != NULL; task = task->forw)
1213  {
1214    task->flags &= ~RTEMS_CAPTURE_TRACED;
1215    task->refcount = 0;
1216  }
1217
1218  if (prime)
1219    capture_flags &= ~(RTEMS_CAPTURE_TRIGGERED | RTEMS_CAPTURE_OVERFLOW);
1220  else
1221    capture_flags &= ~RTEMS_CAPTURE_OVERFLOW;
1222
1223  capture_count = 0;
1224  capture_in    = capture_records;
1225  capture_out   = 0;
1226 
1227  rtems_interrupt_enable (level);
1228
1229  task = capture_tasks;
1230
1231  while (task)
1232  {
1233    rtems_capture_task_t* check = task;
1234    task = task->forw;
1235    rtems_capture_destroy_capture_task (check);
1236  }
1237
1238  return RTEMS_SUCCESSFUL;
1239}
1240
1241/*
1242 * rtems_capture_watch_add
1243 *
1244 *  DESCRIPTION:
1245 *
1246 * This function defines a watch for a specific task given a name. A watch
1247 * causes it to be traced either in or out of context. The watch can be
1248 * optionally enabled or disabled with the set routine. It is disabled by
1249 * default.
1250 */
1251rtems_status_code
1252rtems_capture_watch_add (rtems_name name, rtems_id id)
1253{
1254  rtems_capture_control_t* control;
1255
1256  if ((name == 0) && (id == 0))
1257    return RTEMS_UNSATISFIED;
1258
1259  control = rtems_capture_find_control (name, id);
1260
1261  if (control && !id)
1262    return RTEMS_TOO_MANY;
1263
1264  if (!control)
1265    control = rtems_capture_create_control (name, id);
1266
1267  if (!control)
1268    return RTEMS_NO_MEMORY;
1269
1270  return RTEMS_SUCCESSFUL;
1271}
1272
1273/*
1274 * rtems_capture_watch_del
1275 *
1276 *  DESCRIPTION:
1277 *
1278 * This function removes a watch for a specific task given a name. The task
1279 * description will still exist if referenced by a trace record in the trace
1280 * buffer or a global watch is defined.
1281 */
1282rtems_status_code
1283rtems_capture_watch_del (rtems_name name, rtems_id id)
1284{
1285  rtems_interrupt_level     level;
1286  rtems_capture_control_t*  control;
1287  rtems_capture_control_t** prev_control;
1288  rtems_capture_task_t*     task;
1289  bool                      found = false;
1290
1291  /*
1292   * Should this test be for wildcards ?
1293   */
1294
1295  for (prev_control = &capture_controls, control = capture_controls;
1296       control != NULL; )
1297  {
1298    if (rtems_capture_match_name_id (control->name, control->id, name, id))
1299    {
1300      rtems_interrupt_disable (level);
1301
1302      for (task = capture_tasks; task != NULL; task = task->forw)
1303        if (task->control == control)
1304          task->control = 0;
1305
1306      *prev_control = control->next;
1307
1308      rtems_interrupt_enable (level);
1309
1310      _Workspace_Free (control);
1311
1312      control = *prev_control;
1313
1314      found = true;
1315    }
1316    else
1317    {
1318      prev_control = &control->next;
1319      control      = control->next;
1320    }
1321  }
1322
1323  if (found)
1324    return RTEMS_SUCCESSFUL;
1325
1326  return RTEMS_INVALID_NAME;
1327}
1328
1329/*
1330 * rtems_capture_watch_set
1331 *
1332 *  DESCRIPTION:
1333 *
1334 * This function allows control of a watch. The watch can be enabled or
1335 * disabled.
1336 */
1337rtems_status_code
1338rtems_capture_watch_ctrl (rtems_name name, rtems_id id, bool enable)
1339{
1340  rtems_interrupt_level    level;
1341  rtems_capture_control_t* control;
1342  bool                     found = false;
1343
1344  /*
1345   * Find the control and then set the watch. It must exist before it can
1346   * be controlled.
1347   */
1348  for (control = capture_controls; control != NULL; control = control->next)
1349  {
1350    if (rtems_capture_match_name_id (control->name, control->id, name, id))
1351    {
1352      rtems_interrupt_disable (level);
1353
1354      if (enable)
1355        control->flags |= RTEMS_CAPTURE_WATCH;
1356      else
1357        control->flags &= ~RTEMS_CAPTURE_WATCH;
1358
1359      rtems_interrupt_enable (level);
1360
1361      found = true;
1362    }
1363  }
1364
1365  if (found)
1366    return RTEMS_SUCCESSFUL;
1367
1368  return RTEMS_INVALID_NAME;
1369}
1370
1371/*
1372 * rtems_capture_watch_global
1373 *
1374 *  DESCRIPTION:
1375 *
1376 * This function allows control of a global watch. The watch can be enabled or
1377 * disabled. A global watch configures all tasks below the ceiling and above
1378 * the floor to be traced.
1379 */
1380rtems_status_code
1381rtems_capture_watch_global (bool enable)
1382{
1383  rtems_interrupt_level level;
1384
1385  rtems_interrupt_disable (level);
1386
1387  /*
1388   * We need to keep specific and global watches separate so
1389   * a global enable/disable does not lose a specific watch.
1390   */
1391  if (enable)
1392    capture_flags |= RTEMS_CAPTURE_GLOBAL_WATCH;
1393  else
1394    capture_flags &= ~RTEMS_CAPTURE_GLOBAL_WATCH;
1395
1396  rtems_interrupt_enable (level);
1397
1398  return RTEMS_SUCCESSFUL;
1399}
1400
1401/*
1402 * rtems_capture_watch_global_on
1403 *
1404 *  DESCRIPTION:
1405 *
1406 * This function returns the global watch state.
1407 */
1408bool
1409rtems_capture_watch_global_on (void)
1410{
1411  return capture_flags & RTEMS_CAPTURE_GLOBAL_WATCH ? 1 : 0;
1412}
1413
1414/*
1415 * rtems_capture_watch_ceiling
1416 *
1417 *  DESCRIPTION:
1418 *
1419 * This function sets a watch ceiling. Tasks at or greating that the
1420 * ceiling priority are not watched. This is a simple way to monitor
1421 * an application and exclude system tasks running at a higher
1422 * priority level.
1423 */
1424rtems_status_code
1425rtems_capture_watch_ceiling (rtems_task_priority ceiling)
1426{
1427  capture_ceiling = ceiling;
1428  return RTEMS_SUCCESSFUL;
1429}
1430
1431/*
1432 * rtems_capture_watch_get_ceiling
1433 *
1434 *  DESCRIPTION:
1435 *
1436 * This function gets the watch ceiling.
1437 */
1438rtems_task_priority
1439rtems_capture_watch_get_ceiling (void)
1440{
1441  return capture_ceiling;
1442}
1443
1444/*
1445 * rtems_capture_watch_floor
1446 *
1447 *  DESCRIPTION:
1448 *
1449 * This function sets a watch floor. Tasks at or less that the
1450 * floor priority are not watched. This is a simple way to monitor
1451 * an application and exclude system tasks running at a lower
1452 * priority level.
1453 */
1454rtems_status_code
1455rtems_capture_watch_floor (rtems_task_priority floor)
1456{
1457  capture_floor = floor;
1458  return RTEMS_SUCCESSFUL;
1459}
1460
1461/*
1462 * rtems_capture_watch_get_floor
1463 *
1464 *  DESCRIPTION:
1465 *
1466 * This function gets the watch floor.
1467 */
1468rtems_task_priority
1469rtems_capture_watch_get_floor (void)
1470{
1471  return capture_floor;
1472}
1473
1474/*
1475 * rtems_capture_map_trigger
1476 *
1477 *  DESCRIPTION:
1478 *
1479 * Map the trigger to a bit mask.
1480 *
1481 */
1482uint32_t
1483rtems_capture_map_trigger (rtems_capture_trigger_t trigger)
1484{
1485  /*
1486   * Transform the mode and trigger to a bit map.
1487   */
1488  switch (trigger)
1489  {
1490    case rtems_capture_switch:
1491      return RTEMS_CAPTURE_SWITCH;
1492    case rtems_capture_create:
1493      return RTEMS_CAPTURE_CREATE;
1494    case rtems_capture_start:
1495      return RTEMS_CAPTURE_START;
1496    case rtems_capture_restart:
1497      return RTEMS_CAPTURE_RESTART;
1498    case rtems_capture_delete:
1499      return RTEMS_CAPTURE_DELETE;
1500    case rtems_capture_begin:
1501      return RTEMS_CAPTURE_BEGIN;
1502    case rtems_capture_exitted:
1503      return RTEMS_CAPTURE_EXITTED;
1504    default:
1505      break;
1506  }
1507  return 0;
1508}
1509
1510/*
1511 * rtems_capture_set_trigger
1512 *
1513 *  DESCRIPTION:
1514 *
1515 * This function sets a trigger.
1516 *
1517 * This set trigger routine will create a capture control for the
1518 * target task. The task list is searched and any existing tasks
1519 * are linked to the new control.
1520 *
1521 * We can have a number of tasks that have the same name so we
1522 * search using names. This means a number of tasks can be
1523 * linked to single control.
1524 */
1525rtems_status_code
1526rtems_capture_set_trigger (rtems_name                   from_name,
1527                           rtems_id                     from_id,
1528                           rtems_name                   to_name,
1529                           rtems_id                     to_id,
1530                           rtems_capture_trigger_mode_t mode,
1531                           rtems_capture_trigger_t      trigger)
1532{
1533  rtems_capture_control_t* control;
1534  uint32_t                 flags;
1535
1536  flags = rtems_capture_map_trigger (trigger);
1537
1538  /*
1539   * The mode sets the opposite type of trigger. For example
1540   * FROM ANY means trigger when the event happens TO this
1541   * task. TO ANY means FROM this task.
1542   */
1543 
1544  if (mode == rtems_capture_to_any)
1545  {
1546    control = rtems_capture_create_control (from_name, from_id);
1547    if (control == NULL)
1548      return RTEMS_NO_MEMORY;
1549    control->from_triggers |= flags & RTEMS_CAPTURE_FROM_TRIGS;
1550  }
1551  else
1552  {
1553    control = rtems_capture_create_control (to_name, to_id);
1554    if (control == NULL)
1555      return RTEMS_NO_MEMORY;
1556    if (mode == rtems_capture_from_any)
1557      control->to_triggers |= flags;
1558    else
1559    {
1560      bool done = false;
1561      int  i;
1562     
1563      control->by_triggers |= flags;
1564     
1565      for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
1566      {
1567        if (rtems_capture_control_by_valid (control, i) &&
1568            ((control->by[i].name == from_name) ||
1569             (from_id && (control->by[i].id == from_id))))
1570        {
1571          control->by[i].trigger |= flags;
1572          done = true;
1573          break;
1574        }
1575      }
1576
1577      if (!done)
1578      {
1579        for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
1580        {
1581          if (!rtems_capture_control_by_valid (control, i))
1582          {
1583            control->by_valid |= RTEMS_CAPTURE_CONTROL_FROM_MASK (i);
1584            control->by[i].name = from_name;
1585            control->by[i].id = from_id;
1586            control->by[i].trigger = flags;
1587            done = true;
1588            break;
1589          }
1590        }
1591      }
1592
1593      if (!done)
1594        return RTEMS_TOO_MANY;
1595    }
1596  }
1597  return RTEMS_SUCCESSFUL;
1598}
1599
1600/*
1601 * rtems_capture_clear_trigger
1602 *
1603 *  DESCRIPTION:
1604 *
1605 * This function clear a trigger.
1606 */
1607rtems_status_code
1608rtems_capture_clear_trigger (rtems_name                   from_name,
1609                             rtems_id                     from_id,
1610                             rtems_name                   to_name,
1611                             rtems_id                     to_id,
1612                             rtems_capture_trigger_mode_t mode,
1613                             rtems_capture_trigger_t      trigger)
1614{
1615  rtems_capture_control_t* control;
1616  uint32_t                 flags;
1617
1618  flags = rtems_capture_map_trigger (trigger);
1619 
1620  if (mode == rtems_capture_to_any)
1621  {
1622    control = rtems_capture_find_control (from_name, from_id);
1623    if (control == NULL)
1624    {
1625      if (from_id)
1626        return RTEMS_INVALID_ID;
1627      return RTEMS_INVALID_NAME;
1628    }
1629    control->from_triggers &= ~flags;
1630  }
1631  else
1632  {
1633    control = rtems_capture_find_control (to_name, to_id);
1634    if (control == NULL)
1635    {
1636      if (to_id)
1637        return RTEMS_INVALID_ID;
1638      return RTEMS_INVALID_NAME;
1639    }
1640    if (mode == rtems_capture_from_any)
1641      control->to_triggers &= ~flags;
1642    else
1643    {
1644      bool done = false;
1645      int  i;
1646     
1647      control->by_triggers &= ~flags;
1648     
1649      for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
1650      {
1651        if (rtems_capture_control_by_valid (control, i) &&
1652            ((control->by[i].name == from_name) ||
1653             (control->by[i].id == from_id)))
1654        {
1655          control->by[i].trigger &= ~trigger;
1656          if (control->by[i].trigger == 0)
1657            control->by_valid &= ~RTEMS_CAPTURE_CONTROL_FROM_MASK (i);
1658          done = true;
1659          break;
1660        }
1661      }
1662
1663      if (!done)
1664      {
1665        if (from_id)
1666          return RTEMS_INVALID_ID;
1667        return RTEMS_INVALID_NAME;
1668      }
1669    }
1670  }
1671  return RTEMS_SUCCESSFUL;
1672}
1673
1674/*
1675 * rtems_capture_read
1676 *
1677 *  DESCRIPTION:
1678 *
1679 * This function reads a number of records from the capture buffer.
1680 * The user can optionally block and wait until the buffer as a
1681 * specific number of records available or a specific time has
1682 * elasped.
1683 *
1684 * The function returns the number of record that is has that are
1685 * in a continous block of memory. If the number of available records
1686 * wrap then only those records are provided. This removes the need for
1687 * caller to be concerned about buffer wrappings. If the number of
1688 * requested records cannot be met due to the wrapping of the records
1689 * less than the specified number will be returned.
1690 *
1691 * The user must release the records. This is achieved with a call to
1692 * rtems_capture_release. Calls this function without a release will
1693 * result in at least the same number of records being released.
1694 *
1695 * The 'threshold' parameter is the number of records that must be
1696 * captured before returning. If a timeout period is specified (non-0)
1697 * any captured records will be returned. These parameters stop
1698 * thrashing occuring for a small number of records, yet allows
1699 * a user configured latiency to be applied for single events.
1700 *
1701 * The 'timeout' parameter is in micro-seconds. A value of 0 will disable
1702 * the timeout.
1703 *
1704 */
1705rtems_status_code
1706rtems_capture_read (uint32_t                 threshold,
1707                    uint32_t                 timeout,
1708                    uint32_t*                read,
1709                    rtems_capture_record_t** recs)
1710{
1711  rtems_interrupt_level level;
1712  rtems_status_code     sc = RTEMS_SUCCESSFUL;
1713  uint32_t              count;
1714
1715  *read = 0;
1716  *recs = NULL;
1717
1718  rtems_interrupt_disable (level);
1719
1720  /*
1721   * Only one reader is allowed.
1722   */
1723
1724  if (capture_flags & RTEMS_CAPTURE_READER_ACTIVE)
1725  {
1726    rtems_interrupt_enable (level);
1727    return RTEMS_RESOURCE_IN_USE;
1728  }
1729
1730  capture_flags |= RTEMS_CAPTURE_READER_ACTIVE;
1731  *read = count = capture_count;
1732
1733  rtems_interrupt_enable (level);
1734
1735  *recs = &capture_records[capture_out];
1736
1737  for (;;)
1738  {
1739    /*
1740     * See if the count wraps the end of the record buffer.
1741     */
1742    if (count && ((capture_out + count) >= capture_size))
1743      *read = capture_size - capture_out;
1744
1745    /*
1746     * Do we have a threshold and the current count has not wrapped
1747     * around the end of the capture record buffer ?
1748     */
1749    if ((*read == count) && threshold)
1750    {
1751      /*
1752       * Do we have enough records ?
1753       */
1754      if (*read < threshold)
1755      {
1756        rtems_event_set event_out;
1757
1758        rtems_task_ident (RTEMS_SELF, RTEMS_LOCAL, &capture_reader);
1759
1760        rtems_interrupt_disable (level);
1761
1762        capture_flags |= RTEMS_CAPTURE_READER_WAITING;
1763
1764        rtems_interrupt_enable (level);
1765
1766        sc = rtems_event_receive (RTEMS_EVENT_0,
1767                                  RTEMS_WAIT | RTEMS_EVENT_ANY,
1768                                  RTEMS_MICROSECONDS_TO_TICKS (timeout),
1769                                  &event_out);
1770
1771        /*
1772         * Let the user handle all other sorts of errors. This may
1773         * not be the best solution, but oh well, it will do for
1774         * now.
1775         */
1776        if ((sc != RTEMS_SUCCESSFUL) && (sc != RTEMS_TIMEOUT))
1777          break;
1778
1779        rtems_interrupt_disable (level);
1780
1781        *read = count = capture_count;
1782
1783        rtems_interrupt_enable (level);
1784
1785        continue;
1786      }
1787    }
1788
1789    /*
1790     * Always out if we reach here. To loop use continue.
1791     */
1792    break;
1793  }
1794
1795  return sc;
1796}
1797
1798/*
1799 * rtems_capture_release
1800 *
1801 *  DESCRIPTION:
1802 *
1803 * This function releases the requested number of record slots back
1804 * to the capture engine. The count must match the number read.
1805 */
1806rtems_status_code
1807rtems_capture_release (uint32_t count)
1808{
1809  rtems_capture_record_t* rec;
1810  uint32_t                counted;
1811 
1812  rtems_interrupt_level level;
1813
1814  rtems_interrupt_disable (level);
1815
1816  if (count > capture_count)
1817    count = capture_count;
1818
1819  rtems_interrupt_enable (level);
1820
1821  counted = count;
1822 
1823  rec = &capture_records[capture_out];
1824
1825  while (counted--)
1826  {
1827    rtems_capture_refcount_down (rec->task);
1828    rtems_capture_destroy_capture_task (rec->task);
1829    rec++;
1830  }
1831 
1832  rtems_interrupt_disable (level);
1833
1834  capture_count -= count;
1835
1836  capture_out = (capture_out + count) % capture_size;
1837
1838  capture_flags &= ~RTEMS_CAPTURE_READER_ACTIVE;
1839
1840  rtems_interrupt_enable (level);
1841
1842  return RTEMS_SUCCESSFUL;
1843}
1844
1845/*
1846 * rtems_capture_tick_time
1847 *
1848 *  DESCRIPTION:
1849 *
1850 * This function returns the tick period in nano-seconds.
1851 */
1852uint32_t
1853rtems_capture_tick_time (void)
1854{
1855  return capture_tick_period;
1856}
1857
1858/*
1859 * rtems_capture_event_text
1860 *
1861 *  DESCRIPTION:
1862 *
1863 * This function returns a string for an event based on the bit in the
1864 * event. The functions takes the bit offset as a number not the bit
1865 * set in a bit map.
1866 */
1867const char*
1868rtems_capture_event_text (int event)
1869{
1870  if ((event < RTEMS_CAPTURE_EVENT_START) || (event > RTEMS_CAPTURE_EVENT_END))
1871    return "invalid event id";
1872  return capture_event_text[event - RTEMS_CAPTURE_EVENT_START];
1873}
1874
1875/*
1876 * rtems_capture_get_task_list
1877 *
1878 *  DESCRIPTION:
1879 *
1880 * This function returns the head of the list of tasks that the
1881 * capture engine has detected.
1882 */
1883rtems_capture_task_t*
1884rtems_capture_get_task_list (void)
1885{
1886  return capture_tasks;
1887}
1888
1889/*
1890 * rtems_capture_task_stack_usage
1891 *
1892 *  DESCRIPTION:
1893 *
1894 * This function updates the stack usage. The task control block
1895 * is updated.
1896 */
1897uint32_t
1898rtems_capture_task_stack_usage (rtems_capture_task_t* task)
1899{
1900  if (task->tcb)
1901  {
1902    uint32_t* st;
1903    uint32_t* s;
1904
1905    /*
1906     * @todo: Assumes all stacks move the same way.
1907     */
1908    st = task->tcb->Start.Initial_stack.area + task->stack_size;
1909    s  = task->tcb->Start.Initial_stack.area;
1910
1911    while (s < st)
1912    {
1913      if (*s != 0xdeaddead)
1914        break;
1915      s++;
1916    }
1917
1918    task->stack_clean =
1919      s - (uint32_t*) task->tcb->Start.Initial_stack.area;
1920  }
1921
1922  return task->stack_clean;
1923}
1924
1925/*
1926 * rtems_capture_get_control_list
1927 *
1928 *  DESCRIPTION:
1929 *
1930 * This function returns the head of the list of control in the
1931 * capture engine.
1932 */
1933rtems_capture_control_t*
1934rtems_capture_get_control_list (void)
1935{
1936  return capture_controls;
1937}
Note: See TracBrowser for help on using the repository browser.