From 1ddf36c500c83a80a054625b4e35f5e76db3faf7 Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Mon, 14 Apr 2008 05:18:26 +0000 Subject: [PATCH] Merged revisions 44111-44378 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r44114 | emildotchevski | 2008-04-08 14:29:37 -0700 (Tue, 08 Apr 2008) | 1 line fixed compile errors, removed tabs as required. ........ r44118 | djowel | 2008-04-08 18:29:12 -0700 (Tue, 08 Apr 2008) | 7 lines In preparation for spirit2: * flat includes * home directory * forwarding headers * classic spirit ........ r44119 | djowel | 2008-04-08 18:51:47 -0700 (Tue, 08 Apr 2008) | 7 lines In preparation for spirit2: * flat includes * home directory * forwarding headers * classic spirit ........ r44120 | hkaiser | 2008-04-08 19:17:53 -0700 (Tue, 08 Apr 2008) | 1 line Fixed one more include path ........ r44121 | johnmaddock | 2008-04-09 04:34:20 -0700 (Wed, 09 Apr 2008) | 1 line Run config_info and config_test in both single and multi-thread modes. ........ r44122 | johnmaddock | 2008-04-09 04:34:45 -0700 (Wed, 09 Apr 2008) | 1 line Run config_info and config_test in both single and multi-thread modes. ........ r44123 | johnmaddock | 2008-04-09 04:35:36 -0700 (Wed, 09 Apr 2008) | 1 line Added needed #includes. ........ r44124 | johnmaddock | 2008-04-09 04:45:15 -0700 (Wed, 09 Apr 2008) | 1 line Added improved SVG support. ........ r44125 | hkaiser | 2008-04-09 06:50:03 -0700 (Wed, 09 Apr 2008) | 1 line Fixed #pragma message directives and a couple of forwarding headers. ........ r44126 | johnmaddock | 2008-04-09 08:21:03 -0700 (Wed, 09 Apr 2008) | 1 line Fix bug report #1797. ........ r44127 | johnmaddock | 2008-04-09 08:31:33 -0700 (Wed, 09 Apr 2008) | 1 line Update for bug report #1790. ........ r44128 | johnmaddock | 2008-04-09 08:32:08 -0700 (Wed, 09 Apr 2008) | 1 line Fix for bug #1790. ........ r44130 | danieljames | 2008-04-09 10:26:31 -0700 (Wed, 09 Apr 2008) | 1 line Fix a typo. ........ r44131 | danieljames | 2008-04-09 10:27:08 -0700 (Wed, 09 Apr 2008) | 1 line Rebuild the function types documentation. ........ r44132 | pdimov | 2008-04-09 10:49:20 -0700 (Wed, 09 Apr 2008) | 1 line Proper try_lock semantics. ........ r44134 | emildotchevski | 2008-04-09 11:48:39 -0700 (Wed, 09 Apr 2008) | 1 line missing include ........ r44136 | anthonyw | 2008-04-09 12:33:06 -0700 (Wed, 09 Apr 2008) | 1 line Added test for trac ticket #1803: condition_variable::notify_one may fail to wake a waiting thread on win32 ........ r44137 | pdimov | 2008-04-09 12:58:54 -0700 (Wed, 09 Apr 2008) | 1 line sp_counted_base_spin.hpp added, enabled by BOOST_SP_USE_SPINLOCK. ........ r44138 | pdimov | 2008-04-09 14:08:39 -0700 (Wed, 09 Apr 2008) | 1 line spinlock_gcc_arm.hpp added. ........ r44139 | grafik | 2008-04-09 14:20:28 -0700 (Wed, 09 Apr 2008) | 1 line Add ARM architecture/instrustion-set. ........ r44140 | pdimov | 2008-04-09 16:19:22 -0700 (Wed, 09 Apr 2008) | 1 line ARM assembly fix. ........ r44145 | johnmaddock | 2008-04-10 05:46:41 -0700 (Thu, 10 Apr 2008) | 2 lines Doh! Changes to code should actually compile! A fix for the last change. ........ r44146 | anthonyw | 2008-04-10 06:14:43 -0700 (Thu, 10 Apr 2008) | 1 line fix for notify problem in trac ticket #1803 ........ r44147 | anthonyw | 2008-04-10 06:27:44 -0700 (Thu, 10 Apr 2008) | 1 line fix for trac ticket #1804 ........ r44148 | anthonyw | 2008-04-10 06:35:07 -0700 (Thu, 10 Apr 2008) | 1 line Added native_handle to thread on posix platforms ........ r44149 | anthonyw | 2008-04-10 07:07:39 -0700 (Thu, 10 Apr 2008) | 1 line added overloads of timed_lock_shared with a relative timeout to shared_mutex ........ r44150 | anthonyw | 2008-04-10 07:15:26 -0700 (Thu, 10 Apr 2008) | 1 line added tests for plain timed_lock on shared_mutex ........ r44151 | daniel_frey | 2008-04-10 07:38:14 -0700 (Thu, 10 Apr 2008) | 1 line Added test and fix for "convertible to bool" requirement ........ r44152 | anthonyw | 2008-04-10 08:52:01 -0700 (Thu, 10 Apr 2008) | 1 line Added native_handle to condition_variable on pthreads ........ r44153 | anthonyw | 2008-04-10 11:34:42 -0700 (Thu, 10 Apr 2008) | 1 line Updated thread.hpp as catch-all header ........ r44160 | dgregor | 2008-04-10 14:05:14 -0700 (Thu, 10 Apr 2008) | 1 line Refactor mpi_datatype_cache to fix problems on VC9 ........ r44161 | danieljames | 2008-04-10 14:06:48 -0700 (Thu, 10 Apr 2008) | 2 lines Try to fix Herve's name in a couple of places. ........ r44163 | djowel | 2008-04-10 16:51:31 -0700 (Thu, 10 Apr 2008) | 1 line moving stuff to classic spirit ........ r44164 | emildotchevski | 2008-04-10 20:51:06 -0700 (Thu, 10 Apr 2008) | 1 line to_string fixes ........ r44165 | grafik | 2008-04-10 22:34:00 -0700 (Thu, 10 Apr 2008) | 1 line Use local sorted() function to support Python < 2.4. ........ r44166 | grafik | 2008-04-10 22:36:28 -0700 (Thu, 10 Apr 2008) | 1 line Add support for toolset requirements at the definition level. ........ r44167 | grafik | 2008-04-11 00:50:47 -0700 (Fri, 11 Apr 2008) | 1 line Initial support for cross-compiling to ARM architecture. ........ r44168 | anthonyw | 2008-04-11 01:52:09 -0700 (Fri, 11 Apr 2008) | 1 line Added test and fix for win32 condition_variable broadcast bug similar to #1803 ........ r44169 | johnmaddock | 2008-04-11 01:53:54 -0700 (Fri, 11 Apr 2008) | 1 line Fix doc typo from issue #1794. ........ r44170 | johnmaddock | 2008-04-11 02:21:08 -0700 (Fri, 11 Apr 2008) | 1 line Beefed up pthreads test cases. ........ r44171 | johnmaddock | 2008-04-11 02:22:31 -0700 (Fri, 11 Apr 2008) | 1 line Hopefully fix gcc/solaris single threading mode. ........ r44172 | jurko | 2008-04-11 03:51:43 -0700 (Fri, 11 Apr 2008) | 1 line Comment typo correction. ........ r44175 | dgregor | 2008-04-11 08:39:41 -0700 (Fri, 11 Apr 2008) | 1 line Fix some header-inclusion and header-ordering issues to get the MPI library compiling again. ........ r44186 | johnmaddock | 2008-04-11 10:54:47 -0700 (Fri, 11 Apr 2008) | 1 line Disable long double tests on unsupported platforms. ........ r44187 | johnmaddock | 2008-04-11 10:57:58 -0700 (Fri, 11 Apr 2008) | 1 line We don't need duplicate using declarations. ........ r44188 | johnmaddock | 2008-04-11 11:08:59 -0700 (Fri, 11 Apr 2008) | 1 line Update error levels for real_concept tests. ........ r44189 | johnmaddock | 2008-04-11 11:12:02 -0700 (Fri, 11 Apr 2008) | 1 line Update tolerance used for skewness test. ........ r44190 | hkaiser | 2008-04-11 11:19:46 -0700 (Fri, 11 Apr 2008) | 1 line Fixed reference to Spirit classic test suite ........ r44192 | emildotchevski | 2008-04-11 11:34:46 -0700 (Fri, 11 Apr 2008) | 1 line to_string adjustments ........ r44195 | jurko | 2008-04-11 14:03:06 -0700 (Fri, 11 Apr 2008) | 1 line Implemented a patch contributed by Igor Nazarenko reimplementing the list_sort() function to use a C qsort() function instead of a hand-crafted merge-sort algorithm. Makes some list sortings (e.g. 1,2,1,2,1,2,1,2,...) extremely faster, in turn significantly speeding up some project builds. ........ r44196 | hkaiser | 2008-04-11 15:01:55 -0700 (Fri, 11 Apr 2008) | 1 line Changed SpiritV1 header files to have a classic_ prefix ........ r44197 | hkaiser | 2008-04-11 15:05:25 -0700 (Fri, 11 Apr 2008) | 1 line Renamed a SpiritV1 header file I missed before ........ r44198 | hkaiser | 2008-04-11 19:35:34 -0700 (Fri, 11 Apr 2008) | 1 line Renamed PhoenixV1 files. ........ r44203 | hkaiser | 2008-04-11 20:00:17 -0700 (Fri, 11 Apr 2008) | 1 line Fixed an ambiguity. ........ r44206 | hkaiser | 2008-04-11 20:02:34 -0700 (Fri, 11 Apr 2008) | 1 line Fixed more SpiritV1 header references after renaming ........ r44246 | emildotchevski | 2008-04-11 20:27:57 -0700 (Fri, 11 Apr 2008) | 1 line removed tabs. what's wrong with tabs anyway? ........ r44342 | emildotchevski | 2008-04-11 23:08:10 -0700 (Fri, 11 Apr 2008) | 1 line documentation cleanup ........ r44343 | speedsnail | 2008-04-12 04:02:35 -0700 (Sat, 12 Apr 2008) | 2 lines Fixed a bug in for seldom used argument in rule format-name. Added /property-name/ may be a regex. ........ r44344 | pdimov | 2008-04-12 07:27:22 -0700 (Sat, 12 Apr 2008) | 1 line shared_ptr::lock no longer requires exceptions. ........ r44346 | johnmaddock | 2008-04-12 09:01:16 -0700 (Sat, 12 Apr 2008) | 1 line Remove references to Boost.Test from the config_test target. ........ r44347 | johnmaddock | 2008-04-12 09:02:24 -0700 (Sat, 12 Apr 2008) | 1 line When -lrt is needed, it's needed in *both* single and multi-threaded builds. ........ r44350 | johnmaddock | 2008-04-12 09:27:11 -0700 (Sat, 12 Apr 2008) | 2 lines Add non central distro's to fwd.hpp. Added needed #include to bessel_ik.hpp. ........ r44351 | johnmaddock | 2008-04-12 09:28:57 -0700 (Sat, 12 Apr 2008) | 3 lines Fix declaration order in dist_nc_beta_incl_test.cpp test. Fix long long usage in sf_modf_incl_test.cpp. Adjust failure rates in test_zeta.cpp to cope with HP aCC and 128-bit long doubles. ........ r44352 | johnmaddock | 2008-04-12 09:42:28 -0700 (Sat, 12 Apr 2008) | 1 line Remove test row that causes problems for VC-7.1 due to a compiler bug. ........ r44353 | pdimov | 2008-04-12 11:22:18 -0700 (Sat, 12 Apr 2008) | 1 line sp_accept_owner added. ........ r44354 | grafik | 2008-04-12 12:44:47 -0700 (Sat, 12 Apr 2008) | 1 line Add multiple requirements for toolset subconditions instead of one composite as they are not supported for conditional requirements. Thanks to Roland for finding the problem. ........ r44355 | hkaiser | 2008-04-12 16:58:29 -0700 (Sat, 12 Apr 2008) | 1 line Changed copyright, started to apply changes for switching namespaces. ........ r44356 | djowel | 2008-04-12 17:15:11 -0700 (Sat, 12 Apr 2008) | 1 line added flat forwarding headers ........ r44357 | djowel | 2008-04-12 17:39:00 -0700 (Sat, 12 Apr 2008) | 1 line added flat forwarding headers ........ r44358 | djowel | 2008-04-12 17:54:10 -0700 (Sat, 12 Apr 2008) | 1 line adding spirit2 ........ r44359 | djowel | 2008-04-12 18:52:31 -0700 (Sat, 12 Apr 2008) | 1 line spirit2 ! :) ........ r44360 | djowel | 2008-04-12 20:02:30 -0700 (Sat, 12 Apr 2008) | 1 line spirit2 ! :) ........ r44361 | djowel | 2008-04-12 20:17:57 -0700 (Sat, 12 Apr 2008) | 1 line spirit2 ! :) ........ r44367 | andreas_huber69 | 2008-04-13 06:57:42 -0700 (Sun, 13 Apr 2008) | 1 line Changed the PingPong example to demonstrate how the inner workings of an asynchronous_state_machine<> subclass can be hidden. ........ r44369 | pdimov | 2008-04-13 08:35:40 -0700 (Sun, 13 Apr 2008) | 1 line Honor BOOST_DISABLE_THREADS; route GCC/ARM to the spinlock implementation; fall back to the spinlock implementation instead of using pthread_mutex. ........ r44370 | anthonyw | 2008-04-13 08:50:08 -0700 (Sun, 13 Apr 2008) | 1 line Added extended adopt/defer/try constructors to upgrade_lock ........ r44371 | hkaiser | 2008-04-13 09:28:27 -0700 (Sun, 13 Apr 2008) | 1 line Fixed Spirit Classic namespace switching. ........ r44372 | emildotchevski | 2008-04-13 10:07:26 -0700 (Sun, 13 Apr 2008) | 1 line minor compile error fix ........ r44374 | hkaiser | 2008-04-13 15:00:04 -0700 (Sun, 13 Apr 2008) | 1 line Added SpiritV2 test suite to regression tests. ........ r44376 | grafik | 2008-04-13 15:12:12 -0700 (Sun, 13 Apr 2008) | 1 line Move array test into canonical test subdir structure. ........ r44377 | grafik | 2008-04-13 15:24:41 -0700 (Sun, 13 Apr 2008) | 1 line Move crc test into canonical test subdir structure. ........ [SVN r44393] --- include/boost/thread.hpp | 8 +- include/boost/thread/locks.hpp | 13 +- .../thread/pthread/condition_variable_fwd.hpp | 6 + include/boost/thread/pthread/mutex.hpp | 2 +- include/boost/thread/pthread/shared_mutex.hpp | 18 ++ include/boost/thread/pthread/thread.hpp | 3 + .../boost/thread/win32/condition_variable.hpp | 94 +++++-- include/boost/thread/win32/shared_mutex.hpp | 12 + src/pthread/thread.cpp | 15 ++ test/Jamfile.v2 | 1 + test/shared_mutex_locking_thread.hpp | 62 +++++ test/test_condition_notify_all.cpp | 42 ++++ test/test_condition_notify_one.cpp | 42 ++++ test/test_shared_mutex_part_2.cpp | 96 ------- test/test_shared_mutex_timed_locks.cpp | 235 ++++++++++++++++++ 15 files changed, 524 insertions(+), 125 deletions(-) create mode 100644 test/test_shared_mutex_timed_locks.cpp diff --git a/include/boost/thread.hpp b/include/boost/thread.hpp index 625e69ec..f0a39c3b 100644 --- a/include/boost/thread.hpp +++ b/include/boost/thread.hpp @@ -1,5 +1,6 @@ // Copyright (C) 2001-2003 // William E. Kempf +// (C) Copyright 2008 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) @@ -10,12 +11,15 @@ #define BOOST_THREAD_WEK01082003_HPP #include -#include +#include #include #include #include #include #include -#include +#include +#include +#include +#include #endif diff --git a/include/boost/thread/locks.hpp b/include/boost/thread/locks.hpp index c056206b..741a2a47 100644 --- a/include/boost/thread/locks.hpp +++ b/include/boost/thread/locks.hpp @@ -400,13 +400,16 @@ namespace boost { lock(); } - upgrade_lock(Mutex& m_,bool do_lock): + upgrade_lock(Mutex& m_,adopt_lock_t): + m(&m_),is_locked(true) + {} + upgrade_lock(Mutex& m_,defer_lock_t): + m(&m_),is_locked(false) + {} + upgrade_lock(Mutex& m_,try_to_lock_t): m(&m_),is_locked(false) { - if(do_lock) - { - lock(); - } + try_lock(); } upgrade_lock(detail::thread_move_t > other): m(other->m),is_locked(other->is_locked) diff --git a/include/boost/thread/pthread/condition_variable_fwd.hpp b/include/boost/thread/pthread/condition_variable_fwd.hpp index 1d1fbdf4..37884dd9 100644 --- a/include/boost/thread/pthread/condition_variable_fwd.hpp +++ b/include/boost/thread/pthread/condition_variable_fwd.hpp @@ -58,6 +58,12 @@ namespace boost return timed_wait(m,get_system_time()+wait_duration,pred); } + typedef pthread_cond_t* native_handle_type; + native_handle_type native_handle() + { + return &cond; + } + void notify_one(); void notify_all(); }; diff --git a/include/boost/thread/pthread/mutex.hpp b/include/boost/thread/pthread/mutex.hpp index 89a2bb94..3044a25b 100644 --- a/include/boost/thread/pthread/mutex.hpp +++ b/include/boost/thread/pthread/mutex.hpp @@ -136,7 +136,7 @@ namespace boost { struct timespec const timeout=detail::get_timespec(abs_time); int const res=pthread_mutex_timedlock(&m,&timeout); - BOOST_ASSERT(!res || res==EBUSY); + BOOST_ASSERT(!res || res==ETIMEDOUT); return !res; } #else diff --git a/include/boost/thread/pthread/shared_mutex.hpp b/include/boost/thread/pthread/shared_mutex.hpp index 4465f559..1648150d 100644 --- a/include/boost/thread/pthread/shared_mutex.hpp +++ b/include/boost/thread/pthread/shared_mutex.hpp @@ -118,6 +118,12 @@ namespace boost } } + template + bool timed_lock_shared(TimeDuration const & relative_time) + { + return timed_lock_shared(get_system_time()+relative_time); + } + void unlock_shared() { boost::mutex::scoped_lock lock(state_change); @@ -196,6 +202,12 @@ namespace boost } } + template + bool timed_lock(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } + bool try_lock() { boost::mutex::scoped_lock lock(state_change); @@ -271,6 +283,12 @@ namespace boost } } + template + bool timed_lock_upgrade(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } + bool try_lock_upgrade() { boost::mutex::scoped_lock lock(state_change); diff --git a/include/boost/thread/pthread/thread.hpp b/include/boost/thread/pthread/thread.hpp index 6a2ac3d9..813ced09 100644 --- a/include/boost/thread/pthread/thread.hpp +++ b/include/boost/thread/pthread/thread.hpp @@ -214,6 +214,9 @@ namespace boost static void sleep(const system_time& xt); static void yield(); + typedef pthread_t native_handle_type; + native_handle_type native_handle(); + // extensions void interrupt(); bool interruption_requested() const; diff --git a/include/boost/thread/win32/condition_variable.hpp b/include/boost/thread/win32/condition_variable.hpp index 6bd4efd6..e606258d 100644 --- a/include/boost/thread/win32/condition_variable.hpp +++ b/include/boost/thread/win32/condition_variable.hpp @@ -34,6 +34,12 @@ namespace boost list_entry(): semaphore(0),count(0),notified(0) {} + + void release(unsigned count_to_release=1) + { + detail::win32::ReleaseSemaphore(semaphore,count_to_release,0); + } + }; BOOST_STATIC_CONSTANT(unsigned,generation_count=3); @@ -41,6 +47,13 @@ namespace boost list_entry generations[generation_count]; detail::win32::handle 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); + } + + static bool no_waiters(list_entry const& entry) { return entry.count==0; @@ -51,7 +64,7 @@ namespace boost list_entry* const last_active_entry=std::remove_if(generations,generations+generation_count,no_waiters); if(last_active_entry==generations+generation_count) { - broadcast_entry(generations[generation_count-1],false); + broadcast_entry(generations[generation_count-1]); } else { @@ -69,15 +82,9 @@ namespace boost generations[0]=list_entry(); } - void broadcast_entry(list_entry& entry,bool wake) + void broadcast_entry(list_entry& entry) { - long const count_to_wake=entry.count; - detail::interlocked_write_release(&total_count,total_count-count_to_wake); - if(wake) - { - detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0); - } - detail::win32::ReleaseSemaphore(entry.semaphore,count_to_wake,0); + entry.release(entry.count); entry.count=0; dispose_entry(entry); } @@ -124,6 +131,7 @@ namespace boost void start_wait_loop_first_time(relocker& locker, detail::win32::handle_manager& local_wake_sem) { + detail::interlocked_write_release(&total_count,total_count+1); locker.unlock(); if(!wake_sem) { @@ -141,6 +149,15 @@ namespace boost active_generation_count=1; } } + + void ensure_generation_present() + { + if(!generations[0].semaphore) + { + generations[0].semaphore=detail::win32::create_anonymous_semaphore(0,LONG_MAX); + BOOST_ASSERT(generations[0].semaphore); + } + } template void start_wait_loop(relocker& locker, @@ -148,16 +165,11 @@ namespace boost detail::win32::handle_manager& sem) { boost::mutex::scoped_lock internal_lock(internal_mutex); - detail::interlocked_write_release(&total_count,total_count+1); if(!local_wake_sem) { start_wait_loop_first_time(locker,local_wake_sem); } - if(!generations[0].semaphore) - { - generations[0].semaphore=detail::win32::create_anonymous_semaphore(0,LONG_MAX); - BOOST_ASSERT(generations[0].semaphore); - } + ensure_generation_present(); ++generations[0].count; sem=detail::win32::duplicate_handle(generations[0].semaphore); } @@ -222,15 +234,22 @@ namespace boost if(detail::interlocked_read_acquire(&total_count)) { boost::mutex::scoped_lock internal_lock(internal_mutex); - detail::win32::ReleaseSemaphore(wake_sem,1,0); + if(!total_count) + { + return; + } + wake_waiters(1); + + unsigned waiting_count=0; + for(unsigned generation=active_generation_count;generation!=0;--generation) { list_entry& entry=generations[generation-1]; + waiting_count+=entry.count; if(entry.count) { - detail::interlocked_write_release(&total_count,total_count-1); entry.notified=true; - detail::win32::ReleaseSemaphore(entry.semaphore,1,0); + entry.release(); if(!--entry.count) { dispose_entry(entry); @@ -241,6 +260,12 @@ namespace boost } } } + if(waiting_count<=total_count) + { + shift_generations_down(); + ensure_generation_present(); + generations[0].release(); + } } } @@ -249,14 +274,23 @@ namespace boost if(detail::interlocked_read_acquire(&total_count)) { boost::mutex::scoped_lock internal_lock(internal_mutex); + long waiting_count=total_count; + + wake_waiters(total_count); for(unsigned generation=active_generation_count;generation!=0;--generation) { list_entry& entry=generations[generation-1]; if(entry.count) { - broadcast_entry(entry,true); + waiting_count-=entry.count; + broadcast_entry(entry); } } + if(waiting_count) + { + ensure_generation_present(); + generations[0].release(waiting_count); + } active_generation_count=0; } } @@ -265,9 +299,18 @@ namespace boost } class condition_variable: - public detail::basic_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& m) { do_wait(m,detail::timeout::sentinel()); @@ -313,9 +356,18 @@ namespace boost }; class condition_variable_any: - public detail::basic_condition_variable + 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 void wait(lock_type& m) { diff --git a/include/boost/thread/win32/shared_mutex.hpp b/include/boost/thread/win32/shared_mutex.hpp index 1c9fd1be..1862cfdd 100644 --- a/include/boost/thread/win32/shared_mutex.hpp +++ b/include/boost/thread/win32/shared_mutex.hpp @@ -120,6 +120,12 @@ namespace boost BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel())); } + template + bool timed_lock_shared(TimeDuration const & relative_time) + { + return timed_lock_shared(get_system_time()+relative_time); + } + bool timed_lock_shared(boost::system_time const& wait_until) { #ifdef BOOST_MSVC @@ -269,6 +275,12 @@ namespace boost BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel())); } + template + bool timed_lock(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } + bool timed_lock(boost::system_time const& wait_until) { #ifdef BOOST_MSVC diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp index 754e0af5..3cd6a86a 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -472,6 +472,21 @@ namespace boost return false; } } + + thread::native_handle_type thread::native_handle() + { + detail::thread_data_ptr const local_thread_info=get_thread_info(); + if(local_thread_info) + { + lock_guard lk(local_thread_info->data_mutex); + return local_thread_info->thread_handle; + } + else + { + return pthread_t(); + } + } + namespace this_thread diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 0145cf5b..04dab7af 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -51,6 +51,7 @@ rule thread-run ( sources ) [ thread-run test_barrier.cpp ] [ thread-run test_shared_mutex.cpp ] [ thread-run test_shared_mutex_part_2.cpp ] + [ thread-run test_shared_mutex_timed_locks.cpp ] [ thread-run test_lock_concept.cpp ] ; } diff --git a/test/shared_mutex_locking_thread.hpp b/test/shared_mutex_locking_thread.hpp index 0d071bd8..98a415b1 100644 --- a/test/shared_mutex_locking_thread.hpp +++ b/test/shared_mutex_locking_thread.hpp @@ -66,5 +66,67 @@ private: void operator=(locking_thread&); }; +class simple_writing_thread +{ + boost::shared_mutex& rwm; + boost::mutex& finish_mutex; + boost::mutex& unblocked_mutex; + unsigned& unblocked_count; + + void operator=(simple_writing_thread&); + +public: + simple_writing_thread(boost::shared_mutex& rwm_, + boost::mutex& finish_mutex_, + boost::mutex& unblocked_mutex_, + unsigned& unblocked_count_): + rwm(rwm_),finish_mutex(finish_mutex_), + unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_) + {} + + void operator()() + { + boost::unique_lock lk(rwm); + + { + boost::mutex::scoped_lock ulk(unblocked_mutex); + ++unblocked_count; + } + + boost::mutex::scoped_lock flk(finish_mutex); + } +}; + +class simple_reading_thread +{ + boost::shared_mutex& rwm; + boost::mutex& finish_mutex; + boost::mutex& unblocked_mutex; + unsigned& unblocked_count; + + void operator=(simple_reading_thread&); + +public: + simple_reading_thread(boost::shared_mutex& rwm_, + boost::mutex& finish_mutex_, + boost::mutex& unblocked_mutex_, + unsigned& unblocked_count_): + rwm(rwm_),finish_mutex(finish_mutex_), + unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_) + {} + + void operator()() + { + boost::shared_lock lk(rwm); + + { + boost::mutex::scoped_lock ulk(unblocked_mutex); + ++unblocked_count; + } + + boost::mutex::scoped_lock flk(finish_mutex); + } +}; + #endif diff --git a/test/test_condition_notify_all.cpp b/test/test_condition_notify_all.cpp index 22074b44..11a983eb 100644 --- a/test/test_condition_notify_all.cpp +++ b/test/test_condition_notify_all.cpp @@ -159,6 +159,47 @@ void do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate( } } +namespace +{ + boost::mutex multiple_wake_mutex; + boost::condition_variable multiple_wake_cond; + unsigned multiple_wake_count=0; + + void wait_for_condvar_and_increase_count() + { + boost::mutex::scoped_lock lk(multiple_wake_mutex); + multiple_wake_cond.wait(lk); + ++multiple_wake_count; + } + +} + + +void do_test_notify_all_following_notify_one_wakes_all_threads() +{ + boost::thread thread1(wait_for_condvar_and_increase_count); + boost::thread thread2(wait_for_condvar_and_increase_count); + + boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + multiple_wake_cond.notify_one(); + + boost::thread thread3(wait_for_condvar_and_increase_count); + + boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + multiple_wake_cond.notify_one(); + multiple_wake_cond.notify_all(); + boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + + { + boost::mutex::scoped_lock lk(multiple_wake_mutex); + BOOST_CHECK(multiple_wake_count==3); + } + + thread1.join(); + thread2.join(); + thread3.join(); +} + void test_condition_notify_all() { timed_test(&do_test_condition_notify_all_wakes_from_wait, timeout_seconds); @@ -166,6 +207,7 @@ void test_condition_notify_all() timed_test(&do_test_condition_notify_all_wakes_from_timed_wait, timeout_seconds); timed_test(&do_test_condition_notify_all_wakes_from_timed_wait_with_predicate, timeout_seconds); timed_test(&do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate, timeout_seconds); + timed_test(&do_test_notify_all_following_notify_one_wakes_all_threads, timeout_seconds); } diff --git a/test/test_condition_notify_one.cpp b/test/test_condition_notify_one.cpp index 45447bd4..a5d82bec 100644 --- a/test/test_condition_notify_one.cpp +++ b/test/test_condition_notify_one.cpp @@ -92,6 +92,47 @@ void do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate( BOOST_CHECK(data.woken); } +namespace +{ + boost::mutex multiple_wake_mutex; + boost::condition_variable multiple_wake_cond; + unsigned multiple_wake_count=0; + + void wait_for_condvar_and_increase_count() + { + boost::mutex::scoped_lock lk(multiple_wake_mutex); + multiple_wake_cond.wait(lk); + ++multiple_wake_count; + } + +} + + +void do_test_multiple_notify_one_calls_wakes_multiple_threads() +{ + boost::thread thread1(wait_for_condvar_and_increase_count); + boost::thread thread2(wait_for_condvar_and_increase_count); + + boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + multiple_wake_cond.notify_one(); + + boost::thread thread3(wait_for_condvar_and_increase_count); + + boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + multiple_wake_cond.notify_one(); + multiple_wake_cond.notify_one(); + boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + + { + boost::mutex::scoped_lock lk(multiple_wake_mutex); + BOOST_CHECK(multiple_wake_count==3); + } + + thread1.join(); + thread2.join(); + thread3.join(); +} + void test_condition_notify_one() { timed_test(&do_test_condition_notify_one_wakes_from_wait, timeout_seconds, execution_monitor::use_mutex); @@ -99,6 +140,7 @@ void test_condition_notify_one() timed_test(&do_test_condition_notify_one_wakes_from_timed_wait, timeout_seconds, execution_monitor::use_mutex); timed_test(&do_test_condition_notify_one_wakes_from_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex); timed_test(&do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex); + timed_test(&do_test_multiple_notify_one_calls_wakes_multiple_threads, timeout_seconds, execution_monitor::use_mutex); } diff --git a/test/test_shared_mutex_part_2.cpp b/test/test_shared_mutex_part_2.cpp index ae7348df..2daa8582 100644 --- a/test/test_shared_mutex_part_2.cpp +++ b/test/test_shared_mutex_part_2.cpp @@ -107,40 +107,6 @@ void test_can_lock_upgrade_if_currently_locked_shared() CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count+1); } -namespace -{ - class simple_writing_thread - { - boost::shared_mutex& rwm; - boost::mutex& finish_mutex; - boost::mutex& unblocked_mutex; - unsigned& unblocked_count; - - void operator=(simple_writing_thread&); - - public: - simple_writing_thread(boost::shared_mutex& rwm_, - boost::mutex& finish_mutex_, - boost::mutex& unblocked_mutex_, - unsigned& unblocked_count_): - rwm(rwm_),finish_mutex(finish_mutex_), - unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_) - {} - - void operator()() - { - boost::unique_lock lk(rwm); - - { - boost::mutex::scoped_lock ulk(unblocked_mutex); - ++unblocked_count; - } - - boost::mutex::scoped_lock flk(finish_mutex); - } - }; -} - void test_if_other_thread_has_write_lock_try_lock_shared_returns_false() { @@ -175,40 +141,6 @@ void test_if_no_thread_has_lock_try_lock_shared_returns_true() } } -namespace -{ - class simple_reading_thread - { - boost::shared_mutex& rwm; - boost::mutex& finish_mutex; - boost::mutex& unblocked_mutex; - unsigned& unblocked_count; - - void operator=(simple_reading_thread&); - - public: - simple_reading_thread(boost::shared_mutex& rwm_, - boost::mutex& finish_mutex_, - boost::mutex& unblocked_mutex_, - unsigned& unblocked_count_): - rwm(rwm_),finish_mutex(finish_mutex_), - unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_) - {} - - void operator()() - { - boost::shared_lock lk(rwm); - - { - boost::mutex::scoped_lock ulk(unblocked_mutex); - ++unblocked_count; - } - - boost::mutex::scoped_lock flk(finish_mutex); - } - }; -} - void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true() { @@ -232,33 +164,6 @@ void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true() writer.join(); } -void test_timed_lock_shared_times_out_if_write_lock_held() -{ - boost::shared_mutex rw_mutex; - boost::mutex finish_mutex; - boost::mutex unblocked_mutex; - unsigned unblocked_count=0; - boost::mutex::scoped_lock finish_lock(finish_mutex); - boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); - boost::thread::sleep(delay(1)); - CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); - - boost::system_time const start=boost::get_system_time(); - boost::system_time const timeout=start+boost::posix_time::milliseconds(2000); - boost::posix_time::milliseconds const timeout_resolution(20); - bool const timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout); - BOOST_CHECK((timeout-timeout_resolution)add(BOOST_TEST_CASE(&test_if_other_thread_has_write_lock_try_lock_shared_returns_false)); test->add(BOOST_TEST_CASE(&test_if_no_thread_has_lock_try_lock_shared_returns_true)); test->add(BOOST_TEST_CASE(&test_if_other_thread_has_shared_lock_try_lock_shared_returns_true)); - test->add(BOOST_TEST_CASE(&test_timed_lock_shared_times_out_if_write_lock_held)); return test; } diff --git a/test/test_shared_mutex_timed_locks.cpp b/test/test_shared_mutex_timed_locks.cpp new file mode 100644 index 00000000..815f7d3e --- /dev/null +++ b/test/test_shared_mutex_timed_locks.cpp @@ -0,0 +1,235 @@ +// (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) + +#include +#include +#include +#include "util.inl" +#include "shared_mutex_locking_thread.hpp" + +#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \ + { \ + boost::mutex::scoped_lock lock(mutex_name); \ + BOOST_CHECK_EQUAL(value,expected_value); \ + } + + +void test_timed_lock_shared_times_out_if_write_lock_held() +{ + boost::shared_mutex rw_mutex; + boost::mutex finish_mutex; + boost::mutex unblocked_mutex; + unsigned unblocked_count=0; + boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); + + boost::system_time const start=boost::get_system_time(); + boost::system_time const timeout=start+boost::posix_time::milliseconds(500); + boost::posix_time::milliseconds const timeout_resolution(50); + bool timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout); + BOOST_CHECK((timeout-timeout_resolution)add(BOOST_TEST_CASE(&test_timed_lock_shared_times_out_if_write_lock_held)); + test->add(BOOST_TEST_CASE(&test_timed_lock_shared_succeeds_if_no_lock_held)); + test->add(BOOST_TEST_CASE(&test_timed_lock_shared_succeeds_if_read_lock_held)); + test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_if_write_lock_held)); + test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_if_read_lock_held)); + test->add(BOOST_TEST_CASE(&test_timed_lock_succeeds_if_no_lock_held)); + + return test; +}