source: rtems/cpukit/libmisc/capture/capture.c @ 463de59

4.115
Last change on this file since 463de59 was 463de59, checked in by Jennifer Averett <jennifer.averett@…>, on 04/16/14 at 14:42:37

capture: Fix capture engine to handle new extensions.

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