// Future.cpp // $Id$ #define ACE_BUILD_DLL #if !defined (ACE_FUTURE_CPP) #define ACE_FUTURE_CPP #include "ace/Future.h" #if defined (ACE_HAS_THREADS) // Dump the state of an object. template void ACE_Future_Rep::dump (void) const { ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); ACE_DEBUG ((LM_DEBUG, "ref_count_ = %d\n", (int) this->ref_count_)); ACE_DEBUG ((LM_INFO,"value_: \n")); if (this->value_) ACE_DEBUG ((LM_DEBUG," (NON-NULL)\n")); else ACE_DEBUG ((LM_DEBUG," (NULL)\n")); ACE_DEBUG ((LM_INFO,"value_ready_: \n")); this->value_ready_.dump (); ACE_DEBUG ((LM_INFO,"value_ready_mutex_: \n")); this->value_ready_mutex_.dump (); ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); } template ACE_Future_Rep::ACE_Future_Rep (void) : value_ (0), ref_count_ (0), value_ready_ (this->value_ready_mutex_) { } template ACE_Future_Rep::~ACE_Future_Rep (void) { delete this->value_; this->value_ = 0; } template int ACE_Future_Rep::ready (void) { return this->value_ != 0; } template int ACE_Future_Rep::set (const T &r) { // If the value is already produced, ignore it... if (this->value_ == 0) { ACE_MT (ACE_GUARD_RETURN (ACE_Thread_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) ACE_NEW_RETURN (this->value_, T (r), -1); // Signal all the waiting threads. return this->value_ready_.broadcast (); // Destructor releases the lock. } return 0; } template int ACE_Future_Rep::get (T &value, ACE_Time_Value *tv) { // If the value is already produced, return it. if (this->value_ == 0) { ACE_MT (ACE_GUARD_RETURN (ACE_Thread_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 ACE_Future_Rep::operator T () { // If the value is already produced, return it. if (this->value_ == 0) { // Constructor of ace_mon acquires the mutex. ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->value_ready_mutex_, 0)); // If the value is not yet defined we must block until the // producer writes to it. while (this->value_ == 0) { // wait forever 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 ACE_Future::ACE_Future (void) : future_rep_ (0) { } template ACE_Future::ACE_Future (const ACE_Future &r) { // copy constructor: // // bind to the same as . // @@ not really clear if this is needed... after all this // ACE_Future is just being instantiated... ACE_MT (ACE_GUARD (ACE_Thread_Mutex, ace_mon, this->mutex_)); // acquire the mutex on . We have to make sure // that does not delete its future_rep_... ACE_MT (ACE_GUARD (ACE_Thread_Mutex, r_mon, (ACE_Thread_Mutex &) r.mutex_)); // Check if 'r' has already a ACE_Future_rep bound to it. if (r.future_rep_ == 0) this->future_rep_ = r.create_rep_i (); else // ACE_Future_rep exists already, we can just link to it. this->future_rep_ = r.future_rep_; this->future_rep_->ref_count_++; } template ACE_Future::ACE_Future (const T &r) { ACE_DEBUG ((LM_DEBUG," (%t) funny constructor\n")); ACE_MT (ACE_GUARD (ACE_Thread_Mutex, ace_mon, this->mutex_)); this->create_rep_i ()->set (r); } template ACE_Future::~ACE_Future (void) { ACE_MT (ACE_GUARD (ACE_Thread_Mutex, ace_mon, this->mutex_)); if (this->future_rep_) { this->future_rep_->ref_count_--; if (this->future_rep_->ref_count_ == 0) { delete this->future_rep_; this->future_rep_ = 0; } } } template int ACE_Future::operator== (const ACE_Future &r) const { return r.future_rep_ == this->future_rep_; } template int ACE_Future::operator!= (const ACE_Future &r) const { return r.future_rep_ != this->future_rep_; } template int ACE_Future::cancel (const T &r) { ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->mutex_, -1)); // If this ACE_Future is already attached to a ACE_Future_Rep, // detach it (maybe delete the ACE_Future_Rep). if (this->future_rep_) { this->future_rep_->ref_count_--; if (this->future_rep_->ref_count_ == 0) delete this->future_rep_; } // Make a new ACE_Future_Rep and immediately assign // the new value to it. this->create_rep_i (); return this->future_rep_->set (r); } template int ACE_Future::set (const T &r) { if (this->future_rep_) // Give the pointer to the result to the ACE_Future_Rep. return this->future_rep_->set (r); else // @@ Maybe this should return a special value to indicate that // there's no yet? return 0; } template ACE_Future_Rep * ACE_Future::create_rep_i (void) const { // Should only be called internally with locks held. ACE_NEW_RETURN (((ACE_Future *) this)->future_rep_, ACE_Future_Rep, 0); this->future_rep_->ref_count_ = 1; return this->future_rep_; } template int ACE_Future::ready (void) { // We're ready if the ACE_Future_rep is ready... if (this->future_rep_) return this->future_rep_->ready (); else return 0; } template int ACE_Future::get (T &value, ACE_Time_Value *tv) { ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->mutex_, -1)); if (this->future_rep_ == 0) // Oops, we have to create a ACE_Future_Rep first. this->create_rep_i (); // We return the ACE_Future_rep. return this->future_rep_->get (value, tv); } template ACE_Future::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 futT; // T t; // t = futT; // perform type conversion on Future_Rep. return *future_rep_; } template void ACE_Future::operator = (const ACE_Future &r) { // assignment: // // bind to the same as . ACE_MT (ACE_GUARD (ACE_Thread_Mutex, ace_mon, this->mutex_)); // if there is already a we have // to disconnect from it... if (this->future_rep_) { // Disconnect from the . this->future_rep_->ref_count_--; if (this->future_rep_->ref_count_ == 0) delete this->future_rep_; } // Acquire the mutex on . We have to make sure // that does not delete it's future_rep_... ACE_MT (ACE_GUARD (ACE_Thread_Mutex, r_mon, (ACE_Thread_Mutex &) r.mutex_)); // Check if 'r' has already a ACE_Future_rep bound to it. if (r.future_rep_ == 0) this->future_rep_ = r.create_rep_i (); else // ACE_Future_rep exists already, we can just link to it. this->future_rep_ = r.future_rep_; this->future_rep_->ref_count_++; } template void ACE_Future::dump (void) const { ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); if (this->future_rep_) this->future_rep_->dump (); this->mutex_.dump (); ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); } template void * ACE_Future::operator new (size_t) { return 0; } template void ACE_Future::operator delete (void *) { } template void ACE_Future::operator &() { } #if defined (ACE_TEMPLATES_REQUIRE_SPECIALIZATION) template class ACE_Atomic_Op; #endif /* ACE_TEMPLATES_REQUIRE_SPECIALIZATION */ #endif /* ACE_HAS_THREADS */ #endif /* ACE_FUTURE_CPP */