[PATCH 2/4] capture: Add SMP support.

Jennifer Averett Jennifer.Averett at OARcorp.com
Tue Nov 4 16:36:56 UTC 2014



> -----Original Message-----
> From: gedare at gwmail.gwu.edu [mailto:gedare at gwmail.gwu.edu] On
> Behalf Of Gedare Bloom
> Sent: Tuesday, November 04, 2014 10:16 AM
> To: Jennifer Averett
> Cc: rtems-devel at rtems.org
> Subject: Re: [PATCH 2/4] capture: Add SMP support.
>
> I was reviewing this code and lost my spot. There are some notes
> below, but I have no more time to weed through. I'd recommend
> splitting this patch into more pieces:
> 1) Moving code into capture_support.
> 2) Adding SMP support.
> 3) Fixing formatting/style/documentation issues in legacy portions.
>
> Currently there are a mix of the three, and it makes reviewing the
> changes quite complex. Anyway, there are some other notes below.
>
>
> On Tue, Nov 4, 2014 at 8:39 AM, Jennifer Averett
> <jennifer.averett at oarcorp.com> wrote:
> > To support smp data was broken into global and percpu capture data.
> > Capture control must be disabled prior to printing or setting of
> > watch points.
> >
> > Methods to print the data were moved from capture-cli into
> > a support area and are no longer static so that they can
> > be shared by test routines, or application code that wants
> > to use the capture engine without the shell interface.
> > ---
> >  cpukit/libmisc/Makefile.am                      |   1 +
> >  cpukit/libmisc/capture/capture-cli.c            | 221 +------------
> >  cpukit/libmisc/capture/capture-cli.h            |   4 +-
> >  cpukit/libmisc/capture/capture.c                | 411 +++++++++++++-----------
> >  cpukit/libmisc/capture/capture.h                |  82 ++---
> >  cpukit/libmisc/capture/capture_buffer.c         |   6 +-
> >  cpukit/libmisc/capture/capture_buffer.h         |   6 +-
> >  cpukit/libmisc/capture/capture_support.c        | 307
> ++++++++++++++++++
> >  cpukit/libmisc/capture/capture_user_extension.c |  17 +-
> >  cpukit/libmisc/capture/captureimpl.h            | 102 ++++--
> >  10 files changed, 667 insertions(+), 490 deletions(-)
> >  create mode 100644 cpukit/libmisc/capture/capture_support.c
> >
> > diff --git a/cpukit/libmisc/Makefile.am b/cpukit/libmisc/Makefile.am
> > index 021a251..352379d 100644
> > --- a/cpukit/libmisc/Makefile.am
> > +++ b/cpukit/libmisc/Makefile.am
> > @@ -19,6 +19,7 @@ EXTRA_DIST += capture/README
> >  noinst_LIBRARIES += libcapture.a
> >  libcapture_a_SOURCES = capture/capture.c capture/capture-cli.c \
> >      capture/capture_user_extension.c capture/capture_buffer.c \
> > +    capture/capture_support.c \
> >      capture/capture.h capture/captureimpl.h capture/capture-cli.h \
> >      capture/capture_buffer.h
> >
> > diff --git a/cpukit/libmisc/capture/capture-cli.c
> b/cpukit/libmisc/capture/capture-cli.c
> > index ad53ccc..595c9cf 100644
> > --- a/cpukit/libmisc/capture/capture-cli.c
> > +++ b/cpukit/libmisc/capture/capture-cli.c
> > @@ -5,7 +5,7 @@
> >    All rights reserved Objective Design Systems Pty Ltd, 2002
> >    Chris Johns (ccj at acm.org)
> >
> > -  COPYRIGHT (c) 1989-1998.
> > +  COPYRIGHT (c) 1989-2014.
> >    On-Line Applications Research Corporation (OAR).
> >
> >    The license and distribution terms for this file may be
> > @@ -41,6 +41,13 @@
> >
> >  #define RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS (20)
> >
> > +typedef struct {
> > +  rtems_capture_record_t* rec;
> > +  uint32_t                read;
> > +  uint32_t                last_t;
> > +  uint32_t                printed;
> > +} ctrace_per_cpu_t;
> > +
> This does not seem to belong here.

Removed

