/*************************************************************************\ * Copyright (c) 2002 The University of Chicago, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * EPICS BASE Versions 3.13.7 * and higher are distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ /* * Revision-Id: anj@aps.anl.gov-20101005192737-disfz3vs0f3fiixd * * * L O S A L A M O S * Los Alamos National Laboratory * Los Alamos, New Mexico 87545 * * Copyright, 1986, The Regents of the University of California. * * * Author: * Jeffrey O. Hill * johill@lanl.gov * 505 665 1831 */ #include #include #include #include #include "epicsMutex.h" #include "epicsEvent.h" #include "epicsTime.h" #include "tsFreeList.h" #include "errMdef.h" #include "errlog.h" #include "caerr.h" // this needs to be eliminated #include "db_access.h" // this needs to be eliminated #define epicsExportSharedSymbols #include "dbCAC.h" #include "dbChannelIO.h" #include "dbPutNotifyBlocker.h" dbPutNotifyBlocker::dbPutNotifyBlocker ( epicsMutex & mutexIn ) : mutex ( mutexIn ), pNotify ( 0 ), maxValueSize ( sizeof ( this->dbrScalarValue ) ) { memset ( & this->pn, '\0', sizeof ( this->pn ) ); memset ( & this->dbrScalarValue, '\0', sizeof ( this->dbrScalarValue ) ); this->pn.pbuffer = & this->dbrScalarValue; } dbPutNotifyBlocker::~dbPutNotifyBlocker () { } void dbPutNotifyBlocker::destructor ( epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); this->cancel ( guard ); if ( this->maxValueSize > sizeof ( this->dbrScalarValue ) ) { char * pBuf = static_cast < char * > ( this->pn.pbuffer ); delete [] pBuf; } this->~dbPutNotifyBlocker (); } void dbPutNotifyBlocker::cancel ( epicsGuard < epicsMutex > & guard ) { guard.assertIdenticalMutex ( this->mutex ); if ( this->pn.paddr ) { epicsGuardRelease < epicsMutex > unguard ( guard ); dbNotifyCancel ( &this->pn ); } this->pNotify = 0; this->block.signal (); } void dbPutNotifyBlocker::expandValueBuf ( epicsGuard < epicsMutex > & guard, unsigned long newSize ) { guard.assertIdenticalMutex ( this->mutex ); if ( this->maxValueSize < newSize ) { if ( this->maxValueSize > sizeof ( this->dbrScalarValue ) ) { char * pBuf = static_cast < char * > ( this->pn.pbuffer ); delete [] pBuf; this->maxValueSize = sizeof ( this->dbrScalarValue ); this->pn.pbuffer = & this->dbrScalarValue; } this->pn.pbuffer = new char [newSize]; this->maxValueSize = newSize; } } extern "C" void putNotifyCompletion ( putNotify *ppn ) { dbPutNotifyBlocker * pBlocker = static_cast < dbPutNotifyBlocker * > ( ppn->usrPvt ); { epicsGuard < epicsMutex > guard ( pBlocker->mutex ); if ( pBlocker->pNotify ) { if ( pBlocker->pn.status != putNotifyOK) { pBlocker->pNotify->exception ( guard, ECA_PUTFAIL, "put notify unsuccessful", static_cast (pBlocker->pn.dbrType), static_cast (pBlocker->pn.nRequest) ); } else { pBlocker->pNotify->completion ( guard ); } } else { errlogPrintf ( "put notify completion with nill pNotify?\n" ); } pBlocker->pNotify = 0; } pBlocker->block.signal (); } void dbPutNotifyBlocker::initiatePutNotify ( epicsGuard < epicsMutex > & guard, cacWriteNotify & notify, struct dbAddr & addr, unsigned type, unsigned long count, const void * pValue ) { guard. assertIdenticalMutex ( this->mutex ); epicsTime begin; bool beginTimeInit = false; while ( true ) { if ( this->pNotify == 0 ) { this->pNotify = & notify; break; } if ( beginTimeInit ) { if ( epicsTime::getCurrent () - begin > 30.0 ) { throw cacChannel::requestTimedOut (); } } else { begin = epicsTime::getCurrent (); beginTimeInit = true; } { epicsGuardRelease < epicsMutex > autoRelease ( guard ); this->block.wait ( 1.0 ); } } if ( count > LONG_MAX ) { throw cacChannel::outOfBounds(); } if ( type > SHRT_MAX ) { throw cacChannel::badType(); } int status = dbPutNotifyMapType ( &this->pn, static_cast ( type ) ); if ( status ) { this->pNotify = 0; throw cacChannel::badType(); } this->pn.nRequest = static_cast < unsigned > ( count ); this->pn.paddr = &addr; this->pn.userCallback = putNotifyCompletion; this->pn.usrPvt = this; unsigned long size = dbr_size_n ( type, count ); this->expandValueBuf ( guard, size ); memcpy ( this->pn.pbuffer, pValue, size ); { epicsGuardRelease < epicsMutex > autoRelease ( guard ); ::dbPutNotify ( &this->pn ); } } void dbPutNotifyBlocker::show ( unsigned level ) const { epicsGuard < epicsMutex > guard ( this->mutex ); this->show ( guard, level ); } void dbPutNotifyBlocker::show ( epicsGuard < epicsMutex > &, unsigned level ) const { printf ( "put notify blocker at %p\n", static_cast ( this ) ); if ( level > 0u ) { this->block.show ( level - 1u ); } } dbSubscriptionIO * dbPutNotifyBlocker::isSubscription () { return 0; } void * dbPutNotifyBlocker::operator new ( size_t size, tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & freeList ) { return freeList.allocate ( size ); } void * dbPutNotifyBlocker::operator new ( size_t ) // X aCC 361 { // The HPUX compiler seems to require this even though no code // calls it directly throw std::logic_error ( "why is the compiler calling private operator new" ); } #ifdef CXX_PLACEMENT_DELETE void dbPutNotifyBlocker::operator delete ( void *pCadaver, tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & freeList ) { freeList.release ( pCadaver ); } #endif void dbPutNotifyBlocker::operator delete ( void * ) { // Visual C++ .net appears to require operator delete if // placement operator delete is defined? I smell a ms rat // because if I declare placement new and delete, but // comment out the placement delete definition there are // no undefined symbols. errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked", __FILE__, __LINE__ ); }