2
0
mirror of https://github.com/boostorg/sync.git synced 2026-01-19 04:42:12 +00:00

Made timed_mutex incompatible with condition variable when mutex_timedwait is not available. The test had to be disabled for now because it requires condition_variable_any.

[SVN r86367]
This commit is contained in:
Andrey Semashev
2013-10-20 13:54:27 +00:00
parent aee4acc3ae
commit eb00dacf07
10 changed files with 85 additions and 82 deletions

View File

@@ -75,13 +75,13 @@ public:
{
int const res = pthread_cond_init(&m_cond, NULL);
if (res)
BOOST_SYNC_DETAIL_THROW(resource_error, (res)("boost::sync::condition_variable constructor failed in pthread_cond_init"));
BOOST_SYNC_DETAIL_THROW(resource_error, (res)("condition_variable constructor failed in pthread_cond_init"));
}
#endif // defined(PTHREAD_COND_INITIALIZER)
~condition_variable()
{
BOOST_VERIFY(::pthread_cond_destroy(&m_cond) == 0);
BOOST_VERIFY(sync::detail::posix::pthread_cond_destroy(&m_cond) == 0);
}
void notify_one() BOOST_NOEXCEPT
@@ -205,7 +205,7 @@ private:
{
int const res = sync::detail::posix::pthread_cond_wait(&m_cond, mtx);
if (res != 0)
BOOST_SYNC_DETAIL_THROW(wait_error, (res)("boost::sync::condition_variable::wait failed in pthread_cond_wait"));
BOOST_SYNC_DETAIL_THROW(wait_error, (res)("condition_variable::wait failed in pthread_cond_wait"));
}
template< typename Mutex >
@@ -221,7 +221,7 @@ private:
if (res == ETIMEDOUT)
return sync::cv_status::timeout;
else if (res != 0)
BOOST_SYNC_DETAIL_THROW(wait_error, (res)("boost::sync::condition_variable timedwait failed in pthread_cond_timedwait"));
BOOST_SYNC_DETAIL_THROW(wait_error, (res)("condition_variable::timed_wait failed in pthread_cond_timedwait"));
return sync::cv_status::no_timeout;
}

View File

@@ -171,7 +171,7 @@ private:
again:
sync::detail::system_duration::native_type time_left = (abs_timeout - sync::detail::system_time_point::now()).get();
if (time_left <= 0)
goto timeout;
return on_wait_timed_out();
const int status = sync::detail::linux_::futex_timedwait(reinterpret_cast< int* >(&m_state), old_state, time_left);
if (status != 0)
{
@@ -179,8 +179,7 @@ private:
switch (err)
{
case ETIMEDOUT:
old_state = m_state.load(detail::atomic_ns::memory_order_acquire);
goto timeout;
return on_wait_timed_out();
case EINTR: // signal received
goto again;
@@ -205,26 +204,6 @@ private:
}
return true;
timeout:
while (true)
{
const unsigned int posts = old_state >> post_count_lowest_bit;
if (posts == 0)
{
// Remove one waiter
if (m_state.compare_exchange_weak(old_state, old_state - 1u, detail::atomic_ns::memory_order_acquire, detail::atomic_ns::memory_order_release))
return false;
}
else
{
// Remove one post and one waiter from the counters
if (m_state.compare_exchange_weak(old_state, old_state - (post_count_one + 1u), detail::atomic_ns::memory_order_acquire, detail::atomic_ns::memory_order_release))
return true;
}
detail::pause();
}
}
bool priv_timed_wait(sync::detail::system_duration dur)
@@ -252,26 +231,7 @@ private:
switch (err)
{
case ETIMEDOUT:
old_state = m_state.load(detail::atomic_ns::memory_order_acquire);
while (true)
{
posts = old_state >> post_count_lowest_bit;
if (posts == 0)
{
// Remove one waiter
if (m_state.compare_exchange_weak(old_state, old_state - 1u, detail::atomic_ns::memory_order_acquire, detail::atomic_ns::memory_order_release))
return false;
}
else
{
// Remove one post and one waiter from the counters
if (m_state.compare_exchange_weak(old_state, old_state - (post_count_one + 1u), detail::atomic_ns::memory_order_acquire, detail::atomic_ns::memory_order_release))
return true;
}
detail::pause();
}
break;
return on_wait_timed_out();
case EINTR: // signal received
goto again;
@@ -316,6 +276,29 @@ private:
return false;
}
bool on_wait_timed_out()
{
unsigned int old_state = m_state.load(detail::atomic_ns::memory_order_acquire);
while (true)
{
unsigned int posts = old_state >> post_count_lowest_bit;
if (posts == 0)
{
// Remove one waiter
if (m_state.compare_exchange_weak(old_state, old_state - 1u, detail::atomic_ns::memory_order_acquire, detail::atomic_ns::memory_order_release))
return false;
}
else
{
// Remove one post and one waiter from the counters
if (m_state.compare_exchange_weak(old_state, old_state - (post_count_one + 1u), detail::atomic_ns::memory_order_acquire, detail::atomic_ns::memory_order_release))
return true;
}
detail::pause();
}
}
private:
BOOST_STATIC_ASSERT_MSG(sizeof(detail::atomic_ns::atomic< unsigned int >) == sizeof(int), "Boost.Sync: unexpected size of atomic< unsigned int >");
detail::atomic_ns::atomic< unsigned int > m_state;

