From 32b3eddb94cf4f47494ff2cc58d6f5e0f3f71d21 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 23 Jun 2019 08:56:32 -0700 Subject: [PATCH] epicsThreadMustJoin() warn only on double self-join --- modules/libcom/src/osi/os/RTEMS/osdThread.c | 14 ++- modules/libcom/src/osi/os/WIN32/osdThread.c | 15 ++- modules/libcom/src/osi/os/posix/osdThread.c | 15 ++- modules/libcom/test/epicsThreadTest.cpp | 106 ++++++++++++++------ 4 files changed, 108 insertions(+), 42 deletions(-) diff --git a/modules/libcom/src/osi/os/RTEMS/osdThread.c b/modules/libcom/src/osi/os/RTEMS/osdThread.c index b30cb4156..b23f66b8f 100644 --- a/modules/libcom/src/osi/os/RTEMS/osdThread.c +++ b/modules/libcom/src/osi/os/RTEMS/osdThread.c @@ -377,10 +377,16 @@ void epicsThreadMustJoin(epicsThreadId id) } 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 thread not joinable.\n", v->name); + if(epicsThreadGetIdSelf()==id) { + errlogPrintf("Warning: %s thread self-join of unjoinable\n", v->name); + + } else { + /* 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("Error: %s thread not joinable.\n", v->name); + } return; } else if(target_tid!=self_tid) { diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.c b/modules/libcom/src/osi/os/WIN32/osdThread.c index 8c3973703..6d43e769f 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.c +++ b/modules/libcom/src/osi/os/WIN32/osdThread.c @@ -669,11 +669,16 @@ void epicsThreadMustJoin(epicsThreadId 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 thread not joinable.\n", pParmWIN32->pName); + if(epicsThreadGetIdSelf()==id) { + fprintf(stderr, "Warning: %s thread self-join of unjoinable\n", pParmWIN32->pName); + + } else { + /* 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("Error: %s thread not joinable.\n", pParmWIN32->pName); + } return; } else if(epicsThreadGetIdSelf() != id) { diff --git a/modules/libcom/src/osi/os/posix/osdThread.c b/modules/libcom/src/osi/os/posix/osdThread.c index ed3785205..5ed2cbc56 100644 --- a/modules/libcom/src/osi/os/posix/osdThread.c +++ b/modules/libcom/src/osi/os/posix/osdThread.c @@ -608,11 +608,16 @@ void epicsThreadMustJoin(epicsThreadId id) 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 thread not joinable.\n", id->name); + if(epicsThreadGetIdSelf()==id) { + errlogPrintf("Warning: %s thread self-join of unjoinable\n", id->name); + + } else { + /* 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("Error: %s thread not joinable.\n", id->name); + } return; } diff --git a/modules/libcom/test/epicsThreadTest.cpp b/modules/libcom/test/epicsThreadTest.cpp index c50d8c5bd..08d7529fa 100644 --- a/modules/libcom/test/epicsThreadTest.cpp +++ b/modules/libcom/test/epicsThreadTest.cpp @@ -18,11 +18,14 @@ #include #include "epicsThread.h" +#include "epicsEvent.h" #include "epicsTime.h" #include "errlog.h" #include "epicsUnitTest.h" #include "testMain.h" +namespace { + static epicsThreadPrivate privateKey; class myThread: public epicsThreadRunable { @@ -60,35 +63,8 @@ void myThread::run() testOk1(thread.getPriority() == epicsThreadGetPriority(self)); } - -typedef struct info { - int isOkToBlock; - int didSomething; -} info; - -extern "C" { -static void thread(void *arg) +void testMyThread() { - info *pinfo = (info *)arg; - - epicsThreadSetOkToBlock(pinfo->isOkToBlock); - - testOk(epicsThreadIsOkToBlock() == pinfo->isOkToBlock, - "%s epicsThreadIsOkToBlock() = %d", - epicsThreadGetNameSelf(), pinfo->isOkToBlock); - - pinfo->didSomething = 1; -} -} - - -MAIN(epicsThreadTest) -{ - testPlan(11); - - unsigned int ncpus = epicsThreadGetCPUs(); - testDiag("System has %u CPUs", ncpus); - testOk1(ncpus > 0); const int ntasks = 3; myThread *myThreads[ntasks]; @@ -108,6 +84,65 @@ MAIN(epicsThreadTest) myThreads[i]->thread.exitWait(); delete myThreads[i]; } +} + +struct selfJoiner { + epicsEvent finished; +}; + +void joiner(void *arg) { + epicsEvent *finished = (epicsEvent*)arg; + + // This is a no-op + epicsThreadMustJoin(epicsThreadGetIdSelf()); + + // This is a no-op as well, except for a warning. + eltc(0); + epicsThreadMustJoin(epicsThreadGetIdSelf()); + eltc(1); + + testPass("Check double self-join"); + finished->signal(); +} + +typedef struct info { + int isOkToBlock; + int didSomething; +} info; + +void testSelfJoin() +{ + epicsEvent finished; + epicsThreadOpts opts; + epicsThreadOptsDefaults(&opts); + opts.priority = 50; + opts.joinable = 1; + + (void)epicsThreadCreateOpt("selfjoin", &joiner, &finished, &opts); + + // as this thread "joins" itself, we can't. + finished.wait(); +} + +} // namespace + +extern "C" { +static void thread(void *arg) +{ + info *pinfo = (info *)arg; + + epicsThreadSetOkToBlock(pinfo->isOkToBlock); + + testOk(epicsThreadIsOkToBlock() == pinfo->isOkToBlock, + "%s epicsThreadIsOkToBlock() = %d", + epicsThreadGetNameSelf(), pinfo->isOkToBlock); + + pinfo->didSomething = 1; +} +} + +static void testOkToBlock() +{ epicsThreadOpts opts; epicsThreadOptsDefaults(&opts); @@ -127,5 +162,20 @@ MAIN(epicsThreadTest) epicsThreadMustJoin(threadA); testOk1(infoA.didSomething); +} + + +MAIN(epicsThreadTest) +{ + testPlan(12); + + unsigned int ncpus = epicsThreadGetCPUs(); + testDiag("System has %u CPUs", ncpus); + testOk1(ncpus > 0); + + testMyThread(); + testSelfJoin(); + testOkToBlock(); + return testDone(); }