diff --git a/src/libCom/osi/os/RTEMS/osdThread.c b/src/libCom/osi/os/RTEMS/osdThread.c index 81aec198b..7158e6b6e 100644 --- a/src/libCom/osi/os/RTEMS/osdThread.c +++ b/src/libCom/osi/os/RTEMS/osdThread.c @@ -6,12 +6,15 @@ * (306) 966-6055 */ +#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1 + #include #include #include #include #include #include +#include #include #include @@ -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 (); }