server/dep/acelite/ace/OS_NS_Thread.inl
2023-01-01 00:55:45 +00:00

3905 lines
113 KiB
C++

// -*- C++ -*-
//
// $Id: OS_NS_Thread.inl 97911 2014-10-07 21:58:25Z shuston $
#include "ace/OS_NS_macros.h"
// for timespec_t, perhaps move it to os_time.h
#include "ace/Time_Value.h"
#include "ace/OS_NS_sys_mman.h"
#include "ace/OS_NS_sys_time.h"
#include "ace/OS_NS_string.h"
#include "ace/OS_NS_unistd.h"
#include "ace/OS_NS_stdio.h"
#include "ace/OS_NS_errno.h"
#if defined (ACE_USES_FIFO_SEM)
# include "ace/OS_NS_sys_stat.h"
# include "ace/OS_NS_sys_select.h"
# include "ace/OS_NS_fcntl.h"
# include "ace/Handle_Set.h"
# endif /* ACE_USES_FIFO_SEM */
#if defined (ACE_HAS_PRIOCNTL)
# include /**/ <sys/priocntl.h>
#endif /* ACE_HAS_PRIOCNTL */
ACE_BEGIN_VERSIONED_NAMESPACE_DECL
/*****************************************************************************/
#if defined (ACE_LACKS_COND_T) && defined (ACE_HAS_THREADS)
ACE_INLINE long
ACE_cond_t::waiters (void) const
{
return this->waiters_;
}
#endif /* ACE_LACKS_COND_T && ACE_HAS_THREADS */
/*****************************************************************************/
#if defined (ACE_HAS_TSS_EMULATION)
# if !defined (ACE_HAS_THREAD_SPECIFIC_STORAGE)
ACE_INLINE
void **&
ACE_TSS_Emulation::tss_base ()
{
# if defined (ACE_HAS_VXTHREADS)
# if (!defined (_WRS_CONFIG_SMP) && !defined (INCLUDE_AMP_CPU))
if (taskVarGet(0, reinterpret_cast<int*>(&ace_tss_keys)) == ERROR)
taskVarAdd(0, reinterpret_cast<int*>(&ace_tss_keys));
# endif
return reinterpret_cast <void **&> (ace_tss_keys);
# else
// Uh oh.
ACE_NOTSUP_RETURN (0);
# endif /* ACE_HAS_VXTHREADS */
}
# endif /* ! ACE_HAS_THREAD_SPECIFIC_STORAGE */
ACE_INLINE
ACE_TSS_Emulation::ACE_TSS_DESTRUCTOR
ACE_TSS_Emulation::tss_destructor (const ACE_thread_key_t key)
{
return tss_destructor_ [key];
}
ACE_INLINE
void
ACE_TSS_Emulation::tss_destructor (const ACE_thread_key_t key,
ACE_TSS_DESTRUCTOR destructor)
{
tss_destructor_ [key] = destructor;
}
ACE_INLINE
void *&
ACE_TSS_Emulation::ts_object (const ACE_thread_key_t key)
{
# if defined (ACE_HAS_VXTHREADS)
/* If someone wants tss_base make sure they get one. This
gets used if someone spawns a VxWorks task directly, not
through ACE. The allocated array will never be deleted! */
if (ace_tss_keys == 0)
{
ace_tss_keys = new void *[ACE_TSS_THREAD_KEYS_MAX];
// Zero the entire TSS array. Do it manually instead of using
// memset, for optimum speed. Though, memset may be faster :-)
void **tss_base_p = reinterpret_cast<void **> (ace_tss_keys);
for (u_int i = 0; i < ACE_TSS_THREAD_KEYS_MAX; ++i, ++tss_base_p)
{
*tss_base_p = 0;
}
}
# endif /* ACE_HAS_VXTHREADS */
return tss_base ()[key];
}
#endif /* ACE_HAS_TSS_EMULATION */
/*****************************************************************************/
ACE_INLINE int
ACE_OS::thr_equal (ACE_thread_t t1, ACE_thread_t t2)
{
#if defined (ACE_HAS_PTHREADS)
# if defined (pthread_equal)
// If it's a macro we can't say "pthread_equal"...
return pthread_equal (t1, t2);
# else
return pthread_equal (t1, t2);
# endif /* pthread_equal */
#else /* For both STHREADS and WTHREADS... */
// Hum, Do we need to treat WTHREAD differently?
// levine 13 oct 98 % I don't think so, ACE_thread_t is a DWORD.
return t1 == t2;
#endif /* ACE_HAS_PTHREADS */
}
ACE_INLINE int
ACE_OS::condattr_destroy (ACE_condattr_t &attributes)
{
#if defined (ACE_HAS_THREADS) && !defined (ACE_LACKS_CONDATTR)
# if defined (ACE_HAS_PTHREADS)
pthread_condattr_destroy (&attributes);
# else
attributes.type = 0;
# endif /* ACE_HAS_PTHREADS */
return 0;
# else
ACE_UNUSED_ARG (attributes);
return 0;
# endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::condattr_init (ACE_condattr_t &attributes, int type)
{
ACE_UNUSED_ARG (type);
# if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_PTHREADS)
int result = -1;
# if !defined (ACE_LACKS_CONDATTR)
# if defined (ACE_PTHREAD_CONDATTR_T_INITIALIZE)
/* Tests show that VxWorks 6.x pthread lib does not only
* require zeroing of mutex/condition objects to function correctly
* but also of the attribute objects.
*/
ACE_OS::memset (&attributes, 0, sizeof (attributes));
# endif
if (
ACE_ADAPT_RETVAL (pthread_condattr_init (&attributes), result) == 0
# if defined (_POSIX_THREAD_PROCESS_SHARED) && !defined (ACE_LACKS_CONDATTR_PSHARED)
&& ACE_ADAPT_RETVAL (pthread_condattr_setpshared (&attributes, type),
result) == 0
# endif /* _POSIX_THREAD_PROCESS_SHARED && ! ACE_LACKS_CONDATTR_PSHARED */
)
# else
if (type == USYNC_THREAD)
# endif /* !ACE_LACKS_CONDATTR */
result = 0;
else
{
ACE_UNUSED_ARG (attributes);
result = -1; // ACE_ADAPT_RETVAL used it for intermediate status
}
return result;
# else
attributes.type = type;
return 0;
# endif /* ACE_HAS_PTHREADS */
# else
ACE_UNUSED_ARG (attributes);
ACE_UNUSED_ARG (type);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::condattr_synctype (ACE_condattr_t &attributes, int& type)
{
# if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_PTHREADS)
# if !defined (ACE_LACKS_CONDATTR) && defined (_POSIX_THREAD_PROCESS_SHARED) && !defined (ACE_LACKS_CONDATTR_PSHARED)
int result = -1;
if (
ACE_ADAPT_RETVAL (pthread_condattr_getpshared (&attributes, &type),
result) == 0
)
{
result = 0;
}
# else
ACE_UNUSED_ARG (attributes);
int result = 0;
type = USYNC_THREAD;
# endif /* !ACE_LACKS_CONDATTR && _POSIX_THREAD_PROCESS_SHARED && ! ACE_LACKS_CONDATTR_PSHARED */
return result;
# else
type = attributes.type;
return 0;
# endif /* ACE_HAS_PTHREADS */
# else
ACE_UNUSED_ARG (attributes);
ACE_UNUSED_ARG (type);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::condattr_setclock (ACE_condattr_t &attributes, clockid_t clock_id)
{
# if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_PTHREADS) && !defined (ACE_LACKS_CONDATTR)
int result = -1;
# if defined (_POSIX_CLOCK_SELECTION) && !defined (ACE_LACKS_CONDATTR_SETCLOCK)
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_condattr_setclock (&attributes, clock_id),
result),
int, -1);
# else
ACE_UNUSED_ARG (clock_id);
ACE_UNUSED_ARG (attributes);
# endif /* _POSIX_CLOCK_SELECTION) && !ACE_LACKS_CONDATTR_SETCLOCK */
return result;
# else
ACE_UNUSED_ARG (clock_id);
ACE_UNUSED_ARG (attributes);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_PTHREADS && !ACE_LACKS_CONDATTR */
# else
ACE_UNUSED_ARG (clock_id);
ACE_UNUSED_ARG (attributes);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_THREADS */
}
#if !defined (ACE_LACKS_COND_T)
// NOTE: The ACE_OS::cond_* functions for Unix platforms are defined
// here because the ACE_OS::sema_* functions below need them.
// However, ACE_WIN32 and VXWORKS define the ACE_OS::cond_* functions
// using the ACE_OS::sema_* functions. So, they are defined in OS_NS_Tread.cpp.
ACE_INLINE int
ACE_OS::cond_broadcast (ACE_cond_t *cv)
{
ACE_OS_TRACE ("ACE_OS::cond_broadcast");
# if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_PTHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_cond_broadcast (cv),
result),
int, -1);
# elif defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::cond_broadcast (cv),
result),
int, -1);
# elif defined (ACE_HAS_WTHREADS) && defined (ACE_HAS_WTHREADS_CONDITION_VARIABLE)
::WakeAllConditionVariable (cv);
return 0;
# endif /* ACE_HAS_STHREADS */
# else
ACE_UNUSED_ARG (cv);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::cond_destroy (ACE_cond_t *cv)
{
ACE_OS_TRACE ("ACE_OS::cond_destroy");
# if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_PTHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_cond_destroy (cv), result), int, -1);
# elif defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::cond_destroy (cv), result), int, -1);
# elif defined (ACE_HAS_WTHREADS) && defined (ACE_HAS_WTHREADS_CONDITION_VARIABLE)
// Windows doesn't have a destroy
return 0;
# endif /* ACE_HAS_STHREADS */
# else
ACE_UNUSED_ARG (cv);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::cond_init (ACE_cond_t *cv,
ACE_condattr_t &attributes,
const char *name,
void *arg)
{
// ACE_OS_TRACE ("ACE_OS::cond_init");
ACE_UNUSED_ARG (name);
ACE_UNUSED_ARG (arg);
# if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_PTHREADS)
int result = -1;
# if defined (ACE_PTHREAD_COND_T_INITIALIZE)
/* VxWorks 6.x API reference states:
* If the memory for the condition variable object has been allocated
* dynamically, it is a good policy to always zero out the
* block of memory so as to avoid spurious EBUSY return code
* when calling this routine.
*/
ACE_OS::memset (cv, 0, sizeof (*cv));
# endif
if (ACE_ADAPT_RETVAL (pthread_cond_init (cv, &attributes), result) == 0)
result = 0;
else
result = -1; // ACE_ADAPT_RETVAL used it for intermediate status
return result;
# elif defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::cond_init (cv,
attributes.type,
arg),
result),
int, -1);
# elif defined (ACE_HAS_WTHREADS) && defined (ACE_HAS_WTHREADS_CONDITION_VARIABLE)
::InitializeConditionVariable (cv);
return 0;
# endif /* ACE_HAS_PTHREADS vs. ACE_HAS_STHREADS */
# else
ACE_UNUSED_ARG (cv);
ACE_UNUSED_ARG (attributes);
ACE_UNUSED_ARG (name);
ACE_UNUSED_ARG (arg);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_THREADS */
}
#if defined (ACE_HAS_WCHAR)
ACE_INLINE int
ACE_OS::cond_init (ACE_cond_t *cv,
ACE_condattr_t &attributes,
const wchar_t *name,
void *arg)
{
return ACE_OS::cond_init (cv, attributes, ACE_Wide_To_Ascii (name).char_rep (), arg);
}
#endif /* ACE_HAS_WCHAR */
#if defined (ACE_HAS_WCHAR)
ACE_INLINE int
ACE_OS::cond_init (ACE_cond_t *cv, short type, const wchar_t *name, void *arg)
{
return ACE_OS::cond_init (cv, type, ACE_Wide_To_Ascii (name).char_rep (), arg);
}
#endif /* ACE_HAS_WCHAR */
ACE_INLINE int
ACE_OS::cond_signal (ACE_cond_t *cv)
{
ACE_OS_TRACE ("ACE_OS::cond_signal");
# if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_PTHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_cond_signal (cv), result),
int, -1);
# elif defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::cond_signal (cv), result), int, -1);
# elif defined (ACE_HAS_WTHREADS) && defined (ACE_HAS_WTHREADS_CONDITION_VARIABLE)
::WakeConditionVariable (cv);
return 0;
# endif /* ACE_HAS_STHREADS */
# else
ACE_UNUSED_ARG (cv);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::cond_wait (ACE_cond_t *cv,
ACE_mutex_t *external_mutex)
{
ACE_OS_TRACE ("ACE_OS::cond_wait");
# if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_PTHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_cond_wait (cv, external_mutex), result),
int, -1);
# elif defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::cond_wait (cv, external_mutex), result),
int, -1);
# elif defined (ACE_HAS_WTHREADS) && defined (ACE_HAS_WTHREADS_CONDITION_VARIABLE)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::SleepConditionVariableCS (cv, &external_mutex->thr_mutex_, INFINITE), result),
int, -1);
# endif /* ACE_HAS_PTHREADS */
# else
ACE_UNUSED_ARG (cv);
ACE_UNUSED_ARG (external_mutex);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::cond_timedwait (ACE_cond_t *cv,
ACE_mutex_t *external_mutex,
ACE_Time_Value *timeout)
{
ACE_OS_TRACE ("ACE_OS::cond_timedwait");
# if defined (ACE_HAS_THREADS)
int result = 0;
timespec_t ts;
if (timeout != 0)
ts = *timeout; // Calls ACE_Time_Value::operator timespec_t().
# if defined (ACE_HAS_PTHREADS)
ACE_OSCALL (ACE_ADAPT_RETVAL (timeout == 0
? pthread_cond_wait (cv, external_mutex)
: pthread_cond_timedwait (cv, external_mutex,
(ACE_TIMESPEC_PTR) &ts),
result),
int, -1, result);
// We need to adjust this to make the POSIX and Solaris return
// values consistent. EAGAIN is from Pthreads DRAFT4 (HP-UX 10.20 and down)
if (result == -1 &&
(errno == ETIMEDOUT || errno == EAGAIN))
errno = ETIME;
# elif defined (ACE_HAS_STHREADS)
ACE_OSCALL (ACE_ADAPT_RETVAL (timeout == 0
? ::cond_wait (cv, external_mutex)
: ::cond_timedwait (cv,
external_mutex,
(timestruc_t*)&ts),
result),
int, -1, result);
# elif defined (ACE_HAS_WTHREADS) && defined (ACE_HAS_WTHREADS_CONDITION_VARIABLE)
int msec_timeout = 0;
if (timeout != 0)
{
ACE_Time_Value relative_time = timeout->to_relative_time ();
// Watchout for situations where a context switch has caused the
// current time to be > the timeout.
if (relative_time > ACE_Time_Value::zero)
msec_timeout = relative_time.msec ();
}
ACE_OSCALL (ACE_ADAPT_RETVAL (::SleepConditionVariableCS (cv, &external_mutex->thr_mutex_, msec_timeout),
result),
int, -1, result);
return result;
# endif /* ACE_HAS_STHREADS */
if (timeout != 0)
timeout->set (ts); // Update the time value before returning.
return result;
# else
ACE_UNUSED_ARG (cv);
ACE_UNUSED_ARG (external_mutex);
ACE_UNUSED_ARG (timeout);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_THREADS */
}
#endif /* !ACE_LACKS_COND_T */
ACE_INLINE int
ACE_OS::mutex_lock (ACE_mutex_t *m,
const ACE_Time_Value *timeout)
{
return timeout == 0 ? ACE_OS::mutex_lock (m) : ACE_OS::mutex_lock (m, *timeout);
}
ACE_INLINE int
ACE_OS::event_init (ACE_event_t *event,
int manual_reset,
int initial_state,
int type,
const char *name,
void *arg,
LPSECURITY_ATTRIBUTES sa)
{
ACE_condattr_t *pattr = 0;
return ACE_OS::event_init (event, type, pattr, manual_reset, initial_state, name, arg, sa);
}
#if defined (ACE_HAS_WCHAR)
ACE_INLINE int
ACE_OS::event_init (ACE_event_t *event,
int manual_reset,
int initial_state,
int type,
const wchar_t *name,
void *arg,
LPSECURITY_ATTRIBUTES sa)
{
#if defined (ACE_WIN32)
ACE_UNUSED_ARG (type);
ACE_UNUSED_ARG (arg);
SECURITY_ATTRIBUTES sa_buffer;
SECURITY_DESCRIPTOR sd_buffer;
*event = ::CreateEventW (ACE_OS::default_win32_security_attributes_r
(sa, &sa_buffer, &sd_buffer),
manual_reset,
initial_state,
name);
if (*event == 0)
ACE_FAIL_RETURN (-1);
// Make sure to set errno to ERROR_ALREADY_EXISTS if necessary.
ACE_OS::set_errno_to_last_error ();
return 0;
#else /* ACE_WIN32 */
return ACE_OS::event_init (event,
manual_reset,
initial_state,
type,
ACE_Wide_To_Ascii (name).char_rep (),
arg,
sa);
#endif /* ACE_WIN32 */
}
ACE_INLINE int
ACE_OS::event_init (ACE_event_t *event,
int type,
ACE_condattr_t *attributes,
int manual_reset,
int initial_state,
const wchar_t *name,
void *arg,
LPSECURITY_ATTRIBUTES sa)
{
#if defined (ACE_WIN32)
ACE_UNUSED_ARG (type);
ACE_UNUSED_ARG (attributes);
ACE_UNUSED_ARG (arg);
SECURITY_ATTRIBUTES sa_buffer;
SECURITY_DESCRIPTOR sd_buffer;
*event = ::CreateEventW (ACE_OS::default_win32_security_attributes_r
(sa, &sa_buffer, &sd_buffer),
manual_reset,
initial_state,
name);
if (*event == 0)
ACE_FAIL_RETURN (-1);
// Make sure to set errno to ERROR_ALREADY_EXISTS if necessary.
ACE_OS::set_errno_to_last_error ();
return 0;
#else /* ACE_WIN32 */
return ACE_OS::event_init (event,
type,
attributes,
manual_reset,
initial_state,
ACE_Wide_To_Ascii (name).char_rep (),
arg,
sa);
#endif /* ACE_WIN32 */
}
#endif /* ACE_HAS_WCHAR */
ACE_INLINE long
ACE_OS::priority_control (ACE_idtype_t idtype, ACE_id_t identifier, int cmd, void *arg)
{
ACE_OS_TRACE ("ACE_OS::priority_control");
#if defined (ACE_HAS_PRIOCNTL)
ACE_OSCALL_RETURN (priocntl (idtype, identifier, cmd, static_cast<caddr_t> (arg)),
long, -1);
#else /* ! ACE_HAS_PRIOCNTL*/
ACE_UNUSED_ARG (idtype);
ACE_UNUSED_ARG (identifier);
ACE_UNUSED_ARG (cmd);
ACE_UNUSED_ARG (arg);
ACE_NOTSUP_RETURN (-1);
#endif /* ! ACE_HAS_PRIOCNTL*/
}
// This method is used to prepare the recursive mutex for releasing
// when waiting on a condition variable. If the platform doesn't have
// native recursive mutex and condition variable support, then ACE needs
// to save the recursion state around the wait and also ensure that the
// wait and lock release are atomic. recursive_mutex_cond_relock()
// is the inverse of this method.
ACE_INLINE int
ACE_OS::recursive_mutex_cond_unlock (ACE_recursive_thread_mutex_t *m,
ACE_recursive_mutex_state &state)
{
#if defined (ACE_HAS_THREADS)
ACE_OS_TRACE ("ACE_OS::recursive_mutex_cond_unlock");
# if defined (ACE_HAS_RECURSIVE_MUTEXES)
// Windows need special handling since it has recursive mutexes, but
// does not integrate them into a condition variable.
# if defined (ACE_WIN32)
// For Windows, the OS takes care of the mutex and its recursion. We just
// need to release the lock one fewer times than this thread has acquired
// it. Remember how many times, and reacquire it that many more times when
// the condition is signaled.
// We're using undocumented fields in the CRITICAL_SECTION structure
// and they've been known to change across Windows variants and versions./
// So be careful if you need to change these - there may be other
// Windows variants that depend on existing values and limits.
state.relock_count_ = 0;
while (
# if !defined (ACE_HAS_WINCE)
m->LockCount > 0 && m->RecursionCount > 1
# else
// WinCE doesn't have RecursionCount and the LockCount semantic
// Mobile 5 has it 1-indexed.
m->LockCount > 1
# endif /* ACE_HAS_WINCE */
)
{
// This may fail if the current thread doesn't own the mutex. If it
// does fail, it'll be on the first try, so don't worry about resetting
// the state.
if (ACE_OS::recursive_mutex_unlock (m) == -1)
return -1;
++state.relock_count_;
}
# else /* not ACE_WIN32 */
// prevent warnings for unused variables
ACE_UNUSED_ARG (state);
ACE_UNUSED_ARG (m);
# endif /* ACE_WIN32 */
return 0;
# else /* ACE_HAS_RECURSIVE_MUTEXES */
// For platforms without recursive mutexes, we obtain the nesting mutex
// to gain control over the mutex internals. Then set the internals to say
// the mutex is available. If there are waiters, signal the condition
// to notify them (this is mostly like the recursive_mutex_unlock() method).
// Then, return with the nesting mutex still held. The condition wait
// will release it atomically, allowing mutex waiters to continue.
// Note that this arrangement relies on the fact that on return from
// the condition wait, this thread will again own the nesting mutex
// and can either set the mutex internals directly or get in line for
// the mutex... this part is handled in recursive_mutex_cond_relock().
if (ACE_OS::thread_mutex_lock (&m->nesting_mutex_) == -1)
return -1;
# if !defined (ACE_NDEBUG)
if (m->nesting_level_ == 0
|| ACE_OS::thr_equal (ACE_OS::thr_self (), m->owner_id_) == 0)
{
ACE_OS::thread_mutex_unlock (&m->nesting_mutex_);
errno = EINVAL;
return -1;
}
# endif /* ACE_NDEBUG */
// To make error recovery a bit easier, signal the condition now. Any
// waiter won't regain control until the mutex is released, which won't
// be until the caller returns and does the wait on the condition.
if (ACE_OS::cond_signal (&m->lock_available_) == -1)
{
// Save/restore errno.
ACE_Errno_Guard error (errno);
ACE_OS::thread_mutex_unlock (&m->nesting_mutex_);
return -1;
}
// Ok, the nesting_mutex_ lock is still held, the condition has been
// signaled... reset the nesting info and return _WITH_ the lock
// held. The lock will be released when the condition waits, in the
// caller.
state.nesting_level_ = m->nesting_level_;
state.owner_id_ = m->owner_id_;
m->nesting_level_ = 0;
m->owner_id_ = ACE_OS::NULL_thread;
return 0;
# endif /* ACE_HAS_RECURSIVE_MUTEXES */
#else
ACE_UNUSED_ARG (m);
ACE_UNUSED_ARG (state);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
// This method is called after waiting on a condition variable when a
// recursive mutex must be reacquired. If the platform doesn't natively
// integrate recursive mutexes and condition variables, it's taken care
// of here (inverse of ACE_OS::recursive_mutex_cond_unlock).
ACE_INLINE void
ACE_OS::recursive_mutex_cond_relock (ACE_recursive_thread_mutex_t *m,
ACE_recursive_mutex_state &state)
{
#if defined (ACE_HAS_THREADS)
ACE_OS_TRACE ("ACE_OS::recursive_mutex_cond_relock");
# if defined (ACE_HAS_RECURSIVE_MUTEXES)
// Windows need special handling since it has recursive mutexes, but
// does not integrate them into a condition variable.
// On entry, the OS has already reacquired the lock for us. Just
// reacquire it the proper number of times so the recursion is the same as
// before waiting on the condition.
# if defined (ACE_WIN32)
while (state.relock_count_ > 0)
{
ACE_OS::recursive_mutex_lock (m);
--state.relock_count_;
}
return;
# else /* not ACE_WIN32 */
// prevent warnings for unused variables
ACE_UNUSED_ARG (state);
ACE_UNUSED_ARG (m);
# endif /* ACE_WIN32 */
# else
// Without recursive mutex support, it's somewhat trickier. On entry,
// the current thread holds the nesting_mutex_, but another thread may
// still be holding the ACE_recursive_mutex_t. If so, mimic the code
// in ACE_OS::recursive_mutex_lock that waits to acquire the mutex.
// After acquiring it, restore the nesting counts and release the
// nesting mutex. This will restore the conditions to what they were
// before calling ACE_OS::recursive_mutex_cond_unlock().
while (m->nesting_level_ > 0)
ACE_OS::cond_wait (&m->lock_available_, &m->nesting_mutex_);
// At this point, we still have nesting_mutex_ and the mutex is free.
m->nesting_level_ = state.nesting_level_;
m->owner_id_ = state.owner_id_;
ACE_OS::thread_mutex_unlock (&m->nesting_mutex_);
return;
# endif /* ACE_HAS_RECURSIVE_MUTEXES */
#else
ACE_UNUSED_ARG (m);
ACE_UNUSED_ARG (state);
return;
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::recursive_mutex_destroy (ACE_recursive_thread_mutex_t *m)
{
#if defined (ACE_HAS_THREADS)
#if defined (ACE_HAS_RECURSIVE_MUTEXES)
return ACE_OS::thread_mutex_destroy (m);
#else
if (ACE_OS::thread_mutex_destroy (&m->nesting_mutex_) == -1)
return -1;
else if (ACE_OS::cond_destroy (&m->lock_available_) == -1)
return -1;
else
return 0;
#endif /* ACE_HAS_RECURSIVE_MUTEXES */
#else
ACE_UNUSED_ARG (m);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::recursive_mutex_init (ACE_recursive_thread_mutex_t *m,
const ACE_TCHAR *name,
ACE_mutexattr_t *arg,
LPSECURITY_ATTRIBUTES sa)
{
ACE_UNUSED_ARG (sa);
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_RECURSIVE_MUTEXES)
# if defined (ACE_HAS_PTHREADS_UNIX98_EXT)
return ACE_OS::thread_mutex_init (m, PTHREAD_MUTEX_RECURSIVE, name, arg);
# else
return ACE_OS::thread_mutex_init (m, 0, name, arg);
# endif /* ACE_HAS_PTHREADS_UNIX98_EXT */
# else
if (ACE_OS::thread_mutex_init (&m->nesting_mutex_, 0, name, arg) == -1)
return -1;
else if (ACE_OS::cond_init (&m->lock_available_,
(short) USYNC_THREAD,
name,
0) == -1)
return -1;
else
{
m->nesting_level_ = 0;
m->owner_id_ = ACE_OS::NULL_thread;
return 0;
}
# endif /* ACE_HAS_RECURSIVE_MUTEXES */
#else
ACE_UNUSED_ARG (m);
ACE_UNUSED_ARG (name);
ACE_UNUSED_ARG (arg);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::recursive_mutex_lock (ACE_recursive_thread_mutex_t *m)
{
#if defined (ACE_HAS_THREADS)
#if defined (ACE_HAS_RECURSIVE_MUTEXES)
return ACE_OS::thread_mutex_lock (m);
#else
ACE_thread_t const t_id = ACE_OS::thr_self ();
int result = 0;
// Acquire the guard.
if (ACE_OS::thread_mutex_lock (&m->nesting_mutex_) == -1)
result = -1;
else
{
// If there's no contention, just grab the lock immediately
// (since this is the common case we'll optimize for it).
if (m->nesting_level_ == 0)
m->owner_id_ = t_id;
// If we already own the lock, then increment the nesting level
// and return.
else if (ACE_OS::thr_equal (t_id, m->owner_id_) == 0)
{
// Wait until the nesting level has dropped to zero, at
// which point we can acquire the lock.
while (m->nesting_level_ > 0)
ACE_OS::cond_wait (&m->lock_available_,
&m->nesting_mutex_);
// At this point the nesting_mutex_ is held...
m->owner_id_ = t_id;
}
// At this point, we can safely increment the nesting_level_ no
// matter how we got here!
++m->nesting_level_;
}
{
// Save/restore errno.
ACE_Errno_Guard error (errno);
ACE_OS::thread_mutex_unlock (&m->nesting_mutex_);
}
return result;
#endif /* ACE_HAS_RECURSIVE_MUTEXES */
#else
ACE_UNUSED_ARG (m);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::recursive_mutex_lock (ACE_recursive_thread_mutex_t *m,
const ACE_Time_Value &timeout)
{
#if defined (ACE_HAS_THREADS)
#if defined (ACE_HAS_RECURSIVE_MUTEXES)
return ACE_OS::thread_mutex_lock (m, timeout);
#else
ACE_thread_t t_id = ACE_OS::thr_self ();
int result = 0;
// Try to acquire the guard.
if (ACE_OS::thread_mutex_lock (&m->nesting_mutex_, timeout) == -1)
result = -1;
else
{
// If there's no contention, just grab the lock immediately
// (since this is the common case we'll optimize for it).
if (m->nesting_level_ == 0)
m->owner_id_ = t_id;
// If we already own the lock, then increment the nesting level
// and return.
else if (ACE_OS::thr_equal (t_id, m->owner_id_) == 0)
{
// Wait until the nesting level has dropped to zero, at
// which point we can acquire the lock.
while (m->nesting_level_ > 0)
{
result = ACE_OS::cond_timedwait (&m->lock_available_,
&m->nesting_mutex_,
const_cast <ACE_Time_Value *> (&timeout));
// The mutex is reacquired even in the case of a timeout
// release the mutex to prevent a deadlock
if (result == -1)
{
// Save/restore errno.
ACE_Errno_Guard error (errno);
ACE_OS::thread_mutex_unlock (&m->nesting_mutex_);
return result;
}
}
// At this point the nesting_mutex_ is held...
m->owner_id_ = t_id;
}
// At this point, we can safely increment the nesting_level_ no
// matter how we got here!
m->nesting_level_++;
// Save/restore errno.
ACE_Errno_Guard error (errno);
ACE_OS::thread_mutex_unlock (&m->nesting_mutex_);
}
return result;
#endif /* ACE_HAS_RECURSIVE_MUTEXES */
#else
ACE_UNUSED_ARG (m);
ACE_UNUSED_ARG (timeout);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::recursive_mutex_lock (ACE_recursive_thread_mutex_t *m,
const ACE_Time_Value *timeout)
{
return timeout == 0
? ACE_OS::recursive_mutex_lock (m)
: ACE_OS::recursive_mutex_lock (m, *timeout);
}
ACE_INLINE int
ACE_OS::recursive_mutex_trylock (ACE_recursive_thread_mutex_t *m)
{
#if defined (ACE_HAS_THREADS)
#if defined (ACE_HAS_RECURSIVE_MUTEXES)
return ACE_OS::thread_mutex_trylock (m);
#else
ACE_thread_t t_id = ACE_OS::thr_self ();
int result = 0;
// Acquire the guard.
if (ACE_OS::thread_mutex_lock (&m->nesting_mutex_) == -1)
result = -1;
else
{
// If there's no contention, just grab the lock immediately.
if (m->nesting_level_ == 0)
{
m->owner_id_ = t_id;
m->nesting_level_ = 1;
}
// If we already own the lock, then increment the nesting level
// and proceed.
else if (ACE_OS::thr_equal (t_id, m->owner_id_))
m->nesting_level_++;
else
{
errno = EBUSY;
result = -1;
}
}
{
// Save/restore errno.
ACE_Errno_Guard error (errno);
ACE_OS::thread_mutex_unlock (&m->nesting_mutex_);
}
return result;
#endif /* ACE_HAS_RECURSIVE_MUTEXES */
#else
ACE_UNUSED_ARG (m);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::recursive_mutex_unlock (ACE_recursive_thread_mutex_t *m)
{
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_RECURSIVE_MUTEXES)
return ACE_OS::thread_mutex_unlock (m);
# else
ACE_OS_TRACE ("ACE_OS::recursive_mutex_unlock");
# if !defined (ACE_NDEBUG)
ACE_thread_t t_id = ACE_OS::thr_self ();
# endif /* ACE_NDEBUG */
int result = 0;
if (ACE_OS::thread_mutex_lock (&m->nesting_mutex_) == -1)
result = -1;
else
{
# if !defined (ACE_NDEBUG)
if (m->nesting_level_ == 0
|| ACE_OS::thr_equal (t_id, m->owner_id_) == 0)
{
errno = EINVAL;
result = -1;
}
else
# endif /* ACE_NDEBUG */
{
m->nesting_level_--;
if (m->nesting_level_ == 0)
{
// This may not be strictly necessary, but it does put
// the mutex into a known state...
m->owner_id_ = ACE_OS::NULL_thread;
// Inform a waiter that the lock is free.
if (ACE_OS::cond_signal (&m->lock_available_) == -1)
result = -1;
}
}
}
{
// Save/restore errno.
ACE_Errno_Guard error (errno);
ACE_OS::thread_mutex_unlock (&m->nesting_mutex_);
}
return result;
# endif /* ACE_HAS_RECURSIVE_MUTEXES */
#else
ACE_UNUSED_ARG (m);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::rw_rdlock (ACE_rwlock_t *rw)
{
ACE_OS_TRACE ("ACE_OS::rw_rdlock");
#if defined (ACE_HAS_THREADS)
# if !defined (ACE_LACKS_RWLOCK_T) || defined (ACE_HAS_PTHREADS_UNIX98_EXT)
# if defined (ACE_HAS_PTHREADS_UNIX98_EXT)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_rwlock_rdlock (rw),
result),
int, -1);
# else /* Solaris */
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::rw_rdlock (rw), result), int, -1);
# endif /* ACE_HAS_PTHREADS_UNIX98_EXT */
# else /* NT, POSIX, and VxWorks don't support this natively. */
# if defined (ACE_HAS_PTHREADS)
ACE_PTHREAD_CLEANUP_PUSH (&rw->lock_);
# endif /* ACE_HAS_PTHREADS */
int result = 0;
if (ACE_OS::mutex_lock (&rw->lock_) == -1)
result = -1; // -1 means didn't get the mutex.
else
{
// Give preference to writers who are waiting.
while (rw->ref_count_ < 0 || rw->num_waiting_writers_ > 0)
{
rw->num_waiting_readers_++;
if (ACE_OS::cond_wait (&rw->waiting_readers_, &rw->lock_) == -1)
{
result = -2; // -2 means that we need to release the mutex.
break;
}
rw->num_waiting_readers_--;
}
}
if (result == 0)
rw->ref_count_++;
if (result != -1)
ACE_OS::mutex_unlock (&rw->lock_);
# if defined (ACE_HAS_PTHREADS)
ACE_PTHREAD_CLEANUP_POP (0);
# endif /* defined (ACE_HAS_PTHREADS) */
return 0;
# endif /* ! ACE_LACKS_RWLOCK_T */
#else
ACE_UNUSED_ARG (rw);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::rw_tryrdlock (ACE_rwlock_t *rw)
{
ACE_OS_TRACE ("ACE_OS::rw_tryrdlock");
#if defined (ACE_HAS_THREADS)
# if !defined (ACE_LACKS_RWLOCK_T) || defined (ACE_HAS_PTHREADS_UNIX98_EXT)
# if defined (ACE_HAS_PTHREADS_UNIX98_EXT)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_rwlock_tryrdlock (rw),
result),
int, -1);
# else /* Solaris */
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::rw_tryrdlock (rw), result), int, -1);
# endif /* ACE_HAS_PTHREADS_UNIX98_EXT */
# else /* NT, POSIX, and VxWorks don't support this natively. */
int result = -1;
if (ACE_OS::mutex_lock (&rw->lock_) != -1)
{
ACE_Errno_Guard error (errno);
if (rw->ref_count_ == -1 || rw->num_waiting_writers_ > 0)
{
error = EBUSY;
result = -1;
}
else
{
rw->ref_count_++;
result = 0;
}
ACE_OS::mutex_unlock (&rw->lock_);
}
return result;
# endif /* ! ACE_LACKS_RWLOCK_T */
#else
ACE_UNUSED_ARG (rw);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::rw_trywrlock (ACE_rwlock_t *rw)
{
ACE_OS_TRACE ("ACE_OS::rw_trywrlock");
#if defined (ACE_HAS_THREADS)
# if !defined (ACE_LACKS_RWLOCK_T) || defined (ACE_HAS_PTHREADS_UNIX98_EXT)
# if defined (ACE_HAS_PTHREADS_UNIX98_EXT)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_rwlock_trywrlock (rw),
result),
int, -1);
# else /* Solaris */
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::rw_trywrlock (rw), result), int, -1);
# endif /* ACE_HAS_PTHREADS_UNIX98_EXT */
# else /* NT, POSIX, and VxWorks don't support this natively. */
int result = -1;
if (ACE_OS::mutex_lock (&rw->lock_) != -1)
{
ACE_Errno_Guard error (errno);
if (rw->ref_count_ != 0)
{
error = EBUSY;
result = -1;
}
else
{
rw->ref_count_ = -1;
result = 0;
}
ACE_OS::mutex_unlock (&rw->lock_);
}
return result;
# endif /* ! ACE_LACKS_RWLOCK_T */
#else
ACE_UNUSED_ARG (rw);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
// Note that the caller of this method *must* already possess this
// lock as a read lock.
// return {-1 and no errno set means: error,
// -1 and errno==EBUSY set means: could not upgrade,
// 0 means: upgraded successfully}
ACE_INLINE int
ACE_OS::rw_trywrlock_upgrade (ACE_rwlock_t *rw)
{
ACE_OS_TRACE ("ACE_OS::rw_trywrlock_upgrade");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_PTHREADS_UNIX98_EXT)
// This will probably result in -1, EDEADLK, at least on HP-UX, but let it
// go - it's a more descriptive error than ENOTSUP.
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_rwlock_trywrlock (rw),
result),
int, -1);
# elif !defined (ACE_LACKS_RWLOCK_T)
// Some native rwlocks, such as those on Solaris, don't
// support the upgrade feature . . .
ACE_UNUSED_ARG (rw);
ACE_NOTSUP_RETURN (-1);
# else /* NT, POSIX, and VxWorks don't support this natively. */
// The ACE rwlock emulation does support upgrade . . .
int result = 0;
# if defined (ACE_HAS_PTHREADS)
ACE_PTHREAD_CLEANUP_PUSH (&rw->lock_);
# endif /* defined (ACE_HAS_PTHREADS) */
if (ACE_OS::mutex_lock (&rw->lock_) == -1)
return -1;
// -1 means didn't get the mutex, error
else if (rw->important_writer_)
// an other reader upgrades already
{
result = -1;
errno = EBUSY;
}
else
{
while (rw->ref_count_ > 1) // wait until only I am left
{
rw->num_waiting_writers_++; // prohibit any more readers
rw->important_writer_ = true;
if (ACE_OS::cond_wait (&rw->waiting_important_writer_, &rw->lock_) == -1)
{
result = -1;
// we know that we have the lock again, we have this guarantee,
// but something went wrong
}
rw->important_writer_ = false;
rw->num_waiting_writers_--;
}
if (result == 0)
{
// nothing bad happend
rw->ref_count_ = -1;
// now I am a writer
// everything is O.K.
}
}
ACE_OS::mutex_unlock (&rw->lock_);
# if defined (ACE_HAS_PTHREADS)
ACE_PTHREAD_CLEANUP_POP (0);
# endif /* defined (ACE_HAS_PTHREADS) */
return result;
# endif /* ! ACE_LACKS_RWLOCK_T */
#else
ACE_UNUSED_ARG (rw);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::rw_unlock (ACE_rwlock_t *rw)
{
ACE_OS_TRACE ("ACE_OS::rw_unlock");
#if defined (ACE_HAS_THREADS)
# if !defined (ACE_LACKS_RWLOCK_T) || defined (ACE_HAS_PTHREADS_UNIX98_EXT)
# if defined (ACE_HAS_PTHREADS_UNIX98_EXT)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_rwlock_unlock (rw),
result),
int, -1);
# else /* Solaris */
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::rw_unlock (rw), result), int, -1);
# endif /* ACE_HAS_PTHREADS_UNIX98_EXT */
# else /* NT, POSIX, and VxWorks don't support this natively. */
if (ACE_OS::mutex_lock (&rw->lock_) == -1)
return -1;
if (rw->ref_count_ > 0) // Releasing a reader.
rw->ref_count_--;
else if (rw->ref_count_ == -1) // Releasing a writer.
rw->ref_count_ = 0;
else
{
(void) ACE_OS::mutex_unlock (&rw->lock_);
return -1; // @@ ACE_ASSERT (!"count should not be 0!\n");
}
int result = 0;
ACE_Errno_Guard error (errno);
if (rw->important_writer_ && rw->ref_count_ == 1)
// only the reader requesting to upgrade its lock is left over.
{
result = ACE_OS::cond_signal (&rw->waiting_important_writer_);
error = errno;
}
else if (rw->num_waiting_writers_ > 0 && rw->ref_count_ == 0)
// give preference to writers over readers...
{
result = ACE_OS::cond_signal (&rw->waiting_writers_);
error = errno;
}
else if (rw->num_waiting_readers_ > 0 && rw->num_waiting_writers_ == 0)
{
result = ACE_OS::cond_broadcast (&rw->waiting_readers_);
error = errno;
}
(void) ACE_OS::mutex_unlock (&rw->lock_);
return result;
# endif /* ! ace_lacks_rwlock_t */
#else
ACE_UNUSED_ARG (rw);
ACE_NOTSUP_RETURN (-1);
#endif /* ace_has_threads */
}
ACE_INLINE int
ACE_OS::rw_wrlock (ACE_rwlock_t *rw)
{
ACE_OS_TRACE ("ACE_OS::rw_wrlock");
#if defined (ACE_HAS_THREADS)
# if !defined (ACE_LACKS_RWLOCK_T) || defined (ACE_HAS_PTHREADS_UNIX98_EXT)
# if defined (ACE_HAS_PTHREADS_UNIX98_EXT)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_rwlock_wrlock (rw),
result),
int, -1);
# else /* Solaris */
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::rw_wrlock (rw), result), int, -1);
# endif /* ACE_HAS_PTHREADS_UNIX98_EXT */
# else /* NT, POSIX, and VxWorks don't support this natively. */
# if defined (ACE_HAS_PTHREADS)
ACE_PTHREAD_CLEANUP_PUSH (&rw->lock_);
# endif /* defined (ACE_HAS_PTHREADS) */
int result = 0;
if (ACE_OS::mutex_lock (&rw->lock_) == -1)
result = -1; // -1 means didn't get the mutex.
else
{
while (rw->ref_count_ != 0)
{
rw->num_waiting_writers_++;
if (ACE_OS::cond_wait (&rw->waiting_writers_, &rw->lock_) == -1)
{
result = -2; // -2 means we need to release the mutex.
break;
}
rw->num_waiting_writers_--;
}
}
if (result == 0)
rw->ref_count_ = -1;
if (result != -1)
ACE_OS::mutex_unlock (&rw->lock_);
# if defined (ACE_HAS_PTHREADS)
ACE_PTHREAD_CLEANUP_POP (0);
# endif /* defined (ACE_HAS_PTHREADS) */
return 0;
# endif /* ! ACE_LACKS_RWLOCK_T */
#else
ACE_UNUSED_ARG (rw);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::rwlock_destroy (ACE_rwlock_t *rw)
{
ACE_OS_TRACE ("ACE_OS::rwlock_destroy");
#if defined (ACE_HAS_THREADS)
# if !defined (ACE_LACKS_RWLOCK_T) || defined (ACE_HAS_PTHREADS_UNIX98_EXT)
# if defined (ACE_HAS_PTHREADS_UNIX98_EXT)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_rwlock_destroy (rw),
result),
int, -1);
# else /* Solaris */
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::rwlock_destroy (rw), result), int, -1);
# endif /* ACE_HAS_PTHREADS_UNIX98_EXT */
# else /* NT, POSIX, and VxWorks don't support this natively. */
ACE_OS::mutex_destroy (&rw->lock_);
ACE_OS::cond_destroy (&rw->waiting_readers_);
ACE_OS::cond_destroy (&rw->waiting_important_writer_);
return ACE_OS::cond_destroy (&rw->waiting_writers_);
# endif /* ACE_HAS_STHREADS && !defined (ACE_LACKS_RWLOCK_T) */
#else
ACE_UNUSED_ARG (rw);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
#if defined (ACE_HAS_THREADS) && (!defined (ACE_LACKS_RWLOCK_T) || \
defined (ACE_HAS_PTHREADS_UNIX98_EXT))
ACE_INLINE int
ACE_OS::rwlock_init (ACE_rwlock_t *rw,
int type,
const ACE_TCHAR *name,
void *arg)
{
// ACE_OS_TRACE ("ACE_OS::rwlock_init");
# if defined (ACE_HAS_PTHREADS_UNIX98_EXT)
ACE_UNUSED_ARG (name);
ACE_UNUSED_ARG (arg);
int status;
pthread_rwlockattr_t attr;
pthread_rwlockattr_init (&attr);
# if !defined (ACE_LACKS_RWLOCKATTR_PSHARED)
pthread_rwlockattr_setpshared (&attr, (type == USYNC_THREAD ?
PTHREAD_PROCESS_PRIVATE :
PTHREAD_PROCESS_SHARED));
# else
ACE_UNUSED_ARG (type);
# endif /* !ACE_LACKS_RWLOCKATTR_PSHARED */
status = ACE_ADAPT_RETVAL (pthread_rwlock_init (rw, &attr), status);
pthread_rwlockattr_destroy (&attr);
return status;
# else
type = type;
name = name;
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::rwlock_init (rw, type, arg), result), int, -1);
# endif /* ACE_HAS_PTHREADS_UNIX98_EXT */
}
#endif /* ACE_HAS THREADS && !defined (ACE_LACKS_RWLOCK_T) */
ACE_INLINE int
ACE_OS::sema_destroy (ACE_sema_t *s)
{
ACE_OS_TRACE ("ACE_OS::sema_destroy");
# if defined (ACE_HAS_POSIX_SEM)
int result;
# if !defined (ACE_HAS_POSIX_SEM_TIMEOUT) && !defined (ACE_DISABLE_POSIX_SEM_TIMEOUT_EMULATION)
ACE_OS::mutex_destroy (&s->lock_);
ACE_OS::cond_destroy (&s->count_nonzero_);
# endif /* !ACE_HAS_POSIX_SEM_TIMEOUT && !ACE_DISABLE_POSIX_SEM_TIMEOUT_EMULATION */
# if defined (ACE_LACKS_NAMED_POSIX_SEM)
if (s->name_)
{
// Only destroy the semaphore if we're the ones who
// initialized it.
ACE_OSCALL (::sem_destroy (s->sema_),int, -1, result);
ACE_OS::shm_unlink (s->name_);
delete s->name_;
return result;
}
# else
if (s->name_)
{
ACE_OSCALL (::sem_unlink (s->name_), int, -1, result);
ACE_OS::free ((void *) s->name_);
ACE_OSCALL_RETURN (::sem_close (s->sema_), int, -1);
}
# endif /* ACE_LACKS_NAMED_POSIX_SEM */
else
{
ACE_OSCALL (::sem_destroy (s->sema_), int, -1, result);
# if defined (ACE_LACKS_NAMED_POSIX_SEM)
if (s->new_sema_)
# endif /* ACE_LACKS_NAMED_POSIX_SEM */
delete s->sema_;
s->sema_ = 0;
return result;
}
# elif defined (ACE_USES_FIFO_SEM)
int r0 = 0;
if (s->name_)
{
r0 = ACE_OS::unlink (s->name_);
ACE_OS::free (s->name_);
s->name_ = 0;
}
int r1 = ACE_OS::close (s->fd_[0]); /* ignore error */
int r2 = ACE_OS::close (s->fd_[1]); /* ignore error */
return r0 != 0 || r1 != 0 || r2 != 0 ? -1 : 0;
# elif defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::sema_destroy (s), result), int, -1);
# elif defined (ACE_HAS_PTHREADS)
int r1 = ACE_OS::mutex_destroy (&s->lock_);
int r2 = ACE_OS::cond_destroy (&s->count_nonzero_);
return r1 != 0 || r2 != 0 ? -1 : 0;
# elif defined (ACE_HAS_WTHREADS)
# if !defined (ACE_USES_WINCE_SEMA_SIMULATION)
ACE_WIN32CALL_RETURN (ACE_ADAPT_RETVAL (::CloseHandle (*s), ace_result_), int, -1);
# else /* ACE_USES_WINCE_SEMA_SIMULATION */
// Free up underlying objects of the simulated semaphore.
int const r1 = ACE_OS::thread_mutex_destroy (&s->lock_);
int const r2 = ACE_OS::event_destroy (&s->count_nonzero_);
return r1 != 0 || r2 != 0 ? -1 : 0;
# endif /* ACE_USES_WINCE_SEMA_SIMULATION */
# elif defined (ACE_VXWORKS)
int result;
ACE_OSCALL (::semDelete (s->sema_), int, -1, result);
s->sema_ = 0;
return result;
# endif /* ACE_HAS_STHREADS */
# else
ACE_UNUSED_ARG (s);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_POSIX_SEM */
}
// NOTE: The previous four function definitions must appear before
// ACE_OS::sema_init ().
ACE_INLINE int
ACE_OS::sema_init (ACE_sema_t *s,
u_int count,
int type,
const char *name,
void *arg,
int max,
LPSECURITY_ATTRIBUTES sa)
{
ACE_condattr_t *pattr = 0;
return ACE_OS::sema_init (s, count, type, pattr, name, arg, max, sa);
}
ACE_INLINE int
ACE_OS::sema_init (ACE_sema_t *s,
u_int count,
int type,
ACE_condattr_t *attributes,
const char *name,
void *arg,
int max,
LPSECURITY_ATTRIBUTES sa)
{
ACE_OS_TRACE ("ACE_OS::sema_init");
#if defined (ACE_HAS_POSIX_SEM)
ACE_UNUSED_ARG (max);
ACE_UNUSED_ARG (sa);
s->name_ = 0;
# if defined (ACE_HAS_POSIX_SEM_TIMEOUT) || defined (ACE_DISABLE_POSIX_SEM_TIMEOUT_EMULATION)
ACE_UNUSED_ARG (arg);
ACE_UNUSED_ARG (attributes);
# else
int result = -1;
if (ACE_OS::mutex_init (&s->lock_, type, name,
(ACE_mutexattr_t *) arg) == 0
&& (attributes == 0 ?
ACE_OS::cond_init (&s->count_nonzero_, type, name, arg) :
ACE_OS::cond_init (&s->count_nonzero_, *attributes, name, arg)) == 0
&& ACE_OS::mutex_lock (&s->lock_) == 0)
{
if (ACE_OS::mutex_unlock (&s->lock_) == 0)
result = 0;
}
if (result == -1)
{
ACE_OS::mutex_destroy (&s->lock_);
ACE_OS::cond_destroy (&s->count_nonzero_);
return result;
}
# endif /* ACE_HAS_POSIX_SEM_TIMEOUT || ACE_DISABLE_POSIX_SEM_TIMEOUT_EMULATION */
# if defined (ACE_LACKS_NAMED_POSIX_SEM)
s->new_sema_ = false;
if (type == USYNC_PROCESS)
{
// Let's see if it already exists.
ACE_HANDLE fd = ACE_OS::shm_open (ACE_TEXT_CHAR_TO_TCHAR (name),
O_RDWR | O_CREAT | O_EXCL,
ACE_DEFAULT_FILE_PERMS);
if (fd == ACE_INVALID_HANDLE)
{
if (errno == EEXIST)
fd = ACE_OS::shm_open (ACE_TEXT_CHAR_TO_TCHAR (name),
O_RDWR | O_CREAT,
ACE_DEFAULT_FILE_PERMS);
else
return -1;
}
else
{
// We own this shared memory object! Let's set its
// size.
if (ACE_OS::ftruncate (fd,
sizeof (ACE_sema_t)) == -1)
return -1;
s->name_ = ACE_OS::strdup (name);
if (s->name_ == 0)
return -1;
}
if (fd == -1)
return -1;
s->sema_ = (sem_t *)
ACE_OS::mmap (0,
sizeof (ACE_sema_t),
PROT_RDWR,
MAP_SHARED,
fd,
0);
ACE_OS::close (fd);
if (s->sema_ == (sem_t *) MAP_FAILED)
return -1;
if (s->name_
// @@ According UNIX Network Programming V2 by Stevens,
// sem_init() is currently not required to return zero on
// success, but it *does* return -1 upon failure. For
// this reason, check for failure by comparing to -1,
// instead of checking for success by comparing to zero.
// -Ossama
// Only initialize it if we're the one who created it.
&& ::sem_init (s->sema_, type == USYNC_PROCESS, count) == -1)
return -1;
return 0;
}
# else
if (name)
{
# if defined (sun) || defined (HPUX)
// Solaris and HP-UX require the name to start with a slash. Solaris
// further requires that there be no other slashes than the first.
const char *last_slash = ACE_OS::strrchr (name, '/');
char name2[MAXPATHLEN];
if (0 == last_slash)
{
ACE_OS::strcpy (name2, "/");
ACE_OS::strcat (name2, name);
name = name2;
}
# if defined (sun)
else
name = last_slash; // Chop off chars preceding last slash
# endif /* sun */
# endif /* sun || HPUX */
ACE_ALLOCATOR_RETURN (s->name_,
ACE_OS::strdup (name),
-1);
s->sema_ = ::sem_open (s->name_,
O_CREAT,
ACE_DEFAULT_FILE_PERMS,
count);
if (s->sema_ == (sem_t *) SEM_FAILED)
return -1;
else
return 0;
}
# endif /* ACE_LACKS_NAMED_POSIX_SEM */
else
{
ACE_NEW_RETURN (s->sema_,
sem_t,
-1);
# if defined (ACE_LACKS_NAMED_POSIX_SEM)
s->new_sema_ = true;
# endif /* ACE_LACKS_NAMED_POSIX_SEM */
ACE_OSCALL_RETURN (::sem_init (s->sema_,
type != USYNC_THREAD,
count), int, -1);
}
#elif defined (ACE_USES_FIFO_SEM)
ACE_UNUSED_ARG (arg);
ACE_UNUSED_ARG (max);
ACE_UNUSED_ARG (sa);
int flags = 0;
mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP;
if (type == USYNC_THREAD)
{
// Create systemwide unique name for semaphore
char uname[ACE_UNIQUE_NAME_LEN];
ACE_OS::unique_name ((const void *) s,
uname,
ACE_UNIQUE_NAME_LEN);
name = &uname[0];
}
s->name_ = 0;
s->fd_[0] = s->fd_[1] = ACE_INVALID_HANDLE;
bool creator = false;
if (ACE_OS::mkfifo (ACE_TEXT_CHAR_TO_TCHAR (name), mode) < 0)
{
if (errno != EEXIST) /* already exists OK else ERR */
return -1;
// check if this is a real FIFO, not just some other existing file
ACE_stat fs;
if (ACE_OS::stat (name, &fs))
return -1;
if (!S_ISFIFO (fs.st_mode))
{
// existing file is not a FIFO
errno = EEXIST;
return -1;
}
}
else
creator = true; // remember we created it for initialization at end
// for processshared semaphores remember who we are to be able to remove
// the FIFO when we're done with it
if (type == USYNC_PROCESS)
{
s->name_ = ACE_OS::strdup (name);
if (s->name_ == 0)
{
if (creator)
ACE_OS::unlink (name);
return -1;
}
}
if ((s->fd_[0] = ACE_OS::open (name, O_RDONLY | O_NONBLOCK)) == ACE_INVALID_HANDLE
|| (s->fd_[1] = ACE_OS::open (name, O_WRONLY | O_NONBLOCK)) == ACE_INVALID_HANDLE)
return -1;
/* turn off nonblocking for fd_[0] */
if ((flags = ACE_OS::fcntl (s->fd_[0], F_GETFL, 0)) < 0)
return -1;
flags &= ~O_NONBLOCK;
if (ACE_OS::fcntl (s->fd_[0], F_SETFL, flags) < 0)
return -1;
//if (s->name_ && count)
if (creator && count)
{
char c = 1;
for (u_int i=0; i<count ;++i)
if (ACE_OS::write (s->fd_[1], &c, sizeof (char)) != 1)
return -1;
}
// In the case of process scope semaphores we can already unlink the FIFO now that
// we completely set it up (the opened handles will keep it active until we close
// thos down). This way we're protected against unexpected crashes as far as removal
// is concerned.
// Unfortunately this does not work for processshared FIFOs since as soon as we
// have unlinked the semaphore no other process will be able to open it anymore.
if (type == USYNC_THREAD)
{
ACE_OS::unlink (name);
}
return 0;
#elif defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_STHREADS)
ACE_UNUSED_ARG (name);
ACE_UNUSED_ARG (max);
ACE_UNUSED_ARG (sa);
ACE_UNUSED_ARG (attributes);
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::sema_init (s, count, type, arg), result),
int, -1);
# elif defined (ACE_HAS_PTHREADS)
ACE_UNUSED_ARG (max);
ACE_UNUSED_ARG (sa);
int result = -1;
if (ACE_OS::mutex_init (&s->lock_, type, name,
(ACE_mutexattr_t *) arg) == 0
&& (attributes == 0 ?
ACE_OS::cond_init (&s->count_nonzero_, type, name, arg) :
ACE_OS::cond_init (&s->count_nonzero_, *attributes, name, arg)) == 0
&& ACE_OS::mutex_lock (&s->lock_) == 0)
{
s->count_ = count;
s->waiters_ = 0;
if (ACE_OS::mutex_unlock (&s->lock_) == 0)
result = 0;
}
if (result == -1)
{
ACE_OS::mutex_destroy (&s->lock_);
ACE_OS::cond_destroy (&s->count_nonzero_);
}
return result;
# elif defined (ACE_HAS_WTHREADS)
ACE_UNUSED_ARG (attributes);
# if ! defined (ACE_USES_WINCE_SEMA_SIMULATION)
ACE_UNUSED_ARG (type);
ACE_UNUSED_ARG (arg);
// Create the semaphore with its value initialized to <count> and
// its maximum value initialized to <max>.
SECURITY_ATTRIBUTES sa_buffer;
SECURITY_DESCRIPTOR sd_buffer;
*s = ACE_TEXT_CreateSemaphore
(ACE_OS::default_win32_security_attributes_r (sa, &sa_buffer, &sd_buffer),
count,
max,
ACE_TEXT_CHAR_TO_TCHAR (name));
if (*s == 0)
ACE_FAIL_RETURN (-1);
/* NOTREACHED */
else
{
// Make sure to set errno to ERROR_ALREADY_EXISTS if necessary.
ACE_OS::set_errno_to_last_error ();
return 0;
}
# else /* ACE_USES_WINCE_SEMA_SIMULATION */
int result = -1;
// Initialize internal object for semaphore simulation.
// Grab the lock as soon as possible when we initializing
// the semaphore count. Notice that we initialize the
// event object as "manually reset" so we can amortize the
// cost for singling/reseting the event.
// @@ I changed the mutex type to thread_mutex. Notice that this
// is basically a CriticalSection object and doesn't not has
// any security attribute whatsoever. However, since this
// semaphore implementation only works within a process, there
// shouldn't any security issue at all.
if (ACE_OS::thread_mutex_init (&s->lock_, type, name, (ACE_mutexattr_t *)arg) == 0
&& ACE_OS::event_init (&s->count_nonzero_, 1,
count > 0, type, name, arg, sa) == 0
&& ACE_OS::thread_mutex_lock (&s->lock_) == 0)
{
s->count_ = count;
if (ACE_OS::thread_mutex_unlock (&s->lock_) == 0)
result = 0;
}
// Destroy the internal objects if we didn't initialize
// either of them successfully. Don't bother to check
// for errors.
if (result == -1)
{
ACE_OS::thread_mutex_destroy (&s->lock_);
ACE_OS::event_destroy (&s->count_nonzero_);
}
return result;
# endif /* ACE_USES_WINCE_SEMA_SIMULATION */
# elif defined (ACE_VXWORKS)
ACE_UNUSED_ARG (attributes);
ACE_UNUSED_ARG (name);
ACE_UNUSED_ARG (arg);
ACE_UNUSED_ARG (max);
ACE_UNUSED_ARG (sa);
s->name_ = 0;
s->sema_ = ::semCCreate (type, count);
return s->sema_ ? 0 : -1;
# endif /* ACE_HAS_STHREADS */
#else
ACE_UNUSED_ARG (s);
ACE_UNUSED_ARG (count);
ACE_UNUSED_ARG (type);
ACE_UNUSED_ARG (attributes);
ACE_UNUSED_ARG (name);
ACE_UNUSED_ARG (arg);
ACE_UNUSED_ARG (max);
ACE_UNUSED_ARG (sa);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_POSIX_SEM */
}
#if defined (ACE_HAS_WCHAR)
ACE_INLINE int
ACE_OS::sema_init (ACE_sema_t *s,
u_int count,
int type,
const wchar_t *name,
void *arg,
int max,
LPSECURITY_ATTRIBUTES sa)
{
ACE_condattr_t *pattr = 0;
return ACE_OS::sema_init (s, count, type, pattr, name, arg, max, sa);
}
ACE_INLINE int
ACE_OS::sema_init (ACE_sema_t *s,
u_int count,
int type,
ACE_condattr_t *attributes,
const wchar_t *name,
void *arg,
int max,
LPSECURITY_ATTRIBUTES sa)
{
# if defined (ACE_HAS_WTHREADS)
ACE_UNUSED_ARG (attributes);
# if ! defined (ACE_USES_WINCE_SEMA_SIMULATION)
ACE_UNUSED_ARG (type);
ACE_UNUSED_ARG (arg);
// Create the semaphore with its value initialized to <count> and
// its maximum value initialized to <max>.
SECURITY_ATTRIBUTES sa_buffer;
SECURITY_DESCRIPTOR sd_buffer;
*s = ::CreateSemaphoreW
(ACE_OS::default_win32_security_attributes_r (sa, &sa_buffer, &sd_buffer),
count,
max,
name);
if (*s == 0)
ACE_FAIL_RETURN (-1);
/* NOTREACHED */
else
{
// Make sure to set errno to ERROR_ALREADY_EXISTS if necessary.
ACE_OS::set_errno_to_last_error ();
return 0;
}
# else /* ACE_USES_WINCE_SEMA_SIMULATION */
int result = -1;
// Initialize internal object for semaphore simulation.
// Grab the lock as soon as possible when we initializing
// the semaphore count. Notice that we initialize the
// event object as "manually reset" so we can amortize the
// cost for singling/reseting the event.
// @@ I changed the mutex type to thread_mutex. Notice that this
// is basically a CriticalSection object and doesn't not has
// any security attribute whatsoever. However, since this
// semaphore implementation only works within a process, there
// shouldn't any security issue at all.
if (ACE_OS::thread_mutex_init (&s->lock_, type, name, (ACE_mutexattr_t *)arg) == 0
&& ACE_OS::event_init (&s->count_nonzero_, 1,
count > 0, type, name, arg, sa) == 0
&& ACE_OS::thread_mutex_lock (&s->lock_) == 0)
{
s->count_ = count;
if (ACE_OS::thread_mutex_unlock (&s->lock_) == 0)
result = 0;
}
// Destroy the internal objects if we didn't initialize
// either of them successfully. Don't bother to check
// for errors.
if (result == -1)
{
ACE_OS::thread_mutex_destroy (&s->lock_);
ACE_OS::event_destroy (&s->count_nonzero_);
}
return result;
# endif /* ACE_USES_WINCE_SEMA_SIMULATION */
# else /* ACE_HAS_WTHREADS */
// Just call the normal char version.
return ACE_OS::sema_init (s, count, type, attributes, ACE_Wide_To_Ascii (name).char_rep (), arg, max, sa);
# endif /* ACE_HAS_WTHREADS */
}
#endif /* ACE_HAS_WCHAR */
ACE_INLINE int
ACE_OS::sema_post (ACE_sema_t *s)
{
ACE_OS_TRACE ("ACE_OS::sema_post");
# if defined (ACE_HAS_POSIX_SEM)
# if defined (ACE_HAS_POSIX_SEM_TIMEOUT) || defined (ACE_DISABLE_POSIX_SEM_TIMEOUT_EMULATION)
ACE_OSCALL_RETURN (::sem_post (s->sema_), int, -1);
# else
int result = -1;
if (ACE_OS::mutex_lock (&s->lock_) == 0)
{
if (::sem_post (s->sema_) == 0)
result = ACE_OS::cond_signal (&s->count_nonzero_);
ACE_OS::mutex_unlock (&s->lock_);
}
return result;
# endif /* ACE_HAS_POSIX_SEM_TIMEOUT || ACE_DISABLE_POSIX_SEM_TIMEOUT_EMULATION */
# elif defined (ACE_USES_FIFO_SEM)
char c = 1;
if (ACE_OS::write (s->fd_[1], &c, sizeof (char)) == sizeof (char))
return 0;
return -1;
# elif defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::sema_post (s), result), int, -1);
# elif defined (ACE_HAS_PTHREADS)
int result = -1;
if (ACE_OS::mutex_lock (&s->lock_) == 0)
{
// Always allow a waiter to continue if there is one.
if (s->waiters_ > 0)
result = ACE_OS::cond_signal (&s->count_nonzero_);
else
result = 0;
s->count_++;
ACE_OS::mutex_unlock (&s->lock_);
}
return result;
# elif defined (ACE_HAS_WTHREADS)
# if !defined (ACE_USES_WINCE_SEMA_SIMULATION)
ACE_WIN32CALL_RETURN (ACE_ADAPT_RETVAL (::ReleaseSemaphore (*s, 1, 0),
ace_result_),
int, -1);
# else /* ACE_USES_WINCE_SEMA_SIMULATION */
int result = -1;
// Since we are simulating semaphores, we need to update semaphore
// count manually. Grab the lock to prevent race condition first.
if (ACE_OS::thread_mutex_lock (&s->lock_) == 0)
{
// Check the original state of event object. Single the event
// object in transition from semaphore not available to
// semaphore available.
if (s->count_++ <= 0)
result = ACE_OS::event_signal (&s->count_nonzero_);
else
result = 0;
ACE_OS::thread_mutex_unlock (&s->lock_);
}
return result;
# endif /* ACE_USES_WINCE_SEMA_SIMULATION */
# elif defined (ACE_VXWORKS)
ACE_OSCALL_RETURN (::semGive (s->sema_), int, -1);
# endif /* ACE_HAS_STHREADS */
# else
ACE_UNUSED_ARG (s);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_POSIX_SEM */
}
ACE_INLINE int
ACE_OS::sema_post (ACE_sema_t *s, u_int release_count)
{
#if defined (ACE_WIN32) && !defined (ACE_USES_WINCE_SEMA_SIMULATION)
// Win32 supports this natively.
ACE_WIN32CALL_RETURN (ACE_ADAPT_RETVAL (::ReleaseSemaphore (*s, release_count, 0),
ace_result_), int, -1);
#else
// On POSIX platforms we need to emulate this ourselves.
// @@ We can optimize on this implementation. However,
// the semaphore promitive on Win32 doesn't allow one
// to increase a semaphore to more than the count it was
// first initialized. Posix and solaris don't seem to have
// this restriction. Should we impose the restriction in
// our semaphore simulation?
for (size_t i = 0; i < release_count; i++)
if (ACE_OS::sema_post (s) == -1)
return -1;
return 0;
#endif /* ACE_WIN32 */
}
ACE_INLINE int
ACE_OS::sema_trywait (ACE_sema_t *s)
{
ACE_OS_TRACE ("ACE_OS::sema_trywait");
# if defined (ACE_HAS_POSIX_SEM)
// POSIX semaphores set errno to EAGAIN if trywait fails
ACE_OSCALL_RETURN (::sem_trywait (s->sema_), int, -1);
# elif defined (ACE_USES_FIFO_SEM)
char c;
int rc, flags;
/* turn on nonblocking for s->fd_[0] */
if ((flags = ACE_OS::fcntl (s->fd_[0], F_GETFL, 0)) < 0)
return -1;
flags |= O_NONBLOCK;
if (ACE_OS::fcntl (s->fd_[0], F_SETFL, flags) < 0)
return -1;
// read sets errno to EAGAIN if no input
rc = ACE_OS::read (s->fd_[0], &c, sizeof (char));
/* turn off nonblocking for fd_[0] */
if ((flags = ACE_OS::fcntl (s->fd_[0], F_GETFL, 0)) >= 0)
{
flags &= ~O_NONBLOCK;
ACE_OS::fcntl (s->fd_[0], F_SETFL, flags);
}
return rc == 1 ? 0 : (-1);
# elif defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_STHREADS)
// STHREADS semaphores set errno to EBUSY if trywait fails.
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::sema_trywait (s),
result),
int, -1);
# elif defined (ACE_HAS_PTHREADS)
int result = -1;
if (ACE_OS::mutex_lock (&s->lock_) == 0)
{
if (s->count_ > 0)
{
--s->count_;
result = 0;
}
else
errno = EBUSY;
ACE_OS::mutex_unlock (&s->lock_);
}
return result;
# elif defined (ACE_HAS_WTHREADS)
# if !defined (ACE_USES_WINCE_SEMA_SIMULATION)
DWORD result = ::WaitForSingleObject (*s, 0);
if (result == WAIT_OBJECT_0)
return 0;
else
{
if (result == WAIT_TIMEOUT)
errno = EBUSY;
else
ACE_OS::set_errno_to_last_error ();
// This is a hack, we need to find an appropriate mapping...
return -1;
}
# else /* ACE_USES_WINCE_SEMA_SIMULATION */
// Check the status of semaphore first. Return immediately
// if the semaphore is not available and avoid grabing the
// lock.
DWORD result = ::WaitForSingleObject (s->count_nonzero_, 0);
if (result == WAIT_OBJECT_0) // Proceed when it is available.
{
ACE_OS::thread_mutex_lock (&s->lock_);
// Need to double check if the semaphore is still available.
// The double checking scheme will slightly affect the
// efficiency if most of the time semaphores are not blocked.
result = ::WaitForSingleObject (s->count_nonzero_, 0);
if (result == WAIT_OBJECT_0)
{
// Adjust the semaphore count. Only update the event
// object status when the state changed.
s->count_--;
if (s->count_ <= 0)
ACE_OS::event_reset (&s->count_nonzero_);
result = 0;
}
ACE_OS::thread_mutex_unlock (&s->lock_);
}
// Translate error message to errno used by ACE.
if (result == WAIT_TIMEOUT)
errno = EBUSY;
else
ACE_OS::set_errno_to_last_error ();
// This is taken from the hack above. ;)
return -1;
# endif /* ACE_USES_WINCE_SEMA_SIMULATION */
# elif defined (ACE_VXWORKS)
if (::semTake (s->sema_, NO_WAIT) == ERROR)
if (errno == S_objLib_OBJ_UNAVAILABLE)
{
// couldn't get the semaphore
errno = EBUSY;
return -1;
}
else
// error
return -1;
else
// got the semaphore
return 0;
# endif /* ACE_HAS_STHREADS */
# else
ACE_UNUSED_ARG (s);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_POSIX_SEM */
}
ACE_INLINE int
ACE_OS::sema_wait (ACE_sema_t *s)
{
ACE_OS_TRACE ("ACE_OS::sema_wait");
# if defined (ACE_HAS_POSIX_SEM)
ACE_OSCALL_RETURN (::sem_wait (s->sema_), int, -1);
# elif defined (ACE_USES_FIFO_SEM)
char c;
if (ACE_OS::read (s->fd_[0], &c, sizeof (char)) == 1)
return 0;
return -1;
# elif defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::sema_wait (s), result), int, -1);
# elif defined (ACE_HAS_PTHREADS)
int result = 0;
ACE_PTHREAD_CLEANUP_PUSH (&s->lock_);
if (ACE_OS::mutex_lock (&s->lock_) != 0)
result = -1;
else
{
// Keep track of the number of waiters so that we can signal
// them properly in <ACE_OS::sema_post>.
s->waiters_++;
// Wait until the semaphore count is > 0.
while (s->count_ == 0)
if (ACE_OS::cond_wait (&s->count_nonzero_,
&s->lock_) == -1)
{
result = -2; // -2 means that we need to release the mutex.
break;
}
--s->waiters_;
}
if (result == 0)
--s->count_;
if (result != -1)
ACE_OS::mutex_unlock (&s->lock_);
ACE_PTHREAD_CLEANUP_POP (0);
return result < 0 ? -1 : result;
# elif defined (ACE_HAS_WTHREADS)
# if !defined (ACE_USES_WINCE_SEMA_SIMULATION)
switch (::WaitForSingleObject (*s, INFINITE))
{
case WAIT_OBJECT_0:
return 0;
default:
// This is a hack, we need to find an appropriate mapping...
ACE_OS::set_errno_to_last_error ();
return -1;
}
/* NOTREACHED */
# else /* ACE_USES_WINCE_SEMA_SIMULATION */
// Timed wait.
int result = -1;
for (;;)
// Check if the semaphore is avialable or not and wait forever.
// Don't bother to grab the lock if it is not available (to avoid
// deadlock.)
switch (::WaitForSingleObject (s->count_nonzero_, INFINITE))
{
case WAIT_OBJECT_0:
ACE_OS::thread_mutex_lock (&s->lock_);
// Need to double check if the semaphore is still available.
// This time, we shouldn't wait at all.
if (::WaitForSingleObject (s->count_nonzero_, 0) == WAIT_OBJECT_0)
{
// Decrease the internal counter. Only update the event
// object's status when the state changed.
s->count_--;
if (s->count_ <= 0)
ACE_OS::event_reset (&s->count_nonzero_);
result = 0;
}
ACE_OS::thread_mutex_unlock (&s->lock_);
// if we didn't get a hold on the semaphore, the result won't
// be 0 and thus, we'll start from the beginning again.
if (result == 0)
return 0;
break;
default:
// Since we wait indefinitely, anything other than
// WAIT_OBJECT_O indicates an error.
ACE_OS::set_errno_to_last_error ();
// This is taken from the hack above. ;)
return -1;
}
/* NOTREACHED */
# endif /* ACE_USES_WINCE_SEMA_SIMULATION */
# elif defined (ACE_VXWORKS)
ACE_OSCALL_RETURN (::semTake (s->sema_, WAIT_FOREVER), int, -1);
# endif /* ACE_HAS_STHREADS */
# else
ACE_UNUSED_ARG (s);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_POSIX_SEM */
}
ACE_INLINE int
ACE_OS::sema_wait (ACE_sema_t *s, ACE_Time_Value &tv)
{
ACE_OS_TRACE ("ACE_OS::sema_wait");
# if defined (ACE_HAS_POSIX_SEM)
# if defined (ACE_HAS_POSIX_SEM_TIMEOUT)
int rc;
timespec_t ts;
ts = tv; // Calls ACE_Time_Value::operator timespec_t().
ACE_OSCALL (::sem_timedwait (s->sema_, &ts), int, -1, rc);
if (rc == -1 && errno == ETIMEDOUT)
errno = ETIME; /* POSIX returns ETIMEDOUT but we need ETIME */
return rc;
# elif !defined (ACE_DISABLE_POSIX_SEM_TIMEOUT_EMULATION)
int result = 0;
bool expired = false;
ACE_Errno_Guard error (errno);
ACE_PTHREAD_CLEANUP_PUSH (&s->lock_);
if (ACE_OS::mutex_lock (&s->lock_) != 0)
result = -2;
else
{
bool finished = true;
do
{
result = ACE_OS::sema_trywait (s);
if (result == -1 && errno == EAGAIN)
expired = (tv.to_relative_time () <= ACE_Time_Value::zero);
else
expired = false;
finished = result != -1 || expired ||
(result == -1 && errno != EAGAIN);
if (!finished)
{
if (ACE_OS::cond_timedwait (&s->count_nonzero_,
&s->lock_,
&tv) == -1)
{
error = errno;
result = -1;
break;
}
}
} while (!finished);
if (expired)
error = ETIME;
# if defined (ACE_LACKS_COND_TIMEDWAIT_RESET)
tv = tv.now ();
# endif /* ACE_LACKS_COND_TIMEDWAIT_RESET */
}
if (result != -2)
ACE_OS::mutex_unlock (&s->lock_);
ACE_PTHREAD_CLEANUP_POP (0);
return result < 0 ? -1 : result;
# else /* No native sem_timedwait(), and emulation disabled */
ACE_UNUSED_ARG (s);
ACE_UNUSED_ARG (tv);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_POSIX_SEM_TIMEOUT */
# elif defined (ACE_USES_FIFO_SEM)
int rc;
ACE_Time_Value timeout = tv.to_relative_time ();
while (timeout > ACE_Time_Value::zero)
{
ACE_Handle_Set fds_;
fds_.set_bit (s->fd_[0]);
if ((rc = ACE_OS::select (ACE_Handle_Set::MAXSIZE, fds_, 0, 0, timeout)) != 1)
{
if (rc == 0 || errno != EAGAIN)
{
if (rc == 0)
errno = ETIME;
return -1;
}
}
// try to read the signal *but* do *not* block
if (rc == 1 && ACE_OS::sema_trywait (s) == 0)
return 0;
// we were woken for input but someone beat us to it
// so we wait again if there is still time
timeout = tv.to_relative_time ();
}
// make sure errno is set right
errno = ETIME;
return -1;
# elif defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_STHREADS)
ACE_UNUSED_ARG (s);
ACE_UNUSED_ARG (tv);
ACE_NOTSUP_RETURN (-1);
# elif defined (ACE_HAS_PTHREADS)
int result = 0;
ACE_Errno_Guard error (errno);
ACE_PTHREAD_CLEANUP_PUSH (&s->lock_);
if (ACE_OS::mutex_lock (&s->lock_) != 0)
result = -1;
else
{
// Keep track of the number of waiters so that we can signal
// them properly in <ACE_OS::sema_post>.
s->waiters_++;
// Wait until the semaphore count is > 0 or until we time out.
while (s->count_ == 0)
if (ACE_OS::cond_timedwait (&s->count_nonzero_,
&s->lock_,
&tv) == -1)
{
error = errno;
result = -2; // -2 means that we need to release the mutex.
break;
}
--s->waiters_;
}
if (result == 0)
{
# if defined (ACE_LACKS_COND_TIMEDWAIT_RESET)
tv = tv.now ();
# endif /* ACE_LACKS_COND_TIMEDWAIT_RESET */
--s->count_;
}
if (result != -1)
ACE_OS::mutex_unlock (&s->lock_);
ACE_PTHREAD_CLEANUP_POP (0);
return result < 0 ? -1 : result;
# elif defined (ACE_HAS_WTHREADS)
# if !defined (ACE_USES_WINCE_SEMA_SIMULATION)
int msec_timeout;
if (tv == ACE_Time_Value::zero)
msec_timeout = 0; // Do a "poll."
else
{
// Note that we must convert between absolute time (which is
// passed as a parameter) and relative time (which is what
// <WaitForSingleObjects> expects).
ACE_Time_Value relative_time = tv.to_relative_time ();
// Watchout for situations where a context switch has caused the
// current time to be > the timeout.
if (relative_time < ACE_Time_Value::zero)
msec_timeout = 0;
else
msec_timeout = relative_time.msec ();
}
switch (::WaitForSingleObject (*s, msec_timeout))
{
case WAIT_OBJECT_0:
tv = tv.now (); // Update time to when acquired
return 0;
case WAIT_TIMEOUT:
errno = ETIME;
return -1;
default:
// This is a hack, we need to find an appropriate mapping...
ACE_OS::set_errno_to_last_error ();
return -1;
}
/* NOTREACHED */
# else /* ACE_USES_WINCE_SEMA_SIMULATION */
// Note that in this mode, the acquire is done in two steps, and
// we may get signaled but cannot grab the semaphore before
// timeout. In that case, we'll need to restart the process with
// updated timeout value.
// tv is an absolute time, but we need relative to work with the Windows
// API. Also, some users have become accustomed to using a 0 time value
// as a shortcut for "now", which works on non-Windows because 0 is
// always earlier than now. However, the need to convert to relative time
// means we need to watch out for this case.
ACE_Time_Value relative_time (ACE_Time_Value::zero);
if (tv != ACE_Time_Value::zero)
relative_time = tv.to_relative_time ();
int result = -1;
// While we are not timeout yet. >= 0 will let this go through once
// and if not able to get the object, it should hit WAIT_TIMEOUT
// right away.
while (relative_time >= ACE_Time_Value::zero)
{
// Wait for our turn to get the object.
switch (::WaitForSingleObject (s->count_nonzero_, relative_time.msec ()))
{
case WAIT_OBJECT_0:
ACE_OS::thread_mutex_lock (&s->lock_);
// Need to double check if the semaphore is still available.
// We can only do a "try lock" styled wait here to avoid
// blocking threads that want to signal the semaphore.
if (::WaitForSingleObject (s->count_nonzero_, 0) == WAIT_OBJECT_0)
{
// As before, only reset the object when the semaphore
// is no longer available.
s->count_--;
if (s->count_ <= 0)
ACE_OS::event_reset (&s->count_nonzero_);
result = 0;
}
ACE_OS::thread_mutex_unlock (&s->lock_);
// Only return when we successfully get the semaphore.
if (result == 0)
{
tv = tv.now (); // Update to time acquired
return 0;
}
break;
// We have timed out.
case WAIT_TIMEOUT:
errno = ETIME;
return -1;
// What?
default:
ACE_OS::set_errno_to_last_error ();
// This is taken from the hack above. ;)
return -1;
};
// Haven't been able to get the semaphore yet, update the
// timeout value to reflect the remaining time we want to wait.
// in case of tv == 0 relative_time will now be < 0 and we will be out of time
relative_time = tv.to_relative_time ();
}
// We have timed out.
errno = ETIME;
return -1;
# endif /* ACE_USES_WINCE_SEMA_SIMULATION */
# elif defined (ACE_VXWORKS)
// Note that we must convert between absolute time (which is
// passed as a parameter) and relative time (which is what
// the system call expects).
ACE_Time_Value relative_time = tv.to_relative_time ();
int ticks_per_sec = ::sysClkRateGet ();
int ticks = relative_time.sec () * ticks_per_sec +
relative_time.usec () * ticks_per_sec / ACE_ONE_SECOND_IN_USECS;
if (::semTake (s->sema_, ticks) == ERROR)
{
if (errno == S_objLib_OBJ_TIMEOUT)
// Convert the VxWorks errno to one that's common for to ACE
// platforms.
errno = ETIME;
else if (errno == S_objLib_OBJ_UNAVAILABLE)
errno = EBUSY;
return -1;
}
else
{
tv = tv.now (); // Update to time acquired
return 0;
}
# endif /* ACE_HAS_STHREADS */
# else
ACE_UNUSED_ARG (s);
ACE_UNUSED_ARG (tv);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_POSIX_SEM */
}
ACE_INLINE int
ACE_OS::sema_wait (ACE_sema_t *s, ACE_Time_Value *tv)
{
return tv == 0 ? ACE_OS::sema_wait (s) : ACE_OS::sema_wait (s, *tv);
}
ACE_INLINE int
ACE_OS::semctl (int int_id, int semnum, int cmd, semun value)
{
ACE_OS_TRACE ("ACE_OS::semctl");
#if defined (ACE_HAS_SYSV_IPC)
ACE_OSCALL_RETURN (::semctl (int_id, semnum, cmd, value), int, -1);
#else
ACE_UNUSED_ARG (int_id);
ACE_UNUSED_ARG (semnum);
ACE_UNUSED_ARG (cmd);
ACE_UNUSED_ARG (value);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_SYSV_IPC */
}
ACE_INLINE int
ACE_OS::semget (key_t key, int nsems, int flags)
{
ACE_OS_TRACE ("ACE_OS::semget");
#if defined (ACE_HAS_SYSV_IPC)
ACE_OSCALL_RETURN (::semget (key, nsems, flags), int, -1);
#else
ACE_UNUSED_ARG (key);
ACE_UNUSED_ARG (nsems);
ACE_UNUSED_ARG (flags);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_SYSV_IPC */
}
ACE_INLINE int
ACE_OS::semop (int int_id, struct sembuf *sops, size_t nsops)
{
ACE_OS_TRACE ("ACE_OS::semop");
#if defined (ACE_HAS_SYSV_IPC)
ACE_OSCALL_RETURN (::semop (int_id, sops, nsops), int, -1);
#else
ACE_UNUSED_ARG (int_id);
ACE_UNUSED_ARG (sops);
ACE_UNUSED_ARG (nsops);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_SYSV_IPC */
}
ACE_INLINE int
ACE_OS::sigtimedwait (const sigset_t *sset,
siginfo_t *info,
const ACE_Time_Value *timeout)
{
ACE_OS_TRACE ("ACE_OS::sigtimedwait");
#if defined (ACE_HAS_SIGTIMEDWAIT)
timespec_t ts;
timespec_t *tsp = 0;
if (timeout != 0)
{
ts = *timeout; // Calls ACE_Time_Value::operator timespec_t().
tsp = &ts;
}
ACE_OSCALL_RETURN (::sigtimedwait (sset, info, tsp),
int, -1);
#else
ACE_UNUSED_ARG (sset);
ACE_UNUSED_ARG (info);
ACE_UNUSED_ARG (timeout);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_SIGTIMEDWAIT */
}
ACE_INLINE int
ACE_OS::sigwait (sigset_t *sset, int *sig)
{
ACE_OS_TRACE ("ACE_OS::sigwait");
int local_sig;
if (sig == 0)
sig = &local_sig;
#if defined (ACE_HAS_THREADS)
# if (defined (__FreeBSD__) && (__FreeBSD__ < 3))
ACE_UNUSED_ARG (sset);
ACE_NOTSUP_RETURN (-1);
# elif defined (ACE_HAS_STHREADS)
# if (_POSIX_C_SOURCE - 0 >= 199506L) || defined (_POSIX_PTHREAD_SEMANTICS)
errno = ::sigwait (sset, sig);
return errno == 0 ? *sig : -1;
#else
*sig = ::sigwait (sset);
return *sig;
#endif /* _POSIX_C_SOURCE - 0 >= 199506L || _POSIX_PTHREAD_SEMANTICS */
# elif defined (ACE_HAS_PTHREADS)
# if defined (CYGWIN32)
// Cygwin has sigwait definition, but it is not implemented
ACE_UNUSED_ARG (sset);
ACE_NOTSUP_RETURN (-1);
# else /* this is std */
errno = ::sigwait (sset, sig);
return errno == 0 ? *sig : -1;
# endif /* CYGWIN32 */
# elif defined (ACE_HAS_WTHREADS)
ACE_UNUSED_ARG (sset);
ACE_NOTSUP_RETURN (-1);
# elif defined (ACE_VXWORKS)
// Second arg is a struct siginfo *, which we don't need (the
// selected signal number is returned). Third arg is timeout: 0
// means forever.
*sig = ::sigtimedwait (sset, 0, 0);
return *sig;
# endif /* __FreeBSD__ */
#else
ACE_UNUSED_ARG (sset);
ACE_UNUSED_ARG (sig);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::sigwaitinfo (const sigset_t *sset,
siginfo_t *info)
{
ACE_OS_TRACE ("ACE_OS::sigwaitinfo");
// If this platform has sigtimedwait, it should have sigwaitinfo as well.
// If this isn't true somewhere, let me know and I'll fix this.
// -Steve Huston <shuston@riverace.com>.
#if defined (ACE_HAS_SIGTIMEDWAIT)
ACE_OSCALL_RETURN (::sigwaitinfo (sset, info), int, -1);
#else
ACE_UNUSED_ARG (sset);
ACE_UNUSED_ARG (info);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_SIGTIMEDWAIT */
}
ACE_INLINE int
ACE_OS::thr_cancel (ACE_thread_t thr_id)
{
ACE_OS_TRACE ("ACE_OS::thr_cancel");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_PTHREADS) && !defined (ACE_LACKS_PTHREAD_CANCEL)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_cancel (thr_id),
result),
int, -1);
# elif defined (ACE_HAS_VXTHREADS)
ACE_OSCALL_RETURN (::taskDelete (thr_id), int, -1);
# else /* Could be ACE_HAS_PTHREADS && ACE_LACKS_PTHREAD_CANCEL */
ACE_UNUSED_ARG (thr_id);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_PTHREADS */
#else
ACE_UNUSED_ARG (thr_id);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::thr_cmp (ACE_hthread_t t1, ACE_hthread_t t2)
{
#if defined (ACE_HAS_PTHREADS)
# if defined (pthread_equal)
// If it's a macro we can't say "pthread_equal"...
return pthread_equal (t1, t2);
# else
return pthread_equal (t1, t2);
# endif /* pthread_equal */
#else /* For STHREADS, WTHREADS, and VXWORKS ... */
// Hum, Do we need to treat WTHREAD differently?
// levine 13 oct 98 % Probably, ACE_hthread_t is a HANDLE.
return t1 == t2;
#endif /* ACE_HAS_PTHREADS */
}
ACE_INLINE int
ACE_OS::thr_continue (ACE_hthread_t target_thread)
{
ACE_OS_TRACE ("ACE_OS::thr_continue");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_continue (target_thread), result), int, -1);
# elif defined (ACE_HAS_PTHREADS)
# if defined (ACE_HAS_PTHREAD_CONTINUE)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_continue (target_thread),
result),
int, -1);
# elif defined (ACE_HAS_PTHREAD_CONTINUE_NP)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_continue_np (target_thread),
result),
int, -1);
# elif defined (ACE_HAS_PTHREAD_RESUME_NP)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_resume_np (target_thread),
result),
int, -1);
# else
ACE_UNUSED_ARG (target_thread);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_PTHREAD_CONTINUE */
# elif defined (ACE_HAS_WTHREADS)
DWORD result = ::ResumeThread (target_thread);
if (result == ACE_SYSCALL_FAILED)
ACE_FAIL_RETURN (-1);
else
return 0;
# elif defined (ACE_HAS_VXTHREADS)
ACE_OSCALL_RETURN (::taskResume (target_thread), int, -1);
# endif /* ACE_HAS_STHREADS */
#else
ACE_UNUSED_ARG (target_thread);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::thr_getconcurrency (void)
{
ACE_OS_TRACE ("ACE_OS::thr_getconcurrency");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_STHREADS)
return ::thr_getconcurrency ();
# elif defined (ACE_HAS_PTHREADS) && defined (ACE_HAS_PTHREAD_GETCONCURRENCY)
return pthread_getconcurrency ();
# else
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_STHREADS */
#else
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::thr_getprio (ACE_hthread_t ht_id, int &priority, int &policy)
{
ACE_OS_TRACE ("ACE_OS::thr_getprio");
ACE_UNUSED_ARG (policy);
#if defined (ACE_HAS_THREADS)
# if (defined (ACE_HAS_PTHREADS) && \
(!defined (ACE_LACKS_SETSCHED) || defined (ACE_HAS_PTHREAD_SCHEDPARAM)))
struct sched_param param;
int result;
ACE_OSCALL (ACE_ADAPT_RETVAL (pthread_getschedparam (ht_id, &policy, &param),
result), int,
-1, result);
priority = param.sched_priority;
return result;
# elif defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_getprio (ht_id, &priority), result), int, -1);
# elif defined (ACE_HAS_WTHREADS)
ACE_Errno_Guard error (errno);
# if defined (ACE_HAS_WINCE) && !defined (ACE_LACKS_CE_THREAD_PRIORITY)
priority = ::CeGetThreadPriority (ht_id);
# else
priority = ::GetThreadPriority (ht_id);
# endif /* defined (ACE_HAS_WINCE) && !defined (ACE_LACKS_CE_THREAD_PRIORITY) */
# if defined (ACE_HAS_PHARLAP)
# if defined (ACE_PHARLAP_LABVIEW_RT)
policy = ACE_SCHED_FIFO;
# else
DWORD timeslice = ::EtsGetTimeSlice ();
policy = timeslice == 0 ? ACE_SCHED_OTHER : ACE_SCHED_FIFO;
# endif /* ACE_PHARLAP_LABVIEW_RT */
# elif !defined (ACE_HAS_WINCE)
DWORD priority_class = ::GetPriorityClass (::GetCurrentProcess ());
if (priority_class == 0 && (error = ::GetLastError ()) != NO_ERROR)
ACE_FAIL_RETURN (-1);
policy =
(priority_class ==
REALTIME_PRIORITY_CLASS) ? ACE_SCHED_FIFO : ACE_SCHED_OTHER;
# endif /* ACE_HAS_PHARLAP */
return 0;
# elif defined (ACE_HAS_VXTHREADS)
ACE_OSCALL_RETURN (::taskPriorityGet (ht_id, &priority), int, -1);
# else
ACE_UNUSED_ARG (ht_id);
ACE_UNUSED_ARG (priority);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_STHREADS */
#else
ACE_UNUSED_ARG (ht_id);
ACE_UNUSED_ARG (priority);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::thr_getprio (ACE_hthread_t ht_id, int &priority)
{
ACE_OS_TRACE ("ACE_OS::thr_getprio");
int policy = 0;
return ACE_OS::thr_getprio (ht_id, priority, policy);
}
#if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE)
ACE_INLINE int
ACE_OS::thr_getspecific_native (ACE_OS_thread_key_t key, void **data)
{
// ACE_OS_TRACE ("ACE_OS::thr_getspecific_native");
# if defined (ACE_HAS_PTHREADS)
*data = pthread_getspecific (key);
return 0;
# elif defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_getspecific (key, data), result), int, -1);
# elif defined (ACE_HAS_WTHREADS)
*data = ::TlsGetValue (key);
if (*data == 0 && ::GetLastError () != NO_ERROR)
{
ACE_OS::set_errno_to_last_error ();
return -1;
}
else
return 0;
# else /* ACE_HAS_PTHREADS etc.*/
ACE_UNUSED_ARG (key);
ACE_UNUSED_ARG (data);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_PTHREADS etc.*/
}
#endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE */
ACE_INLINE int
ACE_OS::thr_getspecific (ACE_thread_key_t key, void **data)
{
// ACE_OS_TRACE ("ACE_OS::thr_getspecific");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_TSS_EMULATION)
if (ACE_TSS_Emulation::is_key (key) == 0)
{
errno = EINVAL;
data = 0;
return -1;
}
else
{
*data = ACE_TSS_Emulation::ts_object (key);
return 0;
}
# elif defined (ACE_HAS_THREAD_SPECIFIC_STORAGE)
return ACE_OS::thr_getspecific_native (key, data);
#else
ACE_UNUSED_ARG (key);
ACE_UNUSED_ARG (data);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_TSS_EMULATION */
#else
ACE_UNUSED_ARG (key);
ACE_UNUSED_ARG (data);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
#if !defined (ACE_HAS_VXTHREADS)
ACE_INLINE int
ACE_OS::thr_join (ACE_hthread_t thr_handle,
ACE_THR_FUNC_RETURN *status)
{
ACE_OS_TRACE ("ACE_OS::thr_join");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_join (thr_handle, 0, status), result),
int, -1);
# elif defined (ACE_HAS_PTHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_join (thr_handle, status), result),
int, -1);
# elif defined (ACE_HAS_WTHREADS)
// Waiting on the calling thread will deadlock, so try to avoid that. The
// direct access to the needed info (GetThreadId) was added at Vista.
// Win Server 2003 is 5.2; Vista is 6.0
# if defined (_WIN32_WINNT) && (_WIN32_WINNT >= 0x0502)
const ACE_TEXT_OSVERSIONINFO &info = ACE_OS::get_win32_versioninfo ();
if (info.dwMajorVersion >= 6 ||
(info.dwMajorVersion == 5 && info.dwMinorVersion == 2))
{
if (::GetThreadId (thr_handle) == ::GetCurrentThreadId ())
{
errno = ERROR_POSSIBLE_DEADLOCK;
return -1;
}
}
# endif /* _WIN32_WINNT */
ACE_THR_FUNC_RETURN local_status = 0;
// Make sure that status is non-NULL.
if (status == 0)
status = &local_status;
if (::WaitForSingleObject (thr_handle, INFINITE) == WAIT_OBJECT_0
&& ::GetExitCodeThread (thr_handle, status) != FALSE)
{
::CloseHandle (thr_handle);
return 0;
}
ACE_FAIL_RETURN (-1);
/* NOTREACHED */
# else
ACE_UNUSED_ARG (thr_handle);
ACE_UNUSED_ARG (status);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_STHREADS */
#else
ACE_UNUSED_ARG (thr_handle);
ACE_UNUSED_ARG (status);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::thr_join (ACE_thread_t waiter_id,
ACE_thread_t *thr_id,
ACE_THR_FUNC_RETURN *status)
{
ACE_OS_TRACE ("ACE_OS::thr_join");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_join (waiter_id, thr_id, status), result),
int, -1);
# elif defined (ACE_HAS_PTHREADS)
ACE_UNUSED_ARG (thr_id);
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_join (waiter_id, status), result),
int, -1);
# elif defined (ACE_HAS_WTHREADS)
ACE_UNUSED_ARG (waiter_id);
ACE_UNUSED_ARG (thr_id);
ACE_UNUSED_ARG (status);
// This could be implemented if the DLL-Main function or the
// task exit base class some log the threads which have exited
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_STHREADS */
#else
ACE_UNUSED_ARG (waiter_id);
ACE_UNUSED_ARG (thr_id);
ACE_UNUSED_ARG (status);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
#endif /* !VXWORKS */
ACE_INLINE int
ACE_OS::thr_kill (ACE_thread_t thr_id, int signum)
{
ACE_OS_TRACE ("ACE_OS::thr_kill");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_PTHREADS)
# if defined (ACE_LACKS_PTHREAD_KILL)
ACE_UNUSED_ARG (signum);
ACE_UNUSED_ARG (thr_id);
ACE_NOTSUP_RETURN (-1);
# else
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_kill (thr_id, signum),
result),
int, -1);
# endif /* ACE_LACKS_PTHREAD_KILL */
# elif defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_kill (thr_id, signum),
result),
int, -1);
# elif defined (ACE_HAS_VXTHREADS)
//FUZZ: disable check_for_lack_ACE_OS
ACE_OSCALL_RETURN (::kill (thr_id, signum), int, -1);
//FUZZ: enable check_for_lack_ACE_OS
# else
ACE_UNUSED_ARG (thr_id);
ACE_UNUSED_ARG (signum);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_STHREADS */
#else
ACE_UNUSED_ARG (thr_id);
ACE_UNUSED_ARG (signum);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE size_t
ACE_OS::thr_min_stack (void)
{
ACE_OS_TRACE ("ACE_OS::thr_min_stack");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_STHREADS)
# if defined (ACE_HAS_THR_MINSTACK)
// Tandem did some weirdo mangling of STHREAD names...
return ::thr_minstack ();
# else
return ::thr_min_stack ();
# endif /* !ACE_HAS_THR_MINSTACK */
# elif defined (ACE_HAS_PTHREADS)
# if defined (_SC_THREAD_STACK_MIN)
return (size_t) ACE_OS::sysconf (_SC_THREAD_STACK_MIN);
# elif defined (PTHREAD_STACK_MIN)
return PTHREAD_STACK_MIN;
# else
ACE_NOTSUP_RETURN (0);
# endif /* _SC_THREAD_STACK_MIN */
# elif defined (ACE_HAS_WTHREADS)
ACE_NOTSUP_RETURN (0);
# elif defined (ACE_HAS_VXTHREADS)
TASK_DESC taskDesc;
STATUS status;
ACE_thread_t tid = ACE_OS::thr_self ();
ACE_OSCALL (ACE_ADAPT_RETVAL (::taskInfoGet (tid, &taskDesc),
status),
STATUS, -1, status);
return status == OK ? taskDesc.td_stackSize : 0;
# else /* Should not happen... */
ACE_NOTSUP_RETURN (0);
# endif /* ACE_HAS_STHREADS */
#else
ACE_NOTSUP_RETURN (0);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE ssize_t
ACE_OS::thr_id (char buffer[], size_t buffer_length)
{
#if defined (ACE_WIN32)
#if defined (ACE_HAS_SNPRINTF)
return ACE_OS::snprintf (buffer,
buffer_length,
"%u",
static_cast <unsigned> (ACE_OS::thr_self ()));
#else
ACE_UNUSED_ARG (buffer_length);
return ACE_OS::sprintf (buffer,
"%u",
static_cast <unsigned> (ACE_OS::thr_self ()));
#endif /* ACE_HAS_SNPRINTF */
#else
ACE_hthread_t t_id;
ACE_OS::thr_self (t_id);
#if defined (ACE_HAS_SNPRINTF)
return ACE_OS::snprintf (buffer,
buffer_length,
"%lu",
(unsigned long) t_id);
#else
ACE_UNUSED_ARG (buffer_length);
return ACE_OS::sprintf (buffer,
"%lu",
(unsigned long) t_id);
#endif /* ACE_HAS_SNPRINTF */
#endif /* WIN32 */
}
ACE_INLINE ACE_thread_t
ACE_OS::thr_self (void)
{
// ACE_OS_TRACE ("ACE_OS::thr_self");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_PTHREADS)
// Note, don't use "::" here since the following call is often a macro.
return pthread_self ();
# elif defined (ACE_HAS_STHREADS)
ACE_OSCALL_RETURN (::thr_self (), int, -1);
# elif defined (ACE_HAS_WTHREADS)
return ::GetCurrentThreadId ();
# elif defined (ACE_HAS_VXTHREADS)
return ::taskIdSelf ();
# endif /* ACE_HAS_STHREADS */
#else
return 1; // Might as well make it the first thread ;-)
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE const char*
ACE_OS::thr_name (void)
{
#if defined (ACE_HAS_THREADS)
#if defined (ACE_HAS_VXTHREADS)
return ::taskName (ACE_OS::thr_self ());
#else
ACE_NOTSUP_RETURN (0);
#endif
#else
ACE_NOTSUP_RETURN (0);
#endif
}
ACE_INLINE void
ACE_OS::thr_self (ACE_hthread_t &self)
{
ACE_OS_TRACE ("ACE_OS::thr_self");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_PTHREADS)
// Note, don't use "::" here since the following call is often a macro.
self = pthread_self ();
# elif defined (ACE_HAS_THREAD_SELF)
self = ::thread_self ();
# elif defined (ACE_HAS_STHREADS)
self = ::thr_self ();
# elif defined (ACE_HAS_WTHREADS)
self = ::GetCurrentThread ();
# elif defined (ACE_HAS_VXTHREADS)
self = ::taskIdSelf ();
# endif /* ACE_HAS_STHREADS */
#else
self = 1; // Might as well make it the main thread ;-)
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::thr_setcancelstate (int new_state, int *old_state)
{
ACE_OS_TRACE ("ACE_OS::thr_setcancelstate");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_PTHREADS) && !defined (ACE_LACKS_PTHREAD_CANCEL)
int result;
int local_new, local_old;
switch (new_state)
{
case THR_CANCEL_ENABLE:
local_new = PTHREAD_CANCEL_ENABLE;
break;
case THR_CANCEL_DISABLE:
local_new = PTHREAD_CANCEL_DISABLE;
break;
default:
errno = EINVAL;
return -1;
}
ACE_OSCALL (ACE_ADAPT_RETVAL (pthread_setcancelstate (local_new,
&local_old),
result),
int, -1, result);
if (result == -1)
return -1;
switch (local_old)
{
case PTHREAD_CANCEL_ENABLE:
*old_state = THR_CANCEL_ENABLE;
break;
case PTHREAD_CANCEL_DISABLE:
*old_state = THR_CANCEL_DISABLE;
break;
}
return result;
# elif defined (ACE_HAS_STHREADS)
ACE_UNUSED_ARG (new_state);
ACE_UNUSED_ARG (old_state);
ACE_NOTSUP_RETURN (-1);
# elif defined (ACE_HAS_WTHREADS)
ACE_UNUSED_ARG (new_state);
ACE_UNUSED_ARG (old_state);
ACE_NOTSUP_RETURN (-1);
# else /* Could be ACE_HAS_PTHREADS && ACE_LACKS_PTHREAD_CANCEL */
ACE_UNUSED_ARG (new_state);
ACE_UNUSED_ARG (old_state);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_PTHREADS */
#else
ACE_UNUSED_ARG (new_state);
ACE_UNUSED_ARG (old_state);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::thr_setcanceltype (int new_type, int *old_type)
{
ACE_OS_TRACE ("ACE_OS::thr_setcanceltype");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_PTHREADS) && !defined (ACE_LACKS_PTHREAD_CANCEL)
int result;
int local_new, local_old;
switch (new_type)
{
case THR_CANCEL_DEFERRED:
local_new = PTHREAD_CANCEL_DEFERRED;
break;
case THR_CANCEL_ASYNCHRONOUS:
local_new = PTHREAD_CANCEL_ASYNCHRONOUS;
break;
default:
errno = EINVAL;
return -1;
}
ACE_OSCALL (ACE_ADAPT_RETVAL (pthread_setcanceltype (local_new,
&local_old),
result),
int, -1, result);
if (result == -1)
return -1;
switch (local_old)
{
case PTHREAD_CANCEL_DEFERRED:
*old_type = THR_CANCEL_DEFERRED;
break;
case PTHREAD_CANCEL_ASYNCHRONOUS:
*old_type = THR_CANCEL_ASYNCHRONOUS;
break;
}
return result;
# else /* Could be ACE_HAS_PTHREADS && ACE_LACKS_PTHREAD_CANCEL */
ACE_UNUSED_ARG (new_type);
ACE_UNUSED_ARG (old_type);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_PTHREADS */
#else
ACE_UNUSED_ARG (new_type);
ACE_UNUSED_ARG (old_type);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::thr_setconcurrency (int hint)
{
ACE_OS_TRACE ("ACE_OS::thr_setconcurrency");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_setconcurrency (hint),
result),
int, -1);
# elif defined (ACE_HAS_PTHREADS) && defined (ACE_HAS_PTHREAD_SETCONCURRENCY)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_setconcurrency (hint),
result),
int, -1);
# else
ACE_UNUSED_ARG (hint);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_STHREADS */
#else
ACE_UNUSED_ARG (hint);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::thr_setprio (ACE_hthread_t ht_id, int priority, int policy)
{
ACE_OS_TRACE ("ACE_OS::thr_setprio");
ACE_UNUSED_ARG (policy);
#if defined (ACE_HAS_THREADS)
# if (defined (ACE_HAS_PTHREADS) && \
(!defined (ACE_LACKS_SETSCHED) || defined (ACE_HAS_PTHREAD_SCHEDPARAM)))
int result;
struct sched_param param;
ACE_OS::memset ((void *) &param, 0, sizeof param);
// If <policy> is -1, we don't want to use it for
// pthread_setschedparam(). Instead, obtain policy from
// pthread_getschedparam().
if (policy == -1)
{
ACE_OSCALL (ACE_ADAPT_RETVAL (pthread_getschedparam (ht_id, &policy, &param),
result),
int, -1, result);
if (result == -1)
return result;
}
param.sched_priority = priority;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_setschedparam (ht_id,
policy,
&param),
result),
int, -1);
# elif defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_setprio (ht_id, priority),
result),
int, -1);
# elif defined (ACE_HAS_WTHREADS)
# if defined (ACE_HAS_WINCE) && !defined (ACE_LACKS_CE_THREAD_PRIORITY)
ACE_WIN32CALL_RETURN (ACE_ADAPT_RETVAL (::CeSetThreadPriority (ht_id, priority),
ace_result_),
int, -1);
# else
ACE_WIN32CALL_RETURN (ACE_ADAPT_RETVAL (::SetThreadPriority (ht_id, priority),
ace_result_),
int, -1);
# endif /* defined (ACE_HAS_WINCE) && !defined (ACE_LACKS_CE_THREAD_PRIORITY) */
# elif defined (ACE_HAS_VXTHREADS)
ACE_OSCALL_RETURN (::taskPrioritySet (ht_id, priority), int, -1);
# else
// For example, platforms that support Pthreads but LACK_SETSCHED.
ACE_UNUSED_ARG (ht_id);
ACE_UNUSED_ARG (priority);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_STHREADS */
#else
ACE_UNUSED_ARG (ht_id);
ACE_UNUSED_ARG (priority);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::thr_sigsetmask (int how,
const sigset_t *nsm,
sigset_t *osm)
{
ACE_OS_TRACE ("ACE_OS::thr_sigsetmask");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_LACKS_PTHREAD_THR_SIGSETMASK)
// DCE threads and Solaris 2.4 have no such function.
ACE_UNUSED_ARG (osm);
ACE_UNUSED_ARG (nsm);
ACE_UNUSED_ARG (how);
ACE_NOTSUP_RETURN (-1);
# elif defined (ACE_HAS_SIGTHREADMASK)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::sigthreadmask (how, nsm, osm),
result), int, -1);
# elif defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_sigsetmask (how, nsm, osm),
result),
int, -1);
# elif defined (ACE_HAS_PTHREADS)
# if !defined (ACE_LACKS_PTHREAD_SIGMASK)
int result;
//FUZZ: disable check_for_lack_ACE_OS
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::pthread_sigmask (how, nsm, osm),
result), int, -1);
//FUZZ: enable check_for_lack_ACE_OS
# endif /* !ACE_LACKS_PTHREAD_SIGMASK */
# elif defined (ACE_HAS_WTHREADS)
ACE_UNUSED_ARG (osm);
ACE_UNUSED_ARG (nsm);
ACE_UNUSED_ARG (how);
ACE_NOTSUP_RETURN (-1);
# elif defined (ACE_VXWORKS)
int old_mask = 0;
switch (how)
{
case SIG_BLOCK:
case SIG_UNBLOCK:
{
// get the old mask
old_mask = ::sigsetmask (*nsm);
// create a new mask: the following assumes that sigset_t is 4 bytes,
// which it is on VxWorks 5.2, so bit operations are done simply . . .
::sigsetmask (how == SIG_BLOCK ? (old_mask |= *nsm) : (old_mask &= ~*nsm));
if (osm)
*osm = old_mask;
break;
}
case SIG_SETMASK:
old_mask = ::sigsetmask (*nsm);
if (osm)
*osm = old_mask;
break;
default:
return -1;
}
return 0;
# else /* Should not happen. */
ACE_UNUSED_ARG (how);
ACE_UNUSED_ARG (nsm);
ACE_UNUSED_ARG (osm);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_LACKS_PTHREAD_THR_SIGSETMASK */
#else
ACE_UNUSED_ARG (how);
ACE_UNUSED_ARG (nsm);
ACE_UNUSED_ARG (osm);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::thr_suspend (ACE_hthread_t target_thread)
{
ACE_OS_TRACE ("ACE_OS::thr_suspend");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_STHREADS)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (::thr_suspend (target_thread), result), int, -1);
# elif defined (ACE_HAS_PTHREADS)
# if defined (ACE_HAS_PTHREAD_SUSPEND)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_suspend (target_thread),
result),
int, -1);
# elif defined (ACE_HAS_PTHREAD_SUSPEND_NP)
int result;
ACE_OSCALL_RETURN (ACE_ADAPT_RETVAL (pthread_suspend_np (target_thread),
result),
int, -1);
# else
ACE_UNUSED_ARG (target_thread);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_PTHREAD_SUSPEND */
# elif defined (ACE_HAS_WTHREADS)
if (::SuspendThread (target_thread) != ACE_SYSCALL_FAILED)
return 0;
else
ACE_FAIL_RETURN (-1);
/* NOTREACHED */
# elif defined (ACE_HAS_VXTHREADS)
ACE_OSCALL_RETURN (::taskSuspend (target_thread), int, -1);
# endif /* ACE_HAS_STHREADS */
#else
ACE_UNUSED_ARG (target_thread);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE void
ACE_OS::thr_testcancel (void)
{
ACE_OS_TRACE ("ACE_OS::thr_testcancel");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_PTHREADS) && !defined (ACE_LACKS_PTHREAD_CANCEL)
pthread_testcancel ();
# elif defined (ACE_HAS_STHREADS)
# elif defined (ACE_HAS_WTHREADS)
# elif defined (ACE_HAS_VXTHREADS)
# else
// no-op: can't use ACE_NOTSUP_RETURN because there is no return value
# endif /* ACE_HAS_PTHREADS */
#else
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE void
ACE_OS::thr_yield (void)
{
ACE_OS_TRACE ("ACE_OS::thr_yield");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_PTHREADS)
::sched_yield ();
# elif defined (ACE_HAS_STHREADS)
::thr_yield ();
# elif defined (ACE_HAS_WTHREADS)
::Sleep (0);
# elif defined (ACE_HAS_VXTHREADS)
// An argument of 0 to ::taskDelay doesn't appear to yield the
// current thread.
// Now, it does seem to work. The context_switch_time test
// works fine with task_delay set to 0.
::taskDelay (0);
# endif /* ACE_HAS_STHREADS */
#else
;
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::thread_mutex_destroy (ACE_thread_mutex_t *m)
{
ACE_OS_TRACE ("ACE_OS::thread_mutex_destroy");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_WTHREADS)
::DeleteCriticalSection (m);
return 0;
# else
return ACE_OS::mutex_destroy (m);
# endif /* ACE_HAS_WTHREADS */
#else
ACE_UNUSED_ARG (m);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::thread_mutex_init (ACE_thread_mutex_t *m,
int lock_type,
const char *name,
ACE_mutexattr_t *arg)
{
// ACE_OS_TRACE ("ACE_OS::thread_mutex_init");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_WTHREADS)
ACE_UNUSED_ARG (lock_type);
ACE_UNUSED_ARG (name);
ACE_UNUSED_ARG (arg);
ACE_SEH_TRY
{
::InitializeCriticalSection (m);
}
ACE_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
errno = ENOMEM;
return -1;
}
return 0;
# elif defined (ACE_HAS_STHREADS) || defined (ACE_HAS_PTHREADS)
// Force the use of USYNC_THREAD!
return ACE_OS::mutex_init (m, USYNC_THREAD, name, arg, 0, lock_type);
# elif defined (ACE_HAS_VXTHREADS)
return mutex_init (m, lock_type, name, arg);
# endif /* ACE_HAS_STHREADS || ACE_HAS_PTHREADS */
#else
ACE_UNUSED_ARG (m);
ACE_UNUSED_ARG (lock_type);
ACE_UNUSED_ARG (name);
ACE_UNUSED_ARG (arg);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
#if defined (ACE_HAS_WCHAR)
ACE_INLINE int
ACE_OS::thread_mutex_init (ACE_thread_mutex_t *m,
int lock_type,
const wchar_t *name,
ACE_mutexattr_t *arg)
{
// ACE_OS_TRACE ("ACE_OS::thread_mutex_init");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_WTHREADS)
ACE_UNUSED_ARG (lock_type);
ACE_UNUSED_ARG (name);
ACE_UNUSED_ARG (arg);
ACE_SEH_TRY
{
::InitializeCriticalSection (m);
}
ACE_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
errno = ENOMEM;
return -1;
}
return 0;
# elif defined (ACE_HAS_STHREADS) || defined (ACE_HAS_PTHREADS)
// Force the use of USYNC_THREAD!
return ACE_OS::mutex_init (m, USYNC_THREAD, name, arg, 0, lock_type);
# elif defined (ACE_HAS_VXTHREADS)
return mutex_init (m, lock_type, name, arg);
# endif /* ACE_HAS_STHREADS || ACE_HAS_PTHREADS */
#else
ACE_UNUSED_ARG (m);
ACE_UNUSED_ARG (lock_type);
ACE_UNUSED_ARG (name);
ACE_UNUSED_ARG (arg);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
#endif /* ACE_HAS_WCHAR */
ACE_INLINE int
ACE_OS::thread_mutex_lock (ACE_thread_mutex_t *m)
{
// ACE_OS_TRACE ("ACE_OS::thread_mutex_lock");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_WTHREADS)
::EnterCriticalSection (m);
return 0;
# else
return ACE_OS::mutex_lock (m);
# endif /* ACE_HAS_WTHREADS */
#else
ACE_UNUSED_ARG (m);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::thread_mutex_lock (ACE_thread_mutex_t *m,
const ACE_Time_Value &timeout)
{
// ACE_OS_TRACE ("ACE_OS::thread_mutex_lock");
// For all platforms, except MS Windows, this method is equivalent
// to calling ACE_OS::mutex_lock() since ACE_thread_mutex_t and
// ACE_mutex_t are the same type. However, those typedefs evaluate
// to different types on MS Windows. The "thread mutex"
// implementation in ACE for MS Windows cannot readily support
// timeouts due to a lack of timeout features for this type of MS
// Windows synchronization mechanism.
#if defined (ACE_HAS_THREADS) && !defined (ACE_HAS_WTHREADS)
return ACE_OS::mutex_lock (m, timeout);
#else
ACE_UNUSED_ARG (m);
ACE_UNUSED_ARG (timeout);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::thread_mutex_lock (ACE_thread_mutex_t *m,
const ACE_Time_Value *timeout)
{
return timeout == 0
? ACE_OS::thread_mutex_lock (m)
: ACE_OS::thread_mutex_lock (m, *timeout);
}
ACE_INLINE int
ACE_OS::thread_mutex_trylock (ACE_thread_mutex_t *m)
{
ACE_OS_TRACE ("ACE_OS::thread_mutex_trylock");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_WTHREADS)
# if defined (ACE_HAS_WIN32_TRYLOCK)
BOOL result = ::TryEnterCriticalSection (m);
if (result == TRUE)
{
return 0;
}
else
{
errno = EBUSY;
return -1;
}
# else
ACE_UNUSED_ARG (m);
ACE_NOTSUP_RETURN (-1);
# endif /* ACE_HAS_WIN32_TRYLOCK */
# elif defined (ACE_HAS_STHREADS) || defined (ACE_HAS_PTHREADS) || defined (ACE_VXWORKS)
return ACE_OS::mutex_trylock (m);
#endif /* Threads variety case */
#else
ACE_UNUSED_ARG (m);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
ACE_INLINE int
ACE_OS::thread_mutex_unlock (ACE_thread_mutex_t *m)
{
ACE_OS_TRACE ("ACE_OS::thread_mutex_unlock");
#if defined (ACE_HAS_THREADS)
# if defined (ACE_HAS_WTHREADS)
::LeaveCriticalSection (m);
return 0;
# else
return ACE_OS::mutex_unlock (m);
# endif /* ACE_HAS_WTHREADS */
#else
ACE_UNUSED_ARG (m);
ACE_NOTSUP_RETURN (-1);
#endif /* ACE_HAS_THREADS */
}
/*****************************************************************************/
# if defined (ACE_IS_SPLITTING)
# define ACE_SPECIAL_INLINE
# else
# define ACE_SPECIAL_INLINE ACE_INLINE
//# define ACE_SPECIAL_INLINE inline
# endif
#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
ACE_INLINE
int
ACE_OS_Thread_Mutex_Guard::acquire (void)
{
return owner_ = ACE_OS::thread_mutex_lock (&lock_);
}
ACE_INLINE
int
ACE_OS_Thread_Mutex_Guard::release (void)
{
if (owner_ == -1)
return 0;
else
{
owner_ = -1;
return ACE_OS::thread_mutex_unlock (&lock_);
}
}
ACE_INLINE
ACE_OS_Thread_Mutex_Guard::ACE_OS_Thread_Mutex_Guard (ACE_thread_mutex_t &m)
: lock_ (m), owner_ (-1)
{
if (!ACE_OS_Object_Manager::starting_up ())
acquire ();
}
ACE_INLINE
ACE_OS_Thread_Mutex_Guard::~ACE_OS_Thread_Mutex_Guard ()
{
release ();
}
/*****************************************************************************/
ACE_INLINE
int
ACE_OS_Recursive_Thread_Mutex_Guard::acquire (void)
{
return owner_ = ACE_OS::recursive_mutex_lock (&lock_);
}
ACE_INLINE
int
ACE_OS_Recursive_Thread_Mutex_Guard::release (void)
{
if (owner_ == -1)
return 0;
else
{
owner_ = -1;
return ACE_OS::recursive_mutex_unlock (&lock_);
}
}
ACE_INLINE
ACE_OS_Recursive_Thread_Mutex_Guard::ACE_OS_Recursive_Thread_Mutex_Guard (
ACE_recursive_thread_mutex_t &m)
: lock_ (m),
owner_ (-1)
{
if (!ACE_OS_Object_Manager::starting_up ())
acquire ();
}
ACE_INLINE
ACE_OS_Recursive_Thread_Mutex_Guard::~ACE_OS_Recursive_Thread_Mutex_Guard ()
{
release ();
}
#endif /* ACE_MT_SAFE && ACE_MT_SAFE != 0 */
/*****************************************************************************/
ACE_INLINE
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_INLINE
ACE_Thread_ID::ACE_Thread_ID (const ACE_Thread_ID &id)
: thread_id_ (id.thread_id_),
thread_handle_ (id.thread_handle_)
{
}
ACE_INLINE
ACE_Thread_ID&
ACE_Thread_ID::operator= (const ACE_Thread_ID &id)
{
if (this != &id)
{
this->thread_id_ = id.thread_id_;
this->thread_handle_ = id.thread_handle_;
}
return *this;
}
ACE_INLINE
ACE_Thread_ID::ACE_Thread_ID (void)
: thread_id_ (ACE_OS::thr_self ())
{
ACE_OS::thr_self (thread_handle_);
}
ACE_INLINE
ACE_thread_t
ACE_Thread_ID::id (void) const
{
return this->thread_id_;
}
ACE_INLINE void
ACE_Thread_ID::id (ACE_thread_t thread_id)
{
this->thread_id_ = thread_id;
}
ACE_INLINE ACE_hthread_t
ACE_Thread_ID::handle (void) const
{
return this->thread_handle_;
}
ACE_INLINE void
ACE_Thread_ID::handle (ACE_hthread_t thread_handle)
{
this->thread_handle_ = thread_handle;
}
ACE_INLINE bool
ACE_Thread_ID::operator== (const ACE_Thread_ID &rhs) const
{
return
ACE_OS::thr_cmp (this->thread_handle_, rhs.thread_handle_)
&& ACE_OS::thr_equal (this->thread_id_, rhs.thread_id_);
}
ACE_INLINE bool
ACE_Thread_ID::operator!= (const ACE_Thread_ID &rhs) const
{
return !(*this == rhs);
}
#if !defined (ACE_WIN32)
ACE_INLINE
ACE_event_t::ACE_event_t (void) :
name_ (0),
eventdata_ (0)
{
}
#endif /* !ACE_WIN32 */
ACE_END_VERSIONED_NAMESPACE_DECL