> >  /*
> >   * Counter used to count the number of active tasks.
> >   */
> > @@ -209,31 +216,6 @@ rtems_capture_cli_disable (int                                argc
> RC_UNUSED,
> >    fprintf (stdout, "capture engine disabled.\n");
> >  }
> >
> > -/*
> > - * rtems_catpure_cli_print_uptime
> > - *
> > - *  DESCRIPTION:
> > - *
> > - * This function prints the nanosecond uptime to stdout.
> > - */
> > -static void
> > -rtems_capture_cli_print_timestamp (uint64_t uptime)
> > -{
> > -  uint32_t hours;
> > -  uint32_t minutes;
> > -  uint32_t seconds;
> > -  uint32_t nanosecs;
> > -
> > -  seconds  = uptime / 1000000000LLU;
> > -  minutes  = seconds / 60;
> > -  hours    = minutes / 60;
> > -  minutes  = minutes % 60;
> > -  seconds  = seconds % 60;
> > -  nanosecs = uptime % 1000000000;
> > -
> > -  fprintf (stdout, "%5lu:%02lu:%02lu.%09lu", hours, minutes, seconds,
> nanosecs);
> > -}
> > -
> >  static void
> >  rtems_capture_cli_print_task (rtems_tcb *tcb)
> >  {
> > @@ -273,47 +255,6 @@ rtems_capture_cli_print_task (rtems_tcb *tcb)
> >    }
> >    fprintf (stdout, "\n");
> >  }
> > -static void
> > -rtems_caputure_cli_print_record_std(rtems_capture_record_t* rec,
> uint64_t diff)
> > -{
> > -  uint32_t                     event;
> > -  int                          e;
> > -
> > -  event = rec->events >> RTEMS_CAPTURE_EVENT_START;
> > -
> > -  for (e = RTEMS_CAPTURE_EVENT_START; e <
> RTEMS_CAPTURE_EVENT_END; e++)
> > -  {
> > -    if (event & 1)
> > -    {
> > -      rtems_capture_cli_print_timestamp (rec->time);
> > -      fprintf (stdout, " %9" PRId64 " ", diff);
> > -      rtems_monitor_dump_id (rec->task_id);
> > -      fprintf(stdout, "      %3" PRId32 " %3" PRId32 " %s\n",
> > -             (rec->events >> RTEMS_CAPTURE_REAL_PRIORITY_EVENT) & 0xff,
> > -             (rec->events >> RTEMS_CAPTURE_CURR_PRIORITY_EVENT) & 0xff,
> > -             rtems_capture_event_text (e));
> > -    }
> > -    event >>= 1;
> > -  }
> > -}
> > -
> > -static void
> > -rtems_caputre_cli_print_record_task(rtems_capture_record_t* rec)
> > -{
> > -  rtems_capture_task_record_t* task_rec =
> (rtems_capture_task_record_t*) rec;
> > -
> > -  rtems_capture_cli_print_timestamp (rec->time);
> > -  fprintf (stdout, "           ");
> > -  rtems_monitor_dump_id (rec->task_id);
> > -   fprintf (stdout, " %c%c%c%c",
> > -            (char) (task_rec->name >> 24) & 0xff,
> > -            (char) (task_rec->name >> 16) & 0xff,
> > -            (char) (task_rec->name >> 8) & 0xff,
> > -            (char) (task_rec->name >> 0) & 0xff);
> > -   fprintf (stdout, " %3" PRId32   " %3" PRId32 "\n",
> > -            task_rec->start_priority,
> > -            task_rec->stack_size);
> > -}
> >
> >  /*
> >   * rtems_capture_cli_count_tasks
> > @@ -355,7 +296,7 @@ rtems_capture_cli_task_list (int                                argc
> RC_UNUSED,
> >    rtems_iterate_over_all_threads (rtems_capture_cli_count_tasks);
> >
> >    fprintf (stdout, "uptime: ");
> > -  rtems_capture_cli_print_timestamp (uptime);
> > +  rtems_capture_print_timestamp (uptime);
> >    fprintf (stdout, "\ntotal %i\n", rtems_capture_cli_task_count);
> >    rtems_iterate_over_all_threads (rtems_capture_cli_print_task);
> >  }
> > @@ -375,79 +316,7 @@ rtems_capture_cli_watch_list (int
> argc RC_UNUSED,
> >                                const rtems_monitor_command_arg_t* command_arg
> RC_UNUSED,
> >                                bool                               verbose RC_UNUSED)
> >  {
> > -  rtems_capture_control_t* control = rtems_capture_get_control_list ();
> > -  rtems_task_priority      ceiling = rtems_capture_watch_get_ceiling ();
> > -  rtems_task_priority      floor = rtems_capture_watch_get_floor ();
> > -
> > -  fprintf (stdout, "watch priority ceiling is %" PRId32 "\n", ceiling);
> > -  fprintf (stdout, "watch priority floor is %" PRId32 "\n", floor);
> > -  fprintf (stdout, "global watch is %s\n",
> > -          rtems_capture_watch_global_on () ? "enabled" : "disabled");
> > -  fprintf (stdout, "total %" PRId32 "\n", rtems_capture_control_count ());
> > -
> > -  while (control)
> > -  {
> > -    uint32_t flags;
> > -    int      f;
> > -    int      fshowed;
> > -    int      lf;
> > -
> > -    fprintf (stdout, " ");
> > -    rtems_monitor_dump_id (rtems_capture_control_id (control));
> > -    fprintf (stdout, " ");
> > -    rtems_monitor_dump_name (rtems_capture_control_name (control));
> > -    flags = rtems_capture_control_flags (control);
> > -    fprintf (stdout, " %c%c ",
> > -             rtems_capture_watch_global_on () ? 'g' : '-',
> > -             flags & RTEMS_CAPTURE_WATCH ? 'w' : '-');
> > -    flags = rtems_capture_control_to_triggers (control);
> > -    fprintf (stdout, " T:%c%c%c%c%c%c%c",
> > -             flags & RTEMS_CAPTURE_SWITCH    ? 'S' : '-',
> > -             flags & RTEMS_CAPTURE_CREATE ? 'C' : '-',
> > -             flags & RTEMS_CAPTURE_START ? 'S' : '-',
> > -             flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
> > -             flags & RTEMS_CAPTURE_DELETE ? 'D' : '-',
> > -             flags & RTEMS_CAPTURE_BEGIN ? 'B' : '-',
> > -             flags & RTEMS_CAPTURE_EXITTED ? 'E' : '-');
> > -    flags = rtems_capture_control_from_triggers (control);
> > -    fprintf (stdout, " F:%c%c%c%c%c",
> > -             flags & RTEMS_CAPTURE_SWITCH  ? 'S' : '-',
> > -             flags & RTEMS_CAPTURE_CREATE  ? 'C' : '-',
> > -             flags & RTEMS_CAPTURE_START   ? 'S' : '-',
> > -             flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
> > -             flags & RTEMS_CAPTURE_DELETE  ? 'D' : '-');
> > -
> > -    for (f = 0, fshowed = 0, lf = 1; f < RTEMS_CAPTURE_TRIGGER_TASKS;
> f++)
> > -    {
> > -      if (rtems_capture_control_by_valid (control, f))
> > -      {
> > -        if (lf && ((fshowed % 3) == 0))
> > -        {
> > -          fprintf (stdout, "\n");
> > -          lf = 0;
> > -        }
> > -
> > -        fprintf (stdout, "  %2i:", f);
> > -        rtems_monitor_dump_name (rtems_capture_control_by_name
> (control, f));
> > -        fprintf (stdout, "/");
> > -        rtems_monitor_dump_id (rtems_capture_control_by_id (control, f));
> > -        flags = rtems_capture_control_by_triggers (control, f);
> > -        fprintf (stdout, ":%c%c%c%c%c",
> > -                 flags & RTEMS_CAPTURE_SWITCH  ? 'S' : '-',
> > -                 flags & RTEMS_CAPTURE_CREATE  ? 'C' : '-',
> > -                 flags & RTEMS_CAPTURE_START   ? 'S' : '-',
> > -                 flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
> > -                 flags & RTEMS_CAPTURE_DELETE  ? 'D' : '-');
> > -        fshowed++;
> > -        lf = 1;
> > -      }
> > -    }
> > -
> > -    if (lf)
> > -      fprintf (stdout, "\n");
> > -
> > -    control = rtems_capture_next_control (control);
> > -  }
> > +  rtems_capture_print_watch_list();
> >  }
> >
> >  /*
> > @@ -1154,16 +1023,9 @@ rtems_capture_cli_trace_records (int
> argc,
> >                                   const rtems_monitor_command_arg_t* command_arg
> RC_UNUSED,
> >                                   bool                               verbose RC_UNUSED)
> >  {
> > -  rtems_status_code       sc;
> >    bool                    csv = false;
> >    static int              dump_total = 22;
> > -  int                     total;
> > -  int                     count;
> > -  uint32_t                read;
> > -  rtems_capture_record_t* rec;
> > -  uint8_t*                ptr;
> >    int                     arg;
> > -  rtems_capture_time_t    last_t = 0;
> >
> >    for (arg = 1; arg < argc; arg++)
> >    {
> > @@ -1192,68 +1054,7 @@ rtems_capture_cli_trace_records (int
> argc,
> >      }
> >    }
> >
> > -  total = dump_total;
> > -
> > -  while (total)
> > -  {
> > -    sc = rtems_capture_read (0, 0, &read, &rec);
> > -
> > -    if (sc != RTEMS_SUCCESSFUL)
> > -    {
> > -      fprintf (stdout, "error: trace read failed: %s\n", rtems_status_text (sc));
> > -      rtems_capture_flush (0);
> > -      return;
> > -    }
> > -
> > -    /*
> > -     * If we have no records then just exist. We still need to release
> > -     * the reader lock.
> > -     */
> > -
> > -    if (read == 0)
> > -    {
> > -      rtems_capture_release (read);
> > -      break;
> > -    }
> > -
> > -    count = total < read ? total : read;
> > -    ptr = (uint8_t *) rec;
> > -    while (count--)
> > -    {
> > -      rec = (rtems_capture_record_t*) ptr;
> > -
> > -      if (csv)
> > -        fprintf (stdout, "%08" PRIu32 ",%03" PRIu32
> > -                   ",%03" PRIu32 ",%04" PRIx32 ",%" PRId64 "\n",
> > -                 rec->task_id,
> > -                 (rec->events >> RTEMS_CAPTURE_REAL_PRIORITY_EVENT) &
> 0xff,
> > -                 (rec->events >> RTEMS_CAPTURE_CURR_PRIORITY_EVENT) &
> 0xff,
> > -                 (rec->events >> RTEMS_CAPTURE_EVENT_START),
> > -                 (uint64_t) rec->time);
> > -      else {
> > -        if ((rec->events >> RTEMS_CAPTURE_EVENT_START) == 0)
> > -          rtems_caputre_cli_print_record_task( rec );
> > -        else {
> > -          uint64_t diff = 0;
> > -          if (last_t)
> > -            diff = rec->time - last_t;
> > -          last_t = rec->time;
> > -
> > -          rtems_caputure_cli_print_record_std( rec, diff );
> > -        }
> > -      }
> > -      ptr += rec->size;
> > -    }
> > -
> > -    count = total < read ? total : read;
> > -
> > -    if (count < total)
> > -      total -= count;
> > -    else
> > -      total = 0;
> > -
> > -    rtems_capture_release (count);
> > -  }
> > +  rtems_capture_print_trace_records( dump_total, csv );
> >  }
> >
> >  /*
> > diff --git a/cpukit/libmisc/capture/capture-cli.h
> b/cpukit/libmisc/capture/capture-cli.h
> > index 8f97522..4fa2a4a 100644
> > --- a/cpukit/libmisc/capture/capture-cli.h
> > +++ b/cpukit/libmisc/capture/capture-cli.h
> > @@ -12,7 +12,7 @@
> >    All rights reserved Objective Design Systems Pty Ltd, 2002
> >    Chris Johns (ccj at acm.org)
> >
> > -  COPYRIGHT (c) 1989-1998.
> > +  COPYRIGHT (c) 1989-2014.
> >    On-Line Applications Research Corporation (OAR).
> >
> >    The license and distribution terms for this file may be
> > @@ -36,7 +36,7 @@
> >  extern "C" {
> >  #endif
> >
> > -#include <rtems/capture.h>
> > +#include <rtems/captureimpl.h>
> >
> Is capture-cli.h included by users? If so, it should not be "leaking"
> captureimpl.h.

Removed from capture-cli.h
>
> >  /**
> >   * rtems_capture_cli_init
> > diff --git a/cpukit/libmisc/capture/capture.c
> b/cpukit/libmisc/capture/capture.c
> > index a83bc90..a0a2089 100644
> > --- a/cpukit/libmisc/capture/capture.c
> > +++ b/cpukit/libmisc/capture/capture.c
> > @@ -5,7 +5,7 @@
> >    All rights reserved Objective Design Systems Pty Ltd, 2002
> >    Chris Johns (ccj at acm.org)
> >
> > -  COPYRIGHT (c) 1989-2009.
> > +  COPYRIGHT (c) 1989-2014.
> >    On-Line Applications Research Corporation (OAR).
> >
> >    The license and distribution terms for this file may be
> > @@ -59,21 +59,52 @@
> >  #define RTEMS_CAPTURE_RECORD_EVENTS  (0)
> >  #endif
> >
> > +typedef struct {
> > +  rtems_capture_buffer_t   records;
> > +  uint32_t                 count;
> > +  rtems_id                 reader;
> > +  rtems_interrupt_lock     lock;
> > +  uint32_t                 flags;
> > +} rtems_capture_per_cpu_data_t;
> > +
> > +typedef struct {
> > +  uint32_t                 flags;
> > +  rtems_capture_control_t* controls;
> > +  int                      extension_index;
> > +  rtems_capture_timestamp  timestamp;
> > +  rtems_task_priority      ceiling;
> > +  rtems_task_priority      floor;
> > +  rtems_interrupt_lock     lock;
> > +} rtems_capture_global_data_t;
> > +
> I'd suggest cleaning up the typedefs to remove the _t specifier. We
> should not be declaring such types in RTEMS that are not POSIX types.
> (Though these are not so bad as they are local to this C file, and not
> leaked through a header, we should still discourage the practice.)

Removed the _t identifier.

> > +static rtems_capture_per_cpu_data_t  *capture_per_cpu = NULL;
> > +
> > +static rtems_capture_global_data_t capture_global;
> >
> >  /*
> >   * RTEMS Capture Data.
> >   */
> > -static rtems_capture_buffer_t   capture_records = {NULL, 0, 0, 0, 0, 0};
> > -static uint32_t                 capture_count;
> > -static uint32_t                 capture_flags;
> > -static rtems_capture_control_t* capture_controls;
> > -static int                      capture_extension_index;
> > -static rtems_capture_timestamp  capture_timestamp;
> > -static rtems_task_priority      capture_ceiling;
> > -static rtems_task_priority      capture_floor;
> > -static rtems_id                 capture_reader;
> > -static rtems_interrupt_lock     capture_lock =
> > -  RTEMS_INTERRUPT_LOCK_INITIALIZER("capture");
> > +#define capture_per_cpu_get( _cpu ) \
> > +   ( &capture_per_cpu[ _cpu ] )
> > +
> > +#define capture_records_on_cpu( _cpu ) capture_per_cpu[ _cpu
> ].records
> > +#define capture_count_on_cpu( _cpu )   capture_per_cpu[ _cpu ].count
> > +#define capture_flags_on_cpu( _cpu )   capture_per_cpu[ _cpu ].flags
> > +#define capture_reader_on_cpu( _cpu )  capture_per_cpu[ _cpu ].reader
> > +#define capture_lock_on_cpu( _cpu )    capture_per_cpu[ _cpu ].lock
> > +
> > +#define capture_records          capture_records_on_cpu(
> _SMP_Get_current_processor() )
> > +#define capture_count            capture_count_on_cpu(
> _SMP_Get_current_processor() )
> > +#define capture_flags_per_cpu    capture_flags_on_cpu(
> _SMP_Get_current_processor() )
> > +#define capture_flags_global     capture_global.flags
> > +#define capture_controls         capture_global.controls
> > +#define capture_extension_index  capture_global.extension_index
> > +#define capture_timestamp        capture_global.timestamp
> > +#define capture_ceiling          capture_global.ceiling
> > +#define capture_floor            capture_global.floor
> > +#define capture_reader           capture_reader_on_cpu(
> _SMP_Get_current_processor() )
> > +#define capture_lock_per_cpu     capture_lock_on_cpu(
> _SMP_Get_current_processor() )
> > +#define capture_lock_global      capture_global.lock
> >
> Why not define capture_lock?

The capture lock was broken into a global lock and a per-cpu lock.  We didn't want
to lock cpu's 1-3 to add records to cpu 0.  I can name capture_lock_global
capture_lock if that is what you are suggesting.

