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

Gedare Bloom gedare at rtems.org
Tue Nov 4 16:16:09 UTC 2014


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.

>  /*
>   * 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.

>  /**
>   * 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.)

> +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?

>  /*
>   * 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?

> -    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