changeset 460:a65a4055f146

* src/common/kapi.cxx: * include/kapi.h: Added function cyg_thread_get_next(), cyg_thread_find() and cyg_thread_get_info() to allow the current set of threads to be enumerated, and per-thread information to be retrieved safely. * doc/kernel.sgml: Documented new KAPI calls. * src/common/thread.cxx: Zero unique_id in thread destructor so that a stale thread pointer can be checked for validity. * include/instrmnt.h: Added cyg_instrument_state() to report the current state of an instrumentation flag. Moved ifdef for CYGDBG_KERNEL_INSTRUMENT_MSGS out of within FLAGS ifdef. We can have messages without flags. * src/instrmnt/meminst.cxx: Added cyg_instrument_state() to report the current state of an instrumentation flag. Modified cyg_instrument_msg() in line with header and table changes. * host/instr/dump_instr.c: * host/instr/instrument.sh: * include/instrument_desc.h: Added a final NULL element to the generated table in instrument_desc.h to mark its end. Otherwise code that does not have access to the table definition cannot find its end. Also added ifdefs to allow instrument_desc.h to be used to acquire the structure definition and table pointer.
author nickg
date Thu, 12 Dec 2002 18:31:34 +0000
parents a6cede66ea36
children aae52574f8c5
files packages/kernel/current/ChangeLog packages/kernel/current/doc/kernel.sgml packages/kernel/current/host/instr/dump_instr.c packages/kernel/current/host/instr/instrument.sh packages/kernel/current/include/instrmnt.h packages/kernel/current/include/instrument_desc.h packages/kernel/current/include/kapi.h packages/kernel/current/src/common/kapi.cxx packages/kernel/current/src/common/thread.cxx packages/kernel/current/src/instrmnt/meminst.cxx
diffstat 10 files changed, 256 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/packages/kernel/current/ChangeLog
+++ b/packages/kernel/current/ChangeLog
@@ -1,3 +1,37 @@
+2002-12-12  Nick Garnett  <nickg@ecoscentric.com>
+
+	* src/common/kapi.cxx: 
+	* include/kapi.h:
+	Added function cyg_thread_get_next(), cyg_thread_find() and
+	cyg_thread_get_info() to allow the current set of threads to be
+	enumerated, and per-thread information to be retrieved safely.
+
+	* doc/kernel.sgml: Documented new KAPI calls.
+
+	* src/common/thread.cxx: Zero unique_id in thread destructor so
+	that a stale thread pointer can be checked for validity.
+
+	* include/instrmnt.h:
+	Added cyg_instrument_state() to report the current state of an
+	instrumentation flag.
+	Moved ifdef for CYGDBG_KERNEL_INSTRUMENT_MSGS out of within FLAGS
+	ifdef. We can have messages without flags.
+
+	* src/instrmnt/meminst.cxx: 
+	Added cyg_instrument_state() to report the current state of an
+	instrumentation flag.
+	Modified cyg_instrument_msg() in line with header and table
+	changes.
+
+	* host/instr/dump_instr.c:
+	* host/instr/instrument.sh:
+	* include/instrument_desc.h: 
+	Added a final NULL element to the generated table in
+	instrument_desc.h to mark its end. Otherwise code that does not
+	have access to the table definition cannot find its end. Also
+	added ifdefs to allow instrument_desc.h to be used to acquire the
+	structure definition and table pointer.
+
 2002-12-03  Gary Thomas  <gthomas@ecoscentric.com>
 
 	* tests/tm_basic.cxx: Add tests of 'flag' synchronizers.
--- a/packages/kernel/current/doc/kernel.sgml
+++ b/packages/kernel/current/doc/kernel.sgml
@@ -1276,6 +1276,9 @@ be achieved when programming in C++ is l
       <refname>cyg_thread_get_stack_base</refname>
       <refname>cyg_thread_get_stack_size</refname>
       <refname>cyg_thread_measure_stack_usage</refname>
+      <refname>cyg_thread_get_next</refname>
+      <refname>cyg_thread_get_info</refname>
+      <refname>cyg_thread_find</refname>
       <refpurpose>Get basic thread information</refpurpose>
     </refnamediv>
 
@@ -1304,6 +1307,21 @@ be achieved when programming in C++ is l
           <funcdef>cyg_uint32 <function>cyg_thread_measure_stack_usage</function></funcdef>
           <paramdef>cyg_handle_t <parameter>thread</parameter></paramdef>
         </funcprototype>        
