You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
418 lines
13 KiB
418 lines
13 KiB
#ifndef BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP |
|
#define BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP |
|
// 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 2007-8 Anthony Williams |
|
|
|
#include <boost/thread/mutex.hpp> |
|
#include "thread_primitives.hpp" |
|
#include <limits.h> |
|
#include <boost/assert.hpp> |
|
#include <algorithm> |
|
#include <boost/thread/thread.hpp> |
|
#include <boost/thread/thread_time.hpp> |
|
#include "interlocked_read.hpp" |
|
#include <boost/thread/xtime.hpp> |
|
#include <vector> |
|
#include <boost/intrusive_ptr.hpp> |
|
|
|
#include <boost/config/abi_prefix.hpp> |
|
|
|
namespace boost |
|
{ |
|
namespace detail |
|
{ |
|
class basic_cv_list_entry; |
|
void intrusive_ptr_add_ref(basic_cv_list_entry * p); |
|
void intrusive_ptr_release(basic_cv_list_entry * p); |
|
|
|
class basic_cv_list_entry |
|
{ |
|
private: |
|
detail::win32::handle_manager semaphore; |
|
detail::win32::handle_manager wake_sem; |
|
long waiters; |
|
bool notified; |
|
long references; |
|
|
|
basic_cv_list_entry(basic_cv_list_entry&); |
|
void operator=(basic_cv_list_entry&); |
|
|
|
public: |
|
explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_): |
|
semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)), |
|
wake_sem(wake_sem_.duplicate()), |
|
waiters(1),notified(false),references(0) |
|
{} |
|
|
|
static bool no_waiters(boost::intrusive_ptr<basic_cv_list_entry> const& entry) |
|
{ |
|
return !detail::interlocked_read_acquire(&entry->waiters); |
|
} |
|
|
|
void add_waiter() |
|
{ |
|
BOOST_INTERLOCKED_INCREMENT(&waiters); |
|
} |
|
|
|
void remove_waiter() |
|
{ |
|
BOOST_INTERLOCKED_DECREMENT(&waiters); |
|
} |
|
|
|
void release(unsigned count_to_release) |
|
{ |
|
notified=true; |
|
detail::win32::ReleaseSemaphore(semaphore,count_to_release,0); |
|
} |
|
|
|
void release_waiters() |
|
{ |
|
release(detail::interlocked_read_acquire(&waiters)); |
|
} |
|
|
|
bool is_notified() const |
|
{ |
|
return notified; |
|
} |
|
|
|
bool wait(timeout wait_until) |
|
{ |
|
return this_thread::interruptible_wait(semaphore,wait_until); |
|
} |
|
|
|
bool woken() |
|
{ |
|
unsigned long const woken_result=detail::win32::WaitForSingleObject(wake_sem,0); |
|
BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0)); |
|
return woken_result==0; |
|
} |
|
|
|
friend void intrusive_ptr_add_ref(basic_cv_list_entry * p); |
|
friend void intrusive_ptr_release(basic_cv_list_entry * p); |
|
}; |
|
|
|
inline void intrusive_ptr_add_ref(basic_cv_list_entry * p) |
|
{ |
|
BOOST_INTERLOCKED_INCREMENT(&p->references); |
|
} |
|
|
|
inline void intrusive_ptr_release(basic_cv_list_entry * p) |
|
{ |
|
if(!BOOST_INTERLOCKED_DECREMENT(&p->references)) |
|
{ |
|
delete p; |
|
} |
|
} |
|
|
|
class basic_condition_variable |
|
{ |
|
boost::mutex internal_mutex; |
|
long total_count; |
|
unsigned active_generation_count; |
|
|
|
typedef basic_cv_list_entry list_entry; |
|
|
|
typedef boost::intrusive_ptr<list_entry> entry_ptr; |
|
typedef std::vector<entry_ptr> generation_list; |
|
|
|
generation_list generations; |
|
detail::win32::handle_manager wake_sem; |
|
|
|
void wake_waiters(long count_to_wake) |
|
{ |
|
detail::interlocked_write_release(&total_count,total_count-count_to_wake); |
|
detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0); |
|
} |
|
|
|
template<typename lock_type> |
|
struct relocker |
|
{ |
|
lock_type& lock; |
|
bool unlocked; |
|
|
|
relocker(lock_type& lock_): |
|
lock(lock_),unlocked(false) |
|
{} |
|
void unlock() |
|
{ |
|
lock.unlock(); |
|
unlocked=true; |
|
} |
|
~relocker() |
|
{ |
|
if(unlocked) |
|
{ |
|
lock.lock(); |
|
} |
|
|
|
} |
|
private: |
|
relocker(relocker&); |
|
void operator=(relocker&); |
|
}; |
|
|
|
|
|
entry_ptr get_wait_entry() |
|
{ |
|
boost::lock_guard<boost::mutex> internal_lock(internal_mutex); |
|
|
|
if(!wake_sem) |
|
{ |
|
wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); |
|
BOOST_ASSERT(wake_sem); |
|
} |
|
|
|
detail::interlocked_write_release(&total_count,total_count+1); |
|
if(generations.empty() || generations.back()->is_notified()) |
|
{ |
|
entry_ptr new_entry(new list_entry(wake_sem)); |
|
generations.push_back(new_entry); |
|
return new_entry; |
|
} |
|
else |
|
{ |
|
generations.back()->add_waiter(); |
|
return generations.back(); |
|
} |
|
} |
|
|
|
struct entry_manager |
|
{ |
|
entry_ptr const entry; |
|
|
|
entry_manager(entry_ptr const& entry_): |
|
entry(entry_) |
|
{} |
|
|
|
~entry_manager() |
|
{ |
|
entry->remove_waiter(); |
|
} |
|
|
|
list_entry* operator->() |
|
{ |
|
return entry.get(); |
|
} |
|
|
|
private: |
|
void operator=(entry_manager&); |
|
entry_manager(entry_manager&); |
|
}; |
|
|
|
|
|
protected: |
|
template<typename lock_type> |
|
bool do_wait(lock_type& lock,timeout wait_until) |
|
{ |
|
relocker<lock_type> locker(lock); |
|
|
|
entry_manager entry(get_wait_entry()); |
|
|
|
locker.unlock(); |
|
|
|
bool woken=false; |
|
while(!woken) |
|
{ |
|
if(!entry->wait(wait_until)) |
|
{ |
|
return false; |
|
} |
|
|
|
woken=entry->woken(); |
|
} |
|
return woken; |
|
} |
|
|
|
template<typename lock_type,typename predicate_type> |
|
bool do_wait(lock_type& m,timeout const& wait_until,predicate_type pred) |
|
{ |
|
while (!pred()) |
|
{ |
|
if(!do_wait(m, wait_until)) |
|
return pred(); |
|
} |
|
return true; |
|
} |
|
|
|
basic_condition_variable(const basic_condition_variable& other); |
|
basic_condition_variable& operator=(const basic_condition_variable& other); |
|
|
|
public: |
|
basic_condition_variable(): |
|
total_count(0),active_generation_count(0),wake_sem(0) |
|
{} |
|
|
|
~basic_condition_variable() |
|
{} |
|
|
|
void notify_one() |
|
{ |
|
if(detail::interlocked_read_acquire(&total_count)) |
|
{ |
|
boost::lock_guard<boost::mutex> internal_lock(internal_mutex); |
|
if(!total_count) |
|
{ |
|
return; |
|
} |
|
wake_waiters(1); |
|
|
|
for(generation_list::iterator it=generations.begin(), |
|
end=generations.end(); |
|
it!=end;++it) |
|
{ |
|
(*it)->release(1); |
|
} |
|
generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end()); |
|
} |
|
} |
|
|
|
void notify_all() |
|
{ |
|
if(detail::interlocked_read_acquire(&total_count)) |
|
{ |
|
boost::lock_guard<boost::mutex> internal_lock(internal_mutex); |
|
if(!total_count) |
|
{ |
|
return; |
|
} |
|
wake_waiters(total_count); |
|
for(generation_list::iterator it=generations.begin(), |
|
end=generations.end(); |
|
it!=end;++it) |
|
{ |
|
(*it)->release_waiters(); |
|
} |
|
generations.clear(); |
|
wake_sem=detail::win32::handle(0); |
|
} |
|
} |
|
|
|
}; |
|
} |
|
|
|
class condition_variable: |
|
private detail::basic_condition_variable |
|
{ |
|
private: |
|
condition_variable(condition_variable&); |
|
void operator=(condition_variable&); |
|
public: |
|
condition_variable() |
|
{} |
|
|
|
using detail::basic_condition_variable::notify_one; |
|
using detail::basic_condition_variable::notify_all; |
|
|
|
void wait(unique_lock<mutex>& m) |
|
{ |
|
do_wait(m,detail::timeout::sentinel()); |
|
} |
|
|
|
template<typename predicate_type> |
|
void wait(unique_lock<mutex>& m,predicate_type pred) |
|
{ |
|
while(!pred()) wait(m); |
|
} |
|
|
|
|
|
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until) |
|
{ |
|
return do_wait(m,wait_until); |
|
} |
|
|
|
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until) |
|
{ |
|
return do_wait(m,system_time(wait_until)); |
|
} |
|
template<typename duration_type> |
|
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration) |
|
{ |
|
return do_wait(m,wait_duration.total_milliseconds()); |
|
} |
|
|
|
template<typename predicate_type> |
|
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until,predicate_type pred) |
|
{ |
|
return do_wait(m,wait_until,pred); |
|
} |
|
template<typename predicate_type> |
|
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until,predicate_type pred) |
|
{ |
|
return do_wait(m,system_time(wait_until),pred); |
|
} |
|
template<typename duration_type,typename predicate_type> |
|
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred) |
|
{ |
|
return do_wait(m,wait_duration.total_milliseconds(),pred); |
|
} |
|
}; |
|
|
|
class condition_variable_any: |
|
private detail::basic_condition_variable |
|
{ |
|
private: |
|
condition_variable_any(condition_variable_any&); |
|
void operator=(condition_variable_any&); |
|
public: |
|
condition_variable_any() |
|
{} |
|
|
|
using detail::basic_condition_variable::notify_one; |
|
using detail::basic_condition_variable::notify_all; |
|
|
|
template<typename lock_type> |
|
void wait(lock_type& m) |
|
{ |
|
do_wait(m,detail::timeout::sentinel()); |
|
} |
|
|
|
template<typename lock_type,typename predicate_type> |
|
void wait(lock_type& m,predicate_type pred) |
|
{ |
|
while(!pred()) wait(m); |
|
} |
|
|
|
template<typename lock_type> |
|
bool timed_wait(lock_type& m,boost::system_time const& wait_until) |
|
{ |
|
return do_wait(m,wait_until); |
|
} |
|
|
|
template<typename lock_type> |
|
bool timed_wait(lock_type& m,boost::xtime const& wait_until) |
|
{ |
|
return do_wait(m,system_time(wait_until)); |
|
} |
|
|
|
template<typename lock_type,typename duration_type> |
|
bool timed_wait(lock_type& m,duration_type const& wait_duration) |
|
{ |
|
return do_wait(m,wait_duration.total_milliseconds()); |
|
} |
|
|
|
template<typename lock_type,typename predicate_type> |
|
bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred) |
|
{ |
|
return do_wait(m,wait_until,pred); |
|
} |
|
|
|
template<typename lock_type,typename predicate_type> |
|
bool timed_wait(lock_type& m,boost::xtime const& wait_until,predicate_type pred) |
|
{ |
|
return do_wait(m,system_time(wait_until),pred); |
|
} |
|
|
|
template<typename lock_type,typename duration_type,typename predicate_type> |
|
bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred) |
|
{ |
|
return do_wait(m,wait_duration.total_milliseconds(),pred); |
|
} |
|
}; |
|
|
|
} |
|
|
|
#include <boost/config/abi_suffix.hpp> |
|
|
|
#endif
|
|
|