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:
Jeff Hill
2004-10-08 14:46:48 +00:00
parent dac63b0826
commit 7571947ceb
2 changed files with 141 additions and 91 deletions
+98 -55
View File
@@ -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"