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:
@@ -38,6 +38,7 @@ epicsThreadId epicsShareAPI epicsThreadCreate (
|
||||
epicsThreadOpts opts;
|
||||
opts.priority = priority;
|
||||
opts.stackSize = stackSize;
|
||||
opts.joinable = 0;
|
||||
|
||||
return epicsThreadCreateOpt(name, funptr, parm, &opts);
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 ()
|
||||
*/
|
||||
|
||||
@@ -11,5 +11,7 @@
|
||||
#ifndef osdThreadh
|
||||
#define osdThreadh
|
||||
|
||||
|
||||
/* This target does not support joining threads */
|
||||
#define EPICS_THREAD_CAN_JOIN (0)
|
||||
|
||||
#endif /* osdThreadh */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -10,4 +10,7 @@
|
||||
#ifndef osdThreadh
|
||||
#define osdThreadh
|
||||
|
||||
/* This target does not support joining threads */
|
||||
#define EPICS_THREAD_CAN_JOIN (0)
|
||||
|
||||
#endif /* osdThreadh */
|
||||
|
||||
Reference in New Issue
Block a user