|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r86326 - in trunk: boost/sync boost/sync/detail/semaphore boost/sync/exceptions boost/sync/support libs/sync/test/run
From: andrey.semashev_at_[hidden]
Date: 2013-10-15 12:49:34
Author: andysem
Date: 2013-10-15 12:49:34 EDT (Tue, 15 Oct 2013)
New Revision: 86326
URL: http://svn.boost.org/trac/boost/changeset/86326
Log:
Ported semaphore implementation to the time units abstraction layer.
Added:
trunk/boost/sync/exceptions/overflow_error.hpp (contents, props changed)
Text files modified:
trunk/boost/sync/detail/semaphore/semaphore_dispatch.hpp | 94 ++++++++++++++---------
trunk/boost/sync/detail/semaphore/semaphore_emulation.hpp | 75 +++++++++---------
trunk/boost/sync/detail/semaphore/semaphore_mach.hpp | 143 ++++++++++++++++++++++++++++--------
trunk/boost/sync/detail/semaphore/semaphore_posix.hpp | 77 ++++++++++---------
trunk/boost/sync/detail/semaphore/semaphore_windows.hpp | 155 +++++++++++++++++++++++++++------------
trunk/boost/sync/exceptions.hpp | 1
trunk/boost/sync/exceptions/overflow_error.hpp | 58 ++++++++++++++
trunk/boost/sync/support/boost_date_time.hpp | 5 +
trunk/libs/sync/test/run/semaphore_test.cpp | 138 ++++++++++++++++++++++++++++++++---
9 files changed, 542 insertions(+), 204 deletions(-)
Modified: trunk/boost/sync/detail/semaphore/semaphore_dispatch.hpp
==============================================================================
--- trunk/boost/sync/detail/semaphore/semaphore_dispatch.hpp Tue Oct 15 12:40:51 2013 (r86325)
+++ trunk/boost/sync/detail/semaphore/semaphore_dispatch.hpp 2013-10-15 12:49:34 EDT (Tue, 15 Oct 2013) (r86326)
@@ -9,19 +9,18 @@
#ifndef BOOST_SYNC_DETAIL_SEMAPHORE_SEMAPHORE_DISPATCH_HPP_INCLUDED_
#define BOOST_SYNC_DETAIL_SEMAPHORE_SEMAPHORE_DISPATCH_HPP_INCLUDED_
+#include <time.h>
#include <cstddef>
#include <dispatch/dispatch.h>
+#include <boost/cstddef.hpp>
+#include <boost/utility/enable_if.hpp>
#include <boost/sync/detail/config.hpp>
+#include <boost/sync/detail/time_traits.hpp>
+#include <boost/sync/detail/time_units.hpp>
#include <boost/sync/detail/throw_exception.hpp>
#include <boost/sync/detail/system_error.hpp>
#include <boost/sync/exceptions/resource_error.hpp>
-
-#ifdef BOOST_SYNC_USES_CHRONO
-#include <boost/chrono/system_clocks.hpp>
-#include <boost/chrono/ceil.hpp>
-#endif
-
#include <boost/sync/detail/header.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
@@ -47,66 +46,89 @@
BOOST_SYNC_DETAIL_THROW(resource_error, (sync::detail::system_ns::errc::not_enough_memory)("boost::sync::semaphore constructor failed in dispatch_semaphore_create"));
}
- ~semaphore() BOOST_NOEXCEPT
+ ~semaphore()
{
dispatch_release(m_sem);
}
- void post() BOOST_NOEXCEPT
+ void post()
{
dispatch_semaphore_signal(m_sem);
}
- void wait() BOOST_NOEXCEPT
+ void wait()
{
dispatch_semaphore_wait(m_sem, DISPATCH_TIME_FOREVER);
}
- bool try_wait(void) BOOST_NOEXCEPT
+ bool try_wait()
{
- const long status = dispatch_semaphore_wait(m_sem, DISPATCH_TIME_NOW);
- return status == 0;
+ return dispatch_semaphore_wait(m_sem, DISPATCH_TIME_NOW) == 0;
}
-#ifdef BOOST_SYNC_USES_CHRONO
- template <class Rep, class Period>
- bool try_wait_for(const chrono::duration<Rep, Period> & rel_time) BOOST_NOEXCEPT
+ template< typename Time >
+ typename enable_if_c< sync::detail::time_traits< Time >::is_specialized, bool >::type timed_wait(Time const& t)
{
- return try_wait_until(chrono::steady_clock::now() + rel_time);
+ return priv_timed_wait(sync::detail::time_traits< Time >::to_sync_unit(t));
}
- template <class Clock, class Duration>
- bool try_wait_until(const chrono::time_point<Clock, Duration> & timeout ) BOOST_NOEXCEPT
+ template< typename Duration >
+ typename enable_if< detail::is_time_tag_of< Duration, detail::time_duration_tag >, bool >::type wait_for(Duration const& duration)
{
- using namespace chrono;
- system_clock::time_point s_now = system_clock::now();
- typename Clock::time_point c_now = Clock::now();
- return try_wait_until(s_now + ceil<nanoseconds>(timeout - c_now));
+ return priv_timed_wait(sync::detail::time_traits< Duration >::to_sync_unit(duration));
}
- template <class Duration>
- bool try_wait_until(const chrono::time_point<chrono::system_clock, Duration>& t) BOOST_NOEXCEPT
+ template< typename TimePoint >
+ typename enable_if< detail::is_time_tag_of< TimePoint, detail::time_point_tag >, bool >::type wait_until(TimePoint const& abs_time)
{
- using namespace chrono;
- typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
- return try_wait_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
+ return priv_timed_wait(sync::detail::time_traits< TimePoint >::to_sync_unit(abs_time));
}
- bool try_wait_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp) BOOST_NOEXCEPT
+private:
+ bool priv_timed_wait(sync::detail::system_duration dur)
{
- chrono::nanoseconds d = tp.time_since_epoch();
- timespec ts = boost::detail::to_timespec(d);
- return do_wait_lock_until(dispatch_walltime(&ts, 0));
+ dispatch_time_t timeout = DISPATCH_TIME_NOW;
+
+ sync::detail::system_duration::native_type time_left = dur.get();
+ if (time_left > 0)
+ {
+ 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
+ };
+
+ const int64_t nanoseconds_left = static_cast< uint64_t >(nanoseconds_fraction) >= system_duration::subsecond_fraction ?
+ time_left / conversion_ratio : time_left * conversion_ratio;
+
+ timeout = dispatch_time(DISPATCH_TIME_NOW, nanoseconds_left);
+ }
+
+ return dispatch_semaphore_wait(m_sem, timeout) == 0;
}
-private:
- bool do_wait_lock_until(const dispatch_time_t timeout) BOOST_NOEXCEPT
+ bool priv_timed_wait(sync::detail::system_time_point const& t)
{
- const long status = dispatch_semaphore_wait(m_sem, timeout);
- return status == 0;
+ return dispatch_semaphore_wait(m_sem, dispatch_walltime(const_cast< struct ::timespec* >(&t.get()), 0)) == 0;
}
-#endif // BOOST_SYNC_USES_CHRONO
+ template< typename TimePoint >
+ bool priv_timed_wait(sync::detail::chrono_time_point< TimePoint > const& t)
+ {
+ typedef TimePoint time_point;
+ typedef typename time_point::clock clock;
+ typedef typename time_point::duration duration;
+ time_point now = clock::now();
+ while (now < t.get())
+ {
+ if (priv_timed_wait(sync::detail::time_traits< duration >::to_sync_unit(t.get() - now)))
+ return true;
+ now = clock::now();
+ }
+ return false;
+ }
private:
dispatch_semaphore_t m_sem;
Modified: trunk/boost/sync/detail/semaphore/semaphore_emulation.hpp
==============================================================================
--- trunk/boost/sync/detail/semaphore/semaphore_emulation.hpp Tue Oct 15 12:40:51 2013 (r86325)
+++ trunk/boost/sync/detail/semaphore/semaphore_emulation.hpp 2013-10-15 12:49:34 EDT (Tue, 15 Oct 2013) (r86326)
@@ -1,6 +1,7 @@
// semaphore.hpp, mutex/condition_varibale emulation
//
// Copyright (C) 2013 Tim Blechmann
+// Copyright (C) 2013 Andrey Semashev
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -9,19 +10,13 @@
#ifndef BOOST_SYNC_DETAIL_SEMAPHORE_SEMAPHORE_EMULATION_HPP_INCLUDED_
#define BOOST_SYNC_DETAIL_SEMAPHORE_SEMAPHORE_EMULATION_HPP_INCLUDED_
-#include <boost/thread/locks.hpp>
-#include <boost/thread/mutex.hpp>
-#include <boost/thread/condition_variable.hpp>
-
+#include <boost/utility/enable_if.hpp>
#include <boost/sync/detail/config.hpp>
-//#include <boost/sync/locks/lock_guard.hpp>
-//#include <boost/sync/locks/unique_lock.hpp>
-
-#ifdef BOOST_SYNC_USES_CHRONO
-#include <boost/chrono/system_clocks.hpp>
-#include <boost/chrono/ceil.hpp>
-#endif
-
+#include <boost/sync/detail/time_traits.hpp>
+#include <boost/sync/locks/lock_guard.hpp>
+#include <boost/sync/locks/unique_lock.hpp>
+#include <boost/sync/mutexes/mutex.hpp>
+#include <boost/sync/condition_variables/condition_variable.hpp>
#include <boost/sync/detail/header.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
@@ -42,29 +37,29 @@
BOOST_DELETED_FUNCTION(semaphore& operator=(semaphore const&))
public:
- explicit semaphore(unsigned int i = 0) BOOST_NOEXCEPT :
- m_count(i)
- {}
+ explicit semaphore(unsigned int i = 0) : m_count(i)
+ {
+ }
- void post(void)
+ void post()
{
- lock_guard< mutex > lock(m_mutex);
+ sync::lock_guard< sync::mutex > lock(m_mutex);
++m_count;
m_cond.notify_one();
}
- void wait(void)
+ void wait()
{
- unique_lock< mutex > lock(m_mutex);
+ sync::unique_lock< sync::mutex > lock(m_mutex);
while (m_count == 0)
m_cond.wait(lock);
--m_count;
}
- bool try_wait(void)
+ bool try_wait()
{
- lock_guard< mutex > lock(m_mutex);
+ sync::lock_guard< sync::mutex > lock(m_mutex);
if (m_count == 0)
return false;
@@ -72,38 +67,44 @@
return true;
}
-#ifdef BOOST_SYNC_USES_CHRONO
- template <class Rep, class Period>
- bool try_wait_for(const chrono::duration<Rep, Period> & rel_time)
- {
- return try_wait_until(chrono::steady_clock::now() + rel_time);
- }
-
- template <class Clock, class Duration>
- bool try_wait_until(const chrono::time_point<Clock, Duration> & timeout)
+ template< typename Time >
+ typename enable_if_c< sync::detail::time_traits< Time >::is_specialized, bool >::type timed_wait(Time const& t)
{
- unique_lock< mutex > lock(m_mutex);
+ sync::unique_lock< sync::mutex > lock(m_mutex);
while (m_count == 0)
{
- if (m_cond.wait_until(lock, timeout) == cv_status::timeout)
+ if (!m_cond.timed_wait(lock, t))
{
if (m_count == 0)
return false;
- break;
+ else
+ break;
}
}
+
--m_count;
return true;
}
-#endif // BOOST_SYNC_USES_CHRONO
+
+ template< typename Duration >
+ typename enable_if< detail::is_time_tag_of< Duration, detail::time_duration_tag >, bool >::type wait_for(Duration const& duration)
+ {
+ return timed_wait(duration);
+ }
+
+ template< typename TimePoint >
+ typename enable_if< detail::is_time_tag_of< TimePoint, detail::time_point_tag >, bool >::type wait_until(TimePoint const& abs_time)
+ {
+ return timed_wait(abs_time);
+ }
private:
- mutex m_mutex;
- condition_variable m_cond;
+ sync::mutex m_mutex;
+ sync::condition_variable m_cond;
unsigned int m_count;
};
-} // namespace
+} // namespace abi
} // namespace sync
Modified: trunk/boost/sync/detail/semaphore/semaphore_mach.hpp
==============================================================================
--- trunk/boost/sync/detail/semaphore/semaphore_mach.hpp Tue Oct 15 12:40:51 2013 (r86325)
+++ trunk/boost/sync/detail/semaphore/semaphore_mach.hpp 2013-10-15 12:49:34 EDT (Tue, 15 Oct 2013) (r86326)
@@ -1,6 +1,7 @@
// semaphore.hpp, mach semaphores
//
// Copyright (C) 2013 Tim Blechmann
+// Copyright (C) 2013 Andrey Semashev
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -9,23 +10,21 @@
#ifndef BOOST_SYNC_DETAIL_SEMAPHORE_SEMAPHORE_MACH_HPP_INCLUDED_
#define BOOST_SYNC_DETAIL_SEMAPHORE_SEMAPHORE_MACH_HPP_INCLUDED_
-#include <cstddef>
-
-#include <boost/sync/detail/config.hpp>
-#include <boost/sync/detail/throw_exception.hpp>
-#include <boost/sync/detail/system_error.hpp>
-#include <boost/sync/exceptions/resource_error.hpp>
-
-#ifdef BOOST_SYNC_USES_CHRONO
-#include <boost/chrono/system_clocks.hpp>
-#include <boost/chrono/ceil.hpp>
-#endif
-
#include <mach/task.h>
#include <mach/semaphore.h>
#include <mach/mach_traps.h>
#include <mach/mach_init.h>
+#include <boost/assert.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/utility/enable_if.hpp>
+#include <boost/sync/detail/config.hpp>
+#include <boost/sync/detail/time_traits.hpp>
+#include <boost/sync/detail/time_units.hpp>
+#include <boost/sync/detail/throw_exception.hpp>
+#include <boost/sync/detail/system_error.hpp>
+#include <boost/sync/exceptions/resource_error.hpp>
+#include <boost/sync/exceptions/wait_error.hpp>
#include <boost/sync/detail/header.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
@@ -48,57 +47,137 @@
{
kern_return_t result = semaphore_create(mach_task_self(), &m_sem, SYNC_POLICY_FIFO, i);
if (result != KERN_SUCCESS)
- BOOST_SYNC_DETAIL_THROW(resource_error, (sync::detail::system_ns::errc::not_enough_memory)("boost::sync::semaphore constructor failed in semaphore_create"));
+ BOOST_SYNC_DETAIL_THROW(resource_error, (sync::detail::system_ns::errc::not_enough_memory)("semaphore constructor failed in semaphore_create"));
}
- ~semaphore() BOOST_NOEXCEPT
+ ~semaphore()
{
kern_return_t result = semaphore_destroy(mach_task_self(), m_sem);
BOOST_VERIFY(result == KERN_SUCCESS);
}
- void post() BOOST_NOEXCEPT
+ void post()
{
kern_return_t result = semaphore_signal(m_sem);
BOOST_VERIFY(result == KERN_SUCCESS);
}
- void wait() BOOST_NOEXCEPT
+ void wait()
{
kern_return_t result = semaphore_wait(m_sem);
- BOOST_VERIFY(result == KERN_SUCCESS);
+ if (BOOST_UNLIKELY(result != KERN_SUCCESS))
+ {
+ switch (result)
+ {
+ case KERN_INVALID_ARGUMENT:
+ BOOST_SYNC_DETAIL_THROW(wait_error, (sync::detail::system_ns::errc::invalid_argument)("semaphore::wait failed: the specified semaphore is invalid."));
+
+ case KERN_TERMINATED:
+ BOOST_SYNC_DETAIL_THROW(wait_error, (sync::detail::system_ns::errc::invalid_argument)("semaphore::wait failed: the specified semaphore has been destroyed"));
+
+ case KERN_ABORTED:
+ default:
+ BOOST_SYNC_DETAIL_THROW(wait_error, (sync::detail::system_ns::errc::operation_canceled)("semaphore::wait failed: the wait operation has been aborted"));
+ }
+ }
}
- bool try_wait(void) BOOST_NOEXCEPT
+ bool try_wait()
{
- const mach_timespec_t mach_wait_time = { 0, 0 };
- return do_try_wait_for( mach_wait_time );
+ const mach_timespec_t wait_time = { 0, 0 };
+ return priv_timed_wait(wait_time);
}
- template <class Rep, class Period>
- bool try_wait_for(const chrono::duration<Rep, Period> & duration) BOOST_NOEXCEPT
+ template< typename Time >
+ typename enable_if_c< sync::detail::time_traits< Time >::is_specialized, bool >::type timed_wait(Time const& t)
{
- chrono::seconds seconds = chrono::duration_cast<chrono::seconds>(duration);
- chrono::nanoseconds nanoseconds = chrono::duration_cast<chrono::nanoseconds>(duration) - seconds;
+ return priv_timed_wait(sync::detail::time_traits< Time >::to_sync_unit(t));
+ }
- const mach_timespec_t mach_wait_time = { static_cast<unsigned int>(seconds.count()), static_cast<clock_res_t>(nanoseconds.count()) };
- return do_try_wait_for(mach_wait_time);
+ template< typename Duration >
+ typename enable_if< detail::is_time_tag_of< Duration, detail::time_duration_tag >, bool >::type wait_for(Duration const& duration)
+ {
+ return priv_timed_wait(sync::detail::time_traits< Duration >::to_sync_unit(duration));
}
- template <class Clock, class Duration>
- bool try_wait_until(const chrono::time_point<Clock, Duration> & timeout ) BOOST_NOEXCEPT
+ template< typename TimePoint >
+ typename enable_if< detail::is_time_tag_of< TimePoint, detail::time_point_tag >, bool >::type wait_until(TimePoint const& abs_time)
{
- return try_wait_for( timeout - Clock::now() );
+ return priv_timed_wait(sync::detail::time_traits< TimePoint >::to_sync_unit(abs_time));
}
private:
- bool do_try_wait_for(const mach_timespec_t & wait_time) BOOST_NOEXCEPT
+ bool priv_timed_wait(sync::detail::system_duration dur)
+ {
+ 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;
+
+ 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
+ };
+
+ const mach_timespec_t wait_time =
+ {
+ time_left_sec,
+ static_cast< uint64_t >(nanoseconds_fraction) >= system_duration::subsecond_fraction ?
+ time_left_subsec / conversion_ratio : time_left_subsec * conversion_ratio
+ };
+
+ return priv_timed_wait(wait_time);
+ }
+
+ bool priv_timed_wait(sync::detail::system_time_point const& t)
+ {
+ return priv_timed_wait(t - sync::detail::system_time_point::now());
+ }
+
+ template< typename TimePoint >
+ bool priv_timed_wait(sync::detail::chrono_time_point< TimePoint > const& t)
+ {
+ typedef TimePoint time_point;
+ typedef typename time_point::clock clock;
+ typedef typename time_point::duration duration;
+ time_point now = clock::now();
+ while (now < t.get())
+ {
+ if (priv_timed_wait(sync::detail::time_traits< duration >::to_sync_unit(t.get() - now)))
+ return true;
+ now = clock::now();
+ }
+ return false;
+ }
+
+ bool priv_timed_wait(const mach_timespec_t& wait_time)
{
kern_return_t result = semaphore_timedwait(m_sem, wait_time);
+
if (result == KERN_SUCCESS)
return true;
- else
- return false;
+
+ if (BOOST_UNLIKELY(result != KERN_OPERATION_TIMED_OUT))
+ {
+ switch (result)
+ {
+ case KERN_INVALID_ARGUMENT:
+ BOOST_SYNC_DETAIL_THROW(wait_error, (sync::detail::system_ns::errc::invalid_argument)("semaphore::try_wait failed: the specified semaphore is invalid."));
+
+ case KERN_TERMINATED:
+ BOOST_SYNC_DETAIL_THROW(wait_error, (sync::detail::system_ns::errc::invalid_argument)("semaphore::try_wait failed: the specified semaphore has been destroyed"));
+
+ case KERN_ABORTED:
+ default:
+ BOOST_SYNC_DETAIL_THROW(wait_error, (sync::detail::system_ns::errc::operation_canceled)("semaphore::try_wait failed: the wait operation has been aborted"));
+ }
+ }
+
+ return false;
}
private:
Modified: trunk/boost/sync/detail/semaphore/semaphore_posix.hpp
==============================================================================
--- trunk/boost/sync/detail/semaphore/semaphore_posix.hpp Tue Oct 15 12:40:51 2013 (r86325)
+++ trunk/boost/sync/detail/semaphore/semaphore_posix.hpp 2013-10-15 12:49:34 EDT (Tue, 15 Oct 2013) (r86326)
@@ -1,6 +1,7 @@
// semaphore.hpp, posix implementation
//
// Copyright (C) 2013 Tim Blechmann
+// Copyright (C) 2013 Andrey Semashev
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -14,15 +15,13 @@
#include <semaphore.h>
#include <boost/assert.hpp>
+#include <boost/utility/enable_if.hpp>
#include <boost/sync/detail/config.hpp>
-#include <boost/sync/detail/throw_exception.hpp>
#include <boost/sync/exceptions/resource_error.hpp>
-
-#ifdef BOOST_SYNC_USES_CHRONO
-#include <boost/chrono/system_clocks.hpp>
-#include <boost/chrono/ceil.hpp>
-#endif
-
+#include <boost/sync/exceptions/overflow_error.hpp>
+#include <boost/sync/detail/throw_exception.hpp>
+#include <boost/sync/detail/time_traits.hpp>
+#include <boost/sync/detail/time_units.hpp>
#include <boost/sync/detail/header.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
@@ -66,7 +65,7 @@
switch (err)
{
case EOVERFLOW:
- BOOST_SYNC_DETAIL_THROW(resource_error, (err)("boost::sync::semaphore post failed: maximum allowable value would be exceeded"));
+ BOOST_SYNC_DETAIL_THROW(overflow_error, (err)("semaphore post failed: semaphore counter overflow"));
break;
case EINVAL:
@@ -77,7 +76,7 @@
}
}
- void wait(void) BOOST_NOEXCEPT
+ void wait()
{
for (;;)
{
@@ -99,7 +98,7 @@
}
}
- bool try_wait(void) BOOST_NOEXCEPT
+ bool try_wait()
{
const int status = sem_trywait(&m_sem);
if (status == 0)
@@ -107,54 +106,46 @@
switch (errno)
{
- case EINVAL:
- BOOST_ASSERT(false);
-
+ case EINTR:
case EAGAIN:
return false;
+ case EINVAL:
default:
+ BOOST_ASSERT(false);
return false;
}
}
-#ifdef BOOST_SYNC_USES_CHRONO
- template <class Rep, class Period>
- bool try_wait_for(const chrono::duration<Rep, Period> & duration) BOOST_NOEXCEPT
+ template< typename Time >
+ typename enable_if_c< sync::detail::time_traits< Time >::is_specialized, bool >::type timed_wait(Time const& t)
{
- return try_wait_until(chrono::steady_clock::now() + duration);
+ return priv_timed_wait(sync::detail::time_traits< Time >::to_sync_unit(t));
}
- template <class Clock, class Duration>
- bool try_wait_until(const chrono::time_point<Clock, Duration> & timeout ) BOOST_NOEXCEPT
+ template< typename Duration >
+ typename enable_if< detail::is_time_tag_of< Duration, detail::time_duration_tag >, bool >::type wait_for(Duration const& duration)
{
- using namespace chrono;
- system_clock::time_point s_now = system_clock::now();
- typename Clock::time_point c_now = Clock::now();
- return try_wait_until(s_now + ceil<nanoseconds>(timeout - c_now));
+ return priv_timed_wait(sync::detail::time_traits< Duration >::to_sync_unit(duration));
}
- template <class Duration>
- bool try_wait_until(const chrono::time_point<chrono::system_clock, Duration>& t) BOOST_NOEXCEPT
+ template< typename TimePoint >
+ typename enable_if< detail::is_time_tag_of< TimePoint, detail::time_point_tag >, bool >::type wait_until(TimePoint const& abs_time)
{
- using namespace chrono;
- typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
- return try_wait_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
+ return priv_timed_wait(sync::detail::time_traits< TimePoint >::to_sync_unit(abs_time));
}
- bool try_wait_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp) BOOST_NOEXCEPT
+private:
+ bool priv_timed_wait(sync::detail::system_duration dur)
{
- chrono::nanoseconds d = tp.time_since_epoch();
- timespec ts = boost::detail::to_timespec(d);
- return do_wait_lock_until(ts);
+ return priv_timed_wait(sync::detail::system_time_point::now() + dur);
}
-private:
- bool do_wait_lock_until(struct timespec const & timeout) BOOST_NOEXCEPT
+ bool priv_timed_wait(sync::detail::system_time_point const& t)
{
for (;;)
{
- const int status = sem_timedwait(&m_sem, &timeout);
+ const int status = sem_timedwait(&m_sem, &t.get());
if (status == 0)
return true;
@@ -175,7 +166,21 @@
}
}
-#endif // BOOST_SYNC_USES_CHRONO
+ template< typename TimePoint >
+ bool priv_timed_wait(sync::detail::chrono_time_point< TimePoint > const& t)
+ {
+ typedef TimePoint time_point;
+ typedef typename time_point::clock clock;
+ typedef typename time_point::duration duration;
+ time_point now = clock::now();
+ while (now < t.get())
+ {
+ if (priv_timed_wait(sync::detail::time_traits< duration >::to_sync_unit(t.get() - now)))
+ return true;
+ now = clock::now();
+ }
+ return false;
+ }
private:
sem_t m_sem;
Modified: trunk/boost/sync/detail/semaphore/semaphore_windows.hpp
==============================================================================
--- trunk/boost/sync/detail/semaphore/semaphore_windows.hpp Tue Oct 15 12:40:51 2013 (r86325)
+++ trunk/boost/sync/detail/semaphore/semaphore_windows.hpp 2013-10-15 12:49:34 EDT (Tue, 15 Oct 2013) (r86326)
@@ -9,14 +9,21 @@
#ifndef BOOST_SYNC_DETAIL_SEMAPHORE_SEMAPHORE_WINDOWS_HPP_INCLUDED_
#define BOOST_SYNC_DETAIL_SEMAPHORE_SEMAPHORE_WINDOWS_HPP_INCLUDED_
+#include <limits.h>
#include <cstddef>
-#include <limits>
+#include <boost/assert.hpp>
+#include <boost/utility/enable_if.hpp>
#include <boost/detail/winapi/GetLastError.hpp>
#include <boost/detail/winapi/synchronization.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/sync/detail/config.hpp>
#include <boost/sync/detail/throw_exception.hpp>
#include <boost/sync/exceptions/resource_error.hpp>
+#include <boost/sync/exceptions/overflow_error.hpp>
+#include <boost/sync/exceptions/wait_error.hpp>
+#include <boost/sync/detail/time_traits.hpp>
+#include <boost/sync/detail/time_units.hpp>
+#include <boost/sync/detail/waitable_timer.hpp>
#include <boost/sync/detail/header.hpp>
#ifdef BOOST_HAS_PRAGMA_ONCE
@@ -34,19 +41,14 @@
BOOST_DELETED_FUNCTION(semaphore(semaphore const&))
BOOST_DELETED_FUNCTION(semaphore& operator=(semaphore const&))
- typedef boost::detail::winapi::HANDLE_ HANDLE_;
- typedef boost::detail::winapi::DWORD_ DWORD_;
- typedef boost::detail::winapi::LONG_ LONG_;
- typedef boost::detail::winapi::BOOL_ BOOL_;
-
public:
explicit semaphore(unsigned int i = 0)
{
- m_sem = boost::detail::winapi::CreateSemaphoreA(NULL, i, (std::numeric_limits<LONG_>::max)(), NULL);
+ m_sem = boost::detail::winapi::create_anonymous_semaphore(NULL, i, LONG_MAX);
if (!m_sem)
{
- const DWORD_ err = boost::detail::winapi::GetLastError();
- BOOST_SYNC_DETAIL_THROW(resource_error, (err)("boost::sync::semaphore constructor failed in CreateSemaphore"));
+ const boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError();
+ BOOST_SYNC_DETAIL_THROW(resource_error, (err)("semaphore constructor failed in CreateSemaphore"));
}
}
@@ -57,81 +59,136 @@
void post()
{
- const BOOL_ status = boost::detail::winapi::ReleaseSemaphore(m_sem, 1, NULL);
+ const boost::detail::winapi::BOOL_ status = boost::detail::winapi::ReleaseSemaphore(m_sem, 1, NULL);
if (status == 0)
{
- const DWORD_ err = boost::detail::winapi::GetLastError();
- BOOST_SYNC_DETAIL_THROW(resource_error, (err)("boost::sync::semaphore::post failed in ReleaseSemaphore"));
+ const boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError();
+ BOOST_SYNC_DETAIL_THROW(overflow_error, (err)("semaphore::post failed in ReleaseSemaphore"));
}
}
-
- bool wait()
+ void wait()
{
- switch (boost::detail::winapi::WaitForSingleObject(m_sem, boost::detail::winapi::infinite))
+ if (boost::detail::winapi::WaitForSingleObject(m_sem, boost::detail::winapi::infinite) != boost::detail::winapi::wait_object_0)
{
- case boost::detail::winapi::wait_object_0:
- return true;
-
- case boost::detail::winapi::wait_failed:
- {
- const DWORD_ err = boost::detail::winapi::GetLastError();
- BOOST_SYNC_DETAIL_THROW(resource_error, (err)("boost::sync::semaphore::wait failed in WaitForSingleObject"));
- }
-
- default:
- BOOST_ASSERT(false);
- return false;
+ const boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError();
+ BOOST_SYNC_DETAIL_THROW(wait_error, (err)("semaphore::wait failed in WaitForSingleObject"));
}
}
bool try_wait()
{
- return do_try_wait_for( 0L );
+ const boost::detail::winapi::DWORD_ res = boost::detail::winapi::WaitForSingleObject(m_sem, 0);
+ if (res == boost::detail::winapi::wait_failed)
+ {
+ const boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError();
+ BOOST_SYNC_DETAIL_THROW(wait_error, (err)("semaphore::try_wait failed in WaitForSingleObject"));
+ }
+
+ return res == boost::detail::winapi::wait_object_0;
}
-#ifdef BOOST_SYNC_USES_CHRONO
- template <class Rep, class Period>
- bool try_wait_for(const chrono::duration<Rep, Period> & rel_time)
+ template< typename Time >
+ typename enable_if_c< sync::detail::time_traits< Time >::is_specialized, bool >::type timed_wait(Time const& t)
{
- return do_try_wait_for(static_cast< DWORD_ >(chrono::duration_cast<chrono::milliseconds>( rel_time ).count()));
+ return priv_timed_wait(sync::detail::time_traits< Time >::to_sync_unit(t));
}
- template <class Clock, class Duration>
- bool try_wait_until(const chrono::time_point<Clock, Duration> & timeout )
+ template< typename Duration >
+ typename enable_if< detail::is_time_tag_of< Duration, detail::time_duration_tag >, bool >::type wait_for(Duration const& duration)
{
- typename Clock::time_point c_now = Clock::now();
- return try_wait_for( timeout - c_now );
+ return priv_timed_wait(sync::detail::time_traits< Duration >::to_sync_unit(duration));
+ }
+
+ template< typename TimePoint >
+ typename enable_if< detail::is_time_tag_of< TimePoint, detail::time_point_tag >, bool >::type wait_until(TimePoint const& abs_time)
+ {
+ return priv_timed_wait(sync::detail::time_traits< TimePoint >::to_sync_unit(abs_time));
}
-#endif
private:
-#ifdef BOOST_SYNC_USES_CHRONO
- bool do_try_wait_for( long milliseconds )
+ bool priv_timed_wait(sync::detail::system_duration t)
{
- switch (boost::detail::winapi::WaitForSingleObject(m_sem, milliseconds))
+ if (try_wait())
+ return true;
+
+ sync::detail::system_duration::native_type time_left = t.get();
+ while (time_left > 0)
{
- case boost::detail::winapi::wait_object_0:
+ const boost::detail::winapi::DWORD_ dur = time_left > boost::detail::winapi::max_non_infinite_wait ?
+ boost::detail::winapi::max_non_infinite_wait : static_cast< boost::detail::winapi::DWORD_ >(time_left);
+ const boost::detail::winapi::DWORD_ res = boost::detail::winapi::WaitForSingleObject(m_sem, dur);
+ switch (res)
+ {
+ case boost::detail::winapi::wait_object_0:
+ return true;
+
+ case boost::detail::winapi::wait_timeout:
+ time_left -= dur;
+ break;
+
+ default:
+ {
+ const boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError();
+ BOOST_SYNC_DETAIL_THROW(wait_error, (err)("semaphore::timed_wait failed in WaitForSingleObject"));
+ }
+ }
+ }
+
+ return false;
+ }
+
+ bool priv_timed_wait(sync::detail::system_time_point const& t)
+ {
+ boost::detail::winapi::HANDLE_ handles[2];
+ handles[0] = m_sem;
+ handles[1] = sync::detail::windows::get_waitable_timer();
+
+ 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(wait_error, (err)("semaphore::timed_wait failed to set a timeout"));
+ }
+
+ const boost::detail::winapi::DWORD_ res = boost::detail::winapi::WaitForMultipleObjects(sizeof(handles) / sizeof(*handles), handles, false, boost::detail::winapi::infinite);
+ switch (res)
+ {
+ case boost::detail::winapi::wait_object_0: // semaphore was signalled
return true;
- case boost::detail::winapi::wait_timeout:
+ default:
+ BOOST_ASSERT(false);
+
+ case boost::detail::winapi::wait_object_0 + 1: // timeout has expired
return false;
case boost::detail::winapi::wait_failed:
{
- const DWORD_ err = boost::detail::winapi::GetLastError();
- BOOST_SYNC_DETAIL_THROW(resource_error, (err)("boost::sync::semaphore::do_try_wait_for failed in WaitForSingleObject"));
+ const boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError();
+ BOOST_SYNC_DETAIL_THROW(lock_error, (err)("semaphore::timed_wait failed in WaitForMultipleObjects"));
}
+ }
+ }
- default:
- BOOST_ASSERT(false);
- return false;
+ template< typename TimePoint >
+ bool priv_timed_wait(sync::detail::chrono_time_point< TimePoint > const& t)
+ {
+ typedef TimePoint time_point;
+ typedef typename time_point::clock clock;
+ typedef typename time_point::duration duration;
+ time_point now = clock::now();
+ while (now < t.get())
+ {
+ if (priv_timed_wait(sync::detail::time_traits< duration >::to_sync_unit(t.get() - now)))
+ return true;
+ now = clock::now();
}
+ return false;
}
-#endif
- HANDLE_ m_sem;
+private:
+ boost::detail::winapi::HANDLE_ m_sem;
};
} // namespace winnt
Modified: trunk/boost/sync/exceptions.hpp
==============================================================================
--- trunk/boost/sync/exceptions.hpp Tue Oct 15 12:40:51 2013 (r86325)
+++ trunk/boost/sync/exceptions.hpp 2013-10-15 12:49:34 EDT (Tue, 15 Oct 2013) (r86326)
@@ -24,5 +24,6 @@
#include <boost/sync/exceptions/resource_error.hpp>
#include <boost/sync/exceptions/lock_error.hpp>
#include <boost/sync/exceptions/wait_error.hpp>
+#include <boost/sync/exceptions/overflow_error.hpp>
#endif // BOOST_SYNC_EXCEPTIONS_HPP_INCLUDED_
Added: trunk/boost/sync/exceptions/overflow_error.hpp
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/boost/sync/exceptions/overflow_error.hpp 2013-10-15 12:49:34 EDT (Tue, 15 Oct 2013) (r86326)
@@ -0,0 +1,58 @@
+/*
+ * 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)
+ *
+ * (C) Copyright 2013 Andrey Semashev
+ */
+/*!
+ * \file exceptions/overflow_error.hpp
+ *
+ * \brief This header defines the \c overflow_error exception.
+ */
+
+#ifndef BOOST_SYNC_EXCEPTIONS_OVERFLOW_ERROR_HPP_INCLUDED_
+#define BOOST_SYNC_EXCEPTIONS_OVERFLOW_ERROR_HPP_INCLUDED_
+
+#include <string>
+#include <boost/sync/detail/config.hpp>
+#include <boost/sync/detail/system_error.hpp>
+#include <boost/sync/exceptions/runtime_exception.hpp>
+#include <boost/sync/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+
+namespace sync {
+
+class BOOST_SYMBOL_VISIBLE overflow_error :
+ public runtime_exception
+{
+public:
+ explicit overflow_error(int sys_err = static_cast< int >(sync::detail::system_ns::errc::value_too_large)) : runtime_exception(sys_err, "boost::sync::overflow_error")
+ {
+ }
+
+ overflow_error(int sys_err, const char* what) : runtime_exception(sys_err, what)
+ {
+ }
+
+ overflow_error(int sys_err, std::string const& what) : runtime_exception(sys_err, what)
+ {
+ }
+
+ ~overflow_error() BOOST_NOEXCEPT_OR_NOTHROW
+ {
+ }
+};
+
+} // namespace sync
+
+} // namespace boost
+
+#include <boost/sync/detail/footer.hpp>
+
+#endif // BOOST_SYNC_EXCEPTIONS_OVERFLOW_ERROR_HPP_INCLUDED_
Modified: trunk/boost/sync/support/boost_date_time.hpp
==============================================================================
--- trunk/boost/sync/support/boost_date_time.hpp Tue Oct 15 12:40:51 2013 (r86325)
+++ trunk/boost/sync/support/boost_date_time.hpp 2013-10-15 12:49:34 EDT (Tue, 15 Oct 2013) (r86326)
@@ -13,6 +13,7 @@
#ifndef BOOST_SYNC_SUPPORT_BOOST_DATE_TIME_HPP_INCLUDED_
#define BOOST_SYNC_SUPPORT_BOOST_DATE_TIME_HPP_INCLUDED_
+#include <boost/assert.hpp>
#include <boost/cstdint.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/sync/detail/config.hpp>
@@ -40,6 +41,8 @@
static system_duration to_sync_unit(T const& dur)
{
+ BOOST_ASSERT(!dur.is_special());
+
typedef typename T::traits_type traits_type;
enum
{
@@ -62,6 +65,8 @@
static system_time_point to_sync_unit(T const& point)
{
+ BOOST_ASSERT(!point.is_special());
+
typedef typename T::date_type date_type;
typedef typename T::time_duration_type time_duration_type;
time_duration_type dur = point - T(date_type(1970, 1, 1));
Modified: trunk/libs/sync/test/run/semaphore_test.cpp
==============================================================================
--- trunk/libs/sync/test/run/semaphore_test.cpp Tue Oct 15 12:40:51 2013 (r86325)
+++ trunk/libs/sync/test/run/semaphore_test.cpp 2013-10-15 12:49:34 EDT (Tue, 15 Oct 2013) (r86326)
@@ -5,29 +5,43 @@
#include <boost/test/unit_test.hpp>
-#include <boost/thread.hpp>
+#include <boost/bind.hpp>
+#include <boost/chrono.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/thread_time.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/sync/semaphore.hpp>
+#include <boost/sync/support/boost_chrono.hpp>
+#include <boost/sync/support/boost_date_time.hpp>
#include <boost/typeof/typeof.hpp>
BOOST_AUTO_TEST_CASE(test_semaphore_post_wait)
{
- boost::sync::semaphore sem(0);
+ boost::sync::semaphore sem;
sem.post();
sem.wait();
}
-
BOOST_AUTO_TEST_CASE(test_semaphore_try_wait)
{
- boost::sync::semaphore sem(0);
+ boost::sync::semaphore sem;
BOOST_REQUIRE(!sem.try_wait());
sem.post();
BOOST_REQUIRE(sem.try_wait());
}
+BOOST_AUTO_TEST_CASE(test_semaphore_initial_count)
+{
+ boost::sync::semaphore sem(2);
+
+ BOOST_REQUIRE(sem.try_wait());
+ BOOST_REQUIRE(sem.try_wait());
+ BOOST_REQUIRE(!sem.try_wait());
+}
+
struct semaphore_wait_and_post_test
{
@@ -53,17 +67,15 @@
test.run();
}
-#ifdef BOOST_SYNC_USES_CHRONO
-
BOOST_AUTO_TEST_CASE(test_semaphore_wait_for)
{
using namespace boost;
- sync::semaphore sem(0);
+ sync::semaphore sem;
BOOST_AUTO(start, chrono::system_clock::now());
- BOOST_REQUIRE(!sem.try_wait_for(chrono::milliseconds(500)));
+ BOOST_REQUIRE(!sem.wait_for(chrono::milliseconds(500)));
BOOST_AUTO(end, chrono::system_clock::now());
BOOST_AUTO(wait_time, end - start);
@@ -74,19 +86,19 @@
sem.post();
- BOOST_REQUIRE(sem.try_wait_for(chrono::milliseconds(500)));
+ BOOST_REQUIRE(sem.wait_for(chrono::milliseconds(500)));
}
BOOST_AUTO_TEST_CASE(test_semaphore_wait_until)
{
using namespace boost;
- sync::semaphore sem(0);
+ sync::semaphore sem;
{
BOOST_AUTO(now, chrono::system_clock::now());
BOOST_AUTO(timeout, now + chrono::milliseconds(500));
- BOOST_REQUIRE(!sem.try_wait_until(timeout));
+ BOOST_REQUIRE(!sem.wait_until(timeout));
BOOST_AUTO(end, chrono::system_clock::now());
BOOST_AUTO(timeout_delta, end - timeout);
@@ -99,10 +111,10 @@
sem.post();
{
- BOOST_AUTO(start, chrono::system_clock::now());
+ BOOST_AUTO(start, chrono::system_clock::now());
BOOST_AUTO(timeout, start + chrono::milliseconds(500));
- BOOST_REQUIRE(sem.try_wait_until(timeout));
+ BOOST_REQUIRE(sem.wait_until(timeout));
BOOST_AUTO(end, chrono::system_clock::now());
@@ -110,4 +122,102 @@
BOOST_REQUIRE( (end - start) < chrono::milliseconds(100) );
}
}
-#endif
+
+BOOST_AUTO_TEST_CASE(test_semaphore_timed_wait)
+{
+ using namespace boost;
+
+ sync::semaphore sem;
+
+ // Relative timeouts
+ {
+ BOOST_AUTO(start, chrono::system_clock::now());
+
+ BOOST_REQUIRE(!sem.timed_wait(chrono::milliseconds(500)));
+
+ BOOST_AUTO(end, chrono::system_clock::now());
+ BOOST_AUTO(wait_time, end - start);
+
+ // guessing!
+ BOOST_REQUIRE( wait_time > chrono::milliseconds(450) );
+ BOOST_REQUIRE( wait_time < chrono::milliseconds(1000) );
+
+ sem.post();
+
+ BOOST_REQUIRE(sem.timed_wait(chrono::milliseconds(500)));
+ }
+
+ {
+ BOOST_AUTO(start, get_system_time());
+
+ BOOST_REQUIRE(!sem.timed_wait(posix_time::milliseconds(500)));
+
+ BOOST_AUTO(end, get_system_time());
+ BOOST_AUTO(wait_time, end - start);
+
+ // guessing!
+ BOOST_REQUIRE( wait_time > posix_time::milliseconds(450) );
+ BOOST_REQUIRE( wait_time < posix_time::milliseconds(1000) );
+
+ sem.post();
+
+ BOOST_REQUIRE(sem.timed_wait(posix_time::milliseconds(500)));
+ }
+
+ // Absolute timeouts
+ {
+ BOOST_AUTO(now, chrono::system_clock::now());
+ BOOST_AUTO(timeout, now + chrono::milliseconds(500));
+
+ BOOST_REQUIRE(!sem.timed_wait(timeout));
+
+ BOOST_AUTO(end, chrono::system_clock::now());
+ BOOST_AUTO(timeout_delta, end - timeout);
+
+ // guessing!
+ BOOST_REQUIRE( timeout_delta > chrono::milliseconds(-400) );
+ BOOST_REQUIRE( timeout_delta < chrono::milliseconds(400) );
+ }
+
+ sem.post();
+
+ {
+ BOOST_AUTO(start, chrono::system_clock::now());
+ BOOST_AUTO(timeout, start + chrono::milliseconds(500));
+
+ BOOST_REQUIRE(sem.timed_wait(timeout));
+
+ BOOST_AUTO(end, chrono::system_clock::now());
+
+ // guessing!
+ BOOST_REQUIRE( (end - start) < chrono::milliseconds(100) );
+ }
+
+ {
+ BOOST_AUTO(now, get_system_time());
+ BOOST_AUTO(timeout, now + posix_time::milliseconds(500));
+
+ BOOST_REQUIRE(!sem.timed_wait(timeout));
+
+ BOOST_AUTO(end, get_system_time());
+ BOOST_AUTO(timeout_delta, end - timeout);
+
+ // guessing!
+ BOOST_REQUIRE( timeout_delta > posix_time::milliseconds(-400) );
+ BOOST_REQUIRE( timeout_delta < posix_time::milliseconds(400) );
+ }
+
+ sem.post();
+
+ {
+ BOOST_AUTO(start, get_system_time());
+ BOOST_AUTO(timeout, start + posix_time::milliseconds(500));
+
+ BOOST_REQUIRE(sem.timed_wait(timeout));
+
+ BOOST_AUTO(end, get_system_time());
+
+ // guessing!
+ BOOST_REQUIRE( (end - start) < posix_time::milliseconds(100) );
+ }
+}
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk