Changes to attempt to silence bcc64x
[ACE_TAO.git] / ACE / ace / Future.cpp
blobf11b76b13a1c635b5eba9bab3a4b1820e716025c
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 (const ACE_Future<T> &item)
24 : item_ (item)
28 // Dump the state of an object.
30 template <class T> void
31 ACE_Future_Rep<T>::dump () const
33 #if defined (ACE_HAS_DUMP)
34 ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
35 ACELIB_DEBUG ((LM_DEBUG,
36 "ref_count_ = %d\n",
37 (int) this->ref_count_));
38 ACELIB_DEBUG ((LM_INFO,"value_:\n"));
39 if (this->value_)
40 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT (" (NON-NULL)\n")));
41 else
42 //FUZZ: disable check_for_NULL
43 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT (" (NULL)\n")));
44 //FUZZ: enable check_for_NULL
46 ACELIB_DEBUG ((LM_INFO,"value_ready_:\n"));
47 this->value_ready_.dump ();
48 ACELIB_DEBUG ((LM_INFO,"value_ready_mutex_:\n"));
49 this->value_ready_mutex_.dump ();
50 ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP));
51 #endif /* ACE_HAS_DUMP */
54 template <class T> ACE_Future_Rep<T> *
55 ACE_Future_Rep<T>::internal_create ()
57 ACE_Future_Rep<T> *temp {};
58 ACE_NEW_RETURN (temp,
59 ACE_Future_Rep<T> (),
60 nullptr);
61 return temp;
64 template <class T> ACE_Future_Rep<T> *
65 ACE_Future_Rep<T>::create ()
67 // Yes set ref count to zero.
68 ACE_Future_Rep<T> *temp = internal_create ();
69 if (!temp)
70 throw std::bad_alloc ();
71 return temp;
75 template <class T> ACE_Future_Rep<T> *
76 ACE_Future_Rep<T>::attach (ACE_Future_Rep<T>*& rep)
78 ACE_ASSERT (rep != nullptr);
79 // Use value_ready_mutex_ for both condition and ref count management
80 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, r_mon, rep->value_ready_mutex_, nullptr);
81 ++rep->ref_count_;
82 return rep;
85 template <class T> void
86 ACE_Future_Rep<T>::detach (ACE_Future_Rep<T>*& rep)
88 ACE_ASSERT (rep != nullptr);
89 // Use value_ready_mutex_ for both condition and ref count management
90 ACE_GUARD (ACE_SYNCH_RECURSIVE_MUTEX, r_mon, rep->value_ready_mutex_);
92 if (rep->ref_count_-- == 0)
94 ACE_MT (r_mon.release ());
95 // We do not need the lock when deleting the representation.
96 // There should be no side effects from deleting rep and we don
97 // not want to release a deleted mutex.
98 delete rep;
102 template <class T> void
103 ACE_Future_Rep<T>::assign (ACE_Future_Rep<T>*& rep, ACE_Future_Rep<T>* new_rep)
105 ACE_ASSERT (rep != nullptr);
106 ACE_ASSERT (new_rep != nullptr);
107 // Use value_ready_mutex_ for both condition and ref count management
108 ACE_GUARD (ACE_SYNCH_RECURSIVE_MUTEX, r_mon, rep->value_ready_mutex_);
110 ACE_Future_Rep<T>* old = rep;
111 rep = new_rep;
113 // detached old last for exception safety
114 if (old->ref_count_-- == 0)
116 ACE_MT (r_mon.release ());
117 // We do not need the lock when deleting the representation.
118 // There should be no side effects from deleting rep and we don
119 // not want to release a deleted mutex.
120 delete old;
124 template <class T>
125 ACE_Future_Rep<T>::ACE_Future_Rep ()
126 : value_ready_ (value_ready_mutex_)
130 template <class T>
131 ACE_Future_Rep<T>::~ACE_Future_Rep ()
133 delete this->value_;
136 template <class T> int
137 ACE_Future_Rep<T>::ready () const
139 return this->value_ != nullptr;
142 template <class T> int
143 ACE_Future_Rep<T>::set (const T &r,
144 ACE_Future<T> &caller)
146 // If the value is already produced, ignore it...
147 if (this->value_ == nullptr)
149 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX,
150 ace_mon,
151 this->value_ready_mutex_,
152 -1);
153 // Otherwise, create a new result value. Note the use of the
154 // Double-checked locking pattern to avoid multiple allocations.
156 if (this->value_ == nullptr) // Still no value, so proceed
158 ACE_NEW_RETURN (this->value_,
159 T (r),
160 -1);
162 // Remove and notify all subscribed observers.
163 typename OBSERVER_COLLECTION::iterator iterator = this->observer_collection_.begin ();
164 typename OBSERVER_COLLECTION::iterator end = this->observer_collection_.end ();
166 while (iterator != end)
168 OBSERVER *observer = *iterator++;
169 if (observer)
171 observer->update (caller);
175 // Signal all the waiting threads.
176 return this->value_ready_.broadcast ();
178 // Destructor releases the lock.
180 return 0;
183 template <class T> int
184 ACE_Future_Rep<T>::get (T &value,
185 ACE_Time_Value *tv) const
187 // If the value is already produced, return it.
188 if (this->value_ == nullptr)
190 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon,
191 this->value_ready_mutex_,
192 -1);
193 // If the value is not yet defined we must block until the
194 // producer writes to it.
196 while (this->value_ == nullptr)
197 // Perform a timed wait.
198 if (this->value_ready_.wait (tv) == -1)
199 return -1;
201 // Destructor releases the lock.
204 value = *this->value_;
205 return 0;
208 template <class T> int
209 ACE_Future_Rep<T>::attach (ACE_Future_Observer<T> *observer,
210 ACE_Future<T> &caller)
212 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->value_ready_mutex_, -1);
214 // Otherwise, create a new result value. Note the use of the
215 // Double-checked locking pattern to avoid corrupting the list.
217 int result = 1;
219 // If the value is already produced, then notify observer
220 if (this->value_ == nullptr)
221 result = this->observer_collection_.insert (observer);
222 else
223 observer->update (caller);
225 return result;
228 template <class T> int
229 ACE_Future_Rep<T>::detach (ACE_Future_Observer<T> *observer)
231 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->value_ready_mutex_, -1);
233 // Remove all occurrences of the specified observer from this
234 // objects hash map.
235 return this->observer_collection_.remove (observer);
238 template <class T>
239 ACE_Future_Rep<T>::operator T ()
241 // If the value is already produced, return it.
242 if (this->value_ == nullptr)
244 // Constructor of ace_mon acquires the mutex.
245 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->value_ready_mutex_, 0);
247 // If the value is not yet defined we must block until the
248 // producer writes to it.
250 // Wait ``forever.''
252 while (this->value_ == nullptr)
253 if (this->value_ready_.wait () == -1)
254 // What to do in this case since we've got to indicate
255 // failure somehow? Exceptions would be nice, but they're
256 // not portable...
257 return 0;
259 // Destructor releases the mutex
262 return *this->value_;
265 template <class T>
266 ACE_Future<T>::ACE_Future ()
267 : future_rep_ (FUTURE_REP::create ())
271 template <class T>
272 ACE_Future<T>::ACE_Future (const ACE_Future<T> &r)
273 : future_rep_ (FUTURE_REP::attach (((ACE_Future<T> &) r).future_rep_))
277 template <class T>
278 ACE_Future<T>::ACE_Future (const T &r)
279 : future_rep_ (FUTURE_REP::create ())
281 this->future_rep_->set (r, *this);
284 template <class T>
285 ACE_Future<T>::~ACE_Future ()
287 FUTURE_REP::detach (future_rep_);
290 template <class T> bool
291 ACE_Future<T>::operator== (const ACE_Future<T> &r) const
293 return r.future_rep_ == this->future_rep_;
296 template <class T> bool
297 ACE_Future<T>::operator!= (const ACE_Future<T> &r) const
299 return r.future_rep_ != this->future_rep_;
302 template <class T> int
303 ACE_Future<T>::cancel (const T &r)
305 this->cancel ();
306 return this->future_rep_->set (r, *this);
309 template <class T> int
310 ACE_Future<T>::cancel ()
312 // If this ACE_Future is already attached to a ACE_Future_Rep,
313 // detach it (maybe delete the ACE_Future_Rep).
314 FUTURE_REP::assign (this->future_rep_,
315 FUTURE_REP::create ());
316 return 0;
319 template <class T> int
320 ACE_Future<T>::set (const T &r)
322 // Give the pointer to the result to the ACE_Future_Rep.
323 return this->future_rep_->set (r, *this);
326 template <class T> int
327 ACE_Future<T>::ready () const
329 // We're ready if the ACE_Future_rep is ready...
330 return this->future_rep_->ready ();
333 template <class T> int
334 ACE_Future<T>::get (T &value, ACE_Time_Value *tv) const
336 // We return the ACE_Future_rep.
337 return this->future_rep_->get (value, tv);
340 template <class T> int
341 ACE_Future<T>::attach (ACE_Future_Observer<T> *observer)
343 return this->future_rep_->attach (observer, *this);
346 template <class T> int
347 ACE_Future<T>::detach (ACE_Future_Observer<T> *observer)
349 return this->future_rep_->detach (observer);
352 template <class T>
353 ACE_Future<T>::operator T ()
355 // note that this will fail (and COREDUMP!)
356 // if future_rep_ == 0 !
358 // but...
359 // this is impossible unless somebody is so stupid to
360 // try something like this:
362 // Future<T> futT;
363 // T t;
364 // t = futT;
366 // perform type conversion on Future_Rep.
367 return *future_rep_;
370 template <class T> void
371 ACE_Future<T>::operator = (const ACE_Future<T> &rhs)
373 // assignment:
375 // bind <this> to the same <ACE_Future_Rep> as <r>.
377 // This will work if &r == this, by first increasing the ref count
378 ACE_Future<T> &r = (ACE_Future<T> &) rhs;
379 FUTURE_REP::assign (this->future_rep_,
380 FUTURE_REP::attach (r.future_rep_));
383 template <class T> void
384 ACE_Future<T>::dump () const
386 #if defined (ACE_HAS_DUMP)
387 ACELIB_DEBUG ((LM_DEBUG,
388 ACE_BEGIN_DUMP, this));
390 if (this->future_rep_)
391 this->future_rep_->dump ();
393 ACELIB_DEBUG ((LM_DEBUG,
394 ACE_END_DUMP));
395 #endif /* ACE_HAS_DUMP */
398 template <class T> ACE_Future_Rep<T> *
399 ACE_Future<T>::get_rep ()
401 return this->future_rep_;
404 ACE_END_VERSIONED_NAMESPACE_DECL
406 #endif /* ACE_HAS_THREADS */
408 #endif /* ACE_FUTURE_CPP */