4 #include "ace/Future.h"
6 #if !defined (ACE_LACKS_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
)
23 ACE_Future_Holder
<T
>::ACE_Future_Holder (const ACE_Future
<T
> &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
,
37 (int) this->ref_count_
));
38 ACELIB_DEBUG ((LM_INFO
,"value_:\n"));
40 ACELIB_DEBUG ((LM_DEBUG
, ACE_TEXT (" (NON-NULL)\n")));
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
{};
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 ();
70 throw std::bad_alloc ();
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);
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.
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
;
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.
125 ACE_Future_Rep
<T
>::ACE_Future_Rep ()
126 : value_ready_ (value_ready_mutex_
)
131 ACE_Future_Rep
<T
>::~ACE_Future_Rep ()
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
,
151 this->value_ready_mutex_
,
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_
,
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
++;
171 observer
->update (caller
);
175 // Signal all the waiting threads.
176 return this->value_ready_
.broadcast ();
178 // Destructor releases the lock.
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_
,
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)
201 // Destructor releases the lock.
204 value
= *this->value_
;
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.
219 // If the value is already produced, then notify observer
220 if (this->value_
== nullptr)
221 result
= this->observer_collection_
.insert (observer
);
223 observer
->update (caller
);
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
235 return this->observer_collection_
.remove (observer
);
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.
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
259 // Destructor releases the mutex
262 return *this->value_
;
266 ACE_Future
<T
>::ACE_Future ()
267 : future_rep_ (FUTURE_REP::create ())
272 ACE_Future
<T
>::ACE_Future (const ACE_Future
<T
> &r
)
273 : future_rep_ (FUTURE_REP::attach (((ACE_Future
<T
> &) r
).future_rep_
))
278 ACE_Future
<T
>::ACE_Future (const T
&r
)
279 : future_rep_ (FUTURE_REP::create ())
281 this->future_rep_
->set (r
, *this);
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
)
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 ());
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
);
353 ACE_Future
<T
>::operator T ()
355 // note that this will fail (and COREDUMP!)
356 // if future_rep_ == 0 !
359 // this is impossible unless somebody is so stupid to
360 // try something like this:
366 // perform type conversion on Future_Rep.
370 template <class T
> void
371 ACE_Future
<T
>::operator = (const ACE_Future
<T
> &rhs
)
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
,
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 */