RCFProto
 All Classes Functions Typedefs
Future.hpp
1 
2 //******************************************************************************
3 // RCF - Remote Call Framework
4 //
5 // Copyright (c) 2005 - 2013, Delta V Software. All rights reserved.
6 // http://www.deltavsoft.com
7 //
8 // RCF is distributed under dual licenses - closed source or GPL.
9 // Consult your particular license for conditions of use.
10 //
11 // If you have not purchased a commercial license, you are using RCF
12 // under GPL terms.
13 //
14 // Version: 2.0
15 // Contact: support <at> deltavsoft.com
16 //
17 //******************************************************************************
18 
19 #ifndef INCLUDE_RCF_FUTURE_HPP
20 #define INCLUDE_RCF_FUTURE_HPP
21 
22 #include <RCF/ClientStub.hpp>
23 #include <RCF/Marshal.hpp>
24 
25 namespace RCF {
26 
27  class I_Future
28  {
29  public:
30  virtual ~I_Future() {}
31  virtual void setClientStub(ClientStub *pClientStub) = 0;
32  };
33 
34  template<typename T>
35  class FutureImpl;
36 
37  template<typename T>
38  class Future
39  {
40  public:
41  Future() : mStatePtr(new State())
42  {}
43 
44  Future(T *pt) : mStatePtr( new State(pt))
45  {}
46 
47  Future(T *pt, ClientStub *pClientStub) : mStatePtr( new State(pt))
48  {
49  pClientStub->enrol(mStatePtr.get());
50  }
51 
52  Future(const T &t) : mStatePtr( new State(t))
53  {}
54 
55  operator T&()
56  {
57  return mStatePtr->operator T&();
58  }
59 
60  T& operator*()
61  {
62  return mStatePtr->operator T&();
63  }
64 
65  Future &operator=(const Future &rhs)
66  {
67  mStatePtr = rhs.mStatePtr;
68  return *this;
69  }
70 
71  Future &operator=(const FutureImpl<T> &rhs)
72  {
73  rhs.assignTo(*this);
74  return *this;
75  }
76 
77  Future(const FutureImpl<T> &rhs) : mStatePtr( new State())
78  {
79  rhs.assignTo(*this);
80  }
81 
82  bool ready()
83  {
84  return mStatePtr->ready();
85  }
86 
87  void wait(boost::uint32_t timeoutMs = 0)
88  {
89  mStatePtr->wait(timeoutMs);
90  }
91 
92  void cancel()
93  {
94  mStatePtr->cancel();
95  }
96 
97  void clear()
98  {
99  mStatePtr->clear();
100  }
101 
102  ClientStub & getClientStub()
103  {
104  return mStatePtr->getClientStub();
105  }
106 
107  std::auto_ptr<Exception> getAsyncException()
108  {
109  return mStatePtr->getClientStub().getAsyncException();
110  }
111 
112  private:
113 
114  template<typename U>
115  friend class FutureImpl;
116 
117  class State : public I_Future, boost::noncopyable
118  {
119  public:
120  State() :
121  mpt(),
122  mtPtr( new T() ),
123  mpClientStub()
124  {}
125 
126  State(T *pt) :
127  mpt(pt),
128  mpClientStub()
129  {}
130 
131  State(const T &t) :
132  mpt(),
133  mtPtr( new T(t) ),
134  mpClientStub()
135  {}
136 
137  ~State()
138  {
139  RCF_DTOR_BEGIN
140  unregisterFromCandidates();
141  RCF_DTOR_END
142  }
143 
144  operator T&()
145  {
146  // If a call has been made, check that it has completed, and
147  // that there was no exception.
148 
149  if (mpClientStub)
150  {
151  if (!mpClientStub->ready())
152  {
153  mpClientStub->waitForReady();
154  }
155 
156  std::auto_ptr<Exception> ePtr =
157  mpClientStub->getAsyncException();
158 
159  if (ePtr.get())
160  {
161  ePtr->throwSelf();
162  }
163  }
164 
165  T *pt = mpt ? mpt : mtPtr.get();
166  {
167  Lock lock(gCandidatesMutex());
168  gCandidates().add(pt, this);
169  }
170 
171  return *pt;
172  }
173 
174  void setClientStub(ClientStub *pClientStub)
175  {
176  mpClientStub = pClientStub;
177  }
178 
179  void setClientStub(ClientStub *pClientStub, T * pt)
180  {
181  unregisterFromCandidates();
182 
183  mpClientStub = pClientStub;
184  mpt = pt;
185  mtPtr.reset();
186  }
187 
188  private:
189 
190  T * mpt;
191  boost::scoped_ptr<T> mtPtr;
192  RCF::ClientStub * mpClientStub;
193 
194  public:
195 
196  bool ready()
197  {
198  return mpClientStub->ready();
199  }
200 
201  void wait(boost::uint32_t timeoutMs = 0)
202  {
203  mpClientStub->waitForReady(timeoutMs);
204  }
205 
206  void cancel()
207  {
208  mpClientStub->cancel();
209  }
210 
211  ClientStub & getClientStub()
212  {
213  return *mpClientStub;
214  }
215 
216  void unregisterFromCandidates()
217  {
218  T *pt = mpt ? mpt : mtPtr.get();
219  Lock lock(gCandidatesMutex());
220  I_Future * pFuture = gCandidates().find(pt);
221  if (pFuture)
222  {
223  gCandidates().erase(pt);
224  }
225  }
226 
227  };
228 
229  boost::shared_ptr<State> mStatePtr;
230  };
231 
232  class LogEntryExit
233  {
234  public:
235  LogEntryExit(ClientStub & clientStub) :
236  mClientStub(clientStub),
237  mMsg(clientStub.mCurrentCallDesc)
238  {
239  if (mClientStub.mCallInProgress)
240  {
241  RCF_THROW(_RcfError_ConcurrentCalls());
242  }
243 
244  mClientStub.mCallInProgress = true;
245  RCF_LOG_2() << "RcfClient - begin remote call. " << mMsg;
246  }
247 
248  ~LogEntryExit()
249  {
250  if (!mClientStub.getAsync())
251  {
252  RCF_LOG_2() << "RcfClient - end remote call. " << mMsg;
253  mClientStub.mCallInProgress = false;
254  }
255  }
256 
257  private:
258  ClientStub & mClientStub;
259  const std::string & mMsg;
260  };
261 
262  // Base class for FutureImpl<>.
263  class RCF_EXPORT FutureImplBase
264  {
265  protected:
266 
267  FutureImplBase(
268  ClientStub &clientStub,
269  const std::string & interfaceName,
270  int fnId,
271  RemoteCallSemantics rcs,
272  const char * szFunc,
273  const char * szArity);
274 
275  FutureImplBase(const FutureImplBase& rhs);
276  FutureImplBase &operator=(const FutureImplBase &rhs);
277 
278  void call() const;
279  void callSync() const;
280  void callAsync() const;
281 
282  ClientStub * mpClientStub;
283  int mFnId;
284  RemoteCallSemantics mRcs;
285  const char * mSzFunc;
286  const char * mSzArity;
287  mutable bool mOwn;
288  };
289 
290  template<typename T>
291  class FutureImpl : public FutureImplBase
292  {
293  public:
294  FutureImpl(
295  T &t,
296  ClientStub &clientStub,
297  const std::string & interfaceName,
298  int fnId,
299  RemoteCallSemantics rcs,
300  const char * szFunc = "",
301  const char * szArity = "") :
302  FutureImplBase(clientStub, interfaceName, fnId, rcs, szFunc, szArity),
303  mpT(&t)
304  {
305  }
306 
307  FutureImpl(const FutureImpl &rhs) :
308  FutureImplBase(rhs),
309  mpT(rhs.mpT)
310  {
311  }
312 
313  FutureImpl &operator=(const FutureImpl &rhs)
314  {
315  FutureImplBase::operator=(rhs);
316  mpT = rhs.mpT;
317  return *this;
318  }
319 
320  T get()
321  {
322  return operator T();
323  }
324 
325  // Conversion to T kicks off a sync call.
326  operator T() const
327  {
328  mOwn = false;
329  call();
330  T t = *mpT;
331  mpClientStub->clearParameters();
332  return t;
333  }
334 
335  // Assignment to Future<> kicks off an async call.
336  void assignTo(Future<T> &future) const
337  {
338  mOwn = false;
339  mpClientStub->setAsync(true);
340  future.mStatePtr->setClientStub(mpClientStub, mpT);
341  call();
342  }
343 
344  // Void or ignored return value, kicks off a sync call.
345  ~FutureImpl() RCF_DTOR_THROWS
346  {
347  if(mOwn)
348  {
349  call();
350 
351  if (!mpClientStub->getAsync())
352  {
353  mpClientStub->clearParameters();
354  }
355  }
356  }
357 
358  private:
359  T * mpT;
360  };
361 
362  template<typename T, typename U>
363  bool operator==(const FutureImpl<T> & fi, const U & u)
364  {
365  return fi.operator T() == u;
366  }
367 
368  template<typename T, typename U>
369  bool operator==(const U & u, const FutureImpl<T> & fi)
370  {
371  return u == fi.operator T();
372  }
373 
374  template<typename T>
375  RCF::MemOstream & operator<<(RCF::MemOstream & os, const FutureImpl<T> & fi)
376  {
377  return os << fi.operator T();
378  }
379 
380 
381 }
382 
383 #endif // INCLUDE_RCF_FUTURE_HPP