From e3c0703df1934f2fe85471a7b98f44f23efedee2 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 21 Apr 2018 13:31:03 -0700 Subject: [PATCH] pvalink: input proc if changed --- documentation/qsrvpage.h | 7 +++++++ pdbApp/pvalink.h | 4 +++- pdbApp/pvalink_channel.cpp | 7 +++++-- pdbApp/pvalink_jlif.cpp | 4 ++++ pdbApp/pvalink_link.cpp | 23 +++++++++++++++++++++++ 5 files changed, 42 insertions(+), 3 deletions(-) diff --git a/documentation/qsrvpage.h b/documentation/qsrvpage.h index 0347a77..214760c 100644 --- a/documentation/qsrvpage.h +++ b/documentation/qsrvpage.h @@ -184,6 +184,7 @@ record(longin, "src") { time:false, # set record time during getValue monorder:0, # Order of record processing as a result of CP and CPP retry:false,# allow Put while disconnected. + always:false,# CP/CPP input link process even when .value field hasn't changed defer:false # Defer put }}) } @@ -283,6 +284,12 @@ Put to contain updates to multiple sub-fields. Allow a Put operation to be queued while the link is disconnected. The Put will be executed when the link becomes connected. +@subsubsection qsrv_link_always always: CP/CPP always process + +By default (always:false) a subscription update will only cause a CP input link +to scan if the structure field (cf. field: option) is marked as changed. +Set to true to override this, and always process the link. + @subsubsection qsrv_link_sem Link semantics/behavior This section attempts to answer some questions about how links behave in certain situations. diff --git a/pdbApp/pvalink.h b/pdbApp/pvalink.h index 719088b..408019f 100644 --- a/pdbApp/pvalink.h +++ b/pdbApp/pvalink.h @@ -78,7 +78,7 @@ struct pvaLinkConfig : public jlink MSI, } ms; - bool defer, pipeline, time, retry, local; + bool defer, pipeline, time, retry, local, always; int monorder; // internals used by jlif parsing @@ -168,6 +168,7 @@ private: std::vector scan_records; std::vector scan_check_passive; + std::vector scan_changed; DBManyLock atomic_lock; }; @@ -194,6 +195,7 @@ struct pvaLink : public pvaLinkConfig epics::pvData::PVStructure::const_shared_pointer fld_display, fld_control, fld_valueAlarm; + epics::pvData::BitSet proc_changed; // cached snapshot of alarm and timestamp // captured in pvaGetValue(). diff --git a/pdbApp/pvalink_channel.cpp b/pdbApp/pvalink_channel.cpp index 15e5f4e..553aa4f 100644 --- a/pdbApp/pvalink_channel.cpp +++ b/pdbApp/pvalink_channel.cpp @@ -256,6 +256,9 @@ void pvaLinkChannel::run_dbProcess(size_t idx) if(scan_check_passive[idx] && precord->scan!=0) { return; + } else if(connected_latched && !op_mon.changed.logical_and(scan_changed[idx])) { + return; + } else if (precord->pact) { if (precord->tpro) printf("%s: Active %s\n", @@ -327,6 +330,7 @@ void pvaLinkChannel::run() scan_records.clear(); scan_check_passive.clear(); + scan_changed.clear(); for(links_t::iterator it(links.begin()), end(links.end()); it!=end; ++it) { @@ -343,6 +347,7 @@ void pvaLinkChannel::run() scan_records.push_back(link->plink->precord); scan_check_passive.push_back(link->pp != pvaLink::CP); + scan_changed.push_back(link->proc_changed); } DBManyLock ML(scan_records); @@ -351,8 +356,6 @@ void pvaLinkChannel::run() links_changed = false; } - - // TODO: if connected_latched. Option to test op_mon.changed with link::fld_value to only process on value change } if(scan_records.empty()) { diff --git a/pdbApp/pvalink_jlif.cpp b/pdbApp/pvalink_jlif.cpp index 9157e1b..2ed1f05 100644 --- a/pdbApp/pvalink_jlif.cpp +++ b/pdbApp/pvalink_jlif.cpp @@ -17,6 +17,7 @@ pvaLinkConfig::pvaLinkConfig() ,time(false) ,retry(false) ,local(false) + ,always(false) ,monorder(0) {} pvaLinkConfig::~pvaLinkConfig() {} @@ -41,6 +42,7 @@ using namespace pvalink; * "monorder":#,// order of processing during CP scan * "defer":true,// whether to immediately start Put, or only queue value to be sent * "retry":true,// queue Put while disconnected, and retry on connect + * "always":true,// CP/CPP updates always process a like, even if its input field hasn't changed * "local":false,// Require local channel * } */ @@ -114,6 +116,8 @@ jlif_result pva_parse_bool(jlink *pjlink, int val) pvt->retry = !!val; } else if(pvt->jkey == "local") { pvt->local = !!val; + } else if(pvt->jkey == "always") { + pvt->always = !!val; } else if(pvt->debug) { printf("pva link parsing unknown integer depth=%u key=\"%s\" value=%s\n", pvt->parseDepth, pvt->jkey.c_str(), val ? "true" : "false"); diff --git a/pdbApp/pvalink_link.cpp b/pdbApp/pvalink_link.cpp index ba37a06..cd1ada0 100644 --- a/pdbApp/pvalink_link.cpp +++ b/pdbApp/pvalink_link.cpp @@ -114,6 +114,29 @@ void pvaLink::onTypeChange() fld_display = std::tr1::dynamic_pointer_cast(getSubField("display")); fld_control = std::tr1::dynamic_pointer_cast(getSubField("control")); fld_valueAlarm = std::tr1::dynamic_pointer_cast(getSubField("valueAlarm")); + + proc_changed.clear(); + + // build mask of all "changed" bits associated with our .value + // CP/CPP input links will process this link only for updates where + // the changed mask and proc_changed share at least one set bit. + if(fld_value) { + // bit for this field + proc_changed.set(fld_value->getFieldOffset()); + + // bits of all parent fields + for(const pvd::PVStructure* parent = fld_value->getParent(); parent; parent = parent->getParent()) { + proc_changed.set(parent->getFieldOffset()); + } + + if(fld_value->getField()->getType()==pvd::structure) + { + // bits of all child fields + const pvd::PVStructure *val = static_cast(fld_value.get()); + for(size_t i=val->getFieldOffset(), N=val->getNextFieldOffset(); i