diff options
-rw-r--r-- | cpukit/libmisc/capture/capture-cli.c | 51 | ||||
-rw-r--r-- | cpukit/libmisc/capture/capture-cli.h | 5 | ||||
-rw-r--r-- | cpukit/libmisc/capture/capture.c | 475 | ||||
-rw-r--r-- | cpukit/libmisc/capture/capture.h | 257 | ||||
-rw-r--r-- | cpukit/libmisc/capture/capture_buffer.c | 164 | ||||
-rw-r--r-- | cpukit/libmisc/capture/capture_buffer.h | 69 | ||||
-rw-r--r-- | cpukit/libmisc/capture/capture_support.c | 323 | ||||
-rw-r--r-- | cpukit/libmisc/capture/capture_user_extension.c | 23 | ||||
-rw-r--r-- | cpukit/libmisc/capture/captureimpl.h | 179 | ||||
-rw-r--r-- | testsuites/smptests/smpcapture02/init.c | 172 |
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); } |