From 460e58e3e5624501a4831eb6f45e9f9d8deb5a78 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 5 Apr 2018 09:04:46 -0700 Subject: [PATCH] libCom "join" win32 threads Wait for completion --- modules/libcom/src/osi/os/WIN32/osdThread.c | 37 ++++++++++++++++++++- modules/libcom/src/osi/os/WIN32/osdThread.h | 4 +-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.c b/modules/libcom/src/osi/os/WIN32/osdThread.c index fb3f39f88..eba41645f 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.c +++ b/modules/libcom/src/osi/os/WIN32/osdThread.c @@ -32,6 +32,7 @@ #include "epicsAssert.h" #include "ellLib.h" #include "epicsExit.h" +#include "epicsAtomic.h" epicsShareFunc void osdThreadHooksRun(epicsThreadId id); @@ -46,6 +47,7 @@ typedef struct win32ThreadGlobal { typedef struct epicsThreadOSD { ELLNODE node; + int refcnt; HANDLE handle; EPICSTHREADFUNC funptr; void * parm; @@ -53,6 +55,7 @@ typedef struct epicsThreadOSD { DWORD id; unsigned epicsPriority; char isSuspended; + char joinable; } win32ThreadParam; typedef struct epicsThreadPrivateOSD { @@ -238,6 +241,8 @@ static void epicsParmCleanupWIN32 ( win32ThreadParam * pParm ) } if ( pParm ) { + if(epicsAtomicDecrIntT(&pParm->refcnt) > 0) return; + /* fprintf ( stderr, "thread %s is exiting\n", pParm->pName ); */ EnterCriticalSection ( & pGbl->mutex ); ellDelete ( & pGbl->threadList, & pParm->node ); @@ -533,6 +538,7 @@ static win32ThreadParam * epicsThreadParmCreate ( const char *pName ) pParmWIN32->pName = (char *) ( pParmWIN32 + 1 ); strcpy ( pParmWIN32->pName, pName ); pParmWIN32->isSuspended = 0; + epicsAtomicIncrIntT(&pParmWIN32->refcnt); } return pParmWIN32; } @@ -648,10 +654,39 @@ epicsThreadId epicsThreadCreateOpt ( return NULL; } + if(opts->joinable) { + pParmWIN32->joinable = 1; + epicsAtomicIncrIntT(&pParmWIN32->refcnt); + } + return ( epicsThreadId ) pParmWIN32; } -void epicsThreadJoin(epicsThreadId id) {} +void epicsThreadJoin(epicsThreadId id) +{ + win32ThreadParam * pParmWIN32 = id; + + if(!id) { + /* no-op */ + } else if(!pParmWIN32->joinable) { + /* try to error nicely, however in all likelyhood de-ref of + * 'pParmWIN32' has already crashed us as we are racing thread exit, + * which free's 'pParmWIN32'. + */ + cantProceed("%s join not enabled for thread.\n", pParmWIN32->pName); + + } else if(epicsThreadGetIdSelf() != id) { + DWORD status = WaitForSingleObject(pParmWIN32->handle, INFINITE); + if(status != WAIT_OBJECT_0) { + /* TODO: signal error? */ + } + + epicsParmCleanupWIN32(pParmWIN32); + } else { + /* join self silently does nothing */ + epicsParmCleanupWIN32(pParmWIN32); + } +} /* * epicsThreadSuspendSelf () diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.h b/modules/libcom/src/osi/os/WIN32/osdThread.h index 10025d2ad..fe60564d1 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.h +++ b/modules/libcom/src/osi/os/WIN32/osdThread.h @@ -11,7 +11,7 @@ #ifndef osdThreadh #define osdThreadh -/* This target does not support joining threads */ -#define EPICS_THREAD_CAN_JOIN (0) +/* This target supports joining threads */ +#define EPICS_THREAD_CAN_JOIN (1) #endif /* osdThreadh */