Add task name access routines.
Add preliminary `show task' support.
This commit is contained in:
@@ -6,12 +6,15 @@
|
||||
* (306) 966-6055
|
||||
*/
|
||||
|
||||
#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/error.h>
|
||||
@@ -24,16 +27,20 @@
|
||||
/*
|
||||
* Per-task variables
|
||||
*/
|
||||
struct taskVars {
|
||||
struct taskVar {
|
||||
struct taskVar *forw;
|
||||
struct taskVar *back;
|
||||
char *name;
|
||||
rtems_id id;
|
||||
THREADFUNC funptr;
|
||||
void *parm;
|
||||
int threadVariableCapacity;
|
||||
void **threadVariables;
|
||||
int threadVariablesAdded;
|
||||
};
|
||||
static void *taskVars = NULL; /* RTEMS task-private variable */
|
||||
static int threadVariableCount = 0;
|
||||
#define RTEMS_NOTEPAD_TASKVAR 11
|
||||
static rtems_id taskVarMutex;
|
||||
static struct taskVar *taskVarHead;
|
||||
#define RTEMS_NOTEPAD_TASKVAR 11
|
||||
|
||||
/* Just map osi 0 to 99 into RTEMS 199 to 100 */
|
||||
/* For RTEMS lower number means higher priority */
|
||||
@@ -64,6 +71,54 @@ threadGetStackSize (threadStackSizeClass size)
|
||||
return(11000*ARCH_STACK_FACTOR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure integrity of task variable list
|
||||
*/
|
||||
static void
|
||||
taskVarLock (void)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
|
||||
if (!taskVarMutex) {
|
||||
rtems_mode mode;
|
||||
rtems_task_mode (RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &mode);
|
||||
if (!taskVarMutex) {
|
||||
sc = rtems_semaphore_create (rtems_build_name ('T', 'V', 'M', 'X'),
|
||||
1,
|
||||
RTEMS_FIFO |
|
||||
RTEMS_BINARY_SEMAPHORE |
|
||||
RTEMS_NO_INHERIT_PRIORITY |
|
||||
RTEMS_NO_PRIORITY_CEILING |
|
||||
RTEMS_LOCAL,
|
||||
0,
|
||||
&taskVarMutex);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
rtems_task_mode (mode, RTEMS_PREEMPT_MASK, &mode);
|
||||
syslog (LOG_ERR, "Can't create task variable mutex: %s", rtems_status_text (sc));
|
||||
cantProceed ("Can't create task variable mutex");
|
||||
}
|
||||
}
|
||||
rtems_task_mode (mode, RTEMS_PREEMPT_MASK, &mode);
|
||||
}
|
||||
sc = rtems_semaphore_obtain (taskVarMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
syslog (LOG_ERR, "Can't obtain task variable mutex: %s", rtems_status_text (sc));
|
||||
cantProceed ("Can't obtain task variable mutex");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
taskVarUnlock (void)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
|
||||
sc = rtems_semaphore_release (taskVarMutex);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
syslog (LOG_ERR, "Can't release task variable mutex: %s", rtems_status_text (sc));
|
||||
cantProceed ("Can't release task variable mutex");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* EPICS threads destroy themselves by returning from the thread entry function.
|
||||
* This simple wrapper provides the same semantics on RTEMS.
|
||||
@@ -71,9 +126,24 @@ threadGetStackSize (threadStackSizeClass size)
|
||||
static rtems_task
|
||||
threadWrapper (rtems_task_argument arg)
|
||||
{
|
||||
struct taskVars *v = (struct taskVars *)arg;
|
||||
struct taskVar *v = (struct taskVar *)arg;
|
||||
|
||||
taskVarLock ();
|
||||
v->forw = taskVarHead;
|
||||
v->back = NULL;
|
||||
if (v->forw)
|
||||
v->forw->back = v;
|
||||
taskVarHead = v;
|
||||
taskVarUnlock ();
|
||||
(*v->funptr)(v->parm);
|
||||
taskVarLock ();
|
||||
if (v->back)
|
||||
v->back->forw = v->forw;
|
||||
else
|
||||
taskVarHead = v->forw;
|
||||
if (v->forw)
|
||||
v->forw->back = v->back;
|
||||
taskVarUnlock ();
|
||||
free (v->name);
|
||||
free (v);
|
||||
rtems_task_delete (RTEMS_SELF);
|
||||
@@ -87,7 +157,7 @@ threadCreate (const char *name,
|
||||
unsigned int priority, unsigned int stackSize,
|
||||
THREADFUNC funptr,void *parm)
|
||||
{
|
||||
struct taskVars *v;
|
||||
struct taskVar *v;
|
||||
rtems_id tid;
|
||||
rtems_status_code sc;
|
||||
rtems_unsigned32 note;
|
||||
@@ -111,10 +181,12 @@ threadCreate (const char *name,
|
||||
v = mallocMustSucceed (sizeof *v, "threadCreate_vars");
|
||||
v->name = mallocMustSucceed (strlen (name) + 1, "threadCreate_name");
|
||||
strcpy (v->name, name);
|
||||
v->id = tid;
|
||||
v->funptr = funptr;
|
||||
v->parm = parm;
|
||||
v->threadVariableCapacity = 0;
|
||||
v->threadVariables = NULL;
|
||||
v->threadVariablesAdded = 0;
|
||||
note = (rtems_unsigned32)v;
|
||||
rtems_task_set_note (RTEMS_SELF, RTEMS_NOTEPAD_TASKVAR, note);
|
||||
rtems_task_start (tid, threadWrapper, (rtems_task_argument)v);
|
||||
@@ -224,10 +296,43 @@ threadGetIdSelf (void)
|
||||
return (threadId)tid;
|
||||
}
|
||||
|
||||
const char *threadGetNameSelf(void)
|
||||
{
|
||||
rtems_unsigned32 note;
|
||||
struct taskVar *v;
|
||||
|
||||
rtems_task_get_note (RTEMS_SELF, RTEMS_NOTEPAD_TASKVAR, ¬e);
|
||||
v = (void *)note;
|
||||
return v->name;
|
||||
}
|
||||
|
||||
void threadGetName(threadId id, char *name,size_t size)
|
||||
{
|
||||
rtems_id tid = (rtems_id)id;
|
||||
rtems_status_code sc;
|
||||
rtems_unsigned32 note;
|
||||
struct taskVar *v;
|
||||
|
||||
taskVarLock ();
|
||||
sc = rtems_task_get_note (tid, RTEMS_NOTEPAD_TASKVAR, ¬e);
|
||||
if (sc == RTEMS_SUCCESSFUL) {
|
||||
v = (void *)note;
|
||||
strncpy (name, v->name, size - 1);
|
||||
name[size-1] = '\0';
|
||||
}
|
||||
else {
|
||||
*name = '\0';
|
||||
}
|
||||
taskVarUnlock ();
|
||||
}
|
||||
|
||||
/*
|
||||
* Thread private storage implementation based on the vxWorks
|
||||
* implementation by Andrew Johnson APS/ASD.
|
||||
*/
|
||||
static void *taskVarPointer = NULL; /* RTEMS task-private variable */
|
||||
static int threadVariableCount = 0;
|
||||
|
||||
threadPrivateId threadPrivateCreate ()
|
||||
{
|
||||
return (void *)++threadVariableCount;
|
||||
@@ -242,7 +347,7 @@ void threadPrivateSet (threadPrivateId id, void *pvt)
|
||||
{
|
||||
int varIndex = (int)id;
|
||||
rtems_unsigned32 note;
|
||||
struct taskVars *v;
|
||||
struct taskVar *v;
|
||||
|
||||
/*
|
||||
* See if task variable has been set up
|
||||
@@ -250,13 +355,12 @@ void threadPrivateSet (threadPrivateId id, void *pvt)
|
||||
* task variable until it's needed
|
||||
*/
|
||||
rtems_task_get_note (RTEMS_SELF, RTEMS_NOTEPAD_TASKVAR, ¬e);
|
||||
if (note) {
|
||||
rtems_task_variable_add (RTEMS_SELF, &taskVars, NULL);
|
||||
taskVars = (void *)note;
|
||||
note = 0;
|
||||
rtems_task_set_note (RTEMS_SELF, RTEMS_NOTEPAD_TASKVAR, note);
|
||||
v = (struct taskVar *)note;
|
||||
if (!v->threadVariablesAdded) {
|
||||
rtems_task_variable_add (RTEMS_SELF, &taskVarPointer, NULL);
|
||||
taskVarPointer = v;
|
||||
v->threadVariablesAdded = 1;
|
||||
}
|
||||
v = taskVars;
|
||||
if (varIndex >= v->threadVariableCapacity) {
|
||||
v->threadVariables = realloc (v->threadVariables, (varIndex + 1) * sizeof (void *));
|
||||
if (v->threadVariables == NULL)
|
||||
@@ -268,6 +372,83 @@ void threadPrivateSet (threadPrivateId id, void *pvt)
|
||||
|
||||
void * threadPrivateGet (threadPrivateId id)
|
||||
{
|
||||
assert (taskVars);
|
||||
return ((struct taskVars *)taskVars)->threadVariables[(int)id];
|
||||
assert (taskVarPointer);
|
||||
return ((struct taskVar *)taskVarPointer)->threadVariables[(int)id];
|
||||
}
|
||||
|
||||
/*
|
||||
* Show task info
|
||||
*/
|
||||
struct bitmap {
|
||||
char *msg;
|
||||
unsigned long mask;
|
||||
unsigned long state;
|
||||
};
|
||||
|
||||
static void
|
||||
showBitmap (char *cbuf, unsigned long bits, const struct bitmap *bp)
|
||||
{
|
||||
for ( ; bp->msg != NULL ; bp++) {
|
||||
if ((bp->mask & bits) == bp->state) {
|
||||
strcpy (cbuf, bp->msg);
|
||||
cbuf += strlen (bp->msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
showInternalTaskInfo (rtems_id tid)
|
||||
{
|
||||
#ifdef __RTEMS_VIOLATE_KERNEL_VISIBILITY__
|
||||
Thread_Control *the_thread;
|
||||
Objects_Locations location;
|
||||
static Thread_Control thread;
|
||||
static char bitbuf[120];
|
||||
static const struct bitmap taskState[] = {
|
||||
{ "RUN", STATES_ALL_SET, STATES_READY },
|
||||
{ "DORM", STATES_DORMANT, STATES_DORMANT },
|
||||
{ "SUSP", STATES_SUSPENDED, STATES_SUSPENDED },
|
||||
{ "TRANS", STATES_TRANSIENT, STATES_TRANSIENT },
|
||||
{ "DELAY", STATES_DELAYING, STATES_DELAYING },
|
||||
{ "Wtime", STATES_WAITING_FOR_TIME, STATES_WAITING_FOR_TIME },
|
||||
{ "Wbuf", STATES_WAITING_FOR_BUFFER, STATES_WAITING_FOR_BUFFER },
|
||||
{ "Wseg", STATES_WAITING_FOR_SEGMENT, STATES_WAITING_FOR_SEGMENT },
|
||||
{ "Wmsg" , STATES_WAITING_FOR_MESSAGE, STATES_WAITING_FOR_MESSAGE },
|
||||
{ "Wevnt", STATES_WAITING_FOR_EVENT, STATES_WAITING_FOR_EVENT },
|
||||
{ "Wsem", STATES_WAITING_FOR_SEMAPHORE,STATES_WAITING_FOR_SEMAPHORE },
|
||||
{ "Wmtx", STATES_WAITING_FOR_MUTEX, STATES_WAITING_FOR_MUTEX },
|
||||
{ "Wjoin", STATES_WAITING_FOR_JOIN_AT_EXIT,STATES_WAITING_FOR_JOIN_AT_EXIT },
|
||||
{ "Wrpc", STATES_WAITING_FOR_RPC_REPLY,STATES_WAITING_FOR_RPC_REPLY },
|
||||
{ "Wrate", STATES_WAITING_FOR_PERIOD, STATES_WAITING_FOR_PERIOD },
|
||||
{ "Wsig", STATES_WAITING_FOR_SIGNAL, STATES_WAITING_FOR_SIGNAL },
|
||||
{ NULL, 0, 0 },
|
||||
};
|
||||
|
||||
the_thread = _Thread_Get (tid, &location);
|
||||
if (location != OBJECTS_LOCAL)
|
||||
return;
|
||||
thread = *the_thread;
|
||||
_Thread_Enable_dispatch();
|
||||
printf ("%4d", threadGetOsiPriorityValue(thread.current_priority));
|
||||
showBitmap (bitbuf, thread.current_state, taskState);
|
||||
printf ("%12.12s", bitbuf);
|
||||
if (thread.current_state & (STATES_WAITING_FOR_SEMAPHORE |
|
||||
STATES_WAITING_FOR_MUTEX |
|
||||
STATES_WAITING_FOR_MESSAGE))
|
||||
printf (" %8.8x", thread.Wait.id);
|
||||
#endif
|
||||
}
|
||||
|
||||
void threadShow (void)
|
||||
{
|
||||
struct taskVar *v;
|
||||
|
||||
printf (" NAME ID PRI STATE WAIT\n");
|
||||
taskVarLock ();
|
||||
for (v = taskVarHead ; v != NULL ; v = v->forw) {
|
||||
printf ("%12.12s %8.8x", v->name, v->id);
|
||||
showInternalTaskInfo (v->id);
|
||||
printf ("\n");
|
||||
}
|
||||
taskVarUnlock ();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user