summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2016-08-30 16:46:25 +1000
committerChris Johns <chrisj@rtems.org>2016-09-01 11:11:22 +1000
commit6da06c559f17f33177f59c0f83164bb2d20c8b9f (patch)
tree9f4b23a8f6e5215489ffbb8219c85fd11aa08e6c
parentcaf2cbd81331b3368db97006a922556c59b09061 (diff)
downloadrtems-6da06c559f17f33177f59c0f83164bb2d20c8b9f.tar.bz2
libmisc/capture: Fix the capture engine on SMP.
This patches some issues with the capture engine: 1. Check is the engine is open in ctrace commands. 2. Check all record open and appends for overflow. 3. Fix the record open to take the size of user data and not the record header. 4. Use packed structs for data being written to the per cpu buffers. 5. Remove direct struct access to the capture buffers to avoid misaligned accesses. 6. Add support to extract records, no struct access to the capture buffers. 7. Update ctrace to extract records from the capture buffers. 8. Add support to ctrace to always print the task name if it has one. 9. Add support to manage names or the lack of a name. 10. Range of minor fixes. 11. Fix a long standing bug in ctset's handling of args. Closes #2780.
-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);
}