// $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_TABLE; typedef ACE_Unbounded_Set_Iterator 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 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 objects that will reside // within thread-specific storage. typedef ACE_Unbounded_Set ACE_TSS_TABLE; typedef ACE_Unbounded_Set_Iterator 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 . int insert (ACE_thread_key_t key, void (*destructor)(void *), void *inst); // Insert a tuple into the table. int remove (ACE_thread_key_t key); // Remove a 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 's. // = Static data. static ACE_TSS_Cleanup *instance_; // Pointer to the singleton instance. public: static ACE_Recursive_Thread_Mutex lock_; // Serialize initialization of . }; // = Static object initialization. // Pointer to the singleton instance. ACE_TSS_Cleanup *ACE_TSS_Cleanup::instance_ = 0; // Serialize initialization of . 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 ). 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 defined (ACE_HAS_STHREADS) // This is the Solaris implementation of pthreads, where // ACE_thread_t and ACE_hthread_t are the same. if (result == 0 && thr_handle != 0) *thr_handle = *thr_id; #else if (thr_handle != 0) thr_handle = (ACE_hthread_t *) 0; #endif /* ACE_HAS_STHREADS */ #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 (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) ACE_hthread_t tid; ACE_OS::thr_self (tid); *((int *) status) = ::taskDelete (tid); #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), ace_result_), int, -1); #elif defined (ACE_HAS_STHREADS) ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_setspecific (key, data), ace_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), ace_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"); inst = inst; #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), ace_result_), int, -1); #else /* ACE_HAS_SETKIND_NP */ ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::pthread_key_create (key, dest), ace_result_), int, -1); #endif /* ACE_HAS_SETKIND_NP */ #elif defined (ACE_HAS_STHREADS) ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_keycreate (key, dest), ace_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 key = key; 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 inst = inst; 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 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 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; } #else version_high = version_high; version_low = version_low; #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 */