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
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
// Author: Jeff Hill
|
||||
//
|
||||
|
||||
#include <stdexcept>
|
||||
#include <exception>
|
||||
#include <typeinfo>
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -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 <void *> (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<epicsThread *> ( epicsThreadGetIdSelf () );
|
||||
//}
|
||||
|
||||
const char *epicsThread::getNameSelf ()
|
||||
const char *epicsThread::getNameSelf () throw ()
|
||||
{
|
||||
return epicsThreadGetNameSelf ();
|
||||
}
|
||||
|
||||
bool epicsThread::isOkToBlock ()
|
||||
bool epicsThread::isOkToBlock () throw ()
|
||||
{
|
||||
return static_cast<bool>(epicsThreadIsOkToBlock());
|
||||
return epicsThreadIsOkToBlock() != 0;
|
||||
}
|
||||
|
||||
void epicsThread::setOkToBlock(bool isOkToBlock)
|
||||
void epicsThread::setOkToBlock(bool isOkToBlock) throw ()
|
||||
{
|
||||
epicsThreadSetOkToBlock(static_cast<int>(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"
|
||||
|
||||
@@ -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 <class T>
|
||||
inline epicsThreadPrivate<T>::epicsThreadPrivate ()
|
||||
{
|
||||
this->id = epicsThreadPrivateCreate ();
|
||||
if (this->id == 0) {
|
||||
throwWithLocation ( unableToCreateThreadPrivate () );
|
||||
if ( this->id == 0 ) {
|
||||
epicsThreadPrivateBase::throwUnableToCreateThreadPrivate ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user