View File

@@ -111,7 +111,6 @@ private:
// Check that system time resolution is nanoseconds
BOOST_STATIC_ASSERT(sync::detail::system_duration::subsecond_fraction == 1000000000u);
// Note that futex timeout must be relative
const int status = sync::detail::linux_::futex_timedwait(reinterpret_cast< int* >(&m_state), 0, time_left);
if (status == 0)
break;
@@ -145,7 +144,6 @@ private:
BOOST_STATIC_ASSERT(sync::detail::system_duration::subsecond_fraction == 1000000000u);
do
{
// Note that futex timeout must be relative
const int status = sync::detail::linux_::futex_timedwait(reinterpret_cast< int* >(&m_state), 0, time_left);
if (status == 0)
break;

View File

@@ -17,6 +17,7 @@
#ifndef BOOST_SYNC_DETAIL_MUTEXES_TIMED_MUTEX_POSIX_HPP_INCLUDED_
#define BOOST_SYNC_DETAIL_MUTEXES_TIMED_MUTEX_POSIX_HPP_INCLUDED_
#include <errno.h>
#include <cstddef>
#include <boost/assert.hpp>
#include <boost/utility/enable_if.hpp>
@@ -47,7 +48,9 @@ BOOST_SYNC_DETAIL_OPEN_ABI_NAMESPACE {
class timed_mutex
{
public:
#if defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK)
typedef void _is_condition_variable_compatible;
#endif
typedef pthread_mutex_t* native_handle_type;
@@ -91,12 +94,12 @@ public:
{
int const res = pthread_mutex_init(&m_mutex, NULL);
if (res)
BOOST_SYNC_DETAIL_THROW(resource_error, (res)("boost:: timed_mutex constructor failed in pthread_mutex_init"));
BOOST_SYNC_DETAIL_THROW(resource_error, (res)("timed_mutex constructor failed in pthread_mutex_init"));
#if !defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK)
int const res2 = pthread_cond_init(&m_cond, NULL);
if (res2)
BOOST_SYNC_DETAIL_THROW(resource_error, (res2)("boost:: timed_mutex constructor failed in pthread_cond_init"));
BOOST_SYNC_DETAIL_THROW(resource_error, (res2)("timed_mutex constructor failed in pthread_cond_init"));
m_is_locked = false;
#endif
}
@@ -106,7 +109,7 @@ public:
{
BOOST_VERIFY(sync::detail::posix::pthread_mutex_destroy(&m_mutex) == 0);
#if !defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK)
BOOST_VERIFY(::pthread_cond_destroy(&m_cond) == 0);
BOOST_VERIFY(sync::detail::posix::pthread_cond_destroy(&m_cond) == 0);
#endif
}
@@ -116,7 +119,7 @@ public:
{
int const res = sync::detail::posix::pthread_mutex_lock(&m_mutex);
if (res)
BOOST_SYNC_DETAIL_THROW(lock_error, (res)("boost: timed_mutex lock failed in pthread_mutex_lock"));
BOOST_SYNC_DETAIL_THROW(lock_error, (res)("timed_mutex lock failed in pthread_mutex_lock"));
}
void unlock() BOOST_NOEXCEPT
@@ -131,7 +134,7 @@ public:
if (res == 0)
return true;
else if (res != EBUSY)
BOOST_SYNC_DETAIL_THROW(lock_error, (res)("boost: timed_mutex trylock failed in pthread_mutex_trylock"));
BOOST_SYNC_DETAIL_THROW(lock_error, (res)("timed_mutex try_lock failed in pthread_mutex_trylock"));
return false;
}
@@ -206,7 +209,7 @@ private:
if (res == 0)
return true;
else if (res != ETIMEDOUT)
BOOST_SYNC_DETAIL_THROW(lock_error, (res)("boost: timed_mutex timedlock failed in pthread_mutex_timedlock"));
BOOST_SYNC_DETAIL_THROW(lock_error, (res)("timed_mutex timed_lock failed in pthread_mutex_timedlock"));
return false;
#else // defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK)
@@ -216,9 +219,16 @@ private:
{
int const cond_res = sync::detail::posix::pthread_cond_timedwait(&m_cond, &m_mutex, &t.get());
if (cond_res == ETIMEDOUT)
return false;
{
if (!m_is_locked)
break;
else
return false;
}
else if (cond_res != 0)
BOOST_SYNC_DETAIL_THROW(lock_error, (cond_res)("boost: timed_mutex timedlock failed in pthread_cond_timedwait"));
{
BOOST_SYNC_DETAIL_THROW(lock_error, (cond_res)("timed_mutex timed_lock failed in pthread_cond_timedwait"));
}
}
m_is_locked = true;
return true;

View File

@@ -122,7 +122,7 @@ private:
if (!boost::detail::winapi::SetWaitableTimer(handles[1], reinterpret_cast< const boost::detail::winapi::LARGE_INTEGER_* >(&t.get()), 0, NULL, NULL, false))
{
const boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError();
BOOST_SYNC_DETAIL_THROW(lock_error, (err)("timed_mutex::timedlock failed to set a timeout"));
BOOST_SYNC_DETAIL_THROW(lock_error, (err)("timed_mutex::timed_lock failed to set a timeout"));
}
while (true)
@@ -131,7 +131,7 @@ private:
if (res == boost::detail::winapi::wait_failed)
{
const boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError();
BOOST_SYNC_DETAIL_THROW(lock_error, (err)("timed_mutex::timedlock failed in WaitForMultipleObjects"));
BOOST_SYNC_DETAIL_THROW(lock_error, (err)("timed_mutex::timed_lock failed in WaitForMultipleObjects"));
}
switch (res)
@@ -189,7 +189,7 @@ private:
default:
{
const boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError();
BOOST_SYNC_DETAIL_THROW(lock_error, (err)("timed_mutex::timedlock failed in WaitForSingleObject"));
BOOST_SYNC_DETAIL_THROW(lock_error, (err)("timed_mutex::timed_lock failed in WaitForSingleObject"));
}
}
}

