431 lines
10 KiB
C++
431 lines
10 KiB
C++
#ifndef ACE_FUTURE_CPP
|
|
#define ACE_FUTURE_CPP
|
|
|
|
#include "ace/Future.h"
|
|
|
|
#if !defined (ACE_LACKS_PRAGMA_ONCE)
|
|
# pragma once
|
|
#endif /* ACE_LACKS_PRAGMA_ONCE */
|
|
|
|
#if defined (ACE_HAS_THREADS)
|
|
|
|
# include "ace/Guard_T.h"
|
|
# include "ace/Recursive_Thread_Mutex.h"
|
|
|
|
ACE_BEGIN_VERSIONED_NAMESPACE_DECL
|
|
|
|
template <class T>
|
|
ACE_Future_Holder<T>::ACE_Future_Holder (void)
|
|
{
|
|
}
|
|
|
|
template <class T>
|
|
ACE_Future_Holder<T>::ACE_Future_Holder (const ACE_Future<T> &item)
|
|
: item_ (item)
|
|
{
|
|
}
|
|
|
|
template <class T>
|
|
ACE_Future_Holder<T>::~ACE_Future_Holder (void)
|
|
{
|
|
}
|
|
|
|
template <class T>
|
|
ACE_Future_Observer<T>::ACE_Future_Observer (void)
|
|
{
|
|
}
|
|
|
|
template <class T>
|
|
ACE_Future_Observer<T>::~ACE_Future_Observer (void)
|
|
{
|
|
}
|
|
|
|
// Dump the state of an object.
|
|
|
|
template <class T> void
|
|
ACE_Future_Rep<T>::dump (void) const
|
|
{
|
|
#if defined (ACE_HAS_DUMP)
|
|
ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
|
|
ACELIB_DEBUG ((LM_DEBUG,
|
|
"ref_count_ = %d\n",
|
|
(int) this->ref_count_));
|
|
ACELIB_DEBUG ((LM_INFO,"value_:\n"));
|
|
if (this->value_)
|
|
ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT (" (NON-NULL)\n")));
|
|
else
|
|
//FUZZ: disable check_for_NULL
|
|
ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT (" (NULL)\n")));
|
|
//FUZZ: enable check_for_NULL
|
|
|
|
ACELIB_DEBUG ((LM_INFO,"value_ready_:\n"));
|
|
this->value_ready_.dump ();
|
|
ACELIB_DEBUG ((LM_INFO,"value_ready_mutex_:\n"));
|
|
this->value_ready_mutex_.dump ();
|
|
ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP));
|
|
#endif /* ACE_HAS_DUMP */
|
|
}
|
|
|
|
template <class T> ACE_Future_Rep<T> *
|
|
ACE_Future_Rep<T>::internal_create (void)
|
|
{
|
|
ACE_Future_Rep<T> *temp = 0;
|
|
ACE_NEW_RETURN (temp,
|
|
ACE_Future_Rep<T> (),
|
|
0);
|
|
return temp;
|
|
}
|
|
|
|
template <class T> ACE_Future_Rep<T> *
|
|
ACE_Future_Rep<T>::create (void)
|
|
{
|
|
// Yes set ref count to zero.
|
|
ACE_Future_Rep<T> *temp = internal_create ();
|
|
#if defined (ACE_NEW_THROWS_EXCEPTIONS)
|
|
if (temp == 0)
|
|
ACE_throw_bad_alloc;
|
|
#else
|
|
ACE_ASSERT (temp != 0);
|
|
#endif /* ACE_NEW_THROWS_EXCEPTIONS */
|
|
return temp;
|
|
}
|
|
|
|
|
|
template <class T> ACE_Future_Rep<T> *
|
|
ACE_Future_Rep<T>::attach (ACE_Future_Rep<T>*& rep)
|
|
{
|
|
ACE_ASSERT (rep != 0);
|
|
// Use value_ready_mutex_ for both condition and ref count management
|
|
ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, r_mon, rep->value_ready_mutex_, 0);
|
|
++rep->ref_count_;
|
|
return rep;
|
|
}
|
|
|
|
template <class T> void
|
|
ACE_Future_Rep<T>::detach (ACE_Future_Rep<T>*& rep)
|
|
{
|
|
ACE_ASSERT (rep != 0);
|
|
// Use value_ready_mutex_ for both condition and ref count management
|
|
ACE_GUARD (ACE_SYNCH_RECURSIVE_MUTEX, r_mon, rep->value_ready_mutex_);
|
|
|
|
if (rep->ref_count_-- == 0)
|
|
{
|
|
ACE_MT (r_mon.release ());
|
|
// We do not need the lock when deleting the representation.
|
|
// There should be no side effects from deleting rep and we don
|
|
// not want to release a deleted mutex.
|
|
delete rep;
|
|
}
|
|
}
|
|
|
|
template <class T> void
|
|
ACE_Future_Rep<T>::assign (ACE_Future_Rep<T>*& rep, ACE_Future_Rep<T>* new_rep)
|
|
{
|
|
ACE_ASSERT (rep != 0);
|
|
ACE_ASSERT (new_rep != 0);
|
|
// Use value_ready_mutex_ for both condition and ref count management
|
|
ACE_GUARD (ACE_SYNCH_RECURSIVE_MUTEX, r_mon, rep->value_ready_mutex_);
|
|
|
|
ACE_Future_Rep<T>* old = rep;
|
|
rep = new_rep;
|
|
|
|
// detached old last for exception safety
|
|
if (old->ref_count_-- == 0)
|
|
{
|
|
ACE_MT (r_mon.release ());
|
|
// We do not need the lock when deleting the representation.
|
|
// There should be no side effects from deleting rep and we don
|
|
// not want to release a deleted mutex.
|
|
delete old;
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
ACE_Future_Rep<T>::ACE_Future_Rep (void)
|
|
: value_ (0),
|
|
ref_count_ (0),
|
|
value_ready_ (value_ready_mutex_)
|
|
{
|
|
}
|
|
|
|
template <class T>
|
|
ACE_Future_Rep<T>::~ACE_Future_Rep (void)
|
|
{
|
|
delete this->value_;
|
|
}
|
|
|
|
template <class T> int
|
|
ACE_Future_Rep<T>::ready (void) const
|
|
{
|
|
return this->value_ != 0;
|
|
}
|
|
|
|
template <class T> int
|
|
ACE_Future_Rep<T>::set (const T &r,
|
|
ACE_Future<T> &caller)
|
|
{
|
|
// If the value is already produced, ignore it...
|
|
if (this->value_ == 0)
|
|
{
|
|
ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX,
|
|
ace_mon,
|
|
this->value_ready_mutex_,
|
|
-1);
|
|
// Otherwise, create a new result value. Note the use of the
|
|
// Double-checked locking pattern to avoid multiple allocations.
|
|
|
|
if (this->value_ == 0) // Still no value, so proceed
|
|
{
|
|
ACE_NEW_RETURN (this->value_,
|
|
T (r),
|
|
-1);
|
|
|
|
// Remove and notify all subscribed observers.
|
|
typename OBSERVER_COLLECTION::iterator iterator =
|
|
this->observer_collection_.begin ();
|
|
|
|
typename OBSERVER_COLLECTION::iterator end =
|
|
this->observer_collection_.end ();
|
|
|
|
while (iterator != end)
|
|
{
|
|
OBSERVER *observer = *iterator++;
|
|
observer->update (caller);
|
|
}
|
|
|
|
// Signal all the waiting threads.
|
|
return this->value_ready_.broadcast ();
|
|
}
|
|
// Destructor releases the lock.
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template <class T> int
|
|
ACE_Future_Rep<T>::get (T &value,
|
|
ACE_Time_Value *tv) const
|
|
{
|
|
// If the value is already produced, return it.
|
|
if (this->value_ == 0)
|
|
{
|
|
ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon,
|
|
this->value_ready_mutex_,
|
|
-1);
|
|
// If the value is not yet defined we must block until the
|
|
// producer writes to it.
|
|
|
|
while (this->value_ == 0)
|
|
// Perform a timed wait.
|
|
if (this->value_ready_.wait (tv) == -1)
|
|
return -1;
|
|
|
|
// Destructor releases the lock.
|
|
}
|
|
|
|
value = *this->value_;
|
|
return 0;
|
|
}
|
|
|
|
template <class T> int
|
|
ACE_Future_Rep<T>::attach (ACE_Future_Observer<T> *observer,
|
|
ACE_Future<T> &caller)
|
|
{
|
|
ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->value_ready_mutex_, -1);
|
|
|
|
// Otherwise, create a new result value. Note the use of the
|
|
// Double-checked locking pattern to avoid corrupting the list.
|
|
|
|
int result = 1;
|
|
|
|
// If the value is already produced, then notify observer
|
|
if (this->value_ == 0)
|
|
result = this->observer_collection_.insert (observer);
|
|
else
|
|
observer->update (caller);
|
|
|
|
return result;
|
|
}
|
|
|
|
template <class T> int
|
|
ACE_Future_Rep<T>::detach (ACE_Future_Observer<T> *observer)
|
|
{
|
|
ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->value_ready_mutex_, -1);
|
|
|
|
// Remove all occurrences of the specified observer from this
|
|
// objects hash map.
|
|
return this->observer_collection_.remove (observer);
|
|
}
|
|
|
|
template <class T>
|
|
ACE_Future_Rep<T>::operator T ()
|
|
{
|
|
// If the value is already produced, return it.
|
|
if (this->value_ == 0)
|
|
{
|
|
// Constructor of ace_mon acquires the mutex.
|
|
ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->value_ready_mutex_, 0);
|
|
|
|
// If the value is not yet defined we must block until the
|
|
// producer writes to it.
|
|
|
|
// Wait ``forever.''
|
|
|
|
while (this->value_ == 0)
|
|
if (this->value_ready_.wait () == -1)
|
|
// What to do in this case since we've got to indicate
|
|
// failure somehow? Exceptions would be nice, but they're
|
|
// not portable...
|
|
return 0;
|
|
|
|
// Destructor releases the mutex
|
|
}
|
|
|
|
return *this->value_;
|
|
}
|
|
|
|
template <class T>
|
|
ACE_Future<T>::ACE_Future (void)
|
|
: future_rep_ (FUTURE_REP::create ())
|
|
{
|
|
}
|
|
|
|
template <class T>
|
|
ACE_Future<T>::ACE_Future (const ACE_Future<T> &r)
|
|
: future_rep_ (FUTURE_REP::attach (((ACE_Future<T> &) r).future_rep_))
|
|
{
|
|
}
|
|
|
|
template <class T>
|
|
ACE_Future<T>::ACE_Future (const T &r)
|
|
: future_rep_ (FUTURE_REP::create ())
|
|
{
|
|
this->future_rep_->set (r, *this);
|
|
}
|
|
|
|
template <class T>
|
|
ACE_Future<T>::~ACE_Future (void)
|
|
{
|
|
FUTURE_REP::detach (future_rep_);
|
|
}
|
|
|
|
template <class T> bool
|
|
ACE_Future<T>::operator== (const ACE_Future<T> &r) const
|
|
{
|
|
return r.future_rep_ == this->future_rep_;
|
|
}
|
|
|
|
template <class T> bool
|
|
ACE_Future<T>::operator!= (const ACE_Future<T> &r) const
|
|
{
|
|
return r.future_rep_ != this->future_rep_;
|
|
}
|
|
|
|
template <class T> int
|
|
ACE_Future<T>::cancel (const T &r)
|
|
{
|
|
this->cancel ();
|
|
return this->future_rep_->set (r, *this);
|
|
}
|
|
|
|
template <class T> int
|
|
ACE_Future<T>::cancel (void)
|
|
{
|
|
// If this ACE_Future is already attached to a ACE_Future_Rep,
|
|
// detach it (maybe delete the ACE_Future_Rep).
|
|
FUTURE_REP::assign (this->future_rep_,
|
|
FUTURE_REP::create ());
|
|
return 0;
|
|
}
|
|
|
|
template <class T> int
|
|
ACE_Future<T>::set (const T &r)
|
|
{
|
|
// Give the pointer to the result to the ACE_Future_Rep.
|
|
return this->future_rep_->set (r, *this);
|
|
}
|
|
|
|
template <class T> int
|
|
ACE_Future<T>::ready (void) const
|
|
{
|
|
// We're ready if the ACE_Future_rep is ready...
|
|
return this->future_rep_->ready ();
|
|
}
|
|
|
|
template <class T> int
|
|
ACE_Future<T>::get (T &value,
|
|
ACE_Time_Value *tv) const
|
|
{
|
|
// We return the ACE_Future_rep.
|
|
return this->future_rep_->get (value, tv);
|
|
}
|
|
|
|
template <class T> int
|
|
ACE_Future<T>::attach (ACE_Future_Observer<T> *observer)
|
|
{
|
|
return this->future_rep_->attach (observer, *this);
|
|
}
|
|
|
|
template <class T> int
|
|
ACE_Future<T>::detach (ACE_Future_Observer<T> *observer)
|
|
{
|
|
return this->future_rep_->detach (observer);
|
|
}
|
|
|
|
template <class T>
|
|
ACE_Future<T>::operator T ()
|
|
{
|
|
// note that this will fail (and COREDUMP!)
|
|
// if future_rep_ == 0 !
|
|
//
|
|
// but...
|
|
// this is impossible unless somebody is so stupid to
|
|
// try something like this:
|
|
//
|
|
// Future<T> futT;
|
|
// T t;
|
|
// t = futT;
|
|
|
|
// perform type conversion on Future_Rep.
|
|
return *future_rep_;
|
|
}
|
|
|
|
template <class T> void
|
|
ACE_Future<T>::operator = (const ACE_Future<T> &rhs)
|
|
{
|
|
// assignment:
|
|
//
|
|
// bind <this> to the same <ACE_Future_Rep> as <r>.
|
|
|
|
// This will work if &r == this, by first increasing the ref count
|
|
ACE_Future<T> &r = (ACE_Future<T> &) rhs;
|
|
FUTURE_REP::assign (this->future_rep_,
|
|
FUTURE_REP::attach (r.future_rep_));
|
|
}
|
|
|
|
template <class T> void
|
|
ACE_Future<T>::dump (void) const
|
|
{
|
|
#if defined (ACE_HAS_DUMP)
|
|
ACELIB_DEBUG ((LM_DEBUG,
|
|
ACE_BEGIN_DUMP, this));
|
|
|
|
if (this->future_rep_)
|
|
this->future_rep_->dump ();
|
|
|
|
ACELIB_DEBUG ((LM_DEBUG,
|
|
ACE_END_DUMP));
|
|
#endif /* ACE_HAS_DUMP */
|
|
}
|
|
|
|
template <class T> ACE_Future_Rep<T> *
|
|
ACE_Future<T>::get_rep ()
|
|
{
|
|
return this->future_rep_;
|
|
}
|
|
|
|
ACE_END_VERSIONED_NAMESPACE_DECL
|
|
|
|
#endif /* ACE_HAS_THREADS */
|
|
|
|
#endif /* ACE_FUTURE_CPP */
|