client: (shallow) copy into Monitor::root

Avoid exposing refs. from monitor queue
which might then be used after release().
Also allows users the possibility of caching
getSubField() until root.get() actually changes.
This commit is contained in:
Michael Davidsaver
2018-02-21 11:19:21 -08:00
parent 79ada524fa
commit b5bf6a4ccd
2 changed files with 35 additions and 4 deletions

View File

@ -196,16 +196,29 @@ bool Monitor::poll()
Guard G(impl->mutex);
if(!impl->done && impl->last.next()) {
root = impl->last->pvStructurePtr;
const epics::pvData::PVStructurePtr& ptr = impl->last->pvStructurePtr;
changed = *impl->last->changedBitSet;
overrun = *impl->last->overrunBitSet;
/* copy the exposed PVStructure for two reasons.
* 1. Prevent accidental use of shared container after release()
* 2. Allows caller to cache results of getSubField() until root.get() changes.
*/
if(!root || (void*)root->getField().get()!=(void*)ptr->getField().get()) {
// initial connection, or new type
root = pvd::getPVDataCreate()->createPVStructure(ptr); // also calls copyUnchecked()
} else {
// same type
const_cast<pvd::PVStructure&>(*root).copyUnchecked(*ptr, changed);
}
impl->seenEmpty = false;
} else {
root.reset();
changed.clear();
overrun.clear();
impl->seenEmpty = true;
}
return impl->seenEmpty = !!root;
return !impl->seenEmpty;
}
bool Monitor::complete() const

View File

@ -104,13 +104,31 @@ struct epicsShareClass Monitor
void cancel();
/** updates root, changed, overrun
*
* @return true if root!=NULL
* @return true if a new update was extracted from the queue.
* @note This method does not block.
* @note MonitorEvent::Data will not be repeated until poll()==false.
* @post root!=NULL (after version 6.0.0)
* @post root!=NULL iff poll()==true (In version 6.0.0)
*/
bool poll();
//! true if all events received.
//! Check after poll()==false
bool complete() const;
/** Monitor update data.
*
* After version 6.0.0
*
* Initially NULL, becomes !NULL the first time poll()==true.
* The PVStructure pointed to be root will presist until
* Monitor reconnect w/ type change. This can be detected
* by comparing `root.get()`. references to root may be cached
* subject to this test.
*
* In version 6.0.0
*
* NULL except after poll()==true. poll()==false sets root=NULL.
* references to root should not be stored between calls to poll().
*/
epics::pvData::PVStructure::const_shared_pointer root;
epics::pvData::BitSet changed,
overrun;