Files
pva2pva/pdbApp/pvalink.h
Michael Davidsaver bdbf57350b replace shareLib.h with QSRV_API
and hopefully avoid at least some of the maddening
include order bugs so common with sharedLib.h.
2019-09-05 20:01:56 -07:00

245 lines
6.5 KiB
C++

#ifndef PVALINK_H
#define PVALINK_H
#include <set>
#include <map>
#define EPICS_DBCA_PRIVATE_API
#include <epicsGuard.h>
#include <dbAccess.h>
#include <dbCommon.h>
#include <dbLink.h>
#include <dbScan.h>
#include <errlog.h>
#include <initHooks.h>
#include <alarm.h>
#include <epicsExit.h>
#include <epicsAtomic.h>
#include <link.h>
#include <dbJLink.h>
#include <errlog.h>
#include <epicsThread.h>
#include <epicsMutex.h>
#include <epicsEvent.h>
#include <dbChannel.h>
#include <dbStaticLib.h>
#include <dbLock.h>
#include <dbEvent.h>
#include <epicsVersion.h>
#include <pv/status.h>
#include <pv/bitSet.h>
#include <pv/pvData.h>
#include <pva/client.h>
#include <pv/anyscalar.h>
#include <pv/thread.h>
#include <pv/lock.h>
#include <pv/iocshelper.h>
#include <pv/sharedPtr.h>
#include "helper.h"
#include "pvif.h"
#include "tpool.h"
extern "C" {
QSRV_API extern int pvaLinkDebug;
QSRV_API extern int pvaLinkIsolate;
QSRV_API extern int pvaLinkNWorkers;
}
#if 0
# define TRACE(X) std::cerr<<"PVAL "<<__func__<<" " X <<"\n"
#else
# define TRACE(X) do {} while(0)
#endif
// pvaLink and pvaLinkChannel have ->debug
#define DEBUG(OBJ, X) do{ if((OBJ)->debug) std::cout X<<"\n"; }while(0)
namespace pvalink {
namespace pvd = epics::pvData;
namespace pva = epics::pvAccess;
typedef epicsGuard<pvd::Mutex> Guard;
typedef epicsGuardRelease<pvd::Mutex> UnGuard;
struct pvaLink;
struct pvaLinkChannel;
extern lset pva_lset;
extern jlif lsetPVA;
struct pvaLinkConfig : public jlink
{
// configuration, output of jlif parsing
//! Channel (aka PV) name string
std::string channelName;
//! sub-field within addressed PVStructure
std::string fieldName;
size_t queueSize;
enum pp_t {
NPP,
Default, // for put() only. For monitor, treated as NPP
PP, // for put() only, For monitor, treated as NPP
CP, // for monitor only, put treats as pp
CPP, // for monitor only, put treats as pp
} pp;
enum ms_t {
NMS,
MS,
MSI,
} ms;
bool defer, pipeline, time, retry, local, always;
int monorder;
// internals used by jlif parsing
std::string jkey;
pvaLinkConfig();
virtual ~pvaLinkConfig();
};
struct pvaGlobal_t {
pvac::ClientProvider provider_local,
provider_remote;
const pvd::PVDataCreatePtr create;
WorkQueue queue;
pvd::Mutex lock;
bool running; // set after dbEvent is initialized and safe to use
// a tuple of channel name and printed pvRequest (or Monitor)
typedef std::pair<std::string, std::string> channels_key_t;
// pvaLinkChannel dtor prunes dead entires
typedef std::map<channels_key_t, std::tr1::weak_ptr<pvaLinkChannel> > channels_t;
// Cache of active Channels (really about caching Monitor)
channels_t channels;
pvaGlobal_t();
~pvaGlobal_t();
};
extern pvaGlobal_t *pvaGlobal;
struct pvaLinkChannel : public pvac::ClientChannel::MonitorCallback,
public pvac::ClientChannel::PutCallback,
public epicsThreadRunable,
public std::tr1::enable_shared_from_this<pvaLinkChannel>
{
const pvaGlobal_t::channels_key_t key; // tuple of (channelName, pvRequest key)
const pvd::PVStructure::const_shared_pointer pvRequest; // used with monitor
static size_t num_instances;
pvd::Mutex lock;
epicsEvent run_done; // used by testing code
pvac::ClientChannel chan;
pvac::Monitor op_mon;
pvac::Operation op_put;
std::string providerName;
size_t num_disconnect, num_type_change;
bool connected;
bool connected_latched; // connection status at the run()
bool isatomic;
bool queued; // added to WorkQueue
bool debug; // set if any jlink::debug is set
std::tr1::shared_ptr<const void> previous_root;
struct LinkSort {
bool operator()(const pvaLink *L, const pvaLink *R) const;
};
typedef std::set<pvaLink*, LinkSort> links_t;
// list of currently attached links. maintained by pvaLink ctor/dtor
// TODO: sort by PHAS
links_t links;
// set when 'links' is modified to trigger re-compute of record scan list
bool links_changed;
pvaLinkChannel(const pvaGlobal_t::channels_key_t& key, const epics::pvData::PVStructure::const_shared_pointer &pvRequest);
virtual ~pvaLinkChannel();
void open();
void put(bool force=false); // begin Put op.
// pvac::ClientChanel::MonitorCallback
virtual void monitorEvent(const pvac::MonitorEvent& evt) OVERRIDE FINAL;
// pvac::ClientChanel::PutCallback
virtual void putBuild(const epics::pvData::StructureConstPtr& build, pvac::ClientChannel::PutCallback::Args& args) OVERRIDE FINAL;
virtual void putDone(const pvac::PutEvent& evt) OVERRIDE FINAL;
private:
virtual void run() OVERRIDE FINAL;
void run_dbProcess(size_t idx); // idx is index in scan_records
// ==== Treat remaining as local to run()
std::vector<dbCommon*> scan_records;
std::vector<bool> scan_check_passive;
std::vector<epics::pvData::BitSet> scan_changed;
DBManyLock atomic_lock;
};
struct pvaLink : public pvaLinkConfig
{
static size_t num_instances;
bool alive; // attempt to catch some use after free
DBLINK * plink; // may be NULL
std::tr1::shared_ptr<pvaLinkChannel> lchan;
bool used_scratch, used_queue;
pvd::shared_vector<const void> put_scratch, put_queue;
// cached fields from channel op_mon
// updated in onTypeChange()
epics::pvData::PVField::const_shared_pointer fld_value;
epics::pvData::PVScalar::const_shared_pointer fld_severity,
fld_seconds,
fld_nanoseconds;
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().
// we choose not to ensure consistency with display/control meta-data
epicsTimeStamp snap_time;
short snap_severity;
pvaLink();
virtual ~pvaLink();
// returns pvRequest to be used with monitor
pvd::PVStructurePtr makeRequest();
bool valid() const;
// fetch a sub-sub-field of the top monitored field.
pvd::PVField::const_shared_pointer getSubField(const char *name);
void onDisconnect();
void onTypeChange();
};
} // namespace pvalink
#endif // PVALINK_H