summaryrefslogtreecommitdiffstats
path: root/cpukit/libmisc/capture
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libmisc/capture')
-rw-r--r--cpukit/libmisc/capture/README255
-rw-r--r--cpukit/libmisc/capture/capture-cli.c1622
-rw-r--r--cpukit/libmisc/capture/capture-cli.h56
-rw-r--r--cpukit/libmisc/capture/capture.c1938
-rw-r--r--cpukit/libmisc/capture/capture.h1042
5 files changed, 4913 insertions, 0 deletions
diff --git a/cpukit/libmisc/capture/README b/cpukit/libmisc/capture/README
new file mode 100644
index 0000000000..d12b5570d6
--- /dev/null
+++ b/cpukit/libmisc/capture/README
@@ -0,0 +1,255 @@
+#
+# $Id$
+#
+
+ RTEMS Performance Monitoring and Measurement Framework
+
+ Copyright 2002-2007 Chris Johns (chrisj@rtems.org)
+ 23 April 2002
+
+This directory contains the source code for the performance monitoring and
+measurement framework. It is more commonly know as the capture engine.
+
+The capture engine is in an early phase of development. Please review the Status
+section of this document for the current status.
+
+Performance.
+
+The capture engine is designed to not effect the system it is
+monitoring. Resources such as memory are used as well as a small performance
+hit in task creation, deletion and context switch. The overhead is small and
+will not be noticed unless the system is operating close to the performance
+limit of the target.
+
+Structure.
+
+The capture engine is implemented in a couple of layers. This lowest layer is
+the capture engine. Its interface is in the file 'capture.h'. Typically this
+interface is directly used unless you are implementing a target interface. The
+user interface is via a target interface.
+
+Command Line Interface (CLI).
+
+This is a target interface that provides a number of user commands via the
+RTEMS monitor. To use you need to provide the following in your
+application initialisation:
+
+ #include <rtems/monitor.h>
+ #include <rtems/capture-cli.h>
+
+ rtems_monitor_init (0);
+ rtems_capture_cli_init (0);
+
+Check the file capture-cli.h for documentation of the interface. The parameter
+is a pointer to your board support package's time stamp handler. The time stamp
+handler is yet to be tested so it is recommended this is left as 0, unless you
+wish to test this part of the engine.
+
+The commands are:
+
+ copen - Open the capture engine.
+ cclose - Close the capture engine.
+ cenable - Enable the capture engine.
+ cdisable - Disable the capture engine.
+ ctlist - List the tasks known to the capture engine.
+ ctload - Display the current load (sort of top).
+ cwlist - List the watch and trigger controls.
+ cwadd - Add a watch.
+ cwdel - Delete a watch.
+ cwctl - Enable or disable a watch.
+ cwglob - Enable or disable the global watch.
+ cwceil - Set the watch ceiling.
+ cwfloor - Set the watch floor.
+ ctrace - Dump the trace records.
+ ctrig - Define a trigger.
+
+Open
+
+ usage: copen [-i] size
+
+Open the capture engine. The size parameter is the size of the capture engine
+trace buffer. A single record hold a single event, for example a task create or
+a context in or out. The option '-i' will enable the capture engine after it is
+opened.
+
+Close
+
+ usage: cclose
+
+Close the capture engine and release all resources held by the capture engine.
+
+Enable
+
+ usage: cenable
+
+Enable the capture engine if it has been opened.
+
+Disable
+
+ usage: cdisable
+
+Disable the capture engine. The enable and disable commands provide a means of
+removing the overhead of the capture engine from the context switch. This may
+be needed when testing if it is felt the capture engines overhead is effecting
+the system.
+
+Task List
+
+ usage: ctlist
+
+List the tasks the capture engine knows about. This may contain tasks that have
+been deleted.
+
+Task Load
+
+ usage: ctload
+
+List the tasks in the order of load in a similar way top does on Unix. The
+command sends ANSI terminal codes. You press enter to stop the update. The
+update period is fixed at 5 seconds. The output looks like:
+
+ Press ENTER to exit.
+
+ PID NAME RPRI CPRI STATE %CPU %STK FLGS EXEC TIME
+04010001 IDLE 255 255 READY 96.012% 0% a-----g 1
+08010009 CPlt 1 1 READY 3.815% 15% a------ 0
+08010003 ntwk 20 20 Wevnt 0.072% 0% at----g 0
+08010004 CSr0 20 20 Wevnt 0.041% 0% at----g 0
+08010001 main 250 250 DELAY 0.041% 0% a-----g 0
+08010008 test 100 100 Wevnt 0.000% 20% at-T-+g 0
+08010007 test 100 100 Wevnt 0.000% 0% at-T-+g 0
+08010005 CSt0 20 20 Wevnt 0.000% 0% at----g 0
+08010006 RMON 1 1 Wsem 0.000% 0% a------ 0
+
+There are 7 flags and from left to right are:
+
+1) 'a' the task is active, and 'd' the task has been deleted.
+2) 't' the task has been traced.
+3) 'F' the task has a from (TO_ANY) trigger.
+4) 'T' the task has a to (FROM_ANY) trigger.
+5) 'E' the task has an edge (FROM_TO) trigger.
+6) '+' the task as a watch control attached, 'w' a watch is enabled.
+7) 'g' the task is part of a global trigger.
+
+The %STK is the percentage of stack used by a task. Currently only tasks
+created while the capture engine is enabled can be monitored.
+
+The RPRI is the real priority. This is the priority set for the task. The
+current priority is the executing priority that may reflect a level set as a
+result of priority inversion.
+
+Watch List
+
+ usage: cwlist
+
+This command lists the watch and trigger controls the capture engine has. A
+control is a structure used by the capture engine to determine if a task is
+watched or triggers capturing.
+
+Watch Add
+
+ usage: cwadd [task name] [id]
+
+Add a watch for a task. You can provide a name or id or both. A name will cause
+all tasks with that name to have the watch added. An id results in a watch
+being for a specific task.
+
+Using a name is useful when the task is not yet created.
+
+Watch Delete
+
+ usage: cwdel [task name] [id]
+
+Delete a watch that has been added.
+
+Watch Control
+
+ usage: cwctl [task name] [id] on/off
+
+Enable or disable a watch. The name and id parameters are the same as the watch
+add command.
+
+Global Watch
+
+ usage: cwglob on/off
+
+Enable or disable the global watch. A global watch is an easy way to enable
+watches for all tasks with real priorities between the watch ceiling and floor
+priorities.
+
+Watch Priority Ceiling
+
+ usage: cwceil priority
+
+Set the watch priority ceiling. All tasks with a priority less than the ceiling
+priority are not watched. This allow you to ignore high priority system and
+driver tasks.
+
+Watch Priority Floor
+
+ usage: cwfloor priority
+
+Set the watch priority floor. All tasks with a priority greater than the floor
+priority level are not watched. This allows you to remove tasks such as IDLE
+from being monitored.
+
+Trace
+
+ usage: ctrace [-c] [-r records]
+
+Dump the trace record. The option '-c' will output the records in comma
+separated variables (CSV). The '-r' option controls the number of records
+dumped. This can help stop the command looping for-ever.
+
+Trigger
+
+ usage: ctrig type [from name] [from id] [to name] [to id]
+
+Set a trigger. The types of triggers are :
+
+ from : trigger on a context switch from a task
+ to : trigger on a context switch to a task
+ edge : trigger on a context switch from a task to a task
+
+The from and to trigger types requires a task name or task id or both be
+provided. The edge requires a from name and/or id and a to name and/or id be
+provided.
+
+Flush
+
+ usage: cflush [-n]
+
+Flush the trace record. The option '-n' stops the capture engine be
+primed. This means an exising trigger state will not be cleared and tracing
+will continue.
+
+Status.
+
+The following is a list of outstanding issues or bugs.
+
+1) The capture engine does not scan the existing list of tasks in the kernel
+ when initialised. This means tasks that exist but are not active are not
+ seen. Not sure how to implement this one.
+
+2) The blocking read of trace records has not been completely implemented or
+ tested. This will wait until I complete the csv support for the cli for a
+ serial UI or the tcp server is implemented.
+
+3) Task control block clean up is not implemented. The control block should be
+ dumped to the trace buffer. This requires extended record formats. This can
+ be implemented using an event flag to indicate an extended record follows
+ the trace record. This would allow a task delete record to be directly
+ followed by the task information.
+
+4) Complete csv (comma separated variable) support for the CLI.
+
+5) Implement a tcp server interface.
+
+6) Complete the capture engine API documentation.
+
+7) Test the user supplied time stamp handler.
+
+8) Task name support is only for the rtems_name type. This means the only the
+ classic API tasks are currently supported. Partial support for the different
+ task names is provided how-ever this is not clean and does not support the
+ variable length task name such as found in the POSIX tasks.
diff --git a/cpukit/libmisc/capture/capture-cli.c b/cpukit/libmisc/capture/capture-cli.c
new file mode 100644
index 0000000000..98f76764f3
--- /dev/null
+++ b/cpukit/libmisc/capture/capture-cli.c
@@ -0,0 +1,1622 @@
+/*
+ ------------------------------------------------------------------------
+ $Id$
+ ------------------------------------------------------------------------
+
+ Copyright Objective Design Systems Pty Ltd, 2002
+ All rights reserved Objective Design Systems Pty Ltd, 2002
+ Chris Johns (ccj@acm.org)
+
+ COPYRIGHT (c) 1989-1998.
+ On-Line Applications Research Corporation (OAR).
+
+ The license and distribution terms for this file may be
+ found in the file LICENSE in this distribution.
+
+ This software with is provided ``as is'' and with NO WARRANTY.
+
+ ------------------------------------------------------------------------
+
+ RTEMS Performance Monitoring and Measurement Framework.
+
+ This is the Target Interface Command Line Interface. You need
+ start the RTEMS monitor.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <rtems.h>
+#include <rtems/capture-cli.h>
+#include <rtems/monitor.h>
+
+#define RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS (20)
+
+/*
+ * The user capture timestamper.
+ */
+static rtems_capture_timestamp capture_timestamp;
+
+/*
+ * Common variable to sync the load monitor task.
+ */
+static volatile int cli_load_thread_active;
+
+/*
+ * rtems_capture_cli_open
+ *
+ * DESCRIPTION:
+ *
+ * This function opens the capture engine. We need the size of the
+ * capture buffer.
+ *
+ */
+
+static const char* open_usage = "usage: copen [-i] size\n";
+
+static void
+rtems_capture_cli_open (int argc,
+ char** argv,
+ const rtems_monitor_command_arg_t* command_arg __attribute__((unused)),
+ bool verbose __attribute__((unused)))
+{
+ uint32_t size = 0;
+ bool enable = false;
+ rtems_status_code sc;
+ int arg;
+
+ if (argc <= 1)
+ {
+ fprintf (stdout, open_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ if (argv[arg][1] == 'i')
+ enable = true;
+ else
+ fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
+ }
+ else
+ {
+ size = strtoul (argv[arg], 0, 0);
+
+ if (size < 100)
+ {
+ fprintf (stdout, "error: size must be greater than or equal to 100\n");
+ return;
+ }
+ }
+ }
+
+ sc = rtems_capture_open (size, capture_timestamp);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fprintf (stdout, "error: open failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ fprintf (stdout, "capture engine opened.\n");
+
+ if (!enable)
+ return;
+
+ sc = rtems_capture_control (enable);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fprintf (stdout, "error: open enable failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ fprintf (stdout, "capture engine enabled.\n");
+}
+
+/*
+ * rtems_capture_cli_close
+ *
+ * DESCRIPTION:
+ *
+ * This function closes the capture engine.
+ *
+ */
+
+static void
+rtems_capture_cli_close (int argc __attribute__((unused)),
+ char** argv __attribute__((unused)),
+ const rtems_monitor_command_arg_t* command_arg __attribute__((unused)),
+ bool verbose __attribute__((unused)))
+{
+ rtems_status_code sc;
+
+ sc = rtems_capture_close ();
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fprintf (stdout, "error: close failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ fprintf (stdout, "capture engine closed.\n");
+}
+
+/*
+ * rtems_capture_cli_enable
+ *
+ * DESCRIPTION:
+ *
+ * This function enables the capture engine.
+ *
+ */
+
+static void
+rtems_capture_cli_enable (int argc __attribute__((unused)),
+ char** argv __attribute__((unused)),
+ const rtems_monitor_command_arg_t* command_arg __attribute__((unused)),
+ bool verbose __attribute__((unused)))
+{
+ rtems_status_code sc;
+
+ sc = rtems_capture_control (1);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fprintf (stdout, "error: enable failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ fprintf (stdout, "capture engine enabled.\n");
+}
+
+/*
+ * rtems_capture_cli_disable
+ *
+ * DESCRIPTION:
+ *
+ * This function disables the capture engine.
+ *
+ */
+
+static void
+rtems_capture_cli_disable (int argc __attribute__((unused)),
+ char** argv __attribute__((unused)),
+ const rtems_monitor_command_arg_t* command_arg __attribute__((unused)),
+ bool verbose __attribute__((unused)))
+{
+ rtems_status_code sc;
+
+ sc = rtems_capture_control (0);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fprintf (stdout, "error: disable failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ fprintf (stdout, "capture engine disabled.\n");
+}
+
+/*
+ * rtems_capture_cli_task_list
+ *
+ * DESCRIPTION:
+ *
+ * This function lists the tasks the capture engine knows about.
+ *
+ */
+
+static void
+rtems_capture_cli_task_list (int argc __attribute__((unused)),
+ char** argv __attribute__((unused)),
+ const rtems_monitor_command_arg_t* command_arg __attribute__((unused)),
+ bool verbose __attribute__((unused)))
+{
+ rtems_task_priority ceiling = rtems_capture_watch_get_ceiling ();
+ rtems_task_priority floor = rtems_capture_watch_get_floor ();
+ rtems_capture_task_t* task = rtems_capture_get_task_list ();
+ uint32_t ticks;
+ uint32_t tick_offset;
+ unsigned long long total_time;
+ int count = rtems_capture_task_count ();
+
+ if (capture_timestamp)
+ capture_timestamp (&ticks, &tick_offset);
+ else
+ {
+ ticks = _Watchdog_Ticks_since_boot;
+ tick_offset = 0;
+ }
+
+ fprintf (stdout, "total %i\n", count);
+
+ while (task)
+ {
+ rtems_task_priority priority;
+ int32_t stack_used;
+ int32_t time_used;
+
+ stack_used = rtems_capture_task_stack_usage (task);
+ if (stack_used)
+ stack_used = (stack_used * 100) / stack_used;
+
+ if (stack_used > 100)
+ stack_used = 100;
+
+ total_time = (ticks * rtems_capture_task_time (task)) + tick_offset;
+
+ time_used = (rtems_capture_task_time (task) * 100) / total_time;
+
+ if (time_used > 100)
+ time_used = 100;
+
+ priority = rtems_capture_task_real_priority (task);
+
+ fprintf (stdout, " ");
+ rtems_monitor_dump_id (rtems_capture_task_id (task));
+ fprintf (stdout, " ");
+ rtems_monitor_dump_name (rtems_capture_task_name (task));
+ fprintf (stdout, " ");
+ rtems_monitor_dump_priority (rtems_capture_task_start_priority (task));
+ fprintf (stdout, " ");
+ rtems_monitor_dump_priority (rtems_capture_task_real_priority (task));
+ fprintf (stdout, " ");
+ rtems_monitor_dump_priority (rtems_capture_task_curr_priority (task));
+ fprintf (stdout, " ");
+ rtems_monitor_dump_state (rtems_capture_task_state (task));
+ fprintf (stdout, " %c%c",
+ rtems_capture_task_valid (task) ? 'a' : 'd',
+ rtems_capture_task_flags (task) & RTEMS_CAPTURE_TRACED ? 't' : '-');
+
+ if ((floor > ceiling) && (ceiling > priority))
+ fprintf (stdout, "--");
+ else
+ {
+ uint32_t flags = rtems_capture_task_control_flags (task);
+ fprintf (stdout, "%c%c",
+ rtems_capture_task_control (task) ?
+ (flags & RTEMS_CAPTURE_WATCH ? 'w' : '+') : '-',
+ rtems_capture_watch_global_on () ? 'g' : '-');
+ }
+ fprintf (stdout, " %3" PRId32 "%% %3" PRId32 "%% (%" PRIu32 ")\n",
+ stack_used, time_used, rtems_capture_task_ticks (task));
+
+ task = rtems_capture_next_task (task);
+ }
+}
+
+/*
+ * rtems_capture_cli_task_load_thread
+ *
+ * DESCRIPTION:
+ *
+ * This function displays the load of the tasks on an ANSI terminal.
+ *
+ */
+
+static void
+rtems_capture_cli_task_load_thread (rtems_task_argument arg __attribute__((unused)))
+{
+ rtems_task_priority ceiling = rtems_capture_watch_get_ceiling ();
+ rtems_task_priority floor = rtems_capture_watch_get_floor ();
+ int last_count = 0;
+
+ for (;;)
+ {
+ rtems_capture_task_t* tasks[RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS + 1];
+ unsigned long long load[RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS + 1];
+ rtems_capture_task_t* task;
+ unsigned long long total_time;
+ int count = 0;
+ int i;
+ int j;
+
+ cli_load_thread_active = 1;
+
+ /*
+ * Iterate over the tasks and sort the highest load tasks
+ * into our local arrays. We only handle a limited number of
+ * tasks.
+ */
+
+ memset (tasks, 0, sizeof (tasks));
+ memset (load, 0, sizeof (load));
+
+ task = rtems_capture_get_task_list ();
+
+ total_time = 0;
+
+ while (task)
+ {
+ if (rtems_capture_task_valid (task))
+ {
+ unsigned long long l = rtems_capture_task_delta_time (task);
+
+ count++;
+
+ total_time += l;
+
+ for (i = 0; i < RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS; i++)
+ {
+ if (tasks[i])
+ {
+ if ((l == 0) || (l < load[i]))
+ continue;
+
+ for (j = (RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS - 1); j >= i; j--)
+ {
+ tasks[j + 1] = tasks[j];
+ load[j + 1] = load[j];
+ }
+ }
+
+ tasks[i] = task;
+ load[i] = l;
+ break;
+ }
+ }
+ task = rtems_capture_next_task (task);
+ }
+
+ fprintf (stdout, "\x1b[H\x1b[J Press ENTER to exit.\n\n");
+ fprintf (stdout,
+ " PID NAME RPRI CPRI STATE %%CPU %%STK FLGS EXEC TIME\n");
+
+ if (count > last_count)
+ j = count;
+ else
+ j = last_count;
+
+ for (i = 0; i < RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS; i++)
+ {
+ rtems_task_priority priority;
+ int stack_used;
+ int task_load;
+ int k;
+
+ if (!tasks[i])
+ break;
+
+ j--;
+
+ stack_used = rtems_capture_task_stack_usage (tasks[i]);
+ if (stack_used)
+ stack_used = (stack_used * 100) / stack_used;
+
+ if (stack_used > 100)
+ stack_used = 100;
+
+ task_load = (int) ((load[i] * 100000) / total_time);
+
+ priority = rtems_capture_task_real_priority (tasks[i]);
+
+ fprintf (stdout, "\x1b[K");
+ rtems_monitor_dump_id (rtems_capture_task_id (tasks[i]));
+ fprintf (stdout, " ");
+ rtems_monitor_dump_name (rtems_capture_task_name (tasks[i]));
+ fprintf (stdout, " ");
+ rtems_monitor_dump_priority (priority);
+ fprintf (stdout, " ");
+ rtems_monitor_dump_priority (rtems_capture_task_curr_priority (tasks[i]));
+ fprintf (stdout, " ");
+ k = rtems_monitor_dump_state (rtems_capture_task_state (tasks[i]));
+ fprintf (stdout, "%*c %3i.%03i%% ", 6 - k, ' ',
+ task_load / 1000, task_load % 1000);
+ fprintf (stdout, "%3i%% %c%c", stack_used,
+ rtems_capture_task_valid (tasks[i]) ? 'a' : 'd',
+ rtems_capture_task_flags (tasks[i]) & RTEMS_CAPTURE_TRACED ? 't' : '-');
+
+ if ((floor > ceiling) && (ceiling > priority))
+ fprintf (stdout, "--");
+ else
+ fprintf (stdout, "%c%c",
+ rtems_capture_task_control (tasks[i]) ?
+ (rtems_capture_task_control_flags (tasks[i]) &
+ RTEMS_CAPTURE_WATCH ? 'w' : '+') : '-',
+ rtems_capture_watch_global_on () ? 'g' : '-');
+
+ fprintf (stdout, " %qi\n", rtems_capture_task_time (tasks[i]));
+ }
+
+ if (count < RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS)
+ {
+ j = RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS - count;
+ while (j > 0)
+ {
+ fprintf (stdout, "\x1b[K\n");
+ j--;
+ }
+ }
+
+ last_count = count;
+
+ cli_load_thread_active = 0;
+
+ rtems_task_wake_after (RTEMS_MICROSECONDS_TO_TICKS (5000000));
+ }
+}
+
+/*
+ * rtems_capture_cli_task_load
+ *
+ * DESCRIPTION:
+ *
+ * This function is a monitor command.
+ *
+ */
+
+static void
+rtems_capture_cli_task_load (int argc __attribute__((unused)),
+ char** argv __attribute__((unused)),
+ const rtems_monitor_command_arg_t* command_arg __attribute__((unused)),
+ bool verbose __attribute__((unused)))
+{
+ rtems_status_code sc;
+ rtems_task_priority priority;
+ rtems_name name;
+ rtems_id id;
+
+ sc = rtems_task_set_priority (RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &priority);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fprintf (stdout, "error: cannot obtain the current priority: %s\n",
+ rtems_status_text (sc));
+ return;
+ }
+
+ name = rtems_build_name('C', 'P', 'l', 't');
+
+ sc = rtems_task_create (name, priority, 4 * 1024,
+ RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
+ RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR,
+ &id);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fprintf (stdout, "error: cannot create helper thread: %s\n",
+ rtems_status_text (sc));
+ return;
+ }
+
+ sc = rtems_task_start (id, rtems_capture_cli_task_load_thread, 0);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fprintf (stdout, "error: cannot start helper thread: %s\n",
+ rtems_status_text (sc));
+ rtems_task_delete (id);
+ return;
+ }
+
+ for (;;)
+ {
+ int c = getchar ();
+
+ if ((c == '\r') || (c == '\n'))
+ {
+ int loops = 20;
+
+ while (loops && cli_load_thread_active)
+ rtems_task_wake_after (RTEMS_MICROSECONDS_TO_TICKS (100000));
+
+ rtems_task_delete (id);
+
+ fprintf (stdout, "load monitoring stopped.\n");
+
+ return;
+ }
+ }
+}
+
+/*
+ * rtems_capture_cli_watch_list
+ *
+ * DESCRIPTION:
+ *
+ * This function lists the controls in the capture engine.
+ *
+ */
+
+static void
+rtems_capture_cli_watch_list (int argc __attribute__((unused)),
+ char** argv __attribute__((unused)),
+ const rtems_monitor_command_arg_t* command_arg __attribute__((unused)),
+ bool verbose __attribute__((unused)))
+{
+ rtems_capture_control_t* control = rtems_capture_get_control_list ();
+ rtems_task_priority ceiling = rtems_capture_watch_get_ceiling ();
+ rtems_task_priority floor = rtems_capture_watch_get_floor ();
+
+ fprintf (stdout, "watch priority ceiling is %" PRId32 "\n", ceiling);
+ fprintf (stdout, "watch priority floor is %" PRId32 "\n", floor);
+ fprintf (stdout, "global watch is %s\n",
+ rtems_capture_watch_global_on () ? "enabled" : "disabled");
+ fprintf (stdout, "total %" PRId32 "\n", rtems_capture_control_count ());
+
+ while (control)
+ {
+ uint32_t flags;
+ int f;
+ int fshowed;
+ int lf;
+
+ fprintf (stdout, " ");
+ rtems_monitor_dump_id (rtems_capture_control_id (control));
+ fprintf (stdout, " ");
+ rtems_monitor_dump_name (rtems_capture_control_name (control));
+ flags = rtems_capture_control_flags (control);
+ fprintf (stdout, " %c%c ",
+ rtems_capture_watch_global_on () ? 'g' : '-',
+ flags & RTEMS_CAPTURE_WATCH ? 'w' : '-');
+ flags = rtems_capture_control_to_triggers (control);
+ fprintf (stdout, " T:%c%c%c%c%c%c%c",
+ flags & RTEMS_CAPTURE_SWITCH ? 'S' : '-',
+ flags & RTEMS_CAPTURE_CREATE ? 'C' : '-',
+ flags & RTEMS_CAPTURE_START ? 'S' : '-',
+ flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
+ flags & RTEMS_CAPTURE_DELETE ? 'D' : '-',
+ flags & RTEMS_CAPTURE_BEGIN ? 'B' : '-',
+ flags & RTEMS_CAPTURE_EXITTED ? 'E' : '-');
+ flags = rtems_capture_control_from_triggers (control);
+ fprintf (stdout, " F:%c%c%c%c%c",
+ flags & RTEMS_CAPTURE_SWITCH ? 'S' : '-',
+ flags & RTEMS_CAPTURE_CREATE ? 'C' : '-',
+ flags & RTEMS_CAPTURE_START ? 'S' : '-',
+ flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
+ flags & RTEMS_CAPTURE_DELETE ? 'D' : '-');
+
+ for (f = 0, fshowed = 0, lf = 1; f < RTEMS_CAPTURE_TRIGGER_TASKS; f++)
+ {
+ if (rtems_capture_control_by_valid (control, f))
+ {
+ if (lf && ((fshowed % 3) == 0))
+ {
+ fprintf (stdout, "\n");
+ lf = 0;
+ }
+
+ fprintf (stdout, " %2i:", f);
+ rtems_monitor_dump_name (rtems_capture_control_by_name (control, f));
+ fprintf (stdout, "/");
+ rtems_monitor_dump_id (rtems_capture_control_by_id (control, f));
+ flags = rtems_capture_control_by_triggers (control, f);
+ fprintf (stdout, ":%c%c%c%c%c",
+ flags & RTEMS_CAPTURE_SWITCH ? 'S' : '-',
+ flags & RTEMS_CAPTURE_CREATE ? 'C' : '-',
+ flags & RTEMS_CAPTURE_START ? 'S' : '-',
+ flags & RTEMS_CAPTURE_RESTART ? 'R' : '-',
+ flags & RTEMS_CAPTURE_DELETE ? 'D' : '-');
+ fshowed++;
+ lf = 1;
+ }
+ }
+
+ if (lf)
+ fprintf (stdout, "\n");
+
+ control = rtems_capture_next_control (control);
+ }
+}
+
+/*
+ * rtems_capture_cli_get_name_id
+ *
+ * DESCRIPTION:
+ *
+ * This function checks arguments for a name or an id.
+ *
+ */
+
+static bool
+rtems_capture_cli_get_name_id (char* arg,
+ bool* valid_name,
+ bool* valid_id,
+ rtems_name* name,
+ rtems_id* id)
+{
+ size_t l;
+ size_t i;
+
+ if (*valid_name && *valid_id)
+ {
+ fprintf (stdout, "error: too many arguments\n");
+ return 0;
+ }
+
+ /*
+ * See if the arg is all hex digits.
+ */
+
+ l = strlen (arg);
+
+ for (i = 0; i < l; i++)
+ if (!isxdigit ((unsigned char)arg[i]))
+ break;
+
+ if (i == l)
+ {
+ *id = strtoul (arg, 0, 16);
+ *valid_id = true;
+ }
+ else
+ {
+ /*
+ * This is a bit of hack but it should work on all platforms
+ * as it is what the score does with names.
+ *
+ * @warning The extra assigns play with the byte order so do not
+ * remove unless the score has been updated.
+ */
+ rtems_name rname;
+
+ rname = rtems_build_name(arg[0], arg[1], arg[2], arg[3]);
+ *name = rname;
+ *valid_name = true;
+ }
+
+ return 1;
+}
+
+/*
+ * rtems_capture_cli_watch_add
+ *
+ * DESCRIPTION:
+ *
+ * This function is a monitor command that add a watch to the capture
+ * engine.
+ *
+ */
+
+static char const * watch_add_usage = "usage: cwadd [task name] [id]\n";
+
+static void
+rtems_capture_cli_watch_add (int argc,
+ char** argv,
+ const rtems_monitor_command_arg_t* command_arg __attribute__((unused)),
+ bool verbose __attribute__((unused)))
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_name name = 0;
+ rtems_id id = 0;
+ bool valid_name = false;
+ bool valid_id = false;
+
+ if (argc <= 1)
+ {
+ fprintf (stdout, watch_add_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
+ }
+ else
+ {
+ if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id,
+ &name, &id))
+ return;
+ }
+ }
+
+ if (!valid_name && !valid_id)
+ {
+ fprintf (stdout, "error: no valid name or task id located\n");
+ return;
+ }
+
+ sc = rtems_capture_watch_add (name, id);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fprintf (stdout,
+ "error: watch add failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ fprintf (stdout, "watch added.\n");
+}
+
+/*
+ * rtems_capture_cli_watch_del
+ *
+ * DESCRIPTION:
+ *
+ * This function is a monitor command that deletes a watch from the capture
+ * engine.
+ *
+ */
+
+static char const * watch_del_usage = "usage: cwdel [task name] [id]\n";
+
+static void
+rtems_capture_cli_watch_del (int argc,
+ char** argv,
+ const rtems_monitor_command_arg_t* command_arg __attribute__((unused)),
+ bool verbose __attribute__((unused)))
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_name name = 0;
+ rtems_id id = 0;
+ bool valid_name = false;
+ bool valid_id = false;
+
+ if (argc <= 1)
+ {
+ fprintf (stdout, watch_del_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
+ }
+ else
+ {
+ if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id,
+ &name, &id))
+ return;
+ }
+ }
+
+ if (!valid_name && !valid_id)
+ {
+ fprintf (stdout, "error: no valid name or task id located\n");
+ return;
+ }
+
+ sc = rtems_capture_watch_del (name, id);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fprintf (stdout, "error: watch delete failed: %s\n",
+ rtems_status_text (sc));
+ return;
+ }
+
+ fprintf (stdout, "watch delete.\n");
+}
+
+/*
+ * rtems_capture_cli_watch_control
+ *
+ * DESCRIPTION:
+ *
+ * This function is a monitor command that controls a watch.
+ *
+ */
+
+static char const * watch_control_usage = "usage: cwctl [task name] [id] on/off\n";
+
+static void
+rtems_capture_cli_watch_control (int argc,
+ char** argv,
+ const rtems_monitor_command_arg_t* command_arg __attribute__((unused)),
+ bool verbose __attribute__((unused)))
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_name name = 0;
+ rtems_id id = 0;
+ bool valid_name = false;
+ bool valid_id = false;
+ bool enable = false;
+
+ if (argc <= 2)
+ {
+ fprintf (stdout, watch_control_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
+ }
+ else
+ {
+ if (strcmp (argv[arg], "on") == 0)
+ enable = true;
+ else if (strcmp (argv[arg], "off") == 0)
+ enable = false;
+ else if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name,
+ &valid_id, &name, &id))
+ return;
+ }
+ }
+
+ if (!valid_name && !valid_id)
+ {
+ fprintf (stdout, "error: no valid name or task id located\n");
+ return;
+ }
+
+ sc = rtems_capture_watch_ctrl (name, id, enable);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fprintf (stdout, "error: watch control failed: %s\n",
+ rtems_status_text (sc));
+ return;
+ }
+
+ fprintf (stdout, "watch %s.\n", enable ? "enabled" : "disabled");
+}
+
+/*
+ * rtems_capture_cli_watch_global
+ *
+ * DESCRIPTION:
+ *
+ * This function is a monitor command that sets a global watch.
+ *
+ */
+
+static char const * watch_global_usage = "usage: cwglob on/off\n";
+
+static void
+rtems_capture_cli_watch_global (int argc,
+ char** argv,
+ const rtems_monitor_command_arg_t* command_arg __attribute__((unused)),
+ bool verbose __attribute__((unused)))
+{
+ rtems_status_code sc;
+ int arg;
+ bool enable = false;
+
+ if (argc <= 1)
+ {
+ fprintf (stdout, watch_global_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
+ }
+ else
+ {
+ if (strcmp (argv[arg], "on") == 0)
+ enable = true;
+ else if (strcmp (argv[arg], "off") == 0)
+ enable = false;
+ }
+ }
+
+ sc = rtems_capture_watch_global (enable);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fprintf (stdout, "error: global watch failed: %s\n",
+ rtems_status_text (sc));
+ return;
+ }
+
+ fprintf (stdout, "global watch %s.\n", enable ? "enabled" : "disabled");
+}
+
+/*
+ * rtems_capture_cli_watch_ceiling
+ *
+ * DESCRIPTION:
+ *
+ * This function is a monitor command that sets watch ceiling.
+ *
+ */
+
+static char const * watch_ceiling_usage = "usage: cwceil priority\n";
+
+static void
+rtems_capture_cli_watch_ceiling (int argc,
+ char** argv,
+ const rtems_monitor_command_arg_t* command_arg __attribute__((unused)),
+ bool verbose __attribute__((unused)))
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_task_priority priority = 0;
+
+ if (argc <= 1)
+ {
+ fprintf (stdout, watch_ceiling_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
+ }
+ else
+ {
+ priority = strtoul (argv[arg], 0, 0);
+ }
+ }
+
+ sc = rtems_capture_watch_ceiling (priority);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fprintf (stdout, "error: watch ceiling failed: %s\n",
+ rtems_status_text (sc));
+ return;
+ }
+
+ fprintf (stdout, "watch ceiling is %" PRId32 ".\n", priority);
+}
+
+/*
+ * rtems_capture_cli_watch_floor
+ *
+ * DESCRIPTION:
+ *
+ * This function is a monitor command that sets watch floor.
+ *
+ */
+
+static char const * watch_floor_usage = "usage: cwfloor priority\n";
+
+static void
+rtems_capture_cli_watch_floor (int argc,
+ char** argv,
+ const rtems_monitor_command_arg_t* command_arg __attribute__((unused)),
+ bool verbose __attribute__((unused)))
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_task_priority priority = 0;
+
+ if (argc <= 1)
+ {
+ fprintf (stdout, watch_floor_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
+ }
+ else
+ {
+ priority = strtoul (argv[arg], 0, 0);
+ }
+ }
+
+ sc = rtems_capture_watch_floor (priority);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fprintf (stdout, "error: watch floor failed: %s\n",
+ rtems_status_text (sc));
+ return;
+ }
+
+ fprintf (stdout, "watch floor is %" PRId32 ".\n", priority);
+}
+
+/*
+ * rtems_capture_cli_trigger_worker
+ *
+ * DESCRIPTION:
+ *
+ * This function is a monitor command that sets or clears a trigger.
+ *
+ */
+
+static char const *trigger_set_usage =
+ "usage: %s [-?] type [to name/id] [from] [from name/id]\n";
+
+static char const *trigger_set_types =
+ " You can say 'type TASK' or 'type TO from FROM'\n" \
+ " where TASK is the task the event is happening to\n" \
+ " or you can say the event TO this task FROM this task.\n" \
+ " No type defaults to 'switch'.\n" \
+ " switch : context switch TASK or FROM or FROM->TO\n" \
+ " create : create TASK, or create TO from FROM\n" \
+ " start : start TASK, or start TO from FROM\n" \
+ " restart : restart TASK, or restart TO from FROM\n" \
+ " delete : delete TASK or delete TO from FROM\n" \
+ " begin : begin TASK\n" \
+ " exitted : exitted TASK\n";
+
+/*
+ * Structure to handle the parsing of the trigger command line.
+ */
+typedef struct rtems_capture_cli_triggers_s
+{
+ char const * name;
+ rtems_capture_trigger_t type;
+ int to_only;
+} rtems_capture_cli_triggers_t;
+
+static rtems_capture_cli_triggers_t rtems_capture_cli_triggers[] =
+{
+ { "switch", rtems_capture_switch, 0 }, /* must be first */
+ { "create", rtems_capture_create, 0 },
+ { "start", rtems_capture_start, 0 },
+ { "restart", rtems_capture_restart, 0 },
+ { "delete", rtems_capture_delete, 0 },
+ { "begin", rtems_capture_begin, 1 },
+ { "exitted", rtems_capture_exitted, 1 }
+};
+
+typedef enum rtems_capture_cli_trig_state_e
+{
+ trig_type,
+ trig_to,
+ trig_from_from,
+ trig_from
+} rtems_capture_cli_trig_state_t;
+
+#define RTEMS_CAPTURE_CLI_TRIGGERS_NUM \
+ (sizeof (rtems_capture_cli_triggers) / sizeof (rtems_capture_cli_triggers_t))
+
+static void
+rtems_capture_cli_trigger_worker (int set, int argc, char** argv)
+{
+ rtems_status_code sc;
+ int arg;
+ int trigger = 0; /* switch */
+ rtems_capture_trigger_mode_t trigger_mode = rtems_capture_from_any;
+ bool trigger_set = false;
+ bool is_from = false;
+ rtems_name name = 0;
+ rtems_id id = 0;
+ bool valid_name = false;
+ bool valid_id = false;
+ rtems_name from_name = 0;
+ rtems_id from_id = 0;
+ bool from_valid_name = false;
+ bool from_valid_id = false;
+ rtems_name to_name = 0;
+ rtems_id to_id = 0;
+ bool to_valid_name = false;
+ bool to_valid_id = false;
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ switch (argv[arg][1])
+ {
+ case '?':
+ fprintf (stdout, trigger_set_usage, set ? "ctset" : "ctclear");
+ fprintf (stdout, trigger_set_types);
+ return;
+ default:
+ fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
+ break;
+ }
+ }
+ else
+ {
+ if (!trigger_set)
+ {
+ bool found = false;
+ int t;
+
+ for (t = 0; t < RTEMS_CAPTURE_CLI_TRIGGERS_NUM; t++)
+ if (strcmp (argv[arg], rtems_capture_cli_triggers[t].name) == 0)
+ {
+ trigger = t;
+ found = true;
+ break;
+ }
+
+ trigger_set = true;
+
+ /*
+ * If a trigger was not found assume the default and
+ * assume the parameter is a task name or id.
+ */
+ if (found)
+ continue;
+ }
+
+ if (strcmp (arg[argv], "from") == 0)
+ {
+ if (is_from)
+ fprintf (stdout, "warning: extra 'from' ignored\n");
+
+ is_from = 1;
+ continue;
+ }
+
+ if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id,
+ &name, &id))
+ return;
+
+ if (valid_name)
+ {
+ if (is_from)
+ {
+ if (!from_valid_name && !from_valid_id)
+ {
+ from_valid_name = true;
+ from_name = name;
+ }
+ else
+ fprintf (stdout, "warning: extra arguments ignored\n");
+ }
+ else if (!to_valid_name && !to_valid_id)
+ {
+ to_valid_name = true;
+ to_name = name;
+ }
+ else
+ fprintf (stdout, "warning: extra arguments ignored\n");
+ }
+
+ if (valid_id)
+ {
+ if (is_from)
+ {
+ if (!from_valid_name && !from_valid_id)
+ {
+ from_valid_id = true;
+ from_id = id;
+ }
+ else
+ fprintf (stdout, "warning: extra arguments ignored\n");
+ }
+ else if (!to_valid_name && !to_valid_id)
+ {
+ to_valid_id = true;
+ to_id = id;
+ }
+ else
+ fprintf (stdout, "warning: extra arguments ignored\n");
+ }
+ }
+ }
+
+ if (is_from && rtems_capture_cli_triggers[trigger].to_only)
+ {
+ fprintf (stdout, "error: a %s trigger can be a TO trigger\n",
+ rtems_capture_cli_triggers[trigger].name);
+ return;
+ }
+
+ if (!to_valid_name && !to_valid_id && !from_valid_name && !from_valid_id)
+ {
+ fprintf (stdout, trigger_set_usage);
+ return;
+ }
+
+ if (!is_from && !to_valid_name && !to_valid_id)
+ {
+ fprintf (stdout, "error: a %s trigger needs a TO name or id\n",
+ rtems_capture_cli_triggers[trigger].name);
+ return;
+ }
+
+ if (is_from && !from_valid_name && !from_valid_id)
+ {
+ fprintf (stdout, "error: a %s trigger needs a FROM name or id\n",
+ rtems_capture_cli_triggers[trigger].name);
+ return;
+ }
+
+ if ((from_valid_name || from_valid_id) && (to_valid_name || to_valid_id))
+ trigger_mode = rtems_capture_from_to;
+ else if (from_valid_name || from_valid_id)
+ trigger_mode = rtems_capture_to_any;
+ else if (to_valid_name || to_valid_id)
+ trigger_mode = rtems_capture_from_any;
+
+ if (set)
+ sc = rtems_capture_set_trigger (from_name, from_id, to_name, to_id,
+ trigger_mode,
+ rtems_capture_cli_triggers[trigger].type);
+ else
+ sc = rtems_capture_clear_trigger (from_name, from_id, to_name, to_id,
+ trigger_mode,
+ rtems_capture_cli_triggers[trigger].type);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fprintf (stdout, "error: %sing the trigger failed: %s\n",
+ set ? "sett" : "clear", rtems_status_text (sc));
+ return;
+ }
+
+ fprintf (stdout, "trigger %s.\n", set ? "set" : "cleared");
+}
+
+/*
+ * rtems_capture_cli_trigger_set
+ *
+ * DESCRIPTION:
+ *
+ * This function is a monitor command that sets a trigger.
+ *
+ */
+
+static void
+rtems_capture_cli_trigger_set (int argc,
+ char** argv,
+ const rtems_monitor_command_arg_t* command_arg __attribute__((unused)),
+ bool verbose __attribute__((unused)))
+{
+ rtems_capture_cli_trigger_worker (1, argc, argv);
+}
+
+/*
+ * rtems_capture_cli_trigger_clear
+ *
+ * DESCRIPTION:
+ *
+ * This function is a monitor command that clears a trigger.
+ *
+ */
+
+static void
+rtems_capture_cli_trigger_clear (int argc,
+ char** argv,
+ const rtems_monitor_command_arg_t* command_arg __attribute__((unused)),
+ bool verbose __attribute__((unused)))
+{
+ rtems_capture_cli_trigger_worker (0, argc, argv);
+}
+
+/*
+ * rtems_capture_cli_trace_records
+ *
+ * DESCRIPTION:
+ *
+ * This function is a monitor command that dumps trace records.
+ *
+ */
+
+static void
+rtems_capture_cli_trace_records (int argc,
+ char** argv,
+ const rtems_monitor_command_arg_t* command_arg __attribute__((unused)),
+ bool verbose __attribute__((unused)))
+{
+ rtems_status_code sc;
+ bool csv = false;
+ static int dump_total = 22;
+ int total;
+ int count;
+ uint32_t read;
+ rtems_capture_record_t* rec;
+ int arg;
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ if (argv[arg][1] == 'c')
+ csv = true;
+ else
+ fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
+ }
+ else
+ {
+ size_t i;
+ size_t l;
+
+ l = strlen (argv[arg]);
+
+ for (i = 0; i < l; i++)
+ if (!isdigit ((unsigned char)argv[arg][i]))
+ {
+ fprintf (stdout, "error: not a number\n");
+ return;
+ }
+
+ dump_total = strtoul (argv[arg], 0, 0);
+ }
+ }
+
+ total = dump_total;
+
+ while (total)
+ {
+ sc = rtems_capture_read (0, 0, &read, &rec);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fprintf (stdout, "error: trace read failed: %s\n", rtems_status_text (sc));
+ rtems_capture_flush (0);
+ return;
+ }
+
+ /*
+ * If we have no records then just exist. We still need to release
+ * the reader lock.
+ */
+
+ if (read == 0)
+ {
+ rtems_capture_release (read);
+ break;
+ }
+
+ count = total < read ? total : read;
+
+ while (count--)
+ {
+ if (csv)
+ fprintf (stdout, "%08" PRIxPTR ",%03" PRIu32
+ ",%03" PRIu32 ",%04" PRIx32 ",%" PRId32 ",%" PRId32 "\n",
+ (uintptr_t) rec->task,
+ (rec->events >> RTEMS_CAPTURE_REAL_PRIORITY_EVENT) & 0xff,
+ (rec->events >> RTEMS_CAPTURE_CURR_PRIORITY_EVENT) & 0xff,
+ (rec->events >> RTEMS_CAPTURE_EVENT_START),
+ rec->ticks, rec->tick_offset);
+ else
+ {
+ unsigned long long t;
+ uint32_t event;
+ int e;
+
+ event = rec->events >> RTEMS_CAPTURE_EVENT_START;
+
+ t = rec->ticks;
+ t *= rtems_capture_tick_time ();
+ t += rec->tick_offset;
+
+ for (e = RTEMS_CAPTURE_EVENT_START; e < RTEMS_CAPTURE_EVENT_END; e++)
+ {
+ if (event & 1)
+ {
+ fprintf (stdout, "%9li.%06li ", (unsigned long) (t / 1000000),
+ (unsigned long) (t % 1000000));
+ rtems_monitor_dump_id (rtems_capture_task_id (rec->task));
+ fprintf (stdout, " ");
+ rtems_monitor_dump_name (rtems_capture_task_name (rec->task));
+ fprintf (stdout, " %3" PRId32 " %3" PRId32 " %s\n",
+ (rec->events >> RTEMS_CAPTURE_REAL_PRIORITY_EVENT) & 0xff,
+ (rec->events >> RTEMS_CAPTURE_CURR_PRIORITY_EVENT) & 0xff,
+ rtems_capture_event_text (e));
+ }
+ event >>= 1;
+ }
+ }
+ rec++;
+ }
+
+ count = total < read ? total : read;
+
+ if (count < total)
+ total -= count;
+ else
+ total = 0;
+
+ rtems_capture_release (count);
+ }
+}
+
+/*
+ * rtems_capture_cli_flush
+ *
+ * DESCRIPTION:
+ *
+ * This function is a monitor command that flushes and primes the capture
+ * engine.
+ *
+ */
+
+static void
+rtems_capture_cli_flush (int argc,
+ char** argv,
+ const rtems_monitor_command_arg_t* command_arg __attribute__((unused)),
+ bool verbose __attribute__((unused)))
+{
+ rtems_status_code sc;
+ bool prime = true;
+ int arg;
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ if (argv[arg][1] == 'n')
+ prime = false;
+ else
+ fprintf (stdout, "warning: option -%c ignored\n", argv[arg][1]);
+ }
+ }
+
+ sc = rtems_capture_flush (prime);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fprintf (stdout, "error: flush failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ fprintf (stdout, "trace buffer flushed and %s.\n",
+ prime ? "primed" : "not primed");
+}
+
+static rtems_monitor_command_entry_t rtems_capture_cli_cmds[] =
+{
+ {
+ "copen",
+ "usage: copen [-i] size\n",
+ 0,
+ rtems_capture_cli_open,
+ { 0 },
+ 0
+ },
+ {
+ "cclose",
+ "usage: cclose\n",
+ 0,
+ rtems_capture_cli_close,
+ { 0 },
+ 0
+ },
+ {
+ "cenable",
+ "usage: cenable\n",
+ 0,
+ rtems_capture_cli_enable,
+ { 0 },
+ 0
+ },
+ {
+ "cdisable",
+ "usage: cdisable\n",
+ 0,
+ rtems_capture_cli_disable,
+ { 0 },
+ 0
+ },
+ {
+ "ctlist",
+ "usage: ctlist \n",
+ 0,
+ rtems_capture_cli_task_list,
+ { 0 },
+ 0
+ },
+ {
+ "ctload",
+ "usage: ctload \n",
+ 0,
+ rtems_capture_cli_task_load,
+ { 0 },
+ 0
+ },
+ {
+ "cwlist",
+ "usage: cwlist\n",
+ 0,
+ rtems_capture_cli_watch_list,
+ { 0 },
+ 0
+ },
+ {
+ "cwadd",
+ "usage: cwadd [task name] [id]\n",
+ 0,
+ rtems_capture_cli_watch_add,
+ { 0 },
+ 0
+ },
+ {
+ "cwdel",
+ "usage: cwdel [task name] [id]\n",
+ 0,
+ rtems_capture_cli_watch_del,
+ { 0 },
+ 0
+ },
+ {
+ "cwctl",
+ "usage: cwctl [task name] [id] on/off\n",
+ 0,
+ rtems_capture_cli_watch_control,
+ { 0 },
+ 0
+ },
+ {
+ "cwglob",
+ "usage: cwglob on/off\n",
+ 0,
+ rtems_capture_cli_watch_global,
+ { 0 },
+ 0
+ },
+ {
+ "cwceil",
+ "usage: cwceil priority\n",
+ 0,
+ rtems_capture_cli_watch_ceiling,
+ { 0 },
+ 0
+ },
+ {
+ "cwfloor",
+ "usage: cwfloor priority\n",
+ 0,
+ rtems_capture_cli_watch_floor,
+ { 0 },
+ 0
+ },
+ {
+ "ctrace",
+ "usage: ctrace [-c] [-r records]\n",
+ 0,
+ rtems_capture_cli_trace_records,
+ { 0 },
+ 0
+ },
+ {
+ "ctset",
+ "usage: ctset -h\n",
+ 0,
+ rtems_capture_cli_trigger_set,
+ { 0 },
+ 0
+ },
+ {
+ "ctclear",
+ "usage: ctclear -?\n",
+ 0,
+ rtems_capture_cli_trigger_clear,
+ { 0 },
+ 0
+ },
+ {
+ "cflush",
+ "usage: cflush [-n]\n",
+ 0,
+ rtems_capture_cli_flush,
+ { 0 },
+ 0
+ }
+};
+
+/*
+ * rtems_capture_cli_init
+ *
+ * DESCRIPTION:
+ *
+ * This function initialises the command line interface to the capture
+ * engine.
+ *
+ */
+
+rtems_status_code
+rtems_capture_cli_init (rtems_capture_timestamp timestamp)
+{
+ size_t cmd;
+
+ capture_timestamp = timestamp;
+
+ for (cmd = 0;
+ cmd < sizeof (rtems_capture_cli_cmds) / sizeof (rtems_monitor_command_entry_t);
+ cmd++)
+ rtems_monitor_insert_cmd (&rtems_capture_cli_cmds[cmd]);
+
+ return RTEMS_SUCCESSFUL;
+}
diff --git a/cpukit/libmisc/capture/capture-cli.h b/cpukit/libmisc/capture/capture-cli.h
new file mode 100644
index 0000000000..99c4e2252c
--- /dev/null
+++ b/cpukit/libmisc/capture/capture-cli.h
@@ -0,0 +1,56 @@
+/**
+ * @file rtems/capture-cli.h
+ */
+
+/*
+ ------------------------------------------------------------------------
+ $Id$
+ ------------------------------------------------------------------------
+
+ Copyright Objective Design Systems Pty Ltd, 2002
+ All rights reserved Objective Design Systems Pty Ltd, 2002
+ Chris Johns (ccj@acm.org)
+
+ COPYRIGHT (c) 1989-1998.
+ On-Line Applications Research Corporation (OAR).
+
+ The license and distribution terms for this file may be
+ found in the file LICENSE in this distribution.
+
+ This software with is provided ``as is'' and with NO WARRANTY.
+
+ ------------------------------------------------------------------------
+
+ RTEMS Performance Monitoring and Measurement Framework.
+
+ This is the Target Interface Command Line Interface. You need
+ start the RTEMS monitor.
+
+*/
+
+#ifndef __CAPTURE_CLI_H_
+#define __CAPTURE_CLI_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems/capture.h>
+
+/**
+ * rtems_capture_cli_init
+ *
+ * DESCRIPTION:
+ *
+ * This function initialises the command line interface to the capture
+ * engine.
+ *
+ */
+rtems_status_code
+rtems_capture_cli_init (rtems_capture_timestamp timestamp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cpukit/libmisc/capture/capture.c b/cpukit/libmisc/capture/capture.c
new file mode 100644
index 0000000000..ac1acc01ac
--- /dev/null
+++ b/cpukit/libmisc/capture/capture.c
@@ -0,0 +1,1938 @@
+/*
+ ------------------------------------------------------------------------
+ $Id$
+ ------------------------------------------------------------------------
+
+ Copyright Objective Design Systems Pty Ltd, 2002
+ All rights reserved Objective Design Systems Pty Ltd, 2002
+ Chris Johns (ccj@acm.org)
+
+ COPYRIGHT (c) 1989-2009.
+ On-Line Applications Research Corporation (OAR).
+
+ The license and distribution terms for this file may be
+ found in the file LICENSE in this distribution.
+
+ This software with is provided ``as is'' and with NO WARRANTY.
+
+ ------------------------------------------------------------------------
+
+ RTEMS Performance Monitoring and Measurement Framework.
+
+ This is the Capture Engine component.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "capture.h"
+#include <rtems/score/states.inl>
+#include <rtems/score/wkspace.h>
+#include <rtems/score/wkspace.inl>
+
+/*
+ * These events are always recorded and are not part of the
+ * watch filters.
+ *
+ * This feature has been disabled as it becomes confusing when
+ * setting up filters and some event leak.
+ */
+#if defined (RTEMS_CAPTURE_ENGINE_ALLOW_RELATED_EVENTS)
+#define RTEMS_CAPTURE_RECORD_EVENTS (RTEMS_CAPTURE_CREATED_BY_EVENT | \
+ RTEMS_CAPTURE_CREATED_EVENT | \
+ RTEMS_CAPTURE_STARTED_BY_EVENT | \
+ RTEMS_CAPTURE_STARTED_EVENT | \
+ RTEMS_CAPTURE_RESTARTED_BY_EVENT | \
+ RTEMS_CAPTURE_RESTARTED_EVENT | \
+ RTEMS_CAPTURE_DELETED_BY_EVENT | \
+ RTEMS_CAPTURE_DELETED_EVENT | \
+ RTEMS_CAPTURE_BEGIN_EVENT | \
+ RTEMS_CAPTURE_EXITTED_EVENT)
+#else
+#define RTEMS_CAPTURE_RECORD_EVENTS (0)
+#endif
+
+/*
+ * Global capture flags.
+ */
+#define RTEMS_CAPTURE_ON (1 << 0)
+#define RTEMS_CAPTURE_NO_MEMORY (1 << 1)
+#define RTEMS_CAPTURE_OVERFLOW (1 << 2)
+#define RTEMS_CAPTURE_TRIGGERED (1 << 3)
+#define RTEMS_CAPTURE_READER_ACTIVE (1 << 4)
+#define RTEMS_CAPTURE_READER_WAITING (1 << 5)
+#define RTEMS_CAPTURE_GLOBAL_WATCH (1 << 6)
+#define RTEMS_CAPTURE_ONLY_MONITOR (1 << 7)
+
+/*
+ * RTEMS Capture Data.
+ */
+static rtems_capture_record_t* capture_records;
+static uint32_t capture_size;
+static uint32_t capture_count;
+static rtems_capture_record_t* capture_in;
+static uint32_t capture_out;
+static uint32_t capture_flags;
+static rtems_capture_task_t* capture_tasks;
+static rtems_capture_control_t* capture_controls;
+static int capture_extension_index;
+static rtems_id capture_id;
+static rtems_capture_timestamp capture_timestamp;
+static rtems_task_priority capture_ceiling;
+static rtems_task_priority capture_floor;
+static uint32_t capture_tick_period;
+static rtems_id capture_reader;
+
+/*
+ * RTEMS Event text.
+ */
+static const char* capture_event_text[] =
+{
+ "CREATED_BY",
+ "CREATED",
+ "STARTED_BY",
+ "STARTED",
+ "RESTARTED_BY",
+ "RESTARTED",
+ "DELETED_BY",
+ "DELETED",
+ "BEGIN",
+ "EXITTED",
+ "SWITCHED_OUT",
+ "SWITCHED_IN",
+ "TIMESTAMP"
+};
+
+/*
+ * rtems_capture_get_time
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the current time. If a handler is provided
+ * by the user get the time from that.
+ */
+static inline void rtems_capture_get_time (uint32_t* ticks,
+ uint32_t* tick_offset)
+{
+ if (capture_timestamp)
+ capture_timestamp (ticks, tick_offset);
+ else
+ {
+ *ticks = _Watchdog_Ticks_since_boot;
+ *tick_offset = 0;
+ }
+}
+
+/*
+ * rtems_capture_match_names
+ *
+ * DESCRIPTION:
+ *
+ * This function compares rtems_names. It protects the
+ * capture engine from a change to the way names are supported
+ * in RTEMS.
+ *
+ */
+static inline bool
+rtems_capture_match_names (rtems_name lhs, rtems_name rhs)
+{
+ return lhs == rhs;
+}
+
+/*
+ * rtems_capture_match_id
+ *
+ * DESCRIPTION:
+ *
+ * This function compares rtems_ids. It protects the
+ * capture engine from a change to the way id are supported
+ * in RTEMS.
+ *
+ */
+static inline bool
+rtems_capture_match_ids (rtems_id lhs, rtems_id rhs)
+{
+ return lhs == rhs;
+}
+
+/*
+ * rtems_capture_match_name_id
+ *
+ * DESCRIPTION:
+ *
+ * This function matches a name and/or id.
+ */
+static inline bool
+rtems_capture_match_name_id (rtems_name lhs_name,
+ rtems_id lhs_id,
+ rtems_name rhs_name,
+ rtems_id rhs_id)
+{
+ /*
+ * 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))
+ {
+ if (rtems_capture_match_names (lhs_name, rhs_name))
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * rtems_capture_dup_name
+ *
+ * DESCRIPTION:
+ *
+ * This function duplicates an rtems_names. It protects the
+ * capture engine from a change to the way names are supported
+ * in RTEMS.
+ *
+ */
+static inline void
+rtems_capture_dup_name (rtems_name* dst, rtems_name src)
+{
+ *dst = src;
+}
+
+/*
+ * rtems_capture_by_in_to
+ *
+ * DESCRIPTION:
+ *
+ * This function sees if a BY control is in the BY names. The use
+ * of the valid_mask in this way assumes the number of trigger
+ * tasks is the number of bits in uint32_t.
+ *
+ */
+static inline bool
+rtems_capture_by_in_to (uint32_t events,
+ rtems_capture_task_t* by,
+ rtems_capture_control_t* to)
+{
+ uint32_t valid_mask = RTEMS_CAPTURE_CONTROL_FROM_MASK (0);
+ uint32_t valid_remainder = 0xffffffff;
+ int i;
+
+ for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
+ {
+ /*
+ * If there are no more valid BY entries then
+ * we are finished.
+ */
+ if ((valid_remainder & to->by_valid) == 0)
+ break;
+
+ /*
+ * Is the froby entry valid and does its name or id match.
+ */
+ if ((valid_mask & to->by_valid) &&
+ (to->by[i].trigger & events))
+ {
+ /*
+ * We have the BY task on the right hand side so we
+ * match with id's first then labels if the id's are
+ * not set.
+ */
+ if (rtems_capture_match_name_id (to->by[i].name, to->by[i].id,
+ by->name, by->id))
+ return 1;
+ }
+
+ valid_mask >>= 1;
+ valid_remainder >>= 1;
+ }
+
+ return 0;
+}
+
+/*
+ * rtems_capture_refcount_up
+ *
+ * DESCRIPTION:
+ *
+ * This function raises the reference count.
+ *
+ */
+static inline void
+rtems_capture_refcount_up (rtems_capture_task_t* task)
+{
+ task->refcount++;
+}
+
+/*
+ * rtems_capture_refcount_down
+ *
+ * DESCRIPTION:
+ *
+ * This function lowers the reference count and if the count
+ * reaches 0 the task control block is returned to the heap.
+ *
+ */
+static inline void
+rtems_capture_refcount_down (rtems_capture_task_t* task)
+{
+ if (task->refcount)
+ task->refcount--;
+}
+
+/*
+ * rtems_capture_init_stack_usage
+ *
+ * DESCRIPTION:
+ *
+ * This function setups a stack so its usage can be monitored.
+ */
+static inline void
+rtems_capture_init_stack_usage (rtems_capture_task_t* task)
+{
+ if (task->tcb)
+ {
+ uint32_t* s;
+ uint32_t i;
+
+ task->stack_size = task->tcb->Start.Initial_stack.size;
+ task->stack_clean = task->stack_size;
+
+ s = task->tcb->Start.Initial_stack.area;
+
+ for (i = 0; i < (task->stack_size - 128); i += 4)
+ *(s++) = 0xdeaddead;
+ }
+}
+
+/*
+ * rtems_capture_find_control
+ *
+ * DESCRIPTION:
+ *
+ * This function searches for a trigger given a name.
+ *
+ */
+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;
+ return control;
+}
+
+/*
+ * rtems_capture_create_control
+ *
+ * DESCRIPTION:
+ *
+ * This function creates a capture control for the capture engine.
+ *
+ */
+static inline rtems_capture_control_t*
+rtems_capture_create_control (rtems_name name, rtems_id id)
+{
+ rtems_interrupt_level level;
+ rtems_capture_control_t* control;
+ rtems_capture_task_t* task;
+
+ if ((name == 0) && (id == 0))
+ return NULL;
+
+ control = rtems_capture_find_control (name, id);
+
+ if (control == NULL)
+ {
+ control = _Workspace_Allocate (sizeof (rtems_capture_control_t));
+
+ if (control == NULL)
+ {
+ capture_flags |= RTEMS_CAPTURE_NO_MEMORY;
+ return NULL;
+ }
+
+ control->name = name;
+ control->id = id;
+ control->flags = 0;
+ control->to_triggers = 0;
+ control->from_triggers = 0;
+ control->by_valid = 0;
+
+ memset (control->by, 0, sizeof (control->by));
+
+ rtems_interrupt_disable (level);
+
+ control->next = capture_controls;
+ capture_controls = control;
+
+ /*
+ * We need to scan the task list as set the control to the
+ * tasks.
+ */
+ for (task = capture_tasks; task != NULL; task = task->forw)
+ if (rtems_capture_match_name_id (name, id, task->name, task->id))
+ task->control = control;
+
+ rtems_interrupt_enable (level);
+ }
+
+ return control;
+}
+
+/*
+ * rtems_capture_create_capture_task
+ *
+ * DESCRIPTION:
+ *
+ * This function create the task control.
+ *
+ */
+static inline rtems_capture_task_t*
+rtems_capture_create_capture_task (rtems_tcb* new_task)
+{
+ rtems_interrupt_level level;
+ rtems_capture_task_t* task;
+ rtems_capture_control_t* control;
+ rtems_name name;
+
+ task = _Workspace_Allocate (sizeof (rtems_capture_task_t));
+
+ if (task == NULL)
+ {
+ capture_flags |= RTEMS_CAPTURE_NO_MEMORY;
+ return NULL;
+ }
+
+ /*
+ * Check the type of name the object has.
+ */
+
+ rtems_object_get_classic_name( new_task->Object.id, &name );
+
+ rtems_capture_dup_name (&task->name, name);
+
+ task->id = new_task->Object.id;
+ task->flags = 0;
+ task->in = 0;
+ task->refcount = 0;
+ task->out = 0;
+ task->tcb = new_task;
+ task->ticks = 0;
+ task->tick_offset = 0;
+ task->ticks_in = 0;
+ task->tick_offset_in = 0;
+ task->control = 0;
+ task->last_ticks = 0;
+ task->last_tick_offset = 0;
+
+ task->tcb->extensions[capture_extension_index] = task;
+
+ task->start_priority = new_task->Start.initial_priority;
+ task->stack_size = new_task->Start.Initial_stack.size;
+ task->stack_clean = task->stack_size;
+
+ rtems_interrupt_disable (level);
+
+ task->forw = capture_tasks;
+ if (task->forw)
+ task->forw->back = task;
+ task->back = NULL;
+ capture_tasks = task;
+
+ rtems_interrupt_enable (level);
+
+ /*
+ * We need to scan the default control list to initialise
+ * this control.
+ */
+
+ for (control = capture_controls; control != NULL; control = control->next)
+ if (rtems_capture_match_name_id (control->name, control->id,
+ task->name, task->id))
+ task->control = control;
+
+ return task;
+}
+
+/*
+ * rtems_capture_destroy_capture_task
+ *
+ * DESCRIPTION:
+ *
+ * This function destroy the task structure if the reference count
+ * is 0 and the tcb has been cleared signalling the task has been
+ * deleted.
+ *
+ */
+static inline void
+rtems_capture_destroy_capture_task (rtems_capture_task_t* task)
+{
+ if (task)
+ {
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable (level);
+
+ if (task->tcb || task->refcount)
+ task = 0;
+
+ if (task)
+ {
+ if (task->forw)
+ task->forw->back = task->back;
+ if (task->back)
+ task->back->forw = task->forw;
+ else
+ capture_tasks = task->forw;
+ }
+
+ rtems_interrupt_enable (level);
+
+ _Workspace_Free (task);
+ }
+}
+
+/*
+ * rtems_capture_record
+ *
+ * DESCRIPTION:
+ *
+ * This function records a capture record into the capture buffer.
+ *
+ */
+static inline void
+rtems_capture_record (rtems_capture_task_t* task,
+ uint32_t events)
+{
+ /*
+ * Check the watch state if we have a task control, and
+ * the task's real priority is lower or equal to the ceiling.
+ */
+ if (task &&
+ ((capture_flags &
+ (RTEMS_CAPTURE_TRIGGERED | RTEMS_CAPTURE_ONLY_MONITOR)) ==
+ RTEMS_CAPTURE_TRIGGERED))
+ {
+ rtems_capture_control_t* control;
+
+ control = task->control;
+
+ /*
+ * Capure the record if we have an event that is always
+ * captured, or the task's real priority is greater than the
+ * watch ceiling, and the global watch or task watch is enabled.
+ */
+
+ if ((events & RTEMS_CAPTURE_RECORD_EVENTS) ||
+ ((task->tcb->real_priority >= capture_ceiling) &&
+ (task->tcb->real_priority <= capture_floor) &&
+ ((capture_flags & RTEMS_CAPTURE_GLOBAL_WATCH) ||
+ (control && (control->flags & RTEMS_CAPTURE_WATCH)))))
+ {
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable (level);
+
+ if (capture_count < capture_size)
+ {
+ capture_count++;
+ capture_in->task = task;
+ capture_in->events = (events |
+ (task->tcb->real_priority) |
+ (task->tcb->current_priority << 8));
+
+ if ((events & RTEMS_CAPTURE_RECORD_EVENTS) == 0)
+ task->flags |= RTEMS_CAPTURE_TRACED;
+
+ rtems_capture_get_time (&capture_in->ticks, &capture_in->tick_offset);
+
+ if (capture_in == &capture_records[capture_size - 1])
+ capture_in = capture_records;
+ else
+ capture_in++;
+
+ rtems_capture_refcount_up (task);
+ }
+ else
+ capture_flags |= RTEMS_CAPTURE_OVERFLOW;
+ rtems_interrupt_enable (level);
+ }
+ }
+}
+
+/*
+ * rtems_capture_trigger
+ *
+ * DESCRIPTION:
+ *
+ * See if we have triggered and if not see if this event is a
+ * cause of a trigger.
+ */
+bool
+rtems_capture_trigger (rtems_capture_task_t* ft,
+ rtems_capture_task_t* tt,
+ uint32_t events)
+{
+ /*
+ * If we have not triggered then see if this is a trigger condition.
+ */
+ if (!(capture_flags & RTEMS_CAPTURE_TRIGGERED))
+ {
+ rtems_capture_control_t* fc = NULL;
+ rtems_capture_control_t* tc = NULL;
+ uint32_t from_events = 0;
+ uint32_t to_events = 0;
+ uint32_t from_to_events = 0;
+
+ if (ft)
+ {
+ fc = ft->control;
+ if (fc)
+ from_events = fc->from_triggers & events;
+ }
+
+ if (tt)
+ {
+ tc = tt->control;
+ if (tc)
+ {
+ to_events = tc->to_triggers & events;
+ if (ft && tc->by_valid)
+ from_to_events = tc->by_triggers & events;
+ }
+ }
+
+ /*
+ * Check if we have any from or to events. These are the
+ * from any or to any type triggers. All from/to triggers are
+ * listed in the to's control with the from in the from list.
+ *
+ * The masking above means any flag set is a trigger.
+ */
+ if (from_events || to_events)
+ {
+ capture_flags |= RTEMS_CAPTURE_TRIGGERED;
+ return 1;
+ }
+
+ /*
+ * Check the from->to events.
+ */
+ if (from_to_events)
+ {
+ if (rtems_capture_by_in_to (events, ft, tc))
+ {
+ capture_flags |= RTEMS_CAPTURE_TRIGGERED;
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * rtems_capture_create_task
+ *
+ * DESCRIPTION:
+ *
+ * This function is called when a task is created.
+ *
+ */
+static bool
+rtems_capture_create_task (rtems_tcb* current_task,
+ rtems_tcb* new_task)
+{
+ rtems_capture_task_t* ct;
+ rtems_capture_task_t* nt;
+
+ ct = current_task->extensions[capture_extension_index];
+
+ /*
+ * The task pointers may not be known as the task may have
+ * been created before the capture engine was open. Add them.
+ */
+
+ if (ct == NULL)
+ ct = rtems_capture_create_capture_task (current_task);
+
+ /*
+ * Create the new task's capture control block.
+ */
+ nt = rtems_capture_create_capture_task (new_task);
+
+ if (rtems_capture_trigger (ct, nt, RTEMS_CAPTURE_CREATE))
+ {
+ rtems_capture_record (ct, RTEMS_CAPTURE_CREATED_BY_EVENT);
+ rtems_capture_record (nt, RTEMS_CAPTURE_CREATED_EVENT);
+ }
+
+ return 1 == 1;
+}
+
+/*
+ * rtems_capture_start_task
+ *
+ * DESCRIPTION:
+ *
+ * This function is called when a task is started.
+ *
+ */
+static void
+rtems_capture_start_task (rtems_tcb* current_task,
+ rtems_tcb* started_task)
+{
+ /*
+ * Get the capture task control block so we can trace this
+ * event.
+ */
+ rtems_capture_task_t* ct;
+ rtems_capture_task_t* st;
+
+ ct = current_task->extensions[capture_extension_index];
+ st = started_task->extensions[capture_extension_index];
+
+ /*
+ * The task pointers may not be known as the task may have
+ * been created before the capture engine was open. Add them.
+ */
+
+ if (ct == NULL)
+ ct = rtems_capture_create_capture_task (current_task);
+
+ if (st == NULL)
+ st = rtems_capture_create_capture_task (started_task);
+
+ if (rtems_capture_trigger (ct, st, RTEMS_CAPTURE_START))
+ {
+ rtems_capture_record (ct, RTEMS_CAPTURE_STARTED_BY_EVENT);
+ rtems_capture_record (st, RTEMS_CAPTURE_STARTED_EVENT);
+ }
+
+ rtems_capture_init_stack_usage (st);
+}
+
+/*
+ * rtems_capture_restart_task
+ *
+ * DESCRIPTION:
+ *
+ * This function is called when a task is restarted.
+ *
+ */
+static void
+rtems_capture_restart_task (rtems_tcb* current_task,
+ rtems_tcb* restarted_task)
+{
+ /*
+ * Get the capture task control block so we can trace this
+ * event.
+ */
+ rtems_capture_task_t* ct;
+ rtems_capture_task_t* rt;
+
+ ct = current_task->extensions[capture_extension_index];
+ rt = restarted_task->extensions[capture_extension_index];
+
+ /*
+ * The task pointers may not be known as the task may have
+ * been created before the capture engine was open. Add them.
+ */
+
+ if (ct == NULL)
+ ct = rtems_capture_create_capture_task (current_task);
+
+ if (rt == NULL)
+ rt = rtems_capture_create_capture_task (restarted_task);
+
+ if (rtems_capture_trigger (ct, rt, RTEMS_CAPTURE_RESTART))
+ {
+ rtems_capture_record (ct, RTEMS_CAPTURE_RESTARTED_BY_EVENT);
+ rtems_capture_record (rt, RTEMS_CAPTURE_RESTARTED_EVENT);
+ }
+
+ rtems_capture_task_stack_usage (rt);
+ rtems_capture_init_stack_usage (rt);
+}
+
+/*
+ * rtems_capture_delete_task
+ *
+ * DESCRIPTION:
+ *
+ * This function is called when a task is deleted.
+ *
+ */
+static void
+rtems_capture_delete_task (rtems_tcb* current_task,
+ rtems_tcb* deleted_task)
+{
+ /*
+ * Get the capture task control block so we can trace this
+ * event.
+ */
+ rtems_capture_task_t* ct;
+ rtems_capture_task_t* dt;
+
+ /*
+ * The task pointers may not be known as the task may have
+ * been created before the capture engine was open. Add them.
+ */
+
+ ct = current_task->extensions[capture_extension_index];
+ dt = deleted_task->extensions[capture_extension_index];
+
+ if (ct == NULL)
+ ct = rtems_capture_create_capture_task (current_task);
+
+ if (dt == NULL)
+ dt = rtems_capture_create_capture_task (deleted_task);
+
+ if (rtems_capture_trigger (ct, dt, RTEMS_CAPTURE_DELETE))
+ {
+ rtems_capture_record (ct, RTEMS_CAPTURE_DELETED_BY_EVENT);
+ rtems_capture_record (dt, RTEMS_CAPTURE_DELETED_EVENT);
+ }
+
+ rtems_capture_task_stack_usage (dt);
+
+ /*
+ * This task's tcb will be invalid. This signals the
+ * task has been deleted.
+ */
+ dt->tcb = 0;
+
+ rtems_capture_destroy_capture_task (dt);
+}
+
+/*
+ * rtems_capture_begin_task
+ *
+ * DESCRIPTION:
+ *
+ * This function is called when a task is begun.
+ *
+ */
+static void
+rtems_capture_begin_task (rtems_tcb* begin_task)
+{
+ /*
+ * Get the capture task control block so we can trace this
+ * event.
+ */
+ rtems_capture_task_t* bt;
+
+ bt = begin_task->extensions[capture_extension_index];
+
+ /*
+ * The task pointers may not be known as the task may have
+ * been created before the capture engine was open. Add them.
+ */
+
+ if (bt == NULL)
+ bt = rtems_capture_create_capture_task (begin_task);
+
+ if (rtems_capture_trigger (NULL, bt, RTEMS_CAPTURE_BEGIN))
+ rtems_capture_record (bt, RTEMS_CAPTURE_BEGIN_EVENT);
+}
+
+/*
+ * rtems_capture_exitted_task
+ *
+ * DESCRIPTION:
+ *
+ * This function is called when a task is exitted. That is
+ * returned rather than was deleted.
+ *
+ */
+static void
+rtems_capture_exitted_task (rtems_tcb* exitted_task)
+{
+ /*
+ * Get the capture task control block so we can trace this
+ * event.
+ */
+ rtems_capture_task_t* et;
+
+ et = exitted_task->extensions[capture_extension_index];
+
+ /*
+ * The task pointers may not be known as the task may have
+ * been created before the capture engine was open. Add them.
+ */
+
+ if (et == NULL)
+ et = rtems_capture_create_capture_task (exitted_task);
+
+ if (rtems_capture_trigger (NULL, et, RTEMS_CAPTURE_EXITTED))
+ rtems_capture_record (et, RTEMS_CAPTURE_EXITTED_EVENT);
+
+ rtems_capture_task_stack_usage (et);
+}
+
+/*
+ * rtems_capture_switch_task
+ *
+ * DESCRIPTION:
+ *
+ * This function is called when a context is switched.
+ *
+ */
+static void
+rtems_capture_switch_task (rtems_tcb* current_task,
+ rtems_tcb* heir_task)
+{
+ /*
+ * Only perform context switch trace processing if tracing is
+ * enabled.
+ */
+ if (capture_flags & RTEMS_CAPTURE_ON)
+ {
+ uint32_t ticks;
+ uint32_t tick_offset;
+
+ /*
+ * Get the cpature task control block so we can update the
+ * reference and perform any watch or trigger functions.
+ * The task pointers may not be known as the task may have
+ * been created before the capture engine was open. Add them.
+ */
+ rtems_capture_task_t* ct;
+ rtems_capture_task_t* ht;
+
+
+ if (_States_Is_transient (current_task->current_state)
+ || _States_Is_dormant (current_task->current_state))
+ {
+ rtems_id ct_id = current_task->Object.id;
+
+ for (ct = capture_tasks; ct; ct = ct->forw)
+ if (ct->id == ct_id)
+ break;
+ }
+ else
+ {
+ ct = current_task->extensions[capture_extension_index];
+
+ if (ct == NULL)
+ ct = rtems_capture_create_capture_task (current_task);
+ }
+
+ ht = heir_task->extensions[capture_extension_index];
+
+ if (ht == NULL)
+ ht = rtems_capture_create_capture_task (heir_task);
+
+ /*
+ * Update the execution time. Assume the tick will not overflow
+ * for now. This may need to change.
+ */
+ rtems_capture_get_time (&ticks, &tick_offset);
+
+ /*
+ * We could end up with null pointers for both the current task
+ * and the heir task.
+ */
+
+ if (ht)
+ {
+ ht->in++;
+ ht->ticks_in = ticks;
+ ht->tick_offset_in = tick_offset;
+ }
+
+ if (ct)
+ {
+ ct->out++;
+ ct->ticks += ticks - ct->ticks_in;
+
+ if (capture_timestamp)
+ {
+ tick_offset += capture_tick_period - ct->tick_offset_in;
+
+ if (tick_offset < capture_tick_period)
+ ct->tick_offset = tick_offset;
+ else
+ {
+ ct->ticks++;
+ ct->tick_offset = tick_offset - capture_tick_period;
+ }
+ }
+ else
+ {
+ ct->tick_offset += 100;
+ }
+ }
+
+ if (rtems_capture_trigger (ct, ht, RTEMS_CAPTURE_SWITCH))
+ {
+ rtems_capture_record (ct, RTEMS_CAPTURE_SWITCHED_OUT_EVENT);
+ rtems_capture_record (ht, RTEMS_CAPTURE_SWITCHED_IN_EVENT);
+ }
+ }
+}
+
+/*
+ * rtems_capture_open
+ *
+ * DESCRIPTION:
+ *
+ * This function initialises the realtime capture engine allocating the trace
+ * buffer. It is assumed we have a working heap at stage of initialisation.
+ *
+ */
+rtems_status_code
+rtems_capture_open (uint32_t size, rtems_capture_timestamp timestamp __attribute__((unused)))
+{
+ rtems_extensions_table capture_extensions;
+ rtems_name name;
+ rtems_status_code sc;
+
+ /*
+ * See if the capture engine is already open.
+ */
+
+ if (capture_records)
+ return RTEMS_RESOURCE_IN_USE;
+
+ capture_records = malloc (size * sizeof (rtems_capture_record_t));
+
+ if (capture_records == NULL)
+ return RTEMS_NO_MEMORY;
+
+ capture_size = size;
+ capture_count = 0;
+ capture_in = capture_records;
+ capture_out = 0;
+ capture_flags = 0;
+ capture_tasks = NULL;
+ capture_ceiling = 0;
+ capture_floor = 255;
+
+ /*
+ * Create the extension table. This is copied so we
+ * can create it as a local.
+ */
+ capture_extensions.thread_create = rtems_capture_create_task;
+ capture_extensions.thread_start = rtems_capture_start_task;
+ capture_extensions.thread_restart = rtems_capture_restart_task;
+ capture_extensions.thread_delete = rtems_capture_delete_task;
+ capture_extensions.thread_switch = rtems_capture_switch_task;
+ capture_extensions.thread_begin = rtems_capture_begin_task;
+ capture_extensions.thread_exitted = rtems_capture_exitted_task;
+ capture_extensions.fatal = NULL;
+
+ /*
+ * Get the tick period from the BSP Configuration Table.
+ */
+ capture_tick_period = Configuration.microseconds_per_tick;
+
+ /*
+ * Register the user extension handlers for the CAPture Engine.
+ */
+ name = rtems_build_name ('C', 'A', 'P', 'E');
+ sc = rtems_extension_create (name, &capture_extensions, &capture_id);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ capture_id = 0;
+ free (capture_records);
+ capture_records = NULL;
+ }
+ else
+ {
+ capture_extension_index = rtems_object_id_get_index (capture_id);;
+ }
+
+ /*
+ * Iterate over the list of existing tasks.
+ */
+
+ return sc;
+}
+
+/*
+ * rtems_capture_close
+ *
+ * DESCRIPTION:
+ *
+ * This function shutdowns the capture engine and release any claimed
+ * resources.
+ */
+rtems_status_code
+rtems_capture_close (void)
+{
+ rtems_interrupt_level level;
+ rtems_capture_task_t* task;
+ rtems_capture_control_t* control;
+ rtems_capture_record_t* records;
+ rtems_status_code sc;
+
+ rtems_interrupt_disable (level);
+
+ if (!capture_records)
+ {
+ rtems_interrupt_enable (level);
+ return RTEMS_SUCCESSFUL;
+ }
+
+ capture_flags &= ~(RTEMS_CAPTURE_ON | RTEMS_CAPTURE_ONLY_MONITOR);
+
+ records = capture_records;
+ capture_records = NULL;
+
+ rtems_interrupt_enable (level);
+
+ /*
+ * Delete the extension first. This means we are now able to
+ * release the resources we have without them being used.
+ */
+
+ sc = rtems_extension_delete (capture_id);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ return sc;
+
+ task = capture_tasks;
+
+ while (task)
+ {
+ rtems_capture_task_t* delete = task;
+ task = task->forw;
+ _Workspace_Free (delete);
+ }
+
+ capture_tasks = NULL;
+
+ control = capture_controls;
+
+ while (control)
+ {
+ rtems_capture_control_t* delete = control;
+ control = control->next;
+ _Workspace_Free (delete);
+ }
+
+ capture_controls = NULL;
+
+ if (capture_records)
+ {
+ free (capture_records);
+ capture_records = NULL;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * rtems_capture_control
+ *
+ * DESCRIPTION:
+ *
+ * This function allows control of tracing at a global level.
+ */
+rtems_status_code
+rtems_capture_control (bool enable)
+{
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable (level);
+
+ if (!capture_records)
+ {
+ rtems_interrupt_enable (level);
+ return RTEMS_UNSATISFIED;
+ }
+
+ if (enable)
+ capture_flags |= RTEMS_CAPTURE_ON;
+ else
+ capture_flags &= ~RTEMS_CAPTURE_ON;
+
+ rtems_interrupt_enable (level);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * rtems_capture_monitor
+ *
+ * DESCRIPTION:
+ *
+ * This function enable the monitor mode. When in the monitor mode
+ * the tasks are monitored but no data is saved. This can be used
+ * to profile the load on a system.
+ */
+rtems_status_code
+rtems_capture_monitor (bool enable)
+{
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable (level);
+
+ if (!capture_records)
+ {
+ rtems_interrupt_enable (level);
+ return RTEMS_UNSATISFIED;
+ }
+
+ if (enable)
+ capture_flags |= RTEMS_CAPTURE_ONLY_MONITOR;
+ else
+ capture_flags &= ~RTEMS_CAPTURE_ONLY_MONITOR;
+
+ rtems_interrupt_enable (level);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * rtems_capture_flush
+ *
+ * DESCRIPTION:
+ *
+ * This function flushes the capture buffer. The prime parameter allows the
+ * capture engine to also be primed again.
+ */
+rtems_status_code
+rtems_capture_flush (bool prime)
+{
+ rtems_interrupt_level level;
+ rtems_capture_task_t* task;
+
+ rtems_interrupt_disable (level);
+
+ for (task = capture_tasks; task != NULL; task = task->forw)
+ {
+ task->flags &= ~RTEMS_CAPTURE_TRACED;
+ task->refcount = 0;
+ }
+
+ if (prime)
+ capture_flags &= ~(RTEMS_CAPTURE_TRIGGERED | RTEMS_CAPTURE_OVERFLOW);
+ else
+ capture_flags &= ~RTEMS_CAPTURE_OVERFLOW;
+
+ capture_count = 0;
+ capture_in = capture_records;
+ capture_out = 0;
+
+ rtems_interrupt_enable (level);
+
+ task = capture_tasks;
+
+ while (task)
+ {
+ rtems_capture_task_t* check = task;
+ task = task->forw;
+ rtems_capture_destroy_capture_task (check);
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * rtems_capture_watch_add
+ *
+ * DESCRIPTION:
+ *
+ * This function defines a watch for a specific task given a name. A watch
+ * causes it to be traced either in or out of context. The watch can be
+ * optionally enabled or disabled with the set routine. It is disabled by
+ * default.
+ */
+rtems_status_code
+rtems_capture_watch_add (rtems_name name, rtems_id id)
+{
+ rtems_capture_control_t* control;
+
+ if ((name == 0) && (id == 0))
+ return RTEMS_UNSATISFIED;
+
+ control = rtems_capture_find_control (name, id);
+
+ if (control && !id)
+ return RTEMS_TOO_MANY;
+
+ if (!control)
+ control = rtems_capture_create_control (name, id);
+
+ if (!control)
+ return RTEMS_NO_MEMORY;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * rtems_capture_watch_del
+ *
+ * DESCRIPTION:
+ *
+ * This function removes a watch for a specific task given a name. The task
+ * description will still exist if referenced by a trace record in the trace
+ * buffer or a global watch is defined.
+ */
+rtems_status_code
+rtems_capture_watch_del (rtems_name name, rtems_id id)
+{
+ rtems_interrupt_level level;
+ rtems_capture_control_t* control;
+ rtems_capture_control_t** prev_control;
+ rtems_capture_task_t* task;
+ bool found = false;
+
+ /*
+ * Should this test be for wildcards ?
+ */
+
+ for (prev_control = &capture_controls, control = capture_controls;
+ control != NULL; )
+ {
+ if (rtems_capture_match_name_id (control->name, control->id, name, id))
+ {
+ rtems_interrupt_disable (level);
+
+ for (task = capture_tasks; task != NULL; task = task->forw)
+ if (task->control == control)
+ task->control = 0;
+
+ *prev_control = control->next;
+
+ rtems_interrupt_enable (level);
+
+ _Workspace_Free (control);
+
+ control = *prev_control;
+
+ found = true;
+ }
+ else
+ {
+ prev_control = &control->next;
+ control = control->next;
+ }
+ }
+
+ if (found)
+ return RTEMS_SUCCESSFUL;
+
+ return RTEMS_INVALID_NAME;
+}
+
+/*
+ * rtems_capture_watch_set
+ *
+ * DESCRIPTION:
+ *
+ * This function allows control of a watch. The watch can be enabled or
+ * disabled.
+ */
+rtems_status_code
+rtems_capture_watch_ctrl (rtems_name name, rtems_id id, bool enable)
+{
+ rtems_interrupt_level level;
+ rtems_capture_control_t* control;
+ bool found = false;
+
+ /*
+ * Find the control and then set the watch. It must exist before it can
+ * be controlled.
+ */
+ for (control = capture_controls; control != NULL; control = control->next)
+ {
+ if (rtems_capture_match_name_id (control->name, control->id, name, id))
+ {
+ rtems_interrupt_disable (level);
+
+ if (enable)
+ control->flags |= RTEMS_CAPTURE_WATCH;
+ else
+ control->flags &= ~RTEMS_CAPTURE_WATCH;
+
+ rtems_interrupt_enable (level);
+
+ found = true;
+ }
+ }
+
+ if (found)
+ return RTEMS_SUCCESSFUL;
+
+ return RTEMS_INVALID_NAME;
+}
+
+/*
+ * rtems_capture_watch_global
+ *
+ * DESCRIPTION:
+ *
+ * This function allows control of a global watch. The watch can be enabled or
+ * disabled. A global watch configures all tasks below the ceiling and above
+ * the floor to be traced.
+ */
+rtems_status_code
+rtems_capture_watch_global (bool enable)
+{
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable (level);
+
+ /*
+ * We need to keep specific and global watches separate so
+ * a global enable/disable does not lose a specific watch.
+ */
+ if (enable)
+ capture_flags |= RTEMS_CAPTURE_GLOBAL_WATCH;
+ else
+ capture_flags &= ~RTEMS_CAPTURE_GLOBAL_WATCH;
+
+ rtems_interrupt_enable (level);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * rtems_capture_watch_global_on
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the global watch state.
+ */
+bool
+rtems_capture_watch_global_on (void)
+{
+ return capture_flags & RTEMS_CAPTURE_GLOBAL_WATCH ? 1 : 0;
+}
+
+/*
+ * rtems_capture_watch_ceiling
+ *
+ * DESCRIPTION:
+ *
+ * This function sets a watch ceiling. Tasks at or greating that the
+ * ceiling priority are not watched. This is a simple way to monitor
+ * an application and exclude system tasks running at a higher
+ * priority level.
+ */
+rtems_status_code
+rtems_capture_watch_ceiling (rtems_task_priority ceiling)
+{
+ capture_ceiling = ceiling;
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * rtems_capture_watch_get_ceiling
+ *
+ * DESCRIPTION:
+ *
+ * This function gets the watch ceiling.
+ */
+rtems_task_priority
+rtems_capture_watch_get_ceiling (void)
+{
+ return capture_ceiling;
+}
+
+/*
+ * rtems_capture_watch_floor
+ *
+ * DESCRIPTION:
+ *
+ * This function sets a watch floor. Tasks at or less that the
+ * floor priority are not watched. This is a simple way to monitor
+ * an application and exclude system tasks running at a lower
+ * priority level.
+ */
+rtems_status_code
+rtems_capture_watch_floor (rtems_task_priority floor)
+{
+ capture_floor = floor;
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * rtems_capture_watch_get_floor
+ *
+ * DESCRIPTION:
+ *
+ * This function gets the watch floor.
+ */
+rtems_task_priority
+rtems_capture_watch_get_floor (void)
+{
+ return capture_floor;
+}
+
+/*
+ * rtems_capture_map_trigger
+ *
+ * DESCRIPTION:
+ *
+ * Map the trigger to a bit mask.
+ *
+ */
+uint32_t
+rtems_capture_map_trigger (rtems_capture_trigger_t trigger)
+{
+ /*
+ * Transform the mode and trigger to a bit map.
+ */
+ switch (trigger)
+ {
+ case rtems_capture_switch:
+ return RTEMS_CAPTURE_SWITCH;
+ case rtems_capture_create:
+ return RTEMS_CAPTURE_CREATE;
+ case rtems_capture_start:
+ return RTEMS_CAPTURE_START;
+ case rtems_capture_restart:
+ return RTEMS_CAPTURE_RESTART;
+ case rtems_capture_delete:
+ return RTEMS_CAPTURE_DELETE;
+ case rtems_capture_begin:
+ return RTEMS_CAPTURE_BEGIN;
+ case rtems_capture_exitted:
+ return RTEMS_CAPTURE_EXITTED;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/*
+ * rtems_capture_set_trigger
+ *
+ * DESCRIPTION:
+ *
+ * This function sets a trigger.
+ *
+ * This set trigger routine will create a capture control for the
+ * target task. The task list is searched and any existing tasks
+ * are linked to the new control.
+ *
+ * We can have a number of tasks that have the same name so we
+ * search using names. This means a number of tasks can be
+ * linked to single control.
+ */
+rtems_status_code
+rtems_capture_set_trigger (rtems_name from_name,
+ rtems_id from_id,
+ rtems_name to_name,
+ rtems_id to_id,
+ rtems_capture_trigger_mode_t mode,
+ rtems_capture_trigger_t trigger)
+{
+ rtems_capture_control_t* control;
+ uint32_t flags;
+
+ flags = rtems_capture_map_trigger (trigger);
+
+ /*
+ * The mode sets the opposite type of trigger. For example
+ * FROM ANY means trigger when the event happens TO this
+ * task. TO ANY means FROM this task.
+ */
+
+ if (mode == rtems_capture_to_any)
+ {
+ control = rtems_capture_create_control (from_name, from_id);
+ if (control == NULL)
+ return RTEMS_NO_MEMORY;
+ control->from_triggers |= flags & RTEMS_CAPTURE_FROM_TRIGS;
+ }
+ else
+ {
+ control = rtems_capture_create_control (to_name, to_id);
+ if (control == NULL)
+ return RTEMS_NO_MEMORY;
+ if (mode == rtems_capture_from_any)
+ control->to_triggers |= flags;
+ else
+ {
+ bool done = false;
+ int i;
+
+ control->by_triggers |= flags;
+
+ for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
+ {
+ if (rtems_capture_control_by_valid (control, i) &&
+ ((control->by[i].name == from_name) ||
+ (from_id && (control->by[i].id == from_id))))
+ {
+ control->by[i].trigger |= flags;
+ done = true;
+ break;
+ }
+ }
+
+ if (!done)
+ {
+ for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
+ {
+ if (!rtems_capture_control_by_valid (control, i))
+ {
+ control->by_valid |= RTEMS_CAPTURE_CONTROL_FROM_MASK (i);
+ control->by[i].name = from_name;
+ control->by[i].id = from_id;
+ control->by[i].trigger = flags;
+ done = true;
+ break;
+ }
+ }
+ }
+
+ if (!done)
+ return RTEMS_TOO_MANY;
+ }
+ }
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * rtems_capture_clear_trigger
+ *
+ * DESCRIPTION:
+ *
+ * This function clear a trigger.
+ */
+rtems_status_code
+rtems_capture_clear_trigger (rtems_name from_name,
+ rtems_id from_id,
+ rtems_name to_name,
+ rtems_id to_id,
+ rtems_capture_trigger_mode_t mode,
+ rtems_capture_trigger_t trigger)
+{
+ rtems_capture_control_t* control;
+ uint32_t flags;
+
+ flags = rtems_capture_map_trigger (trigger);
+
+ if (mode == rtems_capture_to_any)
+ {
+ control = rtems_capture_find_control (from_name, from_id);
+ if (control == NULL)
+ {
+ if (from_id)
+ return RTEMS_INVALID_ID;
+ return RTEMS_INVALID_NAME;
+ }
+ control->from_triggers &= ~flags;
+ }
+ else
+ {
+ control = rtems_capture_find_control (to_name, to_id);
+ if (control == NULL)
+ {
+ if (to_id)
+ return RTEMS_INVALID_ID;
+ return RTEMS_INVALID_NAME;
+ }
+ if (mode == rtems_capture_from_any)
+ control->to_triggers &= ~flags;
+ else
+ {
+ bool done = false;
+ int i;
+
+ control->by_triggers &= ~flags;
+
+ for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
+ {
+ if (rtems_capture_control_by_valid (control, i) &&
+ ((control->by[i].name == from_name) ||
+ (control->by[i].id == from_id)))
+ {
+ control->by[i].trigger &= ~trigger;
+ if (control->by[i].trigger == 0)
+ control->by_valid &= ~RTEMS_CAPTURE_CONTROL_FROM_MASK (i);
+ done = true;
+ break;
+ }
+ }
+
+ if (!done)
+ {
+ if (from_id)
+ return RTEMS_INVALID_ID;
+ return RTEMS_INVALID_NAME;
+ }
+ }
+ }
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * rtems_capture_read
+ *
+ * DESCRIPTION:
+ *
+ * This function reads a number of records from the capture buffer.
+ * The user can optionally block and wait until the buffer as a
+ * specific number of records available or a specific time has
+ * elasped.
+ *
+ * The function returns the number of record that is has that are
+ * in a continous block of memory. If the number of available records
+ * wrap then only those records are provided. This removes the need for
+ * caller to be concerned about buffer wrappings. If the number of
+ * requested records cannot be met due to the wrapping of the records
+ * less than the specified number will be returned.
+ *
+ * The user must release the records. This is achieved with a call to
+ * rtems_capture_release. Calls this function without a release will
+ * result in at least the same number of records being released.
+ *
+ * The 'threshold' parameter is the number of records that must be
+ * captured before returning. If a timeout period is specified (non-0)
+ * any captured records will be returned. These parameters stop
+ * thrashing occuring for a small number of records, yet allows
+ * a user configured latiency to be applied for single events.
+ *
+ * The 'timeout' parameter is in micro-seconds. A value of 0 will disable
+ * the timeout.
+ *
+ */
+rtems_status_code
+rtems_capture_read (uint32_t threshold,
+ uint32_t timeout,
+ uint32_t* read,
+ rtems_capture_record_t** recs)
+{
+ rtems_interrupt_level level;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ uint32_t count;
+
+ *read = 0;
+ *recs = NULL;
+
+ rtems_interrupt_disable (level);
+
+ /*
+ * Only one reader is allowed.
+ */
+
+ if (capture_flags & RTEMS_CAPTURE_READER_ACTIVE)
+ {
+ rtems_interrupt_enable (level);
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ capture_flags |= RTEMS_CAPTURE_READER_ACTIVE;
+ *read = count = capture_count;
+
+ rtems_interrupt_enable (level);
+
+ *recs = &capture_records[capture_out];
+
+ for (;;)
+ {
+ /*
+ * See if the count wraps the end of the record buffer.
+ */
+ if (count && ((capture_out + count) >= capture_size))
+ *read = capture_size - capture_out;
+
+ /*
+ * Do we have a threshold and the current count has not wrapped
+ * around the end of the capture record buffer ?
+ */
+ if ((*read == count) && threshold)
+ {
+ /*
+ * Do we have enough records ?
+ */
+ if (*read < threshold)
+ {
+ rtems_event_set event_out;
+
+ rtems_task_ident (RTEMS_SELF, RTEMS_LOCAL, &capture_reader);
+
+ rtems_interrupt_disable (level);
+
+ capture_flags |= RTEMS_CAPTURE_READER_WAITING;
+
+ rtems_interrupt_enable (level);
+
+ sc = rtems_event_receive (RTEMS_EVENT_0,
+ RTEMS_WAIT | RTEMS_EVENT_ANY,
+ RTEMS_MICROSECONDS_TO_TICKS (timeout),
+ &event_out);
+
+ /*
+ * Let the user handle all other sorts of errors. This may
+ * not be the best solution, but oh well, it will do for
+ * now.
+ */
+ if ((sc != RTEMS_SUCCESSFUL) && (sc != RTEMS_TIMEOUT))
+ break;
+
+ rtems_interrupt_disable (level);
+
+ *read = count = capture_count;
+
+ rtems_interrupt_enable (level);
+
+ continue;
+ }
+ }
+
+ /*
+ * Always out if we reach here. To loop use continue.
+ */
+ break;
+ }
+
+ return sc;
+}
+
+/*
+ * rtems_capture_release
+ *
+ * DESCRIPTION:
+ *
+ * This function releases the requested number of record slots back
+ * to the capture engine. The count must match the number read.
+ */
+rtems_status_code
+rtems_capture_release (uint32_t count)
+{
+ rtems_capture_record_t* rec;
+ uint32_t counted;
+
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable (level);
+
+ if (count > capture_count)
+ count = capture_count;
+
+ rtems_interrupt_enable (level);
+
+ counted = count;
+
+ rec = &capture_records[capture_out];
+
+ while (counted--)
+ {
+ rtems_capture_refcount_down (rec->task);
+ rtems_capture_destroy_capture_task (rec->task);
+ rec++;
+ }
+
+ rtems_interrupt_disable (level);
+
+ capture_count -= count;
+
+ capture_out = (capture_out + count) % capture_size;
+
+ capture_flags &= ~RTEMS_CAPTURE_READER_ACTIVE;
+
+ rtems_interrupt_enable (level);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * rtems_capture_tick_time
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the tick period in nano-seconds.
+ */
+uint32_t
+rtems_capture_tick_time (void)
+{
+ return capture_tick_period;
+}
+
+/*
+ * rtems_capture_event_text
+ *
+ * DESCRIPTION:
+ *
+ * This function returns a string for an event based on the bit in the
+ * event. The functions takes the bit offset as a number not the bit
+ * set in a bit map.
+ */
+const char*
+rtems_capture_event_text (int event)
+{
+ if ((event < RTEMS_CAPTURE_EVENT_START) || (event > RTEMS_CAPTURE_EVENT_END))
+ return "invalid event id";
+ return capture_event_text[event - RTEMS_CAPTURE_EVENT_START];
+}
+
+/*
+ * rtems_capture_get_task_list
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the head of the list of tasks that the
+ * capture engine has detected.
+ */
+rtems_capture_task_t*
+rtems_capture_get_task_list (void)
+{
+ return capture_tasks;
+}
+
+/*
+ * rtems_capture_task_stack_usage
+ *
+ * DESCRIPTION:
+ *
+ * This function updates the stack usage. The task control block
+ * is updated.
+ */
+uint32_t
+rtems_capture_task_stack_usage (rtems_capture_task_t* task)
+{
+ if (task->tcb)
+ {
+ uint32_t* st;
+ uint32_t* s;
+
+ /*
+ * @todo: Assumes all stacks move the same way.
+ */
+ st = task->tcb->Start.Initial_stack.area + task->stack_size;
+ s = task->tcb->Start.Initial_stack.area;
+
+ while (s < st)
+ {
+ if (*s != 0xdeaddead)
+ break;
+ s++;
+ }
+
+ task->stack_clean =
+ s - (uint32_t*) task->tcb->Start.Initial_stack.area;
+ }
+
+ return task->stack_clean;
+}
+
+/*
+ * rtems_capture_get_control_list
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the head of the list of control in the
+ * capture engine.
+ */
+rtems_capture_control_t*
+rtems_capture_get_control_list (void)
+{
+ return capture_controls;
+}
diff --git a/cpukit/libmisc/capture/capture.h b/cpukit/libmisc/capture/capture.h
new file mode 100644
index 0000000000..48ba5ebec4
--- /dev/null
+++ b/cpukit/libmisc/capture/capture.h
@@ -0,0 +1,1042 @@
+/**
+ * @file rtems/capture.h
+ */
+
+/*
+ ------------------------------------------------------------------------
+ $Id$
+ ------------------------------------------------------------------------
+
+ Copyright Objective Design Systems Pty Ltd, 2002
+ All rights reserved Objective Design Systems Pty Ltd, 2002
+ Chris Johns (ccj@acm.org)
+
+ COPYRIGHT (c) 1989-1998.
+ On-Line Applications Research Corporation (OAR).
+
+ The license and distribution terms for this file may be
+ found in the file LICENSE in this distribution.
+
+ This software with is provided ``as is'' and with NO WARRANTY.
+
+ ------------------------------------------------------------------------
+
+ RTEMS Performance Monitoring and Measurement Framework.
+ This is the Capture Engine component.
+
+*/
+
+#ifndef __CAPTURE_H_
+#define __CAPTURE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+
+/**
+ * The number of tasks in a trigger group.
+ */
+#define RTEMS_CAPTURE_TRIGGER_TASKS (32)
+
+/**
+ * rtems_capture_from_t
+ *
+ * DESCRIPTION:
+ *
+ * A from capture is a task id and a mask for the type of
+ * from trigger we are interested in. The mask uses the same
+ * bit maps as the flags field in the control structure. There
+ * will only be a from type trigger if the flags in the control
+ * structure has the specific *_BY bit set.
+ */
+typedef struct rtems_capture_from_s
+{
+ rtems_name name;
+ rtems_id id;
+ uint32_t trigger;
+} rtems_capture_from_t;
+
+/**
+ * rtems_capture_control_t
+ *
+ * DESCRIPTION:
+ *
+ * RTEMS control holds the trigger and watch configuration for a group of
+ * tasks with the same name. The flags hold global control flags.
+ *
+ * The to_triggers fields holds triggers TO this task. The from_triggers holds
+ * triggers from this task. The by_triggers is an OR or triggers which are
+ * caused BY the task listed TO this task. The by_valid flag which entries
+ * in by are valid.
+ */
+typedef struct rtems_capture_control_s
+{
+ rtems_name name;
+ rtems_id id;
+ uint32_t flags;
+ uint32_t to_triggers;
+ uint32_t from_triggers;
+ uint32_t by_triggers;
+ uint32_t by_valid;
+ rtems_capture_from_t by[RTEMS_CAPTURE_TRIGGER_TASKS];
+ struct rtems_capture_control_s* next;
+} rtems_capture_control_t;
+
+/**
+ * The from_valid mask.
+ */
+#define RTEMS_CAPTURE_CONTROL_FROM_MASK(_s) \
+ (UINT32_C(1) << (RTEMS_CAPTURE_TRIGGER_TASKS - ((_s) + 1)))
+
+/**
+ * Control flags.
+ */
+#define RTEMS_CAPTURE_WATCH (1 << 0)
+
+/**
+ * Control triggers.
+ */
+#define RTEMS_CAPTURE_SWITCH (1 << 0)
+#define RTEMS_CAPTURE_CREATE (1 << 1)
+#define RTEMS_CAPTURE_START (1 << 2)
+#define RTEMS_CAPTURE_RESTART (1 << 3)
+#define RTEMS_CAPTURE_DELETE (1 << 4)
+#define RTEMS_CAPTURE_BEGIN (1 << 5)
+#define RTEMS_CAPTURE_EXITTED (1 << 6)
+
+#define RTEMS_CAPTURE_FROM_TRIGS (RTEMS_CAPTURE_SWITCH | \
+ RTEMS_CAPTURE_CREATE | \
+ RTEMS_CAPTURE_START | \
+ RTEMS_CAPTURE_RESTART | \
+ RTEMS_CAPTURE_DELETE)
+
+#define RTEMS_CAPTURE_TO_TRIGS (RTEMS_CAPTURE_SWITCH | \
+ RTEMS_CAPTURE_CREATE | \
+ RTEMS_CAPTURE_START | \
+ RTEMS_CAPTURE_RESTART | \
+ RTEMS_CAPTURE_DELETE | \
+ RTEMS_CAPTURE_BEGIN | \
+ RTEMS_CAPTURE_EXITTED)
+
+/**
+ * rtems_capture_task_t
+ *
+ * DESCRIPTION:
+ *
+ * RTEMS capture control provdes the information about a task, along
+ * with its trigger state. The control is referenced by each
+ * capture record. This is information neeed by the decoder. The
+ * capture record cannot assume the task will exist when the record is
+ * dumped via the target interface so task info needed for tracing is
+ * copied and held here. Once the references in the trace buffer
+ * have been removed and the task is deleted this structure is
+ * released back to the heap.
+ *
+ * The inline helper functions provide more details about the info
+ * contained in this structure.
+ *
+ * Note, the tracer code exploits the fact an rtems_name is a
+ * 32bit value.
+ */
+typedef struct rtems_capture_task_s
+{
+ rtems_name name;
+ rtems_id id;
+ uint32_t flags;
+ uint32_t refcount;
+ rtems_tcb* tcb;
+ uint32_t in;
+ uint32_t out;
+ rtems_task_priority start_priority;
+ uint32_t stack_size;
+ uint32_t stack_clean;
+ uint32_t ticks;
+ uint32_t tick_offset;
+ uint32_t ticks_in;
+ uint32_t tick_offset_in;
+ uint32_t last_ticks;
+ uint32_t last_tick_offset;
+ rtems_capture_control_t* control;
+ struct rtems_capture_task_s* forw;
+ struct rtems_capture_task_s* back;
+} rtems_capture_task_t;
+
+/**
+ * Task flags.
+ */
+#define RTEMS_CAPTURE_TRACED (1 << 0)
+
+/*
+ * rtems_capture_record_t
+ *
+ * DESCRIPTION:
+ *
+ * RTEMS capture record. This is a record that is written into
+ * the buffer. The events includes the priority of the task
+ * at the time of the context switch.
+ */
+typedef struct rtems_capture_record_s
+{
+ rtems_capture_task_t* task;
+ uint32_t events;
+ uint32_t ticks;
+ uint32_t tick_offset;
+} rtems_capture_record_t;
+
+/**
+ * The capture record event flags.
+ */
+#define RTEMS_CAPTURE_REAL_PRI_EVENT_MASK UINT32_C (0x000000ff)
+#define RTEMS_CAPTURE_CURR_PRI_EVENT_MASK UINT32_C (0x0000ff00)
+#define RTEMS_CAPTURE_REAL_PRIORITY_EVENT (0)
+#define RTEMS_CAPTURE_CURR_PRIORITY_EVENT (8)
+#define RTEMS_CAPTURE_EVENT_START (16)
+#define RTEMS_CAPTURE_CREATED_BY_EVENT UINT32_C (0x00010000)
+#define RTEMS_CAPTURE_CREATED_EVENT UINT32_C (0x00020000)
+#define RTEMS_CAPTURE_STARTED_BY_EVENT UINT32_C (0x00040000)
+#define RTEMS_CAPTURE_STARTED_EVENT UINT32_C (0x00080000)
+#define RTEMS_CAPTURE_RESTARTED_BY_EVENT UINT32_C (0x00100000)
+#define RTEMS_CAPTURE_RESTARTED_EVENT UINT32_C (0x00200000)
+#define RTEMS_CAPTURE_DELETED_BY_EVENT UINT32_C (0x00400000)
+#define RTEMS_CAPTURE_DELETED_EVENT UINT32_C (0x00800000)
+#define RTEMS_CAPTURE_BEGIN_EVENT UINT32_C (0x01000000)
+#define RTEMS_CAPTURE_EXITTED_EVENT UINT32_C (0x02000000)
+#define RTEMS_CAPTURE_SWITCHED_OUT_EVENT UINT32_C (0x04000000)
+#define RTEMS_CAPTURE_SWITCHED_IN_EVENT UINT32_C (0x08000000)
+#define RTEMS_CAPTURE_TIMESTAMP UINT32_C (0x10000000)
+#define RTEMS_CAPTURE_EVENT_END (28)
+
+/**
+ * rtems_capture_trigger_mode_t
+ *
+ * DESCRIPTION:
+ *
+ * The types of trigger modes that exist.
+ */
+typedef enum rtems_capture_trigger_mode_e
+{
+ rtems_capture_to_any,
+ rtems_capture_from_any,
+ rtems_capture_from_to
+} rtems_capture_trigger_mode_t;
+
+/**
+ * rtems_capture_trigger_t
+ *
+ * DESCRIPTION:
+ *
+ * The types of triggers that exist.
+ */
+typedef enum rtems_capture_trigger_e
+{
+ rtems_capture_switch,
+ rtems_capture_create,
+ rtems_capture_start,
+ rtems_capture_restart,
+ rtems_capture_delete,
+ rtems_capture_begin,
+ rtems_capture_exitted
+} rtems_capture_trigger_t;
+
+/**
+ * rtems_capture_timestamp
+ *
+ * DESCRIPTION:
+ *
+ * This defines the callout handler to obtain a time stamp. The
+ * value returned is time count since the last read.
+ *
+ */
+
+typedef void (*rtems_capture_timestamp)
+ (uint32_t* ticks, uint32_t* micro);
+
+/**
+ * rtems_capture_open
+ *
+ * DESCRIPTION:
+ *
+ * This function initialises the realtime trace manager allocating the
+ * capture buffer. It is assumed we have a working heap at stage of
+ * initialisation.
+ *
+ */
+rtems_status_code
+rtems_capture_open (uint32_t size,
+ rtems_capture_timestamp timestamp);
+
+/**
+ * rtems_capture_close
+ *
+ * DESCRIPTION:
+ *
+ * This function shutdowns the tracer and release any claimed
+ * resources.
+ */
+rtems_status_code
+rtems_capture_close (void);
+
+/**
+ * rtems_capture_control
+ *
+ * DESCRIPTION:
+ *
+ * This function allows control of tracing at a global level.
+ */
+rtems_status_code
+rtems_capture_control (bool enable);
+
+/**
+ * rtems_capture_monitor
+ *
+ * DESCRIPTION:
+ *
+ * This function enable the monitor mode. When in the monitor mode
+ * the tasks are monitored but no data is saved. This can be used
+ * to profile the load on a system.
+ */
+rtems_status_code
+rtems_capture_monitor (bool enable);
+
+/*
+ * rtems_capture_flush
+ *
+ * DESCRIPTION:
+ *
+ * This function flushes the trace buffer. The prime parameter allows the
+ * capture engine to also be primed again.
+ */
+rtems_status_code
+rtems_capture_flush (bool prime);
+
+/**
+ * rtems_capture_watch_add
+ *
+ * DESCRIPTION:
+ *
+ * This function defines a watch for a specific task given a name. A watch
+ * causes it to be traced either in or out of context. The watch can be
+ * optionally enabled or disabled with the set routine. It is disabled by
+ * default.
+ */
+rtems_status_code
+rtems_capture_watch_add (rtems_name name, rtems_id id);
+
+/**
+ * rtems_capture_watch_del
+ *
+ * DESCRIPTION:
+ *
+ * This function removes a watch for a specific task given a name. The task
+ * description will still exist if referenced by a trace record in the trace
+ * buffer or a global watch is defined.
+ */
+rtems_status_code
+rtems_capture_watch_del (rtems_name name, rtems_id id);
+
+/**
+ * rtems_capture_watch_set
+ *
+ * DESCRIPTION:
+ *
+ * This function allows control of a watch. The watch can be enabled or
+ * disabled.
+ */
+rtems_status_code
+rtems_capture_watch_ctrl (rtems_name name,
+ rtems_id id,
+ bool enable);
+
+/**
+ * rtems_capture_watch_global
+ *
+ * DESCRIPTION:
+ *
+ * This function allows control of a global watch. The watch can
+ * be enabled or disabled. A global watch configures all tasks below
+ * the ceiling and above the floor to be traced.
+ */
+rtems_status_code
+rtems_capture_watch_global (bool enable);
+
+/**
+ * rtems_capture_watch_global_on
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the global watch state.
+ */
+bool
+rtems_capture_watch_global_on (void);
+
+/**
+ * rtems_capture_watch_ceiling
+ *
+ * DESCRIPTION:
+ *
+ * This function sets a watch ceiling. Tasks at or greating that the
+ * ceiling priority are not watched. This is a simple way to monitor
+ * an application and exclude system tasks running at a higher
+ * priority level.
+ */
+rtems_status_code
+rtems_capture_watch_ceiling (rtems_task_priority ceiling);
+
+/**
+ * rtems_capture_watch_get_ceiling
+ *
+ * DESCRIPTION:
+ *
+ * This function gets the watch ceiling.
+ */
+rtems_task_priority
+rtems_capture_watch_get_ceiling (void);
+
+/**
+ * rtems_capture_watch_floor
+ *
+ * DESCRIPTION:
+ *
+ * This function sets a watch floor. Tasks at or less that the
+ * floor priority are not watched. This is a simple way to monitor
+ * an application and exclude system tasks running at a lower
+ * priority level.
+ */
+rtems_status_code
+rtems_capture_watch_floor (rtems_task_priority floor);
+
+/**
+ * rtems_capture_watch_get_floor
+ *
+ * DESCRIPTION:
+ *
+ * This function gets the watch floor.
+ */
+rtems_task_priority
+rtems_capture_watch_get_floor (void);
+
+/**
+ * rtems_capture_set_trigger
+ *
+ * DESCRIPTION:
+ *
+ * This function sets a trigger.
+ *
+ * This set trigger routine will create a trace control for the
+ * target task. The task list is searched and any existing tasks
+ * are linked to the new control.
+ *
+ * We can have a number of tasks that have the same name so we
+ * search using names. This means a number of tasks can be
+ * linked to single control.
+ */
+rtems_status_code
+rtems_capture_set_trigger (rtems_name from_name,
+ rtems_id from_id,
+ rtems_name to_name,
+ rtems_id to_id,
+ rtems_capture_trigger_mode_t mode,
+ rtems_capture_trigger_t trigger);
+
+/**
+ * rtems_capture_clear_trigger
+ *
+ * DESCRIPTION:
+ *
+ * This function clears a trigger.
+ *
+ * This clear trigger routine will not clear a watch.
+ */
+rtems_status_code
+rtems_capture_clear_trigger (rtems_name from_name,
+ rtems_id from_id,
+ rtems_name to_name,
+ rtems_id to_id,
+ rtems_capture_trigger_mode_t mode,
+ rtems_capture_trigger_t trigger);
+
+/**
+ * rtems_capture_read
+ *
+ * DESCRIPTION:
+ *
+ * This function reads a number of records from the capture buffer.
+ * The user can optionally block and wait until the buffer as a
+ * specific number of records available or a specific time has
+ * elasped.
+ *
+ * The function returns the number of record that is has that are
+ * in a continous block of memory. If the number of available records
+ * wrap then only those records are provided. This removes the need for
+ * caller to be concerned about buffer wrappings. If the number of
+ * requested records cannot be met due to the wrapping of the records
+ * less than the specified number will be returned.
+ *
+ * The user must release the records. This is achieved with a call to
+ * rtems_capture_release. Calls this function without a release will
+ * result in at least the same number of records being released.
+ *
+ * The 'threshold' parameter is the number of records that must be
+ * captured before returning. If a timeout period is specified (non-0)
+ * any captured records will be returned. These parameters stop
+ * thrashing occuring for a small number of records, yet allows
+ * a user configured latiency to be applied for single events.
+ *
+ * The 'timeout' parameter is in micro-seconds. A value of 0 will
+ * disable the timeout.
+ *
+ */
+rtems_status_code
+rtems_capture_read (uint32_t threshold,
+ uint32_t timeout,
+ uint32_t* read,
+ rtems_capture_record_t** recs);
+
+/**
+ * rtems_capture_release
+ *
+ * DESCRIPTION:
+ *
+ * This function releases the requested number of record slots back
+ * to the capture engine. The count must match the number read.
+ */
+rtems_status_code
+rtems_capture_release (uint32_t count);
+
+/**
+ * rtems_capture_tick_time
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the tick period in micro-seconds.
+ */
+uint32_t
+rtems_capture_tick_time (void);
+
+/*
+ * rtems_capture_tick_time
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the tick period in micro-seconds.
+ */
+uint32_t
+rtems_capture_tick_time (void);
+
+/**
+ * rtems_capture_event_text
+ *
+ * DESCRIPTION:
+ *
+ * This function returns a string for an event based on the bit in the
+ * event. The functions takes the bit offset as a number not the bit
+ * set in a bit map.
+ */
+const char*
+rtems_capture_event_text (int event);
+
+/**
+ * rtems_capture_get_task_list
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the head of the list of tasks that the
+ * capture engine has detected.
+ */
+rtems_capture_task_t*
+rtems_capture_get_task_list (void);
+
+/**
+ * rtems_capture_next_task
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the pointer to the next task in the list. The
+ * pointer NULL terminates the list.
+ */
+static inline rtems_capture_task_t*
+rtems_capture_next_task (rtems_capture_task_t* task)
+{
+ return task->forw;
+}
+
+/**
+ * rtems_capture_task_valid
+ *
+ * DESCRIPTION:
+ *
+ * This function returns true if the task control block points to
+ * a valid task.
+ */
+static inline bool
+rtems_capture_task_valid (rtems_capture_task_t* task)
+{
+ return task->tcb != NULL;
+}
+
+/**
+ * rtems_capture_task_id
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the task id.
+ */
+static inline rtems_id
+rtems_capture_task_id (rtems_capture_task_t* task)
+{
+ return task->id;
+}
+
+/**
+ * rtems_capture_task_state
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the task state.
+ */
+static inline States_Control
+rtems_capture_task_state (rtems_capture_task_t* task)
+{
+ if (rtems_capture_task_valid (task))
+ return task->tcb->current_state;
+ return 0;
+}
+
+/**
+ * rtems_capture_task_name
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the task name.
+ */
+static inline rtems_name
+rtems_capture_task_name (rtems_capture_task_t* task)
+{
+ return task->name;
+}
+
+/**
+ * rtems_capture_task_flags
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the task flags.
+ */
+static inline uint32_t
+rtems_capture_task_flags (rtems_capture_task_t* task)
+{
+ return task->flags;
+}
+
+/**
+ * rtems_capture_task_control
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the task control if present.
+ */
+static inline rtems_capture_control_t*
+rtems_capture_task_control (rtems_capture_task_t* task)
+{
+ return task->control;
+}
+
+/**
+ * rtems_capture_task_control_flags
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the task control flags if a control is present.
+ */
+static inline uint32_t
+rtems_capture_task_control_flags (rtems_capture_task_t* task)
+{
+ if (!task->control)
+ return 0;
+ return task->control->flags;
+}
+
+/**
+ * rtems_capture_task_switched_in
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the number of times the task has
+ * been switched into context.
+ */
+static inline uint32_t
+rtems_capture_task_switched_in (rtems_capture_task_t* task)
+{
+ return task->in;
+}
+
+/**
+ * rtems_capture_task_switched_out
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the number of times the task has
+ * been switched out of context.
+ */
+static inline uint32_t
+rtems_capture_task_switched_out (rtems_capture_task_t* task)
+{
+ return task->out;
+}
+
+/**
+ * rtems_capture_task_curr_priority
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the tasks start priority. The tracer needs this
+ * to track where the task's priority goes.
+ */
+static inline rtems_task_priority
+rtems_capture_task_start_priority (rtems_capture_task_t* task)
+{
+ return task->start_priority;
+}
+
+/**
+ * rtems_capture_task_real_priority
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the tasks real priority.
+ */
+static inline rtems_task_priority
+rtems_capture_task_real_priority (rtems_capture_task_t* task)
+{
+ if (rtems_capture_task_valid (task))
+ return task->tcb->real_priority;
+ return 0;
+}
+
+/**
+ * rtems_capture_task_curr_priority
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the tasks current priority.
+ */
+static inline rtems_task_priority
+rtems_capture_task_curr_priority (rtems_capture_task_t* task)
+{
+ if (rtems_capture_task_valid (task))
+ return task->tcb->current_priority;
+ return 0;
+}
+
+/**
+ * rtems_capture_task_stack_usage
+ *
+ * DESCRIPTION:
+ *
+ * This function updates the stack usage. The task control block
+ * is updated.
+ */
+uint32_t
+rtems_capture_task_stack_usage (rtems_capture_task_t* task);
+
+/**
+ * rtems_capture_task_stack_size
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the task's stack size.
+ */
+static inline uint32_t
+rtems_capture_task_stack_size (rtems_capture_task_t* task)
+{
+ return task->stack_size;
+}
+
+/**
+ * rtems_capture_task_stack_used
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the amount of stack used.
+ */
+static inline uint32_t
+rtems_capture_task_stack_used (rtems_capture_task_t* task)
+{
+ return task->stack_size - task->stack_clean;
+}
+
+/**
+ * rtems_capture_task_ticks
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the current execution time as ticks.
+ */
+static inline uint32_t
+rtems_capture_task_ticks (rtems_capture_task_t* task)
+{
+ return task->ticks;
+}
+
+/**
+ * rtems_capture_task_tick_offset
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the current execution time tick offset.
+ */
+static inline uint32_t
+rtems_capture_task_tick_offset (rtems_capture_task_t* task)
+{
+ return task->tick_offset;
+}
+
+/**
+ * rtems_capture_task_time
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the current execution time.
+ */
+static inline unsigned long long
+rtems_capture_task_time (rtems_capture_task_t* task)
+{
+ unsigned long long t = task->ticks;
+ return (t * rtems_capture_tick_time ()) + task->tick_offset;;
+}
+
+/**
+ * rtems_capture_task_delta_time
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the execution time as a different between the
+ * last time the detla time was and now.
+ */
+static inline unsigned long long
+rtems_capture_task_delta_time (rtems_capture_task_t* task)
+{
+ unsigned long long t = task->ticks - task->last_ticks;
+ uint32_t o = task->tick_offset - task->last_tick_offset;
+
+ task->last_ticks = task->ticks;
+ task->last_tick_offset = task->tick_offset;
+
+ return (t * rtems_capture_tick_time ()) + o;
+}
+
+/**
+ * rtems_capture_task_count
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the number of tasks the capture
+ * engine knows about.
+ */
+static inline uint32_t
+rtems_capture_task_count (void)
+{
+ rtems_capture_task_t* task = rtems_capture_get_task_list ();
+ uint32_t count = 0;
+
+ while (task)
+ {
+ count++;
+ task = rtems_capture_next_task (task);
+ }
+
+ return count;
+}
+
+/**
+ * rtems_capture_get_control_list
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the head of the list of controls in the
+ * capture engine.
+ */
+rtems_capture_control_t*
+rtems_capture_get_control_list (void);
+
+/**
+ * rtems_capture_next_control
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the pointer to the next control in the list. The
+ * pointer NULL terminates the list.
+ */
+static inline rtems_capture_control_t*
+rtems_capture_next_control (rtems_capture_control_t* control)
+{
+ return control->next;
+}
+
+/**
+ * rtems_capture_control_id
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the control id.
+ */
+static inline rtems_id
+rtems_capture_control_id (rtems_capture_control_t* control)
+{
+ return control->id;
+}
+
+/**
+ * rtems_capture_control_name
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the control name.
+ */
+static inline rtems_name
+rtems_capture_control_name (rtems_capture_control_t* control)
+{
+ return control->name;
+}
+
+/**
+ * rtems_capture_control_flags
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the control flags.
+ */
+static inline uint32_t
+rtems_capture_control_flags (rtems_capture_control_t* control)
+{
+ return control->flags;
+}
+
+/**
+ * rtems_capture_control_to_triggers
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the task control to triggers.
+ */
+static inline uint32_t
+rtems_capture_control_to_triggers (rtems_capture_control_t* control)
+{
+ return control->to_triggers;
+}
+
+/**
+ * rtems_capture_control_from_triggers
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the task control from triggers.
+ */
+static inline uint32_t
+rtems_capture_control_from_triggers (rtems_capture_control_t* control)
+{
+ return control->from_triggers;
+}
+
+/**
+ * rtems_capture_control_all_by_triggers
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the task control by triggers.
+ */
+static inline uint32_t
+rtems_capture_control_all_by_triggers (rtems_capture_control_t* control)
+{
+ return control->by_triggers;
+}
+
+/**
+ * rtems_capture_control_by_valid
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the control valid BY flags.
+ */
+static inline int
+rtems_capture_control_by_valid (rtems_capture_control_t* control, int slot)
+{
+ return control->by_valid & RTEMS_CAPTURE_CONTROL_FROM_MASK (slot);
+}
+
+/**
+ * rtems_capture_control_by_name
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the control BY task name.
+ */
+static inline rtems_name
+rtems_capture_control_by_name (rtems_capture_control_t* control, int by)
+{
+ if (by < RTEMS_CAPTURE_TRIGGER_TASKS)
+ return control->by[by].name;
+ return control->by[0].name;
+}
+
+/**
+ * rtems_capture_control_by_id
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the control BY task id.
+ */
+static inline rtems_id
+rtems_capture_control_by_id (rtems_capture_control_t* control, int by)
+{
+ if (by < RTEMS_CAPTURE_TRIGGER_TASKS)
+ return control->by[by].id;
+ return control->by[0].id;
+}
+
+/**
+ * rtems_capture_control_by_triggers
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the control BY task triggers.
+ */
+static inline uint32_t
+rtems_capture_control_by_triggers (rtems_capture_control_t* control,
+ int by)
+{
+ if (by < RTEMS_CAPTURE_TRIGGER_TASKS)
+ return control->by[by].trigger;
+ return control->by[0].trigger;
+}
+
+/**
+ * rtems_capture_control_count
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the number of controls the capture
+ * engine has.
+ */
+static inline uint32_t
+rtems_capture_control_count (void)
+{
+ rtems_capture_control_t* control = rtems_capture_get_control_list ();
+ uint32_t count = 0;
+
+ while (control)
+ {
+ count++;
+ control = rtems_capture_next_control (control);
+ }
+
+ return count;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif