diff --git a/src/libCom/misc/ipAddrToAsciiAsynchronous.cpp b/src/libCom/misc/ipAddrToAsciiAsynchronous.cpp index f6597428d..b952cba55 100644 --- a/src/libCom/misc/ipAddrToAsciiAsynchronous.cpp +++ b/src/libCom/misc/ipAddrToAsciiAsynchronous.cpp @@ -82,7 +82,7 @@ template class tsFreeList extern "C" { static void ipAddrToAsciiEngineGlobalMutexConstruct ( void * ); -static void ipAddrToAsciiEngineGlobalMutexDestruct ( void * ); +static void ipAddrToAsciiEngineShutdownRequest ( void * ); } // - this class executes the synchronous DNS query @@ -111,6 +111,7 @@ private: static epicsMutex * pGlobalMutex; static ipAddrToAsciiEnginePrivate * pEngine; static unsigned numberOfReferences; + static bool shutdownRequest; ipAddrToAsciiTransaction & createTransaction (); void release (); void run (); @@ -118,13 +119,14 @@ private: ipAddrToAsciiEnginePrivate & operator = ( const ipAddrToAsciiEngine & ); friend class ipAddrToAsciiEngine; friend class ipAddrToAsciiTransactionPrivate; - friend void ipAddrToAsciiEngineGlobalMutexDestruct ( void * ); + friend void ipAddrToAsciiEngineShutdownRequest ( void * ); friend void ipAddrToAsciiEngineGlobalMutexConstruct ( void * ); }; epicsMutex * ipAddrToAsciiEnginePrivate :: pGlobalMutex = 0; ipAddrToAsciiEnginePrivate * ipAddrToAsciiEnginePrivate :: pEngine = 0; unsigned ipAddrToAsciiEnginePrivate :: numberOfReferences = 0u; +bool ipAddrToAsciiEnginePrivate :: shutdownRequest = false; static epicsThreadOnceId ipAddrToAsciiEngineGlobalMutexOnceFlag = 0; // the users are not required to supply a show routine @@ -136,15 +138,19 @@ ipAddrToAsciiCallBack::~ipAddrToAsciiCallBack () {} ipAddrToAsciiTransaction::~ipAddrToAsciiTransaction () {} ipAddrToAsciiEngine::~ipAddrToAsciiEngine () {} -static void ipAddrToAsciiEngineGlobalMutexDestruct ( void * ) +static void ipAddrToAsciiEngineShutdownRequest ( void * ) { - delete ipAddrToAsciiEnginePrivate :: pGlobalMutex; + epicsGuard < epicsMutex > guard ( * ipAddrToAsciiEnginePrivate::pGlobalMutex ); + ipAddrToAsciiEnginePrivate :: shutdownRequest = true; + if ( ipAddrToAsciiEnginePrivate::numberOfReferences == 0u ) { + delete ipAddrToAsciiEnginePrivate :: pGlobalMutex; + } } static void ipAddrToAsciiEngineGlobalMutexConstruct ( void * ) { ipAddrToAsciiEnginePrivate :: pGlobalMutex = new epicsMutex (); - epicsAtExit ( ipAddrToAsciiEngineGlobalMutexDestruct, 0 ); + epicsAtExit ( ipAddrToAsciiEngineShutdownRequest, 0 ); } // for now its probably sufficent to allocate one @@ -156,6 +162,16 @@ ipAddrToAsciiEngine & ipAddrToAsciiEngine::allocate () epicsThreadOnce ( & ipAddrToAsciiEngineGlobalMutexOnceFlag, ipAddrToAsciiEngineGlobalMutexConstruct, 0 ); + // since we must not own lock when checking this flag + // this diagnostic has imperfect detection, but never + // incorrect detection + if ( ipAddrToAsciiEnginePrivate :: shutdownRequest ) { + throw std :: runtime_error ( + "ipAddrToAsciiEngine::allocate (): " + "attempts to create an " + "ipAddrToAsciiEngine while the exit " + "handlers are running are rejected"); + } epicsGuard < epicsMutex > guard ( * ipAddrToAsciiEnginePrivate::pGlobalMutex ); if ( ! ipAddrToAsciiEnginePrivate::pEngine ) { ipAddrToAsciiEnginePrivate::pEngine = new ipAddrToAsciiEnginePrivate (); @@ -190,15 +206,24 @@ ipAddrToAsciiEnginePrivate::~ipAddrToAsciiEnginePrivate () // leave our options open for the future void ipAddrToAsciiEnginePrivate::release () { + bool deleteGlobalMutexCondDetected = false; epicsThreadOnce ( & ipAddrToAsciiEngineGlobalMutexOnceFlag, ipAddrToAsciiEngineGlobalMutexConstruct, 0 ); - epicsGuard < epicsMutex > guard ( * ipAddrToAsciiEnginePrivate::pGlobalMutex ); - assert ( ipAddrToAsciiEnginePrivate::numberOfReferences > 0u ); - ipAddrToAsciiEnginePrivate::numberOfReferences--; - if ( ipAddrToAsciiEnginePrivate::numberOfReferences == 0u ) { - delete ipAddrToAsciiEnginePrivate::pEngine; - ipAddrToAsciiEnginePrivate::pEngine = 0; + { + epicsGuard < epicsMutex > + guard ( * ipAddrToAsciiEnginePrivate::pGlobalMutex ); + assert ( ipAddrToAsciiEnginePrivate::numberOfReferences > 0u ); + ipAddrToAsciiEnginePrivate::numberOfReferences--; + if ( ipAddrToAsciiEnginePrivate::numberOfReferences == 0u ) { + delete ipAddrToAsciiEnginePrivate::pEngine; + ipAddrToAsciiEnginePrivate::pEngine = 0; + deleteGlobalMutexCondDetected = + ipAddrToAsciiEnginePrivate::shutdownRequest; + } + } + if ( deleteGlobalMutexCondDetected ) { + delete ipAddrToAsciiEnginePrivate :: pGlobalMutex; } }