This is Unofficial EPICS BASE Doxygen Site
clientMonitor.cpp
Go to the documentation of this file.
1 /*
2  * Copyright information and license terms for this software can be
3  * found in the file LICENSE that is included with the distribution
4  */
5 
6 #include <epicsMutex.h>
7 #include <epicsGuard.h>
8 #include <epicsEvent.h>
9 #include <epicsThread.h>
10 
11 #include <pv/current_function.h>
12 #include <pv/pvData.h>
13 #include <pv/bitSet.h>
14 #include <pv/reftrack.h>
15 
16 #define epicsExportSharedSymbols
17 #include "pv/logger.h"
18 #include "clientpvt.h"
19 #include "pv/pvAccess.h"
20 
21 namespace pvac {
24 
26  public pva::MonitorRequester,
27  public pvac::detail::wrapped_shared_from_this<Monitor::Impl>
28 {
29  pva::Channel::shared_pointer chan;
30  operation_type::shared_pointer op;
32 
33  ClientChannel::MonitorCallback *cb;
34  MonitorEvent event;
35 
36  pva::MonitorElement::Ref last;
37 
38  static size_t num_instances;
39 
40  Impl(ClientChannel::MonitorCallback* cb)
41  :started(false)
42  ,done(false)
43  ,seenEmpty(false)
44  ,cb(cb)
45  {REFTRACE_INCREMENT(num_instances);}
46  virtual ~Impl() {
47  CallbackGuard G(*this);
48  cb = 0;
49  G.wait(); // paranoia
50  REFTRACE_DECREMENT(num_instances);
51  }
52 
54  {
55  ClientChannel::MonitorCallback *cb=this->cb;
56  if(!cb) return;
57 
58  event.event = evt;
59 
61  this->cb = 0; // last event
62 
63  try {
64  CallbackUse U(G);
65  cb->monitorEvent(event);
66  return;
67  }catch(std::exception& e){
68  if(!this->cb || evt==MonitorEvent::Fail) {
69  LOG(pva::logLevelError, "Unhandled exception in ClientChannel::MonitorCallback::monitorEvent(): %s", e.what());
70  return;
71  } else {
72  event.event = MonitorEvent::Fail;
73  event.message = e.what();
74  }
75  }
76  // continues error handling
77  try {
78  CallbackUse U(G);
79  cb->monitorEvent(event);
80  return;
81  }catch(std::exception& e){
82  LOG(pva::logLevelError, "Unhandled exception following exception in ClientChannel::MonitorCallback::monitorEvent(): %s", e.what());
83  }
84  }
85 
86  // called automatically via wrapped_shared_from_this
87  void cancel()
88  {
89  operation_type::shared_pointer temp;
90  {
91  // keepalive for safety in case callback wants to destroy us
92  std::tr1::shared_ptr<Monitor::Impl> keepalive(internal_shared_from_this());
93 
94  CallbackGuard G(*this);
95 
96  last.reset();
97 
98  if(started && op) {
99  op->stop();
100  started = false;
101  }
102  temp.swap(op);
103 
105  G.wait();
106  }
107  if(temp)
108  temp->destroy();
109  }
110 
111  virtual std::string getRequesterName() OVERRIDE FINAL
112  {
113  Guard G(mutex);
114  return chan ? chan->getRequesterName() : "<dead>";
115  }
116 
117 
118  virtual void monitorConnect(pvd::Status const & status,
119  pva::MonitorPtr const & operation,
121  {
122  std::tr1::shared_ptr<Monitor::Impl> keepalive(internal_shared_from_this());
123  CallbackGuard G(*this);
124  if(!cb || started || done) return;
125 
126  if(!status.isOK()) {
127  event.message = status.getMessage();
128  } else {
129  event.message.clear();
130  }
131  if(!status.isSuccess()) {
132  callEvent(G);
133 
134  } else {
135  pvd::Status sts(operation->start());
136  if(sts.isSuccess()) {
137  started = true;
138  /* storing raw pointer to operation, which is expected
139  * to outlive our 'op'.
140  */
141  last.attach(operation);
142  } else {
143  event.message = sts.getMessage();
144  callEvent(G);
145  }
146  }
147  }
148 
149 
150  virtual void channelDisconnect(bool destroy) OVERRIDE FINAL
151  {
152  std::tr1::shared_ptr<Monitor::Impl> keepalive(internal_shared_from_this());
153  CallbackGuard G(*this);
154  if(!cb || done) return;
155  event.message = "Disconnect";
156  started = false;
158  }
159 
160  virtual void monitorEvent(pva::MonitorPtr const & monitor) OVERRIDE FINAL
161  {
162  std::tr1::shared_ptr<Monitor::Impl> keepalive(internal_shared_from_this());
163  CallbackGuard G(*this);
164  if(!cb || done) return;
165  event.message.clear();
166 
168  }
169 
170  virtual void unlisten(pva::MonitorPtr const & monitor) OVERRIDE FINAL
171  {
172  std::tr1::shared_ptr<Monitor::Impl> keepalive(internal_shared_from_this());
173  CallbackGuard G(*this);
174  if(!cb || done) return;
175  done = true;
176 
177  if(seenEmpty)
179  // else // wait until final poll()
180  }
181 };
182 
184 
185 Monitor::Monitor(const std::tr1::shared_ptr<Impl>& impl)
186  :impl(impl)
187 {}
188 
190 
191 
192 std::string Monitor::name() const
193 {
194  return impl ? impl->chan->getChannelName() : "<NULL>";
195 }
196 
198 {
199  if(impl) impl->cancel();
200 }
201 
203 {
204  if(!impl) return false;
205  Guard G(impl->mutex);
206 
207  if(!impl->done && impl->op && impl->started && impl->last.next()) {
208  const epics::pvData::PVStructurePtr& ptr = impl->last->pvStructurePtr;
209  changed = *impl->last->changedBitSet;
210  overrun = *impl->last->overrunBitSet;
211 
212  /* copy the exposed PVStructure for two reasons.
213  * 1. Prevent accidental use of shared container after release()
214  * 2. Allows caller to cache results of getSubField() until root.get() changes.
215  */
216  if(!root || (void*)root->getField().get()!=(void*)ptr->getField().get()) {
217  // initial connection, or new type
218  root = pvd::getPVDataCreate()->createPVStructure(ptr); // also calls copyUnchecked()
219  } else {
220  // same type
221  const_cast<pvd::PVStructure&>(*root).copyUnchecked(*ptr, changed);
222  }
223 
224  impl->seenEmpty = false;
225  } else {
226  changed.clear();
227  overrun.clear();
228  impl->seenEmpty = true;
229  }
230  return !impl->seenEmpty;
231 }
232 
233 bool Monitor::complete() const
234 {
235  if(!impl) return true;
236  Guard G(impl->mutex);
237  return impl->done && impl->seenEmpty;
238 }
239 
240 Monitor
242  epics::pvData::PVStructure::const_shared_pointer pvRequest)
243 {
244  if(!impl) throw std::logic_error("Dead Channel");
245  if(!pvRequest)
246  pvRequest = pvd::createRequest("field()");
247 
248  std::tr1::shared_ptr<Monitor::Impl> ret(Monitor::Impl::build(cb));
249  ret->chan = getChannel();
250 
251  {
252  Guard G(ret->mutex);
253  ret->op = ret->chan->createMonitor(ret->internal_shared_from_this(),
255  }
256 
257  return Monitor(ret);
258 }
259 
260 ::std::ostream& operator<<(::std::ostream& strm, const Monitor& op)
261 {
262  if(op.impl) {
263  strm << "Monitor("
264  "\"" << op.impl->chan->getChannelName() <<"\", "
265  "\"" << op.impl->chan->getProvider()->getProviderName() <<"\", "
266  "connected="<<(op.impl->chan->isConnected()?"true":"false")
267  <<"\")";
268  } else {
269  strm << "Monitor()";
270  }
271  return strm;
272 }
273 
274 namespace detail {
275 
277 {
278  epics::registerRefCounter("pvac::Monitor::Impl", &Monitor::Impl::num_instances);
279 }
280 
281 }
282 
283 }//namespace pvac
BitSet & clear(uint32 bitIndex)
Definition: bitSet.cpp:112
pvd::Status status
virtual void monitorConnect(pvd::Status const &status, pva::MonitorPtr const &operation, pvd::StructureConstPtr const &structure) OVERRIDE FINAL
ClientChannel::MonitorCallback * cb
subscription interrupted due to loss of communication
Definition: client.h:189
std::tr1::shared_ptr< const Structure > StructureConstPtr
Definition: pvIntrospect.h:162
virtual std::string getRequesterName() OVERRIDE FINAL
pva::Channel::shared_pointer chan
epics::pvData::BitSet overrun
Definition: client.h:161
Handle for monitor subscription.
Definition: client.h:117
Impl(ClientChannel::MonitorCallback *cb)
#define OVERRIDE
Definition: pvAccess.h:55
const std::string & getMessage() const
Definition: status.h:80
PVStructure::shared_pointer createRequest(std::string const &request)
const std::tr1::weak_ptr< Process2PutProxy > operation
Definition: pvAccess.cpp:69
void registerRefTrackMonitor()
static std::tr1::shared_ptr< Monitor::Impl > build()
Definition: clientpvt.h:62
subscription ends in cancellation
Definition: client.h:188
void copyUnchecked(const PVStructure &from)
epics::pvData::PVStructure::const_shared_pointer root
Definition: client.h:160
#define LOG(level, format,...)
Definition: logger.h:48
void cancel()
Immediate cancellation.
std::tr1::shared_ptr< Monitor::Impl > internal_shared_from_this()
Definition: clientpvt.h:44
APIs for the epicsMutex mutual exclusion semaphore.
pva::MonitorElement::Ref last
bool isSuccess() const
Definition: status.h:103
virtual void channelDisconnect(bool destroy) OVERRIDE FINAL
friend epicsShareFunc::std::ostream & operator<<(::std::ostream &strm, const Monitor &op)
Data interface for a structure,.
Definition: pvData.h:712
void callEvent(CallbackGuard &G, MonitorEvent::event_t evt=MonitorEvent::Fail)
void registerRefCounter(const char *name, const size_t *counter)
Definition: reftrack.cpp:59
APIs for the epicsEvent binary semaphore.
std::tr1::shared_ptr< PVStructure > PVStructurePtr
Definition: pvData.h:87
std::string name() const
Channel name.
Callback implemented by monitor clients.
Definition: pvAccess.h:249
bool isOK() const
Definition: status.h:95
virtual void monitorEvent(pva::MonitorPtr const &monitor) OVERRIDE FINAL
ChannelPut::shared_pointer op
Definition: pvAccess.cpp:132
Data queue not empty. Call Monitor::poll()
Definition: client.h:190
Monitor event notification.
Definition: client.h:403
epics::pvData::BitSet changed
Definition: client.h:161
shared_ptr< T > const_pointer_cast(shared_ptr< U > const &r) BOOST_NOEXCEPT
Definition: shared_ptr.hpp:798
C++ and C descriptions for a thread.
virtual void unlisten(pva::MonitorPtr const &monitor) OVERRIDE FINAL
#define false
Definition: flexdef.h:85
FORCE_INLINE const PVDataCreatePtr & getPVDataCreate()
Definition: pvData.h:1648
std::tr1::shared_ptr< Monitor > MonitorPtr
Definition: monitor.h:44
#define FINAL
Definition: pvAccess.h:48
bool complete() const
See Client API API.
Definition: client.cpp:30
subscription ends in an error
Definition: client.h:187
operation_type::shared_pointer op
Monitor monitor(MonitorCallback *cb, epics::pvData::PVStructure::const_shared_pointer pvRequest=epics::pvData::PVStructure::const_shared_pointer())