View File

@@ -53,6 +53,7 @@ using ::pthread_mutex_trylock;
using ::pthread_mutex_timedlock;
#endif
using ::pthread_mutex_unlock;
using ::pthread_cond_destroy;
using ::pthread_cond_wait;
using ::pthread_cond_timedwait;
@@ -60,7 +61,7 @@ using ::pthread_cond_timedwait;
// Workaround for https://svn.boost.org/trac/boost/ticket/6200
BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m)
BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m) BOOST_NOEXCEPT
{
int ret;
do
@@ -71,7 +72,7 @@ BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m)
return ret;
}
BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m)
BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m) BOOST_NOEXCEPT
{
int ret;
do
@@ -82,7 +83,7 @@ BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m)
return ret;
}
BOOST_FORCEINLINE int pthread_mutex_trylock(pthread_mutex_t* m)
BOOST_FORCEINLINE int pthread_mutex_trylock(pthread_mutex_t* m) BOOST_NOEXCEPT
{
int ret;
do
@@ -94,7 +95,7 @@ BOOST_FORCEINLINE int pthread_mutex_trylock(pthread_mutex_t* m)
}
#if defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK)
BOOST_FORCEINLINE int pthread_mutex_timedlock(pthread_mutex_t* m, const struct ::timespec* t)
BOOST_FORCEINLINE int pthread_mutex_timedlock(pthread_mutex_t* m, const struct ::timespec* t) BOOST_NOEXCEPT
{
int ret;
do
@@ -106,7 +107,7 @@ BOOST_FORCEINLINE int pthread_mutex_timedlock(pthread_mutex_t* m, const struct :
}
#endif
BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m)
BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m) BOOST_NOEXCEPT
{
int ret;
do
@@ -117,7 +118,18 @@ BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m)
return ret;
}
BOOST_FORCEINLINE int pthread_cond_wait(pthread_cond_t* c, pthread_mutex_t* m)
BOOST_FORCEINLINE int pthread_cond_destroy(pthread_cond_t* c) BOOST_NOEXCEPT
{
int ret;
do
{
ret = ::pthread_cond_destroy(c);
}
while (ret == EINTR);
return ret;
}
BOOST_FORCEINLINE int pthread_cond_wait(pthread_cond_t* c, pthread_mutex_t* m) BOOST_NOEXCEPT
{
int ret;
do
@@ -128,7 +140,7 @@ BOOST_FORCEINLINE int pthread_cond_wait(pthread_cond_t* c, pthread_mutex_t* m)
return ret;
}
BOOST_FORCEINLINE int pthread_cond_timedwait(pthread_cond_t* c, pthread_mutex_t* m, const struct ::timespec* t)
BOOST_FORCEINLINE int pthread_cond_timedwait(pthread_cond_t* c, pthread_mutex_t* m, const struct ::timespec* t) BOOST_NOEXCEPT
{
int ret;
do

View File

@@ -40,12 +40,12 @@ class pthread_mutex_lock_guard
public:
explicit pthread_mutex_lock_guard(pthread_mutex_t& m) BOOST_NOEXCEPT : m_mutex(&m)
{
BOOST_VERIFY(pthread_mutex_lock(m_mutex) == 0);
BOOST_VERIFY(sync::detail::posix::pthread_mutex_lock(m_mutex) == 0);
}
~pthread_mutex_lock_guard()
{
BOOST_VERIFY(pthread_mutex_unlock(m_mutex) == 0);
BOOST_VERIFY(sync::detail::posix::pthread_mutex_unlock(m_mutex) == 0);
}
BOOST_DELETED_FUNCTION(pthread_mutex_lock_guard(pthread_mutex_lock_guard const&))
@@ -59,12 +59,12 @@ class pthread_mutex_unlock_guard
public:
explicit pthread_mutex_unlock_guard(pthread_mutex_t& m) BOOST_NOEXCEPT : m_mutex(&m)
{
BOOST_VERIFY(pthread_mutex_unlock(m_mutex) == 0);
BOOST_VERIFY(sync::detail::posix::pthread_mutex_unlock(m_mutex) == 0);
}
~pthread_mutex_unlock_guard()
{
BOOST_VERIFY(pthread_mutex_lock(m_mutex) == 0);
BOOST_VERIFY(sync::detail::posix::pthread_mutex_lock(m_mutex) == 0);
}
BOOST_DELETED_FUNCTION(pthread_mutex_unlock_guard(pthread_mutex_unlock_guard const&))

View File

@@ -97,21 +97,21 @@ public:
sync::detail::system_duration::native_type time_left = dur.get();
if (time_left < 0)
time_left = 0;
sync::detail::system_duration::native_type time_left_sec = time_left / system_duration::subsecond_fraction;
sync::detail::system_duration::native_type time_left_subsec = time_left % system_duration::subsecond_fraction;
sync::detail::system_duration::native_type time_left_sec = time_left / sync::detail::system_duration::subsecond_fraction;
sync::detail::system_duration::native_type time_left_subsec = time_left % sync::detail::system_duration::subsecond_fraction;
enum
{
nanoseconds_fraction = 1000000000u,
conversion_ratio = static_cast< uint64_t >(nanoseconds_fraction) >= system_duration::subsecond_fraction ?
nanoseconds_fraction / system_duration::subsecond_fraction :
system_duration::subsecond_fraction / nanoseconds_fraction
conversion_ratio = static_cast< uint64_t >(nanoseconds_fraction) >= sync::detail::system_duration::subsecond_fraction ?
nanoseconds_fraction / sync::detail::system_duration::subsecond_fraction :
sync::detail::system_duration::subsecond_fraction / nanoseconds_fraction
};
const mach_timespec_t wait_time =
{
time_left_sec,
static_cast< uint64_t >(nanoseconds_fraction) >= system_duration::subsecond_fraction ?
static_cast< uint64_t >(nanoseconds_fraction) >= sync::detail::system_duration::subsecond_fraction ?
time_left_subsec / conversion_ratio : time_left_subsec * conversion_ratio
};

View File

@@ -284,6 +284,7 @@ BOOST_AUTO_TEST_CASE(test_try_mutex)
timed_test(&do_test_try_mutex, 3);
}
/*
void do_test_timed_mutex()
{
test_lock<boost::sync::timed_mutex>()();
@@ -296,7 +297,6 @@ BOOST_AUTO_TEST_CASE(test_timed_mutex)
timed_test(&do_test_timed_mutex, 3);
}
/*
void do_test_recursive_mutex()
{
test_lock<boost::recursive_mutex>()();

View File

@@ -2,7 +2,7 @@
// William E. Kempf
// Copyright (C) 2007-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_SYNC_LIBS_TEST_UTILS_HPP_INCLUDED_
@@ -150,7 +150,7 @@ private:
}
// boostinspect:nounnamed
namespace
namespace
{
template <typename F>
@@ -191,7 +191,7 @@ private:
}
// boostinspect:nounnamed
namespace
namespace
{
template <typename F, typename T>
inline thread_detail_anon::thread_binder<F, T> bind(const F& func, const T& param)
@@ -226,7 +226,7 @@ private:
}
// boostinspect:nounnamed
namespace
namespace
{
template <typename R, typename T>
inline thread_detail_anon::thread_member_binder<R, T> bind(R (T::*func)(), T& param)