+        <funcprototype>
+          <funcdef>cyg_bool <function>cyg_thread_get_next</function></funcdef>
+          <paramdef>cyg_handle_t *<parameter>thread</parameter></paramdef>
+          <paramdef>cyg_uint16 *<parameter>id</parameter></paramdef>
+        </funcprototype>        
+        <funcprototype>
+          <funcdef>cyg_bool <function>cyg_thread_get_info</function></funcdef>
+          <paramdef>cyg_handle_t <parameter>thread</parameter></paramdef>
+          <paramdef>cyg_uint16 <parameter>id</parameter></paramdef>
+          <paramdef>cyg_thread_info *<parameter>info</parameter></paramdef>
+        </funcprototype>        
+        <funcprototype>
+          <funcdef>cyg_handle_t <function>cyg_thread_find</function></funcdef>
+          <paramdef>cyg_uint16 <parameter>id</parameter></paramdef>
+        </funcprototype>        
       </funcsynopsis>
     </refsynopsisdiv>
 
@@ -1344,6 +1362,31 @@ run the specified thread has not yet bee
 point in the function call graph. Never the less the value returned
 can give some useful indication of the thread's stack requirements.
       </para>
+      <para>
+<function>cyg_thread_get_next</function> is used to enumerate all the
+current threads in the system. It should be called intially with the
+locations pointed to by <parameter>thread</parameter> and
+<parameter>id</parameter> set to zero. On return these will be set to
+the handle and ID of the first thread. On subsequent calls, these
+parameters should be left set to the values returned by the previous
+call.  The handle and ID of the next thread in the system will be
+installed each time, until a <literal>false</literal> return value
+indicates the end of the list.
+      </para>
+      <para>
+<function>cyg_thread_get_info</function> fills in the
+<type>cyg_thread_info</type> structure with information about the
+thread described by the <parameter>thread</parameter> and
+<parameter>id</parameter> arguments. The information returned includes
+the thread's handle and id, its state and name, priorities and stack
+parameters. If the thread does not exist the function returns
+<literal>false</literal>.
+    </para>
+    <para>
+<function>cyg_thread_find</function> returns a handle for the thread
+whose ID is <parameter>id</parameter>. If no such thread exists, a
+zero handle is returned.
+    </para>
     </refsect1>
 
     <refsect1 id="kernel-thread-info-context"><title>Valid contexts</title>
@@ -1359,6 +1402,38 @@ stack usage involves looping over at lea
 so this should normally only be done from thread context.
       </para>
     </refsect1>
+
+    <refsect1 id="kernel-thread-info-examples"><title>Examples</title>
+      <para>
+A simple example of the use of the
+<function>cyg_thread_get_next</function> and
+<function>cyg_thread_get_info</function> follows:      
+      </para>
+      <programlisting width=72>
+
+#include &lt;cyg/kernel/kapi.h&gt;
+#include &lt;stdio.h&gt;
+
+void show_threads(void)
+{
+    cyg_handle_t thread = 0;
+    cyg_uint16 id = 0;
+
+    while( cyg_thread_get_next( &amp;thread, &amp;id ) )
+    {
+        cyg_thread_info info;
+
+        if( !cyg_thread_get_info( thread, id, &amp;info ) )
+            break;
+
+        printf("ID: %04x name: %10s pri: %d\n",
+                info.id, info.name?info.name:"----", info.set_pri );
+    }
+}
+
+      </programlisting>
+    </refsect1>
+
   </refentry>
 
 <!-- }}} -->
--- a/packages/kernel/current/host/instr/dump_instr.c
+++ b/packages/kernel/current/host/instr/dump_instr.c
@@ -21,6 +21,7 @@ struct Instrument_Record
 // -------------------------------------------------------------------------
 
 #ifdef CYGDBG_KERNEL_INSTRUMENT_MSGS
