libCom: joinable threads (posix only)

Add epicsThreadJoin() and epicsThreadOpts::joinable.
For compatibility, default threads aren't joinable
by default.

Currently only POSIX can join.
This commit is contained in:
Michael Davidsaver
2018-04-04 11:23:53 -07:00
parent ca800fa57d
commit d989c8fade
11 changed files with 80 additions and 14 deletions

View File

@@ -38,6 +38,7 @@ epicsThreadId epicsShareAPI epicsThreadCreate (
epicsThreadOpts opts;
opts.priority = priority;
opts.stackSize = stackSize;
opts.joinable = 0;
return epicsThreadCreateOpt(name, funptr, parm, &opts);
}

View File

@@ -73,6 +73,8 @@ typedef struct epicsThreadOpts {
* @warning Do not pass enum epicsThreadStackSizeClass directly!
*/
unsigned int stackSize;
/** Should thread be joinable? (default (0) is not joinable). */
unsigned int joinable;
} epicsThreadOpts;
epicsShareFunc void epicsThreadOptsDefaults(epicsThreadOpts *opts);
@@ -86,7 +88,8 @@ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate (
EPICSTHREADFUNC funptr,void * parm );
epicsShareFunc epicsThreadId epicsShareAPI epicsThreadMustCreate (
const char * name, unsigned int priority, unsigned int stackSize,
EPICSTHREADFUNC funptr,void * parm );
EPICSTHREADFUNC funptr,void * parm );
epicsShareFunc void epicsThreadJoin(epicsThreadId id);
epicsShareFunc void epicsShareAPI epicsThreadSuspendSelf(void);
epicsShareFunc void epicsShareAPI epicsThreadResume(epicsThreadId id);
epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPriority(

View File

@@ -16,12 +16,16 @@
#include "ellLib.h"
#include "epicsEvent.h"
/* This target supports joining threads */
#define EPICS_THREAD_CAN_JOIN (1)
#ifdef __cplusplus
extern "C" {
#endif
typedef struct epicsThreadOSD {
ELLNODE node;
int refcnt;
pthread_t tid;
pid_t lwpId;
pthread_attr_t attr;
@@ -35,6 +39,7 @@ typedef struct epicsThreadOSD {
int isRealTimeScheduled;
int isOnThreadList;
unsigned int osiPriority;
int joinable;
char name[1]; /* actually larger */
} epicsThreadOSD;

View File

@@ -148,7 +148,7 @@ epicsThreadGetStackSize (epicsThreadStackSizeClass size)
return stackSize;
}
static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, 5000};
static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, 5000, 0};
void epicsThreadOptsDefaults(epicsThreadOpts *opts)
{
@@ -316,6 +316,8 @@ threadMustCreate (const char *name,
return tid;
}
void epicsThreadJoin(epicsThreadId id) {}
void
epicsThreadSuspendSelf (void)
{

View File

@@ -8,5 +8,8 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* This target does not support joining threads */
#define EPICS_THREAD_CAN_JOIN (0)
int epicsThreadGetOssPriorityValue(unsigned int osiPriority);

View File

@@ -464,7 +464,7 @@ epicsShareFunc unsigned int epicsShareAPI
return stackSizeTable[stackSizeClass];
}
static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, STACK_SIZE(1)};
static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, STACK_SIZE(1), 0};
void epicsThreadOptsDefaults(epicsThreadOpts *opts)
{
@@ -651,6 +651,8 @@ epicsThreadId epicsThreadCreateOpt (
return ( epicsThreadId ) pParmWIN32;
}
void epicsThreadJoin(epicsThreadId id) {}
/*
* epicsThreadSuspendSelf ()
*/

View File

@@ -11,5 +11,7 @@
#ifndef osdThreadh
#define osdThreadh
/* This target does not support joining threads */
#define EPICS_THREAD_CAN_JOIN (0)
#endif /* osdThreadh */

View File

@@ -38,6 +38,7 @@
#include "errlog.h"
#include "epicsAssert.h"
#include "epicsExit.h"
#include "epicsAtomic.h"
epicsShareFunc void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level);
epicsShareFunc void osdThreadHooksRun(epicsThreadId id);
@@ -167,12 +168,14 @@ static epicsThreadOSD * create_threadInfo(const char *name)
return NULL;
}
strcpy(pthreadInfo->name, name);
epicsAtomicIncrIntT(&pthreadInfo->refcnt); /* initial ref for the thread itself */
return pthreadInfo;
}
static epicsThreadOSD * init_threadInfo(const char *name,
unsigned int priority, unsigned int stackSize,
EPICSTHREADFUNC funptr,void *parm)
EPICSTHREADFUNC funptr,void *parm,
unsigned joinable)
{
epicsThreadOSD *pthreadInfo;
int status;
@@ -182,12 +185,15 @@ static epicsThreadOSD * init_threadInfo(const char *name,
return NULL;
pthreadInfo->createFunc = funptr;
pthreadInfo->createArg = parm;
pthreadInfo->joinable = joinable;
status = pthread_attr_init(&pthreadInfo->attr);
checkStatusOnce(status,"pthread_attr_init");
if(status) return 0;
status = pthread_attr_setdetachstate(
&pthreadInfo->attr, PTHREAD_CREATE_DETACHED);
checkStatusOnce(status,"pthread_attr_setdetachstate");
if(!joinable){
status = pthread_attr_setdetachstate(
&pthreadInfo->attr, PTHREAD_CREATE_DETACHED);
checkStatusOnce(status,"pthread_attr_setdetachstate");
}
#if defined (_POSIX_THREAD_ATTR_STACKSIZE)
#if ! defined (OSITHREAD_USE_DEFAULT_STACK)
status = pthread_attr_setstacksize( &pthreadInfo->attr,(size_t)stackSize);
@@ -204,6 +210,8 @@ static void free_threadInfo(epicsThreadOSD *pthreadInfo)
{
int status;
if(epicsAtomicDecrIntT(&pthreadInfo->refcnt) > 0) return;
status = mutexLock(&listLock);
checkStatusQuit(status,"pthread_mutex_lock","free_threadInfo");
if(pthreadInfo->isOnThreadList) ellDelete(&pthreadList,&pthreadInfo->node);
@@ -366,7 +374,7 @@ static void once(void)
if(errVerbose) fprintf(stderr,"task priorities are not implemented\n");
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
pthreadInfo = init_threadInfo("_main_",0,epicsThreadGetStackSize(epicsThreadStackSmall),0,0);
pthreadInfo = init_threadInfo("_main_",0,epicsThreadGetStackSize(epicsThreadStackSmall),0,0,0);
assert(pthreadInfo!=NULL);
status = pthread_setspecific(getpthreadInfo,(void *)pthreadInfo);
checkStatusOnceQuit(status,"pthread_setspecific","epicsThreadInit");
@@ -462,7 +470,7 @@ epicsShareFunc unsigned int epicsShareAPI epicsThreadGetStackSize (epicsThreadSt
#endif /*_POSIX_THREAD_ATTR_STACKSIZE*/
}
static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, STACK_SIZE(1)};
static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, STACK_SIZE(1), 0};
void epicsThreadOptsDefaults(epicsThreadOpts *opts)
{
@@ -525,7 +533,7 @@ epicsThreadCreateOpt (
assert(pcommonAttr);
sigfillset(&blockAllSig);
pthread_sigmask(SIG_SETMASK,&blockAllSig,&oldSig);
pthreadInfo = init_threadInfo(name,opts->priority,opts->stackSize,funptr,parm);
pthreadInfo = init_threadInfo(name,opts->priority,opts->stackSize,funptr,parm,opts->joinable);
if(pthreadInfo==0) return 0;
pthreadInfo->isEpicsThread = 1;
setSchedulingPolicy(pthreadInfo,SCHED_FIFO);
@@ -535,7 +543,7 @@ epicsThreadCreateOpt (
if(status==EPERM){
/* Try again without SCHED_FIFO*/
free_threadInfo(pthreadInfo);
pthreadInfo = init_threadInfo(name,opts->priority,opts->stackSize,funptr,parm);
pthreadInfo = init_threadInfo(name,opts->priority,opts->stackSize,funptr,parm,opts->joinable);
if(pthreadInfo==0) return 0;
pthreadInfo->isEpicsThread = 1;
status = pthread_create(&pthreadInfo->tid,&pthreadInfo->attr,
@@ -548,6 +556,10 @@ epicsThreadCreateOpt (
}
status = pthread_sigmask(SIG_SETMASK,&oldSig,NULL);
checkStatusOnce(status,"pthread_sigmask");
if(pthreadInfo->joinable) {
/* extra ref for epicsThreadJoin() */
epicsAtomicIncrIntT(&pthreadInfo->refcnt);
}
return(pthreadInfo);
}
@@ -587,7 +599,33 @@ static epicsThreadOSD *createImplicit(void)
}
return pthreadInfo;
}
void epicsThreadJoin(epicsThreadId id)
{
void *ret = NULL;
int status;
if(!id) {
return;
} else if(!id->joinable) {
/* try to error nicely, however in all likelyhood de-ref of
* 'id' has already caused SIGSEGV as we are racing thread exit,
* which free's 'id'.
*/
cantProceed("%s join not enabled for thread.\n", id->name);
}
status = pthread_join(id->tid, &ret);
if(status == EDEADLK) {
/* Thread can't join itself (directly or indirectly)
* so we detach instead.
*/
status = pthread_detach(id->tid);
checkStatusOnce(status, "pthread_detach");
} else checkStatusOnce(status, "pthread_join");
free_threadInfo(id);
}
epicsShareFunc void epicsShareAPI epicsThreadSuspendSelf(void)
{
epicsThreadOSD *pthreadInfo;

View File

@@ -16,12 +16,16 @@
#include "ellLib.h"
#include "epicsEvent.h"
/* This target supports joining threads */
#define EPICS_THREAD_CAN_JOIN (1)
#ifdef __cplusplus
extern "C" {
#endif
typedef struct epicsThreadOSD {
ELLNODE node;
int refcnt;
pthread_t tid;
pthread_attr_t attr;
struct sched_param schedParam;
@@ -34,6 +38,7 @@ typedef struct epicsThreadOSD {
int isRealTimeScheduled;
int isOnThreadList;
unsigned int osiPriority;
int joinable;
char name[1]; /* actually larger */
} epicsThreadOSD;

View File

@@ -133,7 +133,7 @@ unsigned int epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass)
return stackSizeTable[stackSizeClass];
}
static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, 4000*ARCH_STACK_FACTOR};
static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, 4000*ARCH_STACK_FACTOR, 0};
void epicsThreadOptsDefaults(epicsThreadOpts *opts)
{
@@ -223,6 +223,8 @@ epicsThreadCreateOpt (
return((epicsThreadId)tid);
}
void epicsThreadJoin(epicsThreadId id) {}
void epicsThreadSuspendSelf()
{
STATUS status;

View File

@@ -10,4 +10,7 @@
#ifndef osdThreadh
#define osdThreadh
/* This target does not support joining threads */
#define EPICS_THREAD_CAN_JOIN (0)
#endif /* osdThreadh */