> >  /*
> >   * RTEMS Event text.
> > @@ -108,12 +139,12 @@ int  rtems_capture_get_extension_index(void)
> >
> >  uint32_t rtems_capture_get_flags(void)
> >  {
> > -  return capture_flags;
> > +  return capture_flags_global;
> >  }
> >
> >  void rtems_capture_set_flags(uint32_t mask)
> >  {
> > -  capture_flags |= mask;
> > +  capture_flags_global |= mask;
> >  }
> >
> >  /*
> > @@ -284,11 +315,11 @@ rtems_capture_create_control (rtems_name
> name, rtems_id id)
> >
> >    if (control == NULL)
> >    {
> > -    bool ok = rtems_workspace_allocate (sizeof (*control), (void **)
> &control);
> > +    control = malloc( sizeof (*control));
> >
> These functional changes would be better presented as a separate
> commit if that makes sense. Was it agreed that replacing the
> workspace_allocate() with malloc() is OK here?

It should be fine.  The only problem that was mentioned in the past was that
we couldn't malloc or workspace_allocate during a task switch.  That was
resolved with the previous sets of patches.  This method is initiated by a user
call, not through user extension accesses.


-- Jennifer

> > -    if (!ok)
> > +    if (!control)
> >      {
> > -      capture_flags |= RTEMS_CAPTURE_NO_MEMORY;
> > +      capture_flags_global |= RTEMS_CAPTURE_NO_MEMORY;
> >        return NULL;
> >      }
> >
> > @@ -301,13 +332,13 @@ rtems_capture_create_control (rtems_name
> name, rtems_id id)
> >
> >      memset (control->by, 0, sizeof (control->by));
> >
> > -    rtems_interrupt_lock_acquire (&capture_lock, &lock_context);
> > +    rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
> >
> >      control->next    = capture_controls;
> >      capture_controls = control;
> >      rtems_iterate_over_all_threads (rtems_capture_initialize_control);
> >
> > -    rtems_interrupt_lock_release (&capture_lock, &lock_context);
> > +    rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
> >    }
> >
> >    return control;
> > @@ -315,16 +346,18 @@ rtems_capture_create_control (rtems_name
> name, rtems_id id)
> >
> >  void rtems_capture_initialize_task( rtems_tcb* tcb )
> >  {
> > -  rtems_capture_control_t*    control;
> > -  rtems_name                  name;
> > +  rtems_capture_control_t*     control;
> > +  rtems_name                   name;
> > +  rtems_interrupt_lock_context lock_context;
> >
> >    /*
> > -   * We need to scan the default control list to initialise
> > +   * We need to scan the default control list to initialize
> >     * this control if it is a new task.
> >     */
> >
> >    rtems_object_get_classic_name( tcb->Object.id, &name );
> >
> > +  rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
> >    if (tcb->Capture.control == NULL) {
> >      for (control = capture_controls; control != NULL; control = control->next)
> >        if (rtems_capture_match_name_id (control->name, control->id,
> > @@ -333,28 +366,31 @@ void rtems_capture_initialize_task( rtems_tcb*
> tcb )
> >    }
> >
> >    tcb->Capture.flags |= RTEMS_CAPTURE_INIT_TASK;
> > +  rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
> >  }
> >
> >  void rtems_capture_record_task( rtems_tcb* tcb )
> >  {
> >    rtems_capture_task_record_t rec;
> >    void*                       ptr;
> > +  rtems_interrupt_lock_context lock_context;
> >
> >    rtems_object_get_classic_name( tcb->Object.id, &rec.name );
> > -
> > +
> >    rec.stack_size = tcb->Start.Initial_stack.size;
> >    rec.start_priority = _RTEMS_tasks_Priority_from_Core(
> >      tcb->Start.initial_priority
> >    );
> >
> > +  rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
> >    tcb->Capture.flags |= RTEMS_CAPTURE_RECORD_TASK;
> > +  rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
> >
> >    /*
> >     *  Log the task information. The first time a task is
> >     *  seen a record is logged.  This record can be identified
> >     *  by a 0 in the event identifier.
> >     */
> > -
> >    rtems_capture_begin_add_record (tcb, 0, sizeof(rec), &ptr);
> >    ptr = rtems_capture_append_to_record(
> >      ptr,
> > @@ -375,14 +411,14 @@ void rtems_capture_record_task( rtems_tcb* tcb
> )
> >  }
> >
> >  /*
> > - * This function indicates if data should be filtered from the
> > + * This function indicates if data should be filtered from the
> >   * log.
> >   */
> >  bool rtems_capture_filter( rtems_tcb*            tcb,
> >                             uint32_t              events)
> >  {
> >    if (tcb &&
> > -      ((capture_flags &
> > +      ((capture_flags_global &
> >          (RTEMS_CAPTURE_TRIGGERED | RTEMS_CAPTURE_ONLY_MONITOR))
> ==
> >         RTEMS_CAPTURE_TRIGGERED))
> >    {
> > @@ -398,7 +434,7 @@ bool rtems_capture_filter( rtems_tcb*            tcb,
> >      if ((events & RTEMS_CAPTURE_RECORD_EVENTS) ||
> >          ((tcb->real_priority >= capture_ceiling) &&
> >           (tcb->real_priority <= capture_floor) &&
> > -         ((capture_flags & RTEMS_CAPTURE_GLOBAL_WATCH) ||
> > +         ((capture_flags_global & RTEMS_CAPTURE_GLOBAL_WATCH) ||
> >            (control && (control->flags & RTEMS_CAPTURE_WATCH)))))
> >      {
> >        return false;
> > @@ -420,7 +456,7 @@ rtems_capture_record_open (rtems_tcb*
> tcb,
> >    uint8_t*                     ptr;
> >    rtems_capture_record_t*      capture_in;
> >
> > -  rtems_interrupt_lock_acquire (&capture_lock, lock_context);
> > +  rtems_interrupt_lock_acquire (&capture_lock_per_cpu, lock_context);
> >
> >    ptr = rtems_capture_buffer_allocate(&capture_records, size);
> >    capture_in = (rtems_capture_record_t *) ptr;
> > @@ -441,14 +477,14 @@ rtems_capture_record_open (rtems_tcb*
> tcb,
> >      ptr = ptr + sizeof(*capture_in);
> >    }
> >    else
> > -    capture_flags |= RTEMS_CAPTURE_OVERFLOW;
> > +    capture_flags_per_cpu |= RTEMS_CAPTURE_OVERFLOW;
> >
> >    return ptr;
> >  }
> >
> >  void rtems_capture_record_close( void *rec,
> rtems_interrupt_lock_context* lock_context)
> >  {
> > -  rtems_interrupt_lock_release (&capture_lock, lock_context);
> > +  rtems_interrupt_lock_release (&capture_lock_per_cpu, lock_context);
> >  }
> >
> >  /*
> > @@ -460,11 +496,10 @@ rtems_capture_trigger (rtems_tcb* ft,
> >                         rtems_tcb* tt,
> >                         uint32_t   events)
> >  {
> > -
> >    /*
> >     * If we have not triggered then see if this is a trigger condition.
> >     */
> > -  if (!(capture_flags & RTEMS_CAPTURE_TRIGGERED))
> > +  if (!(capture_flags_global & RTEMS_CAPTURE_TRIGGERED))
> >    {
> >      rtems_capture_control_t* fc = NULL;
> >      rtems_capture_control_t* tc = NULL;
> > @@ -499,7 +534,7 @@ rtems_capture_trigger (rtems_tcb* ft,
> >       */
> >      if (from_events || to_events)
> >      {
> > -      capture_flags |= RTEMS_CAPTURE_TRIGGERED;
> > +      capture_flags_global |= RTEMS_CAPTURE_TRIGGERED;
> >        return 1;
> >      }
> >
> > @@ -510,7 +545,7 @@ rtems_capture_trigger (rtems_tcb* ft,
> >      {
> >        if (rtems_capture_by_in_to (events, ft, tc))
> >        {
> > -        capture_flags |= RTEMS_CAPTURE_TRIGGERED;
> > +        capture_flags_global |= RTEMS_CAPTURE_TRIGGERED;
> >          return 1;
> >        }
> >      }
> > @@ -523,47 +558,61 @@ rtems_capture_trigger (rtems_tcb* ft,
> >
> >  /*
> >   * This function initialises the realtime capture engine allocating the trace
> > - * buffer. It is assumed we have a working heap at stage of initialisation.
> > + * buffer. It is assumed we have a working heap at stage of initialization.
> >   */
> >  rtems_status_code
> >  rtems_capture_open (uint32_t   size, rtems_capture_timestamp
> timestamp __attribute__((unused)))
> >  {
> > -  rtems_status_code      sc;
> > +  rtems_status_code       sc = RTEMS_SUCCESSFUL;
> > +  size_t                  count;
> > +  uint32_t                i;
> > +  rtems_capture_buffer_t* buff;
> >
> >    /*
> >     * See if the capture engine is already open.
> >     */
> >
> > -  if (capture_records.buffer)
> > +  if ((capture_flags_global & RTEMS_CAPTURE_INIT) ==
> RTEMS_CAPTURE_INIT) {
> >      return RTEMS_RESOURCE_IN_USE;
> > +  }
> >
> > -  rtems_capture_buffer_create( &capture_records, size );
> > +  count = rtems_get_processor_count();
> > +  if (capture_per_cpu == NULL) {
> > +    capture_per_cpu = calloc( count,
> sizeof(rtems_capture_per_cpu_data_t) );
> > +  }
> >
> > -  if (capture_records.buffer == NULL)
> > -    return RTEMS_NO_MEMORY;
> > +  for (i=0; i<count; i++) {
> > +    buff = &capture_records_on_cpu(i);
> > +    rtems_capture_buffer_create( buff, size );
> > +    if (buff->buffer == NULL) {
> > +      sc = RTEMS_NO_MEMORY;
> > +      break;
> > +    }
> >
> > -  capture_count   = 0;
> > -  capture_flags   = 0;
> > +    capture_count_on_cpu(i) = 0;
> > +    capture_flags_on_cpu(i) = 0;
> > +  }
> > +
> > +  capture_flags_global   = 0;
> >    capture_ceiling = 0;
> >    capture_floor   = 255;
> > -
> > -  sc = rtems_capture_user_extension_open();
> > +  if (sc == RTEMS_SUCCESSFUL)
> > +    sc = rtems_capture_user_extension_open();
> >
> >    if (sc != RTEMS_SUCCESSFUL)
> >    {
> > -    rtems_capture_buffer_destroy( &capture_records);
> > +    for (i=0; i<count; i++)
> > +      rtems_capture_buffer_destroy( &capture_records_on_cpu(i));
> > +  }  else {
> > +    capture_flags_global |= RTEMS_CAPTURE_INIT;
> >    }
> >
> > -  /*
> > -   * Iterate over the list of existing tasks.
> > -   */
> > -
> >    return sc;
> >  }
> >
> >  /*
> >   * This function shutdowns the capture engine and release any claimed
> > - * resources.
> > + * resources.  Capture control must be disabled prior to calling a close.
> >   */
> >  rtems_status_code
> >  rtems_capture_close (void)
> > @@ -571,18 +620,26 @@ rtems_capture_close (void)
> >    rtems_interrupt_lock_context lock_context;
> >    rtems_capture_control_t*     control;
> >    rtems_status_code            sc;
> > +  uint32_t                     cpu;
> >
> > -  rtems_interrupt_lock_acquire (&capture_lock, &lock_context);
> > +  rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
> >
> > -  if (!capture_records.buffer)
> > +  if ((capture_flags_global & RTEMS_CAPTURE_INIT) !=
> RTEMS_CAPTURE_INIT)
> >    {
> > -    rtems_interrupt_lock_release (&capture_lock, &lock_context);
> > +    rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
> >      return RTEMS_SUCCESSFUL;
> >    }
> >
> > -  capture_flags &= ~(RTEMS_CAPTURE_ON |
> RTEMS_CAPTURE_ONLY_MONITOR);
> > +  if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
> > +  {
> > +    rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
> > +    return RTEMS_UNSATISFIED;
> > +  }
> > +
> > +  capture_flags_global &=
> > +    ~(RTEMS_CAPTURE_ON | RTEMS_CAPTURE_ONLY_MONITOR |
> RTEMS_CAPTURE_INIT);
> >
> > -  rtems_interrupt_lock_release (&capture_lock, &lock_context);
> > +  rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
> >
> >    /*
> >     * Delete the extension first. This means we are now able to
> > @@ -600,16 +657,19 @@ rtems_capture_close (void)
> >    {
> >      rtems_capture_control_t* delete = control;
> >      control = control->next;
> > -    rtems_workspace_free (delete);
> > +    free (delete);
> >    }
> >
> >    capture_controls = NULL;
> > -
> > -  if (capture_records.buffer)
> > -  {
> > -    rtems_capture_buffer_destroy( &capture_records);
> > +  for (cpu=0; cpu < rtems_get_processor_count(); cpu++) {
> > +    capture_count_on_cpu(cpu) = 0;
> > +    if (capture_records_on_cpu(cpu).buffer)
> > +      rtems_capture_buffer_destroy( &capture_records_on_cpu(cpu) );
> >    }
> >
> > +  free( capture_per_cpu );
> > +  capture_per_cpu = NULL;
> > +
> >    return RTEMS_SUCCESSFUL;
> >  }
> >
> > @@ -618,20 +678,20 @@ rtems_capture_control (bool enable)
> >  {
> >    rtems_interrupt_lock_context lock_context;
> >
> > -  rtems_interrupt_lock_acquire (&capture_lock, &lock_context);
> > +  rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
> >
> > -  if (!capture_records.buffer)
> > +  if ((capture_flags_global & RTEMS_CAPTURE_INIT) !=
> RTEMS_CAPTURE_INIT)
> >    {
> > -    rtems_interrupt_lock_release (&capture_lock, &lock_context);
> > +    rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
> >      return RTEMS_UNSATISFIED;
> >    }
> >
> >    if (enable)
> > -    capture_flags |= RTEMS_CAPTURE_ON;
> > +    capture_flags_global |= RTEMS_CAPTURE_ON;
> >    else
> > -    capture_flags &= ~RTEMS_CAPTURE_ON;
> > +    capture_flags_global &= ~RTEMS_CAPTURE_ON;
> >
> > -  rtems_interrupt_lock_release (&capture_lock, &lock_context);
> > +  rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
> >
> >    return RTEMS_SUCCESSFUL;
> >  }
> > @@ -646,20 +706,20 @@ rtems_capture_monitor (bool enable)
> >  {
> >    rtems_interrupt_lock_context lock_context;
> >
> > -  rtems_interrupt_lock_acquire (&capture_lock, &lock_context);
> > +  rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
> >
> > -  if (!capture_records.buffer)
> > +  if ((capture_flags_global & RTEMS_CAPTURE_INIT) !=
> RTEMS_CAPTURE_INIT)
> >    {
> > -    rtems_interrupt_lock_release (&capture_lock, &lock_context);
> > +    rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
> >      return RTEMS_UNSATISFIED;
> >    }
> >
> >    if (enable)
> > -    capture_flags |= RTEMS_CAPTURE_ONLY_MONITOR;
> > +    capture_flags_global |= RTEMS_CAPTURE_ONLY_MONITOR;
> >    else
> > -    capture_flags &= ~RTEMS_CAPTURE_ONLY_MONITOR;
> > +    capture_flags_global &= ~RTEMS_CAPTURE_ONLY_MONITOR;
> >
> > -  rtems_interrupt_lock_release (&capture_lock, &lock_context);
> > +  rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
> >
> >    return RTEMS_SUCCESSFUL;
> >  }
> > @@ -673,7 +733,6 @@ rtems_capture_flush_tcb (rtems_tcb *tcb)
> >    tcb->Capture.flags &= ~RTEMS_CAPTURE_TRACED;
> >  }
> >
> > -
> >  /*
> >   * This function flushes the capture buffer. The prime parameter allows
> the
> >   * capture engine to also be primed again.
> > @@ -681,21 +740,36 @@ rtems_capture_flush_tcb (rtems_tcb *tcb)
> >  rtems_status_code
> >  rtems_capture_flush (bool prime)
> >  {
> > -  rtems_interrupt_lock_context lock_context;
> > +  rtems_interrupt_lock_context lock_context_global;
> > +  rtems_interrupt_lock_context lock_context_per_cpu;
> > +  rtems_interrupt_lock*        lock;
> > +  uint32_t                     cpu;
> > +
> > +  rtems_interrupt_lock_acquire (&capture_lock_global,
> &lock_context_global);
> >
> > -  rtems_interrupt_lock_acquire (&capture_lock, &lock_context);
> > +  if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
> > +  {
> > +    rtems_interrupt_lock_release (&capture_lock_global,
> &lock_context_global);
> > +    return RTEMS_UNSATISFIED;
> > +  }
> >
> >    rtems_iterate_over_all_threads (rtems_capture_flush_tcb);
> >
> >    if (prime)
> > -    capture_flags &= ~(RTEMS_CAPTURE_TRIGGERED |
> RTEMS_CAPTURE_OVERFLOW);
> > +    capture_flags_global &= ~(RTEMS_CAPTURE_TRIGGERED |
> RTEMS_CAPTURE_OVERFLOW);
> >    else
> > -    capture_flags &= ~RTEMS_CAPTURE_OVERFLOW;
> > -
> > -  rtems_capture_buffer_flush( &capture_records );
> > -  capture_count = 0;
> > +    capture_flags_global &= ~RTEMS_CAPTURE_OVERFLOW;
> > +
> > +  for (cpu=0; cpu < rtems_get_processor_count(); cpu++) {
> > +    lock = &(capture_lock_on_cpu( cpu ));
> > +    rtems_interrupt_lock_acquire (lock, &lock_context_per_cpu);
> > +    capture_count_on_cpu(cpu) = 0;
> > +    if (capture_records_on_cpu(cpu).buffer)
> > +      rtems_capture_buffer_flush( &capture_records_on_cpu(cpu) );
> > +    rtems_interrupt_lock_release (lock, &lock_context_per_cpu);
> > +  }
> >
> > -  rtems_interrupt_lock_release (&capture_lock, &lock_context);
> > +  rtems_interrupt_lock_release (&capture_lock_global,
> &lock_context_global);
> >
> >    return RTEMS_SUCCESSFUL;
> >  }
> > @@ -704,13 +778,16 @@ rtems_capture_flush (bool prime)
> >   * This function defines a watch for a specific task given a name. A watch
> >   * causes it to be traced either in or out of context. The watch can be
> >   * optionally enabled or disabled with the set routine. It is disabled by
> > - * default.
> > + * default.  A watch can only be defined when capture control is disabled
> >   */
> >  rtems_status_code
> >  rtems_capture_watch_add (rtems_name name, rtems_id id)
> >  {
> >    rtems_capture_control_t* control;
> >
> > +  if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
> > +    return RTEMS_UNSATISFIED;
> > +
> >    if ((name == 0) && (id == 0))
> >      return RTEMS_UNSATISFIED;
> >
> > @@ -731,7 +808,8 @@ rtems_capture_watch_add (rtems_name name,
> rtems_id id)
> >  /*
> >   * This function removes a watch for a specific task given a name. The task
> >   * description will still exist if referenced by a trace record in the trace
> > - * buffer or a global watch is defined.
> > + * buffer or a global watch is defined.  A watch can only be deleted when
> > + * capture control is disabled.
> >   */
> >  rtems_status_code
> >  rtems_capture_watch_del (rtems_name name, rtems_id id)
> > @@ -741,6 +819,9 @@ rtems_capture_watch_del (rtems_name name,
> rtems_id id)
> >    rtems_capture_control_t**    prev_control;
> >    bool                         found = false;
> >
> > +  if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
> > +    return RTEMS_UNSATISFIED;
> > +
> >    /*
> >     * Should this test be for wildcards ?
> >     */
> > @@ -750,13 +831,13 @@ rtems_capture_watch_del (rtems_name name,
> rtems_id id)
> >    {
> >      if (rtems_capture_match_name_id (control->name, control->id, name,
> id))
> >      {
> > -      rtems_interrupt_lock_acquire (&capture_lock, &lock_context);
> > +      rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
> >
> >        *prev_control = control->next;
> >
> > -      rtems_interrupt_lock_release (&capture_lock, &lock_context);
> > +      rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
> >
> > -      rtems_workspace_free (control);
> > +      free (control);
> >
> >        control = *prev_control;
> >
> > @@ -786,6 +867,9 @@ rtems_capture_watch_ctrl (rtems_name name,
> rtems_id id, bool enable)
> >    rtems_capture_control_t*     control;
> >    bool                         found = false;
> >
> > +  if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
> > +    return RTEMS_UNSATISFIED;
> > +
> >    /*
> >     * Find the control and then set the watch. It must exist before it can
> >     * be controlled.
> > @@ -794,14 +878,14 @@ rtems_capture_watch_ctrl (rtems_name name,
> rtems_id id, bool enable)
> >    {
> >      if (rtems_capture_match_name_id (control->name, control->id, name,
> id))
> >      {
> > -      rtems_interrupt_lock_acquire (&capture_lock, &lock_context);
> > +      rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
> >
> >        if (enable)
> >          control->flags |= RTEMS_CAPTURE_WATCH;
> >        else
> >          control->flags &= ~RTEMS_CAPTURE_WATCH;
> >
> > -      rtems_interrupt_lock_release (&capture_lock, &lock_context);
> > +      rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
> >
> >        found = true;
> >      }
> > @@ -823,18 +907,18 @@ rtems_capture_watch_global (bool enable)
> >  {
> >    rtems_interrupt_lock_context lock_context;
> >
> > -  rtems_interrupt_lock_acquire (&capture_lock, &lock_context);
> > +  rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context);
> >
> >    /*
> >     * We need to keep specific and global watches separate so
> >     * a global enable/disable does not lose a specific watch.
> >     */
> >    if (enable)
> > -    capture_flags |= RTEMS_CAPTURE_GLOBAL_WATCH;
> > +    capture_flags_global |= RTEMS_CAPTURE_GLOBAL_WATCH;
> >    else
> > -    capture_flags &= ~RTEMS_CAPTURE_GLOBAL_WATCH;
> > +    capture_flags_global &= ~RTEMS_CAPTURE_GLOBAL_WATCH;
> >
> > -  rtems_interrupt_lock_release (&capture_lock, &lock_context);
> > +  rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
> >
> >    return RTEMS_SUCCESSFUL;
> >  }
> > @@ -845,7 +929,7 @@ rtems_capture_watch_global (bool enable)
> >  bool
> >  rtems_capture_watch_global_on (void)
> >  {
> > -  return capture_flags & RTEMS_CAPTURE_GLOBAL_WATCH ? 1 : 0;
> > +  return capture_flags_global & RTEMS_CAPTURE_GLOBAL_WATCH ? 1 : 0;
> >  }
> >
> >  /*
> > @@ -1082,30 +1166,26 @@ rtems_capture_clear_trigger (rtems_name
> from_name,
> >  }
> >
> >  static inline uint32_t rtems_capture_count_records( void* recs, size_t size
> )
> > -{
> > +{
> >    rtems_capture_record_t* rec;
> >    uint8_t*                ptr = recs;
> >    uint32_t                rec_count = 0;
> >    size_t                  byte_count = 0;
> > -
> > -
> > +
> > +
> >   while (byte_count < size) {
> >      rec = (rtems_capture_record_t*) ptr;
> >      rec_count++;
> >      _Assert( rec->size >= sizeof(*rec) );
> >      ptr += rec->size;
> >      byte_count += rec->size;
> > -    _Assert( rec_count <= capture_count );
> >   };
> > -
> > +
> >   return rec_count;
> >  }
> >
> >  /*
> >   * This function reads a number of records from the capture buffer.
> > - * The user can optionally block and wait until the buffer as a
> > - * specific number of records available or a specific time has
> > - * elasped.
> >   *
> >   * The function returns the number of record that is has that are
> >   * in a continous block of memory. If the number of available records
> > @@ -1117,106 +1197,47 @@ static inline uint32_t
> rtems_capture_count_records( void* recs, size_t size )
> >   * The user must release the records. This is achieved with a call to
> >   * rtems_capture_release. Calls this function without a release will
> >   * result in at least the same number of records being released.
> > - *
> > - * The 'threshold' parameter is the number of records that must be
> > - * captured before returning. If a timeout period is specified (non-0)
> > - * any captured records will be returned. These parameters stop
> > - * thrashing occuring for a small number of records, yet allows
> > - * a user configured latiency to be applied for single events.
> > - *
> > - * The 'timeout' parameter is in micro-seconds. A value of 0 will disable
> > - * the timeout.
> >   */
> >  rtems_status_code
> > -rtems_capture_read (uint32_t                 threshold,
> > -                    uint32_t                 timeout,
> > +rtems_capture_read (uint32_t                 cpu,
> >                      uint32_t*                read,
> >                      rtems_capture_record_t** recs)
> >  {
> >    rtems_interrupt_lock_context lock_context;
> >    rtems_status_code            sc = RTEMS_SUCCESSFUL;
> >    size_t                       recs_size = 0;
> > -  bool                         wrapped;
> > +  rtems_interrupt_lock*        lock = &(capture_lock_on_cpu( cpu ));
> > +  rtems_capture_buffer_t*      records = &(capture_records_on_cpu( cpu
> ));
> > +  uint32_t*                    flags = &(capture_flags_on_cpu( cpu ));
> >
> >    *read = 0;
> >    *recs = NULL;
> >
> > -  rtems_interrupt_lock_acquire (&capture_lock, &lock_context);
> > +  rtems_interrupt_lock_acquire (lock, &lock_context);
> >
> >    /*
> >     * Only one reader is allowed.
> >     */
> >
> > -  if (capture_flags & RTEMS_CAPTURE_READER_ACTIVE)
> > +  if (*flags & RTEMS_CAPTURE_READER_ACTIVE)
> >    {
> > -    rtems_interrupt_lock_release (&capture_lock, &lock_context);
> > +    rtems_interrupt_lock_release (lock, &lock_context);
> >      return RTEMS_RESOURCE_IN_USE;
> >    }
> >
> > -  capture_flags |= RTEMS_CAPTURE_READER_ACTIVE;
> > -
> > -  *recs = rtems_capture_buffer_peek( &capture_records, &recs_size );
> > -  *read = rtems_capture_count_records( *recs, recs_size );
> > -
> > -  rtems_interrupt_lock_release (&capture_lock, &lock_context);
> > -
> > -  for (;;)
> > +  if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
> >    {
> > -    /*
> > -     * See if the data wraps the end of the record buffer.
> > -     */
> > -    wrapped = rtems_capture_buffer_has_wrapped( &capture_records);
> > -
> > -    /*
> > -     * Do we have a threshold and have not wrapped
> > -     * around the end of the capture record buffer ?
> > -     */
> > -    if ((!wrapped) && threshold)
> > -    {
> > -      /*
> > -       * Do we have enough records ?
> > -       */
> > -      if (*read < threshold)
> > -      {
> > -        rtems_event_set event_out;
> > -
> > -        rtems_task_ident (RTEMS_SELF, RTEMS_LOCAL, &capture_reader);
> > -
> > -        rtems_interrupt_lock_acquire (&capture_lock, &lock_context);
> > -
> > -        capture_flags |= RTEMS_CAPTURE_READER_WAITING;
> > -
> > -        rtems_interrupt_lock_release (&capture_lock, &lock_context);
> > -
> > -        sc = rtems_event_receive (RTEMS_EVENT_0,
> > -                                  RTEMS_WAIT | RTEMS_EVENT_ANY,
> > -                                  RTEMS_MICROSECONDS_TO_TICKS (timeout),
> > -                                  &event_out);
> > -
> > -        /*
> > -         * Let the user handle all other sorts of errors. This may
> > -         * not be the best solution, but oh well, it will do for
> > -         * now.
> > -         */
> > -        if ((sc != RTEMS_SUCCESSFUL) && (sc != RTEMS_TIMEOUT))
> > -          break;
> > -
> > -        rtems_interrupt_lock_acquire (&capture_lock, &lock_context);
> > +    rtems_interrupt_lock_release (lock, &lock_context);
> > +    return RTEMS_UNSATISFIED;
> > +  }
> >
> > -        *recs = rtems_capture_buffer_peek( &capture_records, &recs_size );
> > -        *read = rtems_capture_count_records( *recs, recs_size );
> > +  *flags |= RTEMS_CAPTURE_READER_ACTIVE;
> >
> > -        rtems_interrupt_lock_release (&capture_lock, &lock_context);
> > +  *recs = rtems_capture_buffer_peek( records, &recs_size );
> >
> > -        continue;
> > -      }
> > -    }
> > +  *read = rtems_capture_count_records( *recs, recs_size );
> >
> > -    /*
> > -     * Always out if we reach here. To loop use continue.
> > -     */
> > -    break;
> > -  }
> > +  rtems_interrupt_lock_release (lock, &lock_context);
> >
> >    return sc;
> >  }
> > @@ -1226,7 +1247,7 @@ rtems_capture_read (uint32_t                 threshold,
> >   * to the capture engine. The count must match the number read.
> >   */
> >  rtems_status_code
> > -rtems_capture_release (uint32_t count)
> > +rtems_capture_release (uint32_t cpu, uint32_t count)
> >  {
> >    rtems_interrupt_lock_context lock_context;
> >    uint8_t*                     ptr;
> > @@ -1235,43 +1256,49 @@ rtems_capture_release (uint32_t count)
> >    size_t                       ptr_size = 0;
> >    size_t                       rel_size = 0;
> >    rtems_status_code            ret_val = RTEMS_SUCCESSFUL;
> > +  rtems_interrupt_lock*        lock = &(capture_lock_on_cpu( cpu ));
> > +  rtems_capture_buffer_t*      records = &(capture_records_on_cpu( cpu
> ));
> > +  uint32_t*                    flags = &(capture_flags_on_cpu( cpu ));
> > +  uint32_t*                    total = &(capture_count_on_cpu( cpu ));
> >
> > -  rtems_interrupt_lock_acquire (&capture_lock, &lock_context);
> > +  rtems_interrupt_lock_acquire (lock, &lock_context);
> >
> > -  if (count > capture_count)
> > -    count = capture_count;
> > +  if (count > *total) {
> > +    count = *total;
> > +  }
> >
> > -  rtems_interrupt_lock_release (&capture_lock, &lock_context);
> > +  if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 ) {
> > +    rtems_interrupt_lock_release (lock, &lock_context);
> > +    return RTEMS_UNSATISFIED;
> > +  }
> >
> >    counted = count;
> > -
> > -  ptr = rtems_capture_buffer_peek( &capture_records, &ptr_size );
> > +
> > +  ptr = rtems_capture_buffer_peek( records, &ptr_size );
> >    _Assert(ptr_size >= (count * sizeof(*rec) ));
> >
> >    rel_size = 0;
> > -  while (counted--)
> > -  {
> > +  while (counted--) {
> >      rec = (rtems_capture_record_t*) ptr;
> >      rel_size += rec->size;
> >      _Assert( rel_size <= ptr_size );
> >      ptr += rec->size;
> >    }
> >
> > -  rtems_interrupt_lock_acquire (&capture_lock, &lock_context);
> > -
> >    if (rel_size > ptr_size ) {
> >      ret_val = RTEMS_INVALID_NUMBER;
> >      rel_size = ptr_size;
> >    }
> >
> > -  capture_count -= count;
> > +  *total -= count;
> >
> > -  if (count)
> > -    rtems_capture_buffer_free( &capture_records, rel_size );
> > +  if (count) {
> > +    rtems_capture_buffer_free( records, rel_size );
> > +  }
> >
> > -  capture_flags &= ~RTEMS_CAPTURE_READER_ACTIVE;
> > +  *flags &= ~RTEMS_CAPTURE_READER_ACTIVE;
> >
> > -  rtems_interrupt_lock_release (&capture_lock, &lock_context);
> > +  rtems_interrupt_lock_release (lock, &lock_context);
> >
> >    return ret_val;
> >  }
> > @@ -1308,5 +1335,3 @@ rtems_capture_get_control_list (void)
> >  {
> >    return capture_controls;
> >  }
> > -
> > -
> > diff --git a/cpukit/libmisc/capture/capture.h
> b/cpukit/libmisc/capture/capture.h
> > index f907686..63d1343 100644
> > --- a/cpukit/libmisc/capture/capture.h
> > +++ b/cpukit/libmisc/capture/capture.h
> > @@ -15,7 +15,7 @@
> >    All rights reserved Objective Design Systems Pty Ltd, 2002
> >    Chris Johns (ccj at acm.org)
> >
> > -  COPYRIGHT (c) 1989-1998.
> > +  COPYRIGHT (c) 1989-2014
> >    On-Line Applications Research Corporation (OAR).
> >
> >    The license and distribution terms for this file may be
> > @@ -245,8 +245,8 @@ typedef void
> (*rtems_capture_timestamp)(rtems_capture_time_t* time);
> >   * initialisation.
> >   *
> >   * @param[in] size The number of capture records to define.
> > - * @param[in] timestamp The timestamp callout handler to use. If the
> > - *            the handler is NULL a default  nano-second timestamp
> > + * @param[in] timestamp The timestamp callout handler to use. If the
> > + *            the handler is NULL a default  nano-second timestamp
> >   *            will be used.
> >   *
> >   * @retval This method returns RTEMS_SUCCESSFUL if there was not an
> > @@ -390,7 +390,7 @@ rtems_capture_watch_global (bool enable);
> >   *
> >   * This function returns the global watch state.
> >   *
> > - * @retval This method returns true  if the global watch
> > + * @retval This method returns true  if the global watch
> >   *         is on.  Otherwise, it returns false.
> >   */
> >  bool
> > @@ -419,7 +419,7 @@ rtems_capture_watch_ceiling (rtems_task_priority
> ceiling);
> >   *
> >   * This function gets the watch ceiling.
> >   *
> > - * @retval The priority level immediately above that at which events
> > + * @retval The priority level immediately above that at which events
> >   *         from tasks are not captured.
> >   */
> >  rtems_task_priority
> > @@ -520,9 +520,6 @@ rtems_capture_clear_trigger (rtems_name
> from_name,
> >   * @brief Capture read records from capture buffer
> >   *
> >   * This function reads a number of records from the capture buffer.
> > - * The user can optionally block and wait until the buffer as a
> > - * specific number of records available or a specific time has
> > - * elasped.
> >   *
> >   * The function returns the number of record that is has that are
> >   * in a continous block of memory. If the number of available records
> > @@ -535,17 +532,7 @@ rtems_capture_clear_trigger (rtems_name
> from_name,
> >   * rtems_capture_release. Calls this function without a release will
> >   * result in at least the same number of records being released.
> >   *
> > - * The 'threshold' parameter is the number of records that must be
> > - * captured before returning. If a timeout period is specified (non-0)
> > - * any captured records will be returned. These parameters stop
> > - * thrashing occuring for a small number of records, yet allows
> > - * a user configured latiency to be applied for single events.
> > - *
> > - * The @a timeout parameter is in microseconds. A value of 0 will
> > - * disable the timeout.
> > - *
> > - * @param[in] threshold The number of records that must be captured
> > - * @param[in] timeout The micro-second timeout period
> > + * @param[in]  cpu The cpu number that the records were recorded on
> >   * @param[out] read will contain the number of records read
> >   * @param[out] recs The capture records that are read.
> >   *
> > @@ -554,8 +541,7 @@ rtems_capture_clear_trigger (rtems_name
> from_name,
> >   *         source of the error.
> >   */
> >  rtems_status_code
> > -rtems_capture_read (uint32_t                 threshold,
> > -                    uint32_t                 timeout,
> > +rtems_capture_read (uint32_t                 cpu,
> >                      uint32_t*                read,
> >                      rtems_capture_record_t** recs);
> >
> > @@ -566,13 +552,13 @@ rtems_capture_read (uint32_t                 threshold,
> >   * to the capture engine. The count must match the number read.
> >   *
> >   * @param[in] count The number of record slots to release
> > - *
> > + *
> >   * @retval This method returns RTEMS_SUCCESSFUL if there was not an
> >   *         error. Otherwise, a status code is returned indicating the
> >   *         source of the error.
> >   */
> >  rtems_status_code
> > -rtems_capture_release (uint32_t count);
> > +rtems_capture_release (uint32_t cpu, uint32_t count);
> >
> >  /*
> >   * @brief Capture nano-second time period.
> > @@ -609,7 +595,7 @@ void rtems_capture_initialize_task( rtems_tcb* tcb
> );
> >
> >  /**
> >   * @brief Capture record task.
> > - *
> > + *
> >   * This function records a new capture task record.
> >   *
> >   * @param[in] tcb is the task control block for the task
> > @@ -631,7 +617,7 @@ static inline bool rtems_capture_task_recorded(
> rtems_tcb* tcb ) {
> >  /**
> >   * @brief Capture task initialized
> >   *
> > - * This function returns true if this task information has been
> > + * This function returns true if this task information has been
> >   * initialized.
> >   *
> >   * @param[in] tcb is the task control block for the task
> > @@ -642,11 +628,11 @@ static inline bool rtems_capture_task_initialized(
> rtems_tcb* tcb ) {
> >
> >  /**
> >   * @brief Capture get task id.
> > - *
> > + *
> >   * This function returns the task id.
> >   *
> >   * @param[in] task The capture task.
> > - *
> > + *
> >   * @retval This function returns the task id.
> >   */
> >  static inline rtems_id
> > @@ -657,11 +643,11 @@ rtems_capture_task_id (rtems_tcb* tcb)
> >
> >  /**
> >   * @brief Capture get task state.
> > - *
> > + *
> >   * This function returns the task state.
> >   *
> >   * @param[in] task The capture task.
> > - *
> > + *
> >   * @retval This function returns the task state.
> >   */
> >  static inline States_Control
> > @@ -674,11 +660,11 @@ rtems_capture_task_state (rtems_tcb* tcb)
> >
> >  /**
> >   * @brief Capture get task name.
> > - *
> > + *
> >   * This function returns the task name.
> >   *
> >   * @param[in] task The capture task.
> > - *
> > + *
> >   * @retval This function returns the task name.
> >   */
> >  static inline rtems_name
> > @@ -691,11 +677,11 @@ rtems_capture_task_name (rtems_tcb* tcb)
> >
> >  /**
> >   * @brief Capture get task flags.
> > - *
> > + *
> >   * This function returns the task flags.
> >   *
> >   * @param[in] task The capture task.
> > - *
> > + *
> >   * @retval This function returns the task flags.
> >   */
> >  static inline uint32_t
> > @@ -706,11 +692,11 @@ rtems_capture_task_flags (rtems_tcb* tcb)
> >
> >  /**
> >   * @brief Capture get task control
> > - *
> > + *
> >   * This function returns the task control if present.
> >   *
> >   * @param[in] task The capture task.
> > - *
> > + *
> >   * @retval This function returns the task control if present.
> >   */
> >  static inline rtems_capture_control_t*
> > @@ -721,11 +707,11 @@ rtems_capture_task_control (rtems_tcb* tcb)
> >
> >  /**
> >   * @brief Capture get task control flags.
> > - *
> > + *
> >   * This function returns the task control flags if a control is present.
> >   *
> >   * @param[in] task The capture task.
> > - *
> > + *
> >   * @retval This function returns the task control flags if a control is present.
> >   */
> >  static inline uint32_t
> > @@ -739,12 +725,12 @@ rtems_capture_task_control_flags (rtems_tcb*
> tcb)
> >
> >  /**
> >   * @brief Capture get task start priority.
> > - *
> > + *
> >   * This function returns the tasks start priority. The tracer needs this
> >   * to track where the task's priority goes.
> >   *
> >   * @param[in] task The capture task.
> > - *
> > + *
> >   * @retval This function returns the tasks start priority. The tracer needs
> this
> >   * to track where the task's priority goes.
> >   */
> > @@ -758,11 +744,11 @@ rtems_capture_task_start_priority (rtems_tcb*
> tcb)
> >
> >  /**
> >   * @brief Capture get task real priority.
> > - *
> > + *
> >   * This function returns the tasks real priority.
> >   *
> >   * @param[in] task The capture task.
> > - *
> > + *
> >   * @retval This function returns the tasks real priority.
> >   */
> >  static inline rtems_task_priority
> > @@ -773,11 +759,11 @@ rtems_capture_task_real_priority (rtems_tcb*
> tcb)
> >
> >  /**
> >   * @brief Capture get task current priority.
> > - *
> > + *
> >   * This function returns the tasks current priority.
> >   *
> >   * @param[in] task The capture task.
> > - *
> > + *
> >   * @retval This function returns the tasks current priority.
> >   */
> >  static inline rtems_task_priority
> > @@ -800,12 +786,12 @@ rtems_capture_get_control_list (void);
> >
> >  /**
> >   * @brief Capture get next capture control.
> > - *
> > + *
> >   * This function returns the pointer to the next control in the list. The
> >   * pointer NULL terminates the list.
> >   *
> >   * @param[in] control the current capture control.
> > - *
> > + *
> >   * @retval This function returns the pointer to the next control in the list.
> The
> >   * pointer NULL terminates the list.
> >   */
> > @@ -817,11 +803,11 @@ rtems_capture_next_control
> (rtems_capture_control_t* control)
> >
> >  /**
> >   * @brief Capture get capture control id.
> > - *
> > + *
> >   * This function returns the control id.
> >   *
> >   * @param[in] control the capture control.
> > - *
> > + *
> >   * @retval This function returns the control id.
> >   */
> >  static inline rtems_id
> > @@ -943,7 +929,7 @@ rtems_capture_control_by_name
> (rtems_capture_control_t* control, int by)
> >   * @brief Capture get capture control by task id.
> >   *
> >   * This function returns the control @a by task id
> > - *
> > + *
> >   * @retval This function returns the control @a by task id.
> >   */
> >  static inline rtems_id
> > diff --git a/cpukit/libmisc/capture/capture_buffer.c
> b/cpukit/libmisc/capture/capture_buffer.c
> > index 9557f70..6f557a9 100644
> > --- a/cpukit/libmisc/capture/capture_buffer.c
> > +++ b/cpukit/libmisc/capture/capture_buffer.c
> > @@ -84,10 +84,10 @@ void * rtems_capture_buffer_allocate(
> rtems_capture_buffer_t* buffer, size_t siz
> >    buffer->head = size;
> >    buffer->count = buffer->count + size;
> >
> > -  return ptr;
> > +  return ptr;
> >  }
> >
> > -void *rtems_capture_buffer_free( rtems_capture_buffer_t* buffer,
> size_t size )
> > +void *rtems_capture_buffer_free( rtems_capture_buffer_t* buffer,
> size_t size )
> >  {
> >      static void             *ptr;
> >      static uint32_t         next;
> > @@ -112,6 +112,6 @@ void *rtems_capture_buffer_free(
> rtems_capture_buffer_t* buffer, size_t size )
> >      } else {
> >        buffer->tail = next;
> >      }
> > -
> > +
> >      return ptr;
> >  }
> > diff --git a/cpukit/libmisc/capture/capture_buffer.h
> b/cpukit/libmisc/capture/capture_buffer.h
> > index a01ca29..ebcc464 100644
> > --- a/cpukit/libmisc/capture/capture_buffer.h
> > +++ b/cpukit/libmisc/capture/capture_buffer.h
> > @@ -79,14 +79,14 @@ static inline bool
> rtems_capture_buffer_has_wrapped( rtems_capture_buffer_t* buf
> >    return false;
> >  }
> >
> > -static inline void *rtems_capture_buffer_peek(
> rtems_capture_buffer_t* buffer, size_t *size )
> > +static inline void *rtems_capture_buffer_peek(
> rtems_capture_buffer_t* buffer, size_t *size )
> >  {
> >    if (rtems_capture_buffer_is_empty(buffer)) {
> > -    *size = 0;
> > +    *size = 0;
> >      return NULL;
> >    }
> >
> > -  if ( buffer->tail > buffer->head)
> > +  if ( buffer->tail > buffer->head)
> >      *size = buffer->end - buffer->tail;
> >    else
> >      *size = buffer->head - buffer->tail;
> > diff --git a/cpukit/libmisc/capture/capture_support.c
> b/cpukit/libmisc/capture/capture_support.c
> > new file mode 100644
> > index 0000000..bdfd37b
> > --- /dev/null
> > +++ b/cpukit/libmisc/capture/capture_support.c
> > @@ -0,0 +1,307 @@
> > +/*
> > +  ------------------------------------------------------------------------
> > +
> > +  Copyright Objective Design Systems Pty Ltd, 2002
> > +  All rights reserved Objective Design Systems Pty Ltd, 2002
> > +  Chris Johns (ccj at acm.org)
> > +
> > +  COPYRIGHT (c) 1989-2014.
> > +  On-Line Applications Research Corporation (OAR).
> > +
> > +  The license and distribution terms for this file may be
> > +  found in the file LICENSE in this distribution.
> > +
> > +  This software with is provided ``as is'' and with NO WARRANTY.
> > +
> > +  ------------------------------------------------------------------------
> > +
> > +  RTEMS Performance Monitoring and Measurement Framework.
> > +
> > +  This is a set of print support routines that may be shared between
> > +  the RTEMS monitor and direct callers of the capture engine.
> > +
> > +*/
> > +
> > +#ifdef HAVE_CONFIG_H
> > +#include "config.h"
> > +#endif
> > +
> > +#include <ctype.h>
> > +#include <stdlib.h>
> > +#include <stdio.h>
> > +#include <string.h>
> > +#include <inttypes.h>
> > +
> > +#include <rtems.h>
> > +#include <rtems/monitor.h>
> > +#include <rtems/captureimpl.h>
> > +
> > +/*
> > + * Structure used during printing of the capture records.
> > + */
> > +
> > +typedef struct {
> > +  rtems_capture_record_t* rec;
> > +  uint32_t                read;
> > +  uint32_t                last_t;
> > +  uint32_t                printed;
> > +} ctrace_per_cpu_t;
> > +
> > +/*
> > + * rtems_catpure_print_uptime
> > + *
> > + *  DESCRIPTION:
> > + *
> > + * This function prints the nanosecond uptime to stdout.
> > + */
> > +void
> > +rtems_capture_print_timestamp (uint64_t uptime)
> > +{
> > +  uint32_t hours;
> > +  uint32_t minutes;
> > +  uint32_t seconds;
> > +  uint32_t nanosecs;
> > +
> > +  seconds  = uptime / 1000000000LLU;
> > +  minutes  = seconds / 60;
> > +  hours    = minutes / 60;
> > +  minutes  = minutes % 60;
> > +  seconds  = seconds % 60;
> > +  nanosecs = uptime % 1000000000;
> > +
> > +  fprintf (stdout, "%5lu:%02lu:%02lu.%09lu", hours, minutes, seconds,
> nanosecs);
> > +}
> > +
> > +void
> > +rtems_capture_print_record_task( uint32_t cpu,
> rtems_capture_record_t* rec)
> > +{
> > +  rtems_capture_task_record_t* task_rec =
> (rtems_capture_task_record_t*) rec;
> > +
> > +  fprintf(stdout,"%2" PRId32 " ", cpu);
> > +  rtems_capture_print_timestamp (rec->time);
> > +  fprintf (stdout, "            ");
> > +  rtems_monitor_dump_id (rec->task_id);
> > +  fprintf (stdout, " %c%c%c%c",
> > +           (char) (task_rec->name >> 24) & 0xff,
> > +           (char) (task_rec->name >> 16) & 0xff,
> > +           (char) (task_rec->name >> 8) & 0xff,
> > +           (char) (task_rec->name >> 0) & 0xff);
> > +  fprintf(stdout, " %3" PRId32 " %3" PRId32 " ",
> > +             (rec->events >> RTEMS_CAPTURE_REAL_PRIORITY_EVENT) & 0xff,
> > +             (rec->events >> RTEMS_CAPTURE_CURR_PRIORITY_EVENT) & 0xff
> );
> > +   fprintf (stdout, "%3" PRId32   " %3" PRId32 "  TASK_RECORD\n",
> > +            task_rec->start_priority,
> > +            task_rec->stack_size);
> > +}
> > +
> > +void
> > +rtems_capture_print_record_capture(
> > +  uint32_t                cpu,
> > +  rtems_capture_record_t* rec,
> > +  uint64_t                diff
> > +){
> > +  uint32_t                     event;
> > +  int                          e;
> > +
> > +  event = rec->events >> RTEMS_CAPTURE_EVENT_START;
> > +  for (e = RTEMS_CAPTURE_EVENT_START; e <
> RTEMS_CAPTURE_EVENT_END; e++)
> > +  {
> > +    if (event & 1)
> > +    {
> > +      fprintf(stdout,"%2" PRId32 " ", cpu);
> > +      rtems_capture_print_timestamp (rec->time);
> > +      fprintf (stdout, " %10" PRId64 " ", diff);
> > +      rtems_monitor_dump_id (rec->task_id);
> > +      fprintf(stdout, "      %3" PRId32 " %3" PRId32 "           %s\n",
> > +             (rec->events >> RTEMS_CAPTURE_REAL_PRIORITY_EVENT) & 0xff,
> > +             (rec->events >> RTEMS_CAPTURE_CURR_PRIORITY_EVENT) & 0xff,
> > +             rtems_capture_event_text (e));
> > +    }
> > +    event >>= 1;
> > +  }
> > +}
> > +
> > +/*
> > + *  rtems_capture_print_trace_records
> > + *
> > + *  DESCRIPTION:
> > + *
> > + * This function is a monitor command that dumps trace records.
> > + *
> > + */
> > +
> > +void
> > +rtems_capture_print_trace_records ( int total, bool csv )
> > +{
> > +  rtems_status_code       sc;
> > +  int                     count;
> > +  ctrace_per_cpu_t*       per_cpu;
> > +  uint8_t*                ptr;
> > +  uint32_t                i;
> > +  uint32_t                cpu = 0;
> > +  rtems_capture_record_t* rec_out;
> > +
> > +  count = rtems_get_processor_count();
> > +  per_cpu = calloc( count, sizeof(*per_cpu) );
> > +
> > +  while (total)
> > +  {
> > +    /* Prime the per_cpu data */
> > +    for (i=0; i< count; i++) {
> > +      if ( per_cpu[i].read == 0 ) {
> > +        sc = rtems_capture_read (i, &per_cpu[i].read, &per_cpu[i].rec);
> > +        if (sc != RTEMS_SUCCESSFUL)
> > +        {
> > +          fprintf (stdout, "error: trace read failed: %s\n", rtems_status_text
> (sc));
> > +          rtems_capture_flush (0);
> > +          return;
> > +        }
> > +        /* Release the buffer if there are no records to read */
> > +        if (per_cpu[i].read == 0)
> > +          rtems_capture_release (i, 0);
> > +      }
> > +    }
> > +
> > +    /* Find the next record to print */
> > +    rec_out = NULL;
> > +    for (i=0; i< count; i++) {
> > +
> > +      if ((rec_out == NULL) ||
> > +          ((per_cpu[i].read != 0) && (rec_out->time > per_cpu[i].rec->time)))
> {
> > +        rec_out = per_cpu[i].rec;
> > +        cpu = i;
> > +      }
> > +    }
> > +
> > +    /*  If we have read all the records abort. */
> > +    if (rec_out == NULL)
> > +      break;
> > +
> > +    /* Print the record */
> > +    if (csv)
> > +      fprintf (stdout, "%03" PRIu32 ",%08" PRIu32 ",%03" PRIu32
> > +                   ",%03" PRIu32 ",%04" PRIx32 ",%" PRId64 "\n",
> > +                 cpu, rec_out->task_id,
> > +                 (rec_out->events >> RTEMS_CAPTURE_REAL_PRIORITY_EVENT)
> & 0xff,
> > +                 (rec_out->events >> RTEMS_CAPTURE_CURR_PRIORITY_EVENT)
> & 0xff,
> > +                 (rec_out->events >> RTEMS_CAPTURE_EVENT_START),
> > +                 (uint64_t) rec_out->time);
> > +    else {
> > +      if ((rec_out->events >> RTEMS_CAPTURE_EVENT_START) == 0)
> > +          rtems_capture_print_record_task(cpu, rec_out );
> > +      else {
> > +        uint64_t diff = 0;
> > +        if (per_cpu[cpu].last_t)
> > +          diff = rec_out->time - per_cpu[cpu].last_t;
> > +        per_cpu[cpu].last_t = rec_out->time;
> > +
> > +        rtems_capture_print_record_capture( cpu, rec_out, diff );
> > +      }
> > +    }
> > +
> > +    /*
> > +     * If we have not printed all the records read
> > +     * increment to the next record.  If we have
> > +     * printed all records release the records printed.
> > +     */
> > +    per_cpu[cpu].printed++;
> > +    if (per_cpu[cpu].printed != per_cpu[cpu].read) {
> > +      ptr =  (uint8_t *)per_cpu[cpu].rec;
> > +      ptr += per_cpu[cpu].rec->size;
> > +      per_cpu[cpu].rec = (rtems_capture_record_t *)ptr;
> > +    } else {
> > +      rtems_capture_release (cpu, per_cpu[cpu].printed);
> > +      per_cpu[cpu].read = 0;
> > +      per_cpu[cpu].printed = 0;
> > +    }
> > +
> > +    total --;
> > +  }
> > +
> > +  /* Finished so release all the records that were printed. */
> > +  for (i=0; i< count; i++) {
> > +    if ( per_cpu[i].read != 0 )  {
> > +      rtems_capture_release( i, per_cpu[i].printed );
> > +    }
> > +  }
> > +
> > +  free( per_cpu );
> > +}
> > +
> > +void
> > +rtems_capture_print_watch_list ()
> > +{
> > +  rtems_capture_control_t* control = rtems_capture_get_control_list ();
> > +  rtems_task_priority      ceiling = rtems_capture_watch_get_ceiling ();
> > +  rtems_task_priority      floor = rtems_capture_watch_get_floor ();
> > +
> > +  fprintf (stdout, "watch priority ceiling is %" PRId32 "\n", ceiling);
> > +  fprintf (stdout, "watch priority floor is %" PRId32 "\n", floor);
> > +  fprintf (stdout, "global watch is %s\n",
> > +          rtems_capture_watch_global_on () ? "enabled" : "disabled");
> > +  fprintf (stdout, "total %" PRId32 "\n", rtems_capture_control_count ());
> > +
> > +  while (control)
> > +  {
> > +    uint32_t flags;
> > +    int      f;
> > +    int      fshowed;
> > +    int      lf;
> > +
> > +    fprintf (stdout, " ");
> > +    rtems_monitor_dump_id (rtems_capture_control_id (control));
> > +    fprintf (stdout, " ");
> > +    rtems_monitor_dump_name (rtems_capture_control_name (control));
> > +    flags = rtems_capture_control_flags (control);
> > +    fprintf (stdout, " %c%c ",
> > +             rtems_capture_watch_global_on () ? 'g' : '-',
> > +             flags & RTEMS_CAPTURE_WATCH ? 'w' : '-');
> > +    flags = rtems_capture_control_to_triggers (control);
> > +    fprintf (stdout, " T:%c%c%c%c%c%c%c",
> > +             flags & RTEMS_CAPTURE_SWITCH    ? 'S' : '-',
> > +             flags & RTEMS_CAPTURE_CREATE ? 'C' : '-',
> > +             flags & RTEMS_CAPTURE_START ? 'S' : '-',
> > +             flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
> > +             flags & RTEMS_CAPTURE_DELETE ? 'D' : '-',
> > +             flags & RTEMS_CAPTURE_BEGIN ? 'B' : '-',
> > +             flags & RTEMS_CAPTURE_EXITTED ? 'E' : '-');
> > +    flags = rtems_capture_control_from_triggers (control);
> > +    fprintf (stdout, " F:%c%c%c%c%c",
> > +             flags & RTEMS_CAPTURE_SWITCH  ? 'S' : '-',
> > +             flags & RTEMS_CAPTURE_CREATE  ? 'C' : '-',
> > +             flags & RTEMS_CAPTURE_START   ? 'S' : '-',
> > +             flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
> > +             flags & RTEMS_CAPTURE_DELETE  ? 'D' : '-');
> > +
> > +    for (f = 0, fshowed = 0, lf = 1; f < RTEMS_CAPTURE_TRIGGER_TASKS;
> f++)
> > +    {
> > +      if (rtems_capture_control_by_valid (control, f))
> > +      {
> > +        if (lf && ((fshowed % 3) == 0))
> > +        {
> > +          fprintf (stdout, "\n");
> > +          lf = 0;
> > +        }
> > +
> > +        fprintf (stdout, "  %2i:", f);
> > +        rtems_monitor_dump_name (rtems_capture_control_by_name
> (control, f));
> > +        fprintf (stdout, "/");
> > +        rtems_monitor_dump_id (rtems_capture_control_by_id (control, f));
> > +        flags = rtems_capture_control_by_triggers (control, f);
> > +        fprintf (stdout, ":%c%c%c%c%c",
> > +                 flags & RTEMS_CAPTURE_SWITCH  ? 'S' : '-',
> > +                 flags & RTEMS_CAPTURE_CREATE  ? 'C' : '-',
> > +                 flags & RTEMS_CAPTURE_START   ? 'S' : '-',
> > +                 flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
> > +                 flags & RTEMS_CAPTURE_DELETE  ? 'D' : '-');
> > +        fshowed++;
> > +        lf = 1;
> > +      }
> > +    }
> > +
> > +    if (lf)
> > +      fprintf (stdout, "\n");
> > +
> > +    control = rtems_capture_next_control (control);
> > +  }
> > +}
> > diff --git a/cpukit/libmisc/capture/capture_user_extension.c
> b/cpukit/libmisc/capture/capture_user_extension.c
> > index 69b8d48..37372cb 100644
> > --- a/cpukit/libmisc/capture/capture_user_extension.c
> > +++ b/cpukit/libmisc/capture/capture_user_extension.c
> > @@ -5,7 +5,7 @@
> >    All rights reserved Objective Design Systems Pty Ltd, 2002
> >    Chris Johns (ccj at acm.org)
> >
> > -  COPYRIGHT (c) 1989-2009.
> > +  COPYRIGHT (c) 1989-2014.
> >    On-Line Applications Research Corporation (OAR).
> >
> >    The license and distribution terms for this file may be
> > @@ -18,10 +18,6 @@
> >    RTEMS Performance Monitoring and Measurement Framework.
> >
> >    This is the Capture Engine component.
> > -rtems_status_code rtems_capture_user_extension_open(void);
> > -rtems_status_code rtems_capture_user_extension_close(void);
> > -
> > -
> >  */
> >
> >  #ifdef HAVE_CONFIG_H
> > @@ -43,8 +39,8 @@ rtems_status_code
> rtems_capture_user_extension_close(void);
> >   */
> >  static rtems_id                 capture_id;
> >
> > -static bool
> > -rtems_capture_create_task (rtems_tcb* current_task,
> > +static bool
> > +rtems_capture_create_task (rtems_tcb* current_task,
> >                             rtems_tcb* new_task);
> >
> >  static void
> > @@ -95,7 +91,7 @@ static inline void rtems_capture_record (
> >
> >    if (rtems_capture_filter( tcb, events) )
> >      return;
> > -
> > +
> >    if (!rtems_capture_task_recorded (tcb))
> >      rtems_capture_record_task (tcb);
> >
> > @@ -143,7 +139,6 @@ rtems_capture_create_task (rtems_tcb* ct,
> >     * The task pointers may not be known as the task may have
> >     * been created before the capture engine was open. Add them.
> >     */
> > -
> >    if (!rtems_capture_task_initialized (ct))
> >      rtems_capture_initialize_task (ct);
> >
> > @@ -176,7 +171,7 @@ rtems_capture_start_task (rtems_tcb* ct,
> >    if (!rtems_capture_task_initialized (ct))
> >      rtems_capture_initialize_task (ct);
> >
> > -  if (st == NULL)
> > +  if (st != NULL)
> >      rtems_capture_initialize_task (st);
> >
> >    if (rtems_capture_trigger (ct, st, RTEMS_CAPTURE_START))
> > @@ -197,7 +192,6 @@ rtems_capture_restart_task (rtems_tcb* ct,
> >     * The task pointers may not be known as the task may have
> >     * been created before the capture engine was open. Add them.
> >     */
> > -
> >    if (!rtems_capture_task_initialized (ct))
> >      rtems_capture_initialize_task (ct);
> >
> > @@ -302,7 +296,6 @@ rtems_capture_switch_task (rtems_tcb* ct,
> >    if (flags & RTEMS_CAPTURE_ON)
> >    {
> >      rtems_capture_time_t time;
> > -
> >      if (!rtems_capture_task_initialized (ct))
> >        rtems_capture_initialize_task (ct);
> >
> > diff --git a/cpukit/libmisc/capture/captureimpl.h
> b/cpukit/libmisc/capture/captureimpl.h
> > index 3c2f6c3..77a6f07 100644
> > --- a/cpukit/libmisc/capture/captureimpl.h
> > +++ b/cpukit/libmisc/capture/captureimpl.h
> > @@ -1,7 +1,7 @@
> >  /**
> >   * @file rtems/captureimpl.h
> >   *
> > - * @brief Capture Implementation file
> > + * @brief Capture Implementation file
> >   *
> >   * This file contains an interface between the capture engine and
> >   * capture user extension methods.
> > @@ -43,20 +43,25 @@ extern "C" {
> >  /*
> >   * Global capture flags.
> >   */
> > -#define RTEMS_CAPTURE_ON             (1U << 0)
> > -#define RTEMS_CAPTURE_NO_MEMORY      (1U << 1)
> > -#define RTEMS_CAPTURE_OVERFLOW       (1U << 2)
> > +#define RTEMS_CAPTURE_INIT           (1u << 0)
> > +#define RTEMS_CAPTURE_ON             (1U << 1)
> > +#define RTEMS_CAPTURE_NO_MEMORY      (1U << 2)
> >  #define RTEMS_CAPTURE_TRIGGERED      (1U << 3)
> > -#define RTEMS_CAPTURE_READER_ACTIVE  (1U << 4)
> > -#define RTEMS_CAPTURE_READER_WAITING (1U << 5)
> > -#define RTEMS_CAPTURE_GLOBAL_WATCH   (1U << 6)
> > -#define RTEMS_CAPTURE_ONLY_MONITOR   (1U << 7)
> > +#define RTEMS_CAPTURE_GLOBAL_WATCH   (1U << 4)
> > +#define RTEMS_CAPTURE_ONLY_MONITOR   (1U << 5)
> > +
> > +/*
> > + * Per-CPU capture flags.
> > + */
> > +#define RTEMS_CAPTURE_OVERFLOW       (1U << 0)
> > +#define RTEMS_CAPTURE_READER_ACTIVE  (1U << 1)
> > +#define RTEMS_CAPTURE_READER_WAITING (1U << 2)
> >
> >  /**
> >   * @brief Capture set extension index.
> >   *
> >   * This function is used to set the extension index
> > - * for the capture engine.
> > + * for the capture engine.
> >   *
> >   * @param[in] index specifies the extension index to be
> >   * used for capture engine data.
> > @@ -81,7 +86,7 @@ int  rtems_capture_get_extension_index(void);
> >   *
> >   * @retval This method returns the global capture
> >   * flags.
> > - *
> > + *
> >   */
> >  uint32_t rtems_capture_get_flags(void);
> >
> > @@ -133,7 +138,7 @@ bool rtems_capture_trigger (rtems_tcb* ft,
> >                              uint32_t   events);
> >
> >  /**
> > - * @brief Capture append to record
> > + * @brief Capture append to record
> >   *
> >   * This function Capture appends data to a capture record.  It should
> >   * be called between rtems_capture_begin_add_record and
> > @@ -145,10 +150,10 @@ bool rtems_capture_trigger (rtems_tcb* ft,
> >   *
> >   * @retval This method returns a pointer which is used as a marker
> >   * for the next location in the capture record. it should only be
> > - * used as input into rtems_capture_append_to_record or
> > + * used as input into rtems_capture_append_to_record or
> >   * rtems_capture_end_add_record.
> >   */
> > -static void *rtems_capture_append_to_record(void*  rec,
> > +static void *rtems_capture_append_to_record(void*  rec,
> >                                       void*  data,
> >                                       size_t size );
> >
> > @@ -162,7 +167,7 @@ static void
> *rtems_capture_append_to_record(void*  rec,
> >   * @param[in] events specifies the events
> >   *
> >   * @retval This method returns true if this data should be
> > - * filtered from the log.  It returns false if this data
> > + * filtered from the log.  It returns false if this data
> >   * should be logged.
> >   */
> >  bool rtems_capture_filter( rtems_tcb*            task,
> > @@ -188,13 +193,13 @@ bool rtems_capture_filter( rtems_tcb*            task,
> >   *
> >   * This function appends data of a specifed size into a capture record.
> >   *
> > - * @param[in] rec specifies the next write point in the capture record
> > + * @param[in] rec specifies the next write point in the capture record
> >   * @param[in] data specifies the data to write
> >   * @param[in] size specifies the size of the data
> >   *
> >   * @retval This method returns the next write point in the capture record.
> >   */
> > -static inline void *rtems_capture_append_to_record(void*  rec,
> > +static inline void *rtems_capture_append_to_record(void*  rec,
> >                                                     void*  data,
> >                                                     size_t size )
> >  {
> > @@ -230,9 +235,9 @@ void rtems_capture_get_time
> (rtems_capture_time_t* time);
> >  /**
> >   * @brief Capture record open.
> >   *
> > - * This function allocates a record and fills in the
> > + * This function allocates a record and fills in the
> >   * header information.  It does a lock acquire
> > - * which will remain in effect until
> > + * which will remain in effect until
> >   * rtems_capture_record_close is called.  This method
> >   * should only be used by rtems_capture_begin_add_record.
> >   *
> > @@ -251,7 +256,7 @@ void* rtems_capture_record_open (rtems_tcb*
> task,
> >  /**
> >   * @brief Capture record close.
> >   *
> > - * This function closes writing to capure record and
> > + * This function closes writing to capure record and
> >   * releases the lock that was held on the record. This
> >   * method should only be used by rtems_capture_end_add_record.
> >   *
> > @@ -261,6 +266,65 @@ void* rtems_capture_record_open (rtems_tcb*
> task,
> >  void rtems_capture_record_close( void *rec,
> rtems_interrupt_lock_context* lock_context);
> >
> >
> > +/**
> > + * @brief Capture print trace records.
> > + *
> > + * This function reads, prints and releases up to
> > + * total trace records in either a csv format or an
> > + * ascii table format.
> > + *
> > + * @param[in] total specifies the number of records to print
> > + * @param[in] csv specifies a comma seperated value format
> > + */
> > +void rtems_capture_print_trace_records ( int total, bool csv );
> > +
> > +/**
> > + * @brief Capture print timestamp.
> > + *
> > + * This function prints uptime in a timestamp format.
> > + *
> > + * @param[in] uptime specifies the timestamp to print
> > + */
> > +void rtems_capture_print_timestamp (uint64_t uptime);
> > +
> > +/**
> > + * @brief Capture print record task.
> > + *
> > + * This function  prints a capture record task.  This
> > + * record contains information to identify a task.  It
> > + * is refrenced in other records by the task id.
> > + *
> > + * @param[in] cpu specifies the cpu the cpu the record was logged on.
> > + * @param[in] rec specifies the task record.
> > + */
> > +void rtems_capture_print_record_task(
> > +  uint32_t                cpu,
> > +  rtems_capture_record_t* rec
> > +);
> > +
> > +/**
> > + * @brief Capture print capture record.
> > + *
> > + * This function prints a user extension
> > + * capture record.
> > + *
> > + * @param[in] cpu specifies the cpu the cpu the record was logged on.
> > + * @param[in] rec specifies the record.
> > + * @param[in] diff specifies the time between this and the last capture
> record.
> > + */
> > +void rtems_capture_print_record_capture(
> > +  uint32_t                cpu,
> > +  rtems_capture_record_t* rec,
> > +  uint64_t                diff
> > +);
> > +
> > +/**
> > + * @brief Capture print watch list
> > + *
> > + * This function  prints a capture watch list
> > + */
> > +void rtems_capture_print_watch_list( void );
> > +
> >  #ifdef __cplusplus
> >  }
> >  #endif
> > --
> > 1.8.1.4
> >
> > _______________________________________________
> > devel mailing list
> > devel at rtems.org
> > http://lists.rtems.org/mailman/listinfo/devel


More information about the devel mailing list