diff --git a/modules/libcom/src/osi/os/posix/osdThread.c b/modules/libcom/src/osi/os/posix/osdThread.c index 17dfacbc86..9ed58db2a5 100644 --- a/modules/libcom/src/osi/os/posix/osdThread.c +++ b/modules/libcom/src/osi/os/posix/osdThread.c @@ -689,32 +689,45 @@ void epicsThreadMustJoin(epicsThreadId id) { void *ret = NULL; int status; + int prev; + epicsThreadId self; - if(!id) { + if(!id) return; - } else if(epicsAtomicCmpAndSwapIntT(&id->joinable, 1, 0)!=1) { - if(epicsThreadGetIdSelf()==id) { - errlogPrintf("Warning: %s thread self-join of unjoinable\n", id->name); + + prev = epicsAtomicCmpAndSwapIntT(&id->joinable, 1, 0); + self = epicsThreadGetIdSelf(); + + if(prev==0) { + /* join of unjoinable */ + if(self==id) { + errlogPrintf(ERL_WARNING ": %s thread self-join of unjoinable\n", id->name); + return; } else { /* try to error nicely, however in all likelihood de-ref of * 'id' has already caused SIGSEGV as we are racing thread exit, * which free's 'id'. */ - cantProceed("Error: %s thread not joinable.\n", id->name); + cantProceed(ERL_ERROR ": %s can't join unjoinable %s\n", self->name, id->name); } - return; - } - status = pthread_join(id->tid, &ret); - if(status == EDEADLK) { + } else if(prev!=1) { /* also not 0, the only other allowed value. */ + cantProceed(ERL_ERROR ": %s joins corrupt thread handle\n", self->name); + + } else if(self==id) { /* 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); + + } else { + status = pthread_join(id->tid, &ret); + checkStatusOnce(status, "pthread_join"); + } + + free_threadInfo(id); /* release joinable reference */ } LIBCOM_API void epicsStdCall epicsThreadSuspendSelf(void)