source: rtems/cpukit/libmisc/capture/capture.c @ 3547ed6

4.9
Last change on this file since 3547ed6 was 3547ed6, checked in by Joel Sherrill <joel.sherrill@…>, on Jan 21, 2011 at 7:40:37 PM

2011-01-21 Eric Norum <wenorum@…>

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