Also use Objects as part of an operation but as a result don't generate Any operation...
[ACE_TAO.git] / ACE / ace / Future.cpp
blobc2ec6adfcc705d24c192c2de370e2f0fd224dd27
1 #ifndef ACE_FUTURE_CPP
2 #define ACE_FUTURE_CPP
4 #include "ace/Future.h"
6 #if !defined (ACE_LACKS_PRAGMA_ONCE)
7 # pragma once
8 #endif /* ACE_LACKS_PRAGMA_ONCE */
10 #if defined (ACE_HAS_THREADS)
12 # include "ace/Guard_T.h"
13 # include "ace/Recursive_Thread_Mutex.h"
15 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
17 ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Future_Holder)
18 ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Future_Observer)
19 ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Future_Rep)
20 ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Future)
22 template <class T>
23 ACE_Future_Holder<T>::ACE_Future_Holder (void)
27 template <class T>
28 ACE_Future_Holder<T>::ACE_Future_Holder (const ACE_Future<T> &item)
29 : item_ (item)
33 template <class T>
34 ACE_Future_Holder<T>::~ACE_Future_Holder (void)
38 template <class T>
39 ACE_Future_Observer<T>::ACE_Future_Observer (void)
43 template <class T>
44 ACE_Future_Observer<T>::~ACE_Future_Observer (void)
48 // Dump the state of an object.
50 template <class T> void
51 ACE_Future_Rep<T>::dump (void) const
53 #if defined (ACE_HAS_DUMP)
54 ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
55 ACELIB_DEBUG ((LM_DEBUG,
56 "ref_count_ = %d\n",
57 (int) this->ref_count_));
58 ACELIB_DEBUG ((LM_INFO,"value_:\n"));
59 if (this->value_)
60 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT (" (NON-NULL)\n")));
61 else
62 //FUZZ: disable check_for_NULL
63 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT (" (NULL)\n")));
64 //FUZZ: enable check_for_NULL
66 ACELIB_DEBUG ((LM_INFO,"value_ready_:\n"));
67 this->value_ready_.dump ();
68 ACELIB_DEBUG ((LM_INFO,"value_ready_mutex_:\n"));
69 this->value_ready_mutex_.dump ();
70 ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP));
71 #endif /* ACE_HAS_DUMP */
74 template <class T> ACE_Future_Rep<T> *
75 ACE_Future_Rep<T>::internal_create (void)
77 ACE_Future_Rep<T> *temp = 0;
78 ACE_NEW_RETURN (temp,
79 ACE_Future_Rep<T> (),
80 0);
81 return temp;
84 template <class T> ACE_Future_Rep<T> *
85 ACE_Future_Rep<T>::create (void)
87 // Yes set ref count to zero.
88 ACE_Future_Rep<T> *temp = internal_create ();
89 #if defined (ACE_NEW_THROWS_EXCEPTIONS)
90 if (temp == 0)
91 ACE_throw_bad_alloc;
92 #else
93 ACE_ASSERT (temp != 0);
94 #endif /* ACE_NEW_THROWS_EXCEPTIONS */
95 return temp;
99 template <class T> ACE_Future_Rep<T> *
100 ACE_Future_Rep<T>::attach (ACE_Future_Rep<T>*& rep)
102 ACE_ASSERT (rep != 0);
103 // Use value_ready_mutex_ for both condition and ref count management
104 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, r_mon, rep->value_ready_mutex_, 0);
105 ++rep->ref_count_;
106 return rep;
109 template <class T> void
110 ACE_Future_Rep<T>::detach (ACE_Future_Rep<T>*& rep)
112 ACE_ASSERT (rep != 0);
113 // Use value_ready_mutex_ for both condition and ref count management
114 ACE_GUARD (ACE_SYNCH_RECURSIVE_MUTEX, r_mon, rep->value_ready_mutex_);
116 if (rep->ref_count_-- == 0)
118 ACE_MT (r_mon.release ());
119 // We do not need the lock when deleting the representation.
120 // There should be no side effects from deleting rep and we don
121 // not want to release a deleted mutex.
122 delete rep;
126 template <class T> void
127 ACE_Future_Rep<T>::assign (ACE_Future_Rep<T>*& rep, ACE_Future_Rep<T>* new_rep)
129 ACE_ASSERT (rep != 0);
130 ACE_ASSERT (new_rep != 0);
131 // Use value_ready_mutex_ for both condition and ref count management
132 ACE_GUARD (ACE_SYNCH_RECURSIVE_MUTEX, r_mon, rep->value_ready_mutex_);
134 ACE_Future_Rep<T>* old = rep;
135 rep = new_rep;
137 // detached old last for exception safety
138 if (old->ref_count_-- == 0)
140 ACE_MT (r_mon.release ());
141 // We do not need the lock when deleting the representation.
142 // There should be no side effects from deleting rep and we don
143 // not want to release a deleted mutex.
144 delete old;
148 template <class T>
149 ACE_Future_Rep<T>::ACE_Future_Rep (void)
150 : value_ (0),
151 ref_count_ (0),
152 value_ready_ (value_ready_mutex_)
156 template <class T>
157 ACE_Future_Rep<T>::~ACE_Future_Rep (void)
159 delete this->value_;
162 template <class T> int
163 ACE_Future_Rep<T>::ready (void) const
165 return this->value_ != 0;
168 template <class T> int
169 ACE_Future_Rep<T>::set (const T &r,
170 ACE_Future<T> &caller)
172 // If the value is already produced, ignore it...
173 if (this->value_ == 0)
175 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX,
176 ace_mon,
177 this->value_ready_mutex_,
178 -1);
179 // Otherwise, create a new result value. Note the use of the
180 // Double-checked locking pattern to avoid multiple allocations.
182 if (this->value_ == 0) // Still no value, so proceed
184 ACE_NEW_RETURN (this->value_,
185 T (r),
186 -1);
188 // Remove and notify all subscribed observers.
189 typename OBSERVER_COLLECTION::iterator iterator =
190 this->observer_collection_.begin ();
192 typename OBSERVER_COLLECTION::iterator end =
193 this->observer_collection_.end ();
195 while (iterator != end)
197 OBSERVER *observer = *iterator++;
198 if (observer)
200 observer->update (caller);
204 // Signal all the waiting threads.
205 return this->value_ready_.broadcast ();
207 // Destructor releases the lock.
209 return 0;
212 template <class T> int
213 ACE_Future_Rep<T>::get (T &value,
214 ACE_Time_Value *tv) const
216 // If the value is already produced, return it.
217 if (this->value_ == 0)
219 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon,
220 this->value_ready_mutex_,
221 -1);
222 // If the value is not yet defined we must block until the
223 // producer writes to it.
225 while (this->value_ == 0)
226 // Perform a timed wait.
227 if (this->value_ready_.wait (tv) == -1)
228 return -1;
230 // Destructor releases the lock.
233 value = *this->value_;
234 return 0;
237 template <class T> int
238 ACE_Future_Rep<T>::attach (ACE_Future_Observer<T> *observer,
239 ACE_Future<T> &caller)
241 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->value_ready_mutex_, -1);
243 // Otherwise, create a new result value. Note the use of the
244 // Double-checked locking pattern to avoid corrupting the list.
246 int result = 1;
248 // If the value is already produced, then notify observer
249 if (this->value_ == 0)
250 result = this->observer_collection_.insert (observer);
251 else
252 observer->update (caller);
254 return result;
257 template <class T> int
258 ACE_Future_Rep<T>::detach (ACE_Future_Observer<T> *observer)
260 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->value_ready_mutex_, -1);
262 // Remove all occurrences of the specified observer from this
263 // objects hash map.
264 return this->observer_collection_.remove (observer);
267 template <class T>
268 ACE_Future_Rep<T>::operator T ()
270 // If the value is already produced, return it.
271 if (this->value_ == 0)
273 // Constructor of ace_mon acquires the mutex.
274 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->value_ready_mutex_, 0);
276 // If the value is not yet defined we must block until the
277 // producer writes to it.
279 // Wait ``forever.''
281 while (this->value_ == 0)
282 if (this->value_ready_.wait () == -1)
283 // What to do in this case since we've got to indicate
284 // failure somehow? Exceptions would be nice, but they're
285 // not portable...
286 return 0;
288 // Destructor releases the mutex
291 return *this->value_;
294 template <class T>
295 ACE_Future<T>::ACE_Future (void)
296 : future_rep_ (FUTURE_REP::create ())
300 template <class T>
301 ACE_Future<T>::ACE_Future (const ACE_Future<T> &r)
302 : future_rep_ (FUTURE_REP::attach (((ACE_Future<T> &) r).future_rep_))
306 template <class T>
307 ACE_Future<T>::ACE_Future (const T &r)
308 : future_rep_ (FUTURE_REP::create ())
310 this->future_rep_->set (r, *this);
313 template <class T>
314 ACE_Future<T>::~ACE_Future (void)
316 FUTURE_REP::detach (future_rep_);
319 template <class T> bool
320 ACE_Future<T>::operator== (const ACE_Future<T> &r) const
322 return r.future_rep_ == this->future_rep_;
325 template <class T> bool
326 ACE_Future<T>::operator!= (const ACE_Future<T> &r) const
328 return r.future_rep_ != this->future_rep_;
331 template <class T> int
332 ACE_Future<T>::cancel (const T &r)
334 this->cancel ();
335 return this->future_rep_->set (r, *this);
338 template <class T> int
339 ACE_Future<T>::cancel (void)
341 // If this ACE_Future is already attached to a ACE_Future_Rep,
342 // detach it (maybe delete the ACE_Future_Rep).
343 FUTURE_REP::assign (this->future_rep_,
344 FUTURE_REP::create ());
345 return 0;
348 template <class T> int
349 ACE_Future<T>::set (const T &r)
351 // Give the pointer to the result to the ACE_Future_Rep.
352 return this->future_rep_->set (r, *this);
355 template <class T> int
356 ACE_Future<T>::ready (void) const
358 // We're ready if the ACE_Future_rep is ready...
359 return this->future_rep_->ready ();
362 template <class T> int
363 ACE_Future<T>::get (T &value,
364 ACE_Time_Value *tv) const
366 // We return the ACE_Future_rep.
367 return this->future_rep_->get (value, tv);
370 template <class T> int
371 ACE_Future<T>::attach (ACE_Future_Observer<T> *observer)
373 return this->future_rep_->attach (observer, *this);
376 template <class T> int
377 ACE_Future<T>::detach (ACE_Future_Observer<T> *observer)
379 return this->future_rep_->detach (observer);
382 template <class T>
383 ACE_Future<T>::operator T ()
385 // note that this will fail (and COREDUMP!)
386 // if future_rep_ == 0 !
388 // but...
389 // this is impossible unless somebody is so stupid to
390 // try something like this:
392 // Future<T> futT;
393 // T t;
394 // t = futT;
396 // perform type conversion on Future_Rep.
397 return *future_rep_;
400 template <class T> void
401 ACE_Future<T>::operator = (const ACE_Future<T> &rhs)
403 // assignment:
405 // bind <this> to the same <ACE_Future_Rep> as <r>.
407 // This will work if &r == this, by first increasing the ref count
408 ACE_Future<T> &r = (ACE_Future<T> &) rhs;
409 FUTURE_REP::assign (this->future_rep_,
410 FUTURE_REP::attach (r.future_rep_));
413 template <class T> void
414 ACE_Future<T>::dump (void) const
416 #if defined (ACE_HAS_DUMP)
417 ACELIB_DEBUG ((LM_DEBUG,
418 ACE_BEGIN_DUMP, this));
420 if (this->future_rep_)
421 this->future_rep_->dump ();
423 ACELIB_DEBUG ((LM_DEBUG,
424 ACE_END_DUMP));
425 #endif /* ACE_HAS_DUMP */
428 template <class T> ACE_Future_Rep<T> *
429 ACE_Future<T>::get_rep ()
431 return this->future_rep_;
434 ACE_END_VERSIONED_NAMESPACE_DECL
436 #endif /* ACE_HAS_THREADS */
438 #endif /* ACE_FUTURE_CPP */