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

4.115
Last change on this file since f39f667a was f39f667a, checked in by Sebastian Huber <sebastian.huber@…>, on 05/14/14 at 11:50:48

score: Simplify _Thread_Change_priority()

The function to change a thread priority was too complex. Simplify it
with a new scheduler operation. This increases the average case
performance due to the simplified logic. The interrupt disabled
critical section is a bit prolonged since now the extract, update and
enqueue steps are executed atomically. This should however not impact
the worst-case interrupt latency since at least for the Deterministic
Priority Scheduler this sequence can be carried out with a wee bit of
instructions and no loops.

Add _Scheduler_Change_priority() to replace the sequence of

  • _Thread_Set_transient(),
  • _Scheduler_Extract(),
  • _Scheduler_Enqueue(), and
  • _Scheduler_Enqueue_first().

Delete STATES_TRANSIENT, _States_Is_transient() and
_Thread_Set_transient() since this state is now superfluous.

With this change it is possible to get rid of the
SCHEDULER_SMP_NODE_IN_THE_AIR state. This considerably simplifies the
implementation of the new SMP locking protocols.

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