+#define CYGDBG_KERNEL_INSTRUMENT_MSGS_DEFINE_TABLE
 #include <cyg/kernel/instrument_desc.h>
 #define NELEM(x) (sizeof(x)/sizeof*(x))
 externC char * cyg_instrument_msg(CYG_WORD16 type) {
@@ -30,7 +31,7 @@ externC char * cyg_instrument_msg(CYG_WO
   CYG_WORD cl, event;
 
   record = instrument_desc;
-  end_record = &instrument_desc[NELEM(instrument_desc)];
+  end_record = &instrument_desc[NELEM(instrument_desc)-1];
   cl = type & 0xff00;
   event = type & 0x00ff;
 
--- a/packages/kernel/current/host/instr/instrument.sh
+++ b/packages/kernel/current/host/instr/instrument.sh
@@ -8,11 +8,16 @@ echo "    char *   msg;                 
 echo "    CYG_WORD num;                                         "
 echo "};                                                        "
 echo
+echo "#ifdef CYGDBG_KERNEL_INSTRUMENT_MSGS_DEFINE_TABLE         "
 echo struct instrument_desc_s instrument_desc[] = {
 
 grep -e \#define.CYG_INSTRUMENT_EVENT -e \#define.CYG_INSTRUMENT_CLASS $1 | grep -v MAX | cut -d " " -f 2- | cut -d "_" -f 4- | sort | awk '{ print("{\""$1"\",   " $2 "},") }'
 
+echo { 0, 0 }
 echo }\;
+echo "#else /* CYGDBG_KERNEL_INSTRUMENT_MSGS_DEFINE_TABLE */    "
+echo "extern struct instrument_desc_s instrument_desc[];        "
+echo "#endif /* CYGDBG_KERNEL_INSTRUMENT_MSGS_DEFINE_TABLE */   "
 echo
 echo "/* EOF instrument_desc.h */"
 
--- a/packages/kernel/current/include/instrmnt.h
+++ b/packages/kernel/current/include/instrmnt.h
@@ -82,10 +82,13 @@ externC void cyg_instrument_enable( cyg_
 
 externC void cyg_instrument_disable( cyg_uint32 cl, cyg_uint32 event );
 
+externC cyg_bool cyg_instrument_state( cyg_uint32 cl, cyg_uint32 event );
+
+#endif
+
 #ifdef CYGDBG_KERNEL_INSTRUMENT_MSGS
 externC char * cyg_instrument_msg(CYG_WORD16 type);
 #endif 
-#endif
 
 // -------------------------------------------------------------------------
 // Instrumentation macros
--- a/packages/kernel/current/include/instrument_desc.h
+++ b/packages/kernel/current/include/instrument_desc.h
@@ -7,6 +7,7 @@ struct instrument_desc_s {
     CYG_WORD num;                                         
 };                                                        
 
+#ifdef CYGDBG_KERNEL_INSTRUMENT_MSGS_DEFINE_TABLE         
 struct instrument_desc_s instrument_desc[] = {
 {"ALARM",   0x0900},
 {"ALARM_ADD",   1},
@@ -133,6 +134,10 @@ struct instrument_desc_s instrument_desc
 {"USER_7",   7},
 {"USER_8",   8},
 {"USER_9",   9},
+{ 0, 0 }
 };
+#else /* CYGDBG_KERNEL_INSTRUMENT_MSGS_DEFINE_TABLE */    
+extern struct instrument_desc_s instrument_desc[];        
+#endif /* CYGDBG_KERNEL_INSTRUMENT_MSGS_DEFINE_TABLE */   
 
 /* EOF instrument_desc.h */
--- a/packages/kernel/current/include/kapi.h
+++ b/packages/kernel/current/include/kapi.h
@@ -12,6 +12,7 @@
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 2002 Bart Veer
+// Copyright (C) 2002 Nick Garnett
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
 //
 // eCos is free software; you can redistribute it and/or modify it under
@@ -207,6 +208,30 @@ cyg_uint32 cyg_thread_measure_stack_usag
 #endif
 
 /*---------------------------------------------------------------------------*/
+/* Thread enumeration and information                                        */
+    
+typedef struct
+{
+    cyg_handle_t        handle;
+    cyg_uint16          id;
+    cyg_uint32          state;
+    char                *name;
+    cyg_priority_t      set_pri;
+    cyg_priority_t      cur_pri;
+    cyg_addrword_t      stack_base;
+    cyg_uint32          stack_size;
+    cyg_uint32          stack_used;
+} cyg_thread_info;
+    
+cyg_bool_t cyg_thread_get_next( cyg_handle_t *thread, cyg_uint16 *id );
+
+cyg_bool_t cyg_thread_get_info( cyg_handle_t thread,
+                                cyg_uint16 id,
+                                cyg_thread_info *info );
+
+cyg_handle_t cyg_thread_find( cyg_uint16 id );
+    
+/*---------------------------------------------------------------------------*/
 /* Per-thread Data                                                           */
 
 #ifdef CYGVAR_KERNEL_THREADS_DATA
--- a/packages/kernel/current/src/common/kapi.cxx
+++ b/packages/kernel/current/src/common/kapi.cxx
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Nick Garnett
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
@@ -309,6 +310,101 @@ externC cyg_uint32 cyg_thread_measure_st
 #endif
 
 /*---------------------------------------------------------------------------*/
+/* Thread enumeration and information                                        */
+
+#ifdef CYGVAR_KERNEL_THREADS_LIST
+
+cyg_bool_t cyg_thread_get_next( cyg_handle_t *current, cyg_uint16 *id )
+{
+    cyg_bool_t result = true;
+    
+    Cyg_Scheduler::lock();
+
+    Cyg_Thread *thread = (Cyg_Thread *)*current;
+
+    if( *current == 0 )
+    {
+        thread = Cyg_Thread::get_list_head();
+        *current = (cyg_handle_t)thread;
+        *id = thread->get_unique_id();
+    }
+    else if( (thread->get_unique_id() == *id) &&
+             (thread = thread->get_list_next()) != NULL )
+    {
+        *current = (cyg_handle_t)thread;
+        *id = thread->get_unique_id();
+    }
+    else
+    {
+        *current = 0;
+        *id = 0;
+        result = false;
+    }
+    
+    Cyg_Scheduler::unlock();
+
+    return result;
+}
+
+cyg_handle_t cyg_thread_find( cyg_uint16 id )
+{
+    Cyg_Scheduler::lock();
+
+    Cyg_Thread *thread = Cyg_Thread::get_list_head();
+
+    while( thread != NULL )
+    {
+        if( thread->get_unique_id() == id )
+            break;
+        
+        thread = thread->get_list_next();
+    }
+
+    Cyg_Scheduler::unlock();
+    
+    return (cyg_handle_t)thread;
+}
+
+#endif
+
+cyg_bool_t cyg_thread_get_info( cyg_handle_t threadh,
+                                cyg_uint16 id,
+                                cyg_thread_info *info )
+{
+    cyg_bool_t result = true;
+    Cyg_Thread *thread = (Cyg_Thread *)threadh;
+    
+    Cyg_Scheduler::lock();
+    
+    if( thread->get_unique_id() == id && info != NULL )
+    {
+        info->handle = threadh;
+        info->id = id;
+        info->state = thread->get_state();
+#ifdef CYGVAR_KERNEL_THREADS_NAME
+        info->name = thread->get_name();
+#else
+        info->name = NULL;
+#endif
+        info->set_pri = thread->get_priority();
+        info->cur_pri = thread->get_current_priority();
+        info->stack_base = thread->get_stack_base();
+        info->stack_size = thread->get_stack_size();
+        
+#ifdef CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT
+        info->stack_used = thread->measure_stack_usage();
+#else
+        info->stack_used = 0;
+#endif
+    }
+    else result = false;
+    
+    Cyg_Scheduler::unlock();
+
+    return result;
+}
+
+/*---------------------------------------------------------------------------*/
 /* Per-thread data                                                           */
 
 #ifdef CYGVAR_KERNEL_THREADS_DATA
--- a/packages/kernel/current/src/common/thread.cxx
+++ b/packages/kernel/current/src/common/thread.cxx
@@ -295,6 +295,9 @@ Cyg_Thread::~Cyg_Thread()
     remove_from_list();
 #endif 
     
+    // Zero the unique_id to render this thread inconsistent.
+    unique_id = 0;
+    
     CYG_REPORT_RETURN();
 }
 
--- a/packages/kernel/current/src/instrmnt/meminst.cxx
+++ b/packages/kernel/current/src/instrmnt/meminst.cxx
@@ -214,11 +214,17 @@ externC void cyg_instrument_disable( cyg
 
 }
 
+externC cyg_bool cyg_instrument_state( cyg_uint32 cl, cyg_uint32 event)
+{
+    return (instrument_flags[cl>>8] & (1<<event)) != 0;
+}
+
 #endif
 
 // -------------------------------------------------------------------------
 
 #ifdef CYGDBG_KERNEL_INSTRUMENT_MSGS
+#define CYGDBG_KERNEL_INSTRUMENT_MSGS_DEFINE_TABLE
 #include <cyg/kernel/instrument_desc.h>
 #define NELEM(x) (sizeof(x)/sizeof*(x))
 externC char * cyg_instrument_msg(CYG_WORD16 type) {
@@ -228,7 +234,7 @@ externC char * cyg_instrument_msg(CYG_WO
   CYG_WORD cl, event;
 
   record = instrument_desc;
-  end_record = &instrument_desc[NELEM(instrument_desc)];
+  end_record = &instrument_desc[NELEM(instrument_desc)-1];
   cl = type & 0xff00;
   event = type & 0x00ff;