|
Boost-Commit : |
From: anthony_at_[hidden]
Date: 2007-10-05 05:46:03
Author: anthonyw
Date: 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
New Revision: 39693
URL: http://svn.boost.org/trac/boost/changeset/39693
Log:
Updated in line with RC 1.34
Removed:
trunk/boost/thread/read_write_mutex.hpp
trunk/libs/thread/build/Jamfile
trunk/libs/thread/build/threads.jam
trunk/libs/thread/build/threads.mcp
trunk/libs/thread/src/read_write_mutex.cpp
trunk/libs/thread/test/test_read_write_mutex.cpp
trunk/libs/thread/tutorial/Jamfile
Text files modified:
trunk/boost/thread/barrier.hpp | 2
trunk/boost/thread/condition.hpp | 1
trunk/boost/thread/mutex.hpp | 1
trunk/boost/thread/tss.hpp | 1
trunk/libs/thread/build/Jamfile.v2 | 2
trunk/libs/thread/doc/acknowledgements.xml | 5
trunk/libs/thread/doc/build.xml | 131 ++++++++++++++++----
trunk/libs/thread/doc/concepts.xml | 29 +++-
trunk/libs/thread/doc/entities.xml | 1
trunk/libs/thread/doc/read_write_mutex-ref.xml | 30 ++++
trunk/libs/thread/doc/reference.xml | 6
trunk/libs/thread/doc/release_notes.xml | 58 +++++++++
trunk/libs/thread/doc/thread-ref.xml | 15 --
trunk/libs/thread/src/condition.cpp | 20 +++
trunk/libs/thread/src/mutex.inl | 18 ++
trunk/libs/thread/src/once.cpp | 21 ++
trunk/libs/thread/src/recursive_mutex.cpp | 6
trunk/libs/thread/src/thread.cpp | 35 ----
trunk/libs/thread/src/timeconv.inl | 1
trunk/libs/thread/src/tss.cpp | 12 +
trunk/libs/thread/src/tss_hooks.cpp | 251 ++++++++++++++++++++++++---------------
trunk/libs/thread/test/Jamfile.v2 | 2
trunk/libs/thread/test/test_tss.cpp | 9
trunk/libs/thread/test/util.inl | 2
24 files changed, 457 insertions(+), 202 deletions(-)
Modified: trunk/boost/thread/barrier.hpp
==============================================================================
--- trunk/boost/thread/barrier.hpp (original)
+++ trunk/boost/thread/barrier.hpp 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -29,7 +29,7 @@
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4251 4231 4660 4275)
-#endif
+#endif
condition m_cond;
#ifdef BOOST_MSVC
# pragma warning(pop)
Modified: trunk/boost/thread/condition.hpp
==============================================================================
--- trunk/boost/thread/condition.hpp (original)
+++ trunk/boost/thread/condition.hpp 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -28,6 +28,7 @@
# pragma warning(push)
# pragma warning(disable: 4251 4231 4660 4275)
#endif
+
namespace detail {
class BOOST_THREAD_DECL condition_impl : private noncopyable
Modified: trunk/boost/thread/mutex.hpp
==============================================================================
--- trunk/boost/thread/mutex.hpp (original)
+++ trunk/boost/thread/mutex.hpp 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -29,6 +29,7 @@
# pragma warning(push)
# pragma warning(disable: 4251 4231 4660 4275)
#endif
+
class BOOST_THREAD_DECL mutex
: private noncopyable
{
Deleted: trunk/boost/thread/read_write_mutex.hpp
==============================================================================
--- trunk/boost/thread/read_write_mutex.hpp 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
+++ (empty file)
@@ -1,285 +0,0 @@
-// Copyright (C) 2002-2003
-// David Moore, William E. Kempf, Michael Glassford
-//
-// 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)
-
-// A Boost::threads implementation of a synchronization
-// primitive which can allow multiple readers or a single
-// writer to have access to a shared resource.
-
-#ifndef BOOST_READ_WRITE_MUTEX_JDM030602_HPP
-#define BOOST_READ_WRITE_MUTEX_JDM030602_HPP
-
-#include <boost/thread/detail/config.hpp>
-
-#include <boost/utility.hpp>
-#include <boost/detail/workaround.hpp>
-
-#include <boost/thread/mutex.hpp>
-#include <boost/thread/detail/lock.hpp>
-#include <boost/thread/detail/read_write_lock.hpp>
-#include <boost/thread/condition.hpp>
-
-namespace boost {
-// disable warnings about non dll import
-// see: http://www.boost.org/more/separate_compilation.html#dlls
-#ifdef BOOST_MSVC
-# pragma warning(push)
-# pragma warning(disable: 4251 4231 4660 4275)
-#endif
-namespace read_write_scheduling_policy {
- enum read_write_scheduling_policy_enum
- {
- writer_priority, //Prefer writers; can starve readers
- reader_priority, //Prefer readers; can starve writers
- alternating_many_reads, //Alternate readers and writers; before a writer, release all queued readers
- alternating_single_read //Alternate readers and writers; before a writer, release only one queued reader
- };
-} // namespace read_write_scheduling_policy
-
-namespace detail {
-
-namespace thread {
-
-// Shared implementation construct for explicit Scheduling Policies
-// This implementation is susceptible to self-deadlock, though....
-template<typename Mutex>
-struct read_write_mutex_impl
-{
- typedef Mutex mutex_type;
- typedef detail::thread::scoped_lock<Mutex> scoped_lock;
- typedef detail::thread::scoped_try_lock<Mutex> scoped_try_lock;
- typedef detail::thread::scoped_timed_lock<Mutex> scoped_timed_lock;
-
- read_write_mutex_impl(read_write_scheduling_policy::read_write_scheduling_policy_enum sp);
-#if !BOOST_WORKAROUND(__BORLANDC__,<= 0x564)
- ~read_write_mutex_impl();
-#endif
-
- Mutex m_prot;
-
- const read_write_scheduling_policy::read_write_scheduling_policy_enum m_sp;
- int m_state; //-1 = write lock; 0 = unlocked; >0 = read locked
-
- boost::condition m_waiting_writers;
- boost::condition m_waiting_readers;
- boost::condition m_waiting_promotion;
- int m_num_waiting_writers;
- int m_num_waiting_readers;
- bool m_state_waiting_promotion;
-
- int m_num_waking_writers;
- int m_num_waking_readers;
- int m_num_max_waking_writers; //Debug only
- int m_num_max_waking_readers; //Debug only
-
- bool m_readers_next;
-
- void do_read_lock();
- void do_write_lock();
- void do_write_unlock();
- void do_read_unlock();
- bool do_try_write_lock();
- bool do_try_read_lock();
- bool do_timed_write_lock(const xtime &xt);
- bool do_timed_read_lock(const xtime &xt);
-
- void do_demote_to_read_lock();
- bool do_try_demote_to_read_lock();
- bool do_timed_demote_to_read_lock(const xtime &xt);
-
- void do_promote_to_write_lock();
- bool do_try_promote_to_write_lock();
- bool do_timed_promote_to_write_lock(const xtime &xt);
-
- bool locked();
- read_write_lock_state::read_write_lock_state_enum state();
-
-private:
-
- bool do_demote_to_read_lock_impl();
-
- enum scheduling_reason
- {
- scheduling_reason_unlock,
- scheduling_reason_timeout,
- scheduling_reason_demote
- };
-
- void do_scheduling_impl(const scheduling_reason reason);
- bool do_wake_one_reader(void);
- bool do_wake_all_readers(void);
- bool do_wake_writer(void);
- bool waker_exists(void);
-};
-
-} // namespace detail
-
-} // namespace thread
-
-class BOOST_THREAD_DECL read_write_mutex : private noncopyable
-{
-public:
-
- read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp);
- ~read_write_mutex();
-
- read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
-
- friend class detail::thread::read_write_lock_ops<read_write_mutex>;
-
- typedef detail::thread::scoped_read_write_lock<
- read_write_mutex> scoped_read_write_lock;
-
- typedef detail::thread::scoped_read_lock<
- read_write_mutex> scoped_read_lock;
-
- typedef detail::thread::scoped_write_lock<
- read_write_mutex> scoped_write_lock;
-
-private:
-
- // Operations that will eventually be done only
- // via lock types
- void do_write_lock();
- void do_read_lock();
- void do_write_unlock();
- void do_read_unlock();
-
- void do_demote_to_read_lock();
-
- void do_promote_to_write_lock();
-
- bool locked();
- read_write_lock_state::read_write_lock_state_enum state();
-
- detail::thread::read_write_mutex_impl<mutex> m_impl;
-};
-
-class BOOST_THREAD_DECL try_read_write_mutex : private noncopyable
-{
-public:
-
- try_read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp);
- ~try_read_write_mutex();
-
- read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
-
- friend class detail::thread::read_write_lock_ops<try_read_write_mutex>;
-
- typedef detail::thread::scoped_read_write_lock<
- try_read_write_mutex> scoped_read_write_lock;
- typedef detail::thread::scoped_try_read_write_lock<
- try_read_write_mutex> scoped_try_read_write_lock;
-
- typedef detail::thread::scoped_read_lock<
- try_read_write_mutex> scoped_read_lock;
- typedef detail::thread::scoped_try_read_lock<
- try_read_write_mutex> scoped_try_read_lock;
-
- typedef detail::thread::scoped_write_lock<
- try_read_write_mutex> scoped_write_lock;
- typedef detail::thread::scoped_try_write_lock<
- try_read_write_mutex> scoped_try_write_lock;
-
-private:
-
- // Operations that will eventually be done only
- // via lock types
- void do_write_lock();
- void do_read_lock();
- void do_write_unlock();
- void do_read_unlock();
- bool do_try_write_lock();
- bool do_try_read_lock();
-
-
- void do_demote_to_read_lock();
- bool do_try_demote_to_read_lock();
-
- void do_promote_to_write_lock();
- bool do_try_promote_to_write_lock();
-
- bool locked();
- read_write_lock_state::read_write_lock_state_enum state();
-
- detail::thread::read_write_mutex_impl<try_mutex> m_impl;
-};
-
-class BOOST_THREAD_DECL timed_read_write_mutex : private noncopyable
-{
-public:
-
- timed_read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp);
- ~timed_read_write_mutex();
-
- read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
-
- friend class detail::thread::read_write_lock_ops<timed_read_write_mutex>;
-
- typedef detail::thread::scoped_read_write_lock<
- timed_read_write_mutex> scoped_read_write_lock;
- typedef detail::thread::scoped_try_read_write_lock<
- timed_read_write_mutex> scoped_try_read_write_lock;
- typedef detail::thread::scoped_timed_read_write_lock<
- timed_read_write_mutex> scoped_timed_read_write_lock;
-
- typedef detail::thread::scoped_read_lock<
- timed_read_write_mutex> scoped_read_lock;
- typedef detail::thread::scoped_try_read_lock<
- timed_read_write_mutex> scoped_try_read_lock;
- typedef detail::thread::scoped_timed_read_lock<
- timed_read_write_mutex> scoped_timed_read_lock;
-
- typedef detail::thread::scoped_write_lock<
- timed_read_write_mutex> scoped_write_lock;
- typedef detail::thread::scoped_try_write_lock<
- timed_read_write_mutex> scoped_try_write_lock;
- typedef detail::thread::scoped_timed_write_lock<
- timed_read_write_mutex> scoped_timed_write_lock;
-
-private:
-
- // Operations that will eventually be done only
- // via lock types
- void do_write_lock();
- void do_read_lock();
- void do_write_unlock();
- void do_read_unlock();
- bool do_try_write_lock();
- bool do_try_read_lock();
- bool do_timed_write_lock(const xtime &xt);
- bool do_timed_read_lock(const xtime &xt);
-
- void do_demote_to_read_lock();
- bool do_try_demote_to_read_lock();
- bool do_timed_demote_to_read_lock(const xtime &xt);
-
- void do_promote_to_write_lock();
- bool do_try_promote_to_write_lock();
- bool do_timed_promote_to_write_lock(const xtime &xt);
-
- bool locked();
- read_write_lock_state::read_write_lock_state_enum state();
-
- detail::thread::read_write_mutex_impl<timed_mutex> m_impl;
-};
-#ifdef BOOST_MSVC
-# pragma warning(pop)
-#endif
-} // namespace boost
-
-#endif
-
-// Change Log:
-// 10 Mar 02
-// Original version.
-// 4 May 04 GlassfordM
-// Implement lock promotion and demotion.
-// Add locked() and state() member functions for debugging
-// (should these be made public?).
-// Rename to improve consistency and eliminate abbreviations:
-// Use "read" and "write" instead of "shared" and "exclusive".
-// Change "rd" to "read", "wr" to "write", "rw" to "read_write".
-// Add mutex_type typdef.
Modified: trunk/boost/thread/tss.hpp
==============================================================================
--- trunk/boost/thread/tss.hpp (original)
+++ trunk/boost/thread/tss.hpp 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -45,6 +45,7 @@
throw boost::thread_resource_error();
}
}
+
~tss();
void* get() const;
void set(void* value);
Deleted: trunk/libs/thread/build/Jamfile
==============================================================================
--- trunk/libs/thread/build/Jamfile 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
+++ (empty file)
@@ -1,122 +0,0 @@
-# Copyright (C) 2001-2003
-# William E. Kempf
-#
-# 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)
-#
-# Boost.Threads build Jamfile
-#
-# Additional configuration variables used:
-# See threads.jam.
-
-# Declare the location of this subproject relative to the root.
-subproject libs/thread/build ;
-
-# Include threads.jam for Boost.Threads global build information.
-# This greatly simplifies the Jam code needed to configure the build
-# for the various Win32 build types.
-import ./threads ;
-
-{
- CPP_SOURCES =
- barrier
- condition
- exceptions
- mutex
- once
- recursive_mutex
- read_write_mutex
- thread
- tss_hooks
- tss_dll
- tss_pe
- tss
- xtime
- ;
-
- template boost_thread_lib_base
- : ## sources ##
- <template>thread_base
- ../src/$(CPP_SOURCES).cpp
- : ## requirements ##
- <sysinclude>$(BOOST_ROOT) #:should be unnecessary (because already included in thread_base)
- <define>BOOST_THREAD_BUILD_LIB=1
- # the common names rule ensures that the library will
- # be named according to the rules used by the install
- # and auto-link features:
- common-variant-tag
- : ## default build ##
- ;
-
- template boost_thread_dll_base
- : ## sources ##
- <template>thread_base
- ../src/$(CPP_SOURCES).cpp
- : ## requirements ##
- <sysinclude>$(BOOST_ROOT) #:should be unnecessary (because already included in thread_base)
- <define>BOOST_THREAD_BUILD_DLL=1
- <runtime-link>dynamic
- # the common names rule ensures that the library will
- # be named according to the rules used by the install
- # and auto-link features:
- common-variant-tag
- : ## default build ##
- ;
-
- lib $(boost_thread_lib_name)
- : ## sources ##
- <template>boost_thread_lib_base
- : ## requirements ##
- <define>BOOST_THREAD_LIB_NAME=$(boost_thread_lib_name)
- : ## default build ##
- ;
-
- dll $(boost_thread_lib_name)
- : ## sources ##
- <template>boost_thread_dll_base
- : ## requirements ##
- <define>BOOST_THREAD_LIB_NAME=$(boost_thread_lib_name)
- : ## default build ##
- ;
-
- stage bin-stage
- : <dll>$(boost_thread_lib_name)
- <lib>$(boost_thread_lib_name)
- ;
-
- install thread lib
- : <dll>$(boost_thread_lib_name)
- <lib>$(boost_thread_lib_name)
- ;
-
- if $(boost_thread_lib_settings_ptw32)
- {
- lib $(boost_thread_lib_name_ptw32)
- : ## sources ##
- <template>boost_thread_lib_base
- : ## requirements ##
- <define>BOOST_THREAD_LIB_NAME=$(boost_thread_lib_name_ptw32)
- $(boost_thread_lib_settings_ptw32)
- : ## default build ##
- ;
-
- dll $(boost_thread_lib_name_ptw32)
- : ## sources ##
- <template>boost_thread_dll_base
- : ## requirements ##
- <define>BOOST_THREAD_LIB_NAME=$(boost_thread_lib_name_ptw32)
- $(boost_thread_lib_settings_ptw32)
- : ## default build ##
- ;
-
- stage bin-stage
- : <dll>$(boost_thread_lib_name_ptw32)
- <lib>$(boost_thread_lib_name_ptw32)
- ;
-
- install thread lib
- : <dll>$(boost_thread_lib_name_ptw32)
- <lib>$(boost_thread_lib_name_ptw32)
- ;
- }
-}
Modified: trunk/libs/thread/build/Jamfile.v2
==============================================================================
--- trunk/libs/thread/build/Jamfile.v2 (original)
+++ trunk/libs/thread/build/Jamfile.v2 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -20,7 +20,7 @@
mutex
once
recursive_mutex
- read_write_mutex
+# read_write_mutex
thread
tss_hooks
tss_dll
Deleted: trunk/libs/thread/build/threads.jam
==============================================================================
--- trunk/libs/thread/build/threads.jam 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
+++ (empty file)
@@ -1,65 +0,0 @@
-# Copyright (C) 2001-2003
-# William E. Kempf
-#
-# 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)
-
-# Additional configuration variables used:
-# 1. PTW32_DIR and PTW32_LIB may be used on Win32 platforms to specify that
-# a version of Boost.Threads should be built that uses the
-# the pthreads-win32 library instead of the Win32 native threading APIs.
-# This feature is mostly used for testing and it's generally recommended
-# that you use the Win32 native threading libraries instead.
-#
-# PTW32_Dir should be set to the installation path of the
-# pthreads-win32 library and PTW32_LIB should be set to the name of the
-# library variant to link against (see the pthreads-win32 documentation).
-# Example: jam -sPTW32_DIR="c:\pthreads-win32" -sPTW32_LIB="pthreadVCE.lib"
-# Alternately, environment variables having the names PTW32_DIR and PTW32_LIB
-# can be set instead of passing these values on the command line.
-#
-# In either case, libraries having the names boost_thread_ptw32<tags>.dll
-# and libboost_thread_ptw32<tags>.lib will be built
-# in addition to the usual boost_thread<tags>.dll and
-# libboost_thread<tags>.lib. Link with one of the ptw32 versions
-# of the Boost.Threads libraries to use the version of Boost.Threads
-# that is implemented using pthreads-win32 (you will need to #define
-# BOOST_THREAD_NO_LIB or BOOST_ALL_NO_LIB to disable auto-linking
-# if your platform supports auto-linking in order to prevent
-# your build from attempting to link to two different versions of
-# the Boost.Threads library).
-
-# Do some OS-specific setup
-{
- #thread library name
- boost_thread_lib_name = boost_thread ;
-
- #thread library name with "pthreads-win32" library
- boost_thread_lib_name_ptw32 = boost_thread_ptw32 ;
-
- if $(NT)
- {
- if $(PTW32_DIR)
- {
- if $(PTW32_LIB)
- {
- boost_thread_lib_settings_ptw32 =
- <define>BOOST_HAS_PTHREADS
- <define>PtW32NoCatchWarn
- <include>$(PTW32_DIR)/pre-built/include
- <library-file>$(PTW32_DIR)/pre-built/lib/$(PTW32_LIB)
- ;
- }
- }
- }
-
- template thread_base
- : ## sources ##
- : ## requirements ##
- <sysinclude>$(BOOST_ROOT)
- <threading>multi
- <borland><*><cxxflags>-w-8004
- <borland><*><cxxflags>-w-8057
- : ## default build ##
- ;
-}
Deleted: trunk/libs/thread/build/threads.mcp
==============================================================================
Binary files trunk/libs/thread/build/threads.mcp 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007) and (empty file) differ
Modified: trunk/libs/thread/doc/acknowledgements.xml
==============================================================================
--- trunk/libs/thread/doc/acknowledgements.xml (original)
+++ trunk/libs/thread/doc/acknowledgements.xml 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -63,6 +63,11 @@
Steve Cleary, Steven Kirk, Thomas Holenstein, Thomas Matelich, Trevor
Perrin, Valentin Bonnard, Vesa Karvonen, Wayne Miller, and William
Kempf.</para>
+ <para>
+ As of February 2006 Anthony Williams and Roland Schwarz took over maintainance
+ and further development of the library after it has been in an orphaned state
+ for a rather long period of time.
+ </para>
<para>Apologies for anyone inadvertently missed.</para>
</section>
Modified: trunk/libs/thread/doc/build.xml
==============================================================================
--- trunk/libs/thread/doc/build.xml (original)
+++ trunk/libs/thread/doc/build.xml 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -5,6 +5,7 @@
%thread.entities;
]>
<!-- Copyright (c) 2002-2003 William E. Kempf, Michael Glassford
+ Copyright (c) 2007 Roland Schwarz
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
@@ -25,38 +26,112 @@
</para>
<section id="thread.build.building">
<title>Building the &Boost.Thread; Libraries</title>
- <para>
- To build the &Boost.Thread; libraries using &Boost.Build;, simply change to the
- directory <emphasis>boost_root</emphasis>/libs/thread/build and execute the command:
- <programlisting>bjam -sTOOLS=<emphasis>toolset</emphasis></programlisting>
- This will create the debug and the release builds of the &Boost.Thread; library.
- <note>Invoking the above command in <emphasis>boost_root</emphasis> will build all of
- the Boost distribution, including &Boost.Thread;.</note>
- </para>
- <para>
- The Jamfile supplied with &Boost.Thread; produces a dynamic link library named
- <emphasis>boost_thread{build-specific-tags}.{extension}</emphasis>, where the build-specific
- tags indicate the toolset used to build the library, whether it's a debug or release
- build, what version of Boost was used, etc.; and the extension is the appropriate extension
- for a dynamic link library for the platform for which &Boost.Thread; is being built.
- For instance, a debug library built for Win32 with VC++ 7.1 using Boost 1.31 would
- be named <emphasis>boost_thread-vc71-mt-gd-1_31.dll</emphasis>.
- </para>
- <para>
- The source files that are used to create the &Boost.Thread; library
- are all of the *.cpp files found in <emphasis>boost_root</emphasis>/libs/thread/src.
- These need to be built with the compiler's and linker's multi-threading support enabled.
- If you want to create your own build solution you'll have to follow these same
- guidelines. One of the most frequently reported problems when trying to do this
- occurs from not enabling the compiler's and linker's support for multi-threading.
- </para>
+ <para>
+ Building the &Boost.Thread; Library depends on how you intend to use it. You have several options:
+ <itemizedlist>
+ <listitem>
+ Using as a <link linkend="thread.build.precompiled">precompiled</link> library, possibly
+ with auto-linking, or for use from within an IDE.
+ </listitem>
+ <listitem>
+ Use from a <link linkend="thread.build.bjam">&Boost.Build;</link> project.
+ </listitem>
+ <listitem>
+ Using in <link linkend="thread.build.source">source</link> form.
+ </listitem>
+ </itemizedlist>
+ </para>
+ <section id="thread.build.precompiled">
+ <title>Precompiled</title>
+ <para>
+ Using the &Boost.Thread; library in precompiled form is the way to go if you want to
+ install the library to a standard place, from where your linker is able to resolve code
+ in binary form. You also will want this option if compile time is a concern. Multiple
+ variants are available, for different toolsets and build variants (debug/release).
+ The library files are named <emphasis>{lead}boost_thread{build-specific-tags}.{extension}</emphasis>,
+ where the build-specific-tags indicate the toolset used to build the library, whether it's
+ a debug or release build, what version of &Boost; was used, etc.; and the lead and extension
+ are the appropriate extensions for a dynamic link library or static library for the platform
+ for which &Boost.Thread; is being built.
+ For instance, a debug build of the dynamic library built for Win32 with VC++ 7.1 using Boost 1.34 would
+ be named <emphasis>boost_thread-vc71-mt-gd-1_34.dll</emphasis>.
+ More information on this should be available from the &Boost.Build; documentation.
+ </para>
+ <para>
+ Building should be possible with the default configuration. If you are running into problems,
+ it might be wise to adjust your local settings of &Boost.Build; though. Typically you will
+ need to get your user-config.jam file to reflect your environment, i.e. used toolsets. Please
+ refer to the &Boost.Build; documentation to learn how to do this.
+ </para>
+ <para>
+ To create the libraries you need to open a command shell and change to the
+ <emphasis>boost_root</emphasis> directory. From there you give the command
+ <programlisting>bjam --toolset=<emphasis>mytoolset</emphasis> stage --with-thread</programlisting>
+ Replace <emphasis>mytoolset</emphasis> with the name of your toolset, e.g. msvc-7.1 .
+ This will compile and put the libraries into the <emphasis>stage</emphasis> directory which is just below the
+ <emphasis>boost_root</emphasis> directory. &Boost.Build; by default will generate static and
+ dynamic variants for debug and release.
+ </para>
+ <note>
+ Invoking the above command without the --with-thread switch &Boost.Build; will build all of
+ the Boost distribution, including &Boost.Thread;.
+ </note>
+ <para>
+ The next step is to copy your libraries to a place where your linker is able to pick them up.
+ It is also quite possible to leave them in the stage directory and instruct your IDE to take them
+ from there.
+ </para>
+ <para>
+ In your IDE you then need to add <emphasis>boost_root</emphasis>/boost to the paths where the compiler
+ expects to find files to be included. For toolsets that support <emphasis>auto-linking</emphasis>
+ it is not necessary to explicitly specify the name of the library to link against, it is sufficient
+ to specify the path of the stage directory. Typically this is true on Windows. For gcc you need
+ to specify the exact library name (including all the tags). Please don't forget that threading
+ support must be turned on to be able to use the library. You should be able now to build your
+ project from the IDE.
+ </para>
+ </section>
+ <section id="thread.build.bjam">
+ <title>&Boost.Build; Project</title>
+ <para>
+ If you have decided to use &Boost.Build; as a build environment for your application, you simply
+ need to add a single line to your <emphasis>Jamroot</emphasis> file:
+ <programlisting>use-project /boost : {path-to-boost-root} ;</programlisting>
+ where <emphasis>{path-to-boost-root}</emphasis> needs to be replaced with the location of
+ your copy of the boost tree.
+ Later when you specify a component that needs to link against &Boost.Thread; you specify this
+ as e.g.:
+ <programlisting>exe myapp : {myappsources} /boost//thread ;</programlisting>
+ and you are done.
+ </para>
+ </section>
+ <section id="thread.build.source">
+ <title>Source Form</title>
+ <para>
+ Of course it is also possible to use the &Boost.Thread; library in source form.
+ First you need to specify the <emphasis>boost_root</emphasis>/boost directory as
+ a path where your compiler expects to find files to include. It is not easy
+ to isolate the &Boost.Thread; include files from the rest of the boost
+ library though. You would also need to isolate every include file that the thread
+ library depends on. Next you need to copy the files from
+ <emphasis>boost_root</emphasis>/libs/thread/src to your project and instruct your
+ build system to compile them together with your project. Please look into the
+ <emphasis>Jamfile</emphasis> in <emphasis>boost_root</emphasis>/libs/thread/build
+ to find out which compiler options and defines you will need to get a clean compile.
+ Using the boost library in this way is the least recommended, and should only be
+ considered if avoiding dependency on &Boost.Build; is a requirement. Even if so
+ it might be a better option to use the library in it's precompiled form.
+ Precompiled downloads are available from the boost consulting web site, or as
+ part of most linux distributions.
+ </para>
+ </section>
</section>
<section id="thread.build.testing">
<title>Testing the &Boost.Thread; Libraries</title>
<para>
- To test the &Boost.Thread; libraries using &Boost.Build;, simply change to the
- directory <emphasis>boost_root</emphasis>/libs/thread/test and execute the command:
- <programlisting>bjam -sTOOLS=<emphasis>toolset</emphasis> test</programlisting>
+ To test the &Boost.Thread; libraries using &Boost.Build;, simply change to the
+ directory <emphasis>boost_root</emphasis>/libs/thread/test and execute the command:
+ <programlisting>bjam --toolset=<emphasis>mytoolset</emphasis> test</programlisting>
</para>
</section>
</section>
Modified: trunk/libs/thread/doc/concepts.xml
==============================================================================
--- trunk/libs/thread/doc/concepts.xml (original)
+++ trunk/libs/thread/doc/concepts.xml 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -18,7 +18,17 @@
which allow only one thread at a time to access a resource when it is
being modified (the "Write" part of Read/Write), but allows multiple threads
to access a resource when it is only being referenced (the "Read" part of
- Read/Write).</para>
+ Read/Write).</para>
+ <note> Unfortunately it turned out that the current implementation of Read/Write Mutex has
+ some serious problems. So it was decided not to put this implementation into
+ release grade code. Also discussions on the mailing list led to the
+ conclusion that the current concepts need to be rethought. In particular
+ the schedulings <link linkend="thread.concepts.read-write-scheduling-policies.inter-class">
+ Inter-Class Scheduling Policies</link> are deemed unnecessary.
+ There seems to be common belief that a fair scheme suffices.
+ The following documentation has been retained however, to give
+ readers of this document the opportunity to study the original design.
+ </note>
<section id="thread.concepts.mutexes">
<title>Mutexes</title>
@@ -739,13 +749,18 @@
<section id="thread.concepts.read-write-mutexes">
<title>Read/Write Mutexes</title>
- <note>Since the read/write mutex and related classes are new,
- both interface and implementation are liable to change
- in future releases of &Boost.Thread;.
- The lock concepts and lock promotion and demotion in particular
- are still under discussion and very likely to change.</note>
+ <note> Unfortunately it turned out that the current implementation has
+ some serious problems. So it was decided not to put this implementation into
+ release grade code. Also discussions on the mailing list led to the
+ conclusion that the current concepts need to be rethought. In particular
+ the schedulings <link linkend="thread.concepts.read-write-scheduling-policies.inter-class">
+ Inter-Class Scheduling Policies</link> are deemed unnecessary.
+ There seems to be common belief that a fair scheme suffices.
+ The following documentation has been retained however, to give
+ readers of this document the opportunity to study the original design.
+ </note>
- <para>A read/write mutex (short for reader/writer mutual-exclusion) object
+ <para>A read/write mutex (short for reader/writer mutual-exclusion) object
is used to serialize access to a resource shared between multiple
threads, where multiple "readers" can share simultaneous access, but
"writers" require exclusive access. The
Modified: trunk/libs/thread/doc/entities.xml
==============================================================================
--- trunk/libs/thread/doc/entities.xml (original)
+++ trunk/libs/thread/doc/entities.xml 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -2,6 +2,7 @@
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
-->
+<!ENTITY Boost "<emphasis role='bold'>Boost</emphasis>">
<!ENTITY Boost.Thread "<emphasis role='bold'>Boost.Thread</emphasis>">
<!ENTITY Boost.Build "<emphasis role='bold'>Boost.Build</emphasis>">
<!ENTITY cite.AndrewsSchneider83 "<citation><xref
Modified: trunk/libs/thread/doc/read_write_mutex-ref.xml
==============================================================================
--- trunk/libs/thread/doc/read_write_mutex-ref.xml (original)
+++ trunk/libs/thread/doc/read_write_mutex-ref.xml 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -37,6 +37,16 @@
<purpose>
<para>The <classname>read_write_mutex</classname> class is a model of the
<link linkend="thread.concepts.ReadWriteMutex">ReadWriteMutex</link> concept.</para>
+ <note> Unfortunately it turned out that the current implementation of Read/Write Mutex has
+ some serious problems. So it was decided not to put this implementation into
+ release grade code. Also discussions on the mailing list led to the
+ conclusion that the current concepts need to be rethought. In particular
+ the schedulings <link linkend="thread.concepts.read-write-scheduling-policies.inter-class">
+ Inter-Class Scheduling Policies</link> are deemed unnecessary.
+ There seems to be common belief that a fair scheme suffices.
+ The following documentation has been retained however, to give
+ readers of this document the opportunity to study the original design.
+ </note>
</purpose>
<description>
@@ -160,6 +170,16 @@
<purpose>
<para>The <classname>try_read_write_mutex</classname> class is a model of the
<link linkend="thread.concepts.TryReadWriteMutex">TryReadWriteMutex</link> concept.</para>
+ <note> Unfortunately it turned out that the current implementation of Read/Write Mutex has
+ some serious problems. So it was decided not to put this implementation into
+ release grade code. Also discussions on the mailing list led to the
+ conclusion that the current concepts need to be rethought. In particular
+ the schedulings <link linkend="thread.concepts.read-write-scheduling-policies.inter-class">
+ Inter-Class Scheduling Policies</link> are deemed unnecessary.
+ There seems to be common belief that a fair scheme suffices.
+ The following documentation has been retained however, to give
+ readers of this document the opportunity to study the original design.
+ </note>
</purpose>
<description>
@@ -302,6 +322,16 @@
<purpose>
<para>The <classname>timed_read_write_mutex</classname> class is a model of the
<link linkend="thread.concepts.TimedReadWriteMutex">TimedReadWriteMutex</link> concept.</para>
+ <note> Unfortunately it turned out that the current implementation of Read/Write Mutex has
+ some serious problems. So it was decided not to put this implementation into
+ release grade code. Also discussions on the mailing list led to the
+ conclusion that the current concepts need to be rethought. In particular
+ the schedulings <link linkend="thread.concepts.read-write-scheduling-policies.inter-class">
+ Inter-Class Scheduling Policies</link> are deemed unnecessary.
+ There seems to be common belief that a fair scheme suffices.
+ The following documentation has been retained however, to give
+ readers of this document the opportunity to study the original design.
+ </note>
</purpose>
<description>
Modified: trunk/libs/thread/doc/reference.xml
==============================================================================
--- trunk/libs/thread/doc/reference.xml (original)
+++ trunk/libs/thread/doc/reference.xml 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -17,6 +17,12 @@
<xi:include href="mutex-ref.xml"/>
<xi:include href="once-ref.xml"/>
<xi:include href="recursive_mutex-ref.xml"/>
+<!--
+ The read_write_mutex is held back from release, since the
+ implementation suffers from a serious, yet unresolved bug.
+ The implementation is likely to appear in a reworked
+ form in the next release.
+-->
<xi:include href="read_write_mutex-ref.xml"/>
<xi:include href="thread-ref.xml"/>
<xi:include href="tss-ref.xml"/>
Modified: trunk/libs/thread/doc/release_notes.xml
==============================================================================
--- trunk/libs/thread/doc/release_notes.xml (original)
+++ trunk/libs/thread/doc/release_notes.xml 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -10,7 +10,63 @@
-->
<section id="thread.release_notes" last-revision="$Date$">
<title>Release Notes</title>
- <section id="thread.release_notes.boost_1_32_0">
+ <section id="thread.release_notes.boost_1_34_0">
+ <title>Boost 1.34.0</title>
+
+ <section id="thread.release_notes.boost_1_34_0.change_log.maintainance">
+ <title>New team of maintainers</title>
+
+ <para>
+ Since the original author William E. Kempf no longer is available to
+ maintain the &Boost.Thread; library, a new team has been formed
+ in an attempt to continue the work on &Boost.Thread;.
+ Fortunately William E. Kempf has given
+ <ulink url="http://lists.boost.org/Archives/boost/2006/09/110143.php">
+ permission </ulink>
+ to use his work under the boost license.
+ </para>
+ <para>
+ The team currently consists of
+ <itemizedlist>
+ <listitem>
+ Anthony Williams, for the Win32 platform,
+ </listitem>
+ <listitem>
+ Roland Schwarz, for the linux platform, and various "housekeeping" tasks.
+ </listitem>
+ </itemizedlist>
+ Volunteers for other platforms are welcome!
+ </para>
+ <para>
+ As the &Boost.Thread; was kind of orphaned over the last release, this release
+ attempts to fix the known bugs. Upcoming releases will bring in new things.
+ </para>
+ </section>
+
+ <section id="thread.release_notes.boost_1_34_0.change_log.read_write_mutex">
+ <title>read_write_mutex still broken</title>
+
+ <para>
+ <note>
+ It has been decided not to release the Read/Write Mutex, since the current
+ implementation suffers from a serious bug. The documentation of the concepts
+ has been included though, giving the interested reader an opportunity to study the
+ original concepts. Please refer to the following links if you are interested
+ which problems led to the decision to held back this mutex type.The issue
+ has been discovered before 1.33 was released and the code has
+ been omitted from that release. A reworked mutex is expected to appear in 1.35.
+ Also see:
+ <ulink url="http://lists.boost.org/Archives/boost/2005/08/92307.php">
+ read_write_mutex bug</ulink>
+ and
+ <ulink url="http://lists.boost.org/Archives/boost/2005/09/93180.php">
+ read_write_mutex fundamentally broken in 1.33</ulink>
+ </note>
+ </para>
+ </section>
+
+ </section>
+ <section id="thread.release_notes.boost_1_32_0">
<title>Boost 1.32.0</title>
<section id="thread.release_notes.boost_1_32_0.change_log.documentation">
Modified: trunk/libs/thread/doc/thread-ref.xml
==============================================================================
--- trunk/libs/thread/doc/thread-ref.xml (original)
+++ trunk/libs/thread/doc/thread-ref.xml 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -264,20 +264,7 @@
<effects>Calls <code>join()</code> on each of the managed
<classname>thread</classname> objects.</effects>
</method>
- </method-group>
-
- <method-group name="capacity">
-
- <method name="size" cv="const">
- <type>int</type>
-
- <returns>the number of <classname>thread</classname>
- objects in the group
- </returns>
-
- </method>
-
- </method-group>
+ </method-group>
</class>
</namespace>
</header>
Modified: trunk/libs/thread/src/condition.cpp
==============================================================================
--- trunk/libs/thread/src/condition.cpp (original)
+++ trunk/libs/thread/src/condition.cpp 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -27,6 +27,12 @@
# include "mac/safe.hpp"
#endif
+// The following include can be removed after the bug on QNX
+// has been tracked down. I need this only for debugging
+//#if !defined(NDEBUG) && defined(BOOST_HAS_PTHREADS)
+#include <iostream>
+//#endif
+
namespace boost {
namespace detail {
@@ -373,6 +379,20 @@
int res = 0;
res = pthread_cond_timedwait(&m_condition, pmutex, &ts);
+// Test code for QNX debugging, to get information during regressions
+#ifndef NDEBUG
+ if (res == EINVAL) {
+ boost::xtime now;
+ boost::xtime_get(&now, boost::TIME_UTC);
+ std::cerr << "now: " << now.sec << " " << now.nsec << std::endl;
+ std::cerr << "time: " << time(0) << std::endl;
+ std::cerr << "xtime: " << xt.sec << " " << xt.nsec << std::endl;
+ std::cerr << "ts: " << ts.tv_sec << " " << ts.tv_nsec << std::endl;
+ std::cerr << "pmutex: " << pmutex << std::endl;
+ std::cerr << "condition: " << &m_condition << std::endl;
+ assert(res != EINVAL);
+ }
+#endif
assert(res == 0 || res == ETIMEDOUT);
return res != ETIMEDOUT;
Modified: trunk/libs/thread/src/mutex.inl
==============================================================================
--- trunk/libs/thread/src/mutex.inl (original)
+++ trunk/libs/thread/src/mutex.inl 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -24,7 +24,15 @@
version_info.dwMajorVersion >= 4)
{
if (HMODULE kernel_module = GetModuleHandle(TEXT("KERNEL32.DLL")))
- g_TryEnterCriticalSection = reinterpret_cast<TryEnterCriticalSection_type>(GetProcAddress(kernel_module, TEXT("TryEnterCriticalSection")));
+ {
+ g_TryEnterCriticalSection = reinterpret_cast<TryEnterCriticalSection_type>(
+#if defined(BOOST_NO_ANSI_APIS)
+ GetProcAddressW(kernel_module, L"TryEnterCriticalSection")
+#else
+ GetProcAddress(kernel_module, "TryEnterCriticalSection")
+#endif
+ );
+ }
}
}
@@ -62,9 +70,11 @@
inline void* new_mutex(const char* name)
{
#if defined(BOOST_NO_ANSI_APIS)
- int num_wide_chars = (strlen(name) + 1);
- LPWSTR wide_name = (LPWSTR)_alloca( num_wide_chars * 2 );
- ::MultiByteToWideChar(CP_ACP, 0, name, -1, wide_name, num_wide_chars);
+ int const num_wide_chars = ::MultiByteToWideChar(CP_ACP, 0, name, -1, 0, 0);
+ LPWSTR const wide_name = (LPWSTR)_alloca( (num_wide_chars+1) * 2 );
+ int const res=::MultiByteToWideChar(CP_ACP, 0, name, -1, wide_name, num_wide_chars);
+ if(!res)
+ throw boost::thread_resource_error();
HANDLE mutex = CreateMutexW(0, 0, wide_name);
#else
HANDLE mutex = CreateMutexA(0, 0, name);
Modified: trunk/libs/thread/src/once.cpp
==============================================================================
--- trunk/libs/thread/src/once.cpp (original)
+++ trunk/libs/thread/src/once.cpp 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -1,5 +1,6 @@
// Copyright (C) 2001-2003
// William E. Kempf
+// Copyright (C) 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)
@@ -9,7 +10,6 @@
#include <boost/detail/workaround.hpp>
#include <boost/thread/once.hpp>
-#include <boost/thread/exceptions.hpp>
#include <cstdio>
#include <cassert>
@@ -19,7 +19,6 @@
using std::size_t;
# endif
# include <windows.h>
-# include "mutex.inl"
# if defined(BOOST_NO_STRINGSTREAM)
# include <strstream>
@@ -116,8 +115,11 @@
inline LONG compare_exchange(volatile LPLONG dest, LONG exch, LONG cmp)
{
#ifdef _WIN64
- return InterlockedCompareExchange(dest, exch, cmp);
-#else
+ // Original patch from Anthony Williams.
+ // I (Roland Schwarz) am trying this for RC_1_34_0, since x64 regressions are
+ // currently not run on x64 platforms for HEAD
+ return InterlockedCompareExchange(dest, exch,cmp);
+#else
return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp);
#endif
}
@@ -139,7 +141,16 @@
<< &flag
<< std::ends;
unfreezer unfreeze(strm);
- HANDLE mutex=new_mutex(strm.str());
+# if defined (BOOST_NO_ANSI_APIS)
+ int const num_wide_chars = ::MultiByteToWideChar(CP_ACP, 0, strm.str(), -1, 0, 0);
+ LPWSTR const wide_name = (LPWSTR)_alloca( (num_wide_chars+1) * 2 );
+ int const res=::MultiByteToWideChar(CP_ACP, 0, name, -1, wide_name, num_wide_chars);
+ if(!res)
+ throw boost::thread_resource_error();
+ HANDLE mutex = CreateMutexW(NULL, FALSE, wide_name);
+# else
+ HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str());
+# endif
#else
# if defined (BOOST_NO_ANSI_APIS)
std::wostringstream strm;
Deleted: trunk/libs/thread/src/read_write_mutex.cpp
==============================================================================
--- trunk/libs/thread/src/read_write_mutex.cpp 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
+++ (empty file)
@@ -1,1732 +0,0 @@
-// Copyright (C) 2002-2003
-// David Moore, William E. Kempf, Michael Glassford
-//
-// 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)
-
-/*
-PROBLEMS:
-
-The algorithms are not exception safe. For instance, if conditon::wait()
-or another call throws an exception, the lock state and other state data
-are not appropriately adjusted.
-
-A harder problem to fix is that, if a thread is killed while inside the
-read-write mutex functions (for example, while waiting),
-bad things happen.
-*/
-
-#include <boost/thread/detail/config.hpp>
-
-#include <boost/assert.hpp>
-#include <boost/thread/read_write_mutex.hpp>
-#include <boost/thread/xtime.hpp>
-
-#include <boost/detail/workaround.hpp>
-
-#if !defined(BOOST_NO_STRINGSTREAM)
-# include <sstream>
-#endif
-
-#ifdef BOOST_HAS_WINTHREADS
-# include <windows.h>
-# include <tchar.h>
-# include <stdio.h>
-
-# 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)
-#endif
-
-#if defined(BOOST_ASSERT)
-# define BOOST_ASSERT_ELSE(expr) if ((BOOST_ASSERT(expr)), true)
-#else
-# define BOOST_ASSERT_ELSE(expr) if (true)
-#endif
-
-//The following macro checks for invalid loop conditions
-//by checking for wait loops that loop more than once.
-//Please note that this does not necessarily indicate any
-//kind of error; there are several valid reasons for
-//a wait loop to loop more than once. For instance:
-//1) if a condition signals a spurious wakeup,
-// it should wait again;
-//2) if a several waiting threads (e.g. readers) are
-// notified, and the first to wake changes conditions
-// so that the others should no longer wake (e.g.
-// by promoting itself to a writer), the wait loops
-// of the other threads, when they wake, will loop again
-// and they will wait again.
-//For this reason, the BOOST_ASSERT_LOOP_COUNT is only
-//enabled when specifically requested by #defining
-//the BOOST_READ_WRITE_MUTEX_TEST_LOOP_COUNTS macro.
-
-#if defined(BOOST_READ_WRITE_MUTEX_TEST_LOOP_COUNTS)
-# define BOOST_DEFINE_LOOP_COUNT int loop_count = 0;
-# define BOOST_ASSERT_LOOP_COUNT() BOOST_ASSERT(++loop_count == 1)
-#else
-# define BOOST_DEFINE_LOOP_COUNT do {} while(false);
-# define BOOST_ASSERT_LOOP_COUNT() do {} while(false)
-#endif
-
-bool boost_error(char const* expr, char const* func, char const* file, long line)
-{
- #if WINVER
- using namespace std;
-
- #ifndef ELEMENTS
- #define ELEMENTS(a) (sizeof(a)/sizeof(*(a)))
- #endif
-
- TCHAR message[200];
- _sntprintf(message,ELEMENTS(message),TEXT("Assertion failed (func=%s, file=%s, line=%d): %s"), func, file, line, expr);
-
- ::OutputDebugString(message);
-
- if(::IsDebuggerPresent())
- ::DebugBreak();
- #endif
-
- return false;
-}
-
-namespace boost {
-namespace detail {
-namespace thread {
-
-//----------------------------------------
-
-inline bool valid_lock_state(int state)
-{
- return (state >= 0) || (state == -1);
-}
-
-inline bool valid_read_write_locked(int state)
-{
- return state != 0;
-}
-
-inline bool valid_read_locked(int state)
-{
- return state > 0;
-}
-
-inline bool valid_read_lockable(int state)
-{
- return state >= 0;
-}
-
-inline bool valid_write_locked(int state)
-{
- return state == -1;
-}
-
-inline bool valid_write_lockable(int state)
-{
- return state == 0;
-}
-
-inline bool valid_promotable(int state)
-{
- return state == 1;
-}
-
-inline bool valid_unlocked(int state)
-{
- return state == 0;
-}
-
-//----------------------------------------
-
-class adjust_state
-{
-public:
-
- adjust_state(bool& state, bool adjust = true)
- : state_(state)
- , adjust_(adjust)
- {
- if (adjust_)
- state_ = true;
- }
-
- ~adjust_state(void)
- {
- adjust_now();
- }
-
- void set_adjust(bool adjust)
- {
- adjust_ = adjust;
- }
-
- void adjust_now(void)
- {
- if (adjust_)
- {
- BOOST_ASSERT(state_);
- state_ = false;
- }
- else
- {
- BOOST_ASSERT(!state_);
- }
- adjust_ = false;
- }
-
-private:
-
- bool& state_;
- bool adjust_;
-};
-
-//----------------------------------------
-
-class adjust_count
-{
-public:
-
- adjust_count(int& count, bool adjust = true)
- : count_(count)
- , adjust_(adjust)
- {
- if (adjust_)
- ++count_;
- }
-
- ~adjust_count(void)
- {
- adjust_now();
- }
-
- void set_adjust(bool adjust)
- {
- adjust_ = adjust;
- }
-
- void adjust_now(void)
- {
- if (adjust_)
- {
- BOOST_ASSERT(count_ > 0);
- if (count_ > 0)
- --count_;
- }
- else
- {
- BOOST_ASSERT(count_ >= 0);
- }
- adjust_ = false;
- }
-
-private:
-
- int& count_;
- bool adjust_;
-};
-
-//----------------------------------------
-
-/*
-Because of the possibility that threads that call
-timed_wait may timeout instead of waking, even after
-they have been notified, the counters m_num_waking_writers
-and m_num_waking_readers cannot be exact, but rather keep
-track of the minimum number of writers and readers (respectively)
-that are waking. For this reason, adjust_count may decrement
-too many times. The max_count mechanism is an attempt to
-keep track of the maximum as well.
-*/
-
-class adjust_dual_count
-{
-public:
-
- adjust_dual_count(int& count, int& max_count, bool adjust = true)
- : count_(count)
- , max_count_(max_count)
- , adjust_(adjust)
- {
- BOOST_ASSERT(&max_count_ != &count_);
- BOOST_ASSERT(max_count_ >= count_);
-
- if (adjust_)
- {
- ++count_;
- ++max_count_;
- }
- }
-
- ~adjust_dual_count(void)
- {
- adjust_now();
- }
-
- void set_adjust(bool adjust)
- {
- adjust_ = adjust;
- }
-
- void adjust_now(void)
- {
- BOOST_ASSERT(max_count_ >= count_);
-
- if (adjust_)
- {
- BOOST_ASSERT(max_count_ > 0);
- if (count_ > 0)
- --count_;
- if (max_count_ > 0)
- --max_count_;
- }
- else
- {
- BOOST_ASSERT(max_count_ >= 0);
- }
- adjust_ = false;
- }
-
-private:
-
- int& count_;
- int& max_count_;
- bool adjust_;
-};
-
-//----------------------------------------
-
-template<typename Mutex>
-read_write_mutex_impl<Mutex>::read_write_mutex_impl(read_write_scheduling_policy::read_write_scheduling_policy_enum sp)
- : m_sp(sp)
- , m_state(0)
- , m_num_waiting_writers(0)
- , m_num_waiting_readers(0)
- , m_state_waiting_promotion(false)
- , m_num_waking_writers(0)
- , m_num_waking_readers(0)
- , m_num_max_waking_writers(0)
- , m_num_max_waking_readers(0)
- , m_readers_next(true)
-{}
-
-#if !BOOST_WORKAROUND(__BORLANDC__, <= 0x564)
-template<typename Mutex>
-read_write_mutex_impl<Mutex>::~read_write_mutex_impl()
-{
- BOOST_ASSERT(valid_unlocked(m_state));
-
- BOOST_ASSERT(m_num_waiting_writers == 0);
- BOOST_ASSERT(m_num_waiting_readers == 0);
- BOOST_ASSERT(!m_state_waiting_promotion);
-
- BOOST_ASSERT(m_num_waking_writers == 0);
- BOOST_ASSERT(m_num_max_waking_writers == 0);
- BOOST_ASSERT(m_num_waking_readers == 0);
- BOOST_ASSERT(m_num_max_waking_readers == 0);
-}
-#endif
-
-template<typename Mutex>
-void read_write_mutex_impl<Mutex>::do_read_lock()
-{
- typename Mutex::scoped_lock l(m_prot);
- BOOST_READ_WRITE_MUTEX_TRACE("do_read_lock() enter");
- BOOST_ASSERT(valid_lock_state(m_state));
-
- if (m_sp == read_write_scheduling_policy::reader_priority)
- {
- //Reader priority: wait while write-locked
-
- BOOST_DEFINE_LOOP_COUNT;
- adjust_dual_count adjust_waking(m_num_waking_readers, m_num_max_waking_readers, false);
- while (m_state == -1)
- {
- BOOST_ASSERT_LOOP_COUNT(); //See note at BOOST_ASSERT_LOOP_COUNT definition above
- BOOST_ASSERT(waker_exists()); //There should be someone to wake us up
- adjust_count adjust_waiting(m_num_waiting_readers);
- adjust_waking.set_adjust(true);
- m_waiting_readers.wait(l);
- };
- }
- else if (m_sp == read_write_scheduling_policy::writer_priority)
- {
- //Writer priority: wait while write-locked or while writers are waiting
-
- BOOST_DEFINE_LOOP_COUNT;
- adjust_dual_count adjust_waking(m_num_waking_readers, m_num_max_waking_readers, false);
-//: if (m_num_waiting_writers > 0 && m_num_waking_writers == 0)
-//: do_wake_one_writer();
- while (m_state == -1 || (m_num_waking_writers > 0) || (m_num_waiting_writers > 0 && waker_exists()))
- {
- BOOST_ASSERT_LOOP_COUNT(); //See note at BOOST_ASSERT_LOOP_COUNT definition above
- BOOST_ASSERT(waker_exists()); //There should be someone to wake us up
- adjust_count adjust_waiting(m_num_waiting_readers);
- adjust_waking.set_adjust(true);
- m_waiting_readers.wait(l);
- }
- }
- else BOOST_ASSERT_ELSE(m_sp == read_write_scheduling_policy::alternating_single_read || m_sp == read_write_scheduling_policy::alternating_many_reads)
- {
- //Alternating priority: wait while write-locked or while not readers' turn
-
- BOOST_DEFINE_LOOP_COUNT
- adjust_dual_count adjust_waking(m_num_waking_readers, m_num_max_waking_readers, false);
- while (m_state == -1 || (m_num_waiting_writers > 0 && m_num_waking_readers == 0 && waker_exists()))
- {
- BOOST_ASSERT_LOOP_COUNT(); //See note at BOOST_ASSERT_LOOP_COUNT definition above
- BOOST_ASSERT(waker_exists()); //There should be someone to wake us up
- adjust_count adjust_waiting(m_num_waiting_readers);
- adjust_waking.set_adjust(true);
- m_waiting_readers.wait(l);
- }
- }
-
- //Obtain a read lock
-
- BOOST_ASSERT(valid_read_lockable(m_state));
- ++m_state;
-
- /*
- Set m_readers_next in the lock function rather than the
- unlock function to prevent thread starvation that can happen,
- e.g., like this: if all writer threads demote themselves
- to reader threads before unlocking, they will unlock using
- do_read_unlock() which will set m_readers_next = false;
- if there are enough writer threads, this will prevent any
- "true" reader threads from ever obtaining the lock.
- */
-
- m_readers_next = false;
-
- BOOST_ASSERT(valid_read_locked(m_state));
- BOOST_READ_WRITE_MUTEX_TRACE("do_read_lock() exit");
-}
-
-template<typename Mutex>
-void read_write_mutex_impl<Mutex>::do_write_lock()
-{
- typename Mutex::scoped_lock l(m_prot);
- BOOST_READ_WRITE_MUTEX_TRACE("do_write_lock() enter");
- BOOST_ASSERT(valid_lock_state(m_state));
-
- if (m_sp == read_write_scheduling_policy::reader_priority)
- {
- //Reader priority: wait while locked or while readers are waiting
-
- BOOST_DEFINE_LOOP_COUNT
- adjust_dual_count adjust_waking(m_num_waking_writers, m_num_max_waking_writers, false);
-//: if (m_num_waiting_readers > 0 && m_num_waking_readers == 0)
-//: do_wake_all_readers();
- while (m_state != 0 || (m_num_waking_readers > 0) || (m_num_waiting_readers > 0 && waker_exists()))
- {
- BOOST_ASSERT_LOOP_COUNT(); //See note at BOOST_ASSERT_LOOP_COUNT definition above
- BOOST_ASSERT(waker_exists()); //There should be someone to wake us up
- adjust_count adjust_waiting(m_num_waiting_writers);
- adjust_waking.set_adjust(true);
- m_waiting_writers.wait(l);
- }
- }
- else if (m_sp == read_write_scheduling_policy::writer_priority)
- {
- //Writer priority: wait while locked
-
- BOOST_DEFINE_LOOP_COUNT
- adjust_dual_count adjust_waking(m_num_waking_writers, m_num_max_waking_writers, false);
- while (m_state != 0)
- {
- BOOST_ASSERT_LOOP_COUNT(); //See note at BOOST_ASSERT_LOOP_COUNT definition above
- BOOST_ASSERT(waker_exists()); //There should be someone to wake us up
- adjust_count adjust_waiting(m_num_waiting_writers);
- adjust_waking.set_adjust(true);
- m_waiting_writers.wait(l);
- }
- }
- else BOOST_ASSERT_ELSE(m_sp == read_write_scheduling_policy::alternating_single_read || m_sp == read_write_scheduling_policy::alternating_many_reads)
- {
- //Shut down extra readers that were scheduled only because of no waiting writers
-
- if (m_sp == read_write_scheduling_policy::alternating_single_read && m_num_waiting_writers == 0)
- m_num_waking_readers = (m_readers_next && m_num_waking_readers > 0) ? 1 : 0;
-
- //Alternating priority: wait while locked or while not writers' turn
-
- BOOST_DEFINE_LOOP_COUNT
- adjust_dual_count adjust_waking(m_num_waking_writers, m_num_max_waking_writers, false);
- while (m_state != 0 || (m_num_waking_readers > 0 && waker_exists()))
- {
- BOOST_ASSERT_LOOP_COUNT(); //See note at BOOST_ASSERT_LOOP_COUNT definition above
- BOOST_ASSERT(waker_exists()); //There should be someone to wake us up
- adjust_count adjust_waiting(m_num_waiting_writers);
- adjust_waking.set_adjust(true);
- m_waiting_writers.wait(l);
- }
- }
-
- //Obtain a write lock
-
- BOOST_ASSERT(valid_write_lockable(m_state));
- m_state = -1;
-
- //See note in read_write_mutex_impl<>::do_read_lock() as to why
- //m_readers_next should be set here
-
- m_readers_next = true;
-
- BOOST_ASSERT(valid_write_locked(m_state));
- BOOST_READ_WRITE_MUTEX_TRACE("do_write_lock() exit");
-}
-
-template<typename Mutex>
-bool read_write_mutex_impl<Mutex>::do_try_read_lock()
-{
- typename Mutex::scoped_try_lock l(m_prot);
- BOOST_ASSERT(valid_lock_state(m_state));
- BOOST_READ_WRITE_MUTEX_TRACE("do_try_read_lock() enter");
-
- if (!l.locked())
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_try_read_lock() exit 1");
- return false;
- }
-
- bool fail;
-
- if (m_sp == read_write_scheduling_policy::reader_priority)
- {
- //Reader priority: fail if write-locked
- fail = (m_state == -1);
- }
- else if (m_sp == read_write_scheduling_policy::writer_priority)
- {
- //Writer priority: fail if write-locked or if writers are waiting
- fail = (m_state == -1 || m_num_waiting_writers > 0);
- }
- else BOOST_ASSERT_ELSE(m_sp == read_write_scheduling_policy::alternating_single_read || m_sp == read_write_scheduling_policy::alternating_many_reads)
- {
- //Alternating priority: fail if write-locked or if not readers' turn
- fail = (m_state == -1 || (m_num_waiting_writers > 0 && m_num_waking_readers == 0));
- }
-
- if (!fail)
- {
- //Obtain a read lock
-
- BOOST_ASSERT(valid_read_lockable(m_state));
- ++m_state;
-
- //See note in read_write_mutex_impl<>::do_read_lock() as to why
- //m_readers_next should be set here
-
- m_readers_next = false;
-
- BOOST_ASSERT(valid_read_locked(m_state));
- //Should be read-locked
- }
- else
- {
- BOOST_ASSERT(valid_write_locked(m_state) || m_num_waiting_writers > 0);
- //Should be write-locked or
- //writer should be waiting
- }
-
- BOOST_READ_WRITE_MUTEX_TRACE("do_try_read_lock() exit 2");
- return !fail;
-}
-
-template<typename Mutex>
-bool read_write_mutex_impl<Mutex>::do_try_write_lock()
-{
- typename Mutex::scoped_try_lock l(m_prot);
- BOOST_READ_WRITE_MUTEX_TRACE("do_try_write_lock() enter");
- BOOST_ASSERT(valid_lock_state(m_state));
-
- if (!l.locked())
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_try_write_lock() exit 1");
- return false;
- }
-
- bool fail;
-
- if (m_sp == read_write_scheduling_policy::reader_priority)
- {
- //Reader priority: fail if locked or if readers are waiting
- fail = (m_state != 0 || m_num_waiting_readers > 0);
- }
- else if (m_sp == read_write_scheduling_policy::writer_priority)
- {
- //Writer priority: fail if locked
- fail = (m_state != 0);
- }
- else BOOST_ASSERT_ELSE(m_sp == read_write_scheduling_policy::alternating_single_read || m_sp == read_write_scheduling_policy::alternating_many_reads)
- {
- //Alternating priority: fail if locked or if not writers' turn
- fail = (m_state != 0 || m_num_waking_readers > 0);
- }
-
- if (!fail)
- {
- //Obtain a write lock
-
- BOOST_ASSERT(valid_write_lockable(m_state));
- m_state = -1;
-
- //See note in read_write_mutex_impl<>::do_read_lock() as to why
- //m_readers_next should be set here
-
- m_readers_next = true;
-
- BOOST_ASSERT(valid_write_locked(m_state));
- //Should be write-locked
- }
- else
- {
- BOOST_ASSERT(valid_read_write_locked(m_state) || m_num_waiting_readers > 0);
- //Should be read-locked or write-locked, or
- //reader should be waiting
- }
-
- BOOST_READ_WRITE_MUTEX_TRACE("do_try_write_lock() exit 2");
- return !fail;
-}
-
-template<typename Mutex>
-bool read_write_mutex_impl<Mutex>::do_timed_read_lock(const boost::xtime &xt)
-{
- typename Mutex::scoped_timed_lock l(m_prot, xt);
- BOOST_READ_WRITE_MUTEX_TRACE("do_timed_read_lock() enter");
- BOOST_ASSERT(valid_lock_state(m_state));
-
- if (!l.locked())
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_timed_read_lock() exit 1");
- return false;
- }
-
- bool fail = false;
-
- if (m_sp == read_write_scheduling_policy::reader_priority)
- {
- //Reader priority: wait while write-locked
-
- BOOST_DEFINE_LOOP_COUNT
- adjust_dual_count adjust_waking(m_num_waking_readers, m_num_max_waking_readers, false);
- while (m_state == -1)
- {
- BOOST_ASSERT_LOOP_COUNT(); //See note at BOOST_ASSERT_LOOP_COUNT definition above
- BOOST_ASSERT(waker_exists()); //There should be someone to wake us up
- adjust_count adjust_waiting(m_num_waiting_readers);
- adjust_waking.set_adjust(true);
- if (!m_waiting_readers.timed_wait(l, xt))
- {
- ++m_num_max_waking_readers;
- fail = true;
- break;
- }
- }
- }
- else if (m_sp == read_write_scheduling_policy::writer_priority)
- {
- //Writer priority: wait while write-locked or while writers are waiting
-
- BOOST_DEFINE_LOOP_COUNT
- adjust_dual_count adjust_waking(m_num_waking_readers, m_num_max_waking_readers, false);
-//: if (m_num_waiting_writers > 0 && m_num_waking_writers == 0)
-//: do_wake_one_writer();
- while (m_state == -1 || (m_num_waking_writers > 0) || (m_num_waiting_writers > 0 && waker_exists()))
- {
- BOOST_ASSERT_LOOP_COUNT(); //See note at BOOST_ASSERT_LOOP_COUNT definition above
- BOOST_ASSERT(waker_exists()); //There should be someone to wake us up
- adjust_count adjust_waiting(m_num_waiting_readers);
- adjust_waking.set_adjust(true);
- if (!m_waiting_readers.timed_wait(l, xt))
- {
- ++m_num_max_waking_readers;
- fail = true;
- break;
- }
- }
- }
- else BOOST_ASSERT_ELSE(m_sp == read_write_scheduling_policy::alternating_single_read || m_sp == read_write_scheduling_policy::alternating_many_reads)
- {
- //Alternating priority: wait while write-locked or while not readers' turn
-
- BOOST_DEFINE_LOOP_COUNT
- while (m_state == -1 || (m_num_waiting_writers > 0 && m_num_waking_readers == 0 && waker_exists()))
- {
- adjust_dual_count adjust_waking(m_num_waking_readers, m_num_max_waking_readers, false);
- BOOST_ASSERT_LOOP_COUNT(); //See note at BOOST_ASSERT_LOOP_COUNT definition above
- BOOST_ASSERT(waker_exists()); //There should be someone to wake us up
- adjust_count adjust_waiting(m_num_waiting_readers);
- adjust_waking.set_adjust(true);
- if (!m_waiting_readers.timed_wait(l, xt))
- {
- ++m_num_max_waking_readers;
- fail = true;
- break;
- }
- }
- }
-
- if (!fail)
- {
- //Obtain a read lock
-
- BOOST_ASSERT(valid_read_lockable(m_state));
- ++m_state;
-
- //See note in read_write_mutex_impl<>::do_read_lock() as to why
- //m_readers_next should be set here
-
- m_readers_next = false;
-
- BOOST_ASSERT(valid_read_locked(m_state));
- //Should be read-locked
- }
- else
- {
- //In case there is no thread with a lock that will
- //call do_scheduling_impl() when it unlocks, call it ourselves
- do_scheduling_impl(scheduling_reason_timeout);
- }
-
- BOOST_READ_WRITE_MUTEX_TRACE("do_timed_read_lock() exit 2");
- return !fail;
-}
-
-template<typename Mutex>
-bool read_write_mutex_impl<Mutex>::do_timed_write_lock(const boost::xtime &xt)
-{
- typename Mutex::scoped_timed_lock l(m_prot, xt);
- BOOST_READ_WRITE_MUTEX_TRACE("do_timed_write_lock() enter");
- BOOST_ASSERT(valid_lock_state(m_state));
-
- if (!l.locked())
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_timed_write_lock() exit 1");
- return false;
- }
-
- bool fail = false;
-
- if (m_sp == read_write_scheduling_policy::reader_priority)
- {
- //Reader priority: wait while locked or while readers are waiting
-
- BOOST_DEFINE_LOOP_COUNT
- adjust_dual_count adjust_waking(m_num_waking_writers, m_num_max_waking_writers, false);
-//: if (m_num_waiting_readers > 0 && m_num_waking_readers == 0)
-//: do_wake_all_readers();
- while (m_state != 0 || (m_num_waking_readers > 0) || (m_num_waiting_readers > 0 && waker_exists()))
- {
- BOOST_ASSERT_LOOP_COUNT(); //See note at BOOST_ASSERT_LOOP_COUNT definition above
- BOOST_ASSERT(waker_exists()); //There should be someone to wake us up
- adjust_count adjust_waiting(m_num_waiting_writers);
- adjust_waking.set_adjust(true);
- if (!m_waiting_writers.timed_wait(l, xt))
- {
- ++m_num_max_waking_writers;
- fail = true;
- break;
- }
- }
- }
- else if (m_sp == read_write_scheduling_policy::writer_priority)
- {
- //Writer priority: wait while locked
-
- BOOST_DEFINE_LOOP_COUNT
- adjust_dual_count adjust_waking(m_num_waking_writers, m_num_max_waking_writers, false);
- while (m_state != 0)
- {
- BOOST_ASSERT_LOOP_COUNT(); //See note at BOOST_ASSERT_LOOP_COUNT definition above
- BOOST_ASSERT(waker_exists()); //There should be someone to wake us up
- adjust_count adjust_waiting(m_num_waiting_writers);
- adjust_waking.set_adjust(true);
- if (!m_waiting_writers.timed_wait(l, xt))
- {
- ++m_num_max_waking_writers;
- fail = true;
- break;
- }
- }
- }
- else BOOST_ASSERT_ELSE(m_sp == read_write_scheduling_policy::alternating_single_read || m_sp == read_write_scheduling_policy::alternating_many_reads)
- {
- //Shut down extra readers that were scheduled only because of no waiting writers
-
- if (m_sp == read_write_scheduling_policy::alternating_single_read && m_num_waiting_writers == 0)
- m_num_waking_readers = (m_readers_next && m_num_waking_readers > 0) ? 1 : 0;
-
- //Alternating priority: wait while locked or while not writers' turn
-
- BOOST_DEFINE_LOOP_COUNT
- adjust_dual_count adjust_waking(m_num_waking_writers, m_num_max_waking_writers, false);
- while (m_state != 0 || (m_num_waking_readers > 0 && waker_exists()))
- {
- BOOST_ASSERT_LOOP_COUNT(); //See note at BOOST_ASSERT_LOOP_COUNT definition above
- BOOST_ASSERT(waker_exists()); //There should be someone to wake us up
- adjust_count adjust_waiting(m_num_waiting_writers);
- adjust_waking.set_adjust(true);
- if (!m_waiting_writers.timed_wait(l, xt))
- {
- ++m_num_max_waking_writers;
- fail = true;
- break;
- }
- }
- }
-
- if (!fail)
- {
- //Obtain a write lock
-
- BOOST_ASSERT(valid_write_lockable(m_state));
- m_state = -1;
-
- //See note in read_write_mutex_impl<>::do_read_lock() as to why
- //m_readers_next should be set here
-
- m_readers_next = true;
-
- BOOST_ASSERT(valid_write_locked(m_state));
- //Should be write-locked
- }
- else
- {
- //In case there is no thread with a lock that will
- //call do_scheduling_impl() when it unlocks, call it ourselves
- do_scheduling_impl(scheduling_reason_timeout);
- }
-
- BOOST_READ_WRITE_MUTEX_TRACE("do_timed_write_lock() exit 2");
- return !fail;
-}
-
-template<typename Mutex>
-void read_write_mutex_impl<Mutex>::do_read_unlock()
-{
- typename Mutex::scoped_lock l(m_prot);
- BOOST_READ_WRITE_MUTEX_TRACE("do_read_unlock() enter");
- BOOST_ASSERT(valid_read_locked(m_state));
-
- if (m_state > 0)
- --m_state;
- else //not read-locked
- throw lock_error();
-
- do_scheduling_impl(scheduling_reason_unlock);
-
- BOOST_ASSERT(valid_read_locked(m_state) || valid_unlocked(m_state));
- BOOST_READ_WRITE_MUTEX_TRACE("do_read_unlock() exit");
-}
-
-template<typename Mutex>
-void read_write_mutex_impl<Mutex>::do_write_unlock()
-{
- typename Mutex::scoped_lock l(m_prot);
- BOOST_READ_WRITE_MUTEX_TRACE("do_write_unlock() enter");
- BOOST_ASSERT(valid_write_locked(m_state));
-
- if (m_state == -1)
- m_state = 0;
- else BOOST_ASSERT_ELSE(m_state >= 0)
- throw lock_error(); // Trying to release a reader-locked or unlocked mutex???
-
- do_scheduling_impl(scheduling_reason_unlock);
-
- BOOST_ASSERT(valid_unlocked(m_state));
- BOOST_READ_WRITE_MUTEX_TRACE("do_write_unlock() exit");
-}
-
-template<typename Mutex>
-bool read_write_mutex_impl<Mutex>::do_demote_to_read_lock_impl()
-{
- BOOST_READ_WRITE_MUTEX_TRACE("do_demote_to_read_lock_impl() enter");
- BOOST_ASSERT(valid_write_locked(m_state));
-
- if (m_state == -1)
- {
- //Convert from write lock to read lock
- m_state = 1;
-
- //If the conditions are right, release other readers
-
- do_scheduling_impl(scheduling_reason_demote);
-
- //Lock demoted
- BOOST_ASSERT(valid_read_locked(m_state));
- BOOST_READ_WRITE_MUTEX_TRACE("do_demote_to_read_lock_impl() exit 1");
- return true;
- }
- else BOOST_ASSERT_ELSE(m_state >= 0)
- {
- //Lock is read-locked or unlocked can't be demoted
- BOOST_READ_WRITE_MUTEX_TRACE("do_demote_to_read_lock_impl() exit 2");
- throw lock_error();
- return false;
- }
- return false; //Eliminate warnings on some compilers
-}
-
-template<typename Mutex>
-void read_write_mutex_impl<Mutex>::do_demote_to_read_lock()
-{
- typename Mutex::scoped_lock l(m_prot);
- BOOST_ASSERT(valid_write_locked(m_state));
-
- do_demote_to_read_lock_impl();
-}
-
-template<typename Mutex>
-bool read_write_mutex_impl<Mutex>::do_try_demote_to_read_lock()
-{
- typename Mutex::scoped_try_lock l(m_prot);
- BOOST_ASSERT(valid_write_locked(m_state));
-
- if (!l.locked())
- return false;
- else //(l.locked())
- return do_demote_to_read_lock_impl();
-}
-
-template<typename Mutex>
-bool read_write_mutex_impl<Mutex>::do_timed_demote_to_read_lock(const boost::xtime &xt)
-{
- typename Mutex::scoped_timed_lock l(m_prot, xt);
- BOOST_ASSERT(valid_write_locked(m_state));
-
- if (!l.locked())
- return false;
- else //(l.locked())
- return do_demote_to_read_lock_impl();
-}
-
-template<typename Mutex>
-void read_write_mutex_impl<Mutex>::do_promote_to_write_lock()
-{
- typename Mutex::scoped_lock l(m_prot);
- BOOST_READ_WRITE_MUTEX_TRACE("do_promote_to_write_lock() enter");
- BOOST_ASSERT(valid_read_locked(m_state));
-
- if (m_state == 1)
- {
- //Convert from read lock to write lock
- m_state = -1;
-
- //Lock promoted
- BOOST_ASSERT(valid_write_locked(m_state));
- }
- else if (m_state <= 0)
- {
- //Lock is write-locked or unlocked can't be promoted
- throw lock_error();
- }
- else if (m_state_waiting_promotion)
- {
- //Someone else is already trying to promote. Avoid deadlock by throwing exception.
- throw lock_error();
- }
- else BOOST_ASSERT_ELSE(m_state > 1 && !m_state_waiting_promotion)
- {
- BOOST_DEFINE_LOOP_COUNT
- adjust_dual_count adjust_waking(m_num_waking_writers, m_num_max_waking_writers, false);
- while (m_state > 1)
- {
- BOOST_ASSERT_LOOP_COUNT(); //See note at BOOST_ASSERT_LOOP_COUNT definition above
- BOOST_ASSERT(waker_exists()); //There should be someone to wake us up
- adjust_count adjust_waiting(m_num_waiting_writers);
- adjust_state adjust_waiting_promotion(m_state_waiting_promotion);
- adjust_waking.set_adjust(true);
- m_waiting_promotion.wait(l);
- }
-
- BOOST_ASSERT(m_num_waiting_writers >= 0);
- BOOST_ASSERT(valid_promotable(m_state));
-
- //Convert from read lock to write lock
- m_state = -1;
-
- //Lock promoted
- BOOST_ASSERT(valid_write_locked(m_state));
- }
- BOOST_READ_WRITE_MUTEX_TRACE("do_promote_to_write_lock() exit");
-}
-
-template<typename Mutex>
-bool read_write_mutex_impl<Mutex>::do_try_promote_to_write_lock()
-{
- typename Mutex::scoped_try_lock l(m_prot);
- BOOST_READ_WRITE_MUTEX_TRACE("do_try_promote_to_write_lock() enter");
- BOOST_ASSERT(valid_read_locked(m_state));
-
- bool result;
-
- if (!l.locked())
- result = false;
- else
- {
- if (m_state == 1)
- {
- //Convert from read lock to write lock
- m_state = -1;
-
- //Lock promoted
- BOOST_ASSERT(valid_write_locked(m_state));
- result = true;
- }
- else if (m_state <= 0)
- {
- //Lock is write-locked or unlocked can't be promoted
- result = false;
- }
- else if (m_state_waiting_promotion)
- {
- //Someone else is already trying to promote. Avoid deadlock by returning false.
- result = false;
- }
- else BOOST_ASSERT_ELSE(m_state > 1 && !m_state_waiting_promotion)
- {
- //There are other readers, so we can't promote
- result = false;
- }
- }
-
- BOOST_READ_WRITE_MUTEX_TRACE("do_try_promote_to_write_lock() exit");
- return result;
-}
-
-template<typename Mutex>
-bool read_write_mutex_impl<Mutex>::do_timed_promote_to_write_lock(const boost::xtime &xt)
-{
- typename Mutex::scoped_timed_lock l(m_prot, xt);
- BOOST_READ_WRITE_MUTEX_TRACE("do_timed_promote_to_write_lock() enter");
- BOOST_ASSERT(valid_read_locked(m_state));
-
- if (!l.locked())
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_timed_promote_to_write_lock( exit 1");
- return false;
- }
-
- bool fail = false;
-
- if (m_state == 1)
- {
- fail = false;
- }
- else if (m_state <= 0)
- {
- //Lock is not read-locked and can't be promoted
- fail = true;
- }
- else if (m_state_waiting_promotion)
- {
- //Someone else is already trying to promote. Avoid deadlock by returning false.
- fail = true;
- }
- else BOOST_ASSERT_ELSE(m_state > 1 && !m_state_waiting_promotion)
- {
- BOOST_DEFINE_LOOP_COUNT
- adjust_dual_count adjust_waking(m_num_waking_writers, m_num_max_waking_writers, false);
- while (m_state > 1)
- {
- BOOST_ASSERT_LOOP_COUNT(); //See note at BOOST_ASSERT_LOOP_COUNT definition above
- BOOST_ASSERT(waker_exists()); //There should be someone to wake us up
- adjust_count adjust_waiting(m_num_waiting_writers);
- adjust_state adjust_waiting_promotion(m_state_waiting_promotion);
- adjust_waking.set_adjust(true);
- if (!m_waiting_promotion.timed_wait(l, xt))
- {
- ++m_num_max_waking_writers;
- fail = true;
- break;
- }
- }
- }
-
- if (!fail)
- {
- //Convert from read lock to write lock
-
- BOOST_ASSERT(m_num_waiting_writers >= 0);
- BOOST_ASSERT(valid_promotable(m_state));
-
- m_state = -1;
-
- //Lock promoted
-
- BOOST_ASSERT(valid_write_locked(m_state));
- }
- else
- {
- //In case there is no thread with a lock that will
- //call do_scheduling_impl() when it unlocks, call it ourselves
- do_scheduling_impl(scheduling_reason_timeout);
- }
-
- BOOST_READ_WRITE_MUTEX_TRACE("do_timed_promote_to_write_lock( exit 2");
- return !fail;
-}
-
-template<typename Mutex>
-bool read_write_mutex_impl<Mutex>::locked()
-{
- int state = m_state;
- BOOST_ASSERT(valid_lock_state(state));
-
- return state != 0;
-}
-
-template<typename Mutex>
-read_write_lock_state::read_write_lock_state_enum read_write_mutex_impl<Mutex>::state()
-{
- int state = m_state;
- BOOST_ASSERT(valid_lock_state(state));
-
- if (state > 0)
- {
- BOOST_ASSERT(valid_read_locked(state));
- return read_write_lock_state::read_locked;
- }
- else if (state == -1)
- {
- BOOST_ASSERT(valid_write_locked(state));
- return read_write_lock_state::write_locked;
- }
- else BOOST_ASSERT_ELSE(state == 0)
- return read_write_lock_state::unlocked;
- return read_write_lock_state::unlocked; //Eliminate warnings on some compilers
-}
-
-template<typename Mutex>
-void read_write_mutex_impl<Mutex>::do_scheduling_impl(const scheduling_reason reason)
-{
- switch(reason)
- {
- case scheduling_reason_unlock:
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_scheduling_impl(): scheduling_reason_unlock");
-
- //A thread just unlocked, so there can be no existing write lock.
- //There may still be read locks, however.
-
- BOOST_ASSERT(valid_read_locked(m_state) || valid_unlocked(m_state));
-
- if (m_state_waiting_promotion)
- {
- //If a thread is waiting for promotion,
- //it must have a read lock.
-
- BOOST_ASSERT(valid_read_locked(m_state));
- }
- }
- break;
-
- case scheduling_reason_timeout:
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_scheduling_impl(): scheduling_reason_timeout");
-
- //A thread waiting for a lock just timed out, so the
- //lock could be in any state (read locked, write locked, unlocked).
-
- BOOST_ASSERT(valid_lock_state(m_state));
-
- if (m_state_waiting_promotion)
- {
- //If a thread is waiting for promotion,
- //it must have a read lock.
-
- BOOST_ASSERT(valid_read_locked(m_state));
- }
- }
- break;
-
- case scheduling_reason_demote:
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_scheduling_impl(): scheduling_reason_demote");
-
- //A write lock has just converted its state to a read lock;
- //since a write-locked thread has an exclusive lock,
- //and no other thread has yet been allowed to obtain
- //a read lock, the state should indicate that there is
- //exactly one reader.
-
- BOOST_ASSERT(m_state == 1);
-
- //No thread should be waiting for promotion because to do
- //so it would first have to obtain a read lock, which
- //is impossible because this thread had a write lock.
-
- BOOST_ASSERT(!m_state_waiting_promotion);
- }
- break;
-
- default:
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_scheduling_impl(): scheduling_reason_none");
-
- throw lock_error();
- return; //eliminate warnings on some compilers
- }
- break;
- };
-
- bool woken;
-
- if (m_num_waiting_writers > 0 && m_num_waiting_readers > 0)
- {
- //Both readers and writers waiting: use scheduling policy
-
- if (m_sp == read_write_scheduling_policy::reader_priority)
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_scheduling_impl() 1: writers & readers, reader_priority");
- woken = do_wake_all_readers();
- if (woken)
- m_num_waking_writers = m_num_max_waking_writers = 0; //shut down any waking writers
- }
- else if (m_sp == read_write_scheduling_policy::writer_priority)
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_scheduling_impl(): writers & readers, writer_priority");
- woken = do_wake_writer();
- if (woken)
- m_num_waking_readers = m_num_max_waking_readers = 0; //shut down any waking readers
- }
- else if (m_sp == read_write_scheduling_policy::alternating_single_read)
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_scheduling_impl() 2: writers & readers, alternating_single_read");
- if (m_readers_next)
- {
- if (m_num_waking_writers == 0)
- woken = do_wake_one_reader();
- else
- woken = false;
- }
- else
- {
- if (m_num_waking_readers == 0)
- woken = do_wake_writer();
- else
- woken = false;
- }
- }
- else BOOST_ASSERT_ELSE(m_sp == read_write_scheduling_policy::alternating_many_reads)
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_scheduling_impl() 3: writers & readers, alternating_many_reads");
- if (m_readers_next)
- {
- if (m_num_waking_writers == 0)
- woken = do_wake_all_readers();
- else
- woken = false;
- }
- else
- {
- if (m_num_waking_readers == 0)
- woken = do_wake_writer();
- else
- woken = false;
- }
- }
- }
- else if (m_num_waiting_writers > 0)
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_scheduling_impl() 4: writers only");
- //Only writers waiting--scheduling policy doesn't matter
- woken = do_wake_writer();
- }
- else if (m_num_waiting_readers > 0)
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_scheduling_impl() 5: readers only");
- //Only readers waiting--scheduling policy doesn't matter
- woken = do_wake_all_readers();
- }
- else
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_scheduling_impl() 6: no writers or readers");
- woken = false;
- }
-
- BOOST_ASSERT(
- woken
- || (m_state == -1) || (m_state > (m_state_waiting_promotion ? 1 : 0))
- || (m_num_waking_writers + m_num_waking_readers > 0)
- || (m_num_waiting_writers + m_num_waiting_readers == 0)
- );
- //Ensure that we woke a thread,
- //that another besides the current thread is already awake to wake others when it's done,
- //that another besides the current thread will wake and can wake others when it's done,
- //or that no other threads are waiting and so none remain to be woken
-}
-
-template<typename Mutex>
-bool read_write_mutex_impl<Mutex>::do_wake_one_reader(void)
-{
- if (m_state == -1)
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_wake_one_reader() 1: don't wake, write locked");
-
- //If write-locked, don't bother waking a reader
- }
- else if (m_num_waking_readers > 0)
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_wake_one_reader() 2: don't wake, nothing to wake");
-
- //If a reader is already waking,
- //don't bother waking another
- //(since we only want one)
- }
- else if (m_num_waiting_readers > 0)
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_wake_one_reader() 3: wake");
-
- //Wake a reader
- BOOST_ASSERT(valid_read_lockable(m_state));
- m_num_waking_readers = m_num_max_waking_readers = 1;
- m_waiting_readers.notify_one();
- return true;
- }
- else
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_wake_one_reader() 4: don't wake, nothing to wake");
- }
-
- return false;
-}
-
-template<typename Mutex>
-bool read_write_mutex_impl<Mutex>::do_wake_all_readers(void)
-{
- if (m_state == -1)
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_wake_all_readers() 1: don't wake, write locked");
-
- //If write-locked, don't bother waking readers
- }
- else if (m_num_waiting_readers > 0)
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_wake_all_readers() 2: wake");
-
- //Wake readers
- BOOST_ASSERT(valid_read_lockable(m_state));
- m_num_waking_readers = m_num_max_waking_readers = m_num_waiting_readers;
- m_waiting_readers.notify_all();
- return true;
- }
- else
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_wake_all_readers() 3: don't wake, nothing to wake");
- }
-
- return false;
-}
-
-template<typename Mutex>
-bool read_write_mutex_impl<Mutex>::do_wake_writer(void)
-{
- if (m_state_waiting_promotion)
- {
- //If a reader is waiting for promotion, promote it
- //(it holds a read lock until it is promoted,
- //so it's not possible to wake a normal writer).
-
- if (m_state == -1 || m_state > 1)
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_wake_writer() 1: waiting promotion: don't wake, still locked");
-
- //If write-locked, or if read-locked by
- //readers other than the thread waiting
- //for promotion, don't bother waking it
- }
- else if (m_num_waking_writers > 0)
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_wake_writer() 2: waiting promotion: don't wake, writer already waking");
-
- //If a writer is already waking,
- //don't bother waking another
- //(since only one at a time can wake anyway)
- }
- else if (m_num_waiting_writers > 0)
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_wake_writer() 3: waiting promotion: wake");
-
- //Wake the thread waiting for promotion
- BOOST_ASSERT(valid_promotable(m_state));
- m_num_waking_writers = m_num_max_waking_writers = 1;
- m_waiting_promotion.notify_one();
- return true;
- }
- else
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_wake_writer() 4: waiting promotion: don't wake, no writers to wake");
- }
- }
- else
- {
- if (m_state != 0)
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_wake_writer() 5: don't wake, still locked");
-
- //If locked, don't bother waking a writer
- }
- else if (m_num_waking_writers > 0)
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_wake_writer() 6: don't wake, writer already waking");
-
- //If a writer is already waking,
- //don't bother waking another
- //(since only one at a time can wake anyway)
- }
- else if (m_num_waiting_writers > 0)
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_wake_writer() 7: wake");
-
- //Wake a writer
- BOOST_ASSERT(valid_write_lockable(m_state));
- m_num_waking_writers = m_num_max_waking_writers = 1;
- m_waiting_writers.notify_one();
- return true;
- }
- else
- {
- BOOST_READ_WRITE_MUTEX_TRACE("do_wake_writer() 8: don't wake, no writers to wake");
- }
- }
-
- return false;
-}
-
-template<typename Mutex>
-bool read_write_mutex_impl<Mutex>::waker_exists(void)
-{
- //Is there a "live" thread (one that is awake or about to wake
- //that will be able to wake up a thread about to go to sleep?
- return valid_read_write_locked(m_state) || (m_num_waking_writers + m_num_waking_readers > 0);
-}
-
- } // namespace thread
- } // namespace detail
-
-read_write_mutex::read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp)
- : m_impl(sp)
-{}
-
-read_write_mutex::~read_write_mutex()
-{}
-
-void read_write_mutex::do_read_lock()
-{
- m_impl.do_read_lock();
-}
-
-void read_write_mutex::do_write_lock()
-{
- m_impl.do_write_lock();
-}
-
-void read_write_mutex::do_read_unlock()
-{
- m_impl.do_read_unlock();
-}
-
-void read_write_mutex::do_write_unlock()
-{
- m_impl.do_write_unlock();
-}
-
-void read_write_mutex::do_demote_to_read_lock()
-{
- m_impl.do_demote_to_read_lock();
-}
-
-void read_write_mutex::do_promote_to_write_lock()
-{
- m_impl.do_promote_to_write_lock();
-}
-
-bool read_write_mutex::locked()
-{
- return m_impl.locked();
-}
-
-read_write_lock_state::read_write_lock_state_enum read_write_mutex::state()
-{
- return m_impl.state();
-}
-
-try_read_write_mutex::try_read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp)
- : m_impl(sp)
-{}
-
-try_read_write_mutex::~try_read_write_mutex()
-{}
-
-void try_read_write_mutex::do_read_lock()
-{
- m_impl.do_read_lock();
-}
-
-void try_read_write_mutex::do_write_lock()
-{
- m_impl.do_write_lock();
-
-}
-
-void try_read_write_mutex::do_write_unlock()
-{
- m_impl.do_write_unlock();
-}
-
-void try_read_write_mutex::do_read_unlock()
-{
- m_impl.do_read_unlock();
-}
-
-bool try_read_write_mutex::do_try_read_lock()
-{
- return m_impl.do_try_read_lock();
-}
-
-bool try_read_write_mutex::do_try_write_lock()
-{
- return m_impl.do_try_write_lock();
-}
-
-void try_read_write_mutex::do_demote_to_read_lock()
-{
- m_impl.do_demote_to_read_lock();
-}
-
-bool try_read_write_mutex::do_try_demote_to_read_lock()
-{
- return m_impl.do_try_demote_to_read_lock();
-}
-
-void try_read_write_mutex::do_promote_to_write_lock()
-{
- m_impl.do_promote_to_write_lock();
-}
-
-bool try_read_write_mutex::do_try_promote_to_write_lock()
-{
- return m_impl.do_try_promote_to_write_lock();
-}
-
-bool try_read_write_mutex::locked()
-{
- return m_impl.locked();
-}
-
-read_write_lock_state::read_write_lock_state_enum try_read_write_mutex::state()
-{
- return m_impl.state();
-}
-
-timed_read_write_mutex::timed_read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp)
- : m_impl(sp)
-{}
-
-timed_read_write_mutex::~timed_read_write_mutex()
-{}
-
-void timed_read_write_mutex::do_read_lock()
-{
- m_impl.do_read_lock();
-}
-
-void timed_read_write_mutex::do_write_lock()
-{
- m_impl.do_write_lock();
-
-}
-
-void timed_read_write_mutex::do_read_unlock()
-{
- m_impl.do_read_unlock();
-}
-
-void timed_read_write_mutex::do_write_unlock()
-{
- m_impl.do_write_unlock();
-}
-
-bool timed_read_write_mutex::do_try_read_lock()
-{
- return m_impl.do_try_read_lock();
-}
-
-bool timed_read_write_mutex::do_try_write_lock()
-{
- return m_impl.do_try_write_lock();
-}
-
-bool timed_read_write_mutex::do_timed_read_lock(const xtime &xt)
-{
- return m_impl.do_timed_read_lock(xt);
-}
-
-bool timed_read_write_mutex::do_timed_write_lock(const xtime &xt)
-{
- return m_impl.do_timed_write_lock(xt);
-}
-
-void timed_read_write_mutex::do_demote_to_read_lock()
-{
- m_impl.do_demote_to_read_lock();
-}
-
-bool timed_read_write_mutex::do_try_demote_to_read_lock()
-{
- return m_impl.do_try_demote_to_read_lock();
-}
-
-bool timed_read_write_mutex::do_timed_demote_to_read_lock(const xtime &xt)
-{
- return m_impl.do_timed_demote_to_read_lock(xt);
-}
-
-void timed_read_write_mutex::do_promote_to_write_lock()
-{
- m_impl.do_promote_to_write_lock();
-}
-
-bool timed_read_write_mutex::do_try_promote_to_write_lock()
-{
- return m_impl.do_try_promote_to_write_lock();
-}
-
-bool timed_read_write_mutex::do_timed_promote_to_write_lock(const xtime &xt)
-{
- return m_impl.do_timed_promote_to_write_lock(xt);
-}
-
-bool timed_read_write_mutex::locked()
-{
- return m_impl.locked();
-}
-
-read_write_lock_state::read_write_lock_state_enum timed_read_write_mutex::state()
-{
- return m_impl.state();
-}
-
-#if !defined(NDEBUG)
- //Explicit instantiations of read/write locks to catch syntax errors in templates
-
- template class boost::detail::thread::scoped_read_write_lock<read_write_mutex>;
- template class boost::detail::thread::scoped_read_write_lock<try_read_write_mutex>;
- template class boost::detail::thread::scoped_read_write_lock<timed_read_write_mutex>;
-
- //template class boost::detail::thread::scoped_try_read_write_lock<read_write_mutex>;
- template class boost::detail::thread::scoped_try_read_write_lock<try_read_write_mutex>;
- template class boost::detail::thread::scoped_try_read_write_lock<timed_read_write_mutex>;
-
- //template class boost::detail::thread::scoped_timed_read_write_lock<read_write_mutex>;
- //template class boost::detail::thread::scoped_timed_read_write_lock<try_read_write_mutex>;
- template class boost::detail::thread::scoped_timed_read_write_lock<timed_read_write_mutex>;
-
- //Explicit instantiations of read locks to catch syntax errors in templates
-
- template class boost::detail::thread::scoped_read_lock<read_write_mutex>;
- template class boost::detail::thread::scoped_read_lock<try_read_write_mutex>;
- template class boost::detail::thread::scoped_read_lock<timed_read_write_mutex>;
-
- //template class boost::detail::thread::scoped_try_read_lock<read_write_mutex>;
- template class boost::detail::thread::scoped_try_read_lock<try_read_write_mutex>;
- template class boost::detail::thread::scoped_try_read_lock<timed_read_write_mutex>;
-
- //template class boost::detail::thread::scoped_timed_read_lock<read_write_mutex>;
- //template class boost::detail::thread::scoped_timed_read_lock<try_read_write_mutex>;
- template class boost::detail::thread::scoped_timed_read_lock<timed_read_write_mutex>;
-
- //Explicit instantiations of write locks to catch syntax errors in templates
-
- template class boost::detail::thread::scoped_write_lock<read_write_mutex>;
- template class boost::detail::thread::scoped_write_lock<try_read_write_mutex>;
- template class boost::detail::thread::scoped_write_lock<timed_read_write_mutex>;
-
- //template class boost::detail::thread::scoped_try_write_lock<read_write_mutex>;
- template class boost::detail::thread::scoped_try_write_lock<try_read_write_mutex>;
- template class boost::detail::thread::scoped_try_write_lock<timed_read_write_mutex>;
-
- //template class boost::detail::thread::scoped_timed_write_lock<read_write_mutex>;
- //template class boost::detail::thread::scoped_timed_write_lock<try_read_write_mutex>;
- template class boost::detail::thread::scoped_timed_write_lock<timed_read_write_mutex>;
-#endif
-} // namespace boost
-
-// Change Log:
-// 10 Mar 02
-// Original version.
-// 4 May 04 GlassfordM
-// For additional changes, see read_write_mutex.hpp.
-// Add many assertions to test validity of mutex state and operations.
-// Rework scheduling algorithm due to addition of lock promotion and
-// demotion.
-// Add explicit template instantiations to catch syntax errors
-// in templates.
Modified: trunk/libs/thread/src/recursive_mutex.cpp
==============================================================================
--- trunk/libs/thread/src/recursive_mutex.cpp (original)
+++ trunk/libs/thread/src/recursive_mutex.cpp 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -291,7 +291,8 @@
res = pthread_mutex_init(&m_mutex, &attr);
{
- int res = pthread_mutexattr_destroy(&attr);
+ int res = 0;
+ res = pthread_mutexattr_destroy(&attr);
assert(res == 0);
}
if (res != 0)
@@ -447,7 +448,8 @@
res = pthread_mutex_init(&m_mutex, &attr);
{
- int res = pthread_mutexattr_destroy(&attr);
+ int res = 0;
+ res = pthread_mutexattr_destroy(&attr);
assert(res == 0);
}
if (res != 0)
Modified: trunk/libs/thread/src/thread.cpp
==============================================================================
--- trunk/libs/thread/src/thread.cpp (original)
+++ trunk/libs/thread/src/thread.cpp 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -1,5 +1,6 @@
// Copyright (C) 2001-2003
// William E. Kempf
+// Copyright (C) 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)
@@ -89,18 +90,6 @@
bool m_started;
};
-#if defined(BOOST_HAS_WINTHREADS)
-
-struct on_thread_exit_guard
-{
- ~on_thread_exit_guard()
- {
- on_thread_exit();
- }
-};
-
-#endif
-
} // unnamed namespace
extern "C" {
@@ -112,25 +101,13 @@
static OSStatus thread_proxy(void* param)
#endif
{
-// try
- {
+ thread_param* p = static_cast<thread_param*>(param);
+ boost::function0<void> threadfunc = p->m_threadfunc;
+ p->started();
+ threadfunc();
#if defined(BOOST_HAS_WINTHREADS)
-
- on_thread_exit_guard guard;
-
+ on_thread_exit();
#endif
-
- thread_param* p = static_cast<thread_param*>(param);
- boost::function0<void> threadfunc = p->m_threadfunc;
- p->started();
- threadfunc();
- }
-// catch (...)
-// {
-//#if defined(BOOST_HAS_WINTHREADS)
-// on_thread_exit();
-//#endif
-// }
#if defined(BOOST_HAS_MPTASKS)
::boost::detail::thread_cleanup();
#endif
Modified: trunk/libs/thread/src/timeconv.inl
==============================================================================
--- trunk/libs/thread/src/timeconv.inl (original)
+++ trunk/libs/thread/src/timeconv.inl 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -3,6 +3,7 @@
//
// 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)
+
// boostinspect:nounnamed
namespace {
Modified: trunk/libs/thread/src/tss.cpp
==============================================================================
--- trunk/libs/thread/src/tss.cpp (original)
+++ trunk/libs/thread/src/tss.cpp 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -31,7 +31,7 @@
boost::mutex* tss_data_mutex = 0;
tss_data_cleanup_handlers_type* tss_data_cleanup_handlers = 0;
#if defined(BOOST_HAS_WINTHREADS)
- DWORD tss_data_native_key;
+ DWORD tss_data_native_key=TLS_OUT_OF_INDEXES;
#elif defined(BOOST_HAS_PTHREADS)
pthread_key_t tss_data_native_key;
#elif defined(BOOST_HAS_MPTASKS)
@@ -60,6 +60,7 @@
tss_data_mutex = 0;
#if defined(BOOST_HAS_WINTHREADS)
TlsFree(tss_data_native_key);
+ tss_data_native_key=TLS_OUT_OF_INDEXES;
#elif defined(BOOST_HAS_PTHREADS)
pthread_key_delete(tss_data_native_key);
#elif defined(BOOST_HAS_MPTASKS)
@@ -78,13 +79,17 @@
(*(*tss_data_cleanup_handlers)[i])((*slots)[i]);
(*slots)[i] = 0;
}
+#if defined(BOOST_HAS_WINTHREADS)
+ TlsSetValue(tss_data_native_key,0);
+#endif
tss_data_dec_use(lock);
delete slots;
}
void init_tss_data()
{
- std::auto_ptr<tss_data_cleanup_handlers_type> temp(new tss_data_cleanup_handlers_type);
+ std::auto_ptr<tss_data_cleanup_handlers_type>
+ temp(new tss_data_cleanup_handlers_type);
std::auto_ptr<boost::mutex> temp_mutex(new boost::mutex);
if (temp_mutex.get() == 0)
@@ -96,9 +101,8 @@
//Allocate tls slot
tss_data_native_key = TlsAlloc();
- if (tss_data_native_key == 0xFFFFFFFF)
+ if (tss_data_native_key == TLS_OUT_OF_INDEXES)
return;
-
#elif defined(BOOST_HAS_PTHREADS)
int res = pthread_key_create(&tss_data_native_key, &cleanup_slots);
if (res != 0)
Modified: trunk/libs/thread/src/tss_hooks.cpp
==============================================================================
--- trunk/libs/thread/src/tss_hooks.cpp (original)
+++ trunk/libs/thread/src/tss_hooks.cpp 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -1,7 +1,5 @@
-// (C) Copyright Michael Glassford 2004.
-// Copyright (c) 2006 Peter Dimov
-// Copyright (c) 2006 Anthony Williams
-//
+// Copyright (C) 2004 Michael Glassford
+// Copyright (C) 2006 Roland Schwarz
// Use, modification and distribution are subject to 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,152 +8,205 @@
#if defined(BOOST_HAS_WINTHREADS)
-#include <boost/thread/detail/tss_hooks.hpp>
+ #include <boost/thread/detail/tss_hooks.hpp>
-#include <boost/assert.hpp>
-#include <boost/thread/once.hpp>
+ #include <boost/assert.hpp>
+// #include <boost/thread/mutex.hpp>
+ #include <boost/thread/once.hpp>
-#include <list>
+ #include <list>
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
-namespace
-{
-
-typedef std::list<thread_exit_handler> thread_exit_handlers;
+ namespace
+ {
+ class CScopedCSLock
+ {
+ public:
+ CScopedCSLock(LPCRITICAL_SECTION cs) : cs(cs), lk(true) {
+ ::EnterCriticalSection(cs);
+ }
+ ~CScopedCSLock() {
+ if (lk) ::LeaveCriticalSection(cs);
+ }
+ void Unlock() {
+ lk = false;
+ ::LeaveCriticalSection(cs);
+ }
+ private:
+ bool lk;
+ LPCRITICAL_SECTION cs;
+ };
+
+ typedef std::list<thread_exit_handler> thread_exit_handlers;
+
+ boost::once_flag once_init_threadmon_mutex = BOOST_ONCE_INIT;
+ //boost::mutex* threadmon_mutex;
+ // We don't use boost::mutex here, to avoid a memory leak report,
+ // because we cannot delete it again easily.
+ CRITICAL_SECTION threadmon_mutex;
+ void init_threadmon_mutex(void)
+ {
+ //threadmon_mutex = new boost::mutex;
+ //if (!threadmon_mutex)
+ // throw boost::thread_resource_error();
+ ::InitializeCriticalSection(&threadmon_mutex);
+ }
-const DWORD invalid_tls_key = TLS_OUT_OF_INDEXES;
-DWORD tls_key = invalid_tls_key;
+ const DWORD invalid_tls_key = TLS_OUT_OF_INDEXES;
+ DWORD tls_key = invalid_tls_key;
-boost::once_flag once_init_tls_key = BOOST_ONCE_INIT;
+ unsigned long attached_thread_count = 0;
+ }
-void init_tls_key()
-{
- tls_key = TlsAlloc();
-}
+ /*
+ Calls to DllMain() and tls_callback() are serialized by the OS;
+ however, calls to at_thread_exit are not, so it must be protected
+ by a mutex. Since we already need a mutex for at_thread_exit(),
+ and since there is no guarantee that on_process_enter(),
+ on_process_exit(), on_thread_enter(), and on_thread_exit()
+ will be called only from DllMain() or tls_callback(), it makes
+ sense to protect those, too.
+ */
-} // unnamed namespace
+ extern "C" BOOST_THREAD_DECL int at_thread_exit(
+ thread_exit_handler exit_handler
+ )
+ {
+ boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
+ //boost::mutex::scoped_lock lock(*threadmon_mutex);
+ CScopedCSLock lock(&threadmon_mutex);
-extern "C" BOOST_THREAD_DECL int at_thread_exit( thread_exit_handler exit_handler )
-{
- boost::call_once( init_tls_key, once_init_tls_key );
+ //Allocate a tls slot if necessary.
- if( tls_key == invalid_tls_key )
- {
- return -1;
- }
+ if (tls_key == invalid_tls_key)
+ tls_key = TlsAlloc();
- // Get the exit handlers list for the current thread from tls.
+ if (tls_key == invalid_tls_key)
+ return -1;
- thread_exit_handlers* exit_handlers =
- static_cast< thread_exit_handlers* >( TlsGetValue( tls_key ) );
+ //Get the exit handlers list for the current thread from tls.
- if( exit_handlers == 0 )
- {
- // No exit handlers list was created yet.
+ thread_exit_handlers* exit_handlers =
+ static_cast<thread_exit_handlers*>(TlsGetValue(tls_key));
- try
+ if (!exit_handlers)
{
- // Attempt to create a new exit handlers list.
+ //No exit handlers list was created yet.
- exit_handlers = new thread_exit_handlers;
+ try
+ {
+ //Attempt to create a new exit handlers list.
- if( exit_handlers == 0 )
+ exit_handlers = new thread_exit_handlers;
+ if (!exit_handlers)
+ return -1;
+
+ //Attempt to store the list pointer in tls.
+
+ if (TlsSetValue(tls_key, exit_handlers))
+ ++attached_thread_count;
+ else
+ {
+ delete exit_handlers;
+ return -1;
+ }
+ }
+ catch (...)
{
return -1;
}
+ }
- // Attempt to store the list pointer in tls.
+ //Like the C runtime library atexit() function,
+ //functions should be called in the reverse of
+ //the order they are added, so push them on the
+ //front of the list.
- if( !TlsSetValue( tls_key, exit_handlers ) )
- {
- delete exit_handlers;
- return -1;
- }
+ try
+ {
+ exit_handlers->push_front(exit_handler);
}
- catch( ... )
+ catch (...)
{
return -1;
}
- }
- // Like the C runtime library atexit() function,
- // functions should be called in the reverse of
- // the order they are added, so push them on the
- // front of the list.
+ //Like the atexit() function, a result of zero
+ //indicates success.
- try
- {
- exit_handlers->push_front( exit_handler );
+ return 0;
}
- catch( ... )
+
+ extern "C" BOOST_THREAD_DECL void on_process_enter(void)
{
- return -1;
+ boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
+// boost::mutex::scoped_lock lock(*threadmon_mutex);
+ CScopedCSLock lock(&threadmon_mutex);
+
+ BOOST_ASSERT(attached_thread_count == 0);
}
- // Like the atexit() function, a result of zero
- // indicates success.
+ extern "C" BOOST_THREAD_DECL void on_process_exit(void)
+ {
+ boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
+// boost::mutex::scoped_lock lock(*threadmon_mutex);
+ CScopedCSLock lock(&threadmon_mutex);
- return 0;
-}
+ BOOST_ASSERT(attached_thread_count == 0);
-extern "C" BOOST_THREAD_DECL void on_process_enter()
-{
-}
+ //Free the tls slot if one was allocated.
-extern "C" BOOST_THREAD_DECL void on_process_exit()
-{
- if( tls_key != invalid_tls_key )
+ if (tls_key != invalid_tls_key)
+ {
+ TlsFree(tls_key);
+ tls_key = invalid_tls_key;
+ }
+ }
+
+ extern "C" BOOST_THREAD_DECL void on_thread_enter(void)
{
- TlsFree(tls_key);
+ //boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
+ //boost::mutex::scoped_lock lock(*threadmon_mutex);
}
-}
-extern "C" BOOST_THREAD_DECL void on_thread_enter()
-{
-}
+ extern "C" BOOST_THREAD_DECL void on_thread_exit(void)
+ {
+ boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
+// boost::mutex::scoped_lock lock(*threadmon_mutex);
+ CScopedCSLock lock(&threadmon_mutex);
-extern "C" BOOST_THREAD_DECL void on_thread_exit()
-{
- // Initializing tls_key here ensures its proper visibility
- boost::call_once( init_tls_key, once_init_tls_key );
+ //Get the exit handlers list for the current thread from tls.
- // Get the exit handlers list for the current thread from tls.
+ if (tls_key == invalid_tls_key)
+ return;
- if( tls_key == invalid_tls_key )
- {
- return;
- }
+ thread_exit_handlers* exit_handlers =
+ static_cast<thread_exit_handlers*>(TlsGetValue(tls_key));
- thread_exit_handlers* exit_handlers =
- static_cast< thread_exit_handlers* >( TlsGetValue( tls_key ) );
+ //If a handlers list was found, use it.
- // If a handlers list was found, invoke its handlers.
+ if (exit_handlers && TlsSetValue(tls_key, 0))
+ {
+ BOOST_ASSERT(attached_thread_count > 0);
+ --attached_thread_count;
- if( exit_handlers != 0 )
- {
- // Call each handler and remove it from the list
+ //lock.unlock();
+ lock.Unlock();
- while( !exit_handlers->empty() )
- {
- if( thread_exit_handler exit_handler = *exit_handlers->begin() )
+ //Call each handler and remove it from the list
+
+ while (!exit_handlers->empty())
{
- (*exit_handler)();
+ if (thread_exit_handler exit_handler = *exit_handlers->begin())
+ (*exit_handler)();
+ exit_handlers->pop_front();
}
- exit_handlers->pop_front();
- }
-
- // If TlsSetValue fails, we can't delete the list,
- // since a second call to on_thread_exit will try
- // to access it.
-
- if( TlsSetValue( tls_key, 0 ) )
- {
delete exit_handlers;
+ exit_handlers = 0;
}
}
-}
#endif //defined(BOOST_HAS_WINTHREADS)
Modified: trunk/libs/thread/test/Jamfile.v2
==============================================================================
--- trunk/libs/thread/test/Jamfile.v2 (original)
+++ trunk/libs/thread/test/Jamfile.v2 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -40,6 +40,6 @@
[ thread-run test_once.cpp ]
[ thread-run test_xtime.cpp ]
[ thread-run test_barrier.cpp ]
- [ thread-run test_read_write_mutex.cpp ]
+# [ thread-run test_read_write_mutex.cpp ]
;
}
Deleted: trunk/libs/thread/test/test_read_write_mutex.cpp
==============================================================================
--- trunk/libs/thread/test/test_read_write_mutex.cpp 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
+++ (empty file)
@@ -1,786 +0,0 @@
-// Copyright (C) 2001-2003
-// William E. Kempf
-//
-// 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 <boost/thread/detail/config.hpp>
-
-#include <boost/thread/thread.hpp>
-#include <boost/thread/xtime.hpp>
-#include <boost/thread/read_write_mutex.hpp>
-
-#include <boost/test/unit_test.hpp>
-
-#include <iostream>
-
-#define TS_CHECK(pred) \
- do { if (!(pred)) BOOST_ERROR (#pred); } while (0)
-#define TS_CHECK_MSG(pred, msg) \
- do { if (!(pred)) BOOST_ERROR (msg); } while (0)
-
-namespace {
-
-int shared_val = 0;
-
-boost::xtime xsecs(int secs)
-{
- //Create an xtime that is secs seconds from now
- boost::xtime ret;
- TS_CHECK (boost::TIME_UTC == boost::xtime_get(&ret, boost::TIME_UTC));
- ret.sec += secs;
- return ret;
-}
-
-#define MESSAGE "w1=" << w1.value_ << ", w2=" << w2.value_ << ", r1=" << r1.value_ << ", r2=" << r2.value_
-
-template <typename RW>
-class thread_adapter
-{
-public:
-
- thread_adapter(
- void (*func)(void*, RW&),
- void* param1,
- RW ¶m2
- )
- : func_(func)
- , param1_(param1)
- , param2_(param2)
- {}
-
- void operator()() const
- {
- func_(param1_, param2_);
- }
-
-private:
-
- void (*func_)(void*, RW&);
- void* param1_;
- RW& param2_;
-};
-
-const int k_data_init = -1;
-
-template <typename RW>
-struct data
-{
- data(
- int id,
- RW& m,
- int wait_for_lock_secs,
- int sleep_with_lock_secs,
- bool demote_after_write = false
- )
- : id_(id)
- , wait_for_lock_secs_(wait_for_lock_secs)
- , sleep_with_lock_secs_(sleep_with_lock_secs)
- , test_promotion_and_demotion_(demote_after_write)
- , value_(k_data_init)
- , rw_(m)
- {}
-
- int id_;
- int wait_for_lock_secs_;
- int sleep_with_lock_secs_;
- bool test_promotion_and_demotion_;
- int value_;
-
- RW& rw_;
-};
-
-template<typename RW>
-void plain_writer(void* arg, RW& rw)
-{
- try
- {
- data<RW>* pdata = (data<RW>*) arg;
- TS_CHECK_MSG(pdata->wait_for_lock_secs_ == 0, "pdata->wait_for_lock_secs_: " << pdata->wait_for_lock_secs_);
-
- typename RW::scoped_read_write_lock l(
- rw,
- pdata->test_promotion_and_demotion_
- ? boost::read_write_lock_state::read_locked
- : boost::read_write_lock_state::write_locked
- );
-
- bool succeeded = true;
-
- if (pdata->test_promotion_and_demotion_)
- {
- try
- {
- l.promote();
- }
- catch(const boost::lock_error&)
- {
- succeeded = false;
- }
- }
-
- if (succeeded)
- {
- if (pdata->sleep_with_lock_secs_ > 0)
- boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
-
- shared_val += 10;
-
- if (pdata->test_promotion_and_demotion_)
- l.demote();
-
- pdata->value_ = shared_val;
- }
- }
- catch(...)
- {
- TS_CHECK_MSG(false, "plain_writer() exception!");
- throw;
- }
-}
-
-template<typename RW>
-void plain_reader(void* arg, RW& rw)
-{
- try
- {
- data<RW>* pdata = (data<RW>*)arg;
- TS_CHECK(!pdata->test_promotion_and_demotion_);
- TS_CHECK_MSG(pdata->wait_for_lock_secs_ == 0, "pdata->wait_for_lock_secs_: " << pdata->wait_for_lock_secs_);
-
- typename RW::scoped_read_write_lock l(rw, boost::read_write_lock_state::read_locked);
-
- if (pdata->sleep_with_lock_secs_ > 0)
- boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
-
- pdata->value_ = shared_val;
- }
- catch(...)
- {
- TS_CHECK_MSG(false, "plain_reader() exception!");
- throw;
- }
-}
-
-template<typename RW>
-void try_writer(void* arg, RW& rw)
-{
- try
- {
- data<RW>* pdata = (data<RW>*) arg;
- TS_CHECK_MSG(pdata->wait_for_lock_secs_ == 0, "pdata->wait_for_lock_secs_: " << pdata->wait_for_lock_secs_);
-
- typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::unlocked);
-
- bool succeeded = false;
-
- if (pdata->test_promotion_and_demotion_)
- succeeded = l.try_read_lock() && l.try_promote();
- else
- succeeded = l.try_write_lock();
-
- if (succeeded)
- {
- if (pdata->sleep_with_lock_secs_ > 0)
- boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
-
- shared_val += 10;
-
- if (pdata->test_promotion_and_demotion_)
- l.demote();
-
- pdata->value_ = shared_val;
- }
- }
- catch(...)
- {
- TS_CHECK_MSG(false, "try_writer() exception!");
- throw;
- }
-}
-
-template<typename RW>
-void try_reader(void*arg, RW& rw)
-{
- try
- {
- data<RW>* pdata = (data<RW>*)arg;
- TS_CHECK(!pdata->test_promotion_and_demotion_);
- TS_CHECK_MSG(pdata->wait_for_lock_secs_ == 0, "pdata->wait_for_lock_secs_: " << pdata->wait_for_lock_secs_);
-
- typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::unlocked);
-
- if (l.try_read_lock())
- {
- if (pdata->sleep_with_lock_secs_ > 0)
- boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
-
- pdata->value_ = shared_val;
- }
- }
- catch(...)
- {
- TS_CHECK_MSG(false, "try_reader() exception!");
- throw;
- }
-}
-
-template<typename RW>
-void timed_writer(void* arg, RW& rw)
-{
- try
- {
- data<RW>* pdata = (data<RW>*)arg;
-
- typename RW::scoped_timed_read_write_lock l(rw, boost::read_write_lock_state::unlocked);
-
- bool succeeded = false;
-
- boost::xtime xt = xsecs(pdata->wait_for_lock_secs_);
- if (pdata->test_promotion_and_demotion_)
- succeeded = l.timed_read_lock(xt) && l.timed_promote(xt);
- else
- succeeded = l.timed_write_lock(xt);
-
- if (succeeded)
- {
- if (pdata->sleep_with_lock_secs_ > 0)
- boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
-
- shared_val += 10;
-
- if (pdata->test_promotion_and_demotion_)
- l.demote();
-
- pdata->value_ = shared_val;
- }
- }
- catch(...)
- {
- TS_CHECK_MSG(false, "timed_writer() exception!");
- throw;
- }
-}
-
-template<typename RW>
-void timed_reader(void* arg, RW& rw)
-{
- try
- {
- data<RW>* pdata = (data<RW>*)arg;
- TS_CHECK(!pdata->test_promotion_and_demotion_);
-
- typename RW::scoped_timed_read_write_lock l(rw,boost::read_write_lock_state::unlocked);
-
- boost::xtime xt = xsecs(pdata->wait_for_lock_secs_);
- if (l.timed_read_lock(xt))
- {
- if (pdata->sleep_with_lock_secs_ > 0)
- boost::thread::sleep(xsecs(pdata->sleep_with_lock_secs_));
-
- pdata->value_ = shared_val;
- }
- }
- catch(...)
- {
- TS_CHECK_MSG(false, "timed_reader() exception!");
- throw;
- }
-}
-
-template<typename RW>
-void clear_data(data<RW>& data1, data<RW>& data2, data<RW>& data3, data<RW>& data4)
-{
- shared_val = 0;
- data1.value_ = k_data_init;
- data2.value_ = k_data_init;
- data3.value_ = k_data_init;
- data4.value_ = k_data_init;
-}
-
-bool shared_test_writelocked = false;
-bool shared_test_readlocked = false;
-bool shared_test_unlocked = false;
-
-template<typename RW>
-void run_try_tests(void* arg, RW& rw)
-{
- try
- {
- TS_CHECK(shared_test_writelocked || shared_test_readlocked || shared_test_unlocked);
-
- typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::unlocked);
-
- if (shared_test_writelocked)
- {
- //Verify that write lock blocks other write locks
- TS_CHECK(!l.try_write_lock());
-
- //Verify that write lock blocks read locks
- TS_CHECK(!l.try_read_lock());
- }
- else if (shared_test_readlocked)
- {
- //Verify that read lock blocks write locks
- TS_CHECK(!l.try_write_lock());
-
- //Verify that read lock does not block other read locks
- TS_CHECK(l.try_read_lock());
-
- //Verify that read lock blocks promotion
- TS_CHECK(!l.try_promote());
- }
- else if (shared_test_unlocked)
- {
- //Verify that unlocked does not blocks write locks
- TS_CHECK(l.try_write_lock());
-
- //Verify that unlocked does not block demotion
- TS_CHECK(l.try_demote());
-
- l.unlock();
-
- //Verify that unlocked does not block read locks
- TS_CHECK(l.try_read_lock());
-
- //Verify that unlocked does not block promotion
- TS_CHECK(l.try_promote());
-
- l.unlock();
- }
- }
- catch(...)
- {
- TS_CHECK_MSG(false, "run_try_tests() exception!");
- throw;
- }
-}
-
-template<typename RW>
-void test_plain_read_write_mutex(RW& rw, bool test_promotion_and_demotion)
-{
- //Verify that a write lock prevents both readers and writers from obtaining a lock
- {
- shared_val = 0;
- data<RW> r1(1, rw, 0, 0);
- data<RW> r2(2, rw, 0, 0);
- data<RW> w1(3, rw, 0, 0);
- data<RW> w2(4, rw, 0, 0);
-
- //Write-lock the mutex and queue up other readers and writers
-
- typename RW::scoped_read_write_lock l(rw, boost::read_write_lock_state::write_locked);
-
- boost::thread tr1(thread_adapter<RW>(plain_reader, &r1, rw));
- boost::thread tr2(thread_adapter<RW>(plain_reader, &r2, rw));
- boost::thread tw1(thread_adapter<RW>(plain_writer, &w1, rw));
- boost::thread tw2(thread_adapter<RW>(plain_writer, &w2, rw));
-
- boost::thread::sleep(xsecs(1));
-
- //At this point, neither queued readers nor queued writers should have obtained access
-
- TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(r1.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(r2.value_ == k_data_init, MESSAGE);
-
- if (test_promotion_and_demotion)
- {
- l.demote();
- boost::thread::sleep(xsecs(1));
- //:boost::thread tr3(thread_adapter<RW>(plain_reader, &r3, rw));
-
- if (rw.policy() == boost::read_write_scheduling_policy::writer_priority)
- {
- //Expected result:
- //Since writers have priority, demotion doesn't release any readers.
- TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(r1.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(r2.value_ == k_data_init, MESSAGE);
- }
- else if (rw.policy() == boost::read_write_scheduling_policy::reader_priority)
- {
- //Expected result:
- //Since readers have priority, demotion releases all readers.
- TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
- TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
- }
- else if (rw.policy() == boost::read_write_scheduling_policy::alternating_many_reads)
- {
- //Expected result:
- //Since readers can be released many at a time, demotion releases all queued readers.
- TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
- TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
- //:TS_CHECK_MSG(r3.value_ == k_data_init, MESSAGE);
- }
- else if (rw.policy() == boost::read_write_scheduling_policy::alternating_single_read)
- {
- //Expected result:
- //Since readers can be released only one at a time, demotion releases one queued reader.
- TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(r1.value_ == k_data_init || r1.value_ == 0, MESSAGE);
- TS_CHECK_MSG(r2.value_ == k_data_init || r2.value_ == 0, MESSAGE);
- TS_CHECK_MSG(r1.value_ != r2.value_, MESSAGE);
- }
- }
-
- l.unlock();
-
- tr2.join();
- tr1.join();
- tw2.join();
- tw1.join();
-
- if (rw.policy() == boost::read_write_scheduling_policy::writer_priority)
- {
- if (!test_promotion_and_demotion)
- {
- //Expected result:
- //1) either w1 or w2 obtains and releases the lock
- //2) the other of w1 and w2 obtains and releases the lock
- //3) r1 and r2 obtain and release the lock "simultaneously"
- TS_CHECK_MSG(w1.value_ == 10 || w1.value_ == 20, MESSAGE);
- TS_CHECK_MSG(w2.value_ == 10 || w2.value_ == 20, MESSAGE);
- TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
- TS_CHECK_MSG(r1.value_ == 20, MESSAGE);
- TS_CHECK_MSG(r2.value_ == 20, MESSAGE);
- }
- else
- {
- //Expected result:
- //The same, except that either w1 or w2 (but not both) may
- //fail to promote to a write lock,
- //and r1, r2, or both may "sneak in" ahead of w1 and/or w2
- //by obtaining a read lock before w1 or w2 can promote
- //their initial read lock to a write lock.
- TS_CHECK_MSG(w1.value_ == k_data_init || w1.value_ == 10 || w1.value_ == 20, MESSAGE);
- TS_CHECK_MSG(w2.value_ == k_data_init || w2.value_ == 10 || w2.value_ == 20, MESSAGE);
- TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
- TS_CHECK_MSG(r1.value_ == k_data_init || r1.value_ == 10 || r1.value_ == 20, MESSAGE);
- TS_CHECK_MSG(r2.value_ == k_data_init || r2.value_ == 10 || r2.value_ == 20, MESSAGE);
- }
- }
- else if (rw.policy() == boost::read_write_scheduling_policy::reader_priority)
- {
- if (!test_promotion_and_demotion)
- {
- //Expected result:
- //1) r1 and r2 obtain and release the lock "simultaneously"
- //2) either w1 or w2 obtains and releases the lock
- //3) the other of w1 and w2 obtains and releases the lock
- TS_CHECK_MSG(w1.value_ == 10 || w1.value_ == 20, MESSAGE);
- TS_CHECK_MSG(w2.value_ == 10 || w2.value_ == 20, MESSAGE);
- TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
- TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
- TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
- }
- else
- {
- //Expected result:
- //The same, except that either w1 or w2 (but not both) may
- //fail to promote to a write lock.
- TS_CHECK_MSG(w1.value_ == k_data_init || w1.value_ == 10 || w1.value_ == 20, MESSAGE);
- TS_CHECK_MSG(w2.value_ == k_data_init || w2.value_ == 10 || w2.value_ == 20, MESSAGE);
- TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
- TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
- TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
- }
- }
- else if (rw.policy() == boost::read_write_scheduling_policy::alternating_many_reads)
- {
- if (!test_promotion_and_demotion)
- {
- //Expected result:
- //1) r1 and r2 obtain and release the lock "simultaneously"
- //2) either w1 or w2 obtains and releases the lock
- //3) the other of w1 and w2 obtains and releases the lock
- TS_CHECK_MSG(w1.value_ == 10 || w1.value_ == 20, MESSAGE);
- TS_CHECK_MSG(w2.value_ == 10 || w2.value_ == 20, MESSAGE);
- TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
- TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
- TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
- }
- else
- {
- //Expected result:
- //The same, except that either w1 or w2 (but not both) may
- //fail to promote to a write lock.
- TS_CHECK_MSG(w1.value_ == k_data_init || w1.value_ == 10 || w1.value_ == 20, MESSAGE);
- TS_CHECK_MSG(w2.value_ == k_data_init || w2.value_ == 10 || w2.value_ == 20, MESSAGE);
- TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
- TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
- TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
- }
- }
- else if (rw.policy() == boost::read_write_scheduling_policy::alternating_single_read)
- {
- if (!test_promotion_and_demotion)
- {
- //Expected result:
- //1) either r1 or r2 obtains and releases the lock
- //2) either w1 or w2 obtains and releases the lock
- //3) the other of r1 and r2 obtains and releases the lock
- //4) the other of w1 and w2 obtains and release the lock
- TS_CHECK_MSG(w1.value_ == 10 || w1.value_ == 20, MESSAGE);
- TS_CHECK_MSG(w2.value_ == 10 || w2.value_ == 20, MESSAGE);
- TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
- TS_CHECK_MSG(r1.value_ == 0 || r1.value_ == 10, MESSAGE);
- TS_CHECK_MSG(r2.value_ == 0 || r2.value_ == 10, MESSAGE);
- TS_CHECK_MSG(r1.value_ != r2.value_, MESSAGE);
- }
- else
- {
- //Expected result:
- //Since w1 and w2 start as read locks, r1, r2, w1, and w2
- //obtain read locks "simultaneously". Each of w1 and w2,
- //after it obtain a read lock, attempts to promote to a
- //write lock; this attempt fails if the other has
- //already done so and currently holds the write lock;
- //otherwise it will succeed as soon as any other
- //read locks have been released.
- //In other words, any ordering is possible, and either
- //w1 or w2 (but not both) may fail to obtain the lock
- //altogether.
- TS_CHECK_MSG(w1.value_ == k_data_init || w1.value_ == 10 || w1.value_ == 20, MESSAGE);
- TS_CHECK_MSG(w2.value_ == k_data_init || w2.value_ == 10 || w2.value_ == 20, MESSAGE);
- TS_CHECK_MSG(w1.value_ != w2.value_, MESSAGE);
- TS_CHECK_MSG(r1.value_ == 0 || r1.value_ == 10 || r1.value_ == 20, MESSAGE);
- TS_CHECK_MSG(r2.value_ == 0 || r2.value_ == 10 || r2.value_ == 20, MESSAGE);
- }
- }
- }
-
- //Verify that a read lock prevents readers but not writers from obtaining a lock
- {
- shared_val = 0;
- data<RW> r1(1, rw, 0, 0);
- data<RW> r2(2, rw, 0, 0);
- data<RW> w1(3, rw, 0, 0);
- data<RW> w2(4, rw, 0, 0);
-
- //Read-lock the mutex and queue up other readers and writers
-
- typename RW::scoped_read_write_lock l(rw, boost::read_write_lock_state::read_locked);
-
- boost::thread tr1(thread_adapter<RW>(plain_reader, &r1, rw));
- boost::thread tr2(thread_adapter<RW>(plain_reader, &r2, rw));
-
- boost::thread::sleep(xsecs(1));
-
- boost::thread tw1(thread_adapter<RW>(plain_writer, &w1, rw));
- boost::thread tw2(thread_adapter<RW>(plain_writer, &w2, rw));
-
- boost::thread::sleep(xsecs(1));
-
- //Expected result: all readers passed through before the writers entered
- TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
- TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
-
- if (test_promotion_and_demotion)
- {
- l.promote();
- }
-
- l.unlock();
-
- tr2.join();
- tr1.join();
- tw2.join();
- tw1.join();
- }
-
- //Verify that a read lock prevents readers but not writers from obtaining a lock
- {
- shared_val = 0;
- data<RW> r1(1, rw, 0, 0);
- data<RW> r2(2, rw, 0, 0);
- data<RW> w1(3, rw, 0, 0);
- data<RW> w2(4, rw, 0, 0);
-
- //Read-lock the mutex and queue up other readers and writers
-
- typename RW::scoped_read_write_lock l(rw, boost::read_write_lock_state::read_locked);
-
- boost::thread tw1(thread_adapter<RW>(plain_writer, &w1, rw));
- boost::thread tw2(thread_adapter<RW>(plain_writer, &w2, rw));
-
- boost::thread::sleep(xsecs(1));
-
- boost::thread tr1(thread_adapter<RW>(plain_reader, &r1, rw));
- boost::thread tr2(thread_adapter<RW>(plain_reader, &r2, rw));
-
- boost::thread::sleep(xsecs(1));
-
- if (rw.policy() == boost::read_write_scheduling_policy::writer_priority)
- {
- //Expected result:
- //Writers have priority, so no readers have been released
- TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(r1.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(r2.value_ == k_data_init, MESSAGE);
- }
- else if (rw.policy() == boost::read_write_scheduling_policy::reader_priority)
- {
- //Expected result:
- //Readers have priority, so all readers have been released
- TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(r1.value_ == 0, MESSAGE);
- TS_CHECK_MSG(r2.value_ == 0, MESSAGE);
- }
- else if (rw.policy() == boost::read_write_scheduling_policy::alternating_many_reads)
- {
- //Expected result:
- //It's the writers' turn, so no readers have been released
- TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(r1.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(r2.value_ == k_data_init, MESSAGE);
- }
- else if (rw.policy() == boost::read_write_scheduling_policy::alternating_single_read)
- {
- //Expected result:
- //It's the writers' turn, so no readers have been released
- TS_CHECK_MSG(w1.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(w2.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(r1.value_ == k_data_init, MESSAGE);
- TS_CHECK_MSG(r2.value_ == k_data_init, MESSAGE);
- }
-
- if (test_promotion_and_demotion)
- {
- l.promote();
- }
-
- l.unlock();
-
- tr2.join();
- tr1.join();
- tw2.join();
- tw1.join();
- }
-}
-
-template<typename RW>
-void test_try_read_write_mutex(RW& rw, bool test_promotion_and_demotion)
-{
- //Repeat the plain tests with the try lock.
- //This is important to verify that try locks are proper
- //read_write_mutexes as well.
-
- test_plain_read_write_mutex(rw, test_promotion_and_demotion);
-
- //Verify try_* operations with write-locked mutex
- {
- typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::write_locked);
-
- shared_test_writelocked = true;
- shared_test_readlocked = false;
- shared_test_unlocked = false;
-
- boost::thread test_thread(thread_adapter<RW>(run_try_tests, NULL, rw));
- test_thread.join();
- }
-
- //Verify try_* operations with read-locked mutex
- {
- typename RW::scoped_try_read_write_lock l(rw, boost::read_write_lock_state::read_locked);
-
- shared_test_writelocked = false;
- shared_test_readlocked = true;
- shared_test_unlocked = false;
-
- boost::thread test_thread(thread_adapter<RW>(run_try_tests, NULL, rw));
- test_thread.join();
- }
-
- //Verify try_* operations with unlocked mutex
- {
- shared_test_writelocked = false;
- shared_test_readlocked = false;
- shared_test_unlocked = true;
-
- boost::thread test_thread(thread_adapter<RW>(run_try_tests, NULL, rw));
- test_thread.join();
- }
-}
-
-template<typename RW>
-void test_timed_read_write_mutex(RW& rw, bool test_promotion_and_demotion)
-{
- //Repeat the try tests with the timed lock.
- //This is important to verify that timed locks are proper
- //try locks as well.
-
- test_try_read_write_mutex(rw, test_promotion_and_demotion);
-
- //:More tests here
-}
-
-} // namespace
-
-void do_test_read_write_mutex(bool test_promotion_and_demotion)
-{
- //Run every test for each scheduling policy
-
- for(int i = (int) boost::read_write_scheduling_policy::writer_priority;
- i <= (int) boost::read_write_scheduling_policy::alternating_single_read;
- i++)
- {
- std::cout << "plain test, sp=" << i
- << (test_promotion_and_demotion ? " with promotion & demotion" : " without promotion & demotion")
- << "\n";
- std::cout.flush();
-
- {
- boost::read_write_mutex plain_rw(static_cast<boost::read_write_scheduling_policy::read_write_scheduling_policy_enum>(i));
- test_plain_read_write_mutex(plain_rw, test_promotion_and_demotion);
- }
-
- std::cout << "try test, sp=" << i
- << (test_promotion_and_demotion ? " with promotion & demotion" : " without promotion & demotion")
- << "\n";
- std::cout.flush();
-
- {
- boost::try_read_write_mutex try_rw(static_cast<boost::read_write_scheduling_policy::read_write_scheduling_policy_enum>(i));
- test_try_read_write_mutex(try_rw, test_promotion_and_demotion);
- }
-
- std::cout << "timed test, sp=" << i
- << (test_promotion_and_demotion ? " with promotion & demotion" : " without promotion & demotion")
- << "\n";
- std::cout.flush();
-
- {
- boost::timed_read_write_mutex timed_rw(static_cast<boost::read_write_scheduling_policy::read_write_scheduling_policy_enum>(i));
- test_timed_read_write_mutex(timed_rw, test_promotion_and_demotion);
- }
- }
-}
-
-void test_read_write_mutex()
-{
- do_test_read_write_mutex(false);
- do_test_read_write_mutex(true);
-}
-
-boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
-{
- boost::unit_test_framework::test_suite* test =
- BOOST_TEST_SUITE("Boost.Threads: read_write_mutex test suite");
-
- test->add(BOOST_TEST_CASE(&test_read_write_mutex));
-
- return test;
-}
Modified: trunk/libs/thread/test/test_tss.cpp
==============================================================================
--- trunk/libs/thread/test/test_tss.cpp (original)
+++ trunk/libs/thread/test/test_tss.cpp 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -144,12 +144,11 @@
<< "\n";
std::cout.flush();
- // The following is not really an error. TSS cleanup support still is available
- // for threads, launched via the boost API. Also this usually will be triggered
- // only when bound to the static version of the thread lib.
- // 2006-10-15 Roland Schwarz
+ // The following is not really an error. TSS cleanup support still is available for boost threads.
+ // Also this usually will be triggered only when bound to the static version of thread lib.
+ // 2006-10-02 Roland Schwarz
//BOOST_CHECK_EQUAL(tss_instances, 0);
- BOOST_CHECK_MESSAGE(tss_instances ==0, "Support of automatic tss cleanup for native threading API not available");
+ BOOST_CHECK_MESSAGE(tss_instances == 0, "Support of automatic tss cleanup for native threading API not available");
BOOST_CHECK_EQUAL(tss_total, 5);
#endif
}
Modified: trunk/libs/thread/test/util.inl
==============================================================================
--- trunk/libs/thread/test/util.inl (original)
+++ trunk/libs/thread/test/util.inl 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
@@ -16,6 +16,8 @@
# define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_condition
#endif
+// boostinspect:nounnamed
+
namespace
{
inline boost::xtime delay(int secs, int msecs=0, int nsecs=0)
Deleted: trunk/libs/thread/tutorial/Jamfile
==============================================================================
--- trunk/libs/thread/tutorial/Jamfile 2007-10-05 05:46:00 EDT (Fri, 05 Oct 2007)
+++ (empty file)
@@ -1,34 +0,0 @@
-# Copyright (C) 2001-2003
-# William E. Kempf
-#
-# 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)
-#
-# Boost.Threads tutorial Jamfile
-#
-# Additional configuration variables used:
-# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
-# library should be used instead of "native" threads. This feature is
-# mostly used for testing and it's generally recommended you use the
-# native threading libraries instead. PTW32 should be set to be a list
-# of two strings, the first specifying the installation path of the
-# pthreads-win32 library and the second specifying which library
-# variant to link against (see the pthreads-win32 documentation).
-# Example: jam -sPTW32="c:\pthreads-win32 pthreadVCE.lib"
-
-project
- : requirements <library>/boost/thread//boost_thread
- <threading>multi
- ;
-
-exe helloworld : helloworld.cpp ;
-exe helloworld2 : helloworld2.cpp ;
-exe helloworld3 : helloworld3.cpp ;
-exe helloworld4 : helloworld4.cpp ;
-exe factorial : factorial.cpp ;
-exe factorial2 : factorial2.cpp ;
-exe factorial3 : factorial3.cpp ;
-exe counter : counter.cpp ;
-exe bounded_buffer : bounded_buffer.cpp ;
-exe once : once.cpp ;
-
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