pvAccessCPP  7.1.5
sharedstate.h
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 #ifndef PV_SHAREDSTATE_H
6 #define PV_SHAREDSTATE_H
7 
8 #include <string>
9 #include <list>
10 
11 #include <shareLib.h>
12 #include <pv/sharedPtr.h>
13 #include <pv/noDefaultMethods.h>
14 #include <pv/bitSet.h>
15 #include <pv/createRequest.h>
16 
17 #include <pva/server.h>
18 
19 namespace epics{namespace pvData{
20 class Structure;
21 class PVStructure;
22 class BitSet;
23 class Status;
24 }} // epics::pvData
25 namespace epics{namespace pvAccess{
26 class ChannelProvider;
27 class Channel;
28 class ChannelRequester;
29 struct ChannelBaseRequester;
30 class GetFieldRequester;
31 void providerRegInit(void*);
32 }} // epics::pvAccess
33 
34 namespace pvas {
35 
36 namespace detail {
37 struct SharedChannel;
38 struct SharedMonitorFIFO;
39 struct SharedPut;
40 struct SharedRPC;
41 }
42 
43 struct Operation;
44 
45 /** @addtogroup pvas
46  * @{
47  */
48 
49 /** A Shared State Process Variable (PV)
50  *
51  * "Shared" in the sense that all clients/subscribers interact with the
52  * same PVStructure (excluding the RPC operation).
53  *
54  * @warning For the purposes of locking, this class is an Operation.
55  * eg. no locks may be held when calling post(), open(), close(), or connect().
56  * @ref provider_roles_requester_locking
57  *
58  * This class contains a cached PVStructure, which is updated by post(),
59  * also a list of subscribing clients and in-progress network Operations.
60  *
61  * On construction a SharedPV is in a "disconnected" state.
62  * It has no associated PVStructure (or Structure). No type.
63  * A type is associated via the open() method.
64  * After it has been open()'d. Calls to post() may be made.
65  * Calling close() will close all currently opened client channels.
66  *
67  * Client channels, and operations on them, may be initiated at any time (via connect()).
68  * However, operations other than RPC will not proceed until open() is called.
69  *
70  * @note A SharedPV does not have a name. Name(s) are associated with a SharedPV
71  * By a Provider (StaticProvider, DynamicProvider, or any epics::pvAccess::ChannelProvider).
72  * These channel names may be seen via connect()
73  *
74  * @see @ref pvas_sharedptr
75  */
76 class epicsShareClass SharedPV
77  : public pvas::StaticProvider::ChannelBuilder
78 {
79  friend struct detail::SharedChannel;
80  friend struct detail::SharedMonitorFIFO;
81  friend struct detail::SharedPut;
82  friend struct detail::SharedRPC;
83 public:
84  POINTER_DEFINITIONS(SharedPV);
85  struct epicsShareClass Config {
86  bool dropEmptyUpdates; //!< default true. Drop updates which don't include an field values.
87  epics::pvData::PVRequestMapper::mode_t mapperMode; //!< default Mask. @see epics::pvData::PVRequestMapper::mode_t
88  Config();
89  };
90 
91  /** Callbacks associated with a SharedPV.
92  *
93  * @note For the purposes of locking, this class is an Requester (see @ref provider_roles_requester_locking)
94  */
95  struct epicsShareClass Handler {
96  POINTER_DEFINITIONS(Handler);
97  virtual ~Handler();
98  virtual void onFirstConnect(const SharedPV::shared_pointer& pv) {}
99  //! Called when the last client disconnects. May close()
100  virtual void onLastDisconnect(const SharedPV::shared_pointer& pv) {}
101  //! Client requests Put
102  virtual void onPut(const SharedPV::shared_pointer& pv, Operation& op);
103  //! Client requests RPC
104  virtual void onRPC(const SharedPV::shared_pointer& pv, Operation& op);
105  };
106 
107  /** Allocate a new PV in the closed state.
108  * @param handler Our callbacks. May be NULL. Stored internally as a shared_ptr<>
109  * @param conf Optional. Extra configuration. If !NULL, will be modified to reflect configuration actually used.
110  * @post In the closed state
111  */
112  static shared_pointer build(const std::tr1::shared_ptr<Handler>& handler, Config* conf=0);
113  //! A SharedPV which fails all Put and RPC operations. In closed state.
114  static shared_pointer buildReadOnly(Config* conf=0);
115  //! A SharedPV which accepts all Put operations, and fails all RPC operations. In closed state.
116  static shared_pointer buildMailbox(Config* conf=0);
117 private:
118  explicit SharedPV(const std::tr1::shared_ptr<Handler>& handler, Config* conf);
119 public:
120  virtual ~SharedPV();
121 
122  //! Replace Handler given with ctor
123  void setHandler(const std::tr1::shared_ptr<Handler>& handler);
124  Handler::shared_pointer getHandler() const;
125 
126  //! test open-ness. cf. open() and close()
127  bool isOpen() const;
128 
129  //! Shorthand for @code open(value, pvd::BitSet().set(0)) @endcode
130  void open(const epics::pvData::PVStructure& value);
131 
132  //! Begin allowing clients to connect.
133  //! @param value The initial value of this PV. (any pending Get/Monitor operation will complete with this)
134  //! @param valid Only these marked fields are considered to have non-default values.
135  //! @throws std::logic_error if not in the closed state.
136  //! @post In the opened state
137  //! @note Provider locking rules apply (@see provider_roles_requester_locking).
138  void open(const epics::pvData::PVStructure& value, const epics::pvData::BitSet& valid);
139 
140  //! Shorthand for @code open(*pvd::getPVDataCreate()->createPVStructure(type), pvd::BitSet().set(0)) @endcode
141  void open(const epics::pvData::StructureConstPtr& type);
142 
143  //! Force any clients to disconnect, and prevent re-connection
144  //! @param destroy Indicate whether this close() is permanent for clients.
145  //! If destroy=false, the internal client list is retained, and these clients will see a subsequent open().
146  //! If destory=true, the internal client list is cleared.
147  //! @post In the closed state
148  //! @note Provider locking rules apply (@see provider_roles_requester_locking).
149  //!
150  //! close() is not final, even with destroy=true new clients may begin connecting, and open() may be called again.
151  //! A final close() should be performed after the removal from StaticProvider/DynamicProvider
152  //! which will prevent new clients.
153  inline void close(bool destroy=false) { realClose(destroy, true, 0); }
154 
155  //! Create a new container which may be used to prepare to call post().
156  //! This container will be owned exclusively by the caller.
157  std::tr1::shared_ptr<epics::pvData::PVStructure> build();
158 
159  //! Update the cached PVStructure in this SharedPV.
160  //! Only those fields marked as changed will be copied in.
161  //! Makes a light-weight copy.
162  //! @pre isOpen()==true
163  //! @throws std::logic_error if !isOpen()
164  //! @note Provider locking rules apply (@see provider_roles_requester_locking).
165  void post(const epics::pvData::PVStructure& value,
166  const epics::pvData::BitSet& changed);
167 
168  //! Update arguments with current value, which is the initial value from open() with accumulated post() calls.
169  void fetch(epics::pvData::PVStructure& value, epics::pvData::BitSet& valid);
170 
171  //! may call Handler::onFirstConnect()
172  //! @note Provider locking rules apply (@see provider_roles_requester_locking).
173  virtual std::tr1::shared_ptr<epics::pvAccess::Channel> connect(
174  const std::tr1::shared_ptr<epics::pvAccess::ChannelProvider>& provider,
175  const std::string& channelName,
176  const std::tr1::shared_ptr<epics::pvAccess::ChannelRequester>& requester) OVERRIDE FINAL;
177 
178  virtual void disconnect(bool destroy, const epics::pvAccess::ChannelProvider* provider) OVERRIDE FINAL;
179 
180  void setDebug(int lvl);
181  int isDebug() const;
182 
183 private:
184  void realClose(bool destroy, bool close, const epics::pvAccess::ChannelProvider* provider);
185 
186  friend void epics::pvAccess::providerRegInit(void*);
187  static size_t num_instances;
188 
189  weak_pointer internal_self; // const after build()
190 
191  const Config config;
192 
193  mutable epicsMutex mutex;
194 
195  std::tr1::shared_ptr<SharedPV::Handler> handler;
196 
197  typedef std::list<detail::SharedPut*> puts_t;
198  typedef std::list<detail::SharedRPC*> rpcs_t;
199  typedef std::list<detail::SharedMonitorFIFO*> monitors_t;
200  typedef std::list<std::tr1::weak_ptr<epics::pvAccess::GetFieldRequester> > getfields_t;
201  typedef std::list<detail::SharedChannel*> channels_t;
202 
203  std::tr1::shared_ptr<const epics::pvData::Structure> type;
204 
205  puts_t puts;
206  rpcs_t rpcs;
207  monitors_t monitors;
208  getfields_t getfields;
209  channels_t channels;
210 
211  std::tr1::shared_ptr<epics::pvData::PVStructure> current;
212  //! mask of fields which are considered to have non-default values.
213  //! Used for initial Monitor update and Get operations.
214  epics::pvData::BitSet valid;
215 
216  // whether onFirstConnect() has been, or is being, called.
217  // Set when the first getField, Put, or Monitor (but not RPC) is created.
218  // Cleared when the last Channel is destroyed.
219  bool notifiedConn;
220 
221  int debugLvl;
222 
223  EPICS_NOT_COPYABLE(SharedPV)
224 };
225 
226 //! An in-progress network operation (Put or RPC).
227 //! Use value(), changed() to see input data, and
228 //! call complete() when done handling.
229 struct epicsShareClass Operation {
230  POINTER_DEFINITIONS(Operation);
231  struct Impl;
232 private:
233  std::tr1::shared_ptr<Impl> impl;
234 
235  friend struct detail::SharedPut;
236  friend struct detail::SharedRPC;
237  explicit Operation(const std::tr1::shared_ptr<Impl> impl);
238 public:
239  Operation() {} //!< create empty op for later assignment
240 
241  //! pvRequest blob, may be used to modify handling.
242  const epics::pvData::PVStructure& pvRequest() const;
243  const epics::pvData::PVStructure& value() const; //!< Input data
244  //! Applies to value(). Which fields of input data are actual valid. Others should not be used.
245  const epics::pvData::BitSet& changed() const;
246  //! The name of the channel through which this request was made (eg. for logging purposes).
247  std::string channelName() const;
248 
249  //! Information about peer transport and authentication.
250  //! @returns May be NULL if no information is available
251  const epics::pvAccess::PeerInfo* peer() const;
252 
253  void complete(); //!< shorthand for successful completion w/o data (Put or RPC with void return)
254  //! Complete with success or error w/o data.
255  void complete(const epics::pvData::Status& sts);
256  //! Sucessful completion with data (RPC only)
257  void complete(const epics::pvData::PVStructure& value,
258  const epics::pvData::BitSet& changed);
259 
260  //! Send info message to client. Does not complete().
261  void info(const std::string&);
262  //! Send warning message to client. Does not complete().
263  void warn(const std::string&);
264 
265  int isDebug() const;
266 
267  // escape hatch. never NULL
268  std::tr1::shared_ptr<epics::pvAccess::Channel> getChannel();
269  // escape hatch. may be NULL
270  std::tr1::shared_ptr<epics::pvAccess::ChannelBaseRequester> getRequester();
271 
272  bool valid() const;
273 
274 #if __cplusplus>=201103L
275  explicit operator bool() const { return valid(); }
276 #else
277 private:
278  typedef bool (Operation::*bool_type)() const;
279 public:
280  operator bool_type() const { return valid() ? &Operation::valid : 0; }
281 #endif
282 };
283 
284 } // namespace pvas
285 
286 //! @}
287 
288 #endif // PV_SHAREDSTATE_H
A Shared State Process Variable (PV)
Definition: sharedstate.h:76
An in-progress network operation (Put or RPC).
Definition: sharedstate.h:229