summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2002-05-15 16:36:10 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2002-05-15 16:36:10 +0000
commita923a82d2d63b29165b249bae6ad46bb045290b2 (patch)
treeac6f3f8aedb59311d3bb95cdca06a8ea93756f98
parentc0d4abe6b0b79ff2c908869e379f71fd80437d49 (diff)
downloadrtems-a923a82d2d63b29165b249bae6ad46bb045290b2.tar.bz2
2002-05-16 Chris Johns <ccj@acm.org>
* Per PR194, added the Capture engine. * capture/Makefile.am, capture/README, capture/capture-cli.c, capture/capture-cli.h, capture/capture.c, capture/capture.h, capture/.cvsignore: New files. * Makefile.am, configure.ac, wrapup/Makefile.am: Modified to reflect addition.
-rw-r--r--c/src/libmisc/ChangeLog9
-rw-r--r--c/src/libmisc/Makefile.am4
-rw-r--r--c/src/libmisc/capture/.cvsignore2
-rw-r--r--c/src/libmisc/capture/Makefile.am44
-rw-r--r--c/src/libmisc/capture/README255
-rw-r--r--c/src/libmisc/capture/capture-cli.c1406
-rw-r--r--c/src/libmisc/capture/capture-cli.h52
-rw-r--r--c/src/libmisc/capture/capture.c1565
-rw-r--r--c/src/libmisc/capture/capture.h869
-rw-r--r--c/src/libmisc/configure.ac1
-rw-r--r--c/src/libmisc/wrapup/Makefile.am2
-rw-r--r--cpukit/libmisc/ChangeLog9
-rw-r--r--cpukit/libmisc/Makefile.am4
-rw-r--r--cpukit/libmisc/capture/.cvsignore2
-rw-r--r--cpukit/libmisc/capture/Makefile.am44
-rw-r--r--cpukit/libmisc/capture/README255
-rw-r--r--cpukit/libmisc/capture/capture-cli.c1406
-rw-r--r--cpukit/libmisc/capture/capture-cli.h52
-rw-r--r--cpukit/libmisc/capture/capture.c1565
-rw-r--r--cpukit/libmisc/capture/capture.h869
-rw-r--r--cpukit/libmisc/configure.ac1
-rw-r--r--cpukit/libmisc/wrapup/Makefile.am2
22 files changed, 8412 insertions, 6 deletions
diff --git a/c/src/libmisc/ChangeLog b/c/src/libmisc/ChangeLog
index 334a3edfcc..1365bea8e3 100644
--- a/c/src/libmisc/ChangeLog
+++ b/c/src/libmisc/ChangeLog
@@ -1,3 +1,12 @@
+2002-05-16 Chris Johns <ccj@acm.org>
+
+ * Per PR194, added the Capture engine.
+ * capture/Makefile.am, capture/README, capture/capture-cli.c,
+ capture/capture-cli.h, capture/capture.c, capture/capture.h,
+ capture/.cvsignore: New files.
+ * Makefile.am, configure.ac, wrapup/Makefile.am: Modified to
+ reflect addition.
+
2001-05-14 Joel Sherrill <joel@OARcorp.com>
* dummy/Makefile.am, wrapup/Makefile.am: Fixed to generate
diff --git a/c/src/libmisc/Makefile.am b/c/src/libmisc/Makefile.am
index cfa832ffba..fa1d2a1b9a 100644
--- a/c/src/libmisc/Makefile.am
+++ b/c/src/libmisc/Makefile.am
@@ -4,8 +4,8 @@
ACLOCAL_AMFLAGS = -I ../../../aclocal
-SUBDIRS = devnull dummy dumpbuf stackchk monitor cpuuse shell rtmonuse rootfs untar \
- mw-fb wrapup
+SUBDIRS = capture cpuuse devnull dummy dumpbuf monitor mw-fb shell rootfs \
+ rtmonuse stackchk untar wrapup
EXTRA_DIST = README
diff --git a/c/src/libmisc/capture/.cvsignore b/c/src/libmisc/capture/.cvsignore
new file mode 100644
index 0000000000..282522db03
--- /dev/null
+++ b/c/src/libmisc/capture/.cvsignore
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/c/src/libmisc/capture/Makefile.am b/c/src/libmisc/capture/Makefile.am
new file mode 100644
index 0000000000..fe533b265e
--- /dev/null
+++ b/c/src/libmisc/capture/Makefile.am
@@ -0,0 +1,44 @@
+##
+## $Id$
+##
+
+AUTOMAKE_OPTIONS = foreign 1.4
+
+include_rtemsdir = $(includedir)/rtems
+
+LIBNAME = libcapture-tmp
+LIB = $(ARCH)/$(LIBNAME).a
+
+C_FILES = capture.c capture-cli.c
+C_O_FILES = $(C_FILES:%.c=$(ARCH)/%.o)
+
+include_rtems_HEADERS = capture.h capture-cli.h
+
+OBJS = $(C_O_FILES)
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
+include $(top_srcdir)/../../../automake/compile.am
+include $(top_srcdir)/../../../automake/lib.am
+
+$(PROJECT_INCLUDE)/rtems:
+ @$(mkinstalldirs) $@
+$(PROJECT_INCLUDE)/rtems/%.h: %.h
+ $(INSTALL_DATA) $< $@
+
+#
+# (OPTIONAL) Add local stuff here using +=
+#
+
+$(LIB): $(OBJS)
+ $(make-library)
+
+PREINSTALL_FILES = $(PROJECT_INCLUDE)/rtems \
+ $(include_rtems_HEADERS:%=$(PROJECT_INCLUDE)/rtems/%)
+
+all-local: $(ARCH) $(PREINSTALL_FILES) $(OBJS) $(LIB)
+
+.PRECIOUS: $(LIB)
+
+EXTRA_DIST = README capture.c capture-cli.c
+
+include $(top_srcdir)/../../../automake/local.am
diff --git a/c/src/libmisc/capture/README b/c/src/libmisc/capture/README
new file mode 100644
index 0000000000..2ea76a4cfe
--- /dev/null
+++ b/c/src/libmisc/capture/README
@@ -0,0 +1,255 @@
+#
+# $Id$
+#
+
+ RTEMS Performance Monitoring and Measurement Framework
+
+ Copyright 2002 Chris Johns (ccj@acm.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/c/src/libmisc/capture/capture-cli.c b/c/src/libmisc/capture/capture-cli.c
new file mode 100644
index 0000000000..0ed145fafc
--- /dev/null
+++ b/c/src/libmisc/capture/capture-cli.c
@@ -0,0 +1,1406 @@
+/*
+ ------------------------------------------------------------------------
+ $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.
+
+*/
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <rtems.h>
+#include <rtems/capture-cli.h>
+#include <rtems/monitor.h>
+
+#define RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS (32)
+
+/*
+ * 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)
+{
+ rtems_unsigned32 size = 0;
+ rtems_boolean enable = 0;
+ rtems_status_code sc;
+ int arg;
+
+ if (argc <= 1)
+ {
+ printf (open_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ if (argv[arg][1] == 'i')
+ enable = 1;
+ else
+ printf ("warning: option -%c ignored\n", argv[arg][1]);
+ }
+ else
+ {
+ size = strtoul (argv[arg], 0, 0);
+
+ if (size < 100)
+ {
+ printf ("error: size must be greater than or equal to 100\n");
+ return;
+ }
+ }
+ }
+
+ sc = rtems_capture_open (size, capture_timestamp);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: open failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("capture engine opened.\n");
+
+ if (!enable)
+ return;
+
+ sc = rtems_capture_control (enable);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: open enable failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("capture engine enabled.\n");
+}
+
+/*
+ * rtems_capture_cli_close
+ *
+ * DESCRIPTION:
+ *
+ * This function closes the capture engine.
+ *
+ */
+
+static void
+rtems_capture_cli_close (int argc, char **argv)
+{
+ rtems_status_code sc;
+
+ sc = rtems_capture_close ();
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: close failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("capture engine closed.\n");
+}
+
+/*
+ * rtems_capture_cli_enable
+ *
+ * DESCRIPTION:
+ *
+ * This function enables the capture engine.
+ *
+ */
+
+static void
+rtems_capture_cli_enable (int argc, char **argv)
+{
+ rtems_status_code sc;
+
+ sc = rtems_capture_control (1);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: enable failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("capture engine enabled.\n");
+}
+
+/*
+ * rtems_capture_cli_disable
+ *
+ * DESCRIPTION:
+ *
+ * This function disables the capture engine.
+ *
+ */
+
+static void
+rtems_capture_cli_disable (int argc, char **argv)
+{
+ rtems_status_code sc;
+
+ sc = rtems_capture_control (0);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: disable failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("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, char **argv)
+{
+ 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 ();
+ rtems_unsigned32 ticks;
+ rtems_unsigned32 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;
+ }
+
+ total_time = (ticks * rtems_capture_task_time (task)) + tick_offset;
+
+ printf ("total %i\n", count);
+
+ while (task)
+ {
+ rtems_task_priority priority;
+ int stack_used;
+ int time_used;
+
+ stack_used = rtems_capture_task_stack_usage (task) * 100;
+ stack_used /= rtems_capture_task_stack_size (task);
+
+ if (stack_used > 100)
+ stack_used = 100;
+
+ time_used = (rtems_capture_task_time (task) * 100) / total_time;
+
+ if (time_used > 100)
+ time_used = 100;
+
+ priority = rtems_capture_task_real_priority (task);
+
+ printf (" ");
+ rtems_monitor_dump_id (rtems_capture_task_id (task));
+ printf (" ");
+ rtems_monitor_dump_name (rtems_capture_task_name (task));
+ printf (" ");
+ rtems_monitor_dump_priority (rtems_capture_task_start_priority (task));
+ printf (" ");
+ rtems_monitor_dump_priority (rtems_capture_task_real_priority (task));
+ printf (" ");
+ rtems_monitor_dump_priority (rtems_capture_task_curr_priority (task));
+ printf (" ");
+ rtems_monitor_dump_state (rtems_capture_task_state (task));
+ printf (" %c%c%c%c%c",
+ rtems_capture_task_valid (task) ? 'a' : 'd',
+ rtems_capture_task_flags (task) & RTEMS_CAPTURE_TRACED ? 't' : '-',
+ rtems_capture_task_control_flags (task) & RTEMS_CAPTURE_TO_ANY ? 'F' : '-',
+ rtems_capture_task_control_flags (task) & RTEMS_CAPTURE_FROM_ANY ? 'T' : '-',
+ rtems_capture_task_control_flags (task) & RTEMS_CAPTURE_FROM_TO ? 'E' : '-');
+ if ((floor > ceiling) && (ceiling > priority))
+ printf ("--");
+ else
+ printf ("%c%c",
+ rtems_capture_task_control (task) ?
+ (rtems_capture_task_control_flags (task) & RTEMS_CAPTURE_WATCH ? 'w' : '+') : '-',
+ rtems_capture_watch_global_on () ? 'g' : '-');
+ printf (" %3i%% %3i%% (%i)\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)
+{
+ rtems_task_priority ceiling = rtems_capture_watch_get_ceiling ();
+ rtems_task_priority floor = rtems_capture_watch_get_floor ();
+ int last_count = 0;
+
+ printf ("\x1b[2J Press ENTER to exit.\n\n");
+ printf (" PID NAME RPRI CPRI STATE %%CPU %%STK FLGS EXEC TIME\n");
+
+ 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 ();
+
+ while (task)
+ {
+ if (rtems_capture_task_valid (task))
+ {
+ unsigned long long l = rtems_capture_task_delta_time (task);
+
+ count++;
+
+ 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);
+ }
+
+ printf ("\x1b[4;0H");
+
+ total_time = 0;
+
+ for (i = 0; i < RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS; i++)
+ total_time += load[i];
+
+ 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]) * 100;
+ stack_used /= rtems_capture_task_stack_size (tasks[i]);
+
+ if (stack_used > 100)
+ stack_used = 100;
+
+ task_load = (int) ((load[i] * 100000) / total_time);
+
+ priority = rtems_capture_task_real_priority (tasks[i]);
+
+ printf ("\x1b[K");
+ rtems_monitor_dump_id (rtems_capture_task_id (tasks[i]));
+ printf (" ");
+ rtems_monitor_dump_name (rtems_capture_task_name (tasks[i]));
+ printf (" ");
+ rtems_monitor_dump_priority (priority);
+ printf (" ");
+ rtems_monitor_dump_priority (rtems_capture_task_curr_priority (tasks[i]));
+ printf (" ");
+ k = rtems_monitor_dump_state (rtems_capture_task_state (tasks[i]));
+ printf ("%*c %3i.%03i%% ", 6 - k, ' ', task_load / 1000, task_load % 1000);
+ printf ("%3i%% %c%c%c%c%c", stack_used,
+ rtems_capture_task_valid (tasks[i]) ? 'a' : 'd',
+ rtems_capture_task_flags (tasks[i]) & RTEMS_CAPTURE_TRACED ? 't' : '-',
+ rtems_capture_task_control_flags (tasks[i]) & RTEMS_CAPTURE_TO_ANY ? 'F' : '-',
+ rtems_capture_task_control_flags (tasks[i]) & RTEMS_CAPTURE_FROM_ANY ? 'T' : '-',
+ rtems_capture_task_control_flags (tasks[i]) & RTEMS_CAPTURE_FROM_TO ? 'E' : '-');
+ if ((floor > ceiling) && (ceiling > priority))
+ printf ("--");
+ else
+ printf ("%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' : '-');
+
+ printf (" %qi\n", rtems_capture_task_time (tasks[i]));
+ }
+
+ while (j)
+ {
+ printf ("\x1b[K\n");
+ j--;
+ }
+
+ last_count = count;
+
+ cli_load_thread_active = 0;
+
+ rtems_task_wake_after (TOD_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, char **argv)
+{
+ 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)
+ {
+ printf ("error: cannot obtain the current priority: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ memcpy (&name, "CPlt", 4);
+
+ sc = rtems_task_create (name, priority, 1024,
+ RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
+ RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR,
+ &id);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("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)
+ {
+ printf ("error: cannot start helper thread: %s\n", rtems_status_text (sc));
+ rtems_task_delete (id);
+ return;
+ }
+
+ for (;;)
+ {
+ char c = getchar ();
+
+ if ((c == '\r') || (c == '\n'))
+ {
+ int loops = 20;
+
+ while (loops && cli_load_thread_active)
+ rtems_task_wake_after (TOD_MICROSECONDS_TO_TICKS (100000));
+
+ rtems_task_delete (id);
+
+ printf ("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, char **argv)
+{
+ 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 ();
+
+ printf ("watch priority ceiling is %i\n", ceiling);
+ printf ("watch priority floor is %i\n", floor);
+ printf ("global watch is %s\n",
+ rtems_capture_watch_global_on () ? "enabled" : "disabled");
+ printf ("total %d\n", rtems_capture_control_count ());
+
+ while (control)
+ {
+ int f;
+ int fshowed;
+ int lf;
+
+ printf (" ");
+ rtems_monitor_dump_id (rtems_capture_control_id (control));
+ printf (" ");
+ rtems_monitor_dump_name (rtems_capture_control_name (control));
+ printf (" %c%c%c%c%c",
+ rtems_capture_control_flags (control) & RTEMS_CAPTURE_WATCH ? 'w' : '-',
+ rtems_capture_watch_global_on () ? 'g' : '-',
+ rtems_capture_control_flags (control) & RTEMS_CAPTURE_TO_ANY ? 'F' : '-',
+ rtems_capture_control_flags (control) & RTEMS_CAPTURE_FROM_ANY ? 'T' : '-',
+ rtems_capture_control_flags (control) & RTEMS_CAPTURE_FROM_TO ? 'E' : '-');
+
+ for (f = 0, fshowed = 0, lf = 1; f < RTEMS_CAPTURE_TRIGGER_TASKS; f++)
+ {
+ if (lf && ((fshowed % 16) == 0))
+ {
+ printf ("\n");
+ lf = 0;
+ }
+
+ /*
+ * FIXME: name test.
+ */
+ if (rtems_capture_control_from_name (control, f))
+ {
+ printf (" %2i:", f);
+ rtems_monitor_dump_name (rtems_capture_control_from_name (control, f));
+ printf ("/");
+ rtems_monitor_dump_id (rtems_capture_control_from_id (control, f));
+ fshowed++;
+ lf = 1;
+ }
+ }
+
+ if (lf)
+ printf ("\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 rtems_boolean
+rtems_capture_cli_get_name_id (char* arg,
+ rtems_boolean* valid_name,
+ rtems_boolean* valid_id,
+ rtems_name* name,
+ rtems_id* id)
+{
+ Objects_Classes objclass;
+ int l;
+ int i;
+
+ if (*valid_name && *valid_id)
+ {
+ printf ("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 (arg[i]))
+ break;
+
+ *id = strtoul (arg, 0, 16);
+
+ objclass = _Objects_Get_class (*id);
+
+ if ((i == l) && (l > 4) &&
+ ((objclass == OBJECTS_INTERNAL_THREADS) ||
+ (objclass == OBJECTS_RTEMS_TASKS) ||
+ (objclass == OBJECTS_POSIX_THREADS) ||
+ (objclass == OBJECTS_ITRON_TASKS)))
+ *valid_id = 1;
+ else
+ {
+ memcpy (name, arg, sizeof (rtems_name));
+ *valid_name = 1;
+ }
+
+ 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)
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_name name = 0;
+ rtems_id id = 0;
+ rtems_boolean valid_name = 0;
+ rtems_boolean valid_id = 0;
+
+ if (argc <= 1)
+ {
+ printf (watch_add_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ printf ("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)
+ {
+ printf("error: no valid name or task id located\n");
+ return;
+ }
+
+ sc = rtems_capture_watch_add (name, id);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: watch add failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("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)
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_name name = 0;
+ rtems_id id = 0;
+ rtems_boolean valid_name = 0;
+ rtems_boolean valid_id = 0;
+
+ if (argc <= 1)
+ {
+ printf (watch_del_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ printf ("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)
+ {
+ printf("error: no valid name or task id located\n");
+ return;
+ }
+
+ sc = rtems_capture_watch_del (name, id);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: watch delete failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("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)
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_name name = 0;
+ rtems_id id = 0;
+ rtems_boolean valid_name = 0;
+ rtems_boolean valid_id = 0;
+ rtems_boolean enable = 0;
+
+ if (argc <= 2)
+ {
+ printf (watch_control_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ printf ("warning: option -%c ignored\n", argv[arg][1]);
+ }
+ else
+ {
+ if (strcmp (argv[arg], "on") == 0)
+ enable = 1;
+ else if (strcmp (argv[arg], "off") == 0)
+ enable = 0;
+ else if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id, &name, &id))
+ return;
+ }
+ }
+
+ if (!valid_name && !valid_id)
+ {
+ printf("error: no valid name or task id located\n");
+ return;
+ }
+
+ sc = rtems_capture_watch_ctrl (name, id, enable);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: watch control failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("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)
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_boolean enable = 0;
+
+ if (argc <= 1)
+ {
+ printf (watch_global_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ printf ("warning: option -%c ignored\n", argv[arg][1]);
+ }
+ else
+ {
+ if (strcmp (argv[arg], "on") == 0)
+ enable = 1;
+ else if (strcmp (argv[arg], "off") == 0)
+ enable = 0;
+ }
+ }
+
+ sc = rtems_capture_watch_global (enable);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: global watch failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("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)
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_task_priority priority = 0;
+
+ if (argc <= 1)
+ {
+ printf (watch_ceiling_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ printf ("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)
+ {
+ printf ("error: watch ceiling failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("watch ceiling is %i.\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)
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_task_priority priority = 0;
+
+ if (argc <= 1)
+ {
+ printf (watch_floor_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ printf ("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)
+ {
+ printf ("error: watch floor failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("watch floor is %i.\n", priority);
+}
+
+/*
+ * rtems_capture_cli_trigger_set
+ *
+ * DESCRIPTION:
+ *
+ * This function is a monitor command that sets a trigger.
+ *
+ */
+
+static char const *trigger_set_usage = "usage: ctrig type [from] [fromid] [to] [to id]\n";
+
+static void
+rtems_capture_cli_trigger_set (int argc, char **argv)
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_capture_trigger_t trigger = rtems_capture_from_to;
+ rtems_boolean trigger_set = 0;
+ rtems_name name = 0;
+ rtems_id id = 0;
+ rtems_boolean valid_name = 0;
+ rtems_boolean valid_id = 0;
+ rtems_name from_name = 0;
+ rtems_id from_id = 0;
+ rtems_boolean from_valid_name = 0;
+ rtems_boolean from_valid_id = 0;
+ rtems_name to_name = 0;
+ rtems_id to_id = 0;
+ rtems_boolean to_valid_name = 0;
+ rtems_boolean to_valid_id = 0;
+
+ if (argc <= 2)
+ {
+ printf (trigger_set_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ printf ("warning: option -%c ignored\n", argv[arg][1]);
+ }
+ else
+ {
+ if (!trigger_set)
+ {
+ if (strcmp (argv[arg], "from") == 0)
+ trigger = rtems_capture_to_any;
+ else if (strcmp (argv[arg], "to") == 0)
+ trigger = rtems_capture_from_any;
+ else if (strcmp (argv[arg], "edge") == 0)
+ trigger = rtems_capture_from_any;
+ else
+ {
+ printf ("error: the first argument is the trigger type (from/to/edge)\n");
+ return;
+ }
+ trigger_set = 1;
+ }
+ else
+ {
+ if (trigger == rtems_capture_to_any)
+ {
+ if (from_valid_name && from_valid_id)
+ printf ("warning: extra arguments ignored\n");
+ else if (!rtems_capture_cli_get_name_id (argv[arg], &from_valid_name, &from_valid_id,
+ &from_name, &from_id))
+ return;
+ }
+ else if (trigger == rtems_capture_from_any)
+ {
+ if (to_valid_name && to_valid_id)
+ printf ("warning: extra arguments ignored\n");
+ else if (!rtems_capture_cli_get_name_id (argv[arg], &to_valid_name, &to_valid_id,
+ &to_name, &to_id))
+ return;
+ }
+ else if (trigger == rtems_capture_from_to)
+ {
+ if (from_valid_name && from_valid_id && to_valid_name && to_valid_id)
+ printf ("warning: extra arguments ignored\n");
+ else
+ {
+ if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id,
+ &name, &id))
+ return;
+
+ if (valid_name)
+ {
+ if (!from_valid_name && !from_valid_id)
+ {
+ from_valid_name = 1;
+ from_name = name;
+ }
+ else if (to_valid_name)
+ printf ("warning: extra arguments ignored\n");
+ else
+ {
+ to_valid_name = 1;
+ to_name = name;
+ }
+ }
+ if (valid_id)
+ {
+ if (!from_valid_id && !to_valid_name)
+ {
+ from_valid_id = 1;
+ from_id = id;
+ }
+ else if (to_valid_id)
+ printf ("warning: extra arguments ignored\n");
+ else
+ {
+ to_valid_id = 1;
+ to_id = id;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ((trigger == rtems_capture_to_any) && !from_valid_name && !from_valid_id)
+ {
+ printf ("error: a from trigger need a to name or id\n");
+ return;
+ }
+
+ if ((trigger == rtems_capture_from_any) && !to_valid_name && !to_valid_id)
+ {
+ printf ("error: a to trigger need a from name or id\n");
+ return;
+ }
+
+ if ((trigger == rtems_capture_from_to) &&
+ ((!from_valid_name && !from_valid_id) || (!to_valid_name && !to_valid_id)))
+ {
+ printf ("error: an edge trigger need a from and to name or id\n");
+ return;
+ }
+
+ sc = rtems_capture_set_trigger (from_name, from_id, to_name, to_id, trigger);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: setting the trigger failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("trigger set.\n");
+}
+
+/*
+ * 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)
+{
+ rtems_status_code sc;
+ rtems_boolean csv = 0;
+ static int dump_total = 32;
+ int total;
+ int count;
+ rtems_unsigned32 read;
+ rtems_capture_record_t* rec;
+ int arg;
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ if (argv[arg][1] == 'c')
+ csv = 1;
+ else if (argv[arg][1] == 'r')
+ {
+ int i;
+ int l;
+
+ arg++;
+ if (arg == argc)
+ {
+ printf ("error: option -r requires number\n");
+ return;
+ }
+
+ l = strlen (argv[arg]);
+
+ for (i = 0; i < l; i++)
+ if (!isdigit (argv[arg][i]))
+ {
+ printf ("error: option -r requires number and currently it is not\n");
+ return;
+ }
+
+ dump_total = strtoul (argv[arg], 0, 0);
+ }
+ else
+ printf ("warning: option -%c ignored\n", argv[arg][1]);
+ }
+ }
+
+ total = dump_total;
+
+ while (total)
+ {
+ sc = rtems_capture_read (0, 0, &read, &rec);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: trace read failed: %s\n", rtems_status_text (sc));
+ rtems_capture_flush (0);
+ return;
+ }
+
+ if (read == 0)
+ break;
+
+ for (count = 0; count < read; count++, rec++)
+ {
+ if (csv)
+ printf ("%08x,%03d,%03d,%04x,%d,%d\n",
+ (rtems_unsigned32) 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;
+ rtems_unsigned32 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)
+ {
+ printf ("%9li.%06li ", (unsigned long) (t / 1000000),
+ (unsigned long) (t % 1000000));
+ rtems_monitor_dump_id (rtems_capture_task_id (rec->task));
+ printf (" ");
+ rtems_monitor_dump_name (rtems_capture_task_name (rec->task));
+ printf (" %3i %3i %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;
+ }
+ }
+ }
+
+ if (read < total)
+ total -= read;
+ else
+ total = 0;
+
+ rtems_capture_release (read);
+ }
+}
+
+/*
+ * 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)
+{
+ rtems_status_code sc;
+ rtems_boolean prime = 1;
+ int arg;
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ if (argv[arg][1] == 'n')
+ prime = 0;
+ else
+ printf ("warning: option -%c ignored\n", argv[arg][1]);
+ }
+ }
+
+ sc = rtems_capture_flush (prime);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: flush failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("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,
+ (void*) rtems_capture_cli_open,
+ 0,
+ 0
+ },
+ {
+ "cclose",
+ "usage: cclose\n",
+ 0,
+ (void*) rtems_capture_cli_close,
+ 0,
+ 0
+ },
+ {
+ "cenable",
+ "usage: cenable\n",
+ 0,
+ (void*) rtems_capture_cli_enable,
+ 0,
+ 0
+ },
+ {
+ "cdisable",
+ "usage: cdisable\n",
+ 0,
+ (void*) rtems_capture_cli_disable,
+ 0,
+ 0
+ },
+ {
+ "ctlist",
+ "usage: ctlist \n",
+ 0,
+ (void*) rtems_capture_cli_task_list,
+ 0,
+ 0
+ },
+ {
+ "ctload",
+ "usage: ctload \n",
+ 0,
+ (void*) rtems_capture_cli_task_load,
+ 0,
+ 0
+ },
+ {
+ "cwlist",
+ "usage: cwlist\n",
+ 0,
+ (void*) rtems_capture_cli_watch_list,
+ 0,
+ 0
+ },
+ {
+ "cwadd",
+ "usage: cwadd [task name] [id]\n",
+ 0,
+ (void*) rtems_capture_cli_watch_add,
+ 0,
+ 0
+ },
+ {
+ "cwdel",
+ "usage: cwdel [task name] [id]\n",
+ 0,
+ (void*) rtems_capture_cli_watch_del,
+ 0,
+ 0
+ },
+ {
+ "cwctl",
+ "usage: cwctl [task name] [id] on/off\n",
+ 0,
+ (void*) rtems_capture_cli_watch_control,
+ 0,
+ 0
+ },
+ {
+ "cwglob",
+ "usage: cwglob on/off\n",
+ 0,
+ (void*) rtems_capture_cli_watch_global,
+ 0,
+ 0
+ },
+ {
+ "cwceil",
+ "usage: cwceil priority\n",
+ 0,
+ (void*) rtems_capture_cli_watch_ceiling,
+ 0,
+ 0
+ },
+ {
+ "cwfloor",
+ "usage: cwfloor priority\n",
+ 0,
+ (void*) rtems_capture_cli_watch_floor,
+ 0,
+ 0
+ },
+ {
+ "ctrace",
+ "usage: ctrace [-c] [-r records]\n",
+ 0,
+ (void*) rtems_capture_cli_trace_records,
+ 0,
+ 0
+ },
+ {
+ "ctrig",
+ "usage: ctrig type [from name] [from id] [to name] [to id]\n",
+ 0,
+ (void*) rtems_capture_cli_trigger_set,
+ 0,
+ 0
+ },
+ {
+ "cflush",
+ "usage: cflush [-n]\n",
+ 0,
+ (void*) 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)
+{
+ int 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/c/src/libmisc/capture/capture-cli.h b/c/src/libmisc/capture/capture-cli.h
new file mode 100644
index 0000000000..968e3217f9
--- /dev/null
+++ b/c/src/libmisc/capture/capture-cli.h
@@ -0,0 +1,52 @@
+/*
+ ------------------------------------------------------------------------
+ $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/c/src/libmisc/capture/capture.c b/c/src/libmisc/capture/capture.c
new file mode 100644
index 0000000000..b58d065d91
--- /dev/null
+++ b/c/src/libmisc/capture/capture.c
@@ -0,0 +1,1565 @@
+/*
+ ------------------------------------------------------------------------
+ $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.
+
+*/
+
+#include <stdlib.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.
+ */
+#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)
+
+/*
+ * 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)
+
+/*
+ * RTEMS Capture Data.
+ */
+static rtems_capture_record_t* capture_records;
+static rtems_unsigned32 capture_size;
+static rtems_unsigned32 capture_count;
+static rtems_capture_record_t* capture_in;
+static rtems_unsigned32 capture_out;
+static rtems_unsigned32 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 rtems_unsigned32 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 (rtems_unsigned32* ticks,
+ rtems_unsigned32* 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 rtems_boolean
+rtems_capture_match_names (rtems_name lhs, rtems_name rhs)
+{
+ return lhs == rhs;
+}
+
+/*
+ * rtems_capture_dup_name
+ *
+ * DESCRIPTION:
+ *
+ * This function duplicates an rtems_names. It protects the
+ * cpature 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_name_in_group
+ *
+ * DESCRIPTION:
+ *
+ * This function sees if a name is in a group of names.
+ *
+ */
+static inline rtems_boolean
+rtems_capture_name_in_group (rtems_name task, rtems_name* tasks)
+{
+ if (tasks)
+ {
+ int i;
+ for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
+ if (rtems_capture_match_names (task, *tasks++))
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * rtems_capture_match_name_id
+ *
+ * DESCRIPTION:
+ *
+ * This function matches a name and/or id.
+ */
+static inline rtems_boolean
+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_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)
+ {
+ rtems_unsigned32* s;
+ rtems_unsigned32 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;
+
+ memset (control->from, 0, sizeof (control->from));
+ memset (control->from_id, 0, sizeof (control->from_id));
+
+ 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->next)
+ 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;
+
+ task = _Workspace_Allocate (sizeof (rtems_capture_task_t));
+
+ if (task == NULL)
+ {
+ capture_flags |= RTEMS_CAPTURE_NO_MEMORY;
+ return NULL;
+ }
+
+ rtems_capture_dup_name (&task->name, *((rtems_name*) new_task->Object.name));
+
+ task->id = new_task->Object.id;
+ task->flags = 0;
+ task->in = 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->next = capture_tasks;
+ 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_record
+ *
+ * DESCRIPTION:
+ *
+ * This function records a capture record into the capture buffer.
+ *
+ */
+static inline void
+rtems_capture_record (rtems_capture_task_t* task,
+ rtems_unsigned32 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)
+ {
+ 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++;
+ }
+ else
+ capture_flags |= RTEMS_CAPTURE_OVERFLOW;
+ rtems_interrupt_enable (level);
+ }
+ }
+}
+
+/*
+ * rtems_capture_create_task
+ *
+ * DESCRIPTION:
+ *
+ * This function is called when a task is created.
+ *
+ */
+static rtems_boolean
+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 ponters 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 we are logging then record this fact.
+ */
+ 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 rtems_extension
+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 ponters 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);
+
+ 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 rtems_extension
+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 ponters 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);
+
+ 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 rtems_extension
+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 ponters 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);
+
+ 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.
+ */
+ dt->tcb = 0;
+}
+
+/*
+ * rtems_capture_begin_task
+ *
+ * DESCRIPTION:
+ *
+ * This function is called when a task is begun.
+ *
+ */
+static rtems_extension
+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 ponters 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);
+
+ 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 rtems_extension
+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 ponters 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);
+
+ 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 rtems_extension
+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)
+ {
+ rtems_unsigned32 ticks;
+ rtems_unsigned32 tick_offset;
+
+ /*
+ * Get the cpature task control block so we can update the
+ * reference anbd perform any watch or trigger functions.
+ * The task ponters 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))
+ {
+ rtems_id ct_id = current_task->Object.id;
+
+ for (ct = capture_tasks; ct; ct = ct->next)
+ 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 we have not triggered then see if this is a trigger condition.
+ */
+ if (!(capture_flags & RTEMS_CAPTURE_TRIGGERED))
+ {
+ rtems_capture_control_t* cc = NULL;
+ rtems_capture_control_t* hc = NULL;
+
+ if (ct)
+ {
+ cc = ct->control;
+
+ /*
+ * Check the current task for a TO_ANY trigger.
+ */
+ if (cc && (cc->flags & RTEMS_CAPTURE_TO_ANY))
+ {
+ capture_flags |= RTEMS_CAPTURE_TRIGGERED;
+ goto triggered;
+ }
+ }
+
+ if (ht)
+ {
+ hc = ht->control;
+
+ /*
+ * Check the next task for a FROM_ANY.
+ */
+ if (hc && (hc->flags & RTEMS_CAPTURE_FROM_ANY))
+ {
+ capture_flags |= RTEMS_CAPTURE_TRIGGERED;
+ goto triggered;
+ }
+ }
+
+ /*
+ * Check is the trigger is from the current task
+ * to the next task.
+ */
+ if (cc && hc && (hc->flags & RTEMS_CAPTURE_FROM_TO))
+ if (rtems_capture_name_in_group (cc->name, hc->from))
+ {
+ capture_flags |= RTEMS_CAPTURE_TRIGGERED;
+ goto triggered;
+ }
+ }
+ else
+ {
+triggered:
+
+ 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 (rtems_unsigned32 size, rtems_capture_timestamp timestamp)
+{
+ 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_Table->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_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 ()
+{
+ 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;
+
+ 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->next;
+ _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 (rtems_boolean 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_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 (rtems_boolean prime)
+{
+ rtems_interrupt_level level;
+ rtems_capture_task_t* task;
+
+ rtems_interrupt_disable (level);
+
+ for (task = capture_tasks; task != NULL; task = task->next)
+ task->flags &= ~RTEMS_CAPTURE_TRACED;
+
+ if (prime)
+ capture_flags &= ~(RTEMS_CAPTURE_TRIGGERED | RTEMS_CAPTURE_OVERFLOW);
+ else
+ capture_flags &= ~RTEMS_CAPTURE_OVERFLOW;
+
+ capture_in = capture_records;
+ capture_out = 0;
+
+ rtems_interrupt_enable (level);
+
+ 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;
+ rtems_boolean found = 0;
+
+ /*
+ * Should this test be for wildcards ?
+ */
+
+ for (prev_control = &capture_controls, control = capture_controls;
+ control != NULL; )
+ {
+ if (rtems_capture_match_name_id (name, id, control->name, control->id))
+ {
+ rtems_interrupt_disable (level);
+
+ for (task = capture_tasks; task != NULL; task = task->next)
+ if (task->control == control)
+ task->control = 0;
+
+ *prev_control = control->next;
+
+ rtems_interrupt_enable (level);
+
+ _Workspace_Free (control);
+
+ control = *prev_control;
+
+ found = 1;
+ }
+ 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, rtems_boolean enable)
+{
+ rtems_interrupt_level level;
+ rtems_capture_control_t* control;
+ rtems_boolean found = 0;
+
+ /*
+ * 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 (name, id, control->name, control->id))
+ {
+ rtems_interrupt_disable (level);
+
+ if (enable)
+ control->flags |= RTEMS_CAPTURE_WATCH;
+ else
+ control->flags &= ~RTEMS_CAPTURE_WATCH;
+
+ rtems_interrupt_enable (level);
+
+ found = 1;
+ }
+ }
+
+ 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 (rtems_boolean 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.
+ */
+rtems_boolean
+rtems_capture_watch_global_on ()
+{
+ 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 ()
+{
+ 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 ()
+{
+ return capture_floor;
+}
+
+/*
+ * rtems_capture_set_trigger
+ *
+ * DESCRIPTION:
+ *
+ * This function sets an edge trigger. Left is the left side of
+ * the edge and right is right side of the edge. The trigger type
+ * can be -
+ *
+ * FROM_ANY : a switch from any task to the right side of the edge.
+ * TO_ANY : a switch from the left side of the edge to any task.
+ * FROM_TO : a switch from the left side of the edge to the right
+ * side of the edge.
+ *
+ * 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,
+ rtems_id from_id,
+ rtems_name to,
+ rtems_id to_id,
+ rtems_capture_trigger_t trigger)
+{
+ rtems_capture_control_t* control;
+ int i;
+
+ /*
+ * Find the capture control blocks for the from and to
+ * tasks.
+ */
+ if (trigger == rtems_capture_to_any)
+ {
+ control = rtems_capture_create_control (from, from_id);
+ if (control == NULL)
+ return RTEMS_NO_MEMORY;
+ control->flags |= RTEMS_CAPTURE_TO_ANY;
+ }
+
+ if ((trigger == rtems_capture_from_to) ||
+ (trigger == rtems_capture_from_any))
+ {
+ control = rtems_capture_create_control (to, to_id);
+ if (control == NULL)
+ return RTEMS_NO_MEMORY;
+
+ if (trigger == rtems_capture_from_any)
+ control->flags |= RTEMS_CAPTURE_FROM_ANY;
+ else
+ {
+ control->flags |= RTEMS_CAPTURE_FROM_TO;
+ for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
+ {
+ if (control->from[i] == 0)
+ {
+ control->from[i] = from;
+ control->from_id[i] = from_id;
+ break;
+ }
+ }
+ }
+ }
+ 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 (rtems_unsigned32 threshold,
+ rtems_unsigned32 timeout,
+ rtems_unsigned32* read,
+ rtems_capture_record_t** recs)
+{
+ rtems_interrupt_level level;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_unsigned32 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,
+ TOD_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;
+ }
+
+ rtems_interrupt_disable (level);
+
+ capture_flags &= ~RTEMS_CAPTURE_READER_ACTIVE;
+
+ rtems_interrupt_enable (level);
+
+ 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 (rtems_unsigned32 count)
+{
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable (level);
+
+ if (count > capture_count)
+ count = capture_count;
+
+ capture_count -= count;
+
+ capture_out = (capture_count + count) % capture_size;
+
+ rtems_interrupt_enable (level);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * rtems_capture_tick_time
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the tick period in nano-seconds.
+ */
+rtems_unsigned32
+rtems_capture_tick_time ()
+{
+ 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 ()
+{
+ return capture_tasks;
+}
+
+/*
+ * rtems_capture_task_stack_usage
+ *
+ * DESCRIPTION:
+ *
+ * This function updates the stack usage. The task control block
+ * is updated.
+ */
+rtems_unsigned32
+rtems_capture_task_stack_usage (rtems_capture_task_t* task)
+{
+ if (task->tcb)
+ {
+ rtems_unsigned32* st;
+ rtems_unsigned32* 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 - (rtems_unsigned32*) 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 ()
+{
+ return capture_controls;
+}
+
diff --git a/c/src/libmisc/capture/capture.h b/c/src/libmisc/capture/capture.h
new file mode 100644
index 0000000000..7e5bfea9a8
--- /dev/null
+++ b/c/src/libmisc/capture/capture.h
@@ -0,0 +1,869 @@
+/*
+ ------------------------------------------------------------------------
+ $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_control_t
+ *
+ * DESCRIPTION:
+ *
+ * RTEMS control holds the trigger and watch configuration for a group of
+ * tasks with the same name.
+ */
+typedef struct rtems_capture_control_s
+{
+ rtems_name name;
+ rtems_id id;
+ rtems_unsigned32 flags;
+ rtems_name from[RTEMS_CAPTURE_TRIGGER_TASKS];
+ rtems_id from_id[RTEMS_CAPTURE_TRIGGER_TASKS];
+ struct rtems_capture_control_s* next;
+} rtems_capture_control_t;
+
+/*
+ * Control flags.
+ */
+#define RTEMS_CAPTURE_WATCH (1 << 0)
+#define RTEMS_CAPTURE_FROM_ANY (1 << 1)
+#define RTEMS_CAPTURE_TO_ANY (1 << 2)
+#define RTEMS_CAPTURE_FROM_TO (1 << 3)
+
+/*
+ * rtems_capture_control_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.
+ *
+ * The inline heper 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;
+ rtems_unsigned32 flags;
+ rtems_tcb* tcb;
+ rtems_unsigned32 in;
+ rtems_unsigned32 out;
+ rtems_task_priority start_priority;
+ rtems_unsigned32 stack_size;
+ rtems_unsigned32 stack_clean;
+ rtems_unsigned32 ticks;
+ rtems_unsigned32 tick_offset;
+ rtems_unsigned32 ticks_in;
+ rtems_unsigned32 tick_offset_in;
+ rtems_unsigned32 last_ticks;
+ rtems_unsigned32 last_tick_offset;
+ rtems_capture_control_t* control;
+ struct rtems_capture_task_s* next;
+} 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;
+ rtems_unsigned32 events;
+ rtems_unsigned32 ticks;
+ rtems_unsigned32 tick_offset;
+} rtems_capture_record_t;
+
+/*
+ * The capture record event flags.
+ */
+#define RTEMS_CAPTURE_REAL_PRI_EVENT_MASK (0x000000ff)
+#define RTEMS_CAPTURE_CURR_PRI_EVENT_MASK (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 (1 << 16)
+#define RTEMS_CAPTURE_CREATED_EVENT (1 << 17)
+#define RTEMS_CAPTURE_STARTED_BY_EVENT (1 << 18)
+#define RTEMS_CAPTURE_STARTED_EVENT (1 << 19)
+#define RTEMS_CAPTURE_RESTARTED_BY_EVENT (1 << 20)
+#define RTEMS_CAPTURE_RESTARTED_EVENT (1 << 21)
+#define RTEMS_CAPTURE_DELETED_BY_EVENT (1 << 22)
+#define RTEMS_CAPTURE_DELETED_EVENT (1 << 23)
+#define RTEMS_CAPTURE_BEGIN_EVENT (1 << 24)
+#define RTEMS_CAPTURE_EXITTED_EVENT (1 << 25)
+#define RTEMS_CAPTURE_SWITCHED_OUT_EVENT (1 << 26)
+#define RTEMS_CAPTURE_SWITCHED_IN_EVENT (1 << 27)
+#define RTEMS_CAPTURE_TIMESTAMP (1 << 28)
+#define RTEMS_CAPTURE_EVENT_END (28)
+
+/*
+ * rtems_capture_trigger_t
+ *
+ * DESCRIPTION:
+ *
+ * The types of triggers that exist. FIXME: add more here.
+ */
+typedef enum rtems_capture_trigger_t
+{
+ rtems_capture_to_any,
+ rtems_capture_from_any,
+ rtems_capture_from_to
+} 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)
+ (rtems_unsigned32* ticks, rtems_unsigned32* 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 (rtems_unsigned32 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 ();
+
+/*
+ * rtems_capture_control
+ *
+ * DESCRIPTION:
+ *
+ * This function allows control of tracing at a global level.
+ */
+rtems_status_code
+rtems_capture_control (rtems_boolean 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 (rtems_boolean 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, rtems_boolean 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 (rtems_boolean enable);
+
+/*
+ * rtems_capture_watch_global_on
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the global watch state.
+ */
+rtems_boolean
+rtems_capture_watch_global_on ();
+
+/*
+ * 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 ();
+
+/*
+ * 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 ();
+
+/*
+ * rtems_capture_set_trigger
+ *
+ * DESCRIPTION:
+ *
+ * This function sets an edge trigger. Left is the left side of
+ * the edge and right is right side of the edge. The trigger type
+ * can be -
+ *
+ * FROM_ANY : a switch from any task to the right side of the edge.
+ * TO_ANY : a switch from the left side of the edge to any task.
+ * FROM_TO : a switch from the left side of the edge to the right
+ * side of the edge.
+ *
+ * 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,
+ rtems_id from_id,
+ rtems_name to,
+ rtems_id to_id,
+ 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 (rtems_unsigned32 threshold,
+ rtems_unsigned32 timeout,
+ rtems_unsigned32* 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 (rtems_unsigned32 count);
+
+/*
+ * rtems_capture_tick_time
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the tick period in micro-seconds.
+ */
+rtems_unsigned32
+rtems_capture_tick_time ();
+
+/*
+ * rtems_capture_tick_time
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the tick period in micro-seconds.
+ */
+rtems_unsigned32
+rtems_capture_tick_time ();
+
+/*
+ * 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 ();
+
+/*
+ * 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->next;
+}
+
+/*
+ * rtems_capture_task_valid
+ *
+ * DESCRIPTION:
+ *
+ * This function returns true if the task control block points to
+ * a valid task.
+ */
+static inline rtems_boolean
+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 rtems_unsigned32
+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 rtems_unsigned32
+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 rtems_unsigned32
+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 rtems_unsigned32
+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.
+ */
+rtems_unsigned32
+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 rtems_unsigned32
+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 rtems_unsigned32
+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 rtems_unsigned32
+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 rtems_unsigned32
+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;
+ rtems_unsigned32 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 rtems_unsigned32
+rtems_capture_task_count ()
+{
+ rtems_capture_task_t* task = rtems_capture_get_task_list ();
+ rtems_unsigned32 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 ();
+
+/*
+ * 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 rtems_unsigned32
+rtems_capture_control_flags (rtems_capture_control_t* control)
+{
+ return control->flags;
+}
+
+/*
+ * rtems_capture_control_from_name
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the control from task name.
+ */
+static inline rtems_name
+rtems_capture_control_from_name (rtems_capture_control_t* control, int from)
+{
+ if (from < RTEMS_CAPTURE_TRIGGER_TASKS)
+ return control->from[from];
+ return control->from[0];
+}
+
+/*
+ * rtems_capture_control_from_id
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the control from task id.
+ */
+static inline rtems_id
+rtems_capture_control_from_id (rtems_capture_control_t* control, int from)
+{
+ if (from < RTEMS_CAPTURE_TRIGGER_TASKS)
+ return control->from_id[from];
+ return control->from_id[0];
+}
+
+/*
+ * rtems_capture_control_count
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the number of controls the capture
+ * engine has.
+ */
+static inline rtems_unsigned32
+rtems_capture_control_count ()
+{
+ rtems_capture_control_t* control = rtems_capture_get_control_list ();
+ rtems_unsigned32 count = 0;
+
+ while (control)
+ {
+ count++;
+ control = rtems_capture_next_control (control);
+ }
+
+ return count;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/libmisc/configure.ac b/c/src/libmisc/configure.ac
index 8ffcc748cc..ee93af7192 100644
--- a/c/src/libmisc/configure.ac
+++ b/c/src/libmisc/configure.ac
@@ -43,6 +43,7 @@ monitor/Makefile
rtmonuse/Makefile
rootfs/Makefile
stackchk/Makefile
+capture/Makefile
untar/Makefile
mw-fb/Makefile
wrapup/Makefile
diff --git a/c/src/libmisc/wrapup/Makefile.am b/c/src/libmisc/wrapup/Makefile.am
index c0313b140c..c0fe6d5363 100644
--- a/c/src/libmisc/wrapup/Makefile.am
+++ b/c/src/libmisc/wrapup/Makefile.am
@@ -19,7 +19,7 @@ TMP_LIBS = ../monitor/$(ARCH)/libmonitor-tmp.a \
../cpuuse/$(ARCH)/libcpuuse-tmp.a ../rtmonuse/$(ARCH)/librtmonuse-tmp.a \
../shell/$(ARCH)/libshell-tmp.a ../dumpbuf/$(ARCH)/libdumpbuf-tmp.a \
../devnull/$(ARCH)/libdevnull-tmp.a ../dummy/$(ARCH)/libdummy-tmp.a \
- ../mw-fb/$(ARCH)/libmw-fb-tmp.a $(NETLIBS)
+ ../mw-fb/$(ARCH)/libmw-fb-tmp.a ../capture/$(ARCH)/libcapture-tmp.a
$(PROJECT_RELEASE)/lib/$(LIBNAME)$(LIB_VARIANT).a: $(LIB)
$(INSTALL_DATA) $< $@
diff --git a/cpukit/libmisc/ChangeLog b/cpukit/libmisc/ChangeLog
index 334a3edfcc..1365bea8e3 100644
--- a/cpukit/libmisc/ChangeLog
+++ b/cpukit/libmisc/ChangeLog
@@ -1,3 +1,12 @@
+2002-05-16 Chris Johns <ccj@acm.org>
+
+ * Per PR194, added the Capture engine.
+ * capture/Makefile.am, capture/README, capture/capture-cli.c,
+ capture/capture-cli.h, capture/capture.c, capture/capture.h,
+ capture/.cvsignore: New files.
+ * Makefile.am, configure.ac, wrapup/Makefile.am: Modified to
+ reflect addition.
+
2001-05-14 Joel Sherrill <joel@OARcorp.com>
* dummy/Makefile.am, wrapup/Makefile.am: Fixed to generate
diff --git a/cpukit/libmisc/Makefile.am b/cpukit/libmisc/Makefile.am
index cfa832ffba..fa1d2a1b9a 100644
--- a/cpukit/libmisc/Makefile.am
+++ b/cpukit/libmisc/Makefile.am
@@ -4,8 +4,8 @@
ACLOCAL_AMFLAGS = -I ../../../aclocal
-SUBDIRS = devnull dummy dumpbuf stackchk monitor cpuuse shell rtmonuse rootfs untar \
- mw-fb wrapup
+SUBDIRS = capture cpuuse devnull dummy dumpbuf monitor mw-fb shell rootfs \
+ rtmonuse stackchk untar wrapup
EXTRA_DIST = README
diff --git a/cpukit/libmisc/capture/.cvsignore b/cpukit/libmisc/capture/.cvsignore
new file mode 100644
index 0000000000..282522db03
--- /dev/null
+++ b/cpukit/libmisc/capture/.cvsignore
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/cpukit/libmisc/capture/Makefile.am b/cpukit/libmisc/capture/Makefile.am
new file mode 100644
index 0000000000..fe533b265e
--- /dev/null
+++ b/cpukit/libmisc/capture/Makefile.am
@@ -0,0 +1,44 @@
+##
+## $Id$
+##
+
+AUTOMAKE_OPTIONS = foreign 1.4
+
+include_rtemsdir = $(includedir)/rtems
+
+LIBNAME = libcapture-tmp
+LIB = $(ARCH)/$(LIBNAME).a
+
+C_FILES = capture.c capture-cli.c
+C_O_FILES = $(C_FILES:%.c=$(ARCH)/%.o)
+
+include_rtems_HEADERS = capture.h capture-cli.h
+
+OBJS = $(C_O_FILES)
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
+include $(top_srcdir)/../../../automake/compile.am
+include $(top_srcdir)/../../../automake/lib.am
+
+$(PROJECT_INCLUDE)/rtems:
+ @$(mkinstalldirs) $@
+$(PROJECT_INCLUDE)/rtems/%.h: %.h
+ $(INSTALL_DATA) $< $@
+
+#
+# (OPTIONAL) Add local stuff here using +=
+#
+
+$(LIB): $(OBJS)
+ $(make-library)
+
+PREINSTALL_FILES = $(PROJECT_INCLUDE)/rtems \
+ $(include_rtems_HEADERS:%=$(PROJECT_INCLUDE)/rtems/%)
+
+all-local: $(ARCH) $(PREINSTALL_FILES) $(OBJS) $(LIB)
+
+.PRECIOUS: $(LIB)
+
+EXTRA_DIST = README capture.c capture-cli.c
+
+include $(top_srcdir)/../../../automake/local.am
diff --git a/cpukit/libmisc/capture/README b/cpukit/libmisc/capture/README
new file mode 100644
index 0000000000..2ea76a4cfe
--- /dev/null
+++ b/cpukit/libmisc/capture/README
@@ -0,0 +1,255 @@
+#
+# $Id$
+#
+
+ RTEMS Performance Monitoring and Measurement Framework
+
+ Copyright 2002 Chris Johns (ccj@acm.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..0ed145fafc
--- /dev/null
+++ b/cpukit/libmisc/capture/capture-cli.c
@@ -0,0 +1,1406 @@
+/*
+ ------------------------------------------------------------------------
+ $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.
+
+*/
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <rtems.h>
+#include <rtems/capture-cli.h>
+#include <rtems/monitor.h>
+
+#define RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS (32)
+
+/*
+ * 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)
+{
+ rtems_unsigned32 size = 0;
+ rtems_boolean enable = 0;
+ rtems_status_code sc;
+ int arg;
+
+ if (argc <= 1)
+ {
+ printf (open_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ if (argv[arg][1] == 'i')
+ enable = 1;
+ else
+ printf ("warning: option -%c ignored\n", argv[arg][1]);
+ }
+ else
+ {
+ size = strtoul (argv[arg], 0, 0);
+
+ if (size < 100)
+ {
+ printf ("error: size must be greater than or equal to 100\n");
+ return;
+ }
+ }
+ }
+
+ sc = rtems_capture_open (size, capture_timestamp);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: open failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("capture engine opened.\n");
+
+ if (!enable)
+ return;
+
+ sc = rtems_capture_control (enable);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: open enable failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("capture engine enabled.\n");
+}
+
+/*
+ * rtems_capture_cli_close
+ *
+ * DESCRIPTION:
+ *
+ * This function closes the capture engine.
+ *
+ */
+
+static void
+rtems_capture_cli_close (int argc, char **argv)
+{
+ rtems_status_code sc;
+
+ sc = rtems_capture_close ();
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: close failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("capture engine closed.\n");
+}
+
+/*
+ * rtems_capture_cli_enable
+ *
+ * DESCRIPTION:
+ *
+ * This function enables the capture engine.
+ *
+ */
+
+static void
+rtems_capture_cli_enable (int argc, char **argv)
+{
+ rtems_status_code sc;
+
+ sc = rtems_capture_control (1);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: enable failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("capture engine enabled.\n");
+}
+
+/*
+ * rtems_capture_cli_disable
+ *
+ * DESCRIPTION:
+ *
+ * This function disables the capture engine.
+ *
+ */
+
+static void
+rtems_capture_cli_disable (int argc, char **argv)
+{
+ rtems_status_code sc;
+
+ sc = rtems_capture_control (0);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: disable failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("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, char **argv)
+{
+ 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 ();
+ rtems_unsigned32 ticks;
+ rtems_unsigned32 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;
+ }
+
+ total_time = (ticks * rtems_capture_task_time (task)) + tick_offset;
+
+ printf ("total %i\n", count);
+
+ while (task)
+ {
+ rtems_task_priority priority;
+ int stack_used;
+ int time_used;
+
+ stack_used = rtems_capture_task_stack_usage (task) * 100;
+ stack_used /= rtems_capture_task_stack_size (task);
+
+ if (stack_used > 100)
+ stack_used = 100;
+
+ time_used = (rtems_capture_task_time (task) * 100) / total_time;
+
+ if (time_used > 100)
+ time_used = 100;
+
+ priority = rtems_capture_task_real_priority (task);
+
+ printf (" ");
+ rtems_monitor_dump_id (rtems_capture_task_id (task));
+ printf (" ");
+ rtems_monitor_dump_name (rtems_capture_task_name (task));
+ printf (" ");
+ rtems_monitor_dump_priority (rtems_capture_task_start_priority (task));
+ printf (" ");
+ rtems_monitor_dump_priority (rtems_capture_task_real_priority (task));
+ printf (" ");
+ rtems_monitor_dump_priority (rtems_capture_task_curr_priority (task));
+ printf (" ");
+ rtems_monitor_dump_state (rtems_capture_task_state (task));
+ printf (" %c%c%c%c%c",
+ rtems_capture_task_valid (task) ? 'a' : 'd',
+ rtems_capture_task_flags (task) & RTEMS_CAPTURE_TRACED ? 't' : '-',
+ rtems_capture_task_control_flags (task) & RTEMS_CAPTURE_TO_ANY ? 'F' : '-',
+ rtems_capture_task_control_flags (task) & RTEMS_CAPTURE_FROM_ANY ? 'T' : '-',
+ rtems_capture_task_control_flags (task) & RTEMS_CAPTURE_FROM_TO ? 'E' : '-');
+ if ((floor > ceiling) && (ceiling > priority))
+ printf ("--");
+ else
+ printf ("%c%c",
+ rtems_capture_task_control (task) ?
+ (rtems_capture_task_control_flags (task) & RTEMS_CAPTURE_WATCH ? 'w' : '+') : '-',
+ rtems_capture_watch_global_on () ? 'g' : '-');
+ printf (" %3i%% %3i%% (%i)\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)
+{
+ rtems_task_priority ceiling = rtems_capture_watch_get_ceiling ();
+ rtems_task_priority floor = rtems_capture_watch_get_floor ();
+ int last_count = 0;
+
+ printf ("\x1b[2J Press ENTER to exit.\n\n");
+ printf (" PID NAME RPRI CPRI STATE %%CPU %%STK FLGS EXEC TIME\n");
+
+ 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 ();
+
+ while (task)
+ {
+ if (rtems_capture_task_valid (task))
+ {
+ unsigned long long l = rtems_capture_task_delta_time (task);
+
+ count++;
+
+ 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);
+ }
+
+ printf ("\x1b[4;0H");
+
+ total_time = 0;
+
+ for (i = 0; i < RTEMS_CAPTURE_CLI_MAX_LOAD_TASKS; i++)
+ total_time += load[i];
+
+ 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]) * 100;
+ stack_used /= rtems_capture_task_stack_size (tasks[i]);
+
+ if (stack_used > 100)
+ stack_used = 100;
+
+ task_load = (int) ((load[i] * 100000) / total_time);
+
+ priority = rtems_capture_task_real_priority (tasks[i]);
+
+ printf ("\x1b[K");
+ rtems_monitor_dump_id (rtems_capture_task_id (tasks[i]));
+ printf (" ");
+ rtems_monitor_dump_name (rtems_capture_task_name (tasks[i]));
+ printf (" ");
+ rtems_monitor_dump_priority (priority);
+ printf (" ");
+ rtems_monitor_dump_priority (rtems_capture_task_curr_priority (tasks[i]));
+ printf (" ");
+ k = rtems_monitor_dump_state (rtems_capture_task_state (tasks[i]));
+ printf ("%*c %3i.%03i%% ", 6 - k, ' ', task_load / 1000, task_load % 1000);
+ printf ("%3i%% %c%c%c%c%c", stack_used,
+ rtems_capture_task_valid (tasks[i]) ? 'a' : 'd',
+ rtems_capture_task_flags (tasks[i]) & RTEMS_CAPTURE_TRACED ? 't' : '-',
+ rtems_capture_task_control_flags (tasks[i]) & RTEMS_CAPTURE_TO_ANY ? 'F' : '-',
+ rtems_capture_task_control_flags (tasks[i]) & RTEMS_CAPTURE_FROM_ANY ? 'T' : '-',
+ rtems_capture_task_control_flags (tasks[i]) & RTEMS_CAPTURE_FROM_TO ? 'E' : '-');
+ if ((floor > ceiling) && (ceiling > priority))
+ printf ("--");
+ else
+ printf ("%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' : '-');
+
+ printf (" %qi\n", rtems_capture_task_time (tasks[i]));
+ }
+
+ while (j)
+ {
+ printf ("\x1b[K\n");
+ j--;
+ }
+
+ last_count = count;
+
+ cli_load_thread_active = 0;
+
+ rtems_task_wake_after (TOD_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, char **argv)
+{
+ 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)
+ {
+ printf ("error: cannot obtain the current priority: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ memcpy (&name, "CPlt", 4);
+
+ sc = rtems_task_create (name, priority, 1024,
+ RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
+ RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR,
+ &id);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("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)
+ {
+ printf ("error: cannot start helper thread: %s\n", rtems_status_text (sc));
+ rtems_task_delete (id);
+ return;
+ }
+
+ for (;;)
+ {
+ char c = getchar ();
+
+ if ((c == '\r') || (c == '\n'))
+ {
+ int loops = 20;
+
+ while (loops && cli_load_thread_active)
+ rtems_task_wake_after (TOD_MICROSECONDS_TO_TICKS (100000));
+
+ rtems_task_delete (id);
+
+ printf ("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, char **argv)
+{
+ 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 ();
+
+ printf ("watch priority ceiling is %i\n", ceiling);
+ printf ("watch priority floor is %i\n", floor);
+ printf ("global watch is %s\n",
+ rtems_capture_watch_global_on () ? "enabled" : "disabled");
+ printf ("total %d\n", rtems_capture_control_count ());
+
+ while (control)
+ {
+ int f;
+ int fshowed;
+ int lf;
+
+ printf (" ");
+ rtems_monitor_dump_id (rtems_capture_control_id (control));
+ printf (" ");
+ rtems_monitor_dump_name (rtems_capture_control_name (control));
+ printf (" %c%c%c%c%c",
+ rtems_capture_control_flags (control) & RTEMS_CAPTURE_WATCH ? 'w' : '-',
+ rtems_capture_watch_global_on () ? 'g' : '-',
+ rtems_capture_control_flags (control) & RTEMS_CAPTURE_TO_ANY ? 'F' : '-',
+ rtems_capture_control_flags (control) & RTEMS_CAPTURE_FROM_ANY ? 'T' : '-',
+ rtems_capture_control_flags (control) & RTEMS_CAPTURE_FROM_TO ? 'E' : '-');
+
+ for (f = 0, fshowed = 0, lf = 1; f < RTEMS_CAPTURE_TRIGGER_TASKS; f++)
+ {
+ if (lf && ((fshowed % 16) == 0))
+ {
+ printf ("\n");
+ lf = 0;
+ }
+
+ /*
+ * FIXME: name test.
+ */
+ if (rtems_capture_control_from_name (control, f))
+ {
+ printf (" %2i:", f);
+ rtems_monitor_dump_name (rtems_capture_control_from_name (control, f));
+ printf ("/");
+ rtems_monitor_dump_id (rtems_capture_control_from_id (control, f));
+ fshowed++;
+ lf = 1;
+ }
+ }
+
+ if (lf)
+ printf ("\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 rtems_boolean
+rtems_capture_cli_get_name_id (char* arg,
+ rtems_boolean* valid_name,
+ rtems_boolean* valid_id,
+ rtems_name* name,
+ rtems_id* id)
+{
+ Objects_Classes objclass;
+ int l;
+ int i;
+
+ if (*valid_name && *valid_id)
+ {
+ printf ("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 (arg[i]))
+ break;
+
+ *id = strtoul (arg, 0, 16);
+
+ objclass = _Objects_Get_class (*id);
+
+ if ((i == l) && (l > 4) &&
+ ((objclass == OBJECTS_INTERNAL_THREADS) ||
+ (objclass == OBJECTS_RTEMS_TASKS) ||
+ (objclass == OBJECTS_POSIX_THREADS) ||
+ (objclass == OBJECTS_ITRON_TASKS)))
+ *valid_id = 1;
+ else
+ {
+ memcpy (name, arg, sizeof (rtems_name));
+ *valid_name = 1;
+ }
+
+ 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)
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_name name = 0;
+ rtems_id id = 0;
+ rtems_boolean valid_name = 0;
+ rtems_boolean valid_id = 0;
+
+ if (argc <= 1)
+ {
+ printf (watch_add_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ printf ("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)
+ {
+ printf("error: no valid name or task id located\n");
+ return;
+ }
+
+ sc = rtems_capture_watch_add (name, id);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: watch add failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("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)
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_name name = 0;
+ rtems_id id = 0;
+ rtems_boolean valid_name = 0;
+ rtems_boolean valid_id = 0;
+
+ if (argc <= 1)
+ {
+ printf (watch_del_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ printf ("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)
+ {
+ printf("error: no valid name or task id located\n");
+ return;
+ }
+
+ sc = rtems_capture_watch_del (name, id);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: watch delete failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("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)
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_name name = 0;
+ rtems_id id = 0;
+ rtems_boolean valid_name = 0;
+ rtems_boolean valid_id = 0;
+ rtems_boolean enable = 0;
+
+ if (argc <= 2)
+ {
+ printf (watch_control_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ printf ("warning: option -%c ignored\n", argv[arg][1]);
+ }
+ else
+ {
+ if (strcmp (argv[arg], "on") == 0)
+ enable = 1;
+ else if (strcmp (argv[arg], "off") == 0)
+ enable = 0;
+ else if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id, &name, &id))
+ return;
+ }
+ }
+
+ if (!valid_name && !valid_id)
+ {
+ printf("error: no valid name or task id located\n");
+ return;
+ }
+
+ sc = rtems_capture_watch_ctrl (name, id, enable);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: watch control failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("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)
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_boolean enable = 0;
+
+ if (argc <= 1)
+ {
+ printf (watch_global_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ printf ("warning: option -%c ignored\n", argv[arg][1]);
+ }
+ else
+ {
+ if (strcmp (argv[arg], "on") == 0)
+ enable = 1;
+ else if (strcmp (argv[arg], "off") == 0)
+ enable = 0;
+ }
+ }
+
+ sc = rtems_capture_watch_global (enable);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: global watch failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("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)
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_task_priority priority = 0;
+
+ if (argc <= 1)
+ {
+ printf (watch_ceiling_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ printf ("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)
+ {
+ printf ("error: watch ceiling failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("watch ceiling is %i.\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)
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_task_priority priority = 0;
+
+ if (argc <= 1)
+ {
+ printf (watch_floor_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ printf ("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)
+ {
+ printf ("error: watch floor failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("watch floor is %i.\n", priority);
+}
+
+/*
+ * rtems_capture_cli_trigger_set
+ *
+ * DESCRIPTION:
+ *
+ * This function is a monitor command that sets a trigger.
+ *
+ */
+
+static char const *trigger_set_usage = "usage: ctrig type [from] [fromid] [to] [to id]\n";
+
+static void
+rtems_capture_cli_trigger_set (int argc, char **argv)
+{
+ rtems_status_code sc;
+ int arg;
+ rtems_capture_trigger_t trigger = rtems_capture_from_to;
+ rtems_boolean trigger_set = 0;
+ rtems_name name = 0;
+ rtems_id id = 0;
+ rtems_boolean valid_name = 0;
+ rtems_boolean valid_id = 0;
+ rtems_name from_name = 0;
+ rtems_id from_id = 0;
+ rtems_boolean from_valid_name = 0;
+ rtems_boolean from_valid_id = 0;
+ rtems_name to_name = 0;
+ rtems_id to_id = 0;
+ rtems_boolean to_valid_name = 0;
+ rtems_boolean to_valid_id = 0;
+
+ if (argc <= 2)
+ {
+ printf (trigger_set_usage);
+ return;
+ }
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ printf ("warning: option -%c ignored\n", argv[arg][1]);
+ }
+ else
+ {
+ if (!trigger_set)
+ {
+ if (strcmp (argv[arg], "from") == 0)
+ trigger = rtems_capture_to_any;
+ else if (strcmp (argv[arg], "to") == 0)
+ trigger = rtems_capture_from_any;
+ else if (strcmp (argv[arg], "edge") == 0)
+ trigger = rtems_capture_from_any;
+ else
+ {
+ printf ("error: the first argument is the trigger type (from/to/edge)\n");
+ return;
+ }
+ trigger_set = 1;
+ }
+ else
+ {
+ if (trigger == rtems_capture_to_any)
+ {
+ if (from_valid_name && from_valid_id)
+ printf ("warning: extra arguments ignored\n");
+ else if (!rtems_capture_cli_get_name_id (argv[arg], &from_valid_name, &from_valid_id,
+ &from_name, &from_id))
+ return;
+ }
+ else if (trigger == rtems_capture_from_any)
+ {
+ if (to_valid_name && to_valid_id)
+ printf ("warning: extra arguments ignored\n");
+ else if (!rtems_capture_cli_get_name_id (argv[arg], &to_valid_name, &to_valid_id,
+ &to_name, &to_id))
+ return;
+ }
+ else if (trigger == rtems_capture_from_to)
+ {
+ if (from_valid_name && from_valid_id && to_valid_name && to_valid_id)
+ printf ("warning: extra arguments ignored\n");
+ else
+ {
+ if (!rtems_capture_cli_get_name_id (argv[arg], &valid_name, &valid_id,
+ &name, &id))
+ return;
+
+ if (valid_name)
+ {
+ if (!from_valid_name && !from_valid_id)
+ {
+ from_valid_name = 1;
+ from_name = name;
+ }
+ else if (to_valid_name)
+ printf ("warning: extra arguments ignored\n");
+ else
+ {
+ to_valid_name = 1;
+ to_name = name;
+ }
+ }
+ if (valid_id)
+ {
+ if (!from_valid_id && !to_valid_name)
+ {
+ from_valid_id = 1;
+ from_id = id;
+ }
+ else if (to_valid_id)
+ printf ("warning: extra arguments ignored\n");
+ else
+ {
+ to_valid_id = 1;
+ to_id = id;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ((trigger == rtems_capture_to_any) && !from_valid_name && !from_valid_id)
+ {
+ printf ("error: a from trigger need a to name or id\n");
+ return;
+ }
+
+ if ((trigger == rtems_capture_from_any) && !to_valid_name && !to_valid_id)
+ {
+ printf ("error: a to trigger need a from name or id\n");
+ return;
+ }
+
+ if ((trigger == rtems_capture_from_to) &&
+ ((!from_valid_name && !from_valid_id) || (!to_valid_name && !to_valid_id)))
+ {
+ printf ("error: an edge trigger need a from and to name or id\n");
+ return;
+ }
+
+ sc = rtems_capture_set_trigger (from_name, from_id, to_name, to_id, trigger);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: setting the trigger failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("trigger set.\n");
+}
+
+/*
+ * 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)
+{
+ rtems_status_code sc;
+ rtems_boolean csv = 0;
+ static int dump_total = 32;
+ int total;
+ int count;
+ rtems_unsigned32 read;
+ rtems_capture_record_t* rec;
+ int arg;
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ if (argv[arg][1] == 'c')
+ csv = 1;
+ else if (argv[arg][1] == 'r')
+ {
+ int i;
+ int l;
+
+ arg++;
+ if (arg == argc)
+ {
+ printf ("error: option -r requires number\n");
+ return;
+ }
+
+ l = strlen (argv[arg]);
+
+ for (i = 0; i < l; i++)
+ if (!isdigit (argv[arg][i]))
+ {
+ printf ("error: option -r requires number and currently it is not\n");
+ return;
+ }
+
+ dump_total = strtoul (argv[arg], 0, 0);
+ }
+ else
+ printf ("warning: option -%c ignored\n", argv[arg][1]);
+ }
+ }
+
+ total = dump_total;
+
+ while (total)
+ {
+ sc = rtems_capture_read (0, 0, &read, &rec);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: trace read failed: %s\n", rtems_status_text (sc));
+ rtems_capture_flush (0);
+ return;
+ }
+
+ if (read == 0)
+ break;
+
+ for (count = 0; count < read; count++, rec++)
+ {
+ if (csv)
+ printf ("%08x,%03d,%03d,%04x,%d,%d\n",
+ (rtems_unsigned32) 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;
+ rtems_unsigned32 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)
+ {
+ printf ("%9li.%06li ", (unsigned long) (t / 1000000),
+ (unsigned long) (t % 1000000));
+ rtems_monitor_dump_id (rtems_capture_task_id (rec->task));
+ printf (" ");
+ rtems_monitor_dump_name (rtems_capture_task_name (rec->task));
+ printf (" %3i %3i %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;
+ }
+ }
+ }
+
+ if (read < total)
+ total -= read;
+ else
+ total = 0;
+
+ rtems_capture_release (read);
+ }
+}
+
+/*
+ * 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)
+{
+ rtems_status_code sc;
+ rtems_boolean prime = 1;
+ int arg;
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ if (argv[arg][1] == 'n')
+ prime = 0;
+ else
+ printf ("warning: option -%c ignored\n", argv[arg][1]);
+ }
+ }
+
+ sc = rtems_capture_flush (prime);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ printf ("error: flush failed: %s\n", rtems_status_text (sc));
+ return;
+ }
+
+ printf ("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,
+ (void*) rtems_capture_cli_open,
+ 0,
+ 0
+ },
+ {
+ "cclose",
+ "usage: cclose\n",
+ 0,
+ (void*) rtems_capture_cli_close,
+ 0,
+ 0
+ },
+ {
+ "cenable",
+ "usage: cenable\n",
+ 0,
+ (void*) rtems_capture_cli_enable,
+ 0,
+ 0
+ },
+ {
+ "cdisable",
+ "usage: cdisable\n",
+ 0,
+ (void*) rtems_capture_cli_disable,
+ 0,
+ 0
+ },
+ {
+ "ctlist",
+ "usage: ctlist \n",
+ 0,
+ (void*) rtems_capture_cli_task_list,
+ 0,
+ 0
+ },
+ {
+ "ctload",
+ "usage: ctload \n",
+ 0,
+ (void*) rtems_capture_cli_task_load,
+ 0,
+ 0
+ },
+ {
+ "cwlist",
+ "usage: cwlist\n",
+ 0,
+ (void*) rtems_capture_cli_watch_list,
+ 0,
+ 0
+ },
+ {
+ "cwadd",
+ "usage: cwadd [task name] [id]\n",
+ 0,
+ (void*) rtems_capture_cli_watch_add,
+ 0,
+ 0
+ },
+ {
+ "cwdel",
+ "usage: cwdel [task name] [id]\n",
+ 0,
+ (void*) rtems_capture_cli_watch_del,
+ 0,
+ 0
+ },
+ {
+ "cwctl",
+ "usage: cwctl [task name] [id] on/off\n",
+ 0,
+ (void*) rtems_capture_cli_watch_control,
+ 0,
+ 0
+ },
+ {
+ "cwglob",
+ "usage: cwglob on/off\n",
+ 0,
+ (void*) rtems_capture_cli_watch_global,
+ 0,
+ 0
+ },
+ {
+ "cwceil",
+ "usage: cwceil priority\n",
+ 0,
+ (void*) rtems_capture_cli_watch_ceiling,
+ 0,
+ 0
+ },
+ {
+ "cwfloor",
+ "usage: cwfloor priority\n",
+ 0,
+ (void*) rtems_capture_cli_watch_floor,
+ 0,
+ 0
+ },
+ {
+ "ctrace",
+ "usage: ctrace [-c] [-r records]\n",
+ 0,
+ (void*) rtems_capture_cli_trace_records,
+ 0,
+ 0
+ },
+ {
+ "ctrig",
+ "usage: ctrig type [from name] [from id] [to name] [to id]\n",
+ 0,
+ (void*) rtems_capture_cli_trigger_set,
+ 0,
+ 0
+ },
+ {
+ "cflush",
+ "usage: cflush [-n]\n",
+ 0,
+ (void*) 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)
+{
+ int 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..968e3217f9
--- /dev/null
+++ b/cpukit/libmisc/capture/capture-cli.h
@@ -0,0 +1,52 @@
+/*
+ ------------------------------------------------------------------------
+ $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..b58d065d91
--- /dev/null
+++ b/cpukit/libmisc/capture/capture.c
@@ -0,0 +1,1565 @@
+/*
+ ------------------------------------------------------------------------
+ $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.
+
+*/
+
+#include <stdlib.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.
+ */
+#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)
+
+/*
+ * 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)
+
+/*
+ * RTEMS Capture Data.
+ */
+static rtems_capture_record_t* capture_records;
+static rtems_unsigned32 capture_size;
+static rtems_unsigned32 capture_count;
+static rtems_capture_record_t* capture_in;
+static rtems_unsigned32 capture_out;
+static rtems_unsigned32 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 rtems_unsigned32 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 (rtems_unsigned32* ticks,
+ rtems_unsigned32* 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 rtems_boolean
+rtems_capture_match_names (rtems_name lhs, rtems_name rhs)
+{
+ return lhs == rhs;
+}
+
+/*
+ * rtems_capture_dup_name
+ *
+ * DESCRIPTION:
+ *
+ * This function duplicates an rtems_names. It protects the
+ * cpature 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_name_in_group
+ *
+ * DESCRIPTION:
+ *
+ * This function sees if a name is in a group of names.
+ *
+ */
+static inline rtems_boolean
+rtems_capture_name_in_group (rtems_name task, rtems_name* tasks)
+{
+ if (tasks)
+ {
+ int i;
+ for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
+ if (rtems_capture_match_names (task, *tasks++))
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * rtems_capture_match_name_id
+ *
+ * DESCRIPTION:
+ *
+ * This function matches a name and/or id.
+ */
+static inline rtems_boolean
+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_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)
+ {
+ rtems_unsigned32* s;
+ rtems_unsigned32 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;
+
+ memset (control->from, 0, sizeof (control->from));
+ memset (control->from_id, 0, sizeof (control->from_id));
+
+ 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->next)
+ 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;
+
+ task = _Workspace_Allocate (sizeof (rtems_capture_task_t));
+
+ if (task == NULL)
+ {
+ capture_flags |= RTEMS_CAPTURE_NO_MEMORY;
+ return NULL;
+ }
+
+ rtems_capture_dup_name (&task->name, *((rtems_name*) new_task->Object.name));
+
+ task->id = new_task->Object.id;
+ task->flags = 0;
+ task->in = 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->next = capture_tasks;
+ 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_record
+ *
+ * DESCRIPTION:
+ *
+ * This function records a capture record into the capture buffer.
+ *
+ */
+static inline void
+rtems_capture_record (rtems_capture_task_t* task,
+ rtems_unsigned32 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)
+ {
+ 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++;
+ }
+ else
+ capture_flags |= RTEMS_CAPTURE_OVERFLOW;
+ rtems_interrupt_enable (level);
+ }
+ }
+}
+
+/*
+ * rtems_capture_create_task
+ *
+ * DESCRIPTION:
+ *
+ * This function is called when a task is created.
+ *
+ */
+static rtems_boolean
+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 ponters 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 we are logging then record this fact.
+ */
+ 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 rtems_extension
+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 ponters 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);
+
+ 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 rtems_extension
+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 ponters 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);
+
+ 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 rtems_extension
+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 ponters 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);
+
+ 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.
+ */
+ dt->tcb = 0;
+}
+
+/*
+ * rtems_capture_begin_task
+ *
+ * DESCRIPTION:
+ *
+ * This function is called when a task is begun.
+ *
+ */
+static rtems_extension
+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 ponters 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);
+
+ 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 rtems_extension
+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 ponters 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);
+
+ 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 rtems_extension
+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)
+ {
+ rtems_unsigned32 ticks;
+ rtems_unsigned32 tick_offset;
+
+ /*
+ * Get the cpature task control block so we can update the
+ * reference anbd perform any watch or trigger functions.
+ * The task ponters 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))
+ {
+ rtems_id ct_id = current_task->Object.id;
+
+ for (ct = capture_tasks; ct; ct = ct->next)
+ 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 we have not triggered then see if this is a trigger condition.
+ */
+ if (!(capture_flags & RTEMS_CAPTURE_TRIGGERED))
+ {
+ rtems_capture_control_t* cc = NULL;
+ rtems_capture_control_t* hc = NULL;
+
+ if (ct)
+ {
+ cc = ct->control;
+
+ /*
+ * Check the current task for a TO_ANY trigger.
+ */
+ if (cc && (cc->flags & RTEMS_CAPTURE_TO_ANY))
+ {
+ capture_flags |= RTEMS_CAPTURE_TRIGGERED;
+ goto triggered;
+ }
+ }
+
+ if (ht)
+ {
+ hc = ht->control;
+
+ /*
+ * Check the next task for a FROM_ANY.
+ */
+ if (hc && (hc->flags & RTEMS_CAPTURE_FROM_ANY))
+ {
+ capture_flags |= RTEMS_CAPTURE_TRIGGERED;
+ goto triggered;
+ }
+ }
+
+ /*
+ * Check is the trigger is from the current task
+ * to the next task.
+ */
+ if (cc && hc && (hc->flags & RTEMS_CAPTURE_FROM_TO))
+ if (rtems_capture_name_in_group (cc->name, hc->from))
+ {
+ capture_flags |= RTEMS_CAPTURE_TRIGGERED;
+ goto triggered;
+ }
+ }
+ else
+ {
+triggered:
+
+ 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 (rtems_unsigned32 size, rtems_capture_timestamp timestamp)
+{
+ 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_Table->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_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 ()
+{
+ 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;
+
+ 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->next;
+ _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 (rtems_boolean 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_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 (rtems_boolean prime)
+{
+ rtems_interrupt_level level;
+ rtems_capture_task_t* task;
+
+ rtems_interrupt_disable (level);
+
+ for (task = capture_tasks; task != NULL; task = task->next)
+ task->flags &= ~RTEMS_CAPTURE_TRACED;
+
+ if (prime)
+ capture_flags &= ~(RTEMS_CAPTURE_TRIGGERED | RTEMS_CAPTURE_OVERFLOW);
+ else
+ capture_flags &= ~RTEMS_CAPTURE_OVERFLOW;
+
+ capture_in = capture_records;
+ capture_out = 0;
+
+ rtems_interrupt_enable (level);
+
+ 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;
+ rtems_boolean found = 0;
+
+ /*
+ * Should this test be for wildcards ?
+ */
+
+ for (prev_control = &capture_controls, control = capture_controls;
+ control != NULL; )
+ {
+ if (rtems_capture_match_name_id (name, id, control->name, control->id))
+ {
+ rtems_interrupt_disable (level);
+
+ for (task = capture_tasks; task != NULL; task = task->next)
+ if (task->control == control)
+ task->control = 0;
+
+ *prev_control = control->next;
+
+ rtems_interrupt_enable (level);
+
+ _Workspace_Free (control);
+
+ control = *prev_control;
+
+ found = 1;
+ }
+ 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, rtems_boolean enable)
+{
+ rtems_interrupt_level level;
+ rtems_capture_control_t* control;
+ rtems_boolean found = 0;
+
+ /*
+ * 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 (name, id, control->name, control->id))
+ {
+ rtems_interrupt_disable (level);
+
+ if (enable)
+ control->flags |= RTEMS_CAPTURE_WATCH;
+ else
+ control->flags &= ~RTEMS_CAPTURE_WATCH;
+
+ rtems_interrupt_enable (level);
+
+ found = 1;
+ }
+ }
+
+ 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 (rtems_boolean 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.
+ */
+rtems_boolean
+rtems_capture_watch_global_on ()
+{
+ 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 ()
+{
+ 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 ()
+{
+ return capture_floor;
+}
+
+/*
+ * rtems_capture_set_trigger
+ *
+ * DESCRIPTION:
+ *
+ * This function sets an edge trigger. Left is the left side of
+ * the edge and right is right side of the edge. The trigger type
+ * can be -
+ *
+ * FROM_ANY : a switch from any task to the right side of the edge.
+ * TO_ANY : a switch from the left side of the edge to any task.
+ * FROM_TO : a switch from the left side of the edge to the right
+ * side of the edge.
+ *
+ * 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,
+ rtems_id from_id,
+ rtems_name to,
+ rtems_id to_id,
+ rtems_capture_trigger_t trigger)
+{
+ rtems_capture_control_t* control;
+ int i;
+
+ /*
+ * Find the capture control blocks for the from and to
+ * tasks.
+ */
+ if (trigger == rtems_capture_to_any)
+ {
+ control = rtems_capture_create_control (from, from_id);
+ if (control == NULL)
+ return RTEMS_NO_MEMORY;
+ control->flags |= RTEMS_CAPTURE_TO_ANY;
+ }
+
+ if ((trigger == rtems_capture_from_to) ||
+ (trigger == rtems_capture_from_any))
+ {
+ control = rtems_capture_create_control (to, to_id);
+ if (control == NULL)
+ return RTEMS_NO_MEMORY;
+
+ if (trigger == rtems_capture_from_any)
+ control->flags |= RTEMS_CAPTURE_FROM_ANY;
+ else
+ {
+ control->flags |= RTEMS_CAPTURE_FROM_TO;
+ for (i = 0; i < RTEMS_CAPTURE_TRIGGER_TASKS; i++)
+ {
+ if (control->from[i] == 0)
+ {
+ control->from[i] = from;
+ control->from_id[i] = from_id;
+ break;
+ }
+ }
+ }
+ }
+ 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 (rtems_unsigned32 threshold,
+ rtems_unsigned32 timeout,
+ rtems_unsigned32* read,
+ rtems_capture_record_t** recs)
+{
+ rtems_interrupt_level level;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_unsigned32 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,
+ TOD_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;
+ }
+
+ rtems_interrupt_disable (level);
+
+ capture_flags &= ~RTEMS_CAPTURE_READER_ACTIVE;
+
+ rtems_interrupt_enable (level);
+
+ 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 (rtems_unsigned32 count)
+{
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable (level);
+
+ if (count > capture_count)
+ count = capture_count;
+
+ capture_count -= count;
+
+ capture_out = (capture_count + count) % capture_size;
+
+ rtems_interrupt_enable (level);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * rtems_capture_tick_time
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the tick period in nano-seconds.
+ */
+rtems_unsigned32
+rtems_capture_tick_time ()
+{
+ 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 ()
+{
+ return capture_tasks;
+}
+
+/*
+ * rtems_capture_task_stack_usage
+ *
+ * DESCRIPTION:
+ *
+ * This function updates the stack usage. The task control block
+ * is updated.
+ */
+rtems_unsigned32
+rtems_capture_task_stack_usage (rtems_capture_task_t* task)
+{
+ if (task->tcb)
+ {
+ rtems_unsigned32* st;
+ rtems_unsigned32* 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 - (rtems_unsigned32*) 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 ()
+{
+ return capture_controls;
+}
+
diff --git a/cpukit/libmisc/capture/capture.h b/cpukit/libmisc/capture/capture.h
new file mode 100644
index 0000000000..7e5bfea9a8
--- /dev/null
+++ b/cpukit/libmisc/capture/capture.h
@@ -0,0 +1,869 @@
+/*
+ ------------------------------------------------------------------------
+ $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_control_t
+ *
+ * DESCRIPTION:
+ *
+ * RTEMS control holds the trigger and watch configuration for a group of
+ * tasks with the same name.
+ */
+typedef struct rtems_capture_control_s
+{
+ rtems_name name;
+ rtems_id id;
+ rtems_unsigned32 flags;
+ rtems_name from[RTEMS_CAPTURE_TRIGGER_TASKS];
+ rtems_id from_id[RTEMS_CAPTURE_TRIGGER_TASKS];
+ struct rtems_capture_control_s* next;
+} rtems_capture_control_t;
+
+/*
+ * Control flags.
+ */
+#define RTEMS_CAPTURE_WATCH (1 << 0)
+#define RTEMS_CAPTURE_FROM_ANY (1 << 1)
+#define RTEMS_CAPTURE_TO_ANY (1 << 2)
+#define RTEMS_CAPTURE_FROM_TO (1 << 3)
+
+/*
+ * rtems_capture_control_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.
+ *
+ * The inline heper 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;
+ rtems_unsigned32 flags;
+ rtems_tcb* tcb;
+ rtems_unsigned32 in;
+ rtems_unsigned32 out;
+ rtems_task_priority start_priority;
+ rtems_unsigned32 stack_size;
+ rtems_unsigned32 stack_clean;
+ rtems_unsigned32 ticks;
+ rtems_unsigned32 tick_offset;
+ rtems_unsigned32 ticks_in;
+ rtems_unsigned32 tick_offset_in;
+ rtems_unsigned32 last_ticks;
+ rtems_unsigned32 last_tick_offset;
+ rtems_capture_control_t* control;
+ struct rtems_capture_task_s* next;
+} 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;
+ rtems_unsigned32 events;
+ rtems_unsigned32 ticks;
+ rtems_unsigned32 tick_offset;
+} rtems_capture_record_t;
+
+/*
+ * The capture record event flags.
+ */
+#define RTEMS_CAPTURE_REAL_PRI_EVENT_MASK (0x000000ff)
+#define RTEMS_CAPTURE_CURR_PRI_EVENT_MASK (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 (1 << 16)
+#define RTEMS_CAPTURE_CREATED_EVENT (1 << 17)
+#define RTEMS_CAPTURE_STARTED_BY_EVENT (1 << 18)
+#define RTEMS_CAPTURE_STARTED_EVENT (1 << 19)
+#define RTEMS_CAPTURE_RESTARTED_BY_EVENT (1 << 20)
+#define RTEMS_CAPTURE_RESTARTED_EVENT (1 << 21)
+#define RTEMS_CAPTURE_DELETED_BY_EVENT (1 << 22)
+#define RTEMS_CAPTURE_DELETED_EVENT (1 << 23)
+#define RTEMS_CAPTURE_BEGIN_EVENT (1 << 24)
+#define RTEMS_CAPTURE_EXITTED_EVENT (1 << 25)
+#define RTEMS_CAPTURE_SWITCHED_OUT_EVENT (1 << 26)
+#define RTEMS_CAPTURE_SWITCHED_IN_EVENT (1 << 27)
+#define RTEMS_CAPTURE_TIMESTAMP (1 << 28)
+#define RTEMS_CAPTURE_EVENT_END (28)
+
+/*
+ * rtems_capture_trigger_t
+ *
+ * DESCRIPTION:
+ *
+ * The types of triggers that exist. FIXME: add more here.
+ */
+typedef enum rtems_capture_trigger_t
+{
+ rtems_capture_to_any,
+ rtems_capture_from_any,
+ rtems_capture_from_to
+} 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)
+ (rtems_unsigned32* ticks, rtems_unsigned32* 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 (rtems_unsigned32 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 ();
+
+/*
+ * rtems_capture_control
+ *
+ * DESCRIPTION:
+ *
+ * This function allows control of tracing at a global level.
+ */
+rtems_status_code
+rtems_capture_control (rtems_boolean 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 (rtems_boolean 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, rtems_boolean 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 (rtems_boolean enable);
+
+/*
+ * rtems_capture_watch_global_on
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the global watch state.
+ */
+rtems_boolean
+rtems_capture_watch_global_on ();
+
+/*
+ * 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 ();
+
+/*
+ * 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 ();
+
+/*
+ * rtems_capture_set_trigger
+ *
+ * DESCRIPTION:
+ *
+ * This function sets an edge trigger. Left is the left side of
+ * the edge and right is right side of the edge. The trigger type
+ * can be -
+ *
+ * FROM_ANY : a switch from any task to the right side of the edge.
+ * TO_ANY : a switch from the left side of the edge to any task.
+ * FROM_TO : a switch from the left side of the edge to the right
+ * side of the edge.
+ *
+ * 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,
+ rtems_id from_id,
+ rtems_name to,
+ rtems_id to_id,
+ 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 (rtems_unsigned32 threshold,
+ rtems_unsigned32 timeout,
+ rtems_unsigned32* 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 (rtems_unsigned32 count);
+
+/*
+ * rtems_capture_tick_time
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the tick period in micro-seconds.
+ */
+rtems_unsigned32
+rtems_capture_tick_time ();
+
+/*
+ * rtems_capture_tick_time
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the tick period in micro-seconds.
+ */
+rtems_unsigned32
+rtems_capture_tick_time ();
+
+/*
+ * 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 ();
+
+/*
+ * 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->next;
+}
+
+/*
+ * rtems_capture_task_valid
+ *
+ * DESCRIPTION:
+ *
+ * This function returns true if the task control block points to
+ * a valid task.
+ */
+static inline rtems_boolean
+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 rtems_unsigned32
+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 rtems_unsigned32
+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 rtems_unsigned32
+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 rtems_unsigned32
+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.
+ */
+rtems_unsigned32
+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 rtems_unsigned32
+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 rtems_unsigned32
+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 rtems_unsigned32
+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 rtems_unsigned32
+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;
+ rtems_unsigned32 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 rtems_unsigned32
+rtems_capture_task_count ()
+{
+ rtems_capture_task_t* task = rtems_capture_get_task_list ();
+ rtems_unsigned32 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 ();
+
+/*
+ * 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 rtems_unsigned32
+rtems_capture_control_flags (rtems_capture_control_t* control)
+{
+ return control->flags;
+}
+
+/*
+ * rtems_capture_control_from_name
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the control from task name.
+ */
+static inline rtems_name
+rtems_capture_control_from_name (rtems_capture_control_t* control, int from)
+{
+ if (from < RTEMS_CAPTURE_TRIGGER_TASKS)
+ return control->from[from];
+ return control->from[0];
+}
+
+/*
+ * rtems_capture_control_from_id
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the control from task id.
+ */
+static inline rtems_id
+rtems_capture_control_from_id (rtems_capture_control_t* control, int from)
+{
+ if (from < RTEMS_CAPTURE_TRIGGER_TASKS)
+ return control->from_id[from];
+ return control->from_id[0];
+}
+
+/*
+ * rtems_capture_control_count
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the number of controls the capture
+ * engine has.
+ */
+static inline rtems_unsigned32
+rtems_capture_control_count ()
+{
+ rtems_capture_control_t* control = rtems_capture_get_control_list ();
+ rtems_unsigned32 count = 0;
+
+ while (control)
+ {
+ count++;
+ control = rtems_capture_next_control (control);
+ }
+
+ return count;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cpukit/libmisc/configure.ac b/cpukit/libmisc/configure.ac
index 8ffcc748cc..ee93af7192 100644
--- a/cpukit/libmisc/configure.ac
+++ b/cpukit/libmisc/configure.ac
@@ -43,6 +43,7 @@ monitor/Makefile
rtmonuse/Makefile
rootfs/Makefile
stackchk/Makefile
+capture/Makefile
untar/Makefile
mw-fb/Makefile
wrapup/Makefile
diff --git a/cpukit/libmisc/wrapup/Makefile.am b/cpukit/libmisc/wrapup/Makefile.am
index c0313b140c..c0fe6d5363 100644
--- a/cpukit/libmisc/wrapup/Makefile.am
+++ b/cpukit/libmisc/wrapup/Makefile.am
@@ -19,7 +19,7 @@ TMP_LIBS = ../monitor/$(ARCH)/libmonitor-tmp.a \
../cpuuse/$(ARCH)/libcpuuse-tmp.a ../rtmonuse/$(ARCH)/librtmonuse-tmp.a \
../shell/$(ARCH)/libshell-tmp.a ../dumpbuf/$(ARCH)/libdumpbuf-tmp.a \
../devnull/$(ARCH)/libdevnull-tmp.a ../dummy/$(ARCH)/libdummy-tmp.a \
- ../mw-fb/$(ARCH)/libmw-fb-tmp.a $(NETLIBS)
+ ../mw-fb/$(ARCH)/libmw-fb-tmp.a ../capture/$(ARCH)/libcapture-tmp.a
$(PROJECT_RELEASE)/lib/$(LIBNAME)$(LIB_VARIANT).a: $(LIB)
$(INSTALL_DATA) $< $@