diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index ee221575..de19e779 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -25,7 +25,6 @@ lib boost_thread_pthread pthread/condition.cpp pthread/exceptions.cpp pthread/xtime.cpp - pthread/once.cpp pthread/tss.cpp : ## requirements ## BOOST_THREAD_POSIX @@ -41,7 +40,6 @@ lib boost_thread pthread/condition.cpp pthread/exceptions.cpp pthread/xtime.cpp - pthread/once.cpp pthread/tss.cpp : ## requirements ## BOOST_THREAD_POSIX diff --git a/include/boost/thread/condition.hpp b/include/boost/thread/condition.hpp index 88a04fa2..1dc7d9e6 100644 --- a/include/boost/thread/condition.hpp +++ b/include/boost/thread/condition.hpp @@ -1,16 +1,57 @@ -// Copyright 2006 Roland Schwarz. +#ifndef BOOST_THREAD_CONDITION_HPP +#define BOOST_THREAD_CONDITION_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) -// -// This work is a reimplementation along the design and ideas -// of William E. Kempf. - -#ifndef BOOST_THREAD_RS06040706_HPP -#define BOOST_THREAD_RS06040706_HPP +// (C) Copyright 2007 Anthony Williams #include -#include BOOST_THREAD_PLATFORM(condition.hpp) +#include BOOST_THREAD_PLATFORM(condition_state.hpp) -#endif // BOOST_THREAD_RS06040706_HPP +namespace boost +{ + template + class condition: + private boost::detail::thread::condition_state + { + public: + typedef Mutex mutex_type; + + condition(); + explicit condition(mutex_type& m); + ~condition(); + +#ifdef BOOST_HAS_DELETED_FUNCTIONS + condition(const condition&) = delete; + condition& operator=(const condition&) = delete; +#endif + + void notify_one(); + void notify_all(); + + template + void wait(Lock& lock); + + template + void wait(Lock& lock, Predicate pred); + + template + bool timed_wait(Lock& lock, const utc_time& abs_time); + + template + bool timed_wait(Lock& lock, const utc_time& abs_time, Predicate pred); + +#ifndef BOOST_HAS_DELETED_FUNCTIONS + private: + explicit condition(condition&); + condition& operator=(condition&); +#endif + + }; +} + +#include BOOST_THREAD_PLATFORM(condition_impl.hpp) +#include + +#endif diff --git a/include/boost/thread/pthread/once.hpp b/include/boost/thread/pthread/once.hpp index 12006285..cd88f35f 100644 --- a/include/boost/thread/pthread/once.hpp +++ b/include/boost/thread/pthread/once.hpp @@ -1,25 +1,74 @@ -// Copyright (C) 2001-2003 William E. Kempf -// Copyright (C) 2006 Roland Schwarz -// 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) -// -// This work is a reimplementation along the design and ideas -// of William E. Kempf. +#ifndef BOOST_THREAD_PTHREAD_ONCE_HPP +#define BOOST_THREAD_PTHREAD_ONCE_HPP -#ifndef BOOST_ONCE_RS06092301_HPP -#define BOOST_ONCE_RS06092301_HPP +// once.hpp +// +// (C) Copyright 2007 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 namespace boost { -typedef pthread_once_t once_flag; -#define BOOST_ONCE_INIT PTHREAD_ONCE_INIT + struct once_flag + { + pthread_mutex_t mutex; + unsigned flag; + }; -void BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag); +#define BOOST_ONCE_INIT {PTHREAD_MUTEX_INITIALIZER,0} -} // namespace boost + namespace detail + { + struct pthread_mutex_scoped_lock + { + pthread_mutex_t * mutex; + + explicit pthread_mutex_scoped_lock(pthread_mutex_t* mutex_): + mutex(mutex_) + { + int const res=pthread_mutex_lock(mutex); + BOOST_ASSERT(!res); + } + ~pthread_mutex_scoped_lock() + { + int const res=pthread_mutex_unlock(mutex); + BOOST_ASSERT(!res); + } + }; + } -#endif // BOOST_ONCE_RS06092301_HPP + template + void call_once(once_flag& flag,Function f) + { + long const function_complete_flag_value=0xc15730e2; + +#ifdef BOOST_PTHREAD_HAS_ATOMICS + if(::boost::detail::interlocked_read_acquire(&flag.flag)!=function_complete_flag_value) + { +#endif + detail::pthread_mutex_scoped_lock const lock(&flag.mutex); + if(flag.flag!=function_complete_flag_value) + { + f(); +#ifdef BOOST_PTHREAD_HAS_ATOMICS + ::boost::detail::interlocked_write_release(&flag.flag,function_complete_flag_value); +#else + flag.flag=function_complete_flag_value; +#endif + } +#ifdef BOOST_PTHREAD_HAS_ATOMICS + } +#endif + } + + +} + +#endif diff --git a/include/boost/thread/win32/interlocked_read.hpp b/include/boost/thread/win32/interlocked_read.hpp index 219a4de2..b5e9b112 100644 --- a/include/boost/thread/win32/interlocked_read.hpp +++ b/include/boost/thread/win32/interlocked_read.hpp @@ -3,7 +3,7 @@ // interlocked_read_win32.hpp // -// (C) Copyright 2005-6 Anthony Williams +// (C) Copyright 2005-7 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -15,13 +15,17 @@ namespace boost { namespace detail { - inline long interlocked_read(long* x) + inline long interlocked_read_acquire(long volatile* x) { - return BOOST_INTERLOCKED_EXCHANGE_ADD(x,0); + long const res=*x; + _ReadWriteBarrier(); + return res; } - inline void* interlocked_read(void** x) + inline void* interlocked_read_acquire(void* volatile* x) { - return BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(x,0,0); + void* const res=*x; + _ReadWriteBarrier(); + return res; } } } diff --git a/include/boost/thread/win32/once.hpp b/include/boost/thread/win32/once.hpp index c21e187e..9fd499f9 100644 --- a/include/boost/thread/win32/once.hpp +++ b/include/boost/thread/win32/once.hpp @@ -3,7 +3,7 @@ // once.hpp // -// (C) Copyright 2005-6 Anthony Williams +// (C) Copyright 2005-7 Anthony Williams // (C) Copyright 2005 John Maddock // // Distributed under the Boost Software License, Version 1.0. (See @@ -35,29 +35,19 @@ namespace boost namespace detail { - struct handle_closer - { - void* const handle_to_close; - handle_closer(void* handle_to_close_): - handle_to_close(handle_to_close_) - {} - ~handle_closer() - { - win32::CloseHandle(handle_to_close); - } - }; - struct win32_mutex_scoped_lock { void* const mutex_handle; - win32_mutex_scoped_lock(void* mutex_handle_): + explicit win32_mutex_scoped_lock(void* mutex_handle_): mutex_handle(mutex_handle_) { - win32::WaitForSingleObject(mutex_handle,win32::infinite); + unsigned long const res=win32::WaitForSingleObject(mutex_handle,win32::infinite); + BOOST_ASSERT(!res); } ~win32_mutex_scoped_lock() { - win32::ReleaseMutex(mutex_handle); + bool const success=win32::ReleaseMutex(mutex_handle)!=0; + BOOST_ASSERT(success); } }; @@ -98,21 +88,21 @@ namespace boost template - void call_once(Function f,once_flag& flag) + void call_once(once_flag& flag,Function f) { // Try for a quick win: if the proceedure has already been called // just skip through: long const function_complete_flag_value=0xc15730e2; - if(::boost::detail::interlocked_read(&flag)!=function_complete_flag_value) + if(::boost::detail::interlocked_read_acquire(&flag)!=function_complete_flag_value) { char mutex_name[::boost::detail::once_mutex_name_length]; void* const mutex_handle(::boost::detail::create_once_mutex(mutex_name,&flag)); BOOST_ASSERT(mutex_handle); - detail::handle_closer const closer(mutex_handle); + detail::win32::handle_manager const closer(mutex_handle); detail::win32_mutex_scoped_lock const lock(mutex_handle); - if(::boost::detail::interlocked_read(&flag)!=function_complete_flag_value) + if(flag!=function_complete_flag_value) { f(); BOOST_INTERLOCKED_EXCHANGE(&flag,function_complete_flag_value); diff --git a/include/boost/thread/win32/thread_primitives.hpp b/include/boost/thread/win32/thread_primitives.hpp index 7b4c1109..444a7389 100644 --- a/include/boost/thread/win32/thread_primitives.hpp +++ b/include/boost/thread/win32/thread_primitives.hpp @@ -10,6 +10,8 @@ // http://www.boost.org/LICENSE_1_0.txt) #include +#include +#include #if defined( BOOST_USE_WINDOWS_H ) # include @@ -110,13 +112,84 @@ namespace boost inline handle create_anonymous_event(event_type type,initial_event_state state) { - return CreateEventA(0,type,state,0); + handle const res=CreateEventA(0,type,state,0); + return res?res:throw thread_resource_error(); } inline handle create_anonymous_semaphore(long initial_count,long max_count) { - return CreateSemaphoreA(NULL,initial_count,max_count,NULL); + handle const res=CreateSemaphoreA(NULL,initial_count,max_count,NULL); + return res?res:throw thread_resource_error(); } + + inline handle duplicate_handle(handle source) + { + handle const current_process=GetCurrentProcess(); + long const same_access_flag=2; + handle new_handle=0; + bool const success=DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0; + return success?new_handle:throw thread_resource_error(); + } + + inline void release_semaphore(handle semaphore,long count) + { + bool const success=ReleaseSemaphore(semaphore,count,0); + BOOST_ASSERT(success); + } + + class handle_manager + { + private: + handle handle_to_manage; + handle_manager(handle_manager&); + handle_manager& operator=(handle_manager&); + + void cleanup() + { + if(handle_to_manage) + { + unsigned long result=CloseHandle(handle_to_manage); + BOOST_ASSERT(result); + } + } + + public: + explicit handle_manager(handle handle_to_manage_): + handle_to_manage(handle_to_manage_) + {} + handle_manager(): + handle_to_manage(0) + {} + + handle_manager& operator=(handle new_handle) + { + cleanup(); + handle_to_manage=new_handle; + } + + operator handle() const + { + return handle_to_manage; + } + + handle release() + { + handle const res=handle_to_manage; + handle_to_manage=0; + return res; + } + + bool operator!() const + { + return !handle_to_manage; + } + + ~handle_manager() + { + cleanup(); + } + }; + } } } diff --git a/src/pthread/once.cpp b/src/pthread/once.cpp deleted file mode 100644 index 013e7578..00000000 --- a/src/pthread/once.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2001-2003 William E. Kempf -// Copyright (C) 2006 Roland Schwarz -// 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) -// -// This work is a reimplementation along the design and ideas -// of William E. Kempf. - -#include - -#include - -namespace { -pthread_key_t key; -pthread_once_t once = PTHREAD_ONCE_INIT; - -typedef void (*once_callback)(); -} - -extern "C" { - - static void key_init() - { - pthread_key_create(&key, 0); - } - - static void do_once() - { - once_callback* cb = reinterpret_cast( - pthread_getspecific(key)); - (**cb)(); - } - -} - -namespace boost { - -void call_once(void (*func)(), once_flag& flag) -{ - pthread_once(&once, &key_init); - pthread_setspecific(key, &func); - pthread_once(&flag, do_once); -} - -} diff --git a/test/test_condition.cpp b/test/test_condition.cpp index ce902fc2..4be1f15f 100644 --- a/test/test_condition.cpp +++ b/test/test_condition.cpp @@ -22,7 +22,7 @@ struct condition_test_data condition_test_data() : notified(0), awoken(0) { } boost::mutex mutex; - boost::condition condition; + boost::condition condition; int notified; int awoken; }; diff --git a/test/test_once.cpp b/test/test_once.cpp index 9e3a8a3a..f9f59b79 100644 --- a/test/test_once.cpp +++ b/test/test_once.cpp @@ -1,4 +1,4 @@ -// (C) Copyright 2006 Anthony Williams +// (C) Copyright 2006-7 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) @@ -25,7 +25,7 @@ void call_once_thread() int my_once_value=0; for(unsigned i=0;i