diff options
Diffstat (limited to 'ace/OS.cpp')
-rw-r--r-- | ace/OS.cpp | 1224 |
1 files changed, 1224 insertions, 0 deletions
diff --git a/ace/OS.cpp b/ace/OS.cpp new file mode 100644 index 00000000000..a55b8fa99c8 --- /dev/null +++ b/ace/OS.cpp @@ -0,0 +1,1224 @@ +// $Id$ + +// OS.cpp +#define ACE_BUILD_DLL +#include "ace/OS.h" + +#include "ace/Log_Msg.h" +#include "ace/ARGV.h" + +// Perhaps we should *always* include ace/OS.i in order to make sure +// we can always link against the OS symbols? +#if !defined (ACE_HAS_INLINED_OSCALLS) +#include "ace/OS.i" +#endif /* ACE_HAS_INLINED_OS_CALLS */ + +void +ACE_OS::flock_t::dump (void) const +{ +// ACE_TRACE ("ACE_OS::flock_t::dump"); + + ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACE_DEBUG ((LM_DEBUG, "handle_ = %u", this->handle_)); +#if defined (ACE_WIN32) + ACE_DEBUG ((LM_DEBUG, "\nInternal = %d", this->overlapped_.Internal)); + ACE_DEBUG ((LM_DEBUG, "\nInternalHigh = %d", this->overlapped_.InternalHigh)); + ACE_DEBUG ((LM_DEBUG, "\nOffsetHigh = %d", this->overlapped_.OffsetHigh)); + ACE_DEBUG ((LM_DEBUG, "\nhEvent = %d", this->overlapped_.hEvent)); +#else + ACE_DEBUG ((LM_DEBUG, "\nl_whence = %d", this->lock_.l_whence)); + ACE_DEBUG ((LM_DEBUG, "\nl_start = %d", this->lock_.l_start)); + ACE_DEBUG ((LM_DEBUG, "\nl_len = %d", this->lock_.l_len)); + ACE_DEBUG ((LM_DEBUG, "\nl_type = %d", this->lock_.l_type)); +#endif /* ACE_WIN32 */ + ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +} + +void +ACE_OS::mutex_lock_cleanup (void *mutex) +{ +// ACE_TRACE ("ACE_OS::mutex_lock_cleanup"); +#if defined (ACE_HAS_THREADS) +#if defined (ACE_HAS_DCETHREADS) || defined (ACE_HAS_PTHREADS) + ACE_mutex_t *p_lock = (ACE_mutex_t *) mutex; + ACE_OS::mutex_unlock (p_lock); +#endif /* ACE_HAS_DCETHREADS */ +#endif /* ACE_HAS_THREADS */ +} + +// = 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 +// is implemented as a structure... +ACE_thread_t ACE_OS::NULL_thread; + +ACE_OS::ACE_OS (void) +{ +// ACE_TRACE ("ACE_OS::ACE_OS"); +} + +#if defined (ACE_WIN32) + +// = Static initialization. + +// Keeps track of whether we've initialized the WinSock DLL. +int ACE_OS::socket_initialized_; + +// We need this to initialize the WinSock DLL. + +BOOL WINAPI +DllMain (HINSTANCE, // DLL module handle + DWORD fdwReason, // Reason called + LPVOID) // Reserved +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + if (ACE_OS::socket_init (ACE_WSOCK_VERSION) != 0) + return FALSE; + break; + + case DLL_PROCESS_DETACH: + if (ACE_OS::socket_fini () != 0) + return FALSE; + break; + + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + + default: + ACE_ERROR_RETURN ((LM_ERROR, + "Sock.DLL DllMain called with unknown fdwReason = %u\n.", + fdwReason), FALSE); + /* NOTREACHED */ + } + + return TRUE; +} + +#include "ace/Synch.h" +#include "ace/Set.h" + +class ACE_TSS_Ref + // = TITLE + // "Reference count" for thread-specific storage keys. + // + // = DESCRIPTION + // Since the ACE_Unbounded_Set doesn't allow duplicates, the + // "reference count" is the identify of the thread_id. +{ +public: + ACE_TSS_Ref (ACE_thread_t id); + // Constructor + + ACE_TSS_Ref (void); + // Default constructor + + int operator== (const ACE_TSS_Ref &); + // Check for equality. + +// private: + + ACE_thread_t tid_; + // ID of thread using a specific key. +}; + +ACE_TSS_Ref::ACE_TSS_Ref (ACE_thread_t id) + : tid_(id) +{ +// ACE_TRACE ("ACE_TSS_Ref::ACE_TSS_Ref"); +} + +ACE_TSS_Ref::ACE_TSS_Ref (void) +{ +// ACE_TRACE ("ACE_TSS_Ref::ACE_TSS_Ref"); +} + +// Check for equality. +int +ACE_TSS_Ref::operator== (const ACE_TSS_Ref &info) +{ +// ACE_TRACE ("ACE_TSS_Ref::operator=="); + + return this->tid_ == info.tid_; +} + +typedef ACE_Unbounded_Set<ACE_TSS_Ref> ACE_TSS_REF_TABLE; +typedef ACE_Unbounded_Set_Iterator<ACE_TSS_Ref> ACE_TSS_REF_TABLE_ITERATOR; + +class ACE_TSS_Info + // = TITLE + // Thread Specific Key management. + // + // = DESCRIPTION + // This class maps a key to a "destructor." +{ +public: + ACE_TSS_Info (ACE_thread_key_t key, + void (*dest)(void *) = 0, + void *tss_inst = 0); + // Constructor + + ACE_TSS_Info (void); + // Default constructor + + int operator== (const ACE_TSS_Info &); + // Check for equality. + + void dump (void); + // Dump the state. + +// private: + ACE_thread_key_t key_; + // Key to the thread-specific storage item. + + void (*destructor_)(void *); + // "Destructor" that gets called when the item is finally released. + + void *tss_obj_; + // Pointer to ACE_TSS<xxx> instance that has/will allocate the key. + + ACE_TSS_REF_TABLE ref_table_; + // Table of thread IDs that are using this key. +}; + +ACE_TSS_Info::ACE_TSS_Info (ACE_thread_key_t key, + void (*dest)(void *), + void *tss_inst) + : key_ (key), + destructor_ (dest), + tss_obj_ (tss_inst) +{ +// ACE_TRACE ("ACE_TSS_Info::ACE_TSS_Info"); +} + +ACE_TSS_Info::ACE_TSS_Info (void) +{ +// ACE_TRACE ("ACE_TSS_Info::ACE_TSS_Info"); +} + +// Check for equality. +int +ACE_TSS_Info::operator== (const ACE_TSS_Info &info) +{ +// ACE_TRACE ("ACE_TSS_Info::operator=="); + + return this->key_ == info.key_; +} + +void +ACE_TSS_Info::dump (void) +{ +// ACE_TRACE ("ACE_TSS_Info::dump"); + + ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACE_DEBUG ((LM_DEBUG, "key_ = %u", this->key_)); + ACE_DEBUG ((LM_DEBUG, "\ndestructor_ = %u", this->destructor_)); + ACE_DEBUG ((LM_DEBUG, "\ntss_obj_ = %u", this->tss_obj_)); + ACE_DEBUG ((LM_DEBUG, "\nref_table_.size_ = %u", this->ref_table_.size ())); + + ACE_TSS_Ref *tid_info = 0; + + ACE_DEBUG ((LM_DEBUG, "\nThread_usage_list\n[\n")); + + for (ACE_TSS_REF_TABLE_ITERATOR iter (this->ref_table_); + iter.next (tid_info) != 0; + iter.advance ()) + ACE_DEBUG ((LM_DEBUG, "\ntid_ = %d", tid_info->tid_)); + + ACE_DEBUG ((LM_DEBUG, "\n]\n")); + ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +} + +// Create a set of <ACE_TSS_Info> objects that will reside +// within thread-specific storage. +typedef ACE_Unbounded_Set<ACE_TSS_Info> ACE_TSS_TABLE; +typedef ACE_Unbounded_Set_Iterator<ACE_TSS_Info> ACE_TSS_TABLE_ITERATOR; + +class ACE_TSS_Cleanup + // = TITLE + // Singleton that knows how to clean up all the thread-specific + // resources for Win32. + // + // = DESCRIPTION + // All this nonsense is required since Win32 doesn't + // automatically cleanup thread-specific storage on thread exit, + // unlike real operating systems... ;-) +{ +public: + static ACE_TSS_Cleanup *instance (void); + + void exit (void *status); + // Cleanup the thread-specific objects and exit with <status>. + + int insert (ACE_thread_key_t key, void (*destructor)(void *), void *inst); + // Insert a <key, destructor> tuple into the table. + + int remove (ACE_thread_key_t key); + // Remove a <key, destructor> tuple from the table. + + int detach (void *inst); + // Detaches a tss_instance from its key. + + int detach (ACE_thread_key_t key, ACE_thread_t tid); + // Detaches a thread from the key. + + int key_used (ACE_thread_key_t key); + // Mark a key as being used by this thread. + +protected: + void dump (void); + + ACE_TSS_Cleanup (void); + // Ensure singleton. + +private: + ACE_TSS_TABLE table_; + // Table of <ACE_TSS_Info>'s. + + // = Static data. + static ACE_TSS_Cleanup *instance_; + // Pointer to the singleton instance. + +public: + static ACE_Recursive_Thread_Mutex lock_; + // Serialize initialization of <key_>. +}; + +// = Static object initialization. + +// Pointer to the singleton instance. +ACE_TSS_Cleanup *ACE_TSS_Cleanup::instance_ = 0; + +// Serialize initialization of <key_>. +ACE_Recursive_Thread_Mutex ACE_TSS_Cleanup::lock_; + +void +ACE_TSS_Cleanup::exit (void *status) +{ +// ACE_TRACE ("ACE_TSS_Cleanup::exit"); + + { + ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, ACE_TSS_Cleanup::lock_); + + // Prevent recursive deletions (note that when a recursive mutex + // is first acquired it has a nesting level of 1...). + if (ACE_TSS_Cleanup::lock_.get_nesting_level () > 1) + return; + + ACE_thread_key_t key_arr[TLS_MINIMUM_AVAILABLE]; + int index = 0; + + ACE_TSS_Info *key_info = 0; + + // Iterate through all the thread-specific items and free them all + // up. + + for (ACE_TSS_TABLE_ITERATOR iter (this->table_); + iter.next (key_info) != 0; + iter.advance ()) + { + void *tss_info = 0; + + int val = key_info->ref_table_.remove (ACE_TSS_Ref (ACE_OS::thr_self ())); + + if ((ACE_OS::thr_getspecific (key_info->key_, &tss_info) == 0) + && (key_info->destructor_) + && tss_info) + // Probably need to have an exception handler here... + (*key_info->destructor_) (tss_info); + + if (key_info->ref_table_.size () == 0 + && key_info->tss_obj_ == 0) + key_arr[index++] = key_info->key_; + } + + for (int i = 0; i < index; i++) + { + ::TlsFree (key_arr[i]); + this->table_.remove (ACE_TSS_Info (key_arr[i])); + } + } + +#if 0 + ::ExitThread ((DWORD) status); +#endif + ::_endthreadex ((DWORD) status); + + /* NOTREACHED */ +} + +ACE_TSS_Cleanup::ACE_TSS_Cleanup (void) +{ +// ACE_TRACE ("ACE_TSS_Cleanup::ACE_TSS_Cleanup"); +} + +ACE_TSS_Cleanup * +ACE_TSS_Cleanup::instance (void) +{ +// ACE_TRACE ("ACE_TSS_Cleanup::instance"); + + // Create and initialize thread-specific key. + if (ACE_TSS_Cleanup::instance_ == 0) + { + // Insure that we are serialized! + ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, ACE_TSS_Cleanup::lock_, 0); + + // Now, use the Double-Checked Locking pattern to make sure we + // only create the key once. + if (instance_ == 0) + ACE_NEW_RETURN (ACE_TSS_Cleanup::instance_, ACE_TSS_Cleanup, 0); + } + + return ACE_TSS_Cleanup::instance_; +} + +int +ACE_TSS_Cleanup::insert (ACE_thread_key_t key, + void (*destructor)(void *), + void *inst) +{ +// ACE_TRACE ("ACE_TSS_Cleanup::insert"); + ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, ACE_TSS_Cleanup::lock_, -1); + + return this->table_.insert (ACE_TSS_Info (key, destructor, inst)); +} + +int +ACE_TSS_Cleanup::remove (ACE_thread_key_t key) +{ +// ACE_TRACE ("ACE_TSS_Cleanup::remove"); + ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, ACE_TSS_Cleanup::lock_, -1); + + return this->table_.remove (ACE_TSS_Info (key)); +} + +int +ACE_TSS_Cleanup::detach (void *inst) +{ + ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, ACE_TSS_Cleanup::lock_, -1); + + ACE_TSS_Info *key_info = 0; + int success = 0; + int ref_cnt = 0; + + for (ACE_TSS_TABLE_ITERATOR iter (this->table_); + iter.next (key_info) != 0; + iter.advance ()) + { + if (key_info->tss_obj_ == inst) + { + key_info->tss_obj_ = 0; + ref_cnt = key_info->ref_table_.size (); + success = 1; + break; + } + } + + if (success == 0) + return -1; + else if (ACE_TSS_Cleanup::lock_.get_nesting_level () > 1) + ACE_ERROR_RETURN ((LM_DEBUG, "Detach() invoked from ACE_TSS_Cleanup::exit()\n"), 0); + else if (ref_cnt == 0) + { + ::TlsFree (key_info->key_); + return this->table_.remove (ACE_TSS_Info (key_info->key_)); + } + + return 0; +} + +int +ACE_TSS_Cleanup::detach (ACE_thread_key_t key, ACE_thread_t tid) +{ + return -1; +} + +int +ACE_TSS_Cleanup::key_used (ACE_thread_key_t key) +{ + ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, ACE_TSS_Cleanup::lock_, -1); + + ACE_TSS_Info *key_info = 0; + + for (ACE_TSS_TABLE_ITERATOR iter (this->table_); + iter.next (key_info) != 0; + iter.advance ()) + if (key_info->key_ == key) + return key_info->ref_table_.insert (ACE_TSS_Ref (ACE_OS::thr_self ())); + + return -1; +} + +void +ACE_TSS_Cleanup::dump (void) +{ + ACE_TSS_Info *key_info = 0; + + // Iterate through all the thread-specific items and dump them all. + + for (ACE_TSS_TABLE_ITERATOR iter (this->table_); + iter.next (key_info) != 0; + iter.advance ()) + key_info->dump (); +} + +// Special thread startup argument (used below in <thr_create>). + +class ACE_Win32_Thread_Adapter +{ +public: + ACE_Win32_Thread_Adapter (ACE_THR_FUNC f, void *a); + // Constructor + + static void *svc_run (ACE_Win32_Thread_Adapter *); + // Run the thread exit point. + +private: + // = Arguments to thread startup. + ACE_THR_FUNC func_; + // Thread startup function. + + void *arg_; + // Argument to thread startup function. +}; + +ACE_Win32_Thread_Adapter::ACE_Win32_Thread_Adapter (ACE_THR_FUNC f, void *a) + : func_(f), + arg_(a) +{ +// ACE_TRACE ("ACE_Win32_Thread_Adapter::ACE_Win32_Thread_Adapter"); +} + +void * +ACE_Win32_Thread_Adapter::svc_run (ACE_Win32_Thread_Adapter *thread_args) +{ +// ACE_TRACE ("ACE_Win32_Thread_Adapter::svc_run"); + ACE_THR_FUNC func = thread_args->func_; + void *arg = thread_args->arg_; + delete thread_args; + void *status; + + ACE_SEH_TRY { + status = (*func) (arg); // Call thread entry point. + } + ACE_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { + // Here's where we might want to provide a hook to report this... + // As it stands now, we just catch all Win32 structured exceptions + // so that we can make sure to clean up correctly when the thread + // exits. + } + + // If dropped off end, call destructors for thread-specific storage + // and exit. + ACE_TSS_Cleanup::instance ()->exit (status); + + /* NOTREACHED */ + return status; +} + +#endif // WIN32 + +int +ACE_OS::thr_create (ACE_THR_FUNC func, + void *args, + long flags, + ACE_thread_t *thr_id, + ACE_hthread_t *thr_handle, + u_int priority, + void *stack, + size_t stacksize) +{ +// ACE_TRACE ("ACE_OS::thr_create"); + +#if defined (ACE_HAS_THREADS) +#if defined (ACE_HAS_DCETHREADS) || defined (ACE_HAS_PTHREADS) + int result; + pthread_attr_t attr; + ACE_thread_t tmp_thr; + ACE_thread_t *p_thr; + +#if defined (ACE_HAS_SETKIND_NP) + if (::pthread_attr_create (&attr) != 0) +#else /* ACE_HAS_SETKIND_NP */ + if (::pthread_attr_init (&attr) != 0) +#endif /* ACE_HAS_SETKIND_NP */ + return -1; + else if (priority != 0) + { + struct sched_param sparam; + + ACE_OS::memset ((void *) &sparam, 0, sizeof sparam); + +#if defined (ACE_HAS_DCETHREADS) && !defined (ACE_HAS_SETKIND_NP) + sparam.sched_priority = priority > PRIORITY_MAX ? PRIORITY_MAX : priority; +#elif defined(ACE_HAS_IRIX62_THREADS) + sparam.sched_priority = priority > PTHREAD_MAX_PRIORITY ? PTHREAD_MAX_PRIORITY : priority; +#elif defined (PTHREAD_MAX_PRIORITY) // For MIT pthreads... + sparam.prio = priority > PTHREAD_MAX_PRIORITY ? PTHREAD_MAX_PRIORITY : priority; +#endif /* ACE_HAS_DCETHREADS */ + +#if !defined (ACE_HAS_FSU_PTHREADS) +#if defined (ACE_HAS_SETKIND_NP) + if (::pthread_attr_setsched (&attr, SCHED_OTHER) != 0) +#else /* ACE_HAS_SETKIND_NP */ + if (::pthread_attr_setschedparam (&attr, &sparam) != 0) +#endif /* ACE_HAS_SETKIND_NP */ + { +#if defined (ACE_HAS_SETKIND_NP) + ::pthread_attr_delete (&attr); +#else /* ACE_HAS_SETKIND_NP */ + ::pthread_attr_destroy (&attr); +#endif /* ACE_HAS_SETKIND_NP */ + return -1; + } +#else + if ((sparam.sched_priority >= PTHREAD_MIN_PRIORITY) + && (sparam.sched_priority <= PTHREAD_MAX_PRIORITY)) + attr.prio = sparam.sched_priority; + else + { + pthread_attr_destroy (&attr); + return -1; + } +#endif // ACE_HAS_FSU_PTHREADS + } + + if (stacksize != 0) + { + size_t size = stacksize; + +#if defined (PTHREAD_STACK_MIN) + if (size < PTHREAD_STACK_MIN) + stacksize = PTHREAD_STACK_MIN; +#endif /* PTHREAD_STACK_MIN */ + + if (::pthread_attr_setstacksize (&attr, size) != 0) + { +#if defined (ACE_HAS_SETKIND_NP) + ::pthread_attr_delete (&attr); +#else /* ACE_HAS_SETKIND_NP */ + ::pthread_attr_destroy (&attr); +#endif /* ACE_HAS_SETKIND_NP */ + return -1; + } + } + +#if !defined (ACE_LACKS_THREAD_STACK_ADDR) + if (stack != 0) + { + if (::pthread_attr_setstackaddr (&attr, stack) != 0) + { +#if defined (ACE_HAS_SETKIND_NP) + ::pthread_attr_delete (&attr); +#else /* ACE_HAS_SETKIND_NP */ + ::pthread_attr_destroy (&attr); +#endif /* ACE_HAS_SETKIND_NP */ + return -1; + } + } +#endif /* !ACE_LACKS_THREAD_STACK_ADDR */ + if (flags != 0) + { +#if !defined (ACE_LACKS_SETDETACH) + if (ACE_BIT_ENABLED (flags, THR_DETACHED) + || ACE_BIT_ENABLED (flags, THR_JOINABLE)) + { + int dstate = PTHREAD_CREATE_JOINABLE; + + if (ACE_BIT_ENABLED (flags, THR_DETACHED)) + dstate = PTHREAD_CREATE_DETACHED; + +#if defined (ACE_HAS_SETKIND_NP) + if (::pthread_attr_setdetach_np (&attr, dstate) != 0) +#else /* ACE_HAS_SETKIND_NP */ + if (::pthread_attr_setdetachstate (&attr, dstate) != 0) +#endif /* ACE_HAS_SETKIND_NP */ + { +#if defined (ACE_HAS_SETKIND_NP) + ::pthread_attr_delete (&attr); +#else /* ACE_HAS_SETKIND_NP */ + ::pthread_attr_destroy (&attr); +#endif /* ACE_HAS_SETKIND_NP */ + return -1; + } + } +#endif /* ACE_LACKS_SETDETACH */ + if (ACE_BIT_ENABLED (flags, THR_SCHED_FIFO) + || ACE_BIT_ENABLED (flags, THR_SCHED_RR) + || ACE_BIT_ENABLED (flags, THR_SCHED_DEFAULT)) + { + int spolicy; + + if (ACE_BIT_ENABLED (flags, THR_SCHED_DEFAULT)) + spolicy = SCHED_OTHER; + else if (ACE_BIT_ENABLED (flags, THR_SCHED_FIFO)) + spolicy = SCHED_FIFO; + else + spolicy = SCHED_RR; + +#if !defined (ACE_HAS_FSU_PTHREADS) +#if defined (ACE_HAS_SETKIND_NP) + if (::pthread_attr_setsched (&attr, spolicy) != 0) +#else /* ACE_HAS_SETKIND_NP */ + if (::pthread_attr_setschedpolicy (&attr, spolicy) != 0) +#endif /* ACE_HAS_SETKIND_NP */ + { +#if defined (ACE_HAS_SETKIND_NP) + ::pthread_attr_delete (&attr); +#else /* ACE_HAS_SETKIND_NP */ + ::pthread_attr_destroy (&attr); +#endif /* ACE_HAS_SETKIND_NP */ + return -1; + } +#else + int ret; + switch (spolicy) + { + case SCHED_FIFO: + case SCHED_RR: + ret = 0; + break; + default: + ret = 22; + break; + } + if (ret != 0) + { +#if defined (ACE_HAS_SETKIND_NP) + ::pthread_attr_delete (&attr); +#else /* ACE_HAS_SETKIND_NP */ + ::pthread_attr_destroy (&attr); +#endif /* ACE_HAS_SETKIND_NP */ + return -1; + } +#endif // ACE_HAS_FSU_PTHREADS + } + + if (ACE_BIT_ENABLED (flags, THR_INHERIT_SCHED) + || ACE_BIT_ENABLED (flags, THR_EXPLICIT_SCHED)) + { +#if defined (ACE_HAS_SETKIND_NP) + int sched = PTHREAD_DEFAULT_SCHED; +#else /* ACE_HAS_SETKIND_NP */ + int sched = PTHREAD_EXPLICIT_SCHED; +#endif /* ACE_HAS_SETKIND_NP */ + if (ACE_BIT_ENABLED (flags, THR_INHERIT_SCHED)) + sched = PTHREAD_INHERIT_SCHED; + if (::pthread_attr_setinheritsched (&attr, sched) != 0) + { +#if defined (ACE_HAS_SETKIND_NP) + ::pthread_attr_delete (&attr); +#else /* ACE_HAS_SETKIND_NP */ + ::pthread_attr_destroy (&attr); +#endif /* ACE_HAS_SETKIND_NP */ + return -1; + } + } +#if !defined (ACE_LACKS_THREAD_PROCESS_SCOPING) + if (ACE_BIT_ENABLED (flags, THR_SCOPE_SYSTEM) + || ACE_BIT_ENABLED (flags, THR_SCOPE_PROCESS)) + { + int scope = PTHREAD_SCOPE_PROCESS; + if (ACE_BIT_ENABLED (flags, THR_SCOPE_SYSTEM)) + scope = PTHREAD_SCOPE_SYSTEM; + + if (::pthread_attr_setscope (&attr, scope) != 0) + { +#if defined (ACE_HAS_SETKIND_NP) + ::pthread_attr_delete (&attr); +#else /* ACE_HAS_SETKIND_NP */ + ::pthread_attr_destroy (&attr); +#endif /* ACE_HAS_SETKIND_NP */ + return -1; + } + } +#endif /* !ACE_LACKS_THREAD_PROCESS_SCOPING */ + + if (ACE_BIT_ENABLED (flags, THR_NEW_LWP)) + { + // Increment the number of LWPs by one to emulate the + // Solaris semantics. + int lwps = ACE_OS::thr_getconcurrency (); + ACE_OS::thr_setconcurrency (lwps + 1); + } + } + + p_thr = (thr_id == 0 ? &tmp_thr : thr_id); + +#if defined (ACE_HAS_SETKIND_NP) + ACE_OSCALL (ACE_ADAPT_RETVAL (::pthread_create (p_thr, attr, func, args), + result), + int, -1, result); + ::pthread_attr_delete (&attr); + if (thr_handle != 0) + thr_handle = (ACE_hthread_t *) 0; +#else /* ACE_HAS_SETKIND_NP */ + ACE_OSCALL (ACE_ADAPT_RETVAL (::pthread_create (p_thr, &attr, func, args), + result), + int, -1, result); + ::pthread_attr_destroy (&attr); + if (thr_handle != 0) + *thr_handle = (ACE_hthread_t) 0; +#endif /* ACE_HAS_SETKIND_NP */ + + return result; +#elif defined (ACE_HAS_STHREADS) + int result; + ACE_OSCALL (ACE_ADAPT_RETVAL (::thr_create (stack, stacksize, func, args, + flags, thr_id), result), + int, -1, result); + if (result == 0 && thr_handle != 0) + *thr_handle = *thr_id; + return result; +#elif defined (ACE_HAS_WTHREADS) + ACE_thread_t t; + ACE_hthread_t handle; + + if (thr_id == 0) + thr_id = &t; + if (thr_handle == 0) + thr_handle = &handle; + + ACE_Win32_Thread_Adapter *thread_args; + + ACE_NEW_RETURN (thread_args, ACE_Win32_Thread_Adapter (func, args), -1); + + typedef unsigned (__stdcall *ThreadFunc) (void*); + +#if defined (ACE_HAS_MFC) + if (ACE_BIT_ENABLED (flags, THR_USE_AFX)) + { + CWinThread *cwin_thread = + // These aren't the right arguments (yet). + ::AfxBeginThread ((ThreadFunc) (ACE_Win32_Thread_Adapter::svc_run), + thread_args, 0, 0, flags); + *thr_handle = cwin_thread->m_hThread; + *thr_id = cwin_thread->m_nThreadID; + // Can we delete the memory of cwin_thread here? + } + else +#endif /* ACE_HAS_MFC */ + *thr_handle = (void *) ::_beginthreadex + (NULL, + stacksize, + (ThreadFunc) (ACE_Win32_Thread_Adapter::svc_run), + thread_args, + flags, + (unsigned int *) thr_id); + +#if 0 + *thr_handle = ::CreateThread + (NULL, stacksize, + LPTHREAD_START_ROUTINE (ACE_Win32_Thread_Adapter::svc_run), + thread_args, flags, thr_id); +#endif /* 0 */ + + // Close down the handle if no one wants to use it. + if (thr_handle == &handle) + ::CloseHandle (thr_handle); + + if (*thr_handle != 0) + return 0; + else + ACE_FAIL_RETURN (-1); + /* NOTREACHED */ +#elif defined (VXWORKS) + // If thr_id points to NULL (or is 0), the call below causes VxWorks + // to assign a unique task name of the form: "t" + an integer. + + // args must be an array of _exactly_ 10 ints. + + // stack arg is ignored: if there's a need for it, we'd have to use + // taskInit ()/taskActivate () instead of taskSpawn () + + // The hard-coded arguments are what ::sp() would use. ::taskInit() + // is used instead of ::sp() so that we can set the priority, flags, + // and stacksize. (::sp() also hardcodes priority to 100, flags + // to VX_FP_TASK, and stacksize to 20,000.) stacksize should be + // an even integer. + + // if called with thr_create() defaults, use same default values as ::sp() + if ( stacksize == 0 ) stacksize = 20000; + if ( priority == 0 ) priority = 100; + + ACE_hthread_t tid = ::taskSpawn (thr_id == 0 ? NULL : *thr_id, priority, + (int) flags, (int) stacksize, func, + ((int *) args)[0], ((int *) args)[1], + ((int *) args)[2], ((int *) args)[3], + ((int *) args)[4], ((int *) args)[5], + ((int *) args)[6], ((int *) args)[7], + ((int *) args)[8], ((int *) args)[9]); + + if ( tid == ERROR ) + return -1; + else + { + // return the thr_id and thr_handle, if addresses were provided for them + if ( thr_id != 0 ) + // taskTcb (int tid) returns the address of the WIND_TCB + // (task control block). According to the taskSpawn() + // documentation, the name of the new task is stored at + // pStackBase, but is that of the current task? If so, it + // would be a bit quicker than this extraction of the tcb . . . + *thr_id = taskTcb (tid)->name; + if ( thr_handle != 0 ) + *thr_handle = tid; + return 0; + } + +#endif /* ACE_HAS_STHREADS */ +#else + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_THREADS */ +} + +void +ACE_OS::thr_exit (void *status) +{ +// ACE_TRACE ("ACE_OS::thr_exit"); +#if defined (ACE_HAS_THREADS) +#if defined (ACE_HAS_DCETHREADS) || defined (ACE_HAS_PTHREADS) + ::pthread_exit (status); +#elif defined (ACE_HAS_STHREADS) + ::thr_exit (status); +#elif defined (ACE_HAS_WTHREADS) + // Cleanup the thread-specific resources and exit. + ACE_TSS_Cleanup::instance ()->exit (status); +#elif defined (VXWORKS) + *((int *) status) = ::taskDelete (ACE_OS::thr_self ()); +#endif /* ACE_HAS_STHREADS */ +#else + ; +#endif /* ACE_HAS_THREADS */ +} + +int +ACE_OS::thr_setspecific (ACE_thread_key_t key, void *data) +{ +// ACE_TRACE ("ACE_OS::thr_setspecific"); +#if defined (ACE_HAS_THREADS) +#if defined (ACE_HAS_DCETHREADS) || defined (ACE_HAS_PTHREADS) +#if defined (ACE_HAS_FSU_PTHREADS) +// Call pthread_init() here to initialize threads package. FSU +// threads need an initialization before the first thread constructor. +// This seems to be the one; however, a segmentation fault may +// indicate that another pthread_init() is necessary, perhaps in +// Synch.cpp or Synch_T.cpp. FSU threads will not reinit if called +// more than once, so another call to pthread_init will not adversely +// affect existing threads. + pthread_init (); +#endif // ACE_HAS_FSU_PTHREADS + ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::pthread_setspecific (key, data), _result), + int, -1); +#elif defined (ACE_HAS_STHREADS) + ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_setspecific (key, data), _result), int, -1); +#elif defined (ACE_HAS_WTHREADS) + ::TlsSetValue (key, data); + ACE_TSS_Cleanup::instance ()->key_used (key); + return 0; +#elif defined (VXWORKS) + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_STHREADS */ +#else + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_THREADS */ +} + +int +ACE_OS::thr_keyfree (ACE_thread_key_t key) +{ +// ACE_TRACE ("ACE_OS::thr_keyfree"); +#if defined (ACE_HAS_THREADS) +#if defined (ACE_LACKS_KEYDELETE) + ACE_NOTSUP_RETURN (-1); +#elif defined (ACE_HAS_PTHREADS) && !defined (ACE_HAS_FSU_PTHREADS) + return ::pthread_key_delete (key); +#elif defined (ACE_HAS_DCETHREADS) + ACE_NOTSUP_RETURN (-1); +#elif defined (ACE_HAS_STHREADS) + ACE_NOTSUP_RETURN (-1); +#elif defined (ACE_HAS_WTHREADS) + // Extract out the thread-specific table instance and and free up + // the key and destructor. + ACE_TSS_Cleanup::instance ()->remove (key); + ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::TlsFree (key), _result), int, -1); +#elif defined (VXWORKS) + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_STHREADS */ +#else + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_THREADS */ +} + +int +ACE_OS::thr_keycreate (ACE_thread_key_t *key, + void (*dest) (void *), + void *inst) +{ +// ACE_TRACE ("ACE_OS::thr_keycreate"); +#if defined (ACE_HAS_THREADS) +#if defined (ACE_HAS_DCETHREADS) || defined (ACE_HAS_PTHREADS) +#if defined (ACE_HAS_SETKIND_NP) + ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::pthread_keycreate (key, dest), + _result), + int, -1); +#else /* ACE_HAS_SETKIND_NP */ + ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::pthread_key_create (key, dest), + _result), + int, -1); +#endif /* ACE_HAS_SETKIND_NP */ +#elif defined (ACE_HAS_STHREADS) + ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_keycreate (key, dest), + _result), + int, -1); +#elif defined (ACE_HAS_WTHREADS) + *key = ::TlsAlloc (); + + if (*key != ACE_SYSCALL_FAILED) + // Extract out the thread-specific table instance and stash away + // the key and destructor so that we can free it up later on... + return ACE_TSS_Cleanup::instance ()->insert (*key, dest, inst); + else + ACE_FAIL_RETURN (-1); + /* NOTREACHED */ + +#elif defined (VXWORKS) + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_STHREADS */ +#else + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_THREADS */ +} + +int +ACE_OS::thr_key_used (ACE_thread_key_t key) +{ +#if defined (ACE_WIN32) + return ACE_TSS_Cleanup::instance ()->key_used (key); +#else + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_WIN32 */ +} + +int +ACE_OS::thr_key_detach (void *inst) +{ +#if defined (ACE_WIN32) + return ACE_TSS_Cleanup::instance()->detach (inst); +#else + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_WIN32 */ +} + +// Create a contiguous command-line argument buffer with each arg +// separated by spaces. + +pid_t +ACE_OS::fork_exec (char *argv[]) +{ +#if defined (ACE_WIN32) + ACE_ARGV argv_buf (argv); + + char *buf = argv_buf.buf (); + + if (buf != 0) + { + PROCESS_INFORMATION process_info; + STARTUPINFO startup_info; + ACE_OS::memset ((void *) &startup_info, 0, sizeof startup_info); + startup_info.cb = sizeof startup_info; + + if (::CreateProcess (NULL, + buf, + NULL, // No process attributes. + NULL, // No thread attributes. + TRUE, // Allow handle inheritance. + CREATE_NEW_CONSOLE, // Create a new console window. + NULL, // No environment. + NULL, // No current directory. + &startup_info, + &process_info)) + { + // Free resources allocated in kernel. + ACE_OS::close (process_info.hThread); + ACE_OS::close (process_info.hProcess); + // Return new process id. + return process_info.dwProcessId; + } + } + + // CreateProcess failed. + return -1; +#else + pid_t result = ACE_OS::fork (); + + switch (result) + { + case -1: + // Error. + return -1; + case 0: + // Child process. + if (ACE_OS::execv (argv[0], argv) == -1) + { + ACE_ERROR ((LM_ERROR, "%p Exec failed\n")); + + // If the execv fails, this child needs to exit. + ACE_OS::exit (errno); + } + default: + // Server process. The fork succeeded. + return result; + } +#endif /* ACE_WIN32 */ + } + +#if defined (ACE_NEEDS_WRITEV) + +// "Fake" writev for sites without it. Note that this is totally +// broken for multi-threaded applications since the <send_n> calls are +// not atomic... + +extern "C" int +writev (ACE_HANDLE handle, ACE_WRITEV_TYPE *vp, int vpcount) +{ +// ACE_TRACE ("::writev"); + + int count; + + for (count = 0; --vpcount >= 0; count += vp->iov_len, vp++) + if (ACE::send_n (handle, vp->iov_base, vp->iov_len) < 0) + return -1; + + return count; +} +#endif /* ACE_NEEDS_WRITEV */ + +#if defined (ACE_NEEDS_READV) + +// "Fake" readv for sites without it. Note that this is totally +// broken for multi-threaded applications since the <send_n> calls are +// not atomic... + +extern "C" int +readv (ACE_HANDLE handle, struct iovec *vp, int vpcount) +{ +// ACE_TRACE ("::readv"); + + int count; + + for (count = 0; --vpcount >= 0; count += vp->iov_len, vp++) + if (ACE::recv_n (handle, vp->iov_base, vp->iov_len) < 0) + return -1; + + return count; +} +#endif /* ACE_NEEDS_READV */ + +#if defined (ACE_NEEDS_FTRUNCATE) +extern "C" int +ftruncate (ACE_HANDLE handle, long len) +{ + struct flock fl; + fl.l_whence = 0; + fl.l_len = 0; + fl.l_start = len; + fl.l_type = F_WRLCK; + + return ::fcntl (handle, F_FREESP, &fl); +} +#endif /* ACE_NEEDS_FTRUNCATE */ + +char * +ACE_OS::mktemp (char *s) +{ + // ACE_TRACE ("ACE_OS::mktemp"); +#if defined (ACE_LACKS_MKTEMP) + if (s == 0) + // check for null template string failed! + return 0; + else + { + char *xxxxxx = ACE_OS::strstr (s, "XXXXXX"); + + if (xxxxxx == 0) + // the template string doesn't contain "XXXXXX"! + return s; + else + { + char unique_letter = 'a'; + struct stat sb; + + // Find an unused filename for this process. It is assumed + // that the user will open the file immediately after + // getting this filename back (so, yes, there is a race + // condition if multiple threads in a process use the same + // template). This appears to match the behavior of the + // Solaris 2.5 mktemp(). + ::sprintf (xxxxxx, "%05d%c", getpid (), unique_letter); + while (::stat (s, &sb) >= 0) + { + if (++unique_letter <= 'z') + ::sprintf (xxxxxx, "%05d%c", getpid (), unique_letter); + else + { + // maximum of 26 unique files per template, per process + ::sprintf (xxxxxx, "%s", ""); + return s; + } + } + } + return s; + } + +#else + return ::mktemp (s); +#endif /* ACE_LACKS_MKTEMP */ +} + +int +ACE_OS::socket_init (int version_high, int version_low) +{ +#if defined (ACE_WIN32) + if (ACE_OS::socket_initialized_ == 0) + { + WORD version_requested = MAKEWORD (version_high, version_low); + WSADATA wsa_data; + int error = ::WSAStartup (version_requested, &wsa_data); + + if (error != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "WSAStartup failed, WSAGetLastError returned %u.\n", + error), -1); + + ACE_OS::socket_initialized_ = 1; + } +#endif /* ACE_WIN32 */ + return 0; +} + +int +ACE_OS::socket_fini (void) +{ +#if defined (ACE_WIN32) + if (ACE_OS::socket_initialized_ != 0) + { + if (::WSACleanup () != 0) + { + int error = ::WSAGetLastError (); + ACE_ERROR_RETURN ((LM_ERROR, + "WSACleanup failed, WSAGetLastError returned %u.\n", + error), -1); + } + ACE_OS::socket_initialized_ = 0; + } +#endif /* ACE_WIN32 */ + return 0; +} + +#if defined (VXWORKS) +int sys_nerr = ERRMAX + 1; +#endif /* VXWORKS */ |