RTEMS thread join

This commit is contained in:
Michael Davidsaver
2018-11-04 20:06:18 -08:00
parent 149ab1186a
commit f9092783f8
3 changed files with 96 additions and 14 deletions
+1
View File
@@ -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)
+93 -12
View File
@@ -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, &note);
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)
+2 -2
View File
@@ -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);