dont hold lock while calling callbacks
This commit is contained in:
@@ -20,13 +20,18 @@
|
||||
#include "epicsMutex.h"
|
||||
#include "tsFreeList.h"
|
||||
|
||||
#include "cadef.h"
|
||||
#include "cacIO.h"
|
||||
#include "cadef.h" // this can be eliminated when the callbacks use the new interface
|
||||
#include "db_access.h" // should be eliminated here in the future
|
||||
#include "caerr.h" // should be eliminated here in the future
|
||||
#include "epicsEvent.h"
|
||||
#include "epicsThread.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "db_access_routines.h"
|
||||
#include "dbCAC.h"
|
||||
#include "dbChannelIOIL.h"
|
||||
#include "dbNotifyBlockerIL.h"
|
||||
|
||||
class dbServiceIOLoadTimeInit {
|
||||
public:
|
||||
@@ -47,7 +52,8 @@ dbServiceIOLoadTimeInit::dbServiceIOLoadTimeInit ()
|
||||
}
|
||||
|
||||
dbServiceIO::dbServiceIO () :
|
||||
ctx (0), pEventCallbackCache (0), eventCallbackCacheSize (0ul)
|
||||
ioTable ( 1024 ), eventCallbackCacheSize ( 0ul ),
|
||||
ctx ( 0 ), pEventCallbackCache ( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
@@ -56,12 +62,12 @@ dbServiceIO::~dbServiceIO ()
|
||||
if ( this->pEventCallbackCache ) {
|
||||
delete [] this->pEventCallbackCache;
|
||||
}
|
||||
if (this->ctx) {
|
||||
db_close_events (this->ctx);
|
||||
if ( this->ctx ) {
|
||||
db_close_events ( this->ctx );
|
||||
}
|
||||
}
|
||||
|
||||
cacChannelIO *dbServiceIO::createChannelIO (
|
||||
cacChannel *dbServiceIO::createChannel (
|
||||
const char *pName, cacChannelNotify ¬ify )
|
||||
{
|
||||
struct dbAddr addr;
|
||||
@@ -78,19 +84,21 @@ cacChannelIO *dbServiceIO::createChannelIO (
|
||||
void dbServiceIO::callReadNotify ( struct dbAddr &addr,
|
||||
unsigned type, unsigned long count,
|
||||
const struct db_field_log *pfl,
|
||||
cacChannelIO &chan, cacNotify ¬ify )
|
||||
cacChannel &chan, cacDataNotify ¬ify )
|
||||
{
|
||||
unsigned long size = dbr_size_n ( type, count );
|
||||
|
||||
if ( type > INT_MAX ) {
|
||||
notify.exceptionNotify ( chan, ECA_BADTYPE,
|
||||
"type code out of range (high side)" );
|
||||
notify.exception ( ECA_BADTYPE,
|
||||
"type code out of range (high side)",
|
||||
type, count );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( count > INT_MAX ) {
|
||||
notify.exceptionNotify ( chan, ECA_BADCOUNT,
|
||||
"element count out of range (high side)" );
|
||||
notify.exception ( ECA_BADCOUNT,
|
||||
"element count out of range (high side)",
|
||||
type, count);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -103,8 +111,9 @@ void dbServiceIO::callReadNotify ( struct dbAddr &addr,
|
||||
this->pEventCallbackCache = new char [size];
|
||||
if ( ! this->pEventCallbackCache ) {
|
||||
this->eventCallbackCacheSize = 0ul;
|
||||
notify.exceptionNotify ( chan, ECA_ALLOCMEM,
|
||||
"unable to allocate callback cache" );
|
||||
notify.exception ( ECA_ALLOCMEM,
|
||||
"unable to allocate callback cache",
|
||||
type, count );
|
||||
return;
|
||||
}
|
||||
this->eventCallbackCacheSize = size;
|
||||
@@ -113,12 +122,12 @@ void dbServiceIO::callReadNotify ( struct dbAddr &addr,
|
||||
int status = db_get_field ( &addr, static_cast <int> ( type ),
|
||||
this->pEventCallbackCache, static_cast <int> ( count ), pvfl );
|
||||
if ( status ) {
|
||||
notify.exceptionNotify ( chan, ECA_GETFAIL,
|
||||
"db_get_field() completed unsuccessfuly" );
|
||||
notify.exception ( ECA_GETFAIL,
|
||||
"db_get_field() completed unsuccessfuly",
|
||||
type, count);
|
||||
}
|
||||
else {
|
||||
notify.completionNotify ( chan, type,
|
||||
count, this->pEventCallbackCache );
|
||||
notify.completion ( type, count, this->pEventCallbackCache );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,12 +139,14 @@ extern "C" void cacAttachClientCtx ( void * pPrivate )
|
||||
assert ( status == ECA_NORMAL );
|
||||
}
|
||||
|
||||
dbEventSubscription dbServiceIO::subscribe ( struct dbAddr &addr, dbSubscriptionIO &subscr, unsigned mask )
|
||||
dbEventSubscription dbServiceIO::subscribe ( struct dbAddr &addr, dbChannelIO &chan,
|
||||
dbSubscriptionIO &subscr, unsigned mask, cacChannel::ioid *pId )
|
||||
{
|
||||
caClientCtx clientCtx;
|
||||
dbEventSubscription es;
|
||||
int status;
|
||||
|
||||
caClientCtx clientCtx;
|
||||
|
||||
status = ca_current_context ( &clientCtx );
|
||||
if ( status != ECA_NORMAL ) {
|
||||
return 0;
|
||||
@@ -156,30 +167,128 @@ dbEventSubscription dbServiceIO::subscribe ( struct dbAddr &addr, dbSubscription
|
||||
above = selfPriority;
|
||||
}
|
||||
status = db_start_events ( this->ctx, "CAC-event",
|
||||
cacAttachClientCtx, clientCtx, above );
|
||||
0/*cacAttachClientCtx*/, 0/*clientCtx*/, above );
|
||||
if ( status ) {
|
||||
db_close_events ( this->ctx );
|
||||
this->ctx = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
chan.dbServicePrivateListOfIO::eventq.add ( subscr );
|
||||
this->ioTable.add ( subscr );
|
||||
}
|
||||
|
||||
es = db_add_event ( this->ctx, &addr,
|
||||
dbSubscriptionEventCallback, (void *) &subscr, mask );
|
||||
if (es) {
|
||||
if ( es ) {
|
||||
db_post_single_event ( es );
|
||||
}
|
||||
else {
|
||||
epicsAutoMutex locker ( this->mutex );
|
||||
chan.dbServicePrivateListOfIO::eventq.remove ( subscr );
|
||||
this->ioTable.remove ( subscr );
|
||||
}
|
||||
|
||||
if ( pId ) {
|
||||
*pId = subscr.getId ();
|
||||
}
|
||||
|
||||
return es;
|
||||
}
|
||||
|
||||
void dbServiceIO::initiatePutNotify ( dbChannelIO &chan, struct dbAddr &addr,
|
||||
unsigned type, unsigned long count, const void *pValue,
|
||||
cacNotify ¬ify, cacChannel::ioid *pId )
|
||||
{
|
||||
epicsAutoMutex locker ( this->mutex );
|
||||
if ( ! chan.dbServicePrivateListOfIO::pBlocker ) {
|
||||
chan.dbServicePrivateListOfIO::pBlocker = new dbPutNotifyBlocker ( chan );
|
||||
if ( ! chan.dbServicePrivateListOfIO::pBlocker ) {
|
||||
throw cacChannel::noMemory();
|
||||
}
|
||||
this->ioTable.add ( *chan.dbServicePrivateListOfIO::pBlocker );
|
||||
}
|
||||
chan.dbServicePrivateListOfIO::pBlocker->initiatePutNotify (
|
||||
this->mutex, notify, addr, type, count, pValue );
|
||||
if ( pId ) {
|
||||
*pId = chan.dbServicePrivateListOfIO::pBlocker->getId ();
|
||||
}
|
||||
}
|
||||
|
||||
void dbServiceIO::putNotifyCompletion ( dbPutNotifyBlocker &blocker )
|
||||
{
|
||||
epicsAutoMutex locker ( this->mutex );
|
||||
blocker.completion ();
|
||||
}
|
||||
|
||||
void dbServiceIO::destroyAllIO ( dbChannelIO & chan )
|
||||
{
|
||||
dbSubscriptionIO *pIO;
|
||||
tsDLList < dbSubscriptionIO > tmp;
|
||||
{
|
||||
epicsAutoMutex locker ( this->mutex );
|
||||
while ( ( pIO = chan.dbServicePrivateListOfIO::eventq.get() ) ) {
|
||||
this->ioTable.remove ( *pIO );
|
||||
tmp.add ( *pIO );
|
||||
}
|
||||
if ( chan.dbServicePrivateListOfIO::pBlocker ) {
|
||||
this->ioTable.remove ( *chan.dbServicePrivateListOfIO::pBlocker );
|
||||
}
|
||||
}
|
||||
while ( ( pIO = tmp.get() ) ) {
|
||||
pIO->destroy ();
|
||||
}
|
||||
chan.dbServicePrivateListOfIO::pBlocker->destroy ();
|
||||
}
|
||||
|
||||
void dbServiceIO::ioCancel ( dbChannelIO & chan, const cacChannel::ioid &id )
|
||||
{
|
||||
epicsAutoMutex locker ( this->mutex );
|
||||
dbBaseIO *pIO = this->ioTable.remove ( id );
|
||||
if ( pIO ) {
|
||||
dbSubscriptionIO *pSIO = pIO->isSubscription ();
|
||||
if ( pSIO ) {
|
||||
chan.dbServicePrivateListOfIO::eventq.remove ( *pSIO );
|
||||
pIO->destroy ();
|
||||
}
|
||||
else if ( pIO == chan.dbServicePrivateListOfIO::pBlocker ) {
|
||||
chan.dbServicePrivateListOfIO::pBlocker->cancel ();
|
||||
}
|
||||
else {
|
||||
errlogPrintf ( "dbServiceIO::ioCancel() unrecognized IO was probably leaked\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dbServiceIO::ioShow ( const cacChannel::ioid &id, unsigned level ) const
|
||||
{
|
||||
epicsAutoMutex locker ( this->mutex );
|
||||
const dbBaseIO *pIO = this->ioTable.lookup ( id );
|
||||
if ( pIO ) {
|
||||
pIO->show ( level );
|
||||
}
|
||||
}
|
||||
|
||||
void dbServiceIO::showAllIO ( const dbChannelIO &chan, unsigned level ) const
|
||||
{
|
||||
epicsAutoMutex locker ( this->mutex );
|
||||
tsDLIterConstBD < dbSubscriptionIO > pItem =
|
||||
chan.dbServicePrivateListOfIO::eventq.firstIter ();
|
||||
while ( pItem.valid () ) {
|
||||
pItem->show ( level );
|
||||
pItem++;
|
||||
}
|
||||
if ( chan.dbServicePrivateListOfIO::pBlocker ) {
|
||||
chan.dbServicePrivateListOfIO::pBlocker->show ( level );
|
||||
}
|
||||
}
|
||||
|
||||
void dbServiceIO::show ( unsigned level ) const
|
||||
{
|
||||
epicsAutoMutex locker ( this->mutex );
|
||||
printf ( "dbServiceIO at %p\n",
|
||||
static_cast <const void *> ( this ) );
|
||||
if (level > 0u ) {
|
||||
if ( level > 0u ) {
|
||||
printf ( "\tevent call back cache location %p, and its size %lu\n",
|
||||
this->pEventCallbackCache, this->eventCallbackCacheSize );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user