Working VxWorks implementation of epicsThreadMustJoin()

This commit is contained in:
Andrew Johnson
2019-06-28 12:28:41 -05:00
parent 14440b2d9d
commit ff1462fcc7

View File

@@ -34,6 +34,22 @@
#include "vxLib.h"
#include "epicsExit.h"
#if EPICS_THREAD_CAN_JOIN
/* The implementation of epicsThreadMustJoin() here uses 2 features
* of VxWorks that were first introduced in VxWorks 6.9: taskWait(),
* and the taskSpareFieldGet/Set routines in taskUtilLib.
*/
#include <taskUtilLib.h>
#define JOIN_WARNING_TIMEOUT (60 * sysClkRateGet())
static SPARE_NUM joinField;
#define ALLOT_JOIN(tid) taskSpareNumAllot(tid, &joinField)
#else
#define ALLOT_JOIN(tid)
#endif
epicsShareFunc void osdThreadHooksRun(epicsThreadId id);
#if CPU_FAMILY == MC680X0
@@ -109,6 +125,7 @@ static void epicsThreadInit(void)
assert(taskIdList);
taskIdListSize = ID_LIST_CHUNK;
atRebootRegister();
ALLOT_JOIN(0);
done = 1;
}
lock = 0;
@@ -177,19 +194,58 @@ void epicsThreadOnce(epicsThreadOnceId *id, void (*func)(void *), void *arg)
}
semGive(epicsThreadOnceMutex);
}
#if EPICS_THREAD_CAN_JOIN
/* This routine is not static so it appears in the back-trace
* of a thread that is waiting to be joined.
*/
void epicsThreadAwaitingJoin(int tid)
{
SEM_ID joinSem = (SEM_ID) taskSpareFieldGet(tid, joinField);
STATUS status;
if (!joinSem || (int) joinSem == ERROR)
return;
/* Wait for our supervisor */
status = semTake(joinSem, JOIN_WARNING_TIMEOUT);
if (status && errno == S_objLib_OBJ_TIMEOUT) {
errlogPrintf("Warning: epicsThread '%s' still awaiting join\n",
epicsThreadGetNameSelf());
status = semTake(joinSem, WAIT_FOREVER);
}
if (status)
perror("epicsThreadAwaitingJoin");
semDelete(joinSem);
taskSpareFieldSet(tid, joinField, 0);
}
#define PREPARE_JOIN(tid, joinable) \
taskSpareFieldSet(tid, joinField, \
joinable ? (int) semBCreate(SEM_Q_FIFO, SEM_EMPTY) : 0)
#define AWAIT_JOIN(tid) epicsThreadAwaitingJoin(tid)
#else
#define PREPARE_JOIN(tid, joinable)
#define AWAIT_JOIN(tid)
#endif
static void createFunction(EPICSTHREADFUNC func, void *parm)
{
int tid = taskIdSelf();
taskVarAdd(tid,(int *)(char *)&papTSD);
/*Make sure that papTSD is still 0 after that call to taskVarAdd*/
papTSD = 0;
papTSD = NULL; /* Initialize for this thread */
osdThreadHooksRun((epicsThreadId)tid);
(*func)(parm);
epicsExitCallAtThreadExits ();
free(papTSD);
taskVarDelete(tid,(int *)(char *)&papTSD);
AWAIT_JOIN(tid);
}
#ifdef ALTIVEC
@@ -197,38 +253,95 @@ static void createFunction(EPICSTHREADFUNC func, void *parm)
#else
#define TASK_FLAGS (VX_FP_TASK)
#endif
epicsThreadId
epicsThreadCreateOpt (
const char * name,
epicsThreadId epicsThreadCreateOpt(const char * name,
EPICSTHREADFUNC funptr, void * parm, const epicsThreadOpts *opts )
{
int tid;
if(!opts) opts = &opts_default;
if (!opts)
opts = &opts_default;
epicsThreadInit();
if(opts->stackSize<100) {
errlogPrintf("epicsThreadCreate %s illegal stackSize %d\n",name,opts->stackSize);
return(0);
if (opts->stackSize < 100) {
errlogPrintf("epicsThreadCreate %s illegal stackSize %d\n",
name, opts->stackSize);
return 0;
}
tid = taskSpawn((char *)name,getOssPriorityValue(opts->priority),
tid = taskCreate((char *)name,getOssPriorityValue(opts->priority),
TASK_FLAGS, opts->stackSize,
(FUNCPTR)createFunction,(int)funptr,(int)parm,
(FUNCPTR)createFunction, (int)funptr, (int)parm,
0,0,0,0,0,0,0,0);
if(tid==ERROR) {
if (tid == ERROR) {
errlogPrintf("epicsThreadCreate %s failure %s\n",
name,strerror(errno));
return(0);
name, strerror(errno));
return 0;
}
return((epicsThreadId)tid);
PREPARE_JOIN(tid, opts->joinable);
taskActivate(tid);
return (epicsThreadId)tid;
}
void epicsThreadMustJoin(epicsThreadId id) {
void epicsThreadMustJoin(epicsThreadId id)
{
const char *fn = "epicsThreadMustJoin";
#if EPICS_THREAD_CAN_JOIN
int tid = (int)id;
int tid = (int) id;
SEM_ID joinSem;
STATUS status;
if (tid)
taskWait(tid, WAIT_FOREVER);
if (!tid)
return;
joinSem = (SEM_ID) taskSpareFieldGet(tid, joinField);
if ((int) joinSem == ERROR) {
errlogPrintf("%s: Thread '%s' no longer exists.\n",
fn, taskName(tid));
return;
}
if (tid == taskIdSelf()) {
if (joinSem) {
semDelete(joinSem);
taskSpareFieldSet(tid, joinField, 0);
}
else {
errlogPrintf("%s: Self-join of unjoinable thread '%s'\n",
fn, taskName(tid));
}
return;
}
if (!joinSem) {
cantProceed("%s: Thread '%s' is not joinable.\n",
fn, taskName(tid));
return;
}
semGive(joinSem); /* Rendezvous with thread */
status = taskWait(tid, JOIN_WARNING_TIMEOUT);
if (status && errno == S_objLib_OBJ_TIMEOUT) {
errlogPrintf("Warning: %s still waiting for thread '%s'\n",
fn, taskName(tid));
status = taskWait(tid, WAIT_FOREVER);
}
if (status) {
if (errno == S_taskLib_ILLEGAL_OPERATION) {
errlogPrintf("%s: This shouldn't happen!\n", fn);
}
else if (errno == S_objLib_OBJ_ID_ERROR) {
errlogPrintf("%s: %x is not a known thread\n", fn, tid);
}
else {
perror(fn);
}
cantProceed(fn);
}
#else
cantProceed("%s called when EPICS_THREAD_CAN_JOIN is 0\n", fn);
#endif
}