pva2pva  1.4.1
 All Classes Functions Variables Pages
pvalink.h
1 #ifndef PVALINK_H
2 #define PVALINK_H
3 
4 #include <set>
5 #include <map>
6 
7 #define EPICS_DBCA_PRIVATE_API
8 #include <epicsGuard.h>
9 #include <dbAccess.h>
10 #include <dbCommon.h>
11 #include <dbLink.h>
12 #include <dbScan.h>
13 #include <errlog.h>
14 #include <initHooks.h>
15 #include <alarm.h>
16 #include <epicsExit.h>
17 #include <epicsAtomic.h>
18 #include <link.h>
19 #include <dbJLink.h>
20 #include <errlog.h>
21 #include <epicsThread.h>
22 #include <epicsMutex.h>
23 #include <epicsEvent.h>
24 #include <dbChannel.h>
25 #include <dbStaticLib.h>
26 #include <dbLock.h>
27 #include <dbEvent.h>
28 #include <epicsVersion.h>
29 
30 #include <pv/status.h>
31 #include <pv/bitSet.h>
32 #include <pv/pvData.h>
33 
34 #include <pva/client.h>
35 #include <pv/anyscalar.h>
36 #include <pv/thread.h>
37 #include <pv/lock.h>
38 #include <pv/iocshelper.h>
39 
40 #include <pv/sharedPtr.h>
41 
42 #include "helper.h"
43 #include "pvif.h"
44 #include "tpool.h"
45 
46 extern "C" {
47  QSRV_API extern int pvaLinkDebug;
48  QSRV_API extern int pvaLinkIsolate;
49  QSRV_API extern int pvaLinkNWorkers;
50 }
51 
52 #if 0
53 # define TRACE(X) std::cerr<<"PVAL "<<__func__<<" " X <<"\n"
54 #else
55 # define TRACE(X) do {} while(0)
56 #endif
57 
58 // pvaLink and pvaLinkChannel have ->debug
59 #define DEBUG(OBJ, X) do{ if((OBJ)->debug) std::cout X<<"\n"; }while(0)
60 
61 namespace pvalink {
62 
63 namespace pvd = epics::pvData;
64 namespace pva = epics::pvAccess;
65 
66 typedef epicsGuard<pvd::Mutex> Guard;
67 typedef epicsGuardRelease<pvd::Mutex> UnGuard;
68 
69 struct pvaLink;
70 struct pvaLinkChannel;
71 
72 extern lset pva_lset;
73 extern jlif lsetPVA;
74 
75 struct pvaLinkConfig : public jlink
76 {
77  // configuration, output of jlif parsing
79  std::string channelName;
81  std::string fieldName;
82 
83  size_t queueSize;
84 
85  enum pp_t {
86  NPP,
87  Default, // for put() only. For monitor, treated as NPP
88  PP, // for put() only, For monitor, treated as NPP
89  CP, // for monitor only, put treats as pp
90  CPP, // for monitor only, put treats as pp
91  } pp;
92  enum ms_t {
93  NMS,
94  MS,
95  MSI,
96  } ms;
97 
98  bool defer, pipeline, time, retry, local, always;
99  int monorder;
100 
101  // internals used by jlif parsing
102  std::string jkey;
103 
104  pvaLinkConfig();
105  virtual ~pvaLinkConfig();
106 };
107 
108 struct pvaGlobal_t {
109  pvac::ClientProvider provider_local,
110  provider_remote;
111 
112  const pvd::PVDataCreatePtr create;
113 
114  WorkQueue queue;
115 
116  pvd::Mutex lock;
117 
118  bool running; // set after dbEvent is initialized and safe to use
119 
120  // a tuple of channel name and printed pvRequest (or Monitor)
121  typedef std::pair<std::string, std::string> channels_key_t;
122  // pvaLinkChannel dtor prunes dead entires
123  typedef std::map<channels_key_t, std::tr1::weak_ptr<pvaLinkChannel> > channels_t;
124  // Cache of active Channels (really about caching Monitor)
125  channels_t channels;
126 
127  pvaGlobal_t();
128  ~pvaGlobal_t();
129 };
130 extern pvaGlobal_t *pvaGlobal;
131 
132 struct pvaLinkChannel : public pvac::ClientChannel::MonitorCallback,
133  public pvac::ClientChannel::PutCallback,
134  public epicsThreadRunable,
135  public std::tr1::enable_shared_from_this<pvaLinkChannel>
136 {
137  const pvaGlobal_t::channels_key_t key; // tuple of (channelName, pvRequest key)
138  const pvd::PVStructure::const_shared_pointer pvRequest; // used with monitor
139 
140  static size_t num_instances;
141 
142  pvd::Mutex lock;
143  epicsEvent run_done; // used by testing code
144 
145  pvac::ClientChannel chan;
146  pvac::Monitor op_mon;
147  pvac::Operation op_put;
148 
149  std::string providerName;
150  size_t num_disconnect, num_type_change;
151  bool connected;
152  bool connected_latched; // connection status at the run()
153  bool isatomic;
154  bool queued; // added to WorkQueue
155  bool debug; // set if any jlink::debug is set
156  std::tr1::shared_ptr<const void> previous_root;
157  typedef std::set<dbCommon*> after_put_t;
158  after_put_t after_put;
159 
160  struct LinkSort {
161  bool operator()(const pvaLink *L, const pvaLink *R) const;
162  };
163 
164  typedef std::set<pvaLink*, LinkSort> links_t;
165 
166  // list of currently attached links. maintained by pvaLink ctor/dtor
167  // TODO: sort by PHAS
168  links_t links;
169 
170  // set when 'links' is modified to trigger re-compute of record scan list
171  bool links_changed;
172 
173  pvaLinkChannel(const pvaGlobal_t::channels_key_t& key, const epics::pvData::PVStructure::const_shared_pointer &pvRequest);
174  virtual ~pvaLinkChannel();
175 
176  void open();
177  void put(bool force=false); // begin Put op.
178 
179  // pvac::ClientChanel::MonitorCallback
180  virtual void monitorEvent(const pvac::MonitorEvent& evt) OVERRIDE FINAL;
181 
182  // pvac::ClientChanel::PutCallback
183  virtual void putBuild(const epics::pvData::StructureConstPtr& build, pvac::ClientChannel::PutCallback::Args& args) OVERRIDE FINAL;
184  virtual void putDone(const pvac::PutEvent& evt) OVERRIDE FINAL;
185  struct AfterPut : public epicsThreadRunable {
186  std::tr1::weak_ptr<pvaLinkChannel> lc;
187  virtual ~AfterPut() {}
188  virtual void run() OVERRIDE FINAL;
189  };
190  std::tr1::shared_ptr<AfterPut> AP;
191 private:
192  virtual void run() OVERRIDE FINAL;
193  void run_dbProcess(size_t idx); // idx is index in scan_records
194 
195  // ==== Treat remaining as local to run()
196 
197  std::vector<dbCommon*> scan_records;
198  std::vector<bool> scan_check_passive;
199  std::vector<epics::pvData::BitSet> scan_changed;
200 
201  DBManyLock atomic_lock;
202 };
203 
204 struct pvaLink : public pvaLinkConfig
205 {
206  static size_t num_instances;
207 
208  bool alive; // attempt to catch some use after free
209  dbfType type;
210 
211  DBLINK * plink; // may be NULL
212 
213  std::tr1::shared_ptr<pvaLinkChannel> lchan;
214 
215  bool used_scratch, used_queue;
216  pvd::shared_vector<const void> put_scratch, put_queue;
217 
218  // cached fields from channel op_mon
219  // updated in onTypeChange()
220  epics::pvData::PVField::const_shared_pointer fld_value;
221  epics::pvData::PVScalar::const_shared_pointer fld_severity,
222  fld_seconds,
223  fld_nanoseconds;
224  epics::pvData::PVStructure::const_shared_pointer fld_display,
225  fld_control,
226  fld_valueAlarm;
227  epics::pvData::BitSet proc_changed;
228 
229  // cached snapshot of alarm and timestamp
230  // captured in pvaGetValue().
231  // we choose not to ensure consistency with display/control meta-data
232  epicsTimeStamp snap_time;
233  short snap_severity;
234 
235  pvaLink();
236  virtual ~pvaLink();
237 
238  // returns pvRequest to be used with monitor
239  pvd::PVStructurePtr makeRequest();
240 
241  bool valid() const;
242 
243  // fetch a sub-sub-field of the top monitored field.
244  pvd::PVField::const_shared_pointer getSubField(const char *name);
245 
246  void onDisconnect();
247  void onTypeChange();
248 };
249 
250 
251 } // namespace pvalink
252 
253 #endif // PVALINK_H