RTEMS thread join
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
#endif
|
||||
|
||||
#define CONFIGURE_MAXIMUM_TASKS rtems_resource_unlimited(30)
|
||||
#define CONFIGURE_MAXIMUM_BARRIERS rtems_resource_unlimited(30)
|
||||
#define CONFIGURE_MAXIMUM_SEMAPHORES rtems_resource_unlimited(500)
|
||||
#define CONFIGURE_MAXIMUM_TIMERS rtems_resource_unlimited(20)
|
||||
#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES rtems_resource_unlimited(5)
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "osiUnistd.h"
|
||||
#include "osdInterrupt.h"
|
||||
#include "epicsExit.h"
|
||||
#include "epicsAtomic.h"
|
||||
|
||||
epicsShareFunc void osdThreadHooksRun(epicsThreadId id);
|
||||
epicsShareFunc void osdThreadHooksRunMain(epicsThreadId id);
|
||||
@@ -47,6 +48,9 @@ struct taskVar {
|
||||
struct taskVar *back;
|
||||
char *name;
|
||||
rtems_id id;
|
||||
rtems_id join_barrier; /* only valid if joinable */
|
||||
int refcnt;
|
||||
int joinable;
|
||||
EPICSTHREADFUNC funptr;
|
||||
void *parm;
|
||||
unsigned int threadVariableCapacity;
|
||||
@@ -170,6 +174,22 @@ taskVarUnlock (void)
|
||||
epicsMutexOsdUnlock (taskVarMutex);
|
||||
}
|
||||
|
||||
static
|
||||
void taskUnref(struct taskVar *v)
|
||||
{
|
||||
int ref = epicsAtomicDecrIntT(&v->refcnt);
|
||||
assert(ref>=0);
|
||||
if(ref>0) return;
|
||||
|
||||
|
||||
if (v->joinable) {
|
||||
rtems_barrier_delete(v->join_barrier);
|
||||
}
|
||||
free (v->threadVariables);
|
||||
free (v->name);
|
||||
free (v);
|
||||
}
|
||||
|
||||
/*
|
||||
* EPICS threads destroy themselves by returning from the thread entry function.
|
||||
* This simple wrapper provides the same semantics on RTEMS.
|
||||
@@ -190,9 +210,12 @@ threadWrapper (rtems_task_argument arg)
|
||||
if (v->forw)
|
||||
v->forw->back = v->back;
|
||||
taskVarUnlock ();
|
||||
free (v->threadVariables);
|
||||
free (v->name);
|
||||
free (v);
|
||||
if(v->joinable) {
|
||||
rtems_status_code sc = rtems_barrier_wait(v->join_barrier, RTEMS_NO_TIMEOUT);
|
||||
if(sc!=RTEMS_SUCCESSFUL)
|
||||
cantProceed("oops %s\n", rtems_status_text(sc));
|
||||
}
|
||||
taskUnref(v);
|
||||
rtems_task_delete (RTEMS_SELF);
|
||||
}
|
||||
|
||||
@@ -203,21 +226,34 @@ void epicsThreadExitMain (void)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
static rtems_status_code
|
||||
setThreadInfo(rtems_id tid, const char *name, EPICSTHREADFUNC funptr,
|
||||
void *parm)
|
||||
void *parm, int joinable)
|
||||
{
|
||||
struct taskVar *v;
|
||||
uint32_t note;
|
||||
rtems_status_code sc;
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
|
||||
v = mallocMustSucceed (sizeof *v, "epicsThreadCreate_vars");
|
||||
v->name = epicsStrDup(name);
|
||||
v->id = tid;
|
||||
v->funptr = funptr;
|
||||
v->parm = parm;
|
||||
v->joinable = joinable;
|
||||
v->refcnt = joinable ? 2 : 1;
|
||||
v->threadVariableCapacity = 0;
|
||||
v->threadVariables = NULL;
|
||||
if (joinable) {
|
||||
char c[3];
|
||||
strncpy(c, v->name, 3);
|
||||
sc = rtems_barrier_create(rtems_build_name('~', c[0], c[1], c[2]),
|
||||
RTEMS_BARRIER_AUTOMATIC_RELEASE | RTEMS_LOCAL,
|
||||
2, &v->join_barrier);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
free(v);
|
||||
return sc;
|
||||
}
|
||||
}
|
||||
note = (uint32_t)v;
|
||||
rtems_task_set_note (tid, RTEMS_NOTEPAD_TASKVAR, note);
|
||||
taskVarLock ();
|
||||
@@ -229,10 +265,14 @@ setThreadInfo(rtems_id tid, const char *name, EPICSTHREADFUNC funptr,
|
||||
taskVarUnlock ();
|
||||
if (funptr) {
|
||||
sc = rtems_task_start (tid, threadWrapper, (rtems_task_argument)v);
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
errlogPrintf ("setThreadInfo: Can't start %s: %s\n",
|
||||
name, rtems_status_text(sc));
|
||||
}
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
if (joinable) {
|
||||
rtems_barrier_delete(v->join_barrier);
|
||||
}
|
||||
free(v);
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -254,7 +294,8 @@ epicsThreadInit (void)
|
||||
if (!onceMutex || !taskVarMutex)
|
||||
cantProceed("epicsThreadInit() can't create global mutexes\n");
|
||||
rtems_task_ident (RTEMS_SELF, 0, &tid);
|
||||
setThreadInfo (tid, "_main_", NULL, NULL);
|
||||
if(setThreadInfo (tid, "_main_", NULL, NULL, 0) != RTEMS_SUCCESSFUL)
|
||||
cantProceed("epicsThreadInit() unable to setup _main_");
|
||||
osdThreadHooksRunMain((epicsThreadId)tid);
|
||||
initialized = 1;
|
||||
epicsThreadCreate ("ImsgDaemon", 99,
|
||||
@@ -300,7 +341,13 @@ epicsThreadCreateOpt (
|
||||
name, rtems_status_text(sc));
|
||||
return 0;
|
||||
}
|
||||
setThreadInfo (tid, name, funptr,parm);
|
||||
sc = setThreadInfo (tid, name, funptr, parm, opts->joinable);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
errlogPrintf ("epicsThreadCreate create failure during setup for %s: %s\n",
|
||||
name, rtems_status_text(sc));
|
||||
rtems_task_delete(tid);
|
||||
return 0;
|
||||
}
|
||||
return (epicsThreadId)tid;
|
||||
}
|
||||
|
||||
@@ -316,7 +363,41 @@ threadMustCreate (const char *name,
|
||||
return tid;
|
||||
}
|
||||
|
||||
void epicsThreadJoin(epicsThreadId id) {}
|
||||
void epicsThreadJoin(epicsThreadId id)
|
||||
{
|
||||
rtems_id target_tid = (rtems_id)id, self_tid;
|
||||
struct taskVar *v;
|
||||
|
||||
rtems_task_ident (RTEMS_SELF, 0, &self_tid);
|
||||
|
||||
{
|
||||
uint32_t note;
|
||||
rtems_task_get_note (target_tid, RTEMS_NOTEPAD_TASKVAR, ¬e);
|
||||
v = (void *)note;
|
||||
}
|
||||
|
||||
if(!v->joinable) {
|
||||
/* try to error nicely, however in all likelyhood rtems_task_get_note failed,
|
||||
* or gave us the wrong thread as we are racing thread exit.
|
||||
*/
|
||||
cantProceed("%s join not enabled for thread.\n", v->name);
|
||||
|
||||
} else if(target_tid!=self_tid) {
|
||||
/* wait for target to complete */
|
||||
rtems_status_code sc = rtems_barrier_wait(v->join_barrier, RTEMS_NO_TIMEOUT);
|
||||
if(sc!=RTEMS_SUCCESSFUL)
|
||||
cantProceed("oopsj %s\n", rtems_status_text(sc));
|
||||
|
||||
if(sc != RTEMS_SUCCESSFUL) {
|
||||
errlogPrintf("epicsThreadJoin('%s') -> %s\n", v->name, rtems_status_text(sc));
|
||||
}
|
||||
}
|
||||
|
||||
taskUnref(v);
|
||||
/* target task may be deleted.
|
||||
* self task is not deleted, even for self join.
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
epicsThreadSuspendSelf (void)
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/* This target does not support joining threads */
|
||||
#define EPICS_THREAD_CAN_JOIN (0)
|
||||
/* This target supports joining threads */
|
||||
#define EPICS_THREAD_CAN_JOIN (1)
|
||||
|
||||
int epicsThreadGetOssPriorityValue(unsigned int osiPriority);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user