This is Unofficial EPICS BASE Doxygen Site
clientPut.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 {
24 
25 struct Putter : public pvac::detail::CallbackStorage,
27  public pvac::Operation::Impl,
29 {
30  const bool getcurrent;
31 
32  bool started; // whether the put() has actually been sent. After which point we can't safely re-try.
33  operation_type::shared_pointer op;
34  pvd::StructureConstPtr puttype;
35 
37  pvac::GetEvent event;
38 
39  static size_t num_instances;
40 
41  Putter(pvac::ClientChannel::PutCallback* cb, bool getcurrent) :getcurrent(getcurrent), started(false), cb(cb)
42  {REFTRACE_INCREMENT(num_instances);}
43  virtual ~Putter() {
44  CallbackGuard G(*this);
45  cb = 0;
46  G.wait(); // paranoia
47  REFTRACE_DECREMENT(num_instances);
48  }
49 
51  {
52  if(!cb) return;
53 
54  event.event = evt;
56  cb = 0;
57  CallbackUse U(G);
58  try {
59  C->putDone(event);
60  } catch(std::exception& e) {
61  LOG(pva::logLevelInfo, "Lost exception during putDone(): %s", e.what());
62  }
63  }
64 
65  virtual std::string name() const OVERRIDE FINAL
66  {
67  Guard G(mutex);
68  return op ? op->getChannel()->getChannelName() : "<dead>";
69  }
70 
71  // called automatically via wrapped_shared_from_this
72  virtual void cancel() OVERRIDE FINAL
73  {
74  // keepalive for safety in case callback wants to destroy us
75  std::tr1::shared_ptr<Putter> keepalive(internal_shared_from_this());
76  CallbackGuard G(*this);
77  if(started && op) op->cancel();
78  callEvent(G, pvac::GetEvent::Cancel);
79  G.wait();
80  }
81 
82  virtual std::string getRequesterName() OVERRIDE FINAL
83  {
84  Guard G(mutex);
85  return op ? op->getChannel()->getRequesterName() : "<dead>";
86  }
87 
88  virtual void channelPutConnect(
90  pva::ChannelPut::shared_pointer const & channelPut,
91  epics::pvData::Structure::const_shared_pointer const & structure) OVERRIDE FINAL
92  {
93  std::tr1::shared_ptr<Putter> keepalive(internal_shared_from_this());
94  CallbackGuard G(*this);
95  op = channelPut; // we may be called before createChannelPut() has returned.
96  puttype = structure;
97  if(started || !cb) return;
98 
99  if(!status.isOK()) {
100  event.message = status.getMessage();
101  } else {
102  event.message.clear();
103  }
104  if(!status.isSuccess()) {
105  callEvent(G);
106 
107  } else if(getcurrent) {
108  // fetch a previous value first
109  op->get();
110  } else {
111  // build Put value immediately
113  pvd::BitSet::shared_pointer tosend(new pvd::BitSet);
114  pvac::ClientChannel::PutCallback::Args args(*tosend, empty);
115  // args.previous = 0; // implied
116  doPut(G, args, channelPut, tosend);
117  }
118  }
119 
120  virtual void channelDisconnect(bool destroy) OVERRIDE FINAL
121  {
122  CallbackGuard G(*this);
123  event.message = "Disconnect";
124 
125  callEvent(G);
126  }
127 
128  void doPut(CallbackGuard& G,
130  pva::ChannelPut::shared_pointer const & channelPut,
131  const pvd::BitSet::shared_pointer& tosend)
132  {
133  try {
135  CallbackUse U(G);
136  C->putBuild(puttype, args);
137  if(!args.root)
138  throw std::logic_error("No put value provided");
139  else if(*args.root->getStructure()!=*puttype)
140  throw std::logic_error("Provided put value with wrong type");
141  }catch(std::exception& e){
142  if(cb) {
143  event.message = e.what();
144  callEvent(G);
145  } else {
146  LOG(pva::logLevelInfo, "Lost exception in %s: %s", CURRENT_FUNCTION, e.what());
147  }
148  }
149  // check cb again after UnGuard
150  if(cb) {
151  started = true;
152  channelPut->put(std::tr1::const_pointer_cast<pvd::PVStructure>(args.root), tosend);
153  }
154  }
155 
156  virtual void getDone(
157  const epics::pvData::Status& status,
158  pva::ChannelPut::shared_pointer const & channelPut,
159  epics::pvData::PVStructure::shared_pointer const & pvStructure,
160  epics::pvData::BitSet::shared_pointer const & bitSet) OVERRIDE FINAL
161  {
162  std::tr1::shared_ptr<Putter> keepalive(internal_shared_from_this());
163  CallbackGuard G(*this);
164  if(!cb) return;
165 
166  if(!status.isOK()) {
167  event.message = status.getMessage();
168 
169  callEvent(G, pvac::GetEvent::Fail);
170 
171  } else {
172  pvd::BitSet::shared_pointer tosend(new pvd::BitSet);
173  pvac::ClientChannel::PutCallback::Args args(*tosend, *bitSet);
174  args.previous = pvStructure;
175  doPut(G, args, channelPut, tosend);
176  }
177  }
178 
179  virtual void putDone(
180  const epics::pvData::Status& status,
181  pva::ChannelPut::shared_pointer const & channelPut) OVERRIDE FINAL
182  {
183  std::tr1::shared_ptr<Putter> keepalive(internal_shared_from_this());
184  CallbackGuard G(*this);
185  if(!cb) return;
186 
187  if(!status.isOK()) {
188  event.message = status.getMessage();
189  } else {
190  event.message.clear();
191  }
192 
193  callEvent(G, status.isSuccess()? pvac::GetEvent::Success : pvac::GetEvent::Fail);
194  }
195 
196  virtual void show(std::ostream &strm) const OVERRIDE FINAL
197  {
198  strm << "Operation(Put"
199  "\"" << name() <<"\""
200  ")";
201  }
202 };
203 
204 size_t Putter::num_instances;
205 
206 } //namespace
207 
208 namespace pvac {
209 
210 Operation
212  epics::pvData::PVStructure::const_shared_pointer pvRequest,
213  bool getprevious)
214 {
215  if(!impl) throw std::logic_error("Dead Channel");
216  if(!pvRequest)
217  pvRequest = pvd::createRequest("field()");
218 
219  std::tr1::shared_ptr<Putter> ret(Putter::build(cb, getprevious));
220 
221  {
222  Guard G(ret->mutex);
223  ret->op = getChannel()->createChannelPut(ret->internal_shared_from_this(),
225  }
226 
227  return Operation(ret);
228 
229 }
230 
231 namespace detail {
232 
234 {
235  epics::registerRefCounter("pvac::Putter", &Putter::num_instances);
236 }
237 
238 }
239 
240 }//namespace pvac
epics::pvData::BitSetPtr empty
Definition: pvAccess.cpp:135
std::tr1::shared_ptr< detail::SharedPut > put
pvd::Status status
Information on get/rpc completion.
Definition: client.h:99
virtual void putDone(const PutEvent &evt)=0
Put operation is complete.
callbacks for put()
Definition: client.h:358
std::tr1::shared_ptr< const Structure > StructureConstPtr
Definition: pvIntrospect.h:162
virtual std::string name() const =0
A vector of bits.
Definition: bitSet.h:56
#define OVERRIDE
Definition: pvAccess.h:55
const std::string & getMessage() const
Definition: status.h:80
PVStructure::shared_pointer createRequest(std::string const &request)
Handle for in-progress get/put/rpc operation.
Definition: client.h:50
void registerRefTrackPut()
Definition: clientPut.cpp:233
virtual void getDone(const epics::pvData::Status &status, ChannelPut::shared_pointer const &channelPut, epics::pvData::PVStructure::shared_pointer const &pvStructure, epics::pvData::BitSet::shared_pointer const &bitSet)=0
virtual void show(std::ostream &) const =0
#define LOG(level, format,...)
Definition: logger.h:48
virtual void channelDisconnect(bool destroy)
Definition: pvAccess.h:198
std::tr1::shared_ptr< Derived > internal_shared_from_this()
Definition: clientpvt.h:44
epics::pvData::PVStructure::const_shared_pointer root
Callee must fill this in with an instance of the Structure passed as the &#39;build&#39; argument.
Definition: client.h:363
epicsMutex mutex
Definition: pvAccess.cpp:71
APIs for the epicsMutex mutual exclusion semaphore.
virtual void cancel()=0
bool isSuccess() const
Definition: status.h:103
virtual void channelPutConnect(const epics::pvData::Status &status, ChannelPut::shared_pointer const &channelPut, epics::pvData::Structure::const_shared_pointer const &structure)=0
Data interface for a structure,.
Definition: pvData.h:712
void registerRefCounter(const char *name, const size_t *counter)
Definition: reftrack.cpp:59
request cancelled before completion
Definition: client.h:92
APIs for the epicsEvent binary semaphore.
virtual void putBuild(const epics::pvData::StructureConstPtr &build, Args &args)=0
request ends in failure. Check message
Definition: client.h:91
bool isOK() const
Definition: status.h:95
epics::pvData::PVStructure::const_shared_pointer previous
Definition: client.h:371
ChannelPut::shared_pointer op
Definition: pvAccess.cpp:132
#define CURRENT_FUNCTION
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.
epicsTimeStamp started
Definition: epicsUnitTest.c:52
It worked!
Definition: client.h:93
#define FINAL
Definition: pvAccess.h:48
See Client API API.
Definition: client.cpp:30
virtual void putDone(const epics::pvData::Status &status, ChannelPut::shared_pointer const &channelPut)=0