summaryrefslogtreecommitdiff
path: root/ace/OS.cpp
diff options
context:
space:
mode:
authorChris Cleeland <chris.cleeland@gmail.com>1997-02-07 23:39:56 +0000
committerChris Cleeland <chris.cleeland@gmail.com>1997-02-07 23:39:56 +0000
commitecb436af35b92e0dce90f5567ab3673109263e11 (patch)
treef6100cffac8fa109ff91d0a7c1657d2717fcf959 /ace/OS.cpp
parent3da05609bfc1309906ce9ac66e07fce8aaa2458c (diff)
downloadATCD-ecb436af35b92e0dce90f5567ab3673109263e11.tar.gz
Updated set_sched_params for Digital and Linux.
Modified Files: OS.cpp
Diffstat (limited to 'ace/OS.cpp')
-rw-r--r--ace/OS.cpp2114
1 files changed, 2114 insertions, 0 deletions
diff --git a/ace/OS.cpp b/ace/OS.cpp
index f4c88991914..262d6d28621 100644
--- a/ace/OS.cpp
+++ b/ace/OS.cpp
@@ -516,6 +516,2120 @@ int
ACE_OS::set_sched_params (const ACE_Scheduling_Params &scheduling_params)
{
// ACE_TRACE ("ACE_OS::set_sched_params");
+#if defined (ACE_HAS_STHREADS)
+ // Set priority class, priority, and quantum of this LWP or process as
+ // specified in scheduling_params.
+
+ pcparms_t pcparms;
+ pcparms.pc_cid = scheduling_params.priority ().os_priority_class ();
+
+ if (scheduling_params.priority ().priority_class () ==
+ ACE_Thread_Priority::ACE_HIGH_PRIORITY_CLASS
+ || scheduling_params.priority ().priority_class () ==
+ ACE_Thread_Priority::ACE_REALTIME_PRIORITY_CLASS)
+ {
+ rtparms_t rtparms;
+ rtparms.rt_pri =
+ scheduling_params.priority ().os_default_thread_priority ();
+
+ if (scheduling_params.quantum () == ACE_Time_Value::zero)
+ {
+ // rtparms.rt_tqsecs is ignored with RT_TQINF
+ rtparms.rt_tqnsecs = RT_TQINF;
+ }
+ else
+ {
+ rtparms.rt_tqsecs = (ulong) scheduling_params.quantum ().sec ();
+ rtparms.rt_tqnsecs = scheduling_params.quantum ().usec () * 1000;
+ }
+
+ // Package up the RT class ID and parameters for the ::priocntl ()
+ // call.
+ ACE_OS::memcpy (pcparms.pc_clparms, &rtparms, sizeof rtparms);
+ }
+ else
+ {
+ tsparms_t tsparms;
+ // Don't change ts_uprilim (user priority limit)
+ tsparms.ts_uprilim = TS_NOCHANGE;
+ tsparms.ts_upri = scheduling_params.priority ().os_default_thread_priority ();
+
+ // Package up the TS class ID and parameters for the ::priocntl ()
+ // call.
+ ACE_OS::memcpy (pcparms.pc_clparms, &tsparms, sizeof tsparms);
+ }
+
+ if (::priocntl ((idtype_t) scheduling_params.scope (), P_MYID, PC_SETPARMS,
+ (char *) &pcparms) < 0)
+ {
+ return ACE_OS::last_error ();
+ }
+
+#elif defined (ACE_WIN32)
+
+ // Set the priority class of this process to the real-time process class.
+ if (! ::SetPriorityClass (::GetCurrentProcess (),
+ scheduling_params.priority ().os_priority_class ()))
+ return -1;
+
+ // Set the thread priority on the current thread.
+ ACE_hthread_t my_thread_id;
+ ACE_OS::thr_self (my_thread_id);
+ if (ACE_OS::thr_setprio (my_thread_id,
+ scheduling_params.priority ().os_default_thread_priority ()) == -1)
+ return -1;
+
+
+#elif defined (VXWORKS)
+ // There is only one class of priorities on VxWorks, and no
+ // time quanta. So, just set the current thread's priority.
+
+ ACE_hthread_t my_thread_id;
+ ACE_OS::thr_self (&my_thread_id);
+ // this call should never fail on VxWorks
+ ACE_OS::thr_setprio (my_thread_id,
+ scheduling_params.priority ().os_default_thread_priority ());
+
+#elif (defined (ACE_HAS_DCETHREADS) || defined (ACE_HAS_PTHREADS)) && !defined (ACE_LACKS_SETSCHED)
+ struct sched_param param;
+ int policy, result;
+ ACE_thread_t thr_id = ACE_OS::thr_self ();
+
+ ACE_OSCALL (ACE_ADAPT_RETVAL (::pthread_getschedparam (thr_id, &policy, &param),
+ result),
+ int, -1, result);
+ if (result == -1)
+ return result; // error in pthread_getschedparam
+
+ param.sched_priority =
+ scheduling_params.priority ().os_default_thread_priority ();
+ policy = scheduling_params.priority ().os_priority_class ();
+
+ ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::pthread_setschedparam (thr_id, policy,&param),
+ result),
+ int, -1);
+#else
+ ACE_NOTSUP_RETURN (ENOTSUP);
+#endif /* ACE_HAS_STHREADS */
+
+ return 0;
+}
+
+// = 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...
+ACE_thread_t ACE_OS::NULL_thread;
+ACE_hthread_t ACE_OS::NULL_hthread;
+ACE_thread_key_t ACE_OS::NULL_key;
+
+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:
+ int mark_cleanup_i (void);
+ // Mark a thread for actually performing cleanup.
+
+ int check_cleanup_i (void);
+ // Check if given thread is performing cleanup.
+
+ int exit_cleanup_i (void);
+ // Indicate that a thread has finished cleanup.
+
+ void dump (void);
+
+ ACE_TSS_Cleanup (void);
+ // Ensure singleton.
+
+private:
+ ACE_TSS_TABLE table_;
+ // Table of <ACE_TSS_Info>'s.
+
+ ACE_TSS_REF_TABLE ref_table_;
+ // Table of thread IDs that are performing cleanup activities.
+
+ // = Static data.
+ static ACE_TSS_Cleanup *instance_;
+ // Pointer to the singleton instance.
+
+public:
+ static ACE_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_Thread_Mutex ACE_TSS_Cleanup::lock_;
+
+int
+ACE_TSS_Cleanup::mark_cleanup_i (void)
+{
+ return this->ref_table_.insert (ACE_TSS_Ref (ACE_OS::thr_self ()));
+}
+
+int
+ACE_TSS_Cleanup::check_cleanup_i (void)
+{
+ return this->ref_table_.find (ACE_TSS_Ref (ACE_OS::thr_self ()));
+}
+
+int
+ACE_TSS_Cleanup::exit_cleanup_i (void)
+{
+ return this->ref_table_.remove (ACE_TSS_Ref (ACE_OS::thr_self ()));
+}
+
+void
+ACE_TSS_Cleanup::exit (void *status)
+{
+// ACE_TRACE ("ACE_TSS_Cleanup::exit");
+
+ ACE_thread_key_t key_arr[TLS_MINIMUM_AVAILABLE];
+ int index = 0;
+
+ ACE_TSS_Info *key_info = 0;
+ ACE_TSS_Info info_arr[TLS_MINIMUM_AVAILABLE];
+ int info_ix = 0;
+
+ // While holding the lock, we only collect the ACE_TSS_Info objects
+ // in an array without invoking the according destructors.
+
+ {
+ ACE_GUARD (ACE_Thread_Mutex, ace_mon, ACE_TSS_Cleanup::lock_);
+
+ // Prevent recursive deletions
+
+ if (this->check_cleanup_i ()) // Are we already performing cleanup?
+ return;
+
+ // If we can't insert our thread_id into the list, we will not be
+ // able to detect recursive invocations for this thread. Therefore
+ // we better risk memory and key leakages, resulting also in
+ // missing close() calls as to be invoked recursively.
+
+ if (this->mark_cleanup_i () != 0) // Insert our thread_id in list
+ return;
+
+ // 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)
+ info_arr[info_ix++] = *key_info; // copy this information into array
+
+ if (key_info->ref_table_.size () == 0
+ && key_info->tss_obj_ == 0)
+ key_arr[index++] = key_info->key_;
+ }
+ }
+
+ // Now we have given up the ACE_TSS_Cleanup::lock_ and we start
+ // invoking destructors.
+
+ for (int i = 0; i < info_ix; i++)
+ {
+ void *tss_info = 0;
+
+ ACE_OS::thr_getspecific (info_arr[i].key_, &tss_info);
+
+ (*info_arr[i].destructor_)(tss_info);
+ }
+
+ // Acquiring ACE_TSS_Cleanup::lock_ to free TLS keys and remove
+ // entries from ACE_TSS_Info table.
+ {
+ ACE_GUARD (ACE_Thread_Mutex, ace_mon, ACE_TSS_Cleanup::lock_);
+
+ for (int i = 0; i < index; i++)
+ {
+ ::TlsFree (key_arr[i]);
+ this->table_.remove (ACE_TSS_Info (key_arr[i]));
+ }
+
+ this->exit_cleanup_i (); // remove thread id from reference list.
+ }
+
+#if defined (ACE_HAS_MFC)
+ // allow CWinThread-destructor to be invoked from AfxEndThread
+ // _endthreadex will be called from AfxEndThread so don't exit the
+ // thread now if we are running an MFC thread.
+ CWinThread *pThread = ::AfxGetThread ();
+ if (!pThread || pThread->m_nThreadID != ACE_OS::thr_self ())
+#endif /* ACE_HAS_MFC */
+ ::_endthreadex ((DWORD) status);
+#if 0
+ ::ExitThread ((DWORD) status);
+#endif
+
+ /* 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_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_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_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_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 (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)
+{
+ ACE_UNUSED_ARG(key);
+ ACE_UNUSED_ARG(tid);
+
+ return -1;
+}
+
+int
+ACE_TSS_Cleanup::key_used (ACE_thread_key_t key)
+{
+ ACE_GUARD_RETURN (ACE_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 ();
+}
+
+#endif /* WIN32 */
+
+#if !defined (VXWORKS)
+class ACE_Thread_Adapter
+ // = TITLE
+ // Converts a C++ function into a function <ace_thread_adapter>
+ // function that can be called from a thread creation routine
+ // (e.g., pthread_create() or _beginthreadex()) that expects an
+ // extern "C" entry point.
+ //
+ // = DESCRIPTION
+ // This is used below in <ACE_OS::thr_create> for Win32 and
+ // MVS.
+{
+public:
+ ACE_Thread_Adapter (ACE_THR_FUNC f, void *a);
+ // Constructor.
+
+ // private:
+ // = Arguments to thread startup.
+ ACE_THR_FUNC func_;
+ // Thread startup function (C++ linkage).
+
+ void *arg_;
+ // Argument to thread startup function.
+
+ ACE_Log_Msg *inherit_log_;
+ // TSS log data of creating thread.
+};
+
+// Run the thread exit point. This must be an extern "C" to make
+// certain compilers happy...
+
+extern "C" void *
+ace_thread_adapter (void *args)
+{
+ // ACE_TRACE ("ace_thread_adapter");
+ ACE_Thread_Adapter *thread_args = (ACE_Thread_Adapter *) args;
+
+ ACE_THR_FUNC func = thread_args->func_;
+
+ // Inherit the logging feature if necessary.
+ ACE_Log_Msg *inherit_log = thread_args->inherit_log_;
+ ACE_Log_Msg *new_log = ACE_LOG_MSG;
+ new_log->msg_ostream (inherit_log->msg_ostream ());
+ new_log->priority_mask (inherit_log->priority_mask ());
+ if (inherit_log->tracing_enabled ())
+ new_log->start_tracing ();
+
+ void *arg = thread_args->arg_;
+
+ delete thread_args;
+
+#if defined (ACE_WIN32)
+ void *status;
+
+ ACE_SEH_TRY {
+ status = (*func) (arg); // Call thread entry point.
+ }
+ ACE_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
+ ACE_DEBUG ((LM_DEBUG, "(%t) Win32 structured exception exiting thread"));
+ // 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;
+#else
+ return (void *) (*func) (arg); // Call thread entry point.
+#endif /* ACE_WIN32 */
+}
+
+ACE_Thread_Adapter::ACE_Thread_Adapter (ACE_THR_FUNC f, void *a)
+ : func_(f),
+ arg_(a),
+ inherit_log_ (ACE_LOG_MSG)
+{
+// ACE_TRACE ("Ace_Thread_Adapter::Ace_Thread_Adapter");
+}
+#endif /* VXWORKS */
+
+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)
+ ACE_thread_t tmp_thr;
+ ACE_hthread_t tmp_handle;
+
+ if (thr_id == 0)
+ thr_id = &tmp_thr;
+
+ if (thr_handle == 0)
+ thr_handle = &tmp_handle;
+
+#if defined (ACE_HAS_DCETHREADS) || defined (ACE_HAS_PTHREADS)
+ int result;
+ pthread_attr_t attr;
+#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;
+#if !defined (ACE_LACKS_SETSCHED)
+ 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) || defined (ACE_HAS_PTHREADS_XAVIER)
+ 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;
+#else
+ sparam.sched_priority = priority;
+#endif /* ACE_HAS_DCETHREADS */
+
+#if !defined (ACE_HAS_FSU_PTHREADS)
+ int retval = 0;
+#if defined (ACE_HAS_SETKIND_NP)
+ if (::pthread_attr_setsched (&attr, SCHED_OTHER) != 0)
+#else /* ACE_HAS_SETKIND_NP */
+ if ((retval = ::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 */
+ errno = retval;
+ 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 */
+ }
+#endif /* ACE_LACKS_SETSCHED */
+
+#if defined (ACE_NEEDS_HUGE_THREAD_STACKSIZE)
+ if (stacksize < ACE_NEEDS_HUGE_THREAD_STACKSIZE)
+ stacksize = ACE_NEEDS_HUGE_THREAD_STACKSIZE;
+#endif /* ACE_NEEDS_HUGE_THREAD_STACKSIZE */
+
+ if (stacksize != 0)
+ {
+ size_t size = stacksize;
+
+#if defined (PTHREAD_STACK_MIN)
+ if (size < PTHREAD_STACK_MIN)
+ size = PTHREAD_STACK_MIN;
+#endif /* PTHREAD_STACK_MIN */
+
+#if !defined (ACE_LACKS_THREAD_STACK_SIZE) // JCEJ 12/17/96
+ 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;
+ }
+#endif /* !ACE_LACKS_THREAD_STACK_SIZE */
+ }
+
+#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 defined (ACE_HAS_PTHREAD_DSTATE_PTR)
+ if (::pthread_attr_setdetachstate (&attr, &dstate) != 0)
+#else
+ if (::pthread_attr_setdetachstate (&attr, dstate) != 0)
+#endif /* ACE_HAS_PTHREAD_DSTATE_PTR */
+#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 !defined (ACE_LACKS_SETSCHED)
+ 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;
+ }
+ }
+#endif /* ACE_LACKS_SETSCHED */
+#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);
+ }
+ }
+
+#if defined (ACE_HAS_SETKIND_NP)
+ ACE_OSCALL (ACE_ADAPT_RETVAL (::pthread_create (thr_id, attr, func, args),
+ result),
+ int, -1, result);
+ ::pthread_attr_delete (&attr);
+#else /* !ACE_HAS_SETKIND_NP */
+#if defined (ACE_HAS_THR_C_FUNC)
+ ACE_Thread_Adapter *thread_args;
+ ACE_NEW_RETURN (thread_args, ACE_Thread_Adapter (func, args), -1);
+
+ ACE_OSCALL (ACE_ADAPT_RETVAL (::pthread_create (thr_id, &attr,
+ ACE_THR_C_FUNC (&ace_thread_adapter),
+ thread_args),
+ result),
+ int, -1, result);
+#else
+ ACE_OSCALL (ACE_ADAPT_RETVAL (::pthread_create (thr_id, &attr, func, args),
+ result),
+ int, -1, result);
+#endif /* ACE_HAS_THR_C_FUNC */
+ ::pthread_attr_destroy (&attr);
+#endif /* ACE_HAS_SETKIND_NP */
+#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 != -1)
+ *thr_handle = *thr_id;
+#else
+ *thr_handle = ACE_OS::NULL_hthread;
+#endif /* ACE_HAS_STHREADS */
+ return result;
+#elif defined (ACE_HAS_STHREADS)
+ int result;
+ int start_suspended = ACE_BIT_ENABLED (flags, THR_SUSPENDED);
+
+ if (priority > 0)
+ // If we need to set the priority, then we need to start the
+ // thread in a suspended mode.
+ ACE_SET_BITS (flags, THR_SUSPENDED);
+
+ ACE_OSCALL (ACE_ADAPT_RETVAL (::thr_create (stack, stacksize, func, args,
+ flags, thr_id), result),
+ int, -1, result);
+
+ if (result != -1)
+ {
+ if (priority > 0)
+ {
+ // Set the priority of the new thread and then let it
+ // continue, but only if the user didn't start it suspended
+ // in the first place!
+ ACE_OS::thr_setprio (*thr_handle, priority);
+
+ if (start_suspended == 0)
+ ACE_OS::thr_continue (*thr_handle);
+ }
+ }
+ return result;
+#elif defined (ACE_HAS_WTHREADS)
+ ACE_UNUSED_ARG (stack);
+ ACE_Thread_Adapter *thread_args;
+ ACE_NEW_RETURN (thread_args, ACE_Thread_Adapter (func, args), -1);
+#if defined (ACE_HAS_MFC)
+ if (ACE_BIT_ENABLED (flags, THR_USE_AFX))
+ {
+ CWinThread *cwin_thread =
+ ::AfxBeginThread ((AFX_THREADPROC) &ace_thread_adapter,
+ thread_args, priority, 0,
+ flags | THR_SUSPENDED);
+ // Have to duplicate the handle because
+ // CWinThread::~CWinThread() closes the original handle.
+ (void) ::DuplicateHandle (::GetCurrentProcess (),
+ cwin_thread->m_hThread,
+ ::GetCurrentProcess (),
+ thr_handle,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS);
+
+ *thr_id = cwin_thread->m_nThreadID;
+
+ if (ACE_BIT_ENABLED (flags, THR_SUSPENDED) == 0)
+ cwin_thread->ResumeThread ();
+ // cwin_thread will be deleted in AfxThreadExit()
+ // Warning: If AfxThreadExit() is called from within the
+ // thread, ACE_TSS_Cleanup->exit() never gets called !
+ }
+ else
+#endif /* ACE_HAS_MFC */
+ {
+ int start_suspended = ACE_BIT_ENABLED (flags, THR_SUSPENDED);
+
+ if (priority > 0)
+ // If we need to set the priority, then we need to start the
+ // thread in a suspended mode.
+ ACE_SET_BITS (flags, THR_SUSPENDED);
+
+ *thr_handle = (void *) ::_beginthreadex
+ (NULL,
+ stacksize,
+ ACE_THR_C_FUNC (&ace_thread_adapter),
+ thread_args,
+ flags,
+ (unsigned int *) thr_id);
+
+ if (priority > 0 && *thr_handle != 0)
+ {
+ // Set the priority of the new thread and then let it
+ // continue, but only if the user didn't start it suspended
+ // in the first place!
+ ACE_OS::thr_setprio (*thr_handle, priority);
+
+ if (start_suspended == 0)
+ ACE_OS::thr_continue (*thr_handle);
+ }
+ }
+#if 0
+ *thr_handle = ::CreateThread
+ (NULL, stacksize,
+ LPTHREAD_START_ROUTINE (ACE_THR_C_FUNC (ace_thread_adapter),
+ thread_args, flags, thr_id);
+#endif /* 0 */
+
+ // Close down the handle if no one wants to use it.
+ if (thr_handle == &tmp_handle)
+ ::CloseHandle (tmp_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.
+
+ // The 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
+ {
+ // ::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
+ // might be a bit quicker than this extraction of the tcb . . .
+ *thr_id = ::taskTcb (tid)->name;
+ *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_THR_KEYDELETE)
+ return ::thr_keydelete (key);
+#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,
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_THR_C_DEST dest,
+#else
+ ACE_THR_DEST dest,
+#endif /* ACE_HAS_THR_C_DEST */
+ 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);
+
+ LPTSTR buf = (LPTSTR) ACE_WIDE_STRING (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;
+ }
+#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 (ACE_LACKS_SYS_NERR)
+int sys_nerr = ERRMAX + 1;
+#endif /* ACE_LACKS_SYS_NERR */
+
+#if defined (VXWORKS)
+#include /**/ <usrLib.h> /* for ::sp() */
+
+// This global function can be used from the VxWorks shell to pass
+// arguments to a C main () function. usage: -> spa main, "arg1",
+// "arg2" All arguments must be quoted, even numbers.
+int
+spa (FUNCPTR entry, ...)
+{
+ static const unsigned int MAX_ARGS = 10;
+ static char *argv[MAX_ARGS];
+ va_list pvar;
+ int argc;
+
+ // Hardcode a program name because the real one isn't available
+ // through the VxWorks shell.
+ argv[0] = "spa ():t";
+
+ // Peel off arguments to spa () and put into argv. va_arg () isn't
+ // necessarily supposed to return 0 when done, though since the
+ // VxWorks shell uses a fixed number (10) of arguments, it might 0
+ // the unused ones. This function could be used to increase that
+ // limit, but then it couldn't depend on the trailing 0. So, the
+ // number of arguments would have to be passed.
+ va_start (pvar, entry);
+
+ for (argc = 1; argc <= MAX_ARGS; ++argc)
+ {
+ argv[argc] = va_arg (pvar, char *);
+
+ if (argv[argc] == 0)
+ break;
+ }
+
+ if (argc > MAX_ARGS && argv[argc-1] != 0)
+ {
+ // try to read another arg, and warn user if the limit was exceeded
+ if (va_arg (pvar, char *) != 0)
+ fprintf (stderr, "spa(): number of arguments limited to %d\n",
+ MAX_ARGS);
+ }
+ else
+ {
+ // fill unused argv slots with 0 to get rid of leftovers
+ // from previous invocations
+ for (int i = argc; i <= MAX_ARGS; ++i)
+ argv[i] = 0;
+ }
+
+ int ret = ::sp (entry, argc, (int) argv, 0, 0, 0, 0, 0, 0, 0);
+ va_end (pvar);
+
+ // ::sp () returns the taskID on success: return 0 instead if
+ // successful
+ return ret > 0 ? 0 : ret;
+}
+#endif /* VXWORKS */
+
+#if !defined (ACE_HAS_SIGINFO_T)
+siginfo_t::siginfo_t (ACE_HANDLE handle)
+ : si_handle_ (handle),
+ si_handles_ (&handle)
+{
+}
+
+siginfo_t::siginfo_t (ACE_HANDLE *handles)
+ : si_handle_ (handles[0]),
+ si_handles_ (handles)
+{
+}
+#endif /* ACE_HAS_SIGINFO_T */
+
+// This is necessary to work around nasty problems with MVS C++.
+
+extern "C" void
+ace_mutex_lock_cleanup_adapter (void *args)
+{
+ ACE_OS::mutex_lock_cleanup (args);
+}
+
+ACE_Thread_ID::ACE_Thread_ID (ACE_thread_t thread_id,
+ ACE_hthread_t thread_handle)
+ : thread_id_ (thread_id),
+ thread_handle_ (thread_handle)
+{
+}
+
+ACE_thread_t
+ACE_Thread_ID::id (void)
+{
+ return this->thread_id_;
+}
+
+void
+ACE_Thread_ID::id (ACE_thread_t thread_id)
+{
+ this->thread_id_ = thread_id;
+}
+
+ACE_hthread_t
+ACE_Thread_ID::handle (void)
+{
+ return this->thread_handle_;
+}
+
+void
+ACE_Thread_ID::handle (ACE_hthread_t thread_handle)
+{
+ this->thread_handle_ = thread_handle;
+}
+
+int
+ACE_Thread_ID::operator == (const ACE_Thread_ID &rhs)
+{
+ return ACE_OS::thr_cmp (this->thread_handle_, rhs.thread_handle_) == 0
+ && ACE_OS::thr_equal (this->thread_id_, rhs.thread_id_) == 0;
+}
+
+int
+ACE_Thread_ID::operator != (const ACE_Thread_ID &rhs)
+{
+ return !(*this == rhs);
+}
+=======
+// $Id$
+
+// OS.cpp
+#define ACE_BUILD_DLL
+#include "ace/OS.h"
+#include "ace/Scheduling_Params.h"
+
+#if defined (ACE_WIN32)
+#include "ace/ARGV.h"
+#endif /* ACE_WIN32 */
+
+// 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 */
+
+// Static constant representing `zero-time'.
+const ACE_Time_Value ACE_Time_Value::zero;
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Time_Value)
+
+// Initializes the ACE_Time_Value object from a timeval.
+
+ACE_Time_Value::ACE_Time_Value (const timeval &tv)
+{
+ // ACE_TRACE ("ACE_Time_Value::ACE_Time_Value");
+ this->set (tv);
+}
+
+#if defined(ACE_WIN32)
+// Initializes the ACE_Time_Value object from a Win32 FILETIME
+
+ACE_Time_Value::ACE_Time_Value (const FILETIME &file_time)
+{
+ // ACE_TRACE ("ACE_Time_Value::ACE_Time_Value");
+ this->set (file_time);
+}
+
+void ACE_Time_Value::set (const FILETIME &file_time)
+{
+ // Initializes the ACE_Time_Value object from a Win32 FILETIME
+ ACE_QWORD _100ns = ACE_MAKE_QWORD (file_time.dwLowDateTime,
+ file_time.dwHighDateTime);
+ // Convert 100ns units to seconds;
+ this->tv_sec_ = long (_100ns / (10000 * 1000));
+ // Convert remainder to microseconds;
+ this->tv_usec_ = long ((_100ns - (this->tv_sec_ * (10000 * 1000))) / 10);
+}
+
+// Returns the value of the object as a Win32 FILETIME.
+
+ACE_Time_Value::operator FILETIME () const
+{
+ // ACE_TRACE ("ACE_Time_Value::operator FILETIME");
+ ACE_QWORD _100ns = ((ACE_QWORD) this->tv_sec_ * (1000 * 1000) + this->tv_usec_) * 10;
+ FILETIME file_time;
+ file_time.dwLowDateTime = ACE_LOW_DWORD (_100ns);
+ file_time.dwHighDateTime = ACE_HIGH_DWORD (_100ns);
+ return file_time;
+}
+
+#endif
+
+void
+ACE_Time_Value::dump (void) const
+{
+ // ACE_TRACE ("ACE_Time_Value::dump");
+#if 0
+ if (tv.usec () < 0 || tv.sec () < 0)
+ stream << "-";
+
+ stream << dec << abs (int (tv.sec ())) << "."
+// << setw (6) << setfill ('0')
+ << dec << abs (int (tv.usec ()));
+// I assume
+ inline int abs(int d) { return (d>0)?d:-d; }
+ is defined somewhere */
+#endif /* 0 */
+}
+
+void
+ACE_Time_Value::set (long sec, long usec)
+{
+ // ACE_TRACE ("ACE_Time_Value::set");
+ this->tv_sec_ = sec;
+ this->tv_usec_ = usec;
+}
+
+void
+ACE_Time_Value::set (double d)
+{
+ // ACE_TRACE ("ACE_Time_Value::set");
+ long l = (long) d;
+ this->tv_sec_ = l;
+ this->tv_usec_ = ((long) (d - (double) l)) * 1000000;
+ this->normalize ();
+}
+
+ACE_Time_Value::ACE_Time_Value (long sec, long usec)
+{
+ // ACE_TRACE ("ACE_Time_Value::ACE_Time_Value");
+ this->set (sec, usec);
+ this->normalize ();
+}
+
+// Returns the value of the object as a timeval.
+
+ACE_Time_Value::operator timeval () const
+{
+ // ACE_TRACE ("ACE_Time_Value::operator timeval");
+ timeval tv;
+ tv.tv_sec = this->tv_sec_;
+ tv.tv_usec = this->tv_usec_;
+ return tv;
+}
+
+// Add TV to this.
+
+void
+ACE_Time_Value::operator+= (const ACE_Time_Value &tv)
+{
+ // ACE_TRACE ("ACE_Time_Value::operator+=");
+ this->tv_sec_ += tv.tv_sec_;
+ this->tv_usec_ += tv.tv_usec_;
+ this->normalize ();
+}
+
+// Subtract TV to this.
+
+void
+ACE_Time_Value::operator-= (const ACE_Time_Value &tv)
+{
+ // ACE_TRACE ("ACE_Time_Value::operator-=");
+ this->tv_sec_ -= tv.tv_sec_;
+ this->tv_usec_ -= tv.tv_usec_;
+ this->normalize ();
+}
+
+// Adds two ACE_Time_Value objects together, returns the sum.
+
+ACE_Time_Value
+operator + (const ACE_Time_Value &tv1, const ACE_Time_Value &tv2)
+{
+ // ACE_TRACE ("operator +");
+ ACE_Time_Value sum (tv1.tv_sec_ + tv2.tv_sec_,
+ tv1.tv_usec_ + tv2.tv_usec_);
+
+ sum.normalize ();
+ return sum;
+}
+
+// Subtracts two ACE_Time_Value objects, returns the difference.
+
+ACE_Time_Value
+operator - (const ACE_Time_Value &tv1, const ACE_Time_Value &tv2)
+{
+ // ACE_TRACE ("operator -");
+ ACE_Time_Value delta (tv1.tv_sec_ - tv2.tv_sec_,
+ tv1.tv_usec_ - tv2.tv_usec_);
+ delta.normalize ();
+ return delta;
+}
+
+// True if tv1 > tv2.
+
+int
+operator > (const ACE_Time_Value &tv1, const ACE_Time_Value &tv2)
+{
+ // ACE_TRACE ("operator >");
+ if (tv1.tv_sec_ > tv2.tv_sec_)
+ return 1;
+ else if (tv1.tv_sec_ == tv2.tv_sec_
+ && tv1.tv_usec_ > tv2.tv_usec_)
+ return 1;
+ else
+ return 0;
+}
+
+// True if tv1 >= tv2.
+
+int
+operator >= (const ACE_Time_Value &tv1, const ACE_Time_Value &tv2)
+{
+ // ACE_TRACE ("operator >=");
+ if (tv1.tv_sec_ > tv2.tv_sec_)
+ return 1;
+ else if (tv1.tv_sec_ == tv2.tv_sec_
+ && tv1.tv_usec_ >= tv2.tv_usec_)
+ return 1;
+ else
+ return 0;
+}
+
+void
+ACE_Time_Value::normalize (void)
+{
+ // ACE_TRACE ("ACE_Time_Value::normalize");
+ // New code from Hans Rohnert...
+
+ if (this->tv_usec_ >= ONE_SECOND)
+ {
+ do
+ {
+ this->tv_sec_++;
+ this->tv_usec_ -= ONE_SECOND;
+ }
+ while (this->tv_usec_ >= ONE_SECOND);
+ }
+ else if (this->tv_usec_ <= -ONE_SECOND)
+ {
+ do
+ {
+ this->tv_sec_--;
+ this->tv_usec_ += ONE_SECOND;
+ }
+ while (this->tv_usec_ <= -ONE_SECOND);
+ }
+
+ if (this->tv_sec_ >= 1 && this->tv_usec_ < 0)
+ {
+ this->tv_sec_--;
+ this->tv_usec_ += ONE_SECOND;
+ }
+ else if (this->tv_sec_ < 0 && this->tv_usec_ > 0)
+ {
+ this->tv_sec_++;
+ this->tv_usec_ -= ONE_SECOND;
+ }
+
+#if 0
+ // Old code...
+ while ((this->tv_usec_ >= ONE_SECOND)
+ || (this->tv_sec_ < 0 && this->tv_usec_ > 0 ))
+ {
+ this->tv_usec_ -= ONE_SECOND;
+ this->tv_sec_++;
+ }
+
+ while ((this->tv_usec_ <= -ONE_SECOND)
+ || (this->tv_sec_ > 0 && this->tv_usec_ < 0))
+ {
+ this->tv_usec_ += ONE_SECOND;
+ this->tv_sec_--;
+ }
+#endif
+}
+
+int
+ACE_Countdown_Time::start (void)
+{
+ this->start_time_ = ACE_OS::gettimeofday ();
+ this->stopped_ = 0;
+ return 0;
+}
+
+int
+ACE_Countdown_Time::update (void)
+{
+ return (this->stop () == 0) && this->start ();
+}
+
+int
+ACE_Countdown_Time::stop (void)
+{
+ if (this->max_wait_time_ != 0 && this->stopped_ == 0)
+ {
+ ACE_Time_Value elapsed_time =
+ ACE_OS::gettimeofday () - this->start_time_;
+
+ if (*this->max_wait_time_ > elapsed_time)
+ *this->max_wait_time_ -= elapsed_time;
+ else
+ {
+ // Used all of timeout.
+ *this->max_wait_time_ = ACE_Time_Value::zero;
+ errno = ETIME;
+ }
+ this->stopped_ = 1;
+ }
+ return 0;
+}
+
+ACE_Countdown_Time::ACE_Countdown_Time (ACE_Time_Value *max_wait_time)
+ : max_wait_time_ (max_wait_time),
+ stopped_ (0)
+{
+ if (max_wait_time != 0)
+ this->start ();
+}
+
+ACE_Countdown_Time::~ACE_Countdown_Time (void)
+{
+ this->stop ();
+}
+
+#if defined(ACE_MT_SAFE) && defined(ACE_LACKS_NETDB_REENTRANT_FUNCTIONS)
+
+int ACE_OS::netdb_mutex_inited_ = 0;
+
+ACE_mutex_t ACE_OS::netdb_mutex_;
+
+int
+ACE_OS::netdb_acquire (void)
+{
+ if (ACE_OS::netdb_mutex_inited_ == 0)
+ {
+ if (ACE_OS::thread_mutex_init (&ACE_OS::netdb_mutex_) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n",
+ "ACE_OS::netdb_acquire[init]"), -1);
+ ACE_OS::netdb_mutex_inited_ = 1;
+ }
+
+ if (ACE_OS::thread_mutex_lock (&ACE_OS::netdb_mutex_) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n",
+ "ACE_OS::netdb_acquire[lock]"), -1);
+ return 0;
+}
+
+int
+ACE_OS::netdb_release (void)
+{
+ if (ACE_OS::netdb_mutex_inited_ == 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n",
+ "ACE_OS::netdb_release[inited]"), -1);
+
+ if (ACE_OS::thread_mutex_unlock (&ACE_OS::netdb_mutex_) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n",
+ "ACE_OS::netdb_release[unlock]"), -1);
+ return 0;
+}
+#endif /* defined(ACE_MT_SAFE) && defined(ACE_LACKS_NETDB_REENTRANT_FUNCTIONS) */
+
+struct hostent *
+ACE_OS::gethostbyname (const char *name)
+{
+ // ACE_TRACE ("ACE_OS::gethostbyname");
+#if defined (VXWORKS)
+ // not thread safe!
+ static hostent ret;
+ static int first_addr = ::hostGetByName ((char *) name);
+ static char *hostaddr[2];
+
+ if (first_addr == -1)
+ return 0;
+
+ hostaddr[0] = (char *) &first_addr;
+ hostaddr[1] = 0;
+
+ // might not be official: just echo input arg.
+ ret.h_name = (char *) name;
+ ret.h_addrtype = AF_INET;
+ ret.h_length = 4; // VxWorks 5.2/3 doesn't define IP_ADDR_LEN;
+ ret.h_addr_list = hostaddr;
+
+ return &ret;
+#elif defined (ACE_HAS_NONCONST_GETBY)
+ ACE_SOCKCALL_RETURN (::gethostbyname ((char *) name), struct hostent *, 0);
+#else
+ ACE_SOCKCALL_RETURN (::gethostbyname (name), struct hostent *, 0);
+#endif /* ACE_HAS_NONCONST_GETBY */
+}
+
+#if defined (VXWORKS)
+// not inline because it has the static char array
+char *
+ACE_OS::inet_ntoa (const struct in_addr addr)
+{
+ // ACE_TRACE ("ACE_OS::inet_ntoa");
+
+ // the following storage is not thread-specific!
+ static char buf[32];
+ // assumes that addr is already in network byte order
+ sprintf (buf, "%d.%d.%d.%d", addr.s_addr / (256*256*256) & 255,
+ addr.s_addr / (256*256) & 255,
+ addr.s_addr / 256 & 255,
+ addr.s_addr & 255);
+ return buf;
+}
+#endif /* VXWORKS */
+
+void
+ACE_OS::ace_flock_t::dump (void) const
+{
+// ACE_TRACE ("ACE_OS::ace_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);
+#else
+ ACE_UNUSED_ARG(mutex);
+#endif /* ACE_HAS_DCETHREADS */
+#endif /* ACE_HAS_THREADS */
+}
+
+// The following *printf functions aren't inline because
+// they use varargs.
+int
+ACE_OS::fprintf (FILE *fp, const char *format, ...)
+{
+ // ACE_TRACE ("ACE_OS::fprintf");
+ int result = 0;
+ va_list ap;
+ va_start (ap, format);
+ ACE_OSCALL (::vfprintf (fp, format, ap), int, -1, result);
+ va_end (ap);
+ return result;
+}
+
+int
+ACE_OS::printf (const char *format, ...)
+{
+ // ACE_TRACE ("ACE_OS::printf");
+ int result;
+ va_list ap;
+ va_start (ap, format);
+ ACE_OSCALL (::vprintf (format, ap), int, -1, result);
+ va_end (ap);
+ return result;
+}
+
+int
+ACE_OS::sprintf (char *buf, const char *format, ...)
+{
+ // ACE_TRACE ("ACE_OS::sprintf");
+ int result;
+ va_list ap;
+ va_start (ap, format);
+ ACE_OSCALL (::vsprintf (buf, format, ap), int, -1, result);
+ va_end (ap);
+ return result;
+}
+
+#if defined (ACE_HAS_UNICODE)
+#if defined (ACE_WIN32)
+int
+ACE_OS::sprintf (wchar_t *buf, const wchar_t *format, ...)
+{
+ // ACE_TRACE ("ACE_OS::sprintf");
+ int result;
+ va_list ap;
+ va_start (ap, format);
+ ACE_OSCALL (::vswprintf (buf, format, ap), int, -1, result);
+ va_end (ap);
+ return result;
+}
+#endif /* ACE_WIN32 */
+#endif /* ACE_HAS_UNICODE */
+
+int
+ACE_OS::execl (const char * /* path */, const char * /* arg0 */, ...)
+{
+ // ACE_TRACE ("ACE_OS::execl");
+#if defined (ACE_WIN32) || defined (VXWORKS)
+ ACE_NOTSUP_RETURN (-1);
+#else
+ ACE_NOTSUP_RETURN (-1);
+ // Need to write this code.
+ // ACE_OSCALL_RETURN (::execv (path, argv), int, -1);
+#endif /* ACE_WIN32 */
+}
+
+int
+ACE_OS::execle (const char * /* path */, const char * /* arg0 */, ...)
+{
+ // ACE_TRACE ("ACE_OS::execle");
+#if defined (ACE_WIN32) || defined (VXWORKS)
+ ACE_NOTSUP_RETURN (-1);
+#else
+ ACE_NOTSUP_RETURN (-1);
+ // Need to write this code.
+ // ACE_OSCALL_RETURN (::execve (path, argv, envp), int, -1);
+#endif /* ACE_WIN32 */
+}
+
+int
+ACE_OS::execlp (const char * /* file */, const char * /* arg0 */, ...)
+{
+ // ACE_TRACE ("ACE_OS::execlp");
+#if defined (ACE_WIN32) || defined (VXWORKS)
+ ACE_NOTSUP_RETURN (-1);
+#else
+ ACE_NOTSUP_RETURN (-1);
+ // Need to write this code.
+ // ACE_OSCALL_RETURN (::execvp (file, argv), int, -1);
+#endif /* ACE_WIN32 */
+}
+
+#if defined (ACE_HAS_STHREADS)
+#include <sys/rtpriocntl.h>
+#include <sys/tspriocntl.h>
+#endif /* ACE_HAS_STHREADS */
+
+int
+ACE_OS::set_sched_params (const ACE_Scheduling_Params &scheduling_params)
+{
+ // ACE_TRACE ("ACE_OS::set_sched_params");
#if defined (ACE_HAS_STHREADS)
// Set priority class, priority, and quantum of this LWP or process as