mxw_wotlk_azerothcore/deps/acelite/ace/Future.cpp

431 lines
10 KiB
C++
Raw Normal View History

2020-10-30 23:45:46 -04:00
#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 */