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

4.115
Last change on this file since a0323a9f was a0323a9f, checked in by Joel Sherrill <joel.sherrill@…>, on 02/16/11 at 00:24:49

2011-02-15 Joel Sherrill <joel.sherrilL@…>

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