// Synch_T.cpp // $Id$ #if !defined (ACE_SYNCH_T_C) #define ACE_SYNCH_T_C #define ACE_BUILD_DLL #include "ace/Thread.h" #include "ace/Time_Value.h" #include "ace/Synch_T.h" #if !defined (__ACE_INLINE__) #include "ace/Synch_T.i" #endif /* __ACE_INLINE__ */ ACE_ALLOC_HOOK_DEFINE(ACE_Atomic_Op) template ACE_Test_and_Set::ACE_Test_and_Set (TYPE initial_value) : is_set_ (initial_value) { } // Returns true if we are done, else false. template TYPE ACE_Test_and_Set::is_set (void) const { ACE_GUARD_RETURN (LOCK, ace_mon, (LOCK &) this->lock_, this->is_set_); return this->is_set_; } // Sets the status. template TYPE ACE_Test_and_Set::set (TYPE status) { ACE_GUARD_RETURN (LOCK, ace_mon, this->lock_, this->is_set_); TYPE o_status = this->is_set_; this->is_set_ = status; return o_status; } template int ACE_Test_and_Set::handle_signal (int, siginfo_t *, ucontext_t *) { this->set (1); return 0; } template void ACE_Atomic_Op::dump (void) const { // ACE_TRACE ("ACE_Atomic_Op::dump"); ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); this->lock_.dump (); ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); } template ACE_Atomic_Op::ACE_Atomic_Op (void) : value_ (0) { // ACE_TRACE ("ACE_Atomic_Op::ACE_Atomic_Op"); } template ACE_Atomic_Op::ACE_Atomic_Op (TYPE c) { // ACE_TRACE ("ACE_Atomic_Op::ACE_Atomic_Op"); this->value_ = c; } ACE_ALLOC_HOOK_DEFINE(ACE_Guard) template void ACE_Guard::dump (void) const { // ACE_TRACE ("ACE_Guard::dump"); ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); ACE_DEBUG ((LM_DEBUG, "lock_ = %x\n", this->lock_)); ACE_DEBUG ((LM_DEBUG, "owner_ = %d\n", this->owner_)); ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); } ACE_ALLOC_HOOK_DEFINE(ACE_Write_Guard) template void ACE_Write_Guard::dump (void) const { // ACE_TRACE ("ACE_Write_Guard::dump"); ACE_Guard::dump (); } ACE_ALLOC_HOOK_DEFINE(ACE_Read_Guard) template void ACE_Read_Guard::dump (void) const { // ACE_TRACE ("ACE_Read_Guard::dump"); ACE_Guard::dump (); } #if defined (ACE_HAS_THREADS) #if defined (__osf__) && ! defined (__GNUG__) #pragma define_template ACE_Condition #endif ACE_ALLOC_HOOK_DEFINE(ACE_Condition) template void ACE_Condition::dump (void) const { // ACE_TRACE ("ACE_Condition::dump"); ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); ACE_DEBUG ((LM_DEBUG, "\n")); ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); } template ACE_Thread_Condition::ACE_Thread_Condition (MUTEX &m, LPCTSTR name, void *arg) : ACE_Condition (m, USYNC_THREAD, name, arg) { // ACE_TRACE ("ACE_Thread_Condition::ACE_Thread_Condition"); } template void ACE_Thread_Condition::dump (void) const { // ACE_TRACE ("ACE_Thread_Condition::dump"); ACE_Condition::dump (); } template ACE_Condition::ACE_Condition (MUTEX &m, int type, LPCTSTR name, void *arg) : mutex_ (m) { // ACE_TRACE ("ACE_Condition::ACE_Condition"); if (ACE_OS::cond_init (&this->cond_, type, name, arg) != 0) ACE_ERROR ((LM_ERROR, "%p\n", "ACE_Condition::ACE_Condition")); } template ACE_Condition::~ACE_Condition (void) { // ACE_TRACE ("ACE_Condition::~ACE_Condition"); if (this->remove () == -1) ACE_ERROR ((LM_ERROR, "%p\n", "ACE_Condition::~ACE_Condition")); } template int ACE_Condition::wait (void) { // ACE_TRACE ("ACE_Condition::wait"); return ACE_OS::cond_wait (&this->cond_, &this->mutex_.lock_); } template int ACE_Condition::wait (MUTEX &mutex, const ACE_Time_Value *abstime) { // ACE_TRACE ("ACE_Condition::wait"); if (abstime == 0) return this->wait (); else return ACE_OS::cond_timedwait (&this->cond_, &mutex.lock_, (ACE_Time_Value *) abstime); } // Peform an "alertable" timed wait. If the argument ABSTIME == 0 // then we do a regular cond_wait(), else we do a timed wait for up to // ABSTIME using the Solaris cond_timedwait() function. template int ACE_Condition::wait (const ACE_Time_Value *abstime) { // ACE_TRACE ("ACE_Condition::wait"); return this->wait (this->mutex_, abstime); } #endif /* ACE_HAS_THREADS */ ACE_ALLOC_HOOK_DEFINE(ACE_TSS) template ACE_TSS::~ACE_TSS (void) { ACE_OS::thr_key_detach (this); } template TYPE * ACE_TSS::operator-> () const { return this->ts_get (); } template ACE_TSS::operator TYPE *(void) const { return this->ts_get (); } template TYPE * ACE_TSS::make_TSS_TYPE (void) const { return new TYPE; } template void ACE_TSS::dump (void) const { // ACE_TRACE ("ACE_TSS::dump"); #if defined (ACE_HAS_THREADS) && defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); this->keylock_.dump (); ACE_DEBUG ((LM_DEBUG, "key_ = %d\n", this->key_)); ACE_DEBUG ((LM_DEBUG, "\nonce_ = %d", this->once_)); ACE_DEBUG ((LM_DEBUG, "\n")); ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); #endif /* defined (ACE_HAS_THREADS) && defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) */ } #if defined (ACE_HAS_THREADS) && defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) template void ACE_TSS::cleanup (void *ptr) { // Cast this to the concrete TYPE * so the destructor gets called. delete (TYPE *) ptr; } template ACE_TSS::ACE_TSS (TYPE *ts_obj) : once_ (0), key_ (ACE_OS::NULL_key) { // If caller has passed us a non-NULL TYPE *, then we'll just use // this to initialize the thread-specific value. Thus, subsequent // calls to operator->() will return this value. This is useful // since it enables us to assign objects to thread-specific data // that have arbitrarily complex constructors! if (ts_obj != 0) { ACE_ASSERT (this->once_ == 0); if (ACE_Thread::keycreate (&this->key_, #if defined (ACE_HAS_THR_C_DEST) &ACE_TSS_C_cleanup, #else &ACE_TSS::cleanup, #endif /* ACE_HAS_THR_C_DEST */ (void *) this) != 0) { int errnum = errno; // What should we do if this call fails?! ACE_OS::fprintf (stderr, "ACE_Thread::keycreate() failed!"); errno = errnum; return; } this->once_ = 1; #if defined (ACE_HAS_THR_C_DEST) // Encapsulate a ts_obj and it's destructor in an ACE_TSS_Adapter ACE_TSS_Adapter *tss_adapter; ACE_NEW (tss_adapter, ACE_TSS_Adapter ((void *)ts_obj, ACE_TSS::cleanup)); // Put the adapter in thread specific storage if (ACE_Thread::setspecific (this->key_, (void *) tss_adapter) != 0) { delete tss_adapter; ACE_ERROR ((LM_ERROR, "%p\n", "ACE_Thread::setspecific() failed!")); } #else if (ACE_Thread::setspecific (this->key_, (void *) ts_obj) != 0) ACE_ERROR ((LM_ERROR, "%p\n", "ACE_Thread::setspecific() failed!")); #endif /* ACE_HAS_THR_C_DEST */ } } template TYPE * ACE_TSS::ts_get (void) const { // Create and initialize thread-specific ts_obj. if (this->once_ == 0) { // Insure that we are serialized! ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, (ACE_Thread_Mutex &) this->keylock_, 0); // Use the Double-Check pattern to make sure we only create the // key once! if (this->once_ == 0) { if (ACE_Thread::keycreate ((ACE_thread_key_t *) &this->key_, #if defined (ACE_HAS_THR_C_DEST) &ACE_TSS_C_cleanup, #else &ACE_TSS::cleanup, #endif /* ACE_HAS_THR_C_DEST */ (void *) this) != 0) return 0; // Major problems, this should *never* happen! else // This *must* come last to avoid race conditions! Note // that we need to "cast away const..." *(int *) &this->once_ = 1; } } TYPE *ts_obj = 0; #if defined (ACE_HAS_THR_C_DEST) ACE_TSS_Adapter *tss_adapter = 0; // Get the adapter from thread-specific storage if (ACE_Thread::getspecific (this->key_, (void **) &tss_adapter) == -1) return 0; // This should not happen! // Check to see if this is the first time in for this thread. if (tss_adapter == 0) #else // Get the ts_obj from thread-specific storage. Note that no locks // are required here... if (ACE_Thread::getspecific (this->key_, (void **) &ts_obj) == -1) return 0; // This should not happen! // Check to see if this is the first time in for this thread. if (ts_obj == 0) #endif /* ACE_HAS_THR_C_DEST */ { // Allocate memory off the heap and store it in a pointer in // thread-specific storage (on the stack...). ts_obj = this->make_TSS_TYPE (); if (ts_obj == 0) return 0; #if defined (ACE_HAS_THR_C_DEST) // Encapsulate a ts_obj and it's destructor in an ACE_TSS_Adapter ACE_NEW_RETURN (tss_adapter, ACE_TSS_Adapter (ts_obj, ACE_TSS::cleanup), 0); // Put the adapter in thread specific storage if (ACE_Thread::setspecific (this->key_, (void *) tss_adapter) != 0) { delete tss_adapter; delete ts_obj; return 0; // Major problems, this should *never* happen! } #else // Store the dynamically allocated pointer in thread-specific // storage. if (ACE_Thread::setspecific (this->key_, (void *) ts_obj) != 0) { delete ts_obj; return 0; // Major problems, this should *never* happen! } #endif /* ACE_HAS_THR_C_DEST */ } #if defined (ACE_HAS_THR_C_DEST) return (TYPE *) tss_adapter->ts_obj_; // return the underlying ts object #else return ts_obj; #endif /* ACE_HAS_THR_C_DEST */ } // Get the thread-specific object for the key associated with this // object. Returns 0 if the ts_obj has never been initialized, // otherwise returns a pointer to the ts_obj. template TYPE * ACE_TSS::ts_object (void) const { // Ensure that we are serialized! ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, (ACE_Thread_Mutex &) this->keylock_, 0); if (this->once_ == 0) // Return 0 if we've never been initialized. return 0; else { TYPE *ts_obj = 0; #if defined (ACE_HAS_THR_C_DEST) ACE_TSS_Adapter *tss_adapter = 0; // Get the tss adapter from thread-specific storage if (ACE_Thread::getspecific (this->key_, (void **) &tss_adapter) == -1) return 0; // This should not happen! else if (tss_adapter != 0) // Extract the real TS object. ts_obj = (TYPE *) tss_adapter->ts_obj_; #else if (ACE_Thread::getspecific (this->key_, (void **) &ts_obj) == -1) return 0; // This should not happen! #endif /* ACE_HAS_THR_C_DEST */ return ts_obj; } } template TYPE * ACE_TSS::ts_object (TYPE *new_ts_obj) { // Ensure that we are serialized! ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->keylock_, 0); if (this->once_ == 0) // Return 0 if we've never been initialized. return 0; else { TYPE *ts_obj = 0; #if defined (ACE_HAS_THR_C_DEST) ACE_TSS_Adapter *tss_adapter = 0; if (ACE_Thread::getspecific (this->key_, (void **) &tss_adapter) == -1) return 0; // This should not happen! if (tss_adapter != 0) { ts_obj = (TYPE *) tss_adapter->ts_obj_; delete tss_adapter; // don't need this anymore } ACE_NEW_RETURN (tss_adapter, ACE_TSS_Adapter ((void *)new_ts_obj, ACE_TSS::cleanup), 0); if (ACE_Thread::setspecific (this->key_, (void *) tss_adapter) == -1) { delete tss_adapter; return ts_obj; // This should not happen! } #else if (ACE_Thread::getspecific (this->key_, (void **) &ts_obj) == -1) return 0; // This should not happen! if (ACE_Thread::setspecific (this->key_, (void *) new_ts_obj) == -1) return ts_obj; // This should not happen! #endif /* ACE_HAS_THR_C_DEST */ else return ts_obj; } } ACE_ALLOC_HOOK_DEFINE(ACE_TSS_Guard) template void ACE_TSS_Guard::dump (void) const { // ACE_TRACE ("ACE_TSS_Guard::dump"); ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); ACE_DEBUG ((LM_DEBUG, "key_ = %d", this->key_)); ACE_DEBUG ((LM_DEBUG, "\n")); ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); } template void ACE_TSS_Guard::init_key (void) { // ACE_TRACE ("ACE_TSS_Guard::init_key"); this->key_ = ACE_OS::NULL_key; ACE_Thread::keycreate (&this->key_, #if defined (ACE_HAS_THR_C_DEST) &ACE_TSS_C_cleanup, #else &ACE_TSS_Guard::cleanup, #endif /* ACE_HAS_THR_C_DEST */ (void *) this); } template ACE_TSS_Guard::ACE_TSS_Guard (void) { // ACE_TRACE ("ACE_TSS_Guard::ACE_TSS_Guard"); this->init_key (); } template int ACE_TSS_Guard::release (void) { // ACE_TRACE ("ACE_TSS_Guard::release"); ACE_Guard *guard = 0; #if defined (ACE_HAS_THR_C_DEST) ACE_TSS_Adapter *tss_adapter = 0; ACE_Thread::getspecific (this->key_, (void **) &tss_adapter); guard = (ACE_Guard *)tss_adapter->ts_obj_; #else ACE_Thread::getspecific (this->key_, (void **) &guard); #endif /* ACE_HAS_THR_C_DEST */ return guard->release (); } template int ACE_TSS_Guard::remove (void) { // ACE_TRACE ("ACE_TSS_Guard::remove"); ACE_Guard *guard = 0; #if defined (ACE_HAS_THR_C_DEST) ACE_TSS_Adapter *tss_adapter = 0; ACE_Thread::getspecific (this->key_, (void **) &tss_adapter); guard = (ACE_Guard *)tss_adapter->ts_obj_; #else ACE_Thread::getspecific (this->key_, (void **) &guard); #endif /* ACE_HAS_THR_C_DEST */ return guard->remove (); } template ACE_TSS_Guard::~ACE_TSS_Guard (void) { // ACE_TRACE ("ACE_TSS_Guard::~ACE_TSS_Guard"); ACE_Guard *guard = 0; #if defined (ACE_HAS_THR_C_DEST) ACE_TSS_Adapter *tss_adapter = 0; ACE_Thread::getspecific (this->key_, (void **) &tss_adapter); guard = (ACE_Guard *)tss_adapter->ts_obj_; #else ACE_Thread::getspecific (this->key_, (void **) &guard); #endif /* ACE_HAS_THR_C_DEST */ // Make sure that this pointer is NULL when we shut down... ACE_Thread::setspecific (this->key_, 0); ACE_Thread::keyfree (this->key_); // Destructor releases lock. delete guard; } template void ACE_TSS_Guard::cleanup (void *ptr) { // ACE_TRACE ("ACE_TSS_Guard::dump"); // Destructor releases lock. delete (ACE_Guard *) ptr; } template ACE_TSS_Guard::ACE_TSS_Guard (LOCK &lock, int block) { // ACE_TRACE ("ACE_TSS_Guard::ACE_TSS_Guard"); this->init_key (); ACE_Guard *guard; ACE_NEW (guard, ACE_Guard (lock, block)); #if defined (ACE_HAS_THR_C_DEST) ACE_TSS_Adapter *tss_adapter; ACE_NEW (tss_adapter, ACE_TSS_Adapter ((void *) guard, ACE_TSS_Guard::cleanup)); ACE_Thread::setspecific (this->key_, (void *) tss_adapter); #else ACE_Thread::setspecific (this->key_, (void *) guard); #endif /* ACE_HAS_THR_C_DEST */ } template int ACE_TSS_Guard::acquire (void) { // ACE_TRACE ("ACE_TSS_Guard::acquire"); ACE_Guard *guard = 0; #if defined (ACE_HAS_THR_C_DEST) ACE_TSS_Adapter *tss_adapter = 0; ACE_Thread::getspecific (this->key_, (void **) &tss_adapter); guard = (ACE_Guard *) tss_adapter->ts_obj_; #else ACE_Thread::getspecific (this->key_, (void **) &guard); #endif /* ACE_HAS_THR_C_DEST */ return guard->acquire (); } template int ACE_TSS_Guard::tryacquire (void) { // ACE_TRACE ("ACE_TSS_Guard::tryacquire"); ACE_Guard *guard = 0; #if defined (ACE_HAS_THR_C_DEST) ACE_TSS_Adapter *tss_adapter = 0; ACE_Thread::getspecific (this->key_, (void **) &tss_adapter); guard = (ACE_Guard *) tss_adapter->ts_obj_; #else ACE_Thread::getspecific (this->key_, (void **) &guard); #endif /* ACE_HAS_THR_C_DEST */ return guard->tryacquire (); } template ACE_TSS_Write_Guard::ACE_TSS_Write_Guard (LOCK &lock, int block) { // ACE_TRACE ("ACE_TSS_Write_Guard::ACE_TSS_Write_Guard"); this->init_key (); ACE_Guard *guard; ACE_NEW (guard, ACE_Write_Guard (lock, block)); #if defined (ACE_HAS_THR_C_DEST) ACE_TSS_Adapter *tss_adapter; ACE_NEW (tss_adapter, ACE_TSS_Adapter ((void *) guard, ACE_TSS_Guard::cleanup)); ACE_Thread::setspecific (this->key_, (void *) tss_adapter); #else ACE_Thread::setspecific (this->key_, (void *) guard); #endif /* ACE_HAS_THR_C_DEST */ } template int ACE_TSS_Write_Guard::acquire (void) { // ACE_TRACE ("ACE_TSS_Write_Guard::acquire"); ACE_Write_Guard *guard = 0; #if defined (ACE_HAS_THR_C_DEST) ACE_TSS_Adapter *tss_adapter = 0; ACE_Thread::getspecific (this->key_, (void **) &tss_adapter); guard = (ACE_Guard *) tss_adapter->ts_obj_; #else ACE_Thread::getspecific (this->key_, (void **) &guard); #endif /* ACE_HAS_THR_C_DEST */ return guard->acquire_write (); } template int ACE_TSS_Write_Guard::tryacquire (void) { // ACE_TRACE ("ACE_TSS_Write_Guard::tryacquire"); ACE_Write_Guard *guard = 0; #if defined (ACE_HAS_THR_C_DEST) ACE_TSS_Adapter *tss_adapter = 0; ACE_Thread::getspecific (this->key_, (void **) &tss_adapter); guard = (ACE_Guard *) tss_adapter->ts_obj_; #else ACE_Thread::getspecific (this->key_, (void **) &guard); #endif /* ACE_HAS_THR_C_DEST */ return guard->tryacquire_write (); } template int ACE_TSS_Write_Guard::acquire_write (void) { // ACE_TRACE ("ACE_TSS_Write_Guard::acquire_write"); return this->acquire (); } template int ACE_TSS_Write_Guard::tryacquire_write (void) { // ACE_TRACE ("ACE_TSS_Write_Guard::tryacquire_write"); return this->tryacquire (); } template void ACE_TSS_Write_Guard::dump (void) const { // ACE_TRACE ("ACE_TSS_Write_Guard::dump"); ACE_TSS_Guard::dump (); } template ACE_TSS_Read_Guard::ACE_TSS_Read_Guard (LOCK &lock, int block) { // ACE_TRACE ("ACE_TSS_Read_Guard::ACE_TSS_Read_Guard"); this->init_key (); ACE_Guard *guard; ACE_NEW (guard, ACE_Read_Guard (lock, block)); #if defined (ACE_HAS_THR_C_DEST) ACE_TSS_Adapter *tss_adapter; ACE_NEW (tss_adapter, ACE_TSS_Adapter ((void *)guard, ACE_TSS_Guard::cleanup)); ACE_Thread::setspecific (this->key_, (void *) tss_adapter); #else ACE_Thread::setspecific (this->key_, (void *) guard); #endif /* ACE_HAS_THR_C_DEST */ } template int ACE_TSS_Read_Guard::acquire (void) { // ACE_TRACE ("ACE_TSS_Read_Guard::acquire"); ACE_Read_Guard *guard = 0; #if defined (ACE_HAS_THR_C_DEST) ACE_TSS_Adapter *tss_adapter = 0; ACE_Thread::getspecific (this->key_, (void **) &tss_adapter); guard = (ACE_Guard *)tss_adapter->ts_obj_; #else ACE_Thread::getspecific (this->key_, (void **) &guard); #endif /* ACE_HAS_THR_C_DEST */ return guard->acquire_read (); } template int ACE_TSS_Read_Guard::tryacquire (void) { // ACE_TRACE ("ACE_TSS_Read_Guard::tryacquire"); ACE_Read_Guard *guard = 0; #if defined (ACE_HAS_THR_C_DEST) ACE_TSS_Adapter *tss_adapter = 0; ACE_Thread::getspecific (this->key_, (void **) &tss_adapter); guard = (ACE_Guard *) tss_adapter->ts_obj_; #else ACE_Thread::getspecific (this->key_, (void **) &guard); #endif /* ACE_HAS_THR_C_DEST */ return guard->tryacquire_read (); } template int ACE_TSS_Read_Guard::acquire_read (void) { // ACE_TRACE ("ACE_TSS_Read_Guard::acquire_read"); return this->acquire (); } template int ACE_TSS_Read_Guard::tryacquire_read (void) { // ACE_TRACE ("ACE_TSS_Read_Guard::tryacquire_read"); return this->tryacquire (); } template void ACE_TSS_Read_Guard::dump (void) const { // ACE_TRACE ("ACE_TSS_Read_Guard::dump"); ACE_TSS_Guard::dump (); } #endif /* defined (ACE_HAS_THREADS) && defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) */ #endif /* ACE_SYNCH_T_C */