diff --git a/include/boost/thread/condition.hpp b/include/boost/thread/condition.hpp index 97a7526b..d0fec03f 100644 --- a/include/boost/thread/condition.hpp +++ b/include/boost/thread/condition.hpp @@ -18,6 +18,9 @@ #include #include +#if defined(BOOST_HAS_WINTHREADS) +# include +#else #if defined(BOOST_HAS_PTHREADS) # include #elif defined(BOOST_HAS_MPTASKS) @@ -187,6 +190,7 @@ private: }; } // namespace boost +#endif // Change Log: // 8 Feb 01 WEKEMPF Initial version. diff --git a/include/boost/thread/detail/condition_win32.hpp b/include/boost/thread/detail/condition_win32.hpp new file mode 100644 index 00000000..dfac95c5 --- /dev/null +++ b/include/boost/thread/detail/condition_win32.hpp @@ -0,0 +1,193 @@ +#ifndef BOOST_CONDITION_WIN32_HPP +#define BOOST_CONDITION_WIN32_HPP + +// condition_win32.hpp +// +// (C) Copyright 2005 Anthony Williams +// +// 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) + +#include +#include +#include +#include + +namespace boost +{ + namespace detail + { + inline int get_milliseconds_until_time(boost::xtime target) + { + boost::xtime now; + boost::xtime_get(&now, boost::TIME_UTC); + + if(boost::xtime_cmp(target,now)<=0) + { + return 0; + } + else + { + long const nanoseconds_per_second=1000000000; + long const milliseconds_per_second=1000; + long const nanoseconds_per_millisecond=nanoseconds_per_second/milliseconds_per_second; + + if(target.nsec(target.sec*milliseconds_per_second)+ + static_cast((target.nsec+(nanoseconds_per_millisecond/2))/nanoseconds_per_millisecond); + } + } + } + + + class condition + { + public: + typedef ::boost::detail::lightweight_mutex gate_type; + gate_type state_change_gate; + typedef gate_type::scoped_lock gate_scoped_lock; + void* notification_sem; + long waiting_count; + long notify_count; + + private: + + void release_notification_sem(bool release_all) + { + state_change_gate.lock(); + long const waiters=BOOST_INTERLOCKED_READ(&waiting_count); + if(waiters) + { + long const count_to_unlock=release_all?waiters:1; + BOOST_INTERLOCKED_EXCHANGE(¬ify_count,count_to_unlock); + BOOST_RELEASE_SEMAPHORE(notification_sem,count_to_unlock,NULL); + } + else + { + state_change_gate.unlock(); + } + } + + struct once_predicate + { + bool called_before; + once_predicate(): + called_before(false) + {} + + bool operator()() + { + if(!called_before) + { + called_before=true; + return false; + } + return true; + } + }; + + template + bool do_wait(scoped_lock_type& m,predicate_type& pred,unsigned time_to_wait_in_milliseconds=BOOST_INFINITE) + { + { + gate_scoped_lock lock(state_change_gate); + if(pred()) + { + return true; + } + m.unlock(); + BOOST_INTERLOCKED_INCREMENT(&waiting_count); + } + + bool const notified=BOOST_WAIT_FOR_SINGLE_OBJECT(notification_sem,time_to_wait_in_milliseconds)==0; + BOOST_INTERLOCKED_DECREMENT(&waiting_count); + if(notified && !BOOST_INTERLOCKED_DECREMENT(¬ify_count)) + { + state_change_gate.unlock(); + } + m.lock(); + return notified && pred(); + } + + + public: + condition(): + notification_sem(BOOST_CREATE_SEMAPHORE(NULL,0,LONG_MAX,NULL)), + waiting_count(0), + notify_count(0) + { + state_change_gate.initialize(); + }; + + + ~condition() + { + BOOST_CLOSE_HANDLE(notification_sem); + } + + template + void wait(scoped_lock_type& m) + { + once_predicate p; + do_wait(m,p); + } + + template + void wait(scoped_lock_type& m,predicate_type pred) + { + if(pred()) + { + return; + } + while(!do_wait(m,pred)); + } + + template + bool timed_wait(scoped_lock_type& m,const xtime& xt) + { + once_predicate p; + return do_wait(m,p,detail::get_milliseconds_until_time(xt)); + } + + template + bool timed_wait(scoped_lock_type& m,const xtime& xt,predicate_type pred) + { + if(pred()) + { + return true; + } + while(!do_wait(m,pred,detail::get_milliseconds_until_time(xt))) + { + if(!detail::get_milliseconds_until_time(xt)) + { + return false; + } + } + return true; + } + + + void notify_one() + { + release_notification_sem(false); + } + + void notify_all() + { + release_notification_sem(true); + } + }; + +} + + + +#endif diff --git a/include/boost/thread/mutex.hpp b/include/boost/thread/mutex.hpp index 6739abf4..6a24ef21 100644 --- a/include/boost/thread/mutex.hpp +++ b/include/boost/thread/mutex.hpp @@ -16,7 +16,9 @@ #include #include - +#ifdef BOOST_HAS_WINTHREADS +#include +#else #if defined(BOOST_HAS_PTHREADS) # include #endif @@ -24,11 +26,13 @@ #if defined(BOOST_HAS_MPTASKS) # include "scoped_critical_region.hpp" #endif +#endif namespace boost { struct xtime; +#ifndef BOOST_HAS_WINTHREADS class BOOST_THREAD_DECL mutex : private noncopyable { @@ -110,6 +114,7 @@ private: threads::mac::detail::scoped_critical_region m_mutex_mutex; #endif }; +#endif class BOOST_THREAD_DECL timed_mutex : private noncopyable diff --git a/src/condition.cpp b/src/condition.cpp index 23be4e49..cf42b1a4 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -37,303 +37,6 @@ namespace boost { namespace detail { #if defined(BOOST_HAS_WINTHREADS) -condition_impl::condition_impl() - : m_gone(0), m_blocked(0), m_waiting(0) -{ - m_gate = reinterpret_cast(CreateSemaphore(0, 1, 1, 0)); - m_queue = reinterpret_cast( - CreateSemaphore(0, 0, (std::numeric_limits::max)(), 0)); - m_mutex = reinterpret_cast(CreateMutex(0, 0, 0)); - - if (!m_gate || !m_queue || !m_mutex) - { - int res = 0; - if (m_gate) - { - res = CloseHandle(reinterpret_cast(m_gate)); - assert(res); - } - if (m_queue) - { - res = CloseHandle(reinterpret_cast(m_queue)); - assert(res); - } - if (m_mutex) - { - res = CloseHandle(reinterpret_cast(m_mutex)); - assert(res); - } - - throw thread_resource_error(); - } -} - -condition_impl::~condition_impl() -{ - int res = 0; - res = CloseHandle(reinterpret_cast(m_gate)); - assert(res); - res = CloseHandle(reinterpret_cast(m_queue)); - assert(res); - res = CloseHandle(reinterpret_cast(m_mutex)); - assert(res); -} - -void condition_impl::notify_one() -{ - unsigned signals = 0; - - int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_mutex), INFINITE); - assert(res == WAIT_OBJECT_0); - - if (m_waiting != 0) // the m_gate is already closed - { - if (m_blocked == 0) - { - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); - return; - } - - ++m_waiting; - --m_blocked; - signals = 1; - } - else - { - res = WaitForSingleObject(reinterpret_cast(m_gate), INFINITE); - assert(res == WAIT_OBJECT_0); - if (m_blocked > m_gone) - { - if (m_gone != 0) - { - m_blocked -= m_gone; - m_gone = 0; - } - signals = m_waiting = 1; - --m_blocked; - } - else - { - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, 0); - assert(res); - } - } - - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); - - if (signals) - { - res = ReleaseSemaphore(reinterpret_cast(m_queue), signals, 0); - assert(res); - } -} - -void condition_impl::notify_all() -{ - unsigned signals = 0; - - int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_mutex), INFINITE); - assert(res == WAIT_OBJECT_0); - - if (m_waiting != 0) // the m_gate is already closed - { - if (m_blocked == 0) - { - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); - return; - } - - m_waiting += (signals = m_blocked); - m_blocked = 0; - } - else - { - res = WaitForSingleObject(reinterpret_cast(m_gate), INFINITE); - assert(res == WAIT_OBJECT_0); - if (m_blocked > m_gone) - { - if (m_gone != 0) - { - m_blocked -= m_gone; - m_gone = 0; - } - signals = m_waiting = m_blocked; - m_blocked = 0; - } - else - { - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, 0); - assert(res); - } - } - - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); - - if (signals) - { - res = ReleaseSemaphore(reinterpret_cast(m_queue), signals, 0); - assert(res); - } -} - -void condition_impl::enter_wait() -{ - int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_gate), INFINITE); - assert(res == WAIT_OBJECT_0); - ++m_blocked; - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, 0); - assert(res); -} - -void condition_impl::do_wait() -{ - int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_queue), INFINITE); - assert(res == WAIT_OBJECT_0); - - unsigned was_waiting=0; - unsigned was_gone=0; - - res = WaitForSingleObject(reinterpret_cast(m_mutex), INFINITE); - assert(res == WAIT_OBJECT_0); - was_waiting = m_waiting; - was_gone = m_gone; - if (was_waiting != 0) - { - if (--m_waiting == 0) - { - if (m_blocked != 0) - { - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, - 0); // open m_gate - assert(res); - was_waiting = 0; - } - else if (m_gone != 0) - m_gone = 0; - } - } - else if (++m_gone == ((std::numeric_limits::max)() / 2)) - { - // timeout occured, normalize the m_gone count - // this may occur if many calls to wait with a timeout are made and - // no call to notify_* is made - res = WaitForSingleObject(reinterpret_cast(m_gate), INFINITE); - assert(res == WAIT_OBJECT_0); - m_blocked -= m_gone; - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, 0); - assert(res); - m_gone = 0; - } - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); - - if (was_waiting == 1) - { - for (/**/ ; was_gone; --was_gone) - { - // better now than spurious later - res = WaitForSingleObject(reinterpret_cast(m_queue), - INFINITE); - assert(res == WAIT_OBJECT_0); - } - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, 0); - assert(res); - } -} - -bool condition_impl::do_timed_wait(const xtime& xt) -{ - bool ret = false; - unsigned int res = 0; - - for (;;) - { - int milliseconds; - to_duration(xt, milliseconds); - - res = WaitForSingleObject(reinterpret_cast(m_queue), - milliseconds); - assert(res != WAIT_FAILED && res != WAIT_ABANDONED); - ret = (res == WAIT_OBJECT_0); - - if (res == WAIT_TIMEOUT) - { - xtime cur; - xtime_get(&cur, TIME_UTC); - if (xtime_cmp(xt, cur) > 0) - continue; - } - - break; - } - - unsigned was_waiting=0; - unsigned was_gone=0; - - res = WaitForSingleObject(reinterpret_cast(m_mutex), INFINITE); - assert(res == WAIT_OBJECT_0); - was_waiting = m_waiting; - was_gone = m_gone; - if (was_waiting != 0) - { - if (!ret) // timeout - { - if (m_blocked != 0) - --m_blocked; - else - ++m_gone; // count spurious wakeups - } - if (--m_waiting == 0) - { - if (m_blocked != 0) - { - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, - 0); // open m_gate - assert(res); - was_waiting = 0; - } - else if (m_gone != 0) - m_gone = 0; - } - } - else if (++m_gone == ((std::numeric_limits::max)() / 2)) - { - // timeout occured, normalize the m_gone count - // this may occur if many calls to wait with a timeout are made and - // no call to notify_* is made - res = WaitForSingleObject(reinterpret_cast(m_gate), INFINITE); - assert(res == WAIT_OBJECT_0); - m_blocked -= m_gone; - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, 0); - assert(res); - m_gone = 0; - } - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); - - if (was_waiting == 1) - { - for (/**/ ; was_gone; --was_gone) - { - // better now than spurious later - res = WaitForSingleObject(reinterpret_cast(m_queue), - INFINITE); - assert(res == WAIT_OBJECT_0); - } - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, 0); - assert(res); - } - - return ret; -} #elif defined(BOOST_HAS_PTHREADS) condition_impl::condition_impl() { diff --git a/src/mutex.cpp b/src/mutex.cpp index ff49d989..16f53f33 100644 --- a/src/mutex.cpp +++ b/src/mutex.cpp @@ -39,104 +39,6 @@ namespace boost { #if defined(BOOST_HAS_WINTHREADS) -mutex::mutex() - : m_mutex(0) - , m_critical_section(false) -{ - m_critical_section = true; - if (m_critical_section) - m_mutex = new_critical_section(); - else - m_mutex = new_mutex(0); -} - -mutex::~mutex() -{ - if (m_critical_section) - delete_critical_section(m_mutex); - else - delete_mutex(m_mutex); -} - -void mutex::do_lock() -{ - if (m_critical_section) - wait_critical_section_infinite(m_mutex); - else - wait_mutex(m_mutex, INFINITE); -} - -void mutex::do_unlock() -{ - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); -} - -void mutex::do_lock(cv_state&) -{ - do_lock(); -} - -void mutex::do_unlock(cv_state&) -{ - do_unlock(); -} - -try_mutex::try_mutex() - : m_mutex(0) - , m_critical_section(false) -{ - m_critical_section = has_TryEnterCriticalSection(); - if (m_critical_section) - m_mutex = new_critical_section(); - else - m_mutex = new_mutex(0); -} - -try_mutex::~try_mutex() -{ - if (m_critical_section) - delete_critical_section(m_mutex); - else - delete_mutex(m_mutex); -} - -void try_mutex::do_lock() -{ - if (m_critical_section) - wait_critical_section_infinite(m_mutex); - else - wait_mutex(m_mutex, INFINITE); -} - -bool try_mutex::do_trylock() -{ - if (m_critical_section) - return wait_critical_section_try(m_mutex); - else - return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0; -} - -void try_mutex::do_unlock() -{ - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); -} - -void try_mutex::do_lock(cv_state&) -{ - do_lock(); -} - -void try_mutex::do_unlock(cv_state&) -{ - do_unlock(); -} - timed_mutex::timed_mutex() : m_mutex(0) { diff --git a/src/read_write_mutex.cpp b/src/read_write_mutex.cpp index 484645af..5ee25c99 100644 --- a/src/read_write_mutex.cpp +++ b/src/read_write_mutex.cpp @@ -23,6 +23,8 @@ bad things happen. #include +#ifndef BOOST_HAS_WINTHREADS + #include #include #include @@ -33,76 +35,6 @@ bad things happen. # include #endif -#ifdef BOOST_HAS_WINTHREADS -# include -# include -# include - -# if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) - inline bool IsDebuggerPresent(void) - { - return false; - } -# endif -# if !defined(OutputDebugString) - inline void OutputDebugStringA(LPCSTR) - {} - inline void OutputDebugStringW(LPCWSTR) - {} - #define OutputDebugString(str) -# endif - -# if defined(BOOST_READ_WRITE_MUTEX_USE_TRACE) && !defined(BOOST_NO_STRINGSTREAM) - inline void DoTrace( - const char* message, - int state, - int num_waiting_writers, - int num_waiting_readers, - bool state_waiting_promotion, - int num_waking_writers, - int num_waking_readers, - int num_max_waking_writers, - int num_max_waking_readers, - bool readers_next - ) - { - std::ostringstream stream; - stream - << std::endl - << "***** " - << std::hex << GetCurrentThreadId() << std::dec << " " - << message << " " - << state << " " - << "[" - << num_waiting_writers << " " - << num_waking_writers << " " - << num_max_waking_writers - << "] [" - << num_waiting_readers << " " - << num_waking_readers << " " - << num_max_waking_readers - << "]" << " " - << state_waiting_promotion << " " - << readers_next - << std::endl; - ::OutputDebugStringA(stream.str().c_str()); - } - -# define BOOST_READ_WRITE_MUTEX_TRACE(message) \ - DoTrace( \ - message, \ - m_state, \ - m_num_waiting_writers, \ - m_num_waiting_readers, \ - m_state_waiting_promotion, \ - m_num_waking_writers, \ - m_num_waking_readers, \ - m_num_max_waking_writers, \ - m_num_max_waking_readers, \ - m_readers_next \ - ) -# endif -#endif #if !defined(BOOST_READ_WRITE_MUTEX_TRACE) # define BOOST_READ_WRITE_MUTEX_TRACE(message) @@ -1724,6 +1656,7 @@ read_write_lock_state::read_write_lock_state_enum timed_read_write_mutex::state( template class boost::detail::thread::scoped_timed_write_lock; #endif } // namespace boost +#endif // Change Log: // 10 Mar 02