/dep/acelite/ace/OS_NS_Thread.cpp
C++ | 1709 lines | 1221 code | 219 blank | 269 comment | 312 complexity | d92194fc64c9407eb015a8ad7a6c046e MD5 | raw file
- // $Id: OS_NS_Thread.cpp 91693 2010-09-09 12:57:54Z johnnyw $
- #include "ace/OS_NS_Thread.h"
- #if !defined (ACE_HAS_INLINED_OSCALLS)
- # include "ace/OS_NS_Thread.inl"
- #endif /* ACE_HAS_INLINED_OSCALLS */
- #include "ace/OS_NS_stdio.h"
- #include "ace/Sched_Params.h"
- #include "ace/OS_Memory.h"
- #include "ace/OS_Thread_Adapter.h"
- #include "ace/Min_Max.h"
- #include "ace/Object_Manager_Base.h"
- #include "ace/OS_NS_errno.h"
- #include "ace/OS_NS_ctype.h"
- #include "ace/Log_Msg.h" // for ACE_ASSERT
- // This is necessary to work around nasty problems with MVS C++.
- #include "ace/Auto_Ptr.h"
- #include "ace/Thread_Mutex.h"
- #include "ace/Condition_T.h"
- #include "ace/Guard_T.h"
- extern "C" void
- ACE_MUTEX_LOCK_CLEANUP_ADAPTER_NAME (void *args)
- {
- ACE_VERSIONED_NAMESPACE_NAME::ACE_OS::mutex_lock_cleanup (args);
- }
- #if !defined(ACE_WIN32) && defined (__IBMCPP__) && (__IBMCPP__ >= 400)
- # define ACE_BEGINTHREADEX(STACK, STACKSIZE, ENTRY_POINT, ARGS, FLAGS, THR_ID) \
- (*THR_ID = ::_beginthreadex ((void(_Optlink*)(void*))ENTRY_POINT, STACK, STACKSIZE, ARGS), *THR_ID)
- #elif defined (ACE_HAS_WINCE)
- # define ACE_BEGINTHREADEX(STACK, STACKSIZE, ENTRY_POINT, ARGS, FLAGS, THR_ID) \
- CreateThread (0, STACKSIZE, (unsigned long (__stdcall *) (void *)) ENTRY_POINT, ARGS, (FLAGS) & (CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION), (unsigned long *) THR_ID)
- #elif defined(ACE_HAS_WTHREADS)
- // Green Hills compiler gets confused when __stdcall is imbedded in
- // parameter list, so we define the type ACE_WIN32THRFUNC_T and use it
- // instead.
- typedef unsigned (__stdcall *ACE_WIN32THRFUNC_T)(void*);
- # define ACE_BEGINTHREADEX(STACK, STACKSIZE, ENTRY_POINT, ARGS, FLAGS, THR_ID) \
- ::_beginthreadex (STACK, STACKSIZE, (ACE_WIN32THRFUNC_T) ENTRY_POINT, ARGS, FLAGS, (unsigned int *) THR_ID)
- #endif /* defined (__IBMCPP__) && (__IBMCPP__ >= 400) */
- /*****************************************************************************/
- ACE_BEGIN_VERSIONED_NAMESPACE_DECL
- void
- ACE_Thread_ID::to_string (char *thr_string) const
- {
- char format[128]; // Converted format string
- char *fp = 0; // Current format pointer
- fp = format;
- *fp++ = '%'; // Copy in the %
- #if defined (ACE_WIN32)
- ACE_OS::strcpy (fp, "u");
- ACE_OS::sprintf (thr_string,
- format,
- static_cast <unsigned> (this->thread_id_));
- #else
- # if defined (ACE_MVS) || defined (ACE_TANDEM_T1248_PTHREADS)
- // MVS's pthread_t is a struct... yuck. So use the ACE 5.0
- // code for it.
- ACE_OS::strcpy (fp, "u");
- ACE_OS::sprintf (thr_string, format, thread_handle_);
- # else
- // Yes, this is an ugly C-style cast, but the
- // correct C++ cast is different depending on
- // whether the t_id is an integral type or a pointer
- // type. FreeBSD uses a pointer type, but doesn't
- // have a _np function to get an integral type, like
- // the OSes above.
- ACE_OS::strcpy (fp, "lu");
- ACE_OS::sprintf (thr_string,
- format,
- (unsigned long) thread_handle_);
- # endif /* ACE_MVS || ACE_TANDEM_T1248_PTHREADS */
- #endif /* ACE_WIN32 */
- }
- /*****************************************************************************/
- #if defined (ACE_WIN32) || defined (ACE_HAS_TSS_EMULATION)
- #if defined (ACE_HAS_TSS_EMULATION)
- u_int ACE_TSS_Emulation::total_keys_ = 0;
- ACE_TSS_Keys* ACE_TSS_Emulation::tss_keys_used_ = 0;
- ACE_TSS_Emulation::ACE_TSS_DESTRUCTOR
- ACE_TSS_Emulation::tss_destructor_[ACE_TSS_Emulation::ACE_TSS_THREAD_KEYS_MAX]
- = { 0 };
- # if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE)
- bool ACE_TSS_Emulation::key_created_ = false;
- ACE_OS_thread_key_t ACE_TSS_Emulation::native_tss_key_;
- /* static */
- # if defined (ACE_HAS_THR_C_FUNC)
- extern "C"
- void
- ACE_TSS_Emulation_cleanup (void *)
- {
- // Really this must be used for ACE_TSS_Emulation code to make the TSS
- // cleanup
- }
- # else
- void
- ACE_TSS_Emulation_cleanup (void *)
- {
- // Really this must be used for ACE_TSS_Emulation code to make the TSS
- // cleanup
- }
- # endif /* ACE_HAS_THR_C_FUNC */
- void **
- ACE_TSS_Emulation::tss_base (void* ts_storage[], u_int *ts_created)
- {
- // TSS Singleton implementation.
- // Create the one native TSS key, if necessary.
- if (!key_created_)
- {
- // Double-checked lock . . .
- ACE_TSS_BASE_GUARD
- if (!key_created_)
- {
- ACE_NO_HEAP_CHECK;
- if (ACE_OS::thr_keycreate_native (&native_tss_key_,
- &ACE_TSS_Emulation_cleanup) != 0)
- {
- ACE_ASSERT (0);
- return 0; // Major problems, this should *never* happen!
- }
- key_created_ = true;
- }
- }
- void **old_ts_storage = 0;
- // Get the tss_storage from thread-OS specific storage.
- if (ACE_OS::thr_getspecific_native (native_tss_key_,
- (void **) &old_ts_storage) == -1)
- {
- ACE_ASSERT (false);
- return 0; // This should not happen!
- }
- // Check to see if this is the first time in for this thread.
- // This block can also be entered after a fork () in the child process.
- if (old_ts_storage == 0)
- {
- if (ts_created)
- *ts_created = 1u;
- // Use the ts_storage passed as argument, if non-zero. It is
- // possible that this has been implemented in the stack. At the
- // moment, this is unknown. The cleanup must not do nothing.
- // If ts_storage is zero, allocate (and eventually leak) the
- // storage array.
- if (ts_storage == 0)
- {
- ACE_NO_HEAP_CHECK;
- ACE_NEW_RETURN (ts_storage,
- void*[ACE_TSS_THREAD_KEYS_MAX],
- 0);
- // Zero the entire TSS array. Do it manually instead of
- // using memset, for optimum speed. Though, memset may be
- // faster :-)
- void **tss_base_p = ts_storage;
- for (u_int i = 0;
- i < ACE_TSS_THREAD_KEYS_MAX;
- ++i)
- *tss_base_p++ = 0;
- }
- // Store the pointer in thread-specific storage. It gets
- // deleted via the ACE_TSS_Emulation_cleanup function when the
- // thread terminates.
- if (ACE_OS::thr_setspecific_native (native_tss_key_,
- (void *) ts_storage) != 0)
- {
- ACE_ASSERT (false);
- return 0; // This should not happen!
- }
- }
- else
- if (ts_created)
- ts_created = 0;
- return ts_storage ? ts_storage : old_ts_storage;
- }
- # endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE */
- u_int
- ACE_TSS_Emulation::total_keys ()
- {
- ACE_OS_Recursive_Thread_Mutex_Guard (
- *static_cast <ACE_recursive_thread_mutex_t *>
- (ACE_OS_Object_Manager::preallocated_object[
- ACE_OS_Object_Manager::ACE_TSS_KEY_LOCK]));
- return total_keys_;
- }
- int
- ACE_TSS_Emulation::next_key (ACE_thread_key_t &key)
- {
- ACE_OS_Recursive_Thread_Mutex_Guard (
- *static_cast <ACE_recursive_thread_mutex_t *>
- (ACE_OS_Object_Manager::preallocated_object[
- ACE_OS_Object_Manager::ACE_TSS_KEY_LOCK]));
- // Initialize the tss_keys_used_ pointer on first use.
- if (tss_keys_used_ == 0)
- {
- ACE_NEW_RETURN (tss_keys_used_, ACE_TSS_Keys, -1);
- }
- if (total_keys_ < ACE_TSS_THREAD_KEYS_MAX)
- {
- u_int counter = 0;
- // Loop through all possible keys and check whether a key is free
- for ( ;counter < ACE_TSS_THREAD_KEYS_MAX; counter++)
- {
- ACE_thread_key_t localkey;
- # if defined (ACE_HAS_NONSCALAR_THREAD_KEY_T)
- ACE_OS::memset (&localkey, 0, sizeof (ACE_thread_key_t));
- ACE_OS::memcpy (&localkey, &counter_, sizeof (u_int));
- # else
- localkey = counter;
- # endif /* ACE_HAS_NONSCALAR_THREAD_KEY_T */
- // If the key is not set as used, we can give out this key, if not
- // we have to search further
- if (tss_keys_used_->is_set(localkey) == 0)
- {
- tss_keys_used_->test_and_set(localkey);
- key = localkey;
- break;
- }
- }
- ++total_keys_;
- return 0;
- }
- else
- {
- key = ACE_OS::NULL_key;
- return -1;
- }
- }
- int
- ACE_TSS_Emulation::release_key (ACE_thread_key_t key)
- {
- ACE_OS_Recursive_Thread_Mutex_Guard (
- *static_cast <ACE_recursive_thread_mutex_t *>
- (ACE_OS_Object_Manager::preallocated_object[
- ACE_OS_Object_Manager::ACE_TSS_KEY_LOCK]));
- if (tss_keys_used_ != 0 &&
- tss_keys_used_->test_and_clear (key) == 0)
- {
- --total_keys_;
- return 0;
- }
- return 1;
- }
- int
- ACE_TSS_Emulation::is_key (ACE_thread_key_t key)
- {
- ACE_OS_Recursive_Thread_Mutex_Guard (
- *static_cast <ACE_recursive_thread_mutex_t *>
- (ACE_OS_Object_Manager::preallocated_object[
- ACE_OS_Object_Manager::ACE_TSS_KEY_LOCK]));
- if (tss_keys_used_ != 0 &&
- tss_keys_used_->is_set (key) == 1)
- {
- return 1;
- }
- return 0;
- }
- void *
- ACE_TSS_Emulation::tss_open (void *ts_storage[ACE_TSS_THREAD_KEYS_MAX])
- {
- # if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE)
- // On VxWorks, in particular, don't check to see if the field
- // is 0. It isn't always, specifically, when a program is run
- // directly by the shell (without spawning a new task) after
- // another program has been run.
- u_int ts_created = 0;
- tss_base (ts_storage, &ts_created);
- if (ts_created)
- {
- # else /* ! ACE_HAS_THREAD_SPECIFIC_STORAGE */
- tss_base () = ts_storage;
- # endif
- // Zero the entire TSS array. Do it manually instead of using
- // memset, for optimum speed. Though, memset may be faster :-)
- void **tss_base_p = tss_base ();
- for (u_int i = 0; i < ACE_TSS_THREAD_KEYS_MAX; ++i, ++tss_base_p)
- {
- *tss_base_p = 0;
- }
- return tss_base ();
- # if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE)
- }
- else
- {
- return 0;
- }
- # endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE */
- }
- void
- ACE_TSS_Emulation::tss_close ()
- {
- #if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE)
- ACE_OS::thr_keyfree_native (native_tss_key_);
- #endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE */
- }
- #endif /* ACE_HAS_TSS_EMULATION */
- #endif /* WIN32 || ACE_HAS_TSS_EMULATION */
- /*****************************************************************************/
- #if defined (ACE_WIN32) || defined (ACE_HAS_TSS_EMULATION)
- // Moved class ACE_TSS_Ref declaration to OS.h so it can be visible to
- // the single file of template instantiations.
- ACE_TSS_Ref::ACE_TSS_Ref (ACE_thread_t id)
- : tid_(id)
- {
- ACE_OS_TRACE ("ACE_TSS_Ref::ACE_TSS_Ref");
- }
- ACE_TSS_Ref::ACE_TSS_Ref (void)
- {
- ACE_OS_TRACE ("ACE_TSS_Ref::ACE_TSS_Ref");
- }
- // Check for equality.
- bool
- ACE_TSS_Ref::operator== (const ACE_TSS_Ref &info) const
- {
- ACE_OS_TRACE ("ACE_TSS_Ref::operator==");
- return this->tid_ == info.tid_;
- }
- // Check for inequality.
- ACE_SPECIAL_INLINE
- bool
- ACE_TSS_Ref::operator != (const ACE_TSS_Ref &tss_ref) const
- {
- ACE_OS_TRACE ("ACE_TSS_Ref::operator !=");
- return !(*this == tss_ref);
- }
- // moved class ACE_TSS_Info declaration
- // to OS.h so it can be visible to the
- // single file of template instantiations
- ACE_TSS_Info::ACE_TSS_Info (ACE_thread_key_t key,
- ACE_TSS_Info::Destructor dest)
- : key_ (key),
- destructor_ (dest),
- thread_count_ (-1)
- {
- ACE_OS_TRACE ("ACE_TSS_Info::ACE_TSS_Info");
- }
- ACE_TSS_Info::ACE_TSS_Info (void)
- : key_ (ACE_OS::NULL_key),
- destructor_ (0),
- thread_count_ (-1)
- {
- ACE_OS_TRACE ("ACE_TSS_Info::ACE_TSS_Info");
- }
- # if defined (ACE_HAS_NONSCALAR_THREAD_KEY_T)
- static inline bool operator== (const ACE_thread_key_t &lhs,
- const ACE_thread_key_t &rhs)
- {
- return ! ACE_OS::memcmp (&lhs, &rhs, sizeof (ACE_thread_key_t));
- }
- static inline bool operator!= (const ACE_thread_key_t &lhs,
- const ACE_thread_key_t &rhs)
- {
- return ! (lhs == rhs);
- }
- # endif /* ACE_HAS_NONSCALAR_THREAD_KEY_T */
- // Check for equality.
- bool
- ACE_TSS_Info::operator== (const ACE_TSS_Info &info) const
- {
- ACE_OS_TRACE ("ACE_TSS_Info::operator==");
- return this->key_ == info.key_;
- }
- // Check for inequality.
- bool
- ACE_TSS_Info::operator != (const ACE_TSS_Info &info) const
- {
- ACE_OS_TRACE ("ACE_TSS_Info::operator !=");
- return !(*this == info);
- }
- void
- ACE_TSS_Info::dump (void)
- {
- # if defined (ACE_HAS_DUMP)
- // ACE_OS_TRACE ("ACE_TSS_Info::dump");
- # if 0
- ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
- ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("key_ = %u\n"), this->key_));
- ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("destructor_ = %u\n"), this->destructor_));
- ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
- # endif /* 0 */
- # endif /* ACE_HAS_DUMP */
- }
- // Moved class ACE_TSS_Keys declaration to OS.h so it can be visible
- // to the single file of template instantiations.
- ACE_TSS_Keys::ACE_TSS_Keys (void)
- {
- for (u_int i = 0; i < ACE_WORDS; ++i)
- {
- key_bit_words_[i] = 0;
- }
- }
- ACE_SPECIAL_INLINE
- void
- ACE_TSS_Keys::find (const u_int key, u_int &word, u_int &bit)
- {
- word = key / ACE_BITS_PER_WORD;
- bit = key % ACE_BITS_PER_WORD;
- }
- int
- ACE_TSS_Keys::test_and_set (const ACE_thread_key_t key)
- {
- ACE_KEY_INDEX (key_index, key);
- u_int word, bit;
- find (key_index, word, bit);
- if (ACE_BIT_ENABLED (key_bit_words_[word], 1 << bit))
- {
- return 1;
- }
- else
- {
- ACE_SET_BITS (key_bit_words_[word], 1 << bit);
- return 0;
- }
- }
- int
- ACE_TSS_Keys::test_and_clear (const ACE_thread_key_t key)
- {
- ACE_KEY_INDEX (key_index, key);
- u_int word, bit;
- find (key_index, word, bit);
- if (word < ACE_WORDS && ACE_BIT_ENABLED (key_bit_words_[word], 1 << bit))
- {
- ACE_CLR_BITS (key_bit_words_[word], 1 << bit);
- return 0;
- }
- else
- {
- return 1;
- }
- }
- int
- ACE_TSS_Keys::is_set (const ACE_thread_key_t key) const
- {
- ACE_KEY_INDEX (key_index, key);
- u_int word, bit;
- find (key_index, word, bit);
- return word < ACE_WORDS ? ACE_BIT_ENABLED (key_bit_words_[word], 1 << bit) : 0;
- }
- /**
- * @class ACE_TSS_Cleanup
- * @brief Singleton that helps to manage the lifetime of TSS objects and keys.
- */
- class ACE_TSS_Cleanup
- {
- public:
- /// Register a newly-allocated key
- /// @param key the key to be monitored
- /// @param destructor the function to call to delete objects stored via this key
- int insert (ACE_thread_key_t key, void (*destructor)(void *));
- /// Mark a key as being used by this thread.
- void thread_use_key (ACE_thread_key_t key);
- /// This thread is no longer using this key
- /// call destructor if appropriate
- int thread_detach_key (ACE_thread_key_t key);
- /// This key is no longer used
- /// Release key if use count == 0
- /// fail if use_count != 0;
- /// @param key the key to be released
- int free_key (ACE_thread_key_t key);
- /// Cleanup the thread-specific objects. Does _NOT_ exit the thread.
- /// For each used key perform the same actions as free_key.
- void thread_exit (void);
- private:
- void dump (void);
- /// Release a key used by this thread
- /// @param info reference to the info for this key
- /// @param destructor out arg to receive destructor function ptr
- /// @param tss_obj out arg to receive pointer to deletable object
- void thread_release (
- ACE_TSS_Info &info,
- ACE_TSS_Info::Destructor & destructor,
- void *& tss_obj);
- /// remove key if it's unused (thread_count == 0)
- /// @param info reference to the info for this key
- int remove_key (ACE_TSS_Info &info);
- /// Find the TSS keys (if any) for this thread.
- /// @param thread_keys reference to pointer to be filled in by this function.
- /// @return false if keys don't exist.
- bool find_tss_keys (ACE_TSS_Keys *& thread_keys) const;
- /// Accessor for this threads ACE_TSS_Keys instance.
- /// Creates the keys if necessary.
- ACE_TSS_Keys *tss_keys ();
- /// Ensure singleton.
- ACE_TSS_Cleanup (void);
- ~ACE_TSS_Cleanup (void);
- /// ACE_TSS_Cleanup access only via TSS_Cleanup_Instance
- friend class TSS_Cleanup_Instance;
- private:
- // Array of <ACE_TSS_Info> objects.
- typedef ACE_TSS_Info ACE_TSS_TABLE[ACE_DEFAULT_THREAD_KEYS];
- typedef ACE_TSS_Info *ACE_TSS_TABLE_ITERATOR;
- /// Table of <ACE_TSS_Info>'s.
- ACE_TSS_TABLE table_;
- /// Key for the thread-specific ACE_TSS_Keys
- /// Used by find_tss_keys() or tss_keys() to find the
- /// bit array that records whether each TSS key is in
- /// use by this thread.
- ACE_thread_key_t in_use_;
- };
- /*****************************************************************************/
- /**
- * @class TSS_Cleanup_Instance
- * @A class to manage an instance pointer to ACE_TSS_Cleanup.
- * Note: that the double checked locking pattern doesn't allow
- * safe deletion.
- * Callers who wish to access the singleton ACE_TSS_Cleanup must
- * do so by instantiating a TSS_Cleanup_Instance, calling the valid
- * method to be sure the ACE_TSS_Cleanup is available, then using
- * the TSS_Cleanup_Instance as a pointer to the instance.
- * Construction argument to the TSS_Cleanup_Instance determines how
- * it is to be used:
- * CREATE means allow this call to create an ACE_TSS_Cleanup if necessary.
- * USE means use the existing ACE_TSS_Cleanup, but do not create a new one.
- * DESTROY means provide exclusive access to the ACE_TSS_Cleanup, then
- * delete it when the TSS_Cleanup_Instance goes out of scope.
- */
- class TSS_Cleanup_Instance
- {
- public:
- enum Purpose
- {
- CREATE,
- USE,
- DESTROY
- };
- TSS_Cleanup_Instance (Purpose purpose = USE);
- ~TSS_Cleanup_Instance();
- bool valid();
- ACE_TSS_Cleanup * operator ->();
- private:
- ACE_TSS_Cleanup * operator *();
- private:
- static unsigned int reference_count_;
- static ACE_TSS_Cleanup * instance_;
- static ACE_Thread_Mutex* mutex_;
- static ACE_Thread_Condition<ACE_Thread_Mutex>* condition_;
- private:
- ACE_TSS_Cleanup * ptr_;
- unsigned short flags_;
- enum
- {
- FLAG_DELETING = 1,
- FLAG_VALID_CHECKED = 2
- };
- };
- TSS_Cleanup_Instance::TSS_Cleanup_Instance (Purpose purpose)
- : ptr_(0)
- , flags_(0)
- {
- // During static construction or construction of the ACE_Object_Manager,
- // there can be only one thread in this constructor at any one time, so
- // it's safe to check for a zero mutex_. If it's zero, we create a new
- // mutex and condition variable.
- if (mutex_ == 0)
- {
- ACE_NEW (mutex_, ACE_Thread_Mutex ());
- ACE_NEW (condition_, ACE_Thread_Condition<ACE_Thread_Mutex> (*mutex_));
- }
- ACE_GUARD (ACE_Thread_Mutex, m, *mutex_);
- if (purpose == CREATE)
- {
- if (instance_ == 0)
- {
- instance_ = new ACE_TSS_Cleanup();
- }
- ptr_ = instance_;
- ++reference_count_;
- }
- else if(purpose == DESTROY)
- {
- if (instance_ != 0)
- {
- ptr_ = instance_;
- instance_ = 0;
- ACE_SET_BITS(flags_, FLAG_DELETING);
- while (reference_count_ > 0)
- {
- condition_->wait();
- }
- }
- }
- else // must be normal use
- {
- ACE_ASSERT(purpose == USE);
- if (instance_ != 0)
- {
- ptr_ = instance_;
- ++reference_count_;
- }
- }
- }
- TSS_Cleanup_Instance::~TSS_Cleanup_Instance (void)
- {
- // Variable to hold the mutex_ to delete outside the scope of the
- // guard.
- ACE_Thread_Mutex *del_mutex = 0;
- // scope the guard
- {
- ACE_GUARD (ACE_Thread_Mutex, guard, *mutex_);
- if (ptr_ != 0)
- {
- if (ACE_BIT_ENABLED (flags_, FLAG_DELETING))
- {
- ACE_ASSERT(instance_ == 0);
- ACE_ASSERT(reference_count_ == 0);
- delete ptr_;
- del_mutex = mutex_ ;
- mutex_ = 0;
- }
- else
- {
- ACE_ASSERT (reference_count_ > 0);
- --reference_count_;
- if (reference_count_ == 0 && instance_ == 0)
- condition_->signal ();
- }
- }
- }// end of guard scope
- if (del_mutex != 0)
- {
- delete condition_;
- condition_ = 0;
- delete del_mutex;
- }
- }
- bool
- TSS_Cleanup_Instance::valid()
- {
- ACE_SET_BITS(flags_, FLAG_VALID_CHECKED);
- return (this->instance_ != 0);
- }
- ACE_TSS_Cleanup *
- TSS_Cleanup_Instance::operator *()
- {
- ACE_ASSERT(ACE_BIT_ENABLED(flags_, FLAG_VALID_CHECKED));
- return instance_;
- }
- ACE_TSS_Cleanup *
- TSS_Cleanup_Instance::operator ->()
- {
- ACE_ASSERT(ACE_BIT_ENABLED(flags_, FLAG_VALID_CHECKED));
- return instance_;
- }
- // = Static object initialization.
- unsigned int TSS_Cleanup_Instance::reference_count_ = 0;
- ACE_TSS_Cleanup * TSS_Cleanup_Instance::instance_ = 0;
- ACE_Thread_Mutex* TSS_Cleanup_Instance::mutex_ = 0;
- ACE_Thread_Condition<ACE_Thread_Mutex>* TSS_Cleanup_Instance::condition_ = 0;
- ACE_TSS_Cleanup::~ACE_TSS_Cleanup (void)
- {
- }
- void
- ACE_TSS_Cleanup::thread_exit (void)
- {
- ACE_OS_TRACE ("ACE_TSS_Cleanup::thread_exit");
- // variables to hold the destructors, keys
- // and pointers to the object to be destructed
- // the actual destruction is deferred until the guard is released
- ACE_TSS_Info::Destructor destructor[ACE_DEFAULT_THREAD_KEYS];
- void * tss_obj[ACE_DEFAULT_THREAD_KEYS];
- ACE_thread_key_t keys[ACE_DEFAULT_THREAD_KEYS];
- // count of items to be destroyed
- unsigned int d_count = 0;
- // scope the guard
- {
- ACE_TSS_CLEANUP_GUARD
- // if not initialized or already cleaned up
- ACE_TSS_Keys *this_thread_keys = 0;
- if (! find_tss_keys (this_thread_keys) )
- {
- return;
- }
- // Minor hack: Iterating in reverse order means the LOG buffer which is
- // accidentally allocated first will be accidentally deallocated (almost)
- // last -- in case someone logs something from the other destructors.
- // applications should not count on this behavior because platforms which
- // do not use ACE_TSS_Cleanup may delete objects in other orders.
- unsigned int key_index = ACE_DEFAULT_THREAD_KEYS;
- while( key_index > 0)
- {
- --key_index;
- ACE_TSS_Info & info = this->table_[key_index];
- // if this key is in use by this thread
- if (info.key_in_use () && this_thread_keys->is_set(info.key_))
- {
- // defer deleting the in-use key until all others have been deleted
- if(info.key_ != this->in_use_)
- {
- destructor[d_count] = 0;
- tss_obj[d_count] = 0;
- keys[d_count] = 0;
- this->thread_release (info, destructor[d_count], tss_obj[d_count]);
- if (destructor[d_count] != 0 && tss_obj[d_count] != 0)
- {
- keys[d_count] = info.key_;
- ++d_count;
- }
- }
- }
- }
- // remove the in_use bit vector last
- ACE_KEY_INDEX (use_index, this->in_use_);
- ACE_TSS_Info & info = this->table_[use_index];
- destructor[d_count] = 0;
- tss_obj[d_count] = 0;
- keys[d_count] = 0;
- this->thread_release (info, destructor[d_count], tss_obj[d_count]);
- if (destructor[d_count] != 0 && tss_obj[d_count] != 0)
- {
- keys[d_count] = info.key_;
- ++d_count;
- }
- } // end of guard scope
- for (unsigned int d_index = 0; d_index < d_count; ++d_index)
- {
- (*destructor[d_index])(tss_obj[d_index]);
- #if defined (ACE_HAS_TSS_EMULATION)
- ACE_TSS_Emulation::ts_object (keys[d_index]) = 0;
- #else // defined (ACE_HAS_TSS_EMULATION)
- ACE_OS::thr_setspecific_native (keys[d_index], 0);
- #endif // defined (ACE_HAS_TSS_EMULATION)
- }
- }
- extern "C" void
- ACE_TSS_Cleanup_keys_destroyer (void *tss_keys)
- {
- delete static_cast <ACE_TSS_Keys *> (tss_keys);
- }
- ACE_TSS_Cleanup::ACE_TSS_Cleanup (void)
- : in_use_ (ACE_OS::NULL_key)
- {
- ACE_OS_TRACE ("ACE_TSS_Cleanup::ACE_TSS_Cleanup");
- }
- int
- ACE_TSS_Cleanup::insert (ACE_thread_key_t key,
- void (*destructor)(void *))
- {
- ACE_OS_TRACE ("ACE_TSS_Cleanup::insert");
- ACE_TSS_CLEANUP_GUARD
- ACE_KEY_INDEX (key_index, key);
- ACE_ASSERT (key_index < ACE_DEFAULT_THREAD_KEYS);
- if (key_index < ACE_DEFAULT_THREAD_KEYS)
- {
- ACE_ASSERT (table_[key_index].thread_count_ == -1);
- table_[key_index] = ACE_TSS_Info (key, destructor);
- table_[key_index].thread_count_ = 0; // inserting it does not use it
- // but it does "allocate" it
- return 0;
- }
- else
- {
- return -1;
- }
- }
- int
- ACE_TSS_Cleanup::free_key (ACE_thread_key_t key)
- {
- ACE_OS_TRACE ("ACE_TSS_Cleanup::free_key");
- ACE_TSS_CLEANUP_GUARD
- ACE_KEY_INDEX (key_index, key);
- if (key_index < ACE_DEFAULT_THREAD_KEYS)
- {
- return remove_key (this->table_ [key_index]);
- }
- return -1;
- }
- int
- ACE_TSS_Cleanup::remove_key (ACE_TSS_Info &info)
- {
- // assume CLEANUP_GUARD is held by caller
- ACE_OS_TRACE ("ACE_TSS_Cleanup::remove_key");
- #if 0 // This was a good idea, but POSIX says it's legal to delete used keys.
- // When this is done, any existing TSS objects controlled by this key are leaked
- // There is no "right thing" to do in this case
- // only remove it if all threads are done with it
- if (info.thread_count_ != 0)
- {
- return -1;
- }
- #endif // 0
- #if !defined (ACE_HAS_TSS_EMULATION)
- ACE_OS_thread_key_t temp_key = info.key_;
- ACE_OS::thr_keyfree_native (temp_key);
- #endif /* !ACE_HAS_TSS_EMULATION */
- if (info.key_ == this->in_use_)
- {
- this->in_use_ = ACE_OS::NULL_key;
- }
- info.key_in_use (0);
- info.destructor_ = 0;
- return 0;
- }
- int
- ACE_TSS_Cleanup::thread_detach_key (ACE_thread_key_t key)
- {
- // variables to hold the destructor and the object to be destructed
- // the actual call is deferred until the guard is released
- ACE_TSS_Info::Destructor destructor = 0;
- void * tss_obj = 0;
- // scope the guard
- {
- ACE_TSS_CLEANUP_GUARD
- ACE_KEY_INDEX (key_index, key);
- ACE_ASSERT (key_index < sizeof(this->table_)/sizeof(this->table_[0])
- && this->table_[key_index].key_ == key);
- ACE_TSS_Info &info = this->table_ [key_index];
- // sanity check
- if (!info.key_in_use ())
- {
- return -1;
- }
- this->thread_release (info, destructor, tss_obj);
- } // end of scope for the Guard
- // if there's a destructor and an object to be destroyed
- if (destructor != 0 && tss_obj != 0)
- {
- (*destructor) (tss_obj);
- }
- return 0;
- }
- void
- ACE_TSS_Cleanup::thread_release (
- ACE_TSS_Info &info,
- ACE_TSS_Info::Destructor & destructor,
- void *& tss_obj)
- {
- // assume guard is held by caller
- // Find the TSS keys (if any) for this thread
- // do not create them if they don't exist
- ACE_TSS_Keys * thread_keys = 0;
- if (find_tss_keys (thread_keys))
- {
- // if this key is in use by this thread
- if (thread_keys->test_and_clear(info.key_) == 0)
- {
- // save destructor & pointer to tss object
- // until after the guard is released
- destructor = info.destructor_;
- ACE_OS::thr_getspecific (info.key_, &tss_obj);
- ACE_ASSERT (info.thread_count_ > 0);
- --info.thread_count_;
- }
- }
- }
- void
- ACE_TSS_Cleanup::thread_use_key (ACE_thread_key_t key)
- {
- // If the key's ACE_TSS_Info in-use bit for this thread is not set,
- // set it and increment the key's thread_count_.
- if (! tss_keys ()->test_and_set (key))
- {
- ACE_TSS_CLEANUP_GUARD
- // Retrieve the key's ACE_TSS_Info and increment its thread_count_.
- ACE_KEY_INDEX (key_index, key);
- ACE_TSS_Info &key_info = this->table_ [key_index];
- ACE_ASSERT (key_info.key_in_use ());
- ++key_info.thread_count_;
- }
- }
- void
- ACE_TSS_Cleanup::dump (void)
- {
- # if defined (ACE_HAS_DUMP)
- // Iterate through all the thread-specific items and dump them all.
- ACE_TSS_TABLE_ITERATOR key_info = table_;
- for (unsigned int i = 0;
- i < ACE_DEFAULT_THREAD_KEYS;
- ++key_info, ++i)
- key_info->dump ();
- # endif /* ACE_HAS_DUMP */
- }
- bool
- ACE_TSS_Cleanup::find_tss_keys (ACE_TSS_Keys *& tss_keys) const
- {
- if (this->in_use_ == ACE_OS::NULL_key)
- return false;
- if (ACE_OS::thr_getspecific (in_use_,
- reinterpret_cast<void **> (&tss_keys)) == -1)
- {
- ACE_ASSERT (false);
- return false; // This should not happen!
- }
- return tss_keys != 0;
- }
- ACE_TSS_Keys *
- ACE_TSS_Cleanup::tss_keys ()
- {
- if (this->in_use_ == ACE_OS::NULL_key)
- {
- ACE_TSS_CLEANUP_GUARD
- // Double-check;
- if (in_use_ == ACE_OS::NULL_key)
- {
- // Initialize in_use_ with a new key.
- if (ACE_OS::thr_keycreate (&in_use_,
- &ACE_TSS_Cleanup_keys_destroyer))
- {
- ACE_ASSERT (false);
- return 0; // Major problems, this should *never* happen!
- }
- }
- }
- void *ts_keys = 0;
- if (ACE_OS::thr_getspecific (in_use_, &ts_keys) == -1)
- {
- ACE_ASSERT (false);
- return 0; // This should not happen!
- }
- if (ts_keys == 0)
- {
- ACE_NEW_RETURN (ts_keys,
- ACE_TSS_Keys,
- 0);
- // Store the dynamically allocated pointer in thread-specific
- // storage.
- if (ACE_OS::thr_setspecific (in_use_, ts_keys) == -1)
- {
- ACE_ASSERT (false);
- delete reinterpret_cast <ACE_TSS_Keys*> (ts_keys);
- return 0; // Major problems, this should *never* happen!
- }
- }
- return reinterpret_cast <ACE_TSS_Keys*>(ts_keys);
- }
- #endif /* ACE_WIN32 || ACE_HAS_TSS_EMULATION */
- /*****************************************************************************/
- // = Static initialization.
- // This is necessary to deal with POSIX pthreads insanity. This
- // guarantees that we've got a "zero'd" thread id even when
- // ACE_thread_t, ACE_hthread_t, and ACE_thread_key_t are implemented
- // as structures... Under no circumstances should these be given
- // initial values.
- // Note: these three objects require static construction.
- ACE_thread_t ACE_OS::NULL_thread;
- ACE_hthread_t ACE_OS::NULL_hthread;
- #if defined (ACE_HAS_TSS_EMULATION)
- ACE_thread_key_t ACE_OS::NULL_key = static_cast <ACE_thread_key_t> (-1);
- #else /* ! ACE_HAS_TSS_EMULATION */
- ACE_thread_key_t ACE_OS::NULL_key;
- #endif /* ! ACE_HAS_TSS_EMULATION */
- /*****************************************************************************/
- void
- ACE_OS::cleanup_tss (const u_int main_thread)
- {
- #if defined (ACE_HAS_TSS_EMULATION) || defined (ACE_WIN32)
- { // scope the cleanup instance
- // Call TSS destructors for current thread.
- TSS_Cleanup_Instance cleanup;
- if (cleanup.valid ())
- {
- cleanup->thread_exit ();
- }
- }
- #endif /* ACE_HAS_TSS_EMULATION || ACE_WIN32 */
- if (main_thread)
- {
- #if !defined (ACE_HAS_TSS_EMULATION) && !defined (ACE_HAS_MINIMAL_ACE_OS)
- // Just close the ACE_Log_Msg for the current (which should be
- // main) thread. We don't have TSS emulation; if there's native
- // TSS, it should call its destructors when the main thread
- // exits.
- ACE_Base_Thread_Adapter::close_log_msg ();
- #endif /* ! ACE_HAS_TSS_EMULATION && ! ACE_HAS_MINIMAL_ACE_OS */
- #if defined (ACE_WIN32) || defined (ACE_HAS_TSS_EMULATION)
- // Finally, free up the ACE_TSS_Cleanup instance. This method gets
- // called by the ACE_Object_Manager.
- TSS_Cleanup_Instance cleanup(TSS_Cleanup_Instance::DESTROY);
- if (cleanup.valid ())
- {
- ; // the pointer deletes the Cleanup when it goes out of scope
- }
- #endif /* WIN32 || ACE_HAS_TSS_EMULATION */
- #if defined (ACE_HAS_TSS_EMULATION)
- ACE_TSS_Emulation::tss_close ();
- #endif /* ACE_HAS_TSS_EMULATION */
- }
- }
- /*****************************************************************************/
- // CONDITIONS BEGIN
- /*****************************************************************************/
- #if defined (ACE_LACKS_COND_T)
- int
- ACE_OS::cond_broadcast (ACE_cond_t *cv)
- {
- ACE_OS_TRACE ("ACE_OS::cond_broadcast");
- # if defined (ACE_HAS_THREADS)
- // The <external_mutex> must be locked before this call is made.
- // This is needed to ensure that <waiters_> and <was_broadcast_> are
- // consistent relative to each other.
- if (ACE_OS::thread_mutex_lock (&cv->waiters_lock_) != 0)
- {
- return -1;
- }
- bool have_waiters = false;
- if (cv->waiters_ > 0)
- {
- // We are broadcasting, even if there is just one waiter...
- // Record the fact that we are broadcasting. This helps the
- // cond_wait() method know how to optimize itself. Be sure to
- // set this with the <waiters_lock_> held.
- cv->was_broadcast_ = 1;
- have_waiters = true;
- }
- if (ACE_OS::thread_mutex_unlock (&cv->waiters_lock_) != 0)
- {
- // This is really bad, we have the lock but can't release it anymore
- return -1;
- }
- int result = 0;
- if (have_waiters)
- {
- // Wake up all the waiters.
- if (ACE_OS::sema_post (&cv->sema_, cv->waiters_) == -1)
- result = -1;
- // Wait for all the awakened threads to acquire their part of
- // the counting semaphore.
- # if defined (ACE_VXWORKS)
- else if (ACE_OS::sema_wait (&cv->waiters_done_) == -1)
- # else
- else if (ACE_OS::event_wait (&cv->waiters_done_) == -1)
- # endif /* ACE_VXWORKS */
- result = -1;
- // This is okay, even without the <waiters_lock_> held because
- // no other waiter threads can wake up to access it.
- cv->was_broadcast_ = 0;
- }
- return result;
- # else
- ACE_UNUSED_ARG (cv);
- ACE_NOTSUP_RETURN (-1);
- # endif /* ACE_HAS_THREADS */
- }
- int
- ACE_OS::cond_destroy (ACE_cond_t *cv)
- {
- ACE_OS_TRACE ("ACE_OS::cond_destroy");
- # if defined (ACE_HAS_THREADS)
- # if defined (ACE_HAS_WTHREADS)
- ACE_OS::event_destroy (&cv->waiters_done_);
- # elif defined (ACE_VXWORKS)
- ACE_OS::sema_destroy (&cv->waiters_done_);
- # endif /* ACE_VXWORKS */
- int result = 0;
- if (ACE_OS::thread_mutex_destroy (&cv->waiters_lock_) != 0)
- result = -1;
- if (ACE_OS::sema_destroy (&cv->sema_) != 0)
- result = -1;
- return result;
- # else
- ACE_UNUSED_ARG (cv);
- ACE_NOTSUP_RETURN (-1);
- # endif /* ACE_HAS_THREADS */
- }
- int
- ACE_OS::cond_init (ACE_cond_t *cv,
- ACE_condattr_t &attributes,
- const char *name, void *arg)
- {
- return
- ACE_OS::cond_init (cv, static_cast<short> (attributes.type), name, arg);
- }
- # if defined (ACE_HAS_WCHAR)
- int
- ACE_OS::cond_init (ACE_cond_t *cv,
- ACE_condattr_t &attributes,
- const wchar_t *name, void *arg)
- {
- return
- ACE_OS::cond_init (cv, static_cast<short> (attributes.type), name, arg);
- }
- # endif /* ACE_HAS_WCHAR */
- int
- ACE_OS::cond_init (ACE_cond_t *cv, short type, const char *name, void *arg)
- {
- ACE_OS_TRACE ("ACE_OS::cond_init");
- # if defined (ACE_HAS_THREADS)
- cv->waiters_ = 0;
- cv->was_broadcast_ = 0;
- int result = 0;
- if (ACE_OS::sema_init (&cv->sema_, 0, type, name, arg) == -1)
- result = -1;
- else if (ACE_OS::thread_mutex_init (&cv->waiters_lock_) == -1)
- result = -1;
- # if defined (ACE_VXWORKS)
- else if (ACE_OS::sema_init (&cv->waiters_done_, 0, type) == -1)
- # else
- else if (ACE_OS::event_init (&cv->waiters_done_) == -1)
- # endif /* ACE_VXWORKS */
- result = -1;
- return result;
- # else
- ACE_UNUSED_ARG (cv);
- ACE_UNUSED_ARG (type);
- ACE_UNUSED_ARG (name);
- ACE_UNUSED_ARG (arg);
- ACE_NOTSUP_RETURN (-1);
- # endif /* ACE_HAS_THREADS */
- }
- # if defined (ACE_HAS_WCHAR)
- int
- ACE_OS::cond_init (ACE_cond_t *cv, short type, const wchar_t *name, void *arg)
- {
- ACE_OS_TRACE ("ACE_OS::cond_init");
- # if defined (ACE_HAS_THREADS)
- cv->waiters_ = 0;
- cv->was_broadcast_ = 0;
- int result = 0;
- if (ACE_OS::sema_init (&cv->sema_, 0, type, name, arg) == -1)
- result = -1;
- else if (ACE_OS::thread_mutex_init (&cv->waiters_lock_) == -1)
- result = -1;
- # if defined (ACE_VXWORKS)
- else if (ACE_OS::sema_init (&cv->waiters_done_, 0, type) == -1)
- # else
- else if (ACE_OS::event_init (&cv->waiters_done_) == -1)
- # endif /* ACE_VXWORKS */
- result = -1;
- return result;
- # else
- ACE_UNUSED_ARG (cv);
- ACE_UNUSED_ARG (type);
- ACE_UNUSED_ARG (name);
- ACE_UNUSED_ARG (arg);
- ACE_NOTSUP_RETURN (-1);
- # endif /* ACE_HAS_THREADS */
- }
- # endif /* ACE_HAS_WCHAR */
- int
- ACE_OS::cond_signal (ACE_cond_t *cv)
- {
- ACE_OS_TRACE ("ACE_OS::cond_signal");
- # if defined (ACE_HAS_THREADS)
- // If there aren't any waiters, then this is a no-op. Note that
- // this function *must* be called with the <external_mutex> held
- // since other wise there is a race condition that can lead to the
- // lost wakeup bug... This is needed to ensure that the <waiters_>
- // value is not in an inconsistent internal state while being
- // updated by another thread.
- if (ACE_OS::thread_mutex_lock (&cv->waiters_lock_) != 0)
- return -1;
- bool const have_waiters = cv->waiters_ > 0;
- if (ACE_OS::thread_mutex_unlock (&cv->waiters_lock_) != 0)
- return -1;
- if (have_waiters)
- return ACE_OS::sema_post (&cv->sema_);
- else
- return 0; // No-op
- # else
- ACE_UNUSED_ARG (cv);
- ACE_NOTSUP_RETURN (-1);
- # endif /* ACE_HAS_THREADS */
- }
- int
- ACE_OS::cond_wait (ACE_cond_t *cv,
- ACE_mutex_t *external_mutex)
- {
- ACE_OS_TRACE ("ACE_OS::cond_wait");
- # if defined (ACE_HAS_THREADS)
- // Prevent race conditions on the <waiters_> count.
- if (ACE_OS::thread_mutex_lock (&cv->waiters_lock_) != 0)
- return -1;
- ++cv->waiters_;
- if (ACE_OS::thread_mutex_unlock (&cv->waiters_lock_) != 0)
- return -1;
- int result = 0;
- # if defined (ACE_HAS_SIGNAL_OBJECT_AND_WAIT)
- if (external_mutex->type_ == USYNC_PROCESS)
- {
- // This call will automatically release the mutex and wait on the semaphore.
- ACE_WIN32CALL (ACE_ADAPT_RETVAL (::SignalObjectAndWait (external_mutex->proc_mutex_,
- cv->sema_, INFINITE, FALSE),
- result),
- int, -1, result);
- if (result == -1)
- return result;
- }
- else
- # endif /* ACE_HAS_SIGNAL_OBJECT_AND_WAIT */
- {
- // We keep the lock held just long enough to increment the count of
- // waiters by one. Note that we can't keep it held across the call
- // to ACE_OS::sema_wait() since that will deadlock other calls to
- // ACE_OS::cond_signal().
- if (ACE_OS::mutex_unlock (external_mutex) != 0)
- return -1;
- // Wait to be awakened by a ACE_OS::cond_signal() or
- // ACE_OS::cond_broadcast().
- result = ACE_OS::sema_wait (&cv->sema_);
- }
- // Reacquire lock to avoid race conditions on the <waiters_> count.
- if (ACE_OS::thread_mutex_lock (&cv->waiters_lock_) != 0)
- return -1;
- // We're ready to return, so there's one less waiter.
- --cv->waiters_;
- bool const last_waiter = cv->was_broadcast_ && cv->waiters_ == 0;
- // Release the lock so that other collaborating threads can make
- // progress.
- if (ACE_OS::thread_mutex_unlock (&cv->waiters_lock_) != 0)
- return -1;
- if (result == -1)
- // Bad things happened, so let's just return below.
- /* NOOP */;
- # if defined (ACE_HAS_SIGNAL_OBJECT_AND_WAIT)
- else if (external_mutex->type_ == USYNC_PROCESS)
- {
- if (last_waiter)
- // This call atomically signals the <waiters_done_> event and
- // waits until it can acquire the mutex. This is important to
- // prevent unfairness.
- ACE_WIN32CALL (ACE_ADAPT_RETVAL (::SignalObjectAndWait (cv->waiters_done_,
- external_mutex->proc_mutex_,
- INFINITE, FALSE),
- result),
- int, -1, result);
- else
- // We must always regain the <external_mutex>, even when
- // errors occur because that's the guarantee that we give to
- // our callers.
- if (ACE_OS::mutex_lock (external_mutex) != 0)
- return -1;
- return result;
- /* NOTREACHED */
- }
- # endif /* ACE_HAS_SIGNAL_OBJECT_AND_WAIT */
- // If we're the last waiter thread during this particular broadcast
- // then let all the other threads proceed.
- else if (last_waiter)
- # if defined (ACE_VXWORKS)
- ACE_OS::sema_post (&cv->waiters_done_);
- # else
- ACE_OS::event_signal (&cv->waiters_done_);
- # endif /* ACE_VXWORKS */
- // We must always regain the <external_mutex>, even when errors
- // occur because that's the guarantee that we give to our callers.
- ACE_OS::mutex_lock (external_mutex);
- return result;
- # else
- ACE_UNUSED_ARG (cv);
- ACE_UNUSED_ARG (external_mutex);
- ACE_NOTSUP_RETURN (-1);
- # endif /* ACE_HAS_THREADS */
- }
- int
- ACE_OS::cond_timedwait (ACE_cond_t *cv,
- ACE_mutex_t *external_mutex,
- ACE_Time_Value *timeout)
- {
- ACE_OS_TRACE ("ACE_OS::cond_timedwait");
- # if defined (ACE_HAS_THREADS)
- // Handle the easy case first.
- if (timeout == 0)
- return ACE_OS::cond_wait (cv, external_mutex);
- # if defined (ACE_HAS_WTHREADS) || defined (ACE_VXWORKS)
- // Prevent race conditions on the <waiters_> count.
- if (ACE_OS::thread_mutex_lock (&cv->waiters_lock_) != 0)
- return -1;
- ++cv->waiters_;
- if (ACE_OS::thread_mutex_unlock (&cv->waiters_lock_) != 0)
- return -1;
- int result = 0;
- ACE_Errno_Guard error (errno, 0);
- int msec_timeout = 0;
- if (timeout != 0 && *timeout != ACE_Time_Value::zero)
- {
- // Note that we must convert between absolute time (which is
- // passed as a parameter) and relative time (which is what
- // WaitForSingleObjects() expects).
- ACE_Time_Value relative_time (*timeout - ACE_OS::gettimeofday ());
- // Watchout for situations where a context switch has caused the
- // current time to be > the timeout.
- if (relative_time > ACE_Time_Value::zero)
- msec_timeout = relative_time.msec ();
- }
- # if defined (ACE_HAS_SIGNAL_OBJECT_AND_WAIT)
- if (external_mutex->type_ == USYNC_PROCESS)
- // This call will automatically release the mutex and wait on the
- // semaphore.
- result = ::SignalObjectAndWait (external_mutex->proc_mutex_,
- cv->sema_,
- msec_timeout,
- FALSE);
- else
- # endif /* ACE_HAS_SIGNAL_OBJECT_AND_WAIT */
- {
- // We keep the lock held just long enough to increment the count
- // of waiters by one. Note that we can't keep it held across
- // the call to WaitForSingleObject since that will deadlock
- // other calls to ACE_OS::cond_signal().
- if (ACE_OS::mutex_unlock (external_mutex) != 0)
- return -1;
- // Wait to be awakened by a ACE_OS::signal() or
- // ACE_OS::broadcast().
- # if defined (ACE_WIN32)
- # if !defined (ACE_USES_WINCE_SEMA_SIMULATION)
- result = ::WaitForSingleObject (cv->sema_, msec_timeout);
- # else /* ACE_USES_WINCE_SEMA_SIMULATION */
- // Can't use Win32 API on our simulated semaphores.
- result = ACE_OS::sema_wait (&cv->sema_,
- timeout);
- # endif /* ACE_USES_WINCE_SEMA_SIMULATION */
- # elif defined (ACE_VXWORKS)
- // Inline the call to ACE_OS::sema_wait () because it takes an
- // ACE_Time_Value argument. Avoid the cost of that conversion . . .
- int const ticks_per_sec = ::sysClkRateGet ();
- int const ticks = msec_timeout * ticks_per_sec / ACE_ONE_SECOND_IN_MSECS;
- result = ::semTake (cv->sema_.sema_, ticks);
- # endif /* ACE_WIN32 || VXWORKS */
- }
- // Reacquire lock to avoid race conditions.
- if (ACE_OS::thread_mutex_lock (&cv->waiters_lock_) != 0)
- return -1;
- --cv->waiters_;
- bool const last_waiter = cv->was_broadcast_ && cv->waiters_ == 0;
- if (ACE_OS::thread_mutex_unlock (&cv->waiters_lock_) != 0)
- return -1;
- # if defined (ACE_WIN32)
- if (result != WAIT_OBJECT_0)
- {
- switch (result)
- {
- case WAIT_TIMEOUT:
- error = ETIME;
- break;
- default:
- error = ::GetLastError ();
- break;
- }
- result = -1;
- }
- # elif defined (ACE_VXWORKS)
- if (result == ERROR)
- {
- switch (errno)
- {
- case S_objLib_OBJ_TIMEOUT:
- error = ETIME;
- break;
- case S_objLib_OBJ_UNAVAILABLE:
- if (msec_timeout == 0)
- error = ETIME;
- break;
- default:
- error = errno;
- break;
- }
- result = -1;
- }
- # endif /* ACE_WIN32 || VXWORKS */
- # if defined (ACE_HAS_SIGNAL_OBJECT_AND_WAIT)
- if (external_mutex->type_ == USYNC_PROCESS)
- {
- if (last_waiter)
- // This call atomically signals the <waiters_done_> event and
- // waits until it can acquire the mutex. This is important to
- // prevent unfairness.
- ACE_WIN32CALL (ACE_ADAPT_RETVAL (::SignalObjectAndWait (cv->waiters_done_,
- external_mutex->proc_mutex_,
- INFINITE, FALSE),
- result),
- int, -1, result);
- else
- {
- // We must always regain the <external_Mutex>, even when
- // errors occur because that's the guarantee that we give to
- // our callers.
- if (ACE_OS::mutex_lock (external_mutex) != 0)
- return -1;
- }
- return result;
- /* NOTREACHED */
- }
- # endif /* ACE_HAS_SIGNAL_OBJECT_AND_WAIT */
- // Note that this *must* be an "if" statement rather than an "else
- // if" statement since the caller may have timed out and hence the
- // result would have been -1 above.
- if (last_waiter)
- {
- // Release the signaler/broadcaster if we're the last waiter.
- # if defined (ACE_WIN32)
- if (ACE_OS::event_signal (&cv->waiters_done_) != 0)
- # else
- if (ACE_OS::sema_post (&cv->waiters_done_) != 0)
- # endif /* ACE_WIN32 */
- return -1;
- }
- // We must always regain the <external_mutex>, even when errors
- // occur because that's the guarantee that we give to our callers.
- if (ACE_OS::mutex_lock (external_mutex) != 0)
- return -1;
- return result;
- # endif /* ACE_HAS_WTHREADS || ACE_HAS_VXWORKS */
- # else
- ACE_UNUSED_ARG (cv);
- ACE_UNUSED_ARG (external_mutex);
- ACE_UNUSED_ARG (timeout);
- ACE_NOTSUP_RETURN (-1);
- # endif /* ACE_HAS_THREADS */
- }
- #else
- int
- ACE_OS::cond_init (ACE_cond_t *cv, short type, const char *name, void *arg)
- {
- ACE_condattr_t attributes;
- if (ACE_OS::condattr_init (attributes, type) == 0
- && ACE_OS::cond_init (cv, attributes, name, arg) == 0)
- {
- (void) ACE_OS::condattr_destroy (attributes);
- return 0;
- }
- return -1;
- }
- #endif /* ACE_LACKS_COND_T */
- #if defined (ACE_WIN32) && defined (ACE_HAS_WTHREADS)
- int
- ACE_OS::cond_timedwait (ACE_cond_t *cv,
- ACE_thread_mutex_t *external_mutex,
- ACE_Time_Value *timeout)
- {
- ACE_OS_TRACE ("ACE_OS::cond_timedwait");
- # if defined (ACE_HAS_THREADS)
- // Handle the easy case first.
- if (timeout == 0)
- return ACE_OS::cond_wait (cv, external_mutex);
- # if defined (ACE_HAS_WTHREADS_CONDITION_VARIABLE)
- int msec_timeout = 0;
- int result = 0;
- ACE_Time_Value relative_time (*timeout - ACE_OS::gettimeofday ());
- // Watchout for situations where a context switch has caused the
- // current time to be > the timeout.
- if (relative_time > ACE_Time_Value::zero)
- msec_timeout = relative_time.msec ();
- ACE_OSCALL (ACE_ADAPT_RETVAL (::SleepConditionVariableCS (cv, external_mutex, msec_timeout),
- result),
- int, -1, result);
- return result;
- #else
- // Prevent race conditions on the <waiters_> count.
- if (ACE_OS::thread_mutex_lock (&cv->waiters_lock_) != 0)
- return -1;
- ++cv->waiters_;
- if (ACE_OS::thread_mutex_unlock (&cv->waiters_lock_) != 0)
- return -1;
- int result = 0;
- int error = 0;
- int msec_timeout = 0;
- if (timeout != 0 && *timeout != ACE_Time_Value::zero)
- {
- // Note that we must convert between absolute time (which is
- // passed as a parameter) and relative time (which is what
- // WaitForSingleObjects() expects).
- ACE_Time_Value relative_time (*timeout - ACE_OS::gettimeofday ());
- // Watchout for situations where a context switch has caused the
- // current time to be > the timeout.
- if (relative_time > ACE_Time_Value::zero)
- msec_timeout = relative_time.msec ();
- }
- // We keep the lock held just long enough to increment the count of
- // waiters by one. Note that we can't keep it held across the call
- // to WaitForSingleObject since that will deadlock other calls to
- // ACE_OS::cond_signal().
- if (ACE_OS::thread_mutex_unlock (external_mutex) != 0)
- return -1;
- // Wait to be awakened by a ACE_OS::signal() or ACE_OS::broadcast().
- # if defined (ACE_USES_WINCE_SEMA_SIMULATION)
- // Can't use Win32 API on simulated semaphores.
- result = ACE_OS::sema_wait (&cv->sema_,
- timeout);
- if (result == -1 && errno == ETIME)
- result = WAIT_TIMEOUT;
- # else
- result = ::WaitForSingleObject (cv->sema_, msec_timeout);
- # endif /* ACE_USES_WINCE_SEMA_SIMULATION */
- // Reacquire lock to avoid race conditions.
- if (ACE_OS::thread_mutex_lock (&cv->waiters_lock_) != 0)
- return -1;
- --cv->waiters_;
- bool const last_waiter = cv->was_broadcast_ && cv->waiters_ == 0;
- if (ACE_OS::thread_mutex_unlock (&cv->waiters_lock_) != 0)
- return -1;
- if (result != WAIT_OBJECT_0)
- {
- switch (result)
- {
- case WAIT_TIMEOUT:
- error = ETIME;
- break;
- default:
- error = ::GetLastError ();
- break;
- }
- result = -1;
- }
- if (last_waiter)
- {
- // Release the signaler/broadcaster if we're the