From 7571947ceb7831da1d8bdcda17ca4932b0b3a385 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Fri, 8 Oct 2004 14:46:48 +0000 Subject: [PATCH] o fixed "no exception thrown if epicsThreadCreate() return nill" o added epicsThreadMustCreate o cleaned up thread rundown blocking o header file need not include exception support --- src/libCom/osi/epicsThread.cpp | 153 +++++++++++++++++++++------------ src/libCom/osi/epicsThread.h | 79 +++++++++-------- 2 files changed, 141 insertions(+), 91 deletions(-) diff --git a/src/libCom/osi/epicsThread.cpp b/src/libCom/osi/epicsThread.cpp index 9412fc355..eb7c72ea6 100644 --- a/src/libCom/osi/epicsThread.cpp +++ b/src/libCom/osi/epicsThread.cpp @@ -13,7 +13,7 @@ // Author: Jeff Hill // -#include +#include #include #include @@ -25,11 +25,29 @@ #include "epicsThread.h" #include "epicsAssert.h" #include "epicsGuard.h" +#include "errlog.h" epicsThreadRunable::~epicsThreadRunable () {} -void epicsThreadRunable::stop () {}; +void epicsThreadRunable::run () {} void epicsThreadRunable::show ( unsigned int ) const {}; +// vxWorks 5.4 gcc fails during compile when I use std::exception +using namespace std; + +// exception payload +class epicsThread::unableToCreateThread : public exception { + const char * what () const throw () { + return "epicsThread class was unable to create a new thread"; + } +}; + +// exception payload +class epicsThread::exitException : public exception { + const char * what () const throw () { + return "epicsThread class's private exit exception"; + } +}; + extern "C" void epicsThreadCallEntryPoint ( void * pPvt ) { epicsThread * pThread = @@ -39,6 +57,9 @@ extern "C" void epicsThreadCallEntryPoint ( void * pPvt ) pThread->pWaitReleaseFlag = & waitRelease; if ( pThread->beginWait () ) { pThread->runable.run (); + // current thread may have run the destructor + // so must not touch the this pointer from + // here on down if waitRelease is true } } catch ( const epicsThread::exitException & ) { @@ -76,12 +97,15 @@ extern "C" void epicsThreadCallEntryPoint ( void * pPvt ) } } if ( ! waitRelease ) { - pThread->exitWaitRelease (); + epicsGuard < epicsMutex > guard ( pThread->mutex ); + pThread->terminated = true; + pThread->exitEvent.signal (); + // once the terminated flag is set and we release the lock + // then the "this" pointer must not be touched again } - return; } -bool epicsThread::beginWait () +bool epicsThread::beginWait () throw () { epicsGuard < epicsMutex > guard ( this->mutex ); while ( ! this->begin && ! this->cancel ) { @@ -96,56 +120,54 @@ void epicsThread::exit () throw exitException (); } -void epicsThread::exitWait () +void epicsThread::exitWait () throw () { assert ( this->exitWait ( DBL_MAX ) ); } -bool epicsThread::exitWait (const double delay ) +bool epicsThread::exitWait ( const double delay ) throw () { - { - epicsTime exitWaitBegin = epicsTime::getCurrent (); - epicsGuard < epicsMutex > guard ( this->mutex ); - double elapsed = 0.0; - this->cancel = true; - while ( ! this->terminated ) { - epicsGuardRelease < epicsMutex > unguard ( guard ); - this->event.signal (); - this->exitEvent.wait ( delay - elapsed ); - epicsTime current = epicsTime::getCurrent (); - double exitWaitElapsed = current - exitWaitBegin; - if ( exitWaitElapsed >= delay ) { - break; - } + // if destructor is running in managed thread then of + // course we will not wait for the managed thread to + // exit + if ( this->isCurrentThread() ) { + if ( this->pWaitReleaseFlag ) { + *this->pWaitReleaseFlag = true; + } + return true; + } + epicsTime exitWaitBegin = epicsTime::getCurrent (); + double exitWaitElapsed = 0.0; + epicsGuard < epicsMutex > guard ( this->mutex ); + this->cancel = true; + while ( ! this->terminated ) { + epicsGuardRelease < epicsMutex > unguard ( guard ); + this->event.signal (); + this->exitEvent.wait ( delay - exitWaitElapsed ); + epicsTime current = epicsTime::getCurrent (); + exitWaitElapsed = current - exitWaitBegin; + if ( exitWaitElapsed >= delay ) { + break; } } return this->terminated; } -void epicsThread::exitWaitRelease () +epicsThread::epicsThread ( + epicsThreadRunable & runableIn, const char * pName, + unsigned stackSize, unsigned priority ) : + runable ( runableIn ), id ( 0 ), pWaitReleaseFlag ( 0 ), + begin ( false ), cancel ( false ), terminated ( false ) { - if ( this->isCurrentThread() ) { - epicsGuard < epicsMutex > guard ( this->mutex ); - if ( this->pWaitReleaseFlag ) { - *this->pWaitReleaseFlag = true; - } - this->terminated = true; - this->exitEvent.signal (); - // once the terminated flag is set and we release the lock - // then the "this" pointer must not be touched again + this->id = epicsThreadCreate ( + pName, priority, stackSize, epicsThreadCallEntryPoint, + static_cast < void * > ( this ) ); + if ( ! this->id ) { + throw unableToCreateThread (); } } -epicsThread::epicsThread ( epicsThreadRunable &r, const char *name, - unsigned stackSize, unsigned priority ) : - runable(r), pWaitReleaseFlag ( 0 ), - begin ( false ), cancel (false), terminated ( false ) -{ - this->id = epicsThreadCreate ( name, priority, stackSize, - epicsThreadCallEntryPoint, static_cast (this) ); -} - -epicsThread::~epicsThread () +epicsThread::~epicsThread () throw () { while ( ! this->exitWait ( 10.0 ) ) { char nameBuf [256]; @@ -159,7 +181,7 @@ epicsThread::~epicsThread () } } -void epicsThread::start () +void epicsThread::start () throw () { { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -168,37 +190,37 @@ void epicsThread::start () this->event.signal (); } -bool epicsThread::isCurrentThread () const +bool epicsThread::isCurrentThread () const throw () { return ( epicsThreadGetIdSelf () == this->id ); } -void epicsThread::resume () +void epicsThread::resume () throw () { epicsThreadResume ( this->id ); } -void epicsThread::getName ( char *name, size_t size ) const +void epicsThread::getName ( char *name, size_t size ) const throw () { epicsThreadGetName ( this->id, name, size ); } -epicsThreadId epicsThread::getId () const +epicsThreadId epicsThread::getId () const throw () { return this->id; } -unsigned int epicsThread::getPriority () const +unsigned int epicsThread::getPriority () const throw () { return epicsThreadGetPriority (this->id); } -void epicsThread::setPriority (unsigned int priority) +void epicsThread::setPriority (unsigned int priority) throw () { epicsThreadSetPriority (this->id, priority); } -bool epicsThread::priorityIsEqual (const epicsThread &otherThread) const +bool epicsThread::priorityIsEqual (const epicsThread &otherThread) const throw () { if ( epicsThreadIsEqual (this->id, otherThread.id) ) { return true; @@ -206,7 +228,7 @@ bool epicsThread::priorityIsEqual (const epicsThread &otherThread) const return false; } -bool epicsThread::isSuspended () const +bool epicsThread::isSuspended () const throw () { if ( epicsThreadIsSuspended (this->id) ) { return true; @@ -214,7 +236,7 @@ bool epicsThread::isSuspended () const return false; } -bool epicsThread::operator == (const epicsThread &rhs) const +bool epicsThread::operator == (const epicsThread &rhs) const throw () { return (this->id == rhs.id); } @@ -234,21 +256,33 @@ void epicsThread::sleep (double seconds) // return * static_cast ( epicsThreadGetIdSelf () ); //} -const char *epicsThread::getNameSelf () +const char *epicsThread::getNameSelf () throw () { return epicsThreadGetNameSelf (); } -bool epicsThread::isOkToBlock () +bool epicsThread::isOkToBlock () throw () { - return static_cast(epicsThreadIsOkToBlock()); + return epicsThreadIsOkToBlock() != 0; } -void epicsThread::setOkToBlock(bool isOkToBlock) +void epicsThread::setOkToBlock(bool isOkToBlock) throw () { epicsThreadSetOkToBlock(static_cast(isOkToBlock)); } +class epicsThreadPrivateBase::unableToCreateThreadPrivate : public exception { + const char * what () const throw () + { + return "epicsThreadPrivate:: unable to create thread private variable"; + } +}; + +void epicsThreadPrivateBase::throwUnableToCreateThreadPrivate () +{ + throw epicsThreadPrivateBase::unableToCreateThreadPrivate (); +} + extern "C" { static epicsThreadOnceId okToBlockOnce = EPICS_THREAD_ONCE_INIT; epicsThreadPrivateId okToBlockPrivate; @@ -282,4 +316,13 @@ extern "C" { pokToBlock = (isOkToBlock) ? &okToBlockYes : &okToBlockNo; epicsThreadPrivateSet(okToBlockPrivate,pokToBlock); } + epicsThreadId epicsShareAPI epicsThreadMustCreate ( + const char *name, unsigned int priority, unsigned int stackSize, + EPICSTHREADFUNC funptr,void *parm) + { + epicsThreadId id = epicsThreadCreate ( + name, priority, stackSize, funptr, parm ); + assert ( id ); + return id; + } } // extern "C" diff --git a/src/libCom/osi/epicsThread.h b/src/libCom/osi/epicsThread.h index afc71e19c..a1e7db293 100644 --- a/src/libCom/osi/epicsThread.h +++ b/src/libCom/osi/epicsThread.h @@ -65,9 +65,12 @@ epicsShareFunc void epicsShareAPI epicsThreadExitMain(void); /* (epicsThreadId)0 is guaranteed to be an invalid thread id */ typedef struct epicsThreadOSD *epicsThreadId; -epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate(const char *name, - unsigned int priority, unsigned int stackSize, - EPICSTHREADFUNC funptr,void *parm); +epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate ( + const char * name, unsigned int priority, unsigned int stackSize, + EPICSTHREADFUNC funptr,void * parm ); +epicsShareFunc epicsThreadId epicsShareAPI epicsThreadMustCreate ( + const char * name, unsigned int priority, unsigned int stackSize, + EPICSTHREADFUNC funptr,void * parm ); epicsShareFunc void epicsShareAPI epicsThreadSuspendSelf(void); epicsShareFunc void epicsShareAPI epicsThreadResume(epicsThreadId id); epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPriority( @@ -116,16 +119,14 @@ epicsShareFunc void * epicsShareAPI epicsThreadPrivateGet(epicsThreadPrivateId); #ifdef __cplusplus -#include "locationException.h" #include "epicsEvent.h" #include "epicsMutex.h" -class epicsThreadRunable { +class epicsShareClass epicsThreadRunable { public: - epicsShareFunc virtual ~epicsThreadRunable (); + virtual ~epicsThreadRunable () = 0; virtual void run () = 0; - epicsShareFunc virtual void stop (); - epicsShareFunc virtual void show ( unsigned int level ) const; + virtual void show ( unsigned int level ) const; }; extern "C" void epicsThreadCallEntryPoint ( void * ); @@ -134,29 +135,28 @@ class epicsShareClass epicsThread { public: epicsThread ( epicsThreadRunable &,const char *name, unsigned int stackSize, unsigned int priority=epicsThreadPriorityLow ); - ~epicsThread (); - void start(); - void exitWait (); - bool exitWait (const double delay ); - void exitWaitRelease (); /* noop if not called by managed thread */ + ~epicsThread () throw (); + void start () throw (); + void exitWait () throw (); + bool exitWait ( const double delay ) throw (); static void exit (); - void resume (); - void getName ( char * name, size_t size ) const; - epicsThreadId getId () const; - unsigned int getPriority () const; - void setPriority (unsigned int); - bool priorityIsEqual (const epicsThread &otherThread) const; - bool isSuspended () const; - bool isCurrentThread () const; - bool operator == (const epicsThread &rhs) const; + void resume () throw (); + void getName ( char * name, size_t size ) const throw (); + epicsThreadId getId () const throw (); + unsigned int getPriority () const throw (); + void setPriority ( unsigned int ) throw (); + bool priorityIsEqual ( const epicsThread & ) const throw (); + bool isSuspended () const throw (); + bool isCurrentThread () const throw (); + bool operator == ( const epicsThread & ) const throw (); /* these operate on the current thread */ - static void suspendSelf (); - static void sleep (double seconds); + static void suspendSelf () throw (); + static void sleep (double seconds) throw (); /* static epicsThread & getSelf (); */ - static const char * getNameSelf (); - static bool isOkToBlock () ; - static void setOkToBlock(bool isOkToBlock) ; - class mustBeCalledByManagedThread {}; /* exception */ + static const char * getNameSelf () throw (); + static bool isOkToBlock () throw (); + static void setOkToBlock ( bool isOkToBlock ) throw (); + class unableToCreateThread; /* exception payload */ private: epicsThreadRunable & runable; epicsThreadId id; @@ -168,22 +168,29 @@ private: bool cancel; bool terminated; - bool beginWait (); + bool beginWait () throw (); epicsThread ( const epicsThread & ); epicsThread & operator = ( const epicsThread & ); friend void epicsThreadCallEntryPoint ( void * ); - class exitException {}; + class exitException; /* exception payload */ +}; + +class epicsShareClass epicsThreadPrivateBase { +public: + class unableToCreateThreadPrivate; /* exception */ +protected: + static void throwUnableToCreateThreadPrivate (); }; template < class T > -class epicsThreadPrivate { +class epicsThreadPrivate : + private epicsThreadPrivateBase { public: epicsThreadPrivate (); ~epicsThreadPrivate (); - T * get () const; - void set (T *); - class unableToCreateThreadPrivate {}; /* exception */ + T * get () const throw (); + void set (T *) throw (); private: epicsThreadPrivateId id; }; @@ -198,8 +205,8 @@ template inline epicsThreadPrivate::epicsThreadPrivate () { this->id = epicsThreadPrivateCreate (); - if (this->id == 0) { - throwWithLocation ( unableToCreateThreadPrivate () ); + if ( this->id == 0 ) { + epicsThreadPrivateBase::throwUnableToCreateThreadPrivate (); } }