summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cpukit/libmisc/capture/capture-cli.c51
-rw-r--r--cpukit/libmisc/capture/capture-cli.h5
-rw-r--r--cpukit/libmisc/capture/capture.c475
-rw-r--r--cpukit/libmisc/capture/capture.h257
-rw-r--r--cpukit/libmisc/capture/capture_buffer.c164
-rw-r--r--cpukit/libmisc/capture/capture_buffer.h69
-rw-r--r--cpukit/libmisc/capture/capture_support.c323
-rw-r--r--cpukit/libmisc/capture/capture_user_extension.c23
-rw-r--r--cpukit/libmisc/capture/captureimpl.h179
-rw-r--r--testsuites/smptests/smpcapture02/init.c172
10 files changed, 975 insertions, 743 deletions
diff --git a/cpukit/libmisc/capture/capture-cli.c b/cpukit/libmisc/capture/capture-cli.c
index b9c2edcd75..d2ee38359b 100644
--- a/cpukit/libmisc/capture/capture-cli.c
+++ b/cpukit/libmisc/capture/capture-cli.c
@@ -204,14 +204,22 @@ rtems_capture_cli_print_task (rtems_tcb *tcb)
rtems_task_priority floor = rtems_capture_watch_get_floor ();
rtems_task_priority priority;
int length;
+ uint32_t flags = rtems_capture_task_control_flags (tcb);
priority = rtems_capture_task_real_priority (tcb);
fprintf (stdout, " ");
rtems_monitor_dump_id (rtems_capture_task_id (tcb));
fprintf (stdout, " ");
- rtems_monitor_dump_name (rtems_capture_task_id (tcb));
- fprintf (stdout, " ");
+ if (rtems_capture_task_api (rtems_capture_task_id (tcb)) != OBJECTS_POSIX_API)
+ {
+ rtems_monitor_dump_name (rtems_capture_task_id (tcb));
+ fprintf (stdout, " ");
+ }
+ else
+ {
+ fprintf (stdout, " ");
+ }
rtems_monitor_dump_priority (rtems_capture_task_start_priority (tcb));
fprintf (stdout, " ");
rtems_monitor_dump_priority (rtems_capture_task_real_priority (tcb));
@@ -222,13 +230,12 @@ rtems_capture_cli_print_task (rtems_tcb *tcb)
fprintf (stdout, "%*c", 14 - length, ' ');
fprintf (stdout, " %c%c",
'a',
- rtems_capture_task_flags (tcb) & RTEMS_CAPTURE_TRACED ? 't' : '-');
+ flags & RTEMS_CAPTURE_TRACED ? 't' : '-');
if ((floor > ceiling) && (ceiling > priority))
fprintf (stdout, "--");
else
{
- uint32_t flags = rtems_capture_task_control_flags (tcb);
fprintf (stdout, "%c%c",
rtems_capture_task_control (tcb) ?
(flags & RTEMS_CAPTURE_WATCH ? 'w' : '+') : '-',
@@ -795,7 +802,7 @@ rtems_capture_cli_trigger_worker (int set, int argc, char** argv)
continue;
}
- if (strcmp (arg[argv], "from") == 0)
+ if (strcmp (argv[arg], "from") == 0)
{
if (from_valid_name || from_valid_id)
fprintf (stdout, "warning: extra 'from' ignored\n");
@@ -804,7 +811,7 @@ rtems_capture_cli_trigger_worker (int set, int argc, char** argv)
continue;
}
- if (strcmp (arg[argv], "to") == 0)
+ if (strcmp (argv[arg], "to") == 0)
{
if (to_valid_name || from_valid_id)
fprintf (stdout, "warning: extra 'to' ignored\n");
@@ -1040,7 +1047,7 @@ static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
{
{
"copen",
- "usage: copen [-i] size\n",
+ "usage: copen [-i] size",
0,
rtems_capture_cli_open,
{ 0 },
@@ -1048,7 +1055,7 @@ static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
},
{
"cclose",
- "usage: cclose\n",
+ "usage: cclose",
0,
rtems_capture_cli_close,
{ 0 },
@@ -1056,7 +1063,7 @@ static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
},
{
"cenable",
- "usage: cenable\n",
+ "usage: cenable",
0,
rtems_capture_cli_enable,
{ 0 },
@@ -1064,7 +1071,7 @@ static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
},
{
"cdisable",
- "usage: cdisable\n",
+ "usage: cdisable",
0,
rtems_capture_cli_disable,
{ 0 },
@@ -1072,7 +1079,7 @@ static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
},
{
"ctlist",
- "usage: ctlist \n",
+ "usage: ctlist",
0,
rtems_capture_cli_task_list,
{ 0 },
@@ -1080,7 +1087,7 @@ static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
},
{
"cwlist",
- "usage: cwlist\n",
+ "usage: cwlist",
0,
rtems_capture_cli_watch_list,
{ 0 },
@@ -1088,7 +1095,7 @@ static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
},
{
"cwadd",
- "usage: cwadd [task name] [id]\n",
+ "usage: cwadd [task name] [id]",
0,
rtems_capture_cli_watch_add,
{ 0 },
@@ -1096,7 +1103,7 @@ static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
},
{
"cwdel",
- "usage: cwdel [task name] [id]\n",
+ "usage: cwdel [task name] [id]",
0,
rtems_capture_cli_watch_del,
{ 0 },
@@ -1104,7 +1111,7 @@ static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
},
{
"cwctl",
- "usage: cwctl [task name] [id] on/off\n",
+ "usage: cwctl [task name] [id] on/off",
0,
rtems_capture_cli_watch_control,
{ 0 },
@@ -1112,7 +1119,7 @@ static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
},
{
"cwglob",
- "usage: cwglob on/off\n",
+ "usage: cwglob on/off",
0,
rtems_capture_cli_watch_global,
{ 0 },
@@ -1120,7 +1127,7 @@ static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
},
{
"cwceil",
- "usage: cwceil priority\n",
+ "usage: cwceil priority",
0,
rtems_capture_cli_watch_ceiling,
{ 0 },
@@ -1128,7 +1135,7 @@ static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
},
{
"cwfloor",
- "usage: cwfloor priority\n",
+ "usage: cwfloor priority",
0,
rtems_capture_cli_watch_floor,
{ 0 },
@@ -1136,7 +1143,7 @@ static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
},
{
"ctrace",
- "usage: ctrace [-c] [-r records]\n",
+ "usage: ctrace [-c] [-r records]",
0,
rtems_capture_cli_trace_records,
{ 0 },
@@ -1144,7 +1151,7 @@ static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
},
{
"ctset",
- "usage: ctset -h\n",
+ "usage: ctset -h",
0,
rtems_capture_cli_trigger_set,
{ 0 },
@@ -1152,7 +1159,7 @@ static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
},
{
"ctclear",
- "usage: ctclear -?\n",
+ "usage: ctclear -?",
0,
rtems_capture_cli_trigger_clear,
{ 0 },
@@ -1160,7 +1167,7 @@ static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
},
{
"cflush",
- "usage: cflush [-n]\n",
+ "usage: cflush [-n]",
0,
rtems_capture_cli_flush,
{ 0 },
diff --git a/cpukit/libmisc/capture/capture-cli.h b/cpukit/libmisc/capture/capture-cli.h
index 24d1e88183..55749b7cb1 100644
--- a/cpukit/libmisc/capture/capture-cli.h
+++ b/cpukit/libmisc/capture/capture-cli.h
@@ -8,9 +8,8 @@
/*
------------------------------------------------------------------------
- Copyright Objective Design Systems Pty Ltd, 2002
- All rights reserved Objective Design Systems Pty Ltd, 2002
- Chris Johns (ccj@acm.org)
+ Copyright 2002, 2016 Chris Johns <chrisj@rtems.org>.
+ All rights reserved.
COPYRIGHT (c) 1989-2014.
On-Line Applications Research Corporation (OAR).
diff --git a/cpukit/libmisc/capture/capture.c b/cpukit/libmisc/capture/capture.c
index 6879a37a81..6cec8a5cf3 100644
--- a/cpukit/libmisc/capture/capture.c
+++ b/cpukit/libmisc/capture/capture.c
@@ -1,9 +1,8 @@
/*
------------------------------------------------------------------------
- Copyright Objective Design Systems Pty Ltd, 2002
- All rights reserved Objective Design Systems Pty Ltd, 2002
- Chris Johns (ccj@acm.org)
+ Copyright 2002, 2016 Chris Johns <chrisj@rtems.org>.
+ All rights reserved.
COPYRIGHT (c) 1989-2014.
On-Line Applications Research Corporation (OAR).
@@ -187,17 +186,22 @@ rtems_capture_match_name_id (rtems_name lhs_name,
rtems_name rhs_name,
rtems_id rhs_id)
{
+ bool match_name;
+
+ match_name = ((rtems_capture_task_api(lhs_id) != OBJECTS_POSIX_API) &&
+ (rtems_capture_task_api(rhs_id) != OBJECTS_POSIX_API));
+
/*
* The left hand side name or id could be 0 which means a wildcard.
*/
if ((lhs_name == 0) && (lhs_id == rhs_id))
- return 1;
- else if ((lhs_id == 0) || (lhs_id == rhs_id))
+ return true;
+ else if (match_name && ((lhs_id == 0) || (lhs_id == rhs_id)))
{
if (rtems_capture_match_names (lhs_name, rhs_name))
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/*
@@ -265,7 +269,6 @@ static inline rtems_capture_control_t*
rtems_capture_find_control (rtems_name name, rtems_id id)
{
rtems_capture_control_t* control;
-
for (control = capture_controls; control != NULL; control = control->next)
if (rtems_capture_match_name_id (name, id, control->name, control->id))
break;
@@ -279,24 +282,32 @@ rtems_capture_find_control (rtems_name name, rtems_id id)
static void
rtems_capture_initialize_control (rtems_tcb *tcb)
{
- rtems_name name;
- rtems_capture_control_t* control;
+ if (tcb->Capture.control == NULL)
+ {
+ rtems_name name = rtems_build_name(0, 0, 0, 0);
+ rtems_id id;
+ rtems_capture_control_t* control;
- /*
- * We need to scan the default control list to initialise
- * this control.
- */
- rtems_object_get_classic_name( tcb->Object.id, &name );
- control = capture_controls;
- if (rtems_capture_match_name_id (control->name, control->id,
- name, tcb->Object.id))
- tcb->Capture.control = control;
+ /*
+ * We need to scan the default control list to initialise
+ * this control.
+ */
+ id = tcb->Object.id;
+ if (rtems_capture_task_api (id) != OBJECTS_POSIX_API)
+ rtems_object_get_classic_name (id, &name);
+ for (control = capture_controls; control != NULL; control = control->next)
+ {
+ if (rtems_capture_match_name_id (control->name, control->id,
+ name, id))
+ {
+ tcb->Capture.control = control;
+ break;
+ }
+ }
+ }
}
-/*
- * This function creates a capture control for the capture engine.
- */
-static inline rtems_capture_control_t*
+static rtems_capture_control_t*
rtems_capture_create_control (rtems_name name, rtems_id id)
{
rtems_interrupt_lock_context lock_context;
@@ -309,7 +320,7 @@ rtems_capture_create_control (rtems_name name, rtems_id id)
if (control == NULL)
{
- control = malloc( sizeof (*control));
+ control = malloc (sizeof (*control));
if (!control)
{
@@ -330,6 +341,7 @@ rtems_capture_create_control (rtems_name name, rtems_id id)
control->next = capture_controls;
capture_controls = control;
+
rtems_iterate_over_all_threads (rtems_capture_initialize_control);
rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
@@ -338,39 +350,114 @@ rtems_capture_create_control (rtems_name name, rtems_id id)
return control;
}
-void rtems_capture_initialize_task( rtems_tcb* tcb )
+void
+rtems_capture_record_lock (rtems_capture_record_lock_context* context)
+{
+ rtems_capture_per_cpu_data* cpu;
+ cpu = capture_per_cpu_get (rtems_get_current_processor ());
+ rtems_interrupt_lock_interrupt_disable (&context->lock_context);
+ context->lock = &cpu->lock;
+ rtems_interrupt_lock_acquire_isr (&cpu->lock, &context->lock_context);
+}
+
+void
+rtems_capture_record_unlock (rtems_capture_record_lock_context* context)
+{
+ rtems_interrupt_lock_release (context->lock, &context->lock_context);
+}
+
+void*
+rtems_capture_record_open (rtems_tcb* tcb,
+ uint32_t events,
+ size_t size,
+ rtems_capture_record_lock_context* context)
+{
+ rtems_capture_per_cpu_data* cpu;
+ uint8_t* ptr;
+
+ size += sizeof (rtems_capture_record_t);
+
+ cpu = capture_per_cpu_get (rtems_get_current_processor ());
+
+ rtems_capture_record_lock (context);
+
+ ptr = rtems_capture_buffer_allocate (&cpu->records, size);
+ if (ptr != NULL)
+ {
+ rtems_capture_record_t in;
+
+ ++cpu->count;
+
+ if ((events & RTEMS_CAPTURE_RECORD_EVENTS) == 0)
+ tcb->Capture.flags |= RTEMS_CAPTURE_TRACED;
+
+ /*
+ * Create a local copy then copy. The buffer maybe mis-aligned.
+ */
+ in.size = size;
+ in.task_id = tcb->Object.id;
+ in.events = (events |
+ (tcb->real_priority) |
+ (tcb->current_priority << 8));
+
+ rtems_capture_get_time (&in.time);
+
+ ptr = rtems_capture_record_append(ptr, &in, sizeof(in));
+ }
+ else
+ cpu->flags |= RTEMS_CAPTURE_OVERFLOW;
+
+ return ptr;
+}
+
+void
+rtems_capture_record_close (rtems_capture_record_lock_context* context)
+{
+ rtems_capture_record_unlock (context);
+}
+
+void
+rtems_capture_initialize_task( rtems_tcb* tcb )
{
rtems_capture_control_t* control;
- rtems_name name;
+ rtems_name name = rtems_build_name(0, 0, 0, 0);
+ rtems_id id = rtems_capture_task_id (tcb);
rtems_interrupt_lock_context lock_context;
/*
* 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 );
+ if (rtems_capture_task_api (id) != OBJECTS_POSIX_API)
+ rtems_object_get_classic_name (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,
- name, tcb->Object.id))
+ name, id))
tcb->Capture.control = control;
}
tcb->Capture.flags |= RTEMS_CAPTURE_INIT_TASK;
+
rtems_interrupt_lock_release (&capture_lock_global, &lock_context);
}
-void rtems_capture_record_task( rtems_tcb* tcb )
+void rtems_capture_record_task (rtems_tcb* tcb)
{
- rtems_capture_task_record_t rec;
- void* ptr;
- rtems_interrupt_lock_context lock_context;
+ rtems_name name = rtems_build_name (0, 0, 0, 0);
+ rtems_id id = rtems_capture_task_id (tcb);
+ rtems_capture_task_record_t rec;
+ void* ptr;
+ rtems_interrupt_lock_context lock_context;
+ rtems_capture_record_lock_context rec_context;
- rtems_object_get_classic_name( tcb->Object.id, &rec.name );
+ if (rtems_capture_task_api (id) != OBJECTS_POSIX_API)
+ rtems_object_get_classic_name (id, &name);
+ rec.name = name;
rec.stack_size = tcb->Start.Initial_stack.size;
rec.start_priority = rtems_capture_task_start_priority (tcb);
@@ -379,35 +466,20 @@ void rtems_capture_record_task( rtems_tcb* tcb )
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.
+ * 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,
- &rec.name,
- sizeof( rec.name )
- );
- ptr = rtems_capture_append_to_record(
- ptr,
- &rec.start_priority,
- sizeof( rec.start_priority)
- );
- ptr = rtems_capture_append_to_record(
- ptr,
- &rec.stack_size,
- sizeof( rec.stack_size)
- );
- rtems_capture_end_add_record ( ptr );
+ ptr = rtems_capture_record_open (tcb, 0, sizeof(rec), &rec_context);
+ if (ptr != NULL)
+ rtems_capture_record_append(ptr, &rec, sizeof (rec));
+ rtems_capture_record_close (&rec_context);
}
/*
* This function indicates if data should be filtered from the
* log.
*/
-bool rtems_capture_filter( rtems_tcb* tcb,
- uint32_t events)
+bool rtems_capture_filter (rtems_tcb* tcb, uint32_t events)
{
if (tcb &&
((capture_flags_global &
@@ -437,60 +509,11 @@ bool rtems_capture_filter( rtems_tcb* tcb,
}
/*
- * This function records a capture record into the capture buffer.
- */
-void *
-rtems_capture_record_open (rtems_tcb* tcb,
- uint32_t events,
- size_t size,
- rtems_capture_record_context_t* context)
-{
- rtems_capture_per_cpu_data* per_cpu;
- uint8_t* ptr;
- rtems_capture_record_t* capture_in;
-
- rtems_interrupt_lock_interrupt_disable (&context->lock_context);
- per_cpu = capture_per_cpu_get (rtems_get_current_processor ());
- context->lock = &per_cpu->lock;
- rtems_interrupt_lock_acquire_isr (&per_cpu->lock, &context->lock_context);
-
- ptr = rtems_capture_buffer_allocate (&per_cpu->records, size);
- capture_in = (rtems_capture_record_t *) ptr;
- if ( capture_in )
- {
- ++per_cpu->count;
- capture_in->size = size;
- capture_in->task_id = tcb->Object.id;
- capture_in->events = (events |
- (tcb->real_priority) |
- (tcb->current_priority << 8));
-
- if ((events & RTEMS_CAPTURE_RECORD_EVENTS) == 0)
- tcb->Capture.flags |= RTEMS_CAPTURE_TRACED;
-
- rtems_capture_get_time (&capture_in->time);
-
- ptr = ptr + sizeof(*capture_in);
- }
- else
- per_cpu->flags |= RTEMS_CAPTURE_OVERFLOW;
-
- return ptr;
-}
-
-void rtems_capture_record_close( void *rec, rtems_capture_record_context_t* context)
-{
- rtems_interrupt_lock_release (context->lock, &context->lock_context);
-}
-
-/*
* See if we have triggered and if not see if this event is a
* cause of a trigger.
*/
bool
-rtems_capture_trigger (rtems_tcb* ft,
- rtems_tcb* tt,
- uint32_t events)
+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.
@@ -531,7 +554,7 @@ rtems_capture_trigger (rtems_tcb* ft,
if (from_events || to_events)
{
capture_flags_global |= RTEMS_CAPTURE_TRIGGERED;
- return 1;
+ return true;
}
/*
@@ -542,14 +565,14 @@ rtems_capture_trigger (rtems_tcb* ft,
if (rtems_capture_by_in_to (events, ft, tc))
{
capture_flags_global |= RTEMS_CAPTURE_TRIGGERED;
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/*
@@ -739,38 +762,44 @@ rtems_capture_flush_tcb (rtems_tcb *tcb)
rtems_status_code
rtems_capture_flush (bool prime)
{
- rtems_interrupt_lock_context lock_context_global;
- uint32_t cpu;
+ rtems_status_code sc = RTEMS_NOT_CONFIGURED;
+ if (capture_per_cpu != NULL)
+ {
+ rtems_interrupt_lock_context lock_context_global;
+ uint32_t cpu;
- rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context_global);
+ rtems_interrupt_lock_acquire (&capture_lock_global, &lock_context_global);
- if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
- {
- rtems_interrupt_lock_release (&capture_lock_global, &lock_context_global);
- return RTEMS_UNSATISFIED;
- }
+ 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);
+ rtems_iterate_over_all_threads (rtems_capture_flush_tcb);
- if (prime)
- capture_flags_global &= ~(RTEMS_CAPTURE_TRIGGERED | RTEMS_CAPTURE_OVERFLOW);
- else
- capture_flags_global &= ~RTEMS_CAPTURE_OVERFLOW;
+ if (prime)
+ capture_flags_global &= ~(RTEMS_CAPTURE_TRIGGERED | RTEMS_CAPTURE_OVERFLOW);
+ else
+ capture_flags_global &= ~RTEMS_CAPTURE_OVERFLOW;
- for (cpu=0; cpu < rtems_get_processor_count(); cpu++) {
- RTEMS_INTERRUPT_LOCK_REFERENCE( lock, &(capture_lock_on_cpu( cpu )) )
- rtems_interrupt_lock_context lock_context_per_cpu;
+ for (cpu=0; cpu < rtems_get_processor_count(); cpu++) {
+ RTEMS_INTERRUPT_LOCK_REFERENCE( lock, &(capture_lock_on_cpu( cpu )) )
+ rtems_interrupt_lock_context lock_context_per_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_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_global, &lock_context_global);
+ rtems_interrupt_lock_release (&capture_lock_global, &lock_context_global);
- return RTEMS_SUCCESSFUL;
+ sc = RTEMS_SUCCESSFUL;
+ }
+
+ return sc;
}
/*
@@ -1164,23 +1193,22 @@ rtems_capture_clear_trigger (rtems_name from_name,
return RTEMS_SUCCESSFUL;
}
-static inline uint32_t rtems_capture_count_records( void* recs, size_t size )
+static inline uint32_t
+rtems_capture_count_records (const void* records, size_t size)
{
- rtems_capture_record_t* rec;
- uint8_t* ptr = recs;
- uint32_t rec_count = 0;
- size_t byte_count = 0;
-
+ const uint8_t* ptr = records;
+ uint32_t recs = 0;
+ size_t bytes = 0;
- while (byte_count < size) {
- rec = (rtems_capture_record_t*) ptr;
- rec_count++;
- _Assert( rec->size >= sizeof(*rec) );
+ while (bytes < size)
+ {
+ const rtems_capture_record_t* rec = (const rtems_capture_record_t*) ptr;
+ recs++;
ptr += rec->size;
- byte_count += rec->size;
- };
+ bytes += rec->size;
+ }
- return rec_count;
+ return recs;
}
/*
@@ -1198,45 +1226,51 @@ static inline uint32_t rtems_capture_count_records( void* recs, size_t size )
* result in at least the same number of records being released.
*/
rtems_status_code
-rtems_capture_read (uint32_t cpu,
- uint32_t* read,
- rtems_capture_record_t** recs)
+rtems_capture_read (uint32_t cpu, size_t* read, const void** recs)
{
- rtems_interrupt_lock_context lock_context;
- rtems_status_code sc = RTEMS_SUCCESSFUL;
- size_t recs_size = 0;
- RTEMS_INTERRUPT_LOCK_REFERENCE( lock, &(capture_lock_on_cpu( cpu )) )
- rtems_capture_buffer_t* records = &(capture_records_on_cpu( cpu ));
- uint32_t* flags = &(capture_flags_on_cpu( cpu ));
+ rtems_status_code sc = RTEMS_NOT_CONFIGURED;
+ if (capture_per_cpu != NULL)
+ {
+ RTEMS_INTERRUPT_LOCK_REFERENCE (lock, &(capture_lock_on_cpu (cpu)))
+ rtems_interrupt_lock_context lock_context;
+ size_t recs_size = 0;
+ rtems_capture_buffer_t* records;
+ uint32_t* flags;
- *read = 0;
- *recs = NULL;
+ *read = 0;
+ *recs = NULL;
- rtems_interrupt_lock_acquire (lock, &lock_context);
+ records = &(capture_records_on_cpu (cpu));
+ flags = &(capture_flags_on_cpu (cpu));
- /*
- * Only one reader is allowed.
- */
+ rtems_interrupt_lock_acquire (lock, &lock_context);
- if (*flags & RTEMS_CAPTURE_READER_ACTIVE)
- {
- rtems_interrupt_lock_release (lock, &lock_context);
- return RTEMS_RESOURCE_IN_USE;
- }
+ /*
+ * Only one reader is allowed.
+ */
- if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
- {
- rtems_interrupt_lock_release (lock, &lock_context);
- return RTEMS_UNSATISFIED;
- }
+ if (*flags & RTEMS_CAPTURE_READER_ACTIVE)
+ {
+ rtems_interrupt_lock_release (lock, &lock_context);
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 )
+ {
+ rtems_interrupt_lock_release (lock, &lock_context);
+ return RTEMS_UNSATISFIED;
+ }
+
+ *flags |= RTEMS_CAPTURE_READER_ACTIVE;
- *flags |= RTEMS_CAPTURE_READER_ACTIVE;
+ *recs = rtems_capture_buffer_peek( records, &recs_size );
- *recs = rtems_capture_buffer_peek( records, &recs_size );
+ *read = rtems_capture_count_records( *recs, recs_size );
- *read = rtems_capture_count_records( *recs, recs_size );
+ rtems_interrupt_lock_release (lock, &lock_context);
- rtems_interrupt_lock_release (lock, &lock_context);
+ sc = RTEMS_SUCCESSFUL;
+ }
return sc;
}
@@ -1248,58 +1282,63 @@ rtems_capture_read (uint32_t cpu,
rtems_status_code
rtems_capture_release (uint32_t cpu, uint32_t count)
{
- rtems_interrupt_lock_context lock_context;
- uint8_t* ptr;
- rtems_capture_record_t* rec;
- uint32_t counted;
- size_t ptr_size = 0;
- size_t rel_size = 0;
- rtems_status_code ret_val = RTEMS_SUCCESSFUL;
- RTEMS_INTERRUPT_LOCK_REFERENCE( 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 (lock, &lock_context);
-
- if (count > *total) {
- count = *total;
- }
+ rtems_status_code sc = RTEMS_NOT_CONFIGURED;
+ if (capture_per_cpu != NULL)
+ {
+ rtems_interrupt_lock_context lock_context;
+ uint8_t* ptr;
+ rtems_capture_record_t* rec;
+ uint32_t counted;
+ size_t ptr_size = 0;
+ size_t rel_size = 0;
+ RTEMS_INTERRUPT_LOCK_REFERENCE( 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 ));
- if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 ) {
- rtems_interrupt_lock_release (lock, &lock_context);
- return RTEMS_UNSATISFIED;
- }
+ sc = RTEMS_SUCCESSFUL;
- counted = count;
+ rtems_interrupt_lock_acquire (lock, &lock_context);
- ptr = rtems_capture_buffer_peek( records, &ptr_size );
- _Assert(ptr_size >= (count * sizeof(*rec) ));
+ if (count > *total) {
+ count = *total;
+ }
- rel_size = 0;
- while (counted--) {
- rec = (rtems_capture_record_t*) ptr;
- rel_size += rec->size;
- _Assert( rel_size <= ptr_size );
- ptr += rec->size;
- }
+ if ( (capture_flags_global & RTEMS_CAPTURE_ON) != 0 ) {
+ rtems_interrupt_lock_release (lock, &lock_context);
+ return RTEMS_UNSATISFIED;
+ }
- if (rel_size > ptr_size ) {
- ret_val = RTEMS_INVALID_NUMBER;
- rel_size = ptr_size;
- }
+ counted = count;
- *total -= count;
+ ptr = rtems_capture_buffer_peek( records, &ptr_size );
+ _Assert(ptr_size >= (count * sizeof(*rec) ));
- if (count) {
- rtems_capture_buffer_free( records, rel_size );
- }
+ rel_size = 0;
+ while (counted--) {
+ rec = (rtems_capture_record_t*) ptr;
+ rel_size += rec->size;
+ _Assert( rel_size <= ptr_size );
+ ptr += rec->size;
+ }
+
+ if (rel_size > ptr_size ) {
+ sc = RTEMS_INVALID_NUMBER;
+ rel_size = ptr_size;
+ }
- *flags &= ~RTEMS_CAPTURE_READER_ACTIVE;
+ *total -= count;
+
+ if (count) {
+ rtems_capture_buffer_free( records, rel_size );
+ }
- rtems_interrupt_lock_release (lock, &lock_context);
+ *flags &= ~RTEMS_CAPTURE_READER_ACTIVE;
- return ret_val;
+ rtems_interrupt_lock_release (lock, &lock_context);
+ }
+
+ return sc;
}
/*
diff --git a/cpukit/libmisc/capture/capture.h b/cpukit/libmisc/capture/capture.h
index d439968005..91eaed38d6 100644
--- a/cpukit/libmisc/capture/capture.h
+++ b/cpukit/libmisc/capture/capture.h
@@ -11,9 +11,8 @@
/*
------------------------------------------------------------------------
- Copyright Objective Design Systems Pty Ltd, 2002
- All rights reserved Objective Design Systems Pty Ltd, 2002
- Chris Johns (ccj@acm.org)
+ Copyright 2002, 2016 Chris Johns <chrisj@rtems.org>.
+ All rights reserved.
COPYRIGHT (c) 1989-2014
On-Line Applications Research Corporation (OAR).
@@ -33,6 +32,10 @@
#ifndef __CAPTURE_H_
#define __CAPTURE_H_
+#include <rtems.h>
+#include <rtems/rtems/tasksimpl.h>
+#include <rtems/score/schedulerimpl.h>
+
/**
* @defgroup libmisc_capture RTEMS Capture Engine
*
@@ -45,9 +48,22 @@
extern "C" {
#endif
-#include <rtems.h>
-#include <rtems/rtems/tasksimpl.h>
-#include <rtems/score/schedulerimpl.h>
+/*
+ * Global capture flags.
+ */
+#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_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)
/**
* The number of tasks in a trigger group.
@@ -154,11 +170,11 @@ typedef struct rtems_capture_control_s
*/
typedef struct rtems_capture_record_s
{
- rtems_capture_time_t time;
size_t size;
uint32_t events;
+ rtems_capture_time_t time;
rtems_id task_id;
-} rtems_capture_record_t;
+} RTEMS_PACKED rtems_capture_record_t;
/*
* @brief Capture task record.
@@ -169,11 +185,10 @@ typedef struct rtems_capture_record_s
*/
typedef struct rtems_capture_task_record_s
{
- rtems_capture_record_t rec;
- rtems_name name;
- rtems_task_priority start_priority;
- uint32_t stack_size;
-} rtems_capture_task_record_t;
+ rtems_name name;
+ rtems_task_priority start_priority;
+ uint32_t stack_size;
+} RTEMS_PACKED rtems_capture_task_record_t;
/**
* The capture record event flags.
@@ -239,6 +254,24 @@ typedef enum rtems_capture_trigger_e
typedef void (*rtems_capture_timestamp)(rtems_capture_time_t* time);
/**
+ * @brief Capture record lock context.
+ *
+ * This structure is used to lock a per CPU buffer when opeining recording. The
+ * per CPU buffer is held locked until the record close is called. Locking
+ * masks interrupts so use this lock only when needed and do not hold it for
+ * long.
+ *
+ * The lock first masks the CPU interrupt before taking the interrupt
+ * lock. This stops a thread context taking the lock and then an interrupt on
+ * the same CPU attempting to take the lock so creating a deadlock.
+ *
+ */
+typedef struct {
+ rtems_interrupt_lock_context lock_context;
+ rtems_interrupt_lock* lock;
+} rtems_capture_record_lock_context;
+
+/**
* @brief Capture open
*
* This function initialises the realtime trace manager allocating the
@@ -254,9 +287,8 @@ typedef void (*rtems_capture_timestamp)(rtems_capture_time_t* time);
* error. Otherwise, a status code is returned indicating the
* source of the error.
*/
-rtems_status_code
-rtems_capture_open (uint32_t size,
- rtems_capture_timestamp timestamp);
+rtems_status_code rtems_capture_open (uint32_t size,
+ rtems_capture_timestamp timestamp);
/**
* @brief Capture close
@@ -268,8 +300,7 @@ rtems_capture_open (uint32_t size,
* error. Otherwise, a status code is returned indicating the
* source of the error.
*/
-rtems_status_code
-rtems_capture_close (void);
+rtems_status_code rtems_capture_close (void);
/**
* @brief Capture control trace enable/disable.
@@ -282,8 +313,7 @@ rtems_capture_close (void);
* error. Otherwise, a status code is returned indicating the
* source of the error.
*/
-rtems_status_code
-rtems_capture_control (bool enable);
+rtems_status_code rtems_capture_control (bool enable);
/**
* @brief Capture monitor enable/disable.
@@ -298,8 +328,7 @@ rtems_capture_control (bool enable);
* error. Otherwise, a status code is returned indicating the
* source of the error.
*/
-rtems_status_code
-rtems_capture_monitor (bool enable);
+rtems_status_code rtems_capture_monitor (bool enable);
/*
* @brief Capture flush trace buffer.
@@ -313,8 +342,7 @@ rtems_capture_monitor (bool enable);
* error. Otherwise, a status code is returned indicating the
* source of the error.
*/
-rtems_status_code
-rtems_capture_flush (bool prime);
+rtems_status_code rtems_capture_flush (bool prime);
/**
* @brief Capture add watch
@@ -331,8 +359,7 @@ rtems_capture_flush (bool prime);
* error. Otherwise, a status code is returned indicating the
* source of the error.
*/
-rtems_status_code
-rtems_capture_watch_add (rtems_name name, rtems_id id);
+rtems_status_code rtems_capture_watch_add (rtems_name name, rtems_id id);
/**
* @brief Capture delete watch.
@@ -348,8 +375,7 @@ rtems_capture_watch_add (rtems_name name, rtems_id id);
* error. Otherwise, a status code is returned indicating the
* source of the error.
*/
-rtems_status_code
-rtems_capture_watch_del (rtems_name name, rtems_id id);
+rtems_status_code rtems_capture_watch_del (rtems_name name, rtems_id id);
/**
* @brief Capture enable/disable watch.
@@ -365,10 +391,9 @@ rtems_capture_watch_del (rtems_name name, rtems_id id);
* error. Otherwise, a status code is returned indicating the
* source of the error.
*/
-rtems_status_code
-rtems_capture_watch_ctrl (rtems_name name,
- rtems_id id,
- bool enable);
+rtems_status_code rtems_capture_watch_ctrl (rtems_name name,
+ rtems_id id,
+ bool enable);
/**
* @brief Capture enable/disable global watch.
@@ -383,8 +408,7 @@ rtems_capture_watch_ctrl (rtems_name name,
* error. Otherwise, a status code is returned indicating the
* source of the error.
*/
-rtems_status_code
-rtems_capture_watch_global (bool enable);
+rtems_status_code rtems_capture_watch_global (bool enable);
/**
* @brief Get global watch state
@@ -394,8 +418,7 @@ rtems_capture_watch_global (bool enable);
* @retval This method returns true if the global watch
* is on. Otherwise, it returns false.
*/
-bool
-rtems_capture_watch_global_on (void);
+bool rtems_capture_watch_global_on (void);
/**
* @brief Set watch ceiling.
@@ -412,8 +435,7 @@ rtems_capture_watch_global_on (void);
* error. Otherwise, a status code is returned indicating the
* source of the error.
*/
-rtems_status_code
-rtems_capture_watch_ceiling (rtems_task_priority ceiling);
+rtems_status_code rtems_capture_watch_ceiling (rtems_task_priority ceiling);
/**
* @brief Get watch ceiling.
@@ -423,8 +445,7 @@ rtems_capture_watch_ceiling (rtems_task_priority ceiling);
* @retval The priority level immediately above that at which events
* from tasks are not captured.
*/
-rtems_task_priority
-rtems_capture_watch_get_ceiling (void);
+rtems_task_priority rtems_capture_watch_get_ceiling (void);
/**
* @brief Capture set watch floor.
@@ -441,8 +462,7 @@ rtems_capture_watch_get_ceiling (void);
* error. Otherwise, a status code is returned indicating the
* source of the error.
*/
-rtems_status_code
-rtems_capture_watch_floor (rtems_task_priority floor);
+rtems_status_code rtems_capture_watch_floor (rtems_task_priority floor);
/**
* @brief Capture set watch floor
@@ -452,8 +472,7 @@ rtems_capture_watch_floor (rtems_task_priority floor);
* @retval The priority level immediately below
* that at which events from tasks are not captured.
*/
-rtems_task_priority
-rtems_capture_watch_get_floor (void);
+rtems_task_priority rtems_capture_watch_get_floor (void);
/**
* @brief Capture set trigger
@@ -541,10 +560,9 @@ rtems_capture_clear_trigger (rtems_name from_name,
* error. Otherwise, a status code is returned indicating the
* source of the error.
*/
-rtems_status_code
-rtems_capture_read (uint32_t cpu,
- uint32_t* read,
- rtems_capture_record_t** recs);
+rtems_status_code rtems_capture_read (uint32_t cpu,
+ size_t* read,
+ const void** recs);
/**
* @brief Capture release records.
@@ -558,8 +576,7 @@ rtems_capture_read (uint32_t cpu,
* error. Otherwise, a status code is returned indicating the
* source of the error.
*/
-rtems_status_code
-rtems_capture_release (uint32_t cpu, uint32_t count);
+rtems_status_code rtems_capture_release (uint32_t cpu, uint32_t count);
/*
* @brief Capture nano-second time period.
@@ -568,8 +585,34 @@ rtems_capture_release (uint32_t cpu, uint32_t count);
*
* @param[out] uptime The nano-second time period.
*/
-void
-rtems_capture_time (rtems_capture_time_t* uptime);
+void rtems_capture_time (rtems_capture_time_t* uptime);
+
+/**
+ * @brief Capture filter
+ *
+ * This function this function specifies if the given task and events should be
+ * logged.
+ *
+ * @param[in] task specifies the capture task control block
+ * @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 should be logged.
+ */
+bool rtems_capture_filter (rtems_tcb* task, uint32_t events);
+
+/**
+ * @brief Capture returns the current time.
+ *
+ * This function returns the current time. If a handler is provided
+ * by the user the time is gotten from that.
+ *
+ * @param[in] time specifies the capture time
+ *
+ * @retval This method returns a nano-second time if no user handler
+ * is provided. Otherwise, it returns a resolution defined by the handler.
+ */
+void rtems_capture_get_time (rtems_capture_time_t* time);
/**
* @brief Capture get event text.
@@ -582,8 +625,7 @@ rtems_capture_time (rtems_capture_time_t* uptime);
*
* @retval This method returns a string description of the given event.
*/
-const char*
-rtems_capture_event_text (int event);
+const char* rtems_capture_event_text (int event);
/**
* @brief Capture initialize task
@@ -604,6 +646,92 @@ void rtems_capture_initialize_task( rtems_tcb* tcb );
void rtems_capture_record_task( rtems_tcb* tcb );
/**
+ * @brief Capture record lock.
+ *
+ * This does a lock acquire which will remain in effect until
+ * rtems_capture_record_unlock is called.
+ *
+ * @param[out] context specifies the record context
+ */
+void rtems_capture_record_lock (rtems_capture_record_lock_context* context);
+
+/**
+ * @brief Capture record unlock.
+ *
+ * This unlocks the record lock.
+ *
+ * @param[in] context specifies the record context
+ */
+void rtems_capture_record_unlock (rtems_capture_record_lock_context* context);
+
+/**
+ * @brief Capture record open.
+ *
+ * This function allocates a record and fills in the header information. It
+ * does a lock acquire which will remain in effect until
+ * rtems_capture_record_close is called. The size is the amount of user data
+ * being recorded. The record header is internally managed.
+ *
+ * @param[in] task specifies the caputre task block
+ * @param[in] events specifies the events
+ * @param[in] size specifies the user's capture data size
+ * @param[out] context specifies the record context
+ *
+ * @retval This method returns a pointer to the next location in
+ * the capture record to store data.
+ */
+void* rtems_capture_record_open (rtems_tcb* task,
+ uint32_t events,
+ size_t size,
+ rtems_capture_record_lock_context* context);
+
+/**
+ * @brief Capture record close.
+ *
+ * This function closes writing to capure record and releases the lock that was
+ * held on the per CPU buffer.
+ *
+ * @param[out] context specifies the record context
+ */
+void rtems_capture_record_close (rtems_capture_record_lock_context* context);
+
+/**
+ * @brief Capture append to record to the per CPU buffer.
+ *
+ * This function appends data of a specifed size into a capture buffer.
+ *
+ * @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_record_append (void* rec, const void* data, size_t size)
+{
+ memcpy (rec, data, size);
+ return ((uint8_t*) rec) + size;
+}
+
+/**
+ * @brief Capture read a record from the per CPU buffer.
+ *
+ * This function reads data of a specifed size from a capture buffer.
+ *
+ * @param[in] rec specifies the next read point in the capture record
+ * @param[in] data specifies where to write the data
+ * @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_record_extract (const void* rec, void* data, size_t size)
+{
+ memcpy (data, rec, size);
+ return ((uint8_t*) rec) + size;
+}
+
+/**
* @brief Capture task recorded
*
* This function returns true if this task information has been
@@ -643,6 +771,21 @@ rtems_capture_task_id (rtems_tcb* tcb)
}
/**
+ * @brief Capture get task API.
+ *
+ * This function returns the task API as an int.
+ *
+ * @param[in] task The capture task.
+ *
+ * @retval This function returns the task API as an int.
+ */
+static inline int
+rtems_capture_task_api (rtems_id id)
+{
+ return _Objects_Get_API (id);
+}
+
+/**
* @brief Capture get task state.
*
* This function returns the task state.
@@ -738,10 +881,8 @@ rtems_capture_task_control_flags (rtems_tcb* tcb)
static inline rtems_task_priority
rtems_capture_task_start_priority (rtems_tcb* tcb)
{
- return _RTEMS_Priority_From_core(
- _Scheduler_Get_own( tcb ),
- tcb->Start.initial_priority
- );
+ return _RTEMS_Priority_From_core (_Scheduler_Get_own( tcb ),
+ tcb->Start.initial_priority);
}
/**
diff --git a/cpukit/libmisc/capture/capture_buffer.c b/cpukit/libmisc/capture/capture_buffer.c
index 13e6d1b624..be812b0af6 100644
--- a/cpukit/libmisc/capture/capture_buffer.c
+++ b/cpukit/libmisc/capture/capture_buffer.c
@@ -26,92 +26,104 @@
#include <rtems/score/assert.h>
#include "capture_buffer.h"
-void * rtems_capture_buffer_allocate( rtems_capture_buffer_t* buffer, size_t size )
+void*
+rtems_capture_buffer_allocate (rtems_capture_buffer_t* buffer, size_t size)
{
- size_t end;
- void *ptr;
-
- if ( rtems_capture_buffer_is_full( buffer ) )
- return NULL;
-
- if ( (buffer->count + size) > buffer->end )
- return NULL;
-
- /*
- * Determine if the end of free space is marked with
- * the end of buffer space, or the head of allocated
- * space.
- *
- * |...|head| freespace |tail| ...| end
- *
- * tail|.....|head| freespace| end
- *
- */
- if (buffer->tail > buffer->head) {
- end = buffer->tail;
- } else {
- end = buffer->end;
- }
+ void* ptr = NULL;
+
+ if ((buffer->count + size) <= buffer->end)
+ {
+ size_t end;
+
+ /*
+ * Determine if the end of free space is marked with the end of buffer
+ * space, or the head of allocated space.
+ *
+ * |...|head| freespace |tail| ...| end
+ *
+ * tail|.....|head| freespace| end
+ */
+ if (buffer->tail > buffer->head)
+ {
+ end = buffer->tail;
+ } else
+ {
+ end = buffer->end;
+ }
- /*
- * Can we allocate it easily?
- */
- if ((buffer->head + size) <= end) {
- ptr = &buffer->buffer[ buffer->head ];
- buffer->head += size;
- buffer->count = buffer->count + size;
- return ptr;
+ /*
+ * Can we allocate it easily?
+ */
+ if ((buffer->head + size) <= end)
+ {
+ ptr = &buffer->buffer[buffer->head];
+ buffer->head += size;
+ buffer->count = buffer->count + size;
+ if (buffer->max_rec < size)
+ buffer->max_rec = size;
+ }
+ else
+ {
+ /*
+ * We have to consider wrapping around to the front of the buffer
+ *
+ * If there is no room at the end of the buffer and we have we already
+ * wrapped then we can't allocate and if there is room at the front of
+ * the buffer.
+ */
+ if ((end != buffer->tail) && (buffer->tail >= size))
+ {
+ /*
+ * Change the end pointer to the last used byte, so a read will wrap
+ * when out of data
+ */
+ buffer->end = buffer->head;
+
+ /*
+ * Now return the buffer
+ */
+ ptr = buffer->buffer;
+ buffer->head = size;
+ buffer->count = buffer->count + size;
+ if (buffer->max_rec < size)
+ buffer->max_rec = size;
+ }
+ }
}
- /*
- * We have to consider wrapping around to the front of the buffer
- */
-
- /* If there is not room at the end of the buffer */
- /* and we have we already wrapped then we can't allocate */
- if ( end == buffer->tail )
- return NULL;
-
- /* Is there no room at the front of the buffer */
- if ( (buffer->tail < size ))
- return NULL;
-
- /* change the end pointer to the last used byte, so a read will wrap when out of data */
- buffer->end = buffer->head;
-
- /* now return the buffer */
- ptr = buffer->buffer;
- buffer->head = size;
- buffer->count = buffer->count + size;
-
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)
{
- void *ptr;
- size_t next;
- size_t buff_size;
-
- if (size == 0)
- return NULL;
-
- ptr = rtems_capture_buffer_peek(buffer, &buff_size);
- next = buffer->tail + size;
+ void *ptr;
+ size_t next;
+ size_t buff_size;
- /* Check if we are freeing space past the end of the buffer */
- _Assert( ! rtems_capture_buffer_is_empty( buffer ) );
- _Assert( !((buffer->tail > buffer->head) && (next > buffer->end)) );
- _Assert( !((buffer->tail < buffer->head) && (next > buffer->head)) );
+ if (size == 0)
+ return NULL;
- buffer->count = buffer->count - size;
+ ptr = rtems_capture_buffer_peek (buffer, &buff_size);
+ next = buffer->tail + size;
- if (next == buffer->end) {
- buffer->end = buffer->size;
- buffer->tail = 0;
- } else {
- buffer->tail = next;
- }
+ /*
+ * Check if we are freeing space past the end of the buffer
+ */
+ _Assert (! rtems_capture_buffer_is_empty( buffer));
+ _Assert (!((buffer->tail > buffer->head) && (next > buffer->end)));
+ _Assert (!((buffer->tail < buffer->head) && (next > buffer->head)));
+
+ buffer->count = buffer->count - size;
+
+ if (next == buffer->end)
+ {
+ buffer->end = buffer->size;
+ buffer->tail = 0;
+ } else
+ {
+ buffer->tail = next;
+ }
- return ptr;
+ return ptr;
}
diff --git a/cpukit/libmisc/capture/capture_buffer.h b/cpukit/libmisc/capture/capture_buffer.h
index 2b90b0abc2..7f21f4709e 100644
--- a/cpukit/libmisc/capture/capture_buffer.h
+++ b/cpukit/libmisc/capture/capture_buffer.h
@@ -12,6 +12,9 @@
COPYRIGHT (c) 2014.
On-Line Applications Research Corporation (OAR).
+ Copyright 2016 Chris Johns <chrisj@rtems.org>.
+ All rights reserved.
+
The license and distribution terms for this file may be
found in the file LICENSE in this distribution.
@@ -20,83 +23,95 @@
------------------------------------------------------------------------
*/
-#ifndef __CAPTUREBUFFER_H_
-#define __CAPTUREBUFFER_H_
+#ifndef __CAPTURE_BUFFER_H_
+#define __CAPTURE_BUFFER_H_
#include <stdlib.h>
-
/**@{*/
#ifdef __cplusplus
extern "C" {
#endif
+/**
+ * Capture buffer. There is one per CPU.
+ */
typedef struct {
- uint8_t *buffer;
- size_t size;
- size_t count;
- size_t head;
- size_t tail;
- size_t end;
+ uint8_t* buffer; /**< The per cpu buffer. */
+ size_t size; /**< The size of the buffer in bytes. */
+ size_t count; /**< The number of used bytes in the buffer. */
+ size_t head; /**< First record. */
+ size_t tail; /**< Head == Tail for empty. */
+ size_t end; /**< Buffer current end, it may move in. */
+ size_t max_rec; /**< The largest record in the buffer. */
} rtems_capture_buffer_t;
-static inline void rtems_capture_buffer_flush( rtems_capture_buffer_t* buffer )
+static inline void
+rtems_capture_buffer_flush (rtems_capture_buffer_t* buffer)
{
buffer->end = buffer->size;
buffer->head = buffer->tail = 0;
buffer->count = 0;
+ buffer->max_rec = 0;
}
-static inline void rtems_capture_buffer_create( rtems_capture_buffer_t* buffer, size_t size )
+static inline void
+rtems_capture_buffer_create (rtems_capture_buffer_t* buffer, size_t size)
{
buffer->buffer = malloc(size);
buffer->size = size;
- rtems_capture_buffer_flush( buffer );
+ rtems_capture_buffer_flush (buffer);
}
-static inline void rtems_capture_buffer_destroy( rtems_capture_buffer_t* buffer )
+static inline void
+rtems_capture_buffer_destroy (rtems_capture_buffer_t* buffer)
{
- rtems_capture_buffer_flush( buffer );
- free( buffer->buffer);
+ rtems_capture_buffer_flush (buffer);
+ free (buffer->buffer);
buffer->buffer = NULL;
}
-static inline bool rtems_capture_buffer_is_empty( rtems_capture_buffer_t* buffer )
+static inline bool
+rtems_capture_buffer_is_empty (rtems_capture_buffer_t* buffer)
{
- return( buffer->count == 0 );
+ return buffer->count == 0;
}
-static inline bool rtems_capture_buffer_is_full( rtems_capture_buffer_t* buffer )
+static inline bool
+rtems_capture_buffer_is_full (rtems_capture_buffer_t* buffer)
{
- return (buffer->count == buffer->size);
+ return buffer->count == buffer->size;
}
-static inline bool rtems_capture_buffer_has_wrapped( rtems_capture_buffer_t* buffer )
+static inline bool
+rtems_capture_buffer_has_wrapped (rtems_capture_buffer_t* buffer)
{
- if ( buffer->tail > buffer->head)
+ if (buffer->tail > buffer->head)
return true;
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)) {
+ if (rtems_capture_buffer_is_empty (buffer))
+ {
*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;
- return &buffer->buffer[ buffer->tail ];
+ return &buffer->buffer[buffer->tail];
}
-void *rtems_capture_buffer_allocate( rtems_capture_buffer_t* buffer, size_t size );
+void* rtems_capture_buffer_allocate (rtems_capture_buffer_t* buffer, size_t size);
-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);
#ifdef __cplusplus
}
diff --git a/cpukit/libmisc/capture/capture_support.c b/cpukit/libmisc/capture/capture_support.c
index f531666463..6e84c2b2d2 100644
--- a/cpukit/libmisc/capture/capture_support.c
+++ b/cpukit/libmisc/capture/capture_support.c
@@ -39,14 +39,128 @@
* 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;
+typedef struct
+{
+ const void* recs; /**< Next record to be read. */
+ size_t read; /**< Number of records read. */
+ size_t printed; /**< Records been printed. */
+ bool rec_valid; /**< The record is valid. */
+ rtems_capture_record_t rec; /**< The record, copied out. */
} ctrace_per_cpu_t;
/*
+ * Task block size.
+ */
+#define CTRACE_TASK_BLOCK_SIZE (64)
+
+/**
+ * Task details from the task records used to print task names.
+ */
+typedef struct
+{
+ rtems_name name;
+ rtems_id id;
+} ctrace_task_name;
+
+/**
+ * Structure to hold the tasks variables.
+ */
+typedef struct
+{
+ ctrace_task_name* tasks;
+ size_t size;
+ size_t count;
+} ctrace_tasks;
+
+/*
+ * Global so the records can span more than one trace.
+ */
+static ctrace_tasks tasks;
+
+/*
+ * Add a name.
+ */
+static void
+ctrace_task_name_add (rtems_id id, const rtems_name* name)
+{
+ if (tasks.tasks == NULL)
+ {
+ tasks.size = CTRACE_TASK_BLOCK_SIZE;
+ tasks.tasks = calloc (tasks.size, sizeof (ctrace_task_name));
+ }
+ if (tasks.tasks != NULL)
+ {
+ if (rtems_object_id_get_api(id) != OBJECTS_POSIX_API)
+ {
+ size_t t;
+ for (t = 0; t < tasks.count; ++t)
+ {
+ if (tasks.tasks[t].id == id)
+ {
+ tasks.tasks[t].name = *name;
+ break;
+ }
+ }
+ if (t == tasks.count)
+ {
+ if (tasks.count >= tasks.size)
+ {
+ tasks.size += CTRACE_TASK_BLOCK_SIZE;
+ tasks.tasks = realloc (tasks.tasks,
+ tasks.size * sizeof (ctrace_task_name));
+ }
+ if (tasks.tasks != NULL)
+ {
+ tasks.tasks[tasks.count].name = *name;
+ tasks.tasks[tasks.count].id = id;
+ ++tasks.count;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Remove a task name.
+ */
+static void
+ctrace_task_name_remove (rtems_id id)
+{
+ size_t t;
+ for (t = 0; t < tasks.count; ++t)
+ {
+ if (tasks.tasks[t].id == id)
+ {
+ size_t count = tasks.count - t - 1;
+ if (count != 0)
+ memmove (&tasks.tasks[t],
+ &tasks.tasks[t + 1],
+ sizeof (ctrace_task_name) * count);
+ --tasks.count;
+ break;
+ }
+ }
+}
+
+/*
+ * Find a name.
+ */
+static void
+ctrace_task_name_find (rtems_id id, const rtems_name** name)
+{
+ size_t t;
+ *name = NULL;
+ for (t = 0; t < tasks.count; ++t)
+ {
+ if (tasks.tasks[t].id == id)
+ {
+ *name = &tasks.tasks[t].name;
+ break;
+ }
+ }
+}
+
+/*
* rtems_catpure_print_uptime
*
* This function prints the nanosecond uptime to stdout.
@@ -72,11 +186,11 @@ rtems_capture_print_timestamp (uint64_t uptime)
}
void
-rtems_capture_print_record_task( uint32_t cpu, rtems_capture_record_t* rec)
+rtems_capture_print_record_task (int cpu,
+ const rtems_capture_record_t* rec,
+ const rtems_capture_task_record_t* task_rec)
{
- rtems_capture_task_record_t* task_rec = (rtems_capture_task_record_t*) rec;
-
- fprintf(stdout,"%2" PRId32 " ", cpu);
+ fprintf(stdout,"%2i ", cpu);
rtems_capture_print_timestamp (rec->time);
fprintf (stdout, " ");
rtems_monitor_dump_id (rec->task_id);
@@ -101,24 +215,36 @@ rtems_capture_print_record_task( uint32_t cpu, rtems_capture_record_t* rec)
}
void
-rtems_capture_print_record_capture(
- uint32_t cpu,
- rtems_capture_record_t* rec,
- uint64_t diff
-){
- uint32_t event;
- int e;
+rtems_capture_print_record_capture(int cpu,
+ const rtems_capture_record_t* rec,
+ uint64_t diff,
+ const rtems_name* name)
+{
+ 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);
+ fprintf(stdout,"%2i ", cpu);
rtems_capture_print_timestamp (rec->time);
fprintf (stdout, " %12" PRId32 " ", (uint32_t) diff);
rtems_monitor_dump_id (rec->task_id);
- fprintf(stdout, " %3" PRId32 " %3" PRId32 " %s\n",
+ if (name != NULL)
+ {
+ fprintf (stdout, " %c%c%c%c",
+ (char) (*name >> 24) & 0xff,
+ (char) (*name >> 16) & 0xff,
+ (char) (*name >> 8) & 0xff,
+ (char) (*name >> 0) & 0xff);
+ }
+ else
+ {
+ fprintf(stdout, " ");
+ }
+ 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));
@@ -134,46 +260,65 @@ rtems_capture_print_record_capture(
*/
void
-rtems_capture_print_trace_records ( int total, bool csv )
+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;
+ ctrace_per_cpu_t* per_cpu;
+ ctrace_per_cpu_t* cpu;
+ int cpus;
+ rtems_capture_time_t last_time = 0;
+ int i;
+
+ cpus = rtems_get_processor_count ();
- count = rtems_get_processor_count();
- per_cpu = calloc( count, sizeof(*per_cpu) );
+ per_cpu = calloc (cpus, sizeof(*per_cpu));
+ if (per_cpu == NULL)
+ {
+ fprintf(stdout, "error: no memory\n");
+ return;
+ }
while (total)
{
+ const rtems_capture_record_t* rec_out = NULL;
+ int cpu_out = -1;
+ rtems_capture_time_t this_time = 0;
+
/* 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);
+ for (i = 0; i < cpus; i++) {
+ cpu = &per_cpu[i];
+
+ if (cpu->read == 0)
+ {
+ rtems_status_code sc;
+ sc = rtems_capture_read (i, &cpu->read, &cpu->recs);
if (sc != RTEMS_SUCCESSFUL)
{
- fprintf (stdout, "error: trace read failed: %s\n", rtems_status_text (sc));
+ fprintf (stdout,
+ "error: trace read failed: %s\n", rtems_status_text (sc));
rtems_capture_flush (0);
- free( per_cpu );
+ free (per_cpu);
return;
}
/* Release the buffer if there are no records to read */
- if (per_cpu[i].read == 0)
+ if (cpu->read == 0)
rtems_capture_release (i, 0);
}
- }
- /* Find the next record to print */
- rec_out = NULL;
- for (i=0; i< count; i++) {
+ /* Read the record out from the capture buffer */
+ if (!cpu->rec_valid && (cpu->read != 0))
+ {
+ cpu->recs = rtems_capture_record_extract (cpu->recs,
+ &cpu->rec,
+ sizeof (cpu->rec));
+ cpu->rec_valid = true;
+ }
- 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;
+ /* Find the next record to print, the earliest recond on any core */
+ if ((cpu->rec_valid) && ((this_time == 0) || (cpu->rec.time < this_time)))
+ {
+ rec_out = &cpu->rec;
+ cpu_out = i;
+ this_time = rec_out->time;
}
}
@@ -181,65 +326,81 @@ rtems_capture_print_trace_records ( int total, bool csv )
if (rec_out == NULL)
break;
+ cpu = &per_cpu[cpu_out];
+
/* Print the record */
- if (csv) {
- fprintf(
- stdout,
- "%03" PRIu32 ",%08" PRIu32 ",%03" PRIu32
- ",%03" PRIu32 ",%04" PRIx32 ",%" PRId64 "\n",
- cpu,
- (uint32_t) 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 (csv)
+ {
+ fprintf(stdout,
+ "%03i,%08" PRIu32 ",%03" PRIu32
+ ",%03" PRIu32 ",%04" PRIx32 ",%" PRId64 "\n",
+ cpu_out,
+ (uint32_t) 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;
- if (per_cpu[cpu].last_t != 0)
- diff = rec_out->time - per_cpu[cpu].last_t;
+ {
+ rtems_capture_task_record_t task_rec;
+ cpu->recs = rtems_capture_record_extract (cpu->recs,
+ &task_rec,
+ sizeof (task_rec));
+ ctrace_task_name_add (rec_out->task_id, &task_rec.name);
+ rtems_capture_print_record_task (cpu_out, rec_out, &task_rec);
+ }
+ else
+ {
+ rtems_capture_time_t diff;
+ const rtems_name* name = NULL;
+ if (last_time != 0)
+ diff = rec_out->time - last_time;
else
diff = 0;
- per_cpu[cpu].last_t = rec_out->time;
-
- rtems_capture_print_record_capture( cpu, rec_out, diff );
+ last_time = rec_out->time;
+ ctrace_task_name_find (rec_out->task_id, &name);
+ rtems_capture_print_record_capture (cpu_out, rec_out, diff, name);
+ if ((rec_out->events &
+ (RTEMS_CAPTURE_DELETED_BY_EVENT | RTEMS_CAPTURE_DELETED_EVENT)) != 0)
+ ctrace_task_name_remove (rec_out->task_id);
}
}
/*
- * If we have not printed all the records read
- * increment to the next record. If we have
- * printed all records release the records printed.
+ * 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;
+ cpu->rec_valid = false;
+ ++cpu->printed;
+ if (cpu->printed == cpu->read)
+ {
+ rtems_capture_release (cpu_out, cpu->printed);
+ cpu->recs = NULL;
+ cpu->read = 0;
+ cpu->printed = 0;
}
- total --;
+ --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 );
+ for (i = 0; i < cpus; i++)
+ {
+ cpu = &per_cpu[i];
+ if (cpu->read != 0)
+ {
+ rtems_capture_release (i, cpu->printed);
}
}
- free( per_cpu );
+ free(per_cpu);
}
void
-rtems_capture_print_watch_list ()
+rtems_capture_print_watch_list (void)
{
rtems_capture_control_t* control = rtems_capture_get_control_list ();
rtems_task_priority ceiling = rtems_capture_watch_get_ceiling ();
diff --git a/cpukit/libmisc/capture/capture_user_extension.c b/cpukit/libmisc/capture/capture_user_extension.c
index 37372cbe1e..6e42fd7c87 100644
--- a/cpukit/libmisc/capture/capture_user_extension.c
+++ b/cpukit/libmisc/capture/capture_user_extension.c
@@ -1,9 +1,7 @@
/*
------------------------------------------------------------------------
- Copyright Objective Design Systems Pty Ltd, 2002
- All rights reserved Objective Design Systems Pty Ltd, 2002
- Chris Johns (ccj@acm.org)
+ Copyright 2002, 2016 Chris Johns <chrisj@rtems.org>. All rights reserved.
COPYRIGHT (c) 1989-2014.
On-Line Applications Research Corporation (OAR).
@@ -37,7 +35,7 @@
/*
* RTEMS Capture User Extension Data.
*/
-static rtems_id capture_id;
+static rtems_id capture_id;
static bool
rtems_capture_create_task (rtems_tcb* current_task,
@@ -80,23 +78,18 @@ static const rtems_extensions_table capture_extensions = {
.thread_terminate = rtems_capture_terminated_task
};
-static inline void rtems_capture_record (
- rtems_tcb* tcb,
- uint32_t events
-)
+static inline void rtems_capture_record (rtems_tcb* tcb, uint32_t events)
{
- rtems_capture_record_t* rec;
- void* ptr;
- size_t size = sizeof(*rec);
+ rtems_capture_record_lock_context rec_context;
- if (rtems_capture_filter( tcb, events) )
+ if (rtems_capture_filter (tcb, events))
return;
if (!rtems_capture_task_recorded (tcb))
rtems_capture_record_task (tcb);
- rtems_capture_begin_add_record (tcb, events, size, &ptr);
- rtems_capture_end_add_record ( ptr );
+ rtems_capture_record_open (tcb, events, 0, &rec_context);
+ rtems_capture_record_close (&rec_context);
}
@@ -115,7 +108,7 @@ rtems_status_code rtems_capture_user_extension_open(void)
capture_id = 0;
else {
index = rtems_object_id_get_index (capture_id);
- rtems_capture_set_extension_index( index );
+ rtems_capture_set_extension_index (index);
}
return sc;
diff --git a/cpukit/libmisc/capture/captureimpl.h b/cpukit/libmisc/capture/captureimpl.h
index 753e41b5c5..78fd83ef34 100644
--- a/cpukit/libmisc/capture/captureimpl.h
+++ b/cpukit/libmisc/capture/captureimpl.h
@@ -10,9 +10,8 @@
/*
------------------------------------------------------------------------
- Copyright Objective Design Systems Pty Ltd, 2002
- All rights reserved Objective Design Systems Pty Ltd, 2002
- Chris Johns (ccj@acm.org)
+ Copyright 2002, 2016 Chris Johns <chrisj@rtems.org>.
+ All rights reserved.
COPYRIGHT (c) 1989-2014.
On-Line Applications Research Corporation (OAR).
@@ -32,31 +31,13 @@
#ifndef __CAPTUREIMPL_H_
#define __CAPTUREIMPL_H_
+#include "capture.h"
/**@{*/
#ifdef __cplusplus
extern "C" {
#endif
-#include "capture.h"
-
-/*
- * Global capture flags.
- */
-#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_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.
*
@@ -138,140 +119,6 @@ bool rtems_capture_trigger (rtems_tcb* ft,
uint32_t events);
/**
- * @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
- * rtems_capture_end_add_record.
- *
- * @param[in] rec specifies the next location to write in the record
- * @param[in] data specifies the data to write
- * @param[in] size specifies specifies the size of the data
- *
- * @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
- * rtems_capture_end_add_record.
- */
-static void *rtems_capture_append_to_record(void* rec,
- void* data,
- size_t size );
-
-/**
- * @brief Capture filter
- *
- * This function this function specifies if the given task
- * and events should be logged.
- *
- * @param[in] task specifies the capture task control block
- * @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
- * should be logged.
- */
-bool rtems_capture_filter( rtems_tcb* task,
- uint32_t events);
-/**
- * @brief Capture begin add record.
- *
- * This function opens a record for writing and inserts
- * the header information
- *
- * @param[in] _task specifies the capture task block
- * @param[in] _events specifies the events
- * @param[in] _size specifies the expected size of the capture record
- * @param[out] _rec specifies the next write point in the capture record
- */
-#define rtems_capture_begin_add_record( _task, _events, _size, _rec) \
- do { \
- rtems_capture_record_context_t _context; \
- *_rec = rtems_capture_record_open( _task, _events, _size, &_context );
-
-/**
- * @brief Capture append to record.
- *
- * 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] 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,
- void* data,
- size_t size )
-{
- uint8_t *ptr = rec;
- memcpy( ptr, data, size );
- return (ptr + size);
-}
-
-/**
- * @brief Capture end add record.
- *
- * This function completes the add capture record process
- *
- * @param[in] _rec specifies the end of the capture record
- */
-#define rtems_capture_end_add_record( _rec ) \
- rtems_capture_record_close( _rec, &_context ); \
- } while (0)
-
-/**
- * @brief Capture returns the current time.
- *
- * This function returns the current time. If a handler is provided
- * by the user the time is gotten from that.
- *
- * @param[in] time specifies the capture time
- *
- * @retval This method returns a nano-second time if no user handler
- * is provided. Otherwise, it returns a resolution defined by the handler.
- */
-void rtems_capture_get_time (rtems_capture_time_t* time);
-
-typedef struct {
- rtems_interrupt_lock_context lock_context;
- rtems_interrupt_lock *lock;
-} rtems_capture_record_context_t;
-
-/**
- * @brief Capture record open.
- *
- * This function allocates a record and fills in the
- * header information. It does a lock acquire
- * which will remain in effect until
- * rtems_capture_record_close is called. This method
- * should only be used by rtems_capture_begin_add_record.
- *
- * @param[in] task specifies the caputre task block
- * @param[in] events specifies the events
- * @param[in] size specifies capture record size
- * @param[out] context specifies the record context
- *
- * @retval This method returns a pointer to the next location in
- * the capture record to store data.
- */
-void* rtems_capture_record_open (rtems_tcb* task,
- uint32_t events,
- size_t size,
- rtems_capture_record_context_t* context);
-/**
- * @brief Capture record close.
- *
- * 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.
- *
- * @param[in] rec specifies the record
- * @param[out] context specifies the record context
- */
-void rtems_capture_record_close( void *rec, rtems_capture_record_context_t* context);
-
-
-/**
* @brief Capture print trace records.
*
* This function reads, prints and releases up to
@@ -302,10 +149,9 @@ void rtems_capture_print_timestamp (uint64_t uptime);
* @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
-);
+void rtems_capture_print_record_task(int cpu,
+ const rtems_capture_record_t* rec,
+ const rtems_capture_task_record_t* task_rec);
/**
* @brief Capture print capture record.
@@ -316,19 +162,20 @@ void rtems_capture_print_record_task(
* @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.
+ * @param[in] name specifies the name of the task, NULL if none.
+ * @param[in] task_count number of tasks to search for.
*/
-void rtems_capture_print_record_capture(
- uint32_t cpu,
- rtems_capture_record_t* rec,
- uint64_t diff
-);
+void rtems_capture_print_record_capture(int cpu,
+ const rtems_capture_record_t* rec,
+ uint64_t diff,
+ const rtems_name* name);
/**
* @brief Capture print watch list
*
* This function prints a capture watch list
*/
-void rtems_capture_print_watch_list( void );
+void rtems_capture_print_watch_list (void);
#ifdef __cplusplus
}
diff --git a/testsuites/smptests/smpcapture02/init.c b/testsuites/smptests/smpcapture02/init.c
index 787b7f339f..6806238336 100644
--- a/testsuites/smptests/smpcapture02/init.c
+++ b/testsuites/smptests/smpcapture02/init.c
@@ -15,6 +15,8 @@
*
*/
+/* #define VERBOSE 1 */
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -50,43 +52,42 @@ static rtems_id finished_sem;
static task_data_t task_data[ TASKS_PER_CPU * TASKS_PER_CPU ];
static rtems_interrupt_handler org_clock_handler;
-enum cap_rec_types {
+typedef enum {
enter_add_number,
exit_add_number,
clock_tick
-};
+} cap_rec_type;
/*
* These records define the data stored in the capture trace.
- * The records must be 64-bit aligned to make sure that the time
- * attribute in rtems_capture_record_t is correctly aligned.
+ * The records must be packed so alignment issues are not a factor.
*/
typedef struct {
- enum cap_rec_types id;
uint32_t a;
uint32_t b;
-} __attribute__ ((aligned (8))) enter_add_number_record_t;
+} RTEMS_PACKED enter_add_number_record_t;
typedef struct {
- enum cap_rec_types id;
uint32_t res;
-} __attribute__ ((aligned (8))) exit_add_number_record_t;
+} RTEMS_PACKED exit_add_number_record_t;
typedef struct {
- enum cap_rec_types id;
void *arg;
-} __attribute__ ((aligned (8))) clock_tick_record_t;
+} RTEMS_PACKED clock_tick_record_t;
-typedef struct {
- enum cap_rec_types id;
-} empty_record_t ;
+/*
+ * Create a printable set of char's from a name.
+ */
+#define PNAME(n) \
+ (char) (n >> 24) & 0xff, (char) (n >> 16) & 0xff, \
+ (char) (n >> 8) & 0xff, (char) (n >> 0) & 0xff
/*
* The function that we want to trace
*/
static uint32_t add_number(uint32_t a, uint32_t b)
{
- return a+b;
+ return a + b;
}
/*
@@ -95,31 +96,43 @@ static uint32_t add_number(uint32_t a, uint32_t b)
*/
static uint32_t add_number_wrapper(uint32_t a, uint32_t b)
{
+ rtems_capture_record_lock_context lock;
enter_add_number_record_t enter_rec;
exit_add_number_record_t exit_rec;
+ cap_rec_type id;
uint32_t res;
void* rec;
- enter_rec.id = enter_add_number;
+ id = enter_add_number;
enter_rec.a = a;
enter_rec.b = b;
- rtems_capture_begin_add_record(_Thread_Get_executing(),
- RTEMS_CAPTURE_TIMESTAMP, sizeof(rtems_capture_record_t)+
- sizeof(enter_add_number_record_t), &rec);
- rec = rtems_capture_append_to_record(rec, &enter_rec, sizeof(enter_rec));
- rtems_capture_end_add_record(rec);
+ rec = rtems_capture_record_open(_Thread_Get_executing(),
+ RTEMS_CAPTURE_TIMESTAMP,
+ sizeof(id) + sizeof(enter_rec),
+ &lock);
+ rtems_test_assert(rec != NULL);
+ rec = rtems_capture_record_append(rec, &id, sizeof(id));
+ rtems_test_assert(rec != NULL);
+ rec = rtems_capture_record_append(rec, &enter_rec, sizeof(enter_rec));
+ rtems_test_assert(rec != NULL);
+ rtems_capture_record_close(&lock);
res = add_number(a, b);
- exit_rec.id = exit_add_number;
+ id = exit_add_number;
exit_rec.res = res;
- rtems_capture_begin_add_record(_Thread_Get_executing(),
- RTEMS_CAPTURE_TIMESTAMP, sizeof(rtems_capture_record_t)+
- sizeof(exit_add_number_record_t), &rec);
- rec = rtems_capture_append_to_record(rec, &exit_rec, sizeof(exit_rec));
- rtems_capture_end_add_record(rec);
+ rec = rtems_capture_record_open(_Thread_Get_executing(),
+ RTEMS_CAPTURE_TIMESTAMP,
+ sizeof(id) + sizeof(exit_rec),
+ &lock);
+ rtems_test_assert(rec != NULL);
+ rec = rtems_capture_record_append(rec, &id, sizeof(id));
+ rtems_test_assert(rec != NULL);
+ rec = rtems_capture_record_append(rec, &exit_rec, sizeof(exit_rec));
+ rtems_test_assert(rec != NULL);
+ rtems_capture_record_close(&lock);
return res;
}
@@ -228,15 +241,19 @@ static void test(uint32_t cpu_count)
/* Writes an entry in the capture trace for every clock tick */
static void clock_tick_wrapper(void *arg)
{
- void* rec;
- clock_tick_record_t clock_tick_record = {.id = clock_tick};
+ rtems_capture_record_lock_context lock;
+ cap_rec_type id = clock_tick;
Thread_Control* tcb = _Thread_Get_executing();
+ void* rec;
- rtems_capture_begin_add_record(tcb, RTEMS_CAPTURE_TIMESTAMP,
- sizeof(rtems_capture_record_t) + sizeof(clock_tick_record_t), &rec);
- rec = rtems_capture_append_to_record(rec, &clock_tick_record,
- sizeof(clock_tick_record));
- rtems_capture_end_add_record(rec);
+ rec = rtems_capture_record_open(tcb,
+ RTEMS_CAPTURE_TIMESTAMP,
+ sizeof(id),
+ &lock);
+ rtems_test_assert(rec != NULL);
+ rec = rtems_capture_record_append(rec, &id, sizeof(id));
+ rtems_test_assert(rec != NULL);
+ rtems_capture_record_close(&lock);
org_clock_handler(arg);
}
@@ -263,20 +280,24 @@ static void Init(rtems_task_argument arg)
uint32_t i;
uint32_t cpu;
uint32_t cpu_count;
- uint32_t read;
uint32_t enter_count;
uint32_t exit_count;
uint32_t clock_tick_count;
uint32_t res_should_be;
- rtems_name name;
- rtems_capture_record_t *recs;
- rtems_capture_record_t *prev_rec;
- empty_record_t *record;
- enter_add_number_record_t *enter_add_number_rec;
- exit_add_number_record_t *exit_add_number_rec;
rtems_vector_number vec;
+ size_t read;
+ const void *recs;
+ cap_rec_type id;
+ rtems_capture_record_t rec;
+ rtems_capture_record_t prev_rec;
+ enter_add_number_record_t enter_rec;
+ exit_add_number_record_t exit_rec;
clock_interrupt_handler cih = {.found = 0};
+#ifdef VERBOSE
+ rtems_name name;
+#endif
+
TEST_BEGIN();
/* Get the number of processors that we are using. */
@@ -325,63 +346,64 @@ static void Init(rtems_task_argument arg)
for ( cpu = 0; cpu < cpu_count; cpu++ ) {
sc = rtems_capture_read(cpu, &read, &recs);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+ rtems_test_assert(recs != NULL);
- prev_rec = recs;
+ memset(&rec, 0, sizeof(rec));
+ prev_rec = rec;
enter_count = 0;
exit_count = 0;
res_should_be = 0;
for ( i = 0; i < read; i++ ) {
+ recs = rtems_capture_record_extract(recs, &rec, sizeof(rec));
+ rtems_test_assert(recs != NULL);
+
/* Verify that time goes forward */
- rtems_test_assert(recs->time>=prev_rec->time);
+ rtems_test_assert(rec.time >= prev_rec.time);
- if ( recs->events & RTEMS_CAPTURE_TIMESTAMP ) {
- record = (empty_record_t*)((char*) recs +
- sizeof(rtems_capture_record_t));
+ if ((rec.events & RTEMS_CAPTURE_TIMESTAMP) != 0) {
+ recs = rtems_capture_record_extract(recs, &id, sizeof(id));
+ rtems_test_assert(recs != NULL);
- switch ( record->id ) {
+ switch (id) {
case enter_add_number:
- rtems_test_assert(enter_count==exit_count);
+ rtems_test_assert(enter_count == exit_count);
enter_count++;
- enter_add_number_rec = (enter_add_number_record_t*)record;
- res_should_be = add_number(enter_add_number_rec->a,
- enter_add_number_rec->b);
- rtems_object_get_classic_name(recs->task_id, &name);
-
+ recs = rtems_capture_record_extract(recs,
+ &enter_rec,
+ sizeof(enter_rec));
+ rtems_test_assert(recs != NULL);
+ res_should_be = add_number(enter_rec.a, enter_rec.b);
#ifdef VERBOSE
/* Print record */
- printf("Time: %"PRIu64"us Task: %4s => Add %"PRIu32" and"
- " %"PRIu32"\n",
- recs->time/1000,
- (char*)&name,
- enter_add_number_rec->a,
- enter_add_number_rec->b);
+ rtems_object_get_classic_name(rec.task_id, &name);
+ printf("Time: %"PRIu64"us Task: %c%c%c%c => Add %"PRIu32" and %"PRIu32" is %"PRIu32"\n",
+ rec.time / 1000, PNAME(name), enter_rec.a, enter_rec.b, res_should_be);
#endif
break;
case exit_add_number:
- rtems_test_assert(enter_count==exit_count+1);
+ rtems_test_assert(enter_count == exit_count+1);
exit_count++;
- exit_add_number_rec = (exit_add_number_record_t*)record;
- /* Verify that the result matches the expected result */
- rtems_test_assert(res_should_be == exit_add_number_rec->res);
-
+ recs = rtems_capture_record_extract(recs,
+ &exit_rec,
+ sizeof(exit_rec));
+ rtems_test_assert(recs != NULL);
#ifdef VERBOSE
/* Print record */
- rtems_object_get_classic_name(recs->task_id, &name);
- printf("Time: %"PRIu64"us Task: %4s => Result is %"PRIu32"\n",
- recs->time/1000,
- (char*)&name,
- exit_add_number_rec->res);
+ rtems_object_get_classic_name(rec.task_id, &name);
+ printf("Time: %"PRIu64"us Task: %c%c%c%c => Result is %"PRIu32"\n",
+ rec.time / 1000, PNAME(name), exit_rec.res);
#endif
+ /* Verify that the result matches the expected result */
+ rtems_test_assert(res_should_be == exit_rec.res);
break;
case clock_tick:
clock_tick_count++;
#ifdef VERBOSE
- rtems_object_get_classic_name(recs->task_id, &name);
- printf("Time: %"PRIu64"us Task: %4s => Clock tick\n",
- recs->time/1000,
- (char*)&name);
+ rtems_object_get_classic_name(rec.task_id, &name);
+ printf("Time: %"PRIu64"us Task: %c%c%c%c => Clock tick\n",
+ rec.time/1000, PNAME(name));
#endif
break;
default:
@@ -389,8 +411,7 @@ static void Init(rtems_task_argument arg)
}
}
- prev_rec = recs;
- recs = (rtems_capture_record_t*) ((char*) recs + recs->size);
+ prev_rec = rec;
}
rtems_test_assert(enter_count == exit_count);
@@ -399,9 +420,6 @@ static void Init(rtems_task_argument arg)
rtems_capture_release(cpu, read);
}
- if( cih.found )
- rtems_test_assert(clock_tick_count == cpu_count * CLOCK_TICKS);
-
TEST_END();
rtems_test_exit(0);
}