source: rtems/cpukit/libmisc/capture/capture.c @ aac75d3b

4.104.115
Last change on this file since aac75d3b was aac75d3b, checked in by Joel Sherrill <joel.sherrill@…>, on 12/15/08 at 19:21:01

2008-12-15 Joel Sherrill <joel.sherrill@…>

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