Skip to content

Commit 1abc7a1

Browse files
committed
fix issue with object references for async callbacks
1 parent 767eab4 commit 1abc7a1

File tree

3 files changed

+21
-7
lines changed

3 files changed

+21
-7
lines changed

src/pvaccess/Channel.482.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,17 +1368,17 @@ void Channel::asyncGetThread(Channel* channel)
13681368

13691369
try {
13701370
AsyncRequestPtr asyncRequest = channel->asyncGetRequestQueue.frontAndPop();
1371+
13711372
// there were queued requests, reset poll counter
13721373
remainingRuntime = MaxAsyncRequestWaitTimeout;
13731374
try {
13741375
// Cannot allow shutdown while callback is being executed
13751376
pvd::Lock lock(channel->asyncGetThreadMutex);
13761377

13771378
channel->asyncConnect();
1378-
pvc::PvaClientGetPtr pvaGet = channel->createGetPtr(asyncRequest->requestDescriptor);
1379-
pvaGet->get();
1380-
pvd::PVStructurePtr pvStructure = pvaGet->getData()->getPVStructure();
1381-
PvObject pvObject(pvStructure);
1379+
pvc::PvaClientGetPtr asyncPvaGet = channel->createGetPtr(asyncRequest->requestDescriptor);
1380+
asyncPvaGet->get();
1381+
PvObject pvObject(asyncPvaGet->getData()->getPVStructure());
13821382
if (!channel->shutdownInProgress) {
13831383
logger.trace("Invoking async get callback");
13841384
channel->invokePyCallback(asyncRequest->pyCallback, pvObject);
@@ -1465,6 +1465,7 @@ void Channel::asyncPutThread(Channel* channel)
14651465

14661466
try {
14671467
AsyncRequestPtr asyncRequest = channel->asyncPutRequestQueue.frontAndPop();
1468+
14681469
// there were queued requests, reset poll counter
14691470
remainingRuntime = MaxAsyncRequestWaitTimeout;
14701471
try {
@@ -1475,8 +1476,7 @@ void Channel::asyncPutThread(Channel* channel)
14751476
pvc::PvaClientPutPtr asyncPvaPut = channel->createPutPtr(asyncRequest->requestDescriptor);
14761477
channel->preparePut(PvObject(asyncRequest->pvStructurePtr), asyncPvaPut);
14771478
asyncPvaPut->put();
1478-
pvd::PVStructurePtr pvStructure = asyncPvaPut->getData()->getPVStructure();
1479-
PvObject pvObject(pvStructure);
1479+
PvObject pvObject(asyncPvaPut->getData()->getPVStructure());
14801480
if (!channel->shutdownInProgress) {
14811481
logger.trace("Invoking async put callback");
14821482
channel->invokePyCallback(asyncRequest->pyCallback, pvObject);

src/pvaccess/Channel.482.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,17 @@ class Channel : public ChannelMonitorDataProcessor
265265
, requestDescriptor(requestDescriptor_)
266266
, pvStructurePtr(pvStructurePtr_)
267267
{}
268+
269+
// In some cases it seems like boost python object reference counts
270+
// go below the minimum before destructor is called
271+
~AsyncRequest() {
272+
if (pyCallback.ptr()->ob_refcnt <= 1) {
273+
boost::python::incref(pyCallback.ptr());
274+
}
275+
if (pyErrorCallback.ptr()->ob_refcnt <= 1) {
276+
boost::python::incref(pyErrorCallback.ptr());
277+
}
278+
}
268279
};
269280

270281
typedef std::tr1::shared_ptr<AsyncRequest> AsyncRequestPtr;

test/testChannelPut.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919

2020
class TestChannelPut:
2121

22+
def putCallback(self, pv):
23+
self.putPv = pv.copy()
24+
2225
#
2326
# Boolean Put
2427
#
@@ -389,7 +392,7 @@ def testAsyncPut_PvObject(self):
389392
pv = c.get('')
390393
pv['int'] = i
391394
print('\nAsync setting int field to: %s' % (i))
392-
c.asyncPut(pv, None, None, '')
395+
c.asyncPut(pv, self.putCallback, None, '')
393396
time.sleep(0.1)
394397
pv2 = c.get('')
395398
print('Testing equality: %s == %s' % (pv['int'], pv2['int']))

0 commit comments

Comments
 (0)