mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
92 Commits
svn-branch
...
svn-branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
870d154ca1 | ||
|
|
25ad6e3f8f | ||
|
|
df0197b617 | ||
|
|
a89c4f01ad | ||
|
|
ae67099633 | ||
|
|
57542d3a5c | ||
|
|
9a1da14116 | ||
|
|
ed050d753d | ||
|
|
8bec363710 | ||
|
|
7c68e190a9 | ||
|
|
7ebf5ea3d1 | ||
|
|
11e0435a4b | ||
|
|
d15ee57cd1 | ||
|
|
56d660b7fd | ||
|
|
792958e693 | ||
|
|
914e67dc04 | ||
|
|
b50a7ccb61 | ||
|
|
f827709d42 | ||
|
|
36abb42175 | ||
|
|
40f3b1b4c8 | ||
|
|
4f35e25688 | ||
|
|
270e88edd7 | ||
|
|
5ded171247 | ||
|
|
332dd988e4 | ||
|
|
bce8db41d7 | ||
|
|
f6fd70245d | ||
|
|
4ff0a055d6 | ||
|
|
c9140267a5 | ||
|
|
72fcee4e5e | ||
|
|
9c8e512edd | ||
|
|
3c191af34a | ||
|
|
5e0b2d7370 | ||
|
|
5994abd453 | ||
|
|
67a2d119c0 | ||
|
|
114215088a | ||
|
|
a78e2b793e | ||
|
|
519ed3834e | ||
|
|
22647135fa | ||
|
|
58c741e9ca | ||
|
|
ef9083089e | ||
|
|
5de1582a0a | ||
|
|
39c864e31f | ||
|
|
320cb63df4 | ||
|
|
c246222ded | ||
|
|
b7edb2873c | ||
|
|
89f2032c0d | ||
|
|
d2f8230093 | ||
|
|
9f6b5d169a | ||
|
|
e56708d4aa | ||
|
|
304156c20e | ||
|
|
31e1566e1d | ||
|
|
3908637056 | ||
|
|
abee301f3d | ||
|
|
9b1d3f8f3c | ||
|
|
3513eaf701 | ||
|
|
08a840afe4 | ||
|
|
370f5d461c | ||
|
|
8efc8458e1 | ||
|
|
6485717c52 | ||
|
|
1d5bbd11a8 | ||
|
|
bc403742b5 | ||
|
|
c7f963f57e | ||
|
|
afb6684bde | ||
|
|
ee3d772235 | ||
|
|
1af08f7085 | ||
|
|
ccf23fa273 | ||
|
|
f701defc5f | ||
|
|
c606f05bf8 | ||
|
|
a646153615 | ||
|
|
60380afe15 | ||
|
|
d4b0a977c9 | ||
|
|
f86156ad10 | ||
|
|
1836ee854f | ||
|
|
c37cdeec9f | ||
|
|
b0b2b17908 | ||
|
|
2918732481 | ||
|
|
5a4d5ddb9d | ||
|
|
55afcf678d | ||
|
|
16c7cf9b5e | ||
|
|
432bd29c1c | ||
|
|
a87914ef23 | ||
|
|
041530a953 | ||
|
|
9d4c55161a | ||
|
|
a706d1df00 | ||
|
|
b15b2e666f | ||
|
|
5d4678364e | ||
|
|
9590526430 | ||
|
|
1c6dfda83c | ||
|
|
a8be12940e | ||
|
|
4b5046366b | ||
|
|
a0fff90c26 | ||
|
|
a8daedac5e |
@@ -1,2 +0,0 @@
|
||||
bin*
|
||||
*.pdb
|
||||
227
build/Jamfile.v2
227
build/Jamfile.v2
@@ -1,39 +1,208 @@
|
||||
# (C) Copyright Vladimir Prus, David Abrahams, Michael Stevens, Hartmut Kaiser,
|
||||
# William E Kempf 2002-2006
|
||||
# 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)
|
||||
# $Id$
|
||||
# Copyright 2006-2007 Roland Schwarz.
|
||||
# Copyright 2007 Anthony Williams
|
||||
# Distributed under the Boost Software License, Version 1.0. (See
|
||||
# accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#########################################################################
|
||||
# The boost threading library can be built on top of different API's
|
||||
# Currently this is the win32 API and the pthreads API.
|
||||
# Pthread is native on unix variants.
|
||||
# To get pthread on windows you need the pthread win32 library
|
||||
# http://sourceware.org/pthreads-win32 which is available under LGPL.
|
||||
#
|
||||
# You need to provide the include path and lib path in the variables
|
||||
# PTW32_INCLUDE and PTW32_LIB respectively. You can specify these
|
||||
# paths in site-config.jam, user-config.jam or in the environment.
|
||||
# A new feature is provided to request a specific API:
|
||||
# <threadapi>win32 and <threadapi)pthread.
|
||||
#
|
||||
# The naming of the resulting libraries is mostly the same for the
|
||||
# variant native to the build platform, i.e.
|
||||
# boost_thread and the boost specific tagging.
|
||||
# For the library variant that is not native on the build platform
|
||||
# an additional tag is applied:
|
||||
# boost_thread_pthread for the pthread variant on windows, and
|
||||
# boost_thread_win32 for the win32 variant (likely when built on cygwin).
|
||||
#
|
||||
# To request the pthread variant on windows, from boost root you would
|
||||
# say e.g:
|
||||
# bjam msvc-8.0 --with-thread install threadapi=pthread
|
||||
#########################################################################
|
||||
|
||||
import os ;
|
||||
|
||||
import feature ;
|
||||
import indirect ;
|
||||
import path ;
|
||||
|
||||
project boost/thread
|
||||
: source-location ../src
|
||||
: requirements <link>shared:<define>BOOST_THREAD_BUILD_DLL=1 <threading>multi
|
||||
: source-location ../src
|
||||
: requirements <threading>multi
|
||||
<link>static:<define>BOOST_THREAD_BUILD_LIB=1
|
||||
<link>shared:<define>BOOST_THREAD_BUILD_DLL=1
|
||||
-<tag>@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag
|
||||
<tag>@$(__name__).tag
|
||||
: default-build <threading>multi
|
||||
;
|
||||
|
||||
CPP_SOURCES =
|
||||
barrier
|
||||
condition
|
||||
exceptions
|
||||
mutex
|
||||
once
|
||||
recursive_mutex
|
||||
read_write_mutex
|
||||
thread
|
||||
tss_hooks
|
||||
tss_dll
|
||||
tss_pe
|
||||
tss
|
||||
xtime
|
||||
local rule default_threadapi ( )
|
||||
{
|
||||
local api = pthread ;
|
||||
if [ os.name ] = "NT" { api = win32 ; }
|
||||
return $(api) ;
|
||||
}
|
||||
|
||||
feature.feature threadapi : pthread win32 : propagated ;
|
||||
feature.set-default threadapi : [ default_threadapi ] ;
|
||||
|
||||
rule tag ( name : type ? : property-set )
|
||||
{
|
||||
local result = $(name) ;
|
||||
|
||||
if $(type) in STATIC_LIB SHARED_LIB IMPORT_LIB
|
||||
{
|
||||
local api = [ $(property-set).get <threadapi> ] ;
|
||||
|
||||
# non native api gets additional tag
|
||||
if $(api) != [ default_threadapi ] {
|
||||
result = $(result)_$(api) ;
|
||||
}
|
||||
}
|
||||
|
||||
# forward to the boost tagging rule
|
||||
return [ indirect.call $(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag
|
||||
$(result) : $(type) : $(property-set) ] ;
|
||||
}
|
||||
|
||||
rule win32_pthread_paths ( properties * )
|
||||
{
|
||||
local result ;
|
||||
local PTW32_INCLUDE ;
|
||||
local PTW32_LIB ;
|
||||
PTW32_INCLUDE = [ modules.peek : PTW32_INCLUDE ] ;
|
||||
PTW32_LIB = [ modules.peek : PTW32_LIB ] ;
|
||||
PTW32_INCLUDE ?= [ modules.peek user-config : PTW32_INCLUDE ] ;
|
||||
PTW32_LIB ?= [ modules.peek user-config : PTW32_LIB ] ;
|
||||
PTW32_INCLUDE ?= [ modules.peek site-config : PTW32_INCLUDE ] ;
|
||||
PTW32_LIB ?= [ modules.peek site-config : PTW32_LIB ] ;
|
||||
|
||||
if ! ( $(PTW32_INCLUDE) && $(PTW32_LIB) )
|
||||
{
|
||||
if ! $(.notified)
|
||||
{
|
||||
echo "************************************************************" ;
|
||||
echo "Trying to build Boost.Thread with pthread support." ;
|
||||
echo "If you need pthread you should specify the paths." ;
|
||||
echo "You can specify them in site-config.jam, user-config.jam" ;
|
||||
echo "or in the environment." ;
|
||||
echo "For example:" ;
|
||||
echo "PTW32_INCLUDE=C:\\Program Files\\ptw32\\Pre-built2\\include" ;
|
||||
echo "PTW32_LIB=C:\\Program Files\\ptw32\\Pre-built2\\lib" ;
|
||||
echo "************************************************************" ;
|
||||
.notified = true ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
local include_path = [ path.make $(PTW32_INCLUDE) ] ;
|
||||
local lib_path = [ path.make $(PTW32_LIB) ] ;
|
||||
local libname = pthread ;
|
||||
if <toolset>msvc in $(properties)
|
||||
{
|
||||
libname = $(libname)VC2.lib ;
|
||||
}
|
||||
if <toolset>gcc in $(properties)
|
||||
{
|
||||
libname = lib$(libname)GC2.a ;
|
||||
}
|
||||
lib_path = [ path.glob $(lib_path) : $(libname) ] ;
|
||||
if ! $(lib_path)
|
||||
{
|
||||
if ! $(.notified)
|
||||
{
|
||||
echo "************************************************************" ;
|
||||
echo "Trying to build Boost.Thread with pthread support." ;
|
||||
echo "But the library" $(libname) "could not be found in path" ;
|
||||
echo $(PTW32_LIB) ;
|
||||
echo "************************************************************" ;
|
||||
.notified = true ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result += <include>$(include_path) ;
|
||||
result += <library>$(lib_path) ;
|
||||
}
|
||||
}
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
rule usage-requirements ( properties * )
|
||||
{
|
||||
local result ;
|
||||
if <threadapi>pthread in $(properties)
|
||||
{
|
||||
result += <define>BOOST_THREAD_POSIX ;
|
||||
if <target-os>windows in $(properties)
|
||||
{
|
||||
result += [ win32_pthread_paths $(properties) ] ;
|
||||
# TODO: What is for static linking? Is the <library> also needed
|
||||
# in that case?
|
||||
}
|
||||
}
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
rule requirements ( properties * )
|
||||
{
|
||||
local result ;
|
||||
|
||||
if <threadapi>pthread in $(properties)
|
||||
{
|
||||
result += <define>BOOST_THREAD_POSIX ;
|
||||
if <target-os>windows in $(properties)
|
||||
{
|
||||
local paths = [ win32_pthread_paths $(properties) ] ;
|
||||
if $(paths)
|
||||
{
|
||||
result += $(paths) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = <build>no ;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
alias thread_sources
|
||||
: ## win32 sources ##
|
||||
win32/thread.cpp
|
||||
win32/exceptions.cpp
|
||||
win32/tss_dll.cpp
|
||||
win32/tss_pe.cpp
|
||||
: ## requirements ##
|
||||
<threadapi>win32
|
||||
;
|
||||
|
||||
alias thread_sources
|
||||
: ## pthread sources ##
|
||||
pthread/thread.cpp
|
||||
pthread/exceptions.cpp
|
||||
pthread/once.cpp
|
||||
: ## requirements ##
|
||||
<threadapi>pthread
|
||||
;
|
||||
|
||||
explicit thread_sources ;
|
||||
|
||||
lib boost_thread
|
||||
: $(CPP_SOURCES).cpp
|
||||
: <link>shared:<define>BOOST_THREAD_BUILD_DLL=1
|
||||
<link>static:<define>BOOST_THREAD_BUILD_LIB=1
|
||||
: # default build
|
||||
: <link>shared:<define>BOOST_THREAD_BUILD_DLL=1
|
||||
<link>static:<define>BOOST_THREAD_BUILD_LIB=1
|
||||
;
|
||||
: thread_sources
|
||||
: <conditional>@requirements
|
||||
:
|
||||
: <link>shared:<define>BOOST_THREAD_USE_DLL=1
|
||||
<link>static:<define>BOOST_THREAD_USE_LIB=1
|
||||
<conditional>@usage-requirements
|
||||
;
|
||||
|
||||
@@ -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 ##
|
||||
;
|
||||
}
|
||||
Binary file not shown.
@@ -63,6 +63,11 @@ last-revision="$Date$">
|
||||
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>
|
||||
|
||||
|
||||
131
doc/build.xml
131
doc/build.xml
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -65,25 +65,23 @@ void init()
|
||||
|
||||
void thread_proc()
|
||||
{
|
||||
boost::call_once(&init, once);
|
||||
boost::call_once(once, &init);
|
||||
}</programlisting>
|
||||
</para></description>
|
||||
|
||||
<parameter name="func">
|
||||
<paramtype>void (*func)()</paramtype>
|
||||
</parameter>
|
||||
|
||||
<parameter name="flag">
|
||||
<paramtype>once_flag&</paramtype>
|
||||
</parameter>
|
||||
|
||||
<requires>The function <code>func</code> shall not throw
|
||||
exceptions.</requires>
|
||||
|
||||
<parameter name="func">
|
||||
<paramtype>Function func</paramtype>
|
||||
</parameter>
|
||||
|
||||
<effects>As if (in an atomic fashion):
|
||||
<code>if (flag == BOOST_ONCE_INIT) func();</code></effects>
|
||||
<code>if (flag == BOOST_ONCE_INIT) func();</code>. If <code>func()</code> throws an exception, it shall be as if this
|
||||
thread never invoked <code>call_once</code></effects>
|
||||
|
||||
<postconditions><code>flag != BOOST_ONCE_INIT</code>
|
||||
<postconditions><code>flag != BOOST_ONCE_INIT</code> unless <code>func()</code> throws an exception.
|
||||
</postconditions>
|
||||
</function>
|
||||
</namespace>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
bin
|
||||
*.pdb
|
||||
@@ -4,6 +4,8 @@
|
||||
// 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)
|
||||
|
||||
// See www.boost.org/libs/thread for documentation.
|
||||
|
||||
#if !defined(BOOST_THREAD_WEK01082003_HPP)
|
||||
#define BOOST_THREAD_WEK01082003_HPP
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (C) 2002-2003
|
||||
// David Moore, 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)
|
||||
@@ -10,34 +11,48 @@
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace boost {
|
||||
|
||||
class BOOST_THREAD_DECL barrier
|
||||
namespace boost
|
||||
{
|
||||
public:
|
||||
barrier(unsigned int count);
|
||||
~barrier();
|
||||
|
||||
bool wait();
|
||||
class barrier
|
||||
{
|
||||
public:
|
||||
barrier(unsigned int count)
|
||||
: m_threshold(count), m_count(count), m_generation(0)
|
||||
{
|
||||
if (count == 0)
|
||||
throw std::invalid_argument("count cannot be zero.");
|
||||
}
|
||||
|
||||
bool wait()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
unsigned int gen = m_generation;
|
||||
|
||||
if (--m_count == 0)
|
||||
{
|
||||
m_generation++;
|
||||
m_count = m_threshold;
|
||||
m_cond.notify_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
mutex m_mutex;
|
||||
// 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
|
||||
condition m_cond;
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
unsigned int m_threshold;
|
||||
unsigned int m_count;
|
||||
unsigned int m_generation;
|
||||
};
|
||||
while (gen == m_generation)
|
||||
m_cond.wait(lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
mutex m_mutex;
|
||||
condition_variable m_cond;
|
||||
unsigned int m_threshold;
|
||||
unsigned int m_count;
|
||||
unsigned int m_generation;
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
@@ -1,200 +1,16 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
#ifndef BOOST_THREAD_CONDITION_HPP
|
||||
#define BOOST_THREAD_CONDITION_HPP
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_CONDITION_WEK070601_HPP
|
||||
#define BOOST_CONDITION_WEK070601_HPP
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include "scoped_critical_region.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
struct xtime;
|
||||
// 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 detail {
|
||||
|
||||
class BOOST_THREAD_DECL condition_impl : private noncopyable
|
||||
namespace boost
|
||||
{
|
||||
friend class condition;
|
||||
typedef condition_variable_any condition;
|
||||
}
|
||||
|
||||
public:
|
||||
condition_impl();
|
||||
~condition_impl();
|
||||
|
||||
void notify_one();
|
||||
void notify_all();
|
||||
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
void enter_wait();
|
||||
void do_wait();
|
||||
bool do_timed_wait(const xtime& xt);
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
void do_wait(pthread_mutex_t* pmutex);
|
||||
bool do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex);
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_gate;
|
||||
void* m_queue;
|
||||
void* m_mutex;
|
||||
unsigned m_gone; // # threads that timed out and never made it to m_queue
|
||||
unsigned long m_blocked; // # threads blocked on the condition
|
||||
unsigned m_waiting; // # threads no longer waiting for the condition but
|
||||
// still waiting to be removed from m_queue
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_cond_t m_condition;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
MPSemaphoreID m_gate;
|
||||
MPSemaphoreID m_queue;
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
unsigned m_gone; // # threads that timed out and never made it to m_queue
|
||||
unsigned long m_blocked; // # threads blocked on the condition
|
||||
unsigned m_waiting; // # threads no longer waiting for the condition but
|
||||
// still waiting to be removed from m_queue
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class condition : private noncopyable
|
||||
{
|
||||
public:
|
||||
condition() { }
|
||||
~condition() { }
|
||||
|
||||
void notify_one() { m_impl.notify_one(); }
|
||||
void notify_all() { m_impl.notify_all(); }
|
||||
|
||||
template <typename L>
|
||||
void wait(L& lock)
|
||||
{
|
||||
if (!lock)
|
||||
throw lock_error();
|
||||
|
||||
do_wait(lock.m_mutex);
|
||||
}
|
||||
|
||||
template <typename L, typename Pr>
|
||||
void wait(L& lock, Pr pred)
|
||||
{
|
||||
if (!lock)
|
||||
throw lock_error();
|
||||
|
||||
while (!pred())
|
||||
do_wait(lock.m_mutex);
|
||||
}
|
||||
|
||||
template <typename L>
|
||||
bool timed_wait(L& lock, const xtime& xt)
|
||||
{
|
||||
if (!lock)
|
||||
throw lock_error();
|
||||
|
||||
return do_timed_wait(lock.m_mutex, xt);
|
||||
}
|
||||
|
||||
template <typename L, typename Pr>
|
||||
bool timed_wait(L& lock, const xtime& xt, Pr pred)
|
||||
{
|
||||
if (!lock)
|
||||
throw lock_error();
|
||||
|
||||
while (!pred())
|
||||
{
|
||||
if (!do_timed_wait(lock.m_mutex, xt))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
detail::condition_impl m_impl;
|
||||
|
||||
template <typename M>
|
||||
void do_wait(M& mutex)
|
||||
{
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
m_impl.enter_wait();
|
||||
#endif
|
||||
|
||||
typedef detail::thread::lock_ops<M>
|
||||
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
||||
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
||||
#endif
|
||||
lock_ops;
|
||||
|
||||
typename lock_ops::lock_state state;
|
||||
lock_ops::unlock(mutex, state);
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
m_impl.do_wait(state.pmutex);
|
||||
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
m_impl.do_wait();
|
||||
#endif
|
||||
|
||||
lock_ops::lock(mutex, state);
|
||||
#undef lock_ops
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
bool do_timed_wait(M& mutex, const xtime& xt)
|
||||
{
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
m_impl.enter_wait();
|
||||
#endif
|
||||
|
||||
typedef detail::thread::lock_ops<M>
|
||||
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
|
||||
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
|
||||
#endif
|
||||
lock_ops;
|
||||
|
||||
typename lock_ops::lock_state state;
|
||||
lock_ops::unlock(mutex, state);
|
||||
|
||||
bool ret = false;
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
ret = m_impl.do_timed_wait(xt, state.pmutex);
|
||||
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
ret = m_impl.do_timed_wait(xt);
|
||||
#endif
|
||||
|
||||
lock_ops::lock(mutex, state);
|
||||
#undef lock_ops
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||
// 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too
|
||||
// difficult to use with spurious wakeups.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
|
||||
#endif // BOOST_CONDITION_WEK070601_HPP
|
||||
|
||||
21
include/boost/thread/condition_variable.hpp
Normal file
21
include/boost/thread/condition_variable.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef BOOST_THREAD_CONDITION_VARIABLE_HPP
|
||||
#define BOOST_THREAD_CONDITION_VARIABLE_HPP
|
||||
|
||||
// condition_variable.hpp
|
||||
//
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/condition_variable.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/condition_variable.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -17,8 +17,7 @@
|
||||
# pragma warn -8066 // Unreachable code
|
||||
#endif
|
||||
|
||||
// insist on threading support being available:
|
||||
#include <boost/config/requires_threads.hpp>
|
||||
#include "platform.hpp"
|
||||
|
||||
// compatibility with the rest of Boost's auto-linking code:
|
||||
#if defined(BOOST_THREAD_DYN_DLL) || defined(BOOST_ALL_DYN_LINK)
|
||||
@@ -31,7 +30,7 @@
|
||||
#elif defined(BOOST_THREAD_USE_DLL) //Use dll
|
||||
#elif defined(BOOST_THREAD_USE_LIB) //Use lib
|
||||
#else //Use default
|
||||
# if defined(BOOST_HAS_WINTHREADS)
|
||||
# if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)
|
||||
//For compilers supporting auto-tss cleanup
|
||||
//with Boost.Threads lib, use Boost.Threads lib
|
||||
|
||||
@@ -1,209 +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)
|
||||
|
||||
#ifndef BOOST_XLOCK_WEK070601_HPP
|
||||
#define BOOST_XLOCK_WEK070601_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
class condition;
|
||||
struct xtime;
|
||||
|
||||
namespace detail { namespace thread {
|
||||
|
||||
template <typename Mutex>
|
||||
class lock_ops : private noncopyable
|
||||
{
|
||||
private:
|
||||
lock_ops() { }
|
||||
|
||||
public:
|
||||
typedef typename Mutex::cv_state lock_state;
|
||||
|
||||
static void lock(Mutex& m)
|
||||
{
|
||||
m.do_lock();
|
||||
}
|
||||
static bool trylock(Mutex& m)
|
||||
{
|
||||
return m.do_trylock();
|
||||
}
|
||||
static bool timedlock(Mutex& m, const xtime& xt)
|
||||
{
|
||||
return m.do_timedlock(xt);
|
||||
}
|
||||
static void unlock(Mutex& m)
|
||||
{
|
||||
m.do_unlock();
|
||||
}
|
||||
static void lock(Mutex& m, lock_state& state)
|
||||
{
|
||||
m.do_lock(state);
|
||||
}
|
||||
static void unlock(Mutex& m, lock_state& state)
|
||||
{
|
||||
m.do_unlock(state);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Mutex>
|
||||
class scoped_lock : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef Mutex mutex_type;
|
||||
|
||||
explicit scoped_lock(Mutex& mx, bool initially_locked=true)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
if (initially_locked) lock();
|
||||
}
|
||||
~scoped_lock()
|
||||
{
|
||||
if (m_locked) unlock();
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
lock_ops<Mutex>::lock(m_mutex);
|
||||
m_locked = true;
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if (!m_locked) throw lock_error();
|
||||
lock_ops<Mutex>::unlock(m_mutex);
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
bool locked() const { return m_locked; }
|
||||
operator const void*() const { return m_locked ? this : 0; }
|
||||
|
||||
private:
|
||||
friend class boost::condition;
|
||||
|
||||
Mutex& m_mutex;
|
||||
bool m_locked;
|
||||
};
|
||||
|
||||
template <typename TryMutex>
|
||||
class scoped_try_lock : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef TryMutex mutex_type;
|
||||
|
||||
explicit scoped_try_lock(TryMutex& mx)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
try_lock();
|
||||
}
|
||||
scoped_try_lock(TryMutex& mx, bool initially_locked)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
if (initially_locked) lock();
|
||||
}
|
||||
~scoped_try_lock()
|
||||
{
|
||||
if (m_locked) unlock();
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
lock_ops<TryMutex>::lock(m_mutex);
|
||||
m_locked = true;
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
return (m_locked = lock_ops<TryMutex>::trylock(m_mutex));
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if (!m_locked) throw lock_error();
|
||||
lock_ops<TryMutex>::unlock(m_mutex);
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
bool locked() const { return m_locked; }
|
||||
operator const void*() const { return m_locked ? this : 0; }
|
||||
|
||||
private:
|
||||
friend class boost::condition;
|
||||
|
||||
TryMutex& m_mutex;
|
||||
bool m_locked;
|
||||
};
|
||||
|
||||
template <typename TimedMutex>
|
||||
class scoped_timed_lock : private noncopyable
|
||||
{
|
||||
public:
|
||||
typedef TimedMutex mutex_type;
|
||||
|
||||
scoped_timed_lock(TimedMutex& mx, const xtime& xt)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
timed_lock(xt);
|
||||
}
|
||||
scoped_timed_lock(TimedMutex& mx, bool initially_locked)
|
||||
: m_mutex(mx), m_locked(false)
|
||||
{
|
||||
if (initially_locked) lock();
|
||||
}
|
||||
~scoped_timed_lock()
|
||||
{
|
||||
if (m_locked) unlock();
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
lock_ops<TimedMutex>::lock(m_mutex);
|
||||
m_locked = true;
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
return (m_locked = lock_ops<TimedMutex>::trylock(m_mutex));
|
||||
}
|
||||
bool timed_lock(const xtime& xt)
|
||||
{
|
||||
if (m_locked) throw lock_error();
|
||||
return (m_locked = lock_ops<TimedMutex>::timedlock(m_mutex, xt));
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if (!m_locked) throw lock_error();
|
||||
lock_ops<TimedMutex>::unlock(m_mutex);
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
bool locked() const { return m_locked; }
|
||||
operator const void*() const { return m_locked ? this : 0; }
|
||||
|
||||
private:
|
||||
friend class boost::condition;
|
||||
|
||||
TimedMutex& m_mutex;
|
||||
bool m_locked;
|
||||
};
|
||||
|
||||
} // namespace thread
|
||||
} // namespace detail
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_XLOCK_WEK070601_HPP
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||
// 30 Jul 01 WEKEMPF Moved lock types into boost::detail::thread. Renamed
|
||||
// some types. Added locked() methods.
|
||||
31
include/boost/thread/detail/move.hpp
Normal file
31
include/boost/thread/detail/move.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
|
||||
#ifndef BOOST_THREAD_MOVE_HPP
|
||||
#define BOOST_THREAD_MOVE_HPP
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename T>
|
||||
struct thread_move_t
|
||||
{
|
||||
T& t;
|
||||
thread_move_t(T& t_):
|
||||
t(t_)
|
||||
{}
|
||||
|
||||
T* operator->() const
|
||||
{
|
||||
return &t;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
71
include/boost/thread/detail/platform.hpp
Normal file
71
include/boost/thread/detail/platform.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright 2006 Roland Schwarz.
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// This work is a reimplementation along the design and ideas
|
||||
// of William E. Kempf.
|
||||
|
||||
#ifndef BOOST_THREAD_RS06040501_HPP
|
||||
#define BOOST_THREAD_RS06040501_HPP
|
||||
|
||||
// fetch compiler and platform configuration
|
||||
#include <boost/config.hpp>
|
||||
|
||||
// insist on threading support being available:
|
||||
#include <boost/config/requires_threads.hpp>
|
||||
|
||||
// choose platform
|
||||
#if defined(linux) || defined(__linux) || defined(__linux__)
|
||||
# define BOOST_THREAD_LINUX
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
# define BOOST_THREAD_BSD
|
||||
#elif defined(sun) || defined(__sun)
|
||||
# define BOOST_THREAD_SOLARIS
|
||||
#elif defined(__sgi)
|
||||
# define BOOST_THREAD_IRIX
|
||||
#elif defined(__hpux)
|
||||
# define BOOST_THREAD_HPUX
|
||||
#elif defined(__CYGWIN__)
|
||||
# define BOOST_THREAD_CYGWIN
|
||||
#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||
# define BOOST_THREAD_WIN32
|
||||
#elif defined(__BEOS__)
|
||||
# define BOOST_THREAD_BEOS
|
||||
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
|
||||
# define BOOST_THREAD_MACOS
|
||||
#elif defined(__IBMCPP__) || defined(_AIX)
|
||||
# define BOOST_THREAD_AIX
|
||||
#elif defined(__amigaos__)
|
||||
# define BOOST_THREAD_AMIGAOS
|
||||
#elif defined(__QNXNTO__)
|
||||
# define BOOST_THREAD_QNXNTO
|
||||
#elif defined(unix) || defined(__unix) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE)
|
||||
# if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_THREAD_POSIX)
|
||||
# define BOOST_THREAD_POSIX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// For every supported platform add a new entry into the dispatch table below.
|
||||
// BOOST_THREAD_POSIX is tested first, so on platforms where posix and native
|
||||
// threading is available, the user may choose, by defining BOOST_THREAD_POSIX
|
||||
// in her source. If a platform is known to support pthreads and no native
|
||||
// port of boost_thread is available just specify "pthread" in the
|
||||
// dispatcher table. If there is no entry for a platform but pthreads is
|
||||
// available on the platform, pthread is choosen as default. If nothing is
|
||||
// available the preprocessor will fail with a diagnostic message.
|
||||
|
||||
#if defined(BOOST_THREAD_POSIX)
|
||||
# define BOOST_THREAD_PLATFORM_PTHREAD
|
||||
#else
|
||||
# if defined(BOOST_THREAD_WIN32)
|
||||
# define BOOST_THREAD_PLATFORM_WIN32
|
||||
# elif defined(BOOST_HAS_PTHREADS)
|
||||
# define BOOST_THREAD_PLATFORM_PTHREAD
|
||||
# else
|
||||
# error "Sorry, no boost threads are available for this platform."
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif // BOOST_THREAD_RS06040501_HPP
|
||||
File diff suppressed because it is too large
Load Diff
@@ -67,7 +67,7 @@
|
||||
//Called automatically by Boost.Threads when
|
||||
//a method for doing so has been discovered.
|
||||
//Must not be omitted; may be called multiple times.
|
||||
|
||||
|
||||
extern "C" void tss_cleanup_implemented(void);
|
||||
//Dummy function used both to detect whether tss cleanup
|
||||
//cleanup has been implemented and to force
|
||||
|
||||
@@ -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)
|
||||
@@ -35,6 +36,17 @@ private:
|
||||
int m_sys_err;
|
||||
};
|
||||
|
||||
class condition_error:
|
||||
public std::exception
|
||||
{
|
||||
public:
|
||||
const char* what() const throw()
|
||||
{
|
||||
return "Condition error";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class BOOST_THREAD_DECL lock_error : public thread_exception
|
||||
{
|
||||
public:
|
||||
|
||||
592
include/boost/thread/locks.hpp
Normal file
592
include/boost/thread/locks.hpp
Normal file
@@ -0,0 +1,592 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
#ifndef BOOST_THREAD_LOCKS_HPP
|
||||
#define BOOST_THREAD_LOCKS_HPP
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <algorithm>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
struct defer_lock_t
|
||||
{};
|
||||
struct try_to_lock_t
|
||||
{};
|
||||
struct adopt_lock_t
|
||||
{};
|
||||
|
||||
const defer_lock_t defer_lock={};
|
||||
const try_to_lock_t try_to_lock={};
|
||||
const adopt_lock_t adopt_lock={};
|
||||
|
||||
template<typename Mutex>
|
||||
class shared_lock;
|
||||
|
||||
template<typename Mutex>
|
||||
class exclusive_lock;
|
||||
|
||||
template<typename Mutex>
|
||||
class upgrade_lock;
|
||||
|
||||
template<typename Mutex>
|
||||
class lock_guard
|
||||
{
|
||||
private:
|
||||
Mutex& m;
|
||||
|
||||
explicit lock_guard(lock_guard&);
|
||||
lock_guard& operator=(lock_guard&);
|
||||
public:
|
||||
explicit lock_guard(Mutex& m_):
|
||||
m(m_)
|
||||
{
|
||||
m.lock();
|
||||
}
|
||||
lock_guard(Mutex& m_,adopt_lock_t):
|
||||
m(m_)
|
||||
{}
|
||||
~lock_guard()
|
||||
{
|
||||
m.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Mutex>
|
||||
class unique_lock
|
||||
{
|
||||
private:
|
||||
Mutex* m;
|
||||
bool is_locked;
|
||||
explicit unique_lock(unique_lock&);
|
||||
unique_lock& operator=(unique_lock&);
|
||||
public:
|
||||
explicit unique_lock(Mutex& m_):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
lock();
|
||||
}
|
||||
unique_lock(Mutex& m_,adopt_lock_t):
|
||||
m(&m_),is_locked(true)
|
||||
{}
|
||||
unique_lock(Mutex& m_,defer_lock_t):
|
||||
m(&m_),is_locked(false)
|
||||
{}
|
||||
unique_lock(Mutex& m_,try_to_lock_t):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
try_lock();
|
||||
}
|
||||
unique_lock(Mutex& m_,system_time const& target_time):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
timed_lock(target_time);
|
||||
}
|
||||
unique_lock(detail::thread_move_t<unique_lock<Mutex> > other):
|
||||
m(other->m),is_locked(other->is_locked)
|
||||
{
|
||||
other->is_locked=false;
|
||||
other->m=0;
|
||||
}
|
||||
unique_lock(detail::thread_move_t<upgrade_lock<Mutex> > other);
|
||||
|
||||
operator detail::thread_move_t<unique_lock<Mutex> >()
|
||||
{
|
||||
return move();
|
||||
}
|
||||
|
||||
detail::thread_move_t<unique_lock<Mutex> > move()
|
||||
{
|
||||
return detail::thread_move_t<unique_lock<Mutex> >(*this);
|
||||
}
|
||||
|
||||
unique_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other)
|
||||
{
|
||||
unique_lock temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
unique_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other)
|
||||
{
|
||||
unique_lock temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(unique_lock& other)
|
||||
{
|
||||
std::swap(m,other.m);
|
||||
std::swap(is_locked,other.is_locked);
|
||||
}
|
||||
void swap(detail::thread_move_t<unique_lock<Mutex> > other)
|
||||
{
|
||||
std::swap(m,other->m);
|
||||
std::swap(is_locked,other->is_locked);
|
||||
}
|
||||
|
||||
~unique_lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
m->unlock();
|
||||
}
|
||||
}
|
||||
void lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
m->lock();
|
||||
is_locked=true;
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
is_locked=m->try_lock();
|
||||
return is_locked;
|
||||
}
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const& relative_time)
|
||||
{
|
||||
is_locked=m->timed_lock(relative_time);
|
||||
return is_locked;
|
||||
}
|
||||
|
||||
bool timed_lock(::boost::system_time const& absolute_time)
|
||||
{
|
||||
is_locked=m->timed_lock(absolute_time);
|
||||
return is_locked;
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if(!owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
m->unlock();
|
||||
is_locked=false;
|
||||
}
|
||||
|
||||
typedef void (unique_lock::*bool_type)();
|
||||
operator bool_type() const
|
||||
{
|
||||
return is_locked?&unique_lock::lock:0;
|
||||
}
|
||||
bool operator!() const
|
||||
{
|
||||
return !owns_lock();
|
||||
}
|
||||
bool owns_lock() const
|
||||
{
|
||||
return is_locked;
|
||||
}
|
||||
|
||||
Mutex* mutex() const
|
||||
{
|
||||
return m;
|
||||
}
|
||||
|
||||
Mutex* release()
|
||||
{
|
||||
Mutex* const res=m;
|
||||
m=0;
|
||||
is_locked=false;
|
||||
return res;
|
||||
}
|
||||
|
||||
friend class shared_lock<Mutex>;
|
||||
friend class upgrade_lock<Mutex>;
|
||||
};
|
||||
|
||||
template<typename Mutex>
|
||||
inline detail::thread_move_t<unique_lock<Mutex> > move(unique_lock<Mutex> & x)
|
||||
{
|
||||
return x.move();
|
||||
}
|
||||
|
||||
template<typename Mutex>
|
||||
inline detail::thread_move_t<unique_lock<Mutex> > move(detail::thread_move_t<unique_lock<Mutex> > x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
template<typename Mutex>
|
||||
class shared_lock
|
||||
{
|
||||
protected:
|
||||
Mutex* m;
|
||||
bool is_locked;
|
||||
private:
|
||||
explicit shared_lock(shared_lock&);
|
||||
shared_lock& operator=(shared_lock&);
|
||||
public:
|
||||
explicit shared_lock(Mutex& m_):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
lock();
|
||||
}
|
||||
shared_lock(Mutex& m_,adopt_lock_t):
|
||||
m(&m_),is_locked(true)
|
||||
{}
|
||||
shared_lock(Mutex& m_,defer_lock_t):
|
||||
m(&m_),is_locked(false)
|
||||
{}
|
||||
shared_lock(Mutex& m_,try_to_lock_t):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
try_lock();
|
||||
}
|
||||
shared_lock(Mutex& m_,system_time const& target_time):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
timed_lock(target_time);
|
||||
}
|
||||
|
||||
shared_lock(detail::thread_move_t<shared_lock<Mutex> > other):
|
||||
m(other->m),is_locked(other->is_locked)
|
||||
{
|
||||
other->is_locked=false;
|
||||
}
|
||||
|
||||
shared_lock(detail::thread_move_t<unique_lock<Mutex> > other):
|
||||
m(other->m),is_locked(other->is_locked)
|
||||
{
|
||||
other->is_locked=false;
|
||||
if(is_locked)
|
||||
{
|
||||
m->unlock_and_lock_shared();
|
||||
}
|
||||
}
|
||||
|
||||
shared_lock(detail::thread_move_t<upgrade_lock<Mutex> > other):
|
||||
m(other->m),is_locked(other->is_locked)
|
||||
{
|
||||
other->is_locked=false;
|
||||
if(is_locked)
|
||||
{
|
||||
m->unlock_upgrade_and_lock_shared();
|
||||
}
|
||||
}
|
||||
|
||||
operator detail::thread_move_t<shared_lock<Mutex> >()
|
||||
{
|
||||
return move();
|
||||
}
|
||||
|
||||
detail::thread_move_t<shared_lock<Mutex> > move()
|
||||
{
|
||||
return detail::thread_move_t<shared_lock<Mutex> >(*this);
|
||||
}
|
||||
|
||||
|
||||
shared_lock& operator=(detail::thread_move_t<shared_lock<Mutex> > other)
|
||||
{
|
||||
shared_lock temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
shared_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other)
|
||||
{
|
||||
shared_lock temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
shared_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other)
|
||||
{
|
||||
shared_lock temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(shared_lock& other)
|
||||
{
|
||||
std::swap(m,other.m);
|
||||
std::swap(is_locked,other.is_locked);
|
||||
}
|
||||
|
||||
~shared_lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
m->unlock_shared();
|
||||
}
|
||||
}
|
||||
void lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
m->lock_shared();
|
||||
is_locked=true;
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
is_locked=m->try_lock_shared();
|
||||
return is_locked;
|
||||
}
|
||||
bool timed_lock(boost::system_time const& target_time)
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
is_locked=m->timed_lock_shared(target_time);
|
||||
return is_locked;
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if(!owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
m->unlock_shared();
|
||||
is_locked=false;
|
||||
}
|
||||
|
||||
typedef void (shared_lock::*bool_type)();
|
||||
operator bool_type() const
|
||||
{
|
||||
return is_locked?&shared_lock::lock:0;
|
||||
}
|
||||
bool operator!() const
|
||||
{
|
||||
return !owns_lock();
|
||||
}
|
||||
bool owns_lock() const
|
||||
{
|
||||
return is_locked;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename Mutex>
|
||||
inline detail::thread_move_t<shared_lock<Mutex> > move(shared_lock<Mutex> & x)
|
||||
{
|
||||
return x.move();
|
||||
}
|
||||
|
||||
template<typename Mutex>
|
||||
inline detail::thread_move_t<shared_lock<Mutex> > move(detail::thread_move_t<shared_lock<Mutex> > x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
template<typename Mutex>
|
||||
class upgrade_lock
|
||||
{
|
||||
protected:
|
||||
Mutex* m;
|
||||
bool is_locked;
|
||||
private:
|
||||
explicit upgrade_lock(upgrade_lock&);
|
||||
upgrade_lock& operator=(upgrade_lock&);
|
||||
public:
|
||||
explicit upgrade_lock(Mutex& m_):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
lock();
|
||||
}
|
||||
upgrade_lock(Mutex& m_,bool do_lock):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
if(do_lock)
|
||||
{
|
||||
lock();
|
||||
}
|
||||
}
|
||||
upgrade_lock(detail::thread_move_t<upgrade_lock<Mutex> > other):
|
||||
m(other->m),is_locked(other->is_locked)
|
||||
{
|
||||
other->is_locked=false;
|
||||
}
|
||||
|
||||
upgrade_lock(detail::thread_move_t<unique_lock<Mutex> > other):
|
||||
m(other->m),is_locked(other->is_locked)
|
||||
{
|
||||
other->is_locked=false;
|
||||
if(is_locked)
|
||||
{
|
||||
m->unlock_and_lock_upgrade();
|
||||
}
|
||||
}
|
||||
|
||||
operator detail::thread_move_t<upgrade_lock<Mutex> >()
|
||||
{
|
||||
return move();
|
||||
}
|
||||
|
||||
detail::thread_move_t<upgrade_lock<Mutex> > move()
|
||||
{
|
||||
return detail::thread_move_t<upgrade_lock<Mutex> >(*this);
|
||||
}
|
||||
|
||||
|
||||
upgrade_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other)
|
||||
{
|
||||
upgrade_lock temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
upgrade_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other)
|
||||
{
|
||||
upgrade_lock temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(upgrade_lock& other)
|
||||
{
|
||||
std::swap(m,other.m);
|
||||
std::swap(is_locked,other.is_locked);
|
||||
}
|
||||
|
||||
~upgrade_lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
m->unlock_upgrade();
|
||||
}
|
||||
}
|
||||
void lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
m->lock_upgrade();
|
||||
is_locked=true;
|
||||
}
|
||||
bool try_lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
is_locked=m->try_lock_upgrade();
|
||||
return is_locked;
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
if(!owns_lock())
|
||||
{
|
||||
throw boost::lock_error();
|
||||
}
|
||||
m->unlock_upgrade();
|
||||
is_locked=false;
|
||||
}
|
||||
|
||||
typedef void (upgrade_lock::*bool_type)();
|
||||
operator bool_type() const
|
||||
{
|
||||
return is_locked?&upgrade_lock::lock:0;
|
||||
}
|
||||
bool operator!() const
|
||||
{
|
||||
return !owns_lock();
|
||||
}
|
||||
bool owns_lock() const
|
||||
{
|
||||
return is_locked;
|
||||
}
|
||||
friend class shared_lock<Mutex>;
|
||||
friend class unique_lock<Mutex>;
|
||||
};
|
||||
|
||||
|
||||
template<typename Mutex>
|
||||
inline detail::thread_move_t<upgrade_lock<Mutex> > move(upgrade_lock<Mutex> & x)
|
||||
{
|
||||
return x.move();
|
||||
}
|
||||
|
||||
template<typename Mutex>
|
||||
inline detail::thread_move_t<upgrade_lock<Mutex> > move(detail::thread_move_t<upgrade_lock<Mutex> > x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
template<typename Mutex>
|
||||
unique_lock<Mutex>::unique_lock(detail::thread_move_t<upgrade_lock<Mutex> > other):
|
||||
m(other->m),is_locked(other->is_locked)
|
||||
{
|
||||
other->is_locked=false;
|
||||
if(is_locked)
|
||||
{
|
||||
m->unlock_upgrade_and_lock();
|
||||
}
|
||||
}
|
||||
|
||||
template <class Mutex>
|
||||
class upgrade_to_unique_lock
|
||||
{
|
||||
private:
|
||||
upgrade_lock<Mutex>* source;
|
||||
unique_lock<Mutex> exclusive;
|
||||
|
||||
explicit upgrade_to_unique_lock(upgrade_to_unique_lock&);
|
||||
upgrade_to_unique_lock& operator=(upgrade_to_unique_lock&);
|
||||
public:
|
||||
explicit upgrade_to_unique_lock(upgrade_lock<Mutex>& m_):
|
||||
source(&m_),exclusive(move(*source))
|
||||
{}
|
||||
~upgrade_to_unique_lock()
|
||||
{
|
||||
if(source)
|
||||
{
|
||||
*source=move(exclusive);
|
||||
}
|
||||
}
|
||||
|
||||
upgrade_to_unique_lock(detail::thread_move_t<upgrade_to_unique_lock<Mutex> > other):
|
||||
source(other->source),exclusive(move(other->exclusive))
|
||||
{
|
||||
other->source=0;
|
||||
}
|
||||
|
||||
upgrade_to_unique_lock& operator=(detail::thread_move_t<upgrade_to_unique_lock<Mutex> > other)
|
||||
{
|
||||
upgrade_to_unique_lock temp(other);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
void swap(upgrade_to_unique_lock& other)
|
||||
{
|
||||
std::swap(source,other.source);
|
||||
exclusive.swap(other.exclusive);
|
||||
}
|
||||
typedef void (upgrade_to_unique_lock::*bool_type)(upgrade_to_unique_lock&);
|
||||
operator bool_type() const
|
||||
{
|
||||
return exclusive.owns_lock()?&upgrade_to_unique_lock::swap:0;
|
||||
}
|
||||
bool operator!() const
|
||||
{
|
||||
return !owns_lock();
|
||||
}
|
||||
bool owns_lock() const
|
||||
{
|
||||
return exclusive.owns_lock();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,169 +1,21 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
#ifndef BOOST_THREAD_MUTEX_HPP
|
||||
#define BOOST_THREAD_MUTEX_HPP
|
||||
|
||||
// mutex.hpp
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 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)
|
||||
|
||||
#ifndef BOOST_MUTEX_WEK070601_HPP
|
||||
#define BOOST_MUTEX_WEK070601_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/mutex.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/mutex.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_MPTASKS)
|
||||
# include "scoped_critical_region.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
struct xtime;
|
||||
// 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
|
||||
class BOOST_THREAD_DECL mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<mutex> scoped_lock;
|
||||
|
||||
mutex();
|
||||
~mutex();
|
||||
|
||||
private:
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
typedef void* cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
struct cv_state
|
||||
{
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
bool m_critical_section;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL try_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<try_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<try_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<try_mutex> scoped_try_lock;
|
||||
|
||||
try_mutex();
|
||||
~try_mutex();
|
||||
|
||||
private:
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
typedef void* cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
struct cv_state
|
||||
{
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
bool do_trylock();
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
bool m_critical_section;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL timed_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<timed_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<timed_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<timed_mutex> scoped_try_lock;
|
||||
typedef detail::thread::scoped_timed_lock<timed_mutex> scoped_timed_lock;
|
||||
|
||||
timed_mutex();
|
||||
~timed_mutex();
|
||||
|
||||
private:
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
typedef void* cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
struct cv_state
|
||||
{
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
bool do_trylock();
|
||||
bool do_timedlock(const xtime& xt);
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
pthread_cond_t m_condition;
|
||||
bool m_locked;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
#endif
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
||||
// to three classes, mutex, try_mutex and timed_mutex.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
|
||||
#endif // BOOST_MUTEX_WEK070601_HPP
|
||||
|
||||
@@ -1,37 +1,29 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
#ifndef BOOST_THREAD_ONCE_HPP
|
||||
#define BOOST_THREAD_ONCE_HPP
|
||||
|
||||
// once.hpp
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_ONCE_WEK080101_HPP
|
||||
#define BOOST_ONCE_WEK080101_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/once.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/once.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
|
||||
typedef pthread_once_t once_flag;
|
||||
#define BOOST_ONCE_INIT PTHREAD_ONCE_INIT
|
||||
|
||||
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
|
||||
typedef long once_flag;
|
||||
#define BOOST_ONCE_INIT 0
|
||||
namespace boost
|
||||
{
|
||||
inline void call_once(void (*func)(),once_flag& flag)
|
||||
{
|
||||
call_once(flag,func);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag);
|
||||
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 1 Aug 01 WEKEMPF Initial version.
|
||||
|
||||
#endif // BOOST_ONCE_WEK080101_HPP
|
||||
|
||||
178
include/boost/thread/pthread/condition_variable.hpp
Normal file
178
include/boost/thread/pthread/condition_variable.hpp
Normal file
@@ -0,0 +1,178 @@
|
||||
#ifndef BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP
|
||||
#define BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
|
||||
#include <limits.h>
|
||||
#include <boost/assert.hpp>
|
||||
#include <algorithm>
|
||||
#include <pthread.h>
|
||||
#include "timespec.hpp"
|
||||
#include "pthread_mutex_scoped_lock.hpp"
|
||||
#include "thread_data.hpp"
|
||||
#include "condition_variable_fwd.hpp"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
inline condition_variable::condition_variable()
|
||||
{
|
||||
int const res=pthread_cond_init(&cond,NULL);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
inline condition_variable::~condition_variable()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
}
|
||||
|
||||
inline void condition_variable::wait(unique_lock<mutex>& m)
|
||||
{
|
||||
detail::interruption_checker check_for_interruption(&cond);
|
||||
BOOST_VERIFY(!pthread_cond_wait(&cond,m.mutex()->native_handle()));
|
||||
}
|
||||
|
||||
inline bool condition_variable::timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until)
|
||||
{
|
||||
detail::interruption_checker check_for_interruption(&cond);
|
||||
struct timespec const timeout=detail::get_timespec(wait_until);
|
||||
int const cond_res=pthread_cond_timedwait(&cond,m.mutex()->native_handle(),&timeout);
|
||||
if(cond_res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(!cond_res);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void condition_variable::notify_one()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
inline void condition_variable::notify_all()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&cond));
|
||||
}
|
||||
|
||||
class condition_variable_any
|
||||
{
|
||||
pthread_mutex_t internal_mutex;
|
||||
pthread_cond_t cond;
|
||||
|
||||
condition_variable_any(condition_variable&);
|
||||
condition_variable_any& operator=(condition_variable&);
|
||||
|
||||
public:
|
||||
condition_variable_any()
|
||||
{
|
||||
int const res=pthread_mutex_init(&internal_mutex,NULL);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
~condition_variable_any()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
void wait(lock_type& m)
|
||||
{
|
||||
int res=0;
|
||||
{
|
||||
detail::interruption_checker check_for_interruption(&cond);
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
m.unlock();
|
||||
res=pthread_cond_wait(&cond,&internal_mutex);
|
||||
}
|
||||
m.lock();
|
||||
}
|
||||
if(res)
|
||||
{
|
||||
throw condition_error();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
void wait(lock_type& m,predicate_type pred)
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until)
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(wait_until);
|
||||
int res=0;
|
||||
{
|
||||
detail::interruption_checker check_for_interruption(&cond);
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
m.unlock();
|
||||
res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
|
||||
}
|
||||
m.lock();
|
||||
}
|
||||
if(res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(res)
|
||||
{
|
||||
throw condition_error();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if(!timed_wait(m, wait_until))
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,xtime const& wait_until,predicate_type pred)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until),pred);
|
||||
}
|
||||
|
||||
template<typename lock_type,typename duration_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
|
||||
{
|
||||
return timed_wait(m,get_system_time()+wait_duration,pred);
|
||||
}
|
||||
|
||||
void notify_one()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
void notify_all()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&cond));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
66
include/boost/thread/pthread/condition_variable_fwd.hpp
Normal file
66
include/boost/thread/pthread/condition_variable_fwd.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP
|
||||
#define BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
|
||||
#include <pthread.h>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class condition_variable
|
||||
{
|
||||
private:
|
||||
pthread_cond_t cond;
|
||||
|
||||
condition_variable(condition_variable&);
|
||||
condition_variable& operator=(condition_variable&);
|
||||
|
||||
public:
|
||||
condition_variable();
|
||||
~condition_variable();
|
||||
|
||||
void wait(unique_lock<mutex>& m);
|
||||
|
||||
template<typename predicate_type>
|
||||
void wait(unique_lock<mutex>& m,predicate_type pred)
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until);
|
||||
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until,predicate_type pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if(!timed_wait(m, wait_until))
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,xtime const& wait_until,predicate_type pred)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until),pred);
|
||||
}
|
||||
|
||||
template<typename duration_type,typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
|
||||
{
|
||||
return timed_wait(m,get_system_time()+wait_duration,pred);
|
||||
}
|
||||
|
||||
void notify_one();
|
||||
void notify_all();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
197
include/boost/thread/pthread/mutex.hpp
Normal file
197
include/boost/thread/pthread/mutex.hpp
Normal file
@@ -0,0 +1,197 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP
|
||||
#define BOOST_THREAD_PTHREAD_MUTEX_HPP
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <pthread.h>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include "timespec.hpp"
|
||||
#include "pthread_mutex_scoped_lock.hpp"
|
||||
|
||||
#ifdef _POSIX_TIMEOUTS
|
||||
#if _POSIX_TIMEOUTS >= 0
|
||||
#define BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
public:
|
||||
mutex()
|
||||
{
|
||||
int const res=pthread_mutex_init(&m,NULL);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
~mutex()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(&m));
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
|
||||
typedef pthread_mutex_t* native_handle_type;
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
return &m;
|
||||
}
|
||||
|
||||
typedef unique_lock<mutex> scoped_lock;
|
||||
typedef scoped_lock scoped_try_lock;
|
||||
};
|
||||
|
||||
typedef mutex try_mutex;
|
||||
|
||||
class timed_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
pthread_cond_t cond;
|
||||
bool is_locked;
|
||||
#endif
|
||||
public:
|
||||
timed_mutex()
|
||||
{
|
||||
int const res=pthread_mutex_init(&m,NULL);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
throw thread_resource_error();
|
||||
}
|
||||
is_locked=false;
|
||||
#endif
|
||||
}
|
||||
~timed_mutex()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(&m));
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
bool timed_lock(system_time const & abs_time)
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(abs_time);
|
||||
int const res=pthread_mutex_timedlock(&m,&timeout);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
#else
|
||||
void lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
while(is_locked)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
|
||||
}
|
||||
is_locked=true;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
is_locked=false;
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
is_locked=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool timed_lock(system_time const & abs_time)
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(abs_time);
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
while(is_locked)
|
||||
{
|
||||
int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
|
||||
if(cond_res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(!cond_res);
|
||||
}
|
||||
is_locked=true;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef unique_lock<timed_mutex> scoped_timed_lock;
|
||||
typedef scoped_timed_lock scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
85
include/boost/thread/pthread/once.hpp
Normal file
85
include/boost/thread/pthread/once.hpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_ONCE_HPP
|
||||
#define BOOST_THREAD_PTHREAD_ONCE_HPP
|
||||
|
||||
// once.hpp
|
||||
//
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <boost/assert.hpp>
|
||||
#include "pthread_mutex_scoped_lock.hpp"
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
struct once_flag
|
||||
{
|
||||
boost::uintmax_t epoch;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
BOOST_THREAD_DECL boost::uintmax_t& get_once_per_thread_epoch();
|
||||
BOOST_THREAD_DECL extern boost::uintmax_t once_global_epoch;
|
||||
BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex;
|
||||
BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv;
|
||||
}
|
||||
|
||||
#define BOOST_ONCE_INITIAL_FLAG_VALUE 0
|
||||
#define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE}
|
||||
|
||||
|
||||
// Based on Mike Burrows fast_pthread_once algorithm as described in
|
||||
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html
|
||||
template<typename Function>
|
||||
void call_once(once_flag& flag,Function f)
|
||||
{
|
||||
static boost::uintmax_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
|
||||
static boost::uintmax_t const being_initialized=uninitialized_flag+1;
|
||||
boost::uintmax_t const epoch=flag.epoch;
|
||||
boost::uintmax_t& this_thread_epoch=detail::get_once_per_thread_epoch();
|
||||
|
||||
if(epoch<this_thread_epoch)
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&detail::once_epoch_mutex);
|
||||
|
||||
while(flag.epoch<=being_initialized)
|
||||
{
|
||||
if(flag.epoch==uninitialized_flag)
|
||||
{
|
||||
flag.epoch=being_initialized;
|
||||
try
|
||||
{
|
||||
pthread::pthread_mutex_scoped_unlock relocker(&detail::once_epoch_mutex);
|
||||
f();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
flag.epoch=uninitialized_flag;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
|
||||
throw;
|
||||
}
|
||||
flag.epoch=--detail::once_global_epoch;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
|
||||
}
|
||||
else
|
||||
{
|
||||
while(flag.epoch==being_initialized)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&detail::once_epoch_cv,&detail::once_epoch_mutex));
|
||||
}
|
||||
}
|
||||
}
|
||||
this_thread_epoch=detail::once_global_epoch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
50
include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp
Normal file
50
include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP
|
||||
#define BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <pthread.h>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace pthread
|
||||
{
|
||||
class pthread_mutex_scoped_lock
|
||||
{
|
||||
pthread_mutex_t* m;
|
||||
public:
|
||||
explicit pthread_mutex_scoped_lock(pthread_mutex_t* m_):
|
||||
m(m_)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(m));
|
||||
}
|
||||
~pthread_mutex_scoped_lock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(m));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class pthread_mutex_scoped_unlock
|
||||
{
|
||||
pthread_mutex_t* m;
|
||||
public:
|
||||
explicit pthread_mutex_scoped_unlock(pthread_mutex_t* m_):
|
||||
m(m_)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(m));
|
||||
}
|
||||
~pthread_mutex_scoped_unlock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(m));
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
249
include/boost/thread/pthread/recursive_mutex.hpp
Normal file
249
include/boost/thread/pthread/recursive_mutex.hpp
Normal file
@@ -0,0 +1,249 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP
|
||||
#define BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <pthread.h>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
#include <errno.h>
|
||||
#include "timespec.hpp"
|
||||
#include "pthread_mutex_scoped_lock.hpp"
|
||||
|
||||
#ifdef _POSIX_TIMEOUTS
|
||||
#if _POSIX_TIMEOUTS >= 0
|
||||
#define BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class recursive_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
public:
|
||||
recursive_mutex()
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
int const init_attr_res=pthread_mutexattr_init(&attr);
|
||||
if(init_attr_res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
|
||||
if(set_attr_res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
int const res=pthread_mutex_init(&m,&attr);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
||||
}
|
||||
~recursive_mutex()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(&m));
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
typedef unique_lock<recursive_mutex> scoped_lock;
|
||||
typedef scoped_lock scoped_try_lock;
|
||||
};
|
||||
|
||||
typedef recursive_mutex recursive_try_mutex;
|
||||
|
||||
class recursive_timed_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
pthread_cond_t cond;
|
||||
bool is_locked;
|
||||
pthread_t owner;
|
||||
unsigned count;
|
||||
#endif
|
||||
public:
|
||||
recursive_timed_mutex()
|
||||
{
|
||||
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
int const init_attr_res=pthread_mutexattr_init(&attr);
|
||||
if(init_attr_res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
|
||||
if(set_attr_res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
int const res=pthread_mutex_init(&m,&attr);
|
||||
if(res)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
||||
throw thread_resource_error();
|
||||
}
|
||||
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
||||
#else
|
||||
int const res=pthread_mutex_init(&m,NULL);
|
||||
if(res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
throw thread_resource_error();
|
||||
}
|
||||
is_locked=false;
|
||||
count=0;
|
||||
#endif
|
||||
}
|
||||
~recursive_timed_mutex()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(&m));
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
bool timed_lock(system_time const & abs_time)
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(abs_time);
|
||||
int const res=pthread_mutex_timedlock(&m,&timeout);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
#else
|
||||
void lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked && pthread_equal(owner,pthread_self()))
|
||||
{
|
||||
++count;
|
||||
return;
|
||||
}
|
||||
|
||||
while(is_locked)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
|
||||
}
|
||||
is_locked=true;
|
||||
++count;
|
||||
owner=pthread_self();
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(!--count)
|
||||
{
|
||||
is_locked=false;
|
||||
}
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked && !pthread_equal(owner,pthread_self()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
is_locked=true;
|
||||
++count;
|
||||
owner=pthread_self();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool timed_lock(system_time const & abs_time)
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(abs_time);
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked && pthread_equal(owner,pthread_self()))
|
||||
{
|
||||
++count;
|
||||
return true;
|
||||
}
|
||||
while(is_locked)
|
||||
{
|
||||
int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
|
||||
if(cond_res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(!cond_res);
|
||||
}
|
||||
is_locked=true;
|
||||
++count;
|
||||
owner=pthread_self();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef unique_lock<recursive_timed_mutex> scoped_timed_lock;
|
||||
typedef scoped_timed_lock scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
307
include/boost/thread/pthread/shared_mutex.hpp
Normal file
307
include/boost/thread/pthread/shared_mutex.hpp
Normal file
@@ -0,0 +1,307 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
|
||||
#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
|
||||
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class shared_mutex
|
||||
{
|
||||
private:
|
||||
struct state_data
|
||||
{
|
||||
unsigned shared_count;
|
||||
bool exclusive;
|
||||
bool upgrade;
|
||||
bool exclusive_waiting_blocked;
|
||||
};
|
||||
|
||||
|
||||
|
||||
state_data state;
|
||||
boost::mutex state_change;
|
||||
boost::condition_variable shared_cond;
|
||||
boost::condition_variable exclusive_cond;
|
||||
boost::condition_variable upgrade_cond;
|
||||
|
||||
void release_waiters()
|
||||
{
|
||||
exclusive_cond.notify_one();
|
||||
shared_cond.notify_all();
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
shared_mutex()
|
||||
{
|
||||
state_data state_={0};
|
||||
state=state_;
|
||||
}
|
||||
|
||||
~shared_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
void lock_shared()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(!state.exclusive && !state.exclusive_waiting_blocked)
|
||||
{
|
||||
++state.shared_count;
|
||||
return;
|
||||
}
|
||||
|
||||
shared_cond.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
if(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
++state.shared_count;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool timed_lock_shared(system_time const& timeout)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(!state.exclusive && !state.exclusive_waiting_blocked)
|
||||
{
|
||||
++state.shared_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!shared_cond.timed_wait(lock,timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
bool const last_reader=!--state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
if(state.upgrade)
|
||||
{
|
||||
state.upgrade=false;
|
||||
state.exclusive=true;
|
||||
upgrade_cond.notify_one();
|
||||
}
|
||||
else
|
||||
{
|
||||
state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
release_waiters();
|
||||
}
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.exclusive=true;
|
||||
return;
|
||||
}
|
||||
exclusive_cond.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
bool timed_lock(system_time const& timeout)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.exclusive=true;
|
||||
return true;
|
||||
}
|
||||
if(!exclusive_cond.timed_wait(lock,timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.exclusive=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
state.exclusive=false;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
void lock_upgrade()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
while(true)
|
||||
{
|
||||
if(!state.exclusive && !state.exclusive_waiting_blocked && !state.upgrade)
|
||||
{
|
||||
++state.shared_count;
|
||||
state.upgrade=true;
|
||||
return;
|
||||
}
|
||||
|
||||
shared_cond.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
bool timed_lock_upgrade(system_time const& timeout)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
while(true)
|
||||
{
|
||||
if(!state.exclusive && !state.exclusive_waiting_blocked && !state.upgrade)
|
||||
{
|
||||
++state.shared_count;
|
||||
state.upgrade=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!shared_cond.timed_wait(lock,timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
++state.shared_count;
|
||||
state.upgrade=true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
state.upgrade=false;
|
||||
bool const last_reader=!--state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
--state.shared_count;
|
||||
while(true)
|
||||
{
|
||||
if(!state.shared_count)
|
||||
{
|
||||
state.upgrade=false;
|
||||
state.exclusive=true;
|
||||
break;
|
||||
}
|
||||
upgrade_cond.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
state.exclusive=false;
|
||||
state.upgrade=true;
|
||||
++state.shared_count;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
state.exclusive=false;
|
||||
++state.shared_count;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
state.upgrade=false;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
301
include/boost/thread/pthread/thread.hpp
Normal file
301
include/boost/thread/pthread/thread.hpp
Normal file
@@ -0,0 +1,301 @@
|
||||
#ifndef BOOST_THREAD_THREAD_PTHREAD_HPP
|
||||
#define BOOST_THREAD_THREAD_PTHREAD_HPP
|
||||
// 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)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include "thread_data.hpp"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class thread;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class thread_id;
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
BOOST_THREAD_DECL detail::thread_id get_id();
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class thread_id
|
||||
{
|
||||
boost::optional<pthread_t> id;
|
||||
|
||||
friend class boost::thread;
|
||||
|
||||
friend thread_id this_thread::get_id();
|
||||
|
||||
thread_id(pthread_t id_):
|
||||
id(id_)
|
||||
{}
|
||||
|
||||
public:
|
||||
thread_id()
|
||||
{}
|
||||
|
||||
bool operator==(const thread_id& y) const
|
||||
{
|
||||
return (id && y.id) && (pthread_equal(*id,*y.id)!=0);
|
||||
}
|
||||
|
||||
bool operator!=(const thread_id& y) const
|
||||
{
|
||||
return !(*this==y);
|
||||
}
|
||||
|
||||
template<class charT, class traits>
|
||||
friend std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const thread_id& x)
|
||||
{
|
||||
if(x.id)
|
||||
{
|
||||
return os<<*x.id;
|
||||
}
|
||||
else
|
||||
{
|
||||
return os<<"{Not-any-thread}";
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
struct xtime;
|
||||
class BOOST_THREAD_DECL thread
|
||||
{
|
||||
private:
|
||||
thread(thread&);
|
||||
thread& operator=(thread&);
|
||||
|
||||
template<typename F>
|
||||
struct thread_data:
|
||||
detail::thread_data_base
|
||||
{
|
||||
F f;
|
||||
|
||||
thread_data(F f_):
|
||||
f(f_)
|
||||
{}
|
||||
thread_data(detail::thread_move_t<F> f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
void run()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
|
||||
mutable boost::mutex thread_info_mutex;
|
||||
boost::shared_ptr<detail::thread_data_base> thread_info;
|
||||
|
||||
void start_thread();
|
||||
|
||||
explicit thread(boost::shared_ptr<detail::thread_data_base> data);
|
||||
|
||||
boost::shared_ptr<detail::thread_data_base> get_thread_info() const;
|
||||
|
||||
public:
|
||||
thread();
|
||||
~thread();
|
||||
|
||||
template <class F>
|
||||
explicit thread(F f):
|
||||
thread_info(new thread_data<F>(f))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
template <class F>
|
||||
thread(detail::thread_move_t<F> f):
|
||||
thread_info(new thread_data<F>(f))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
thread(detail::thread_move_t<thread> x);
|
||||
thread& operator=(detail::thread_move_t<thread> x);
|
||||
operator detail::thread_move_t<thread>();
|
||||
detail::thread_move_t<thread> move();
|
||||
|
||||
void swap(thread& x);
|
||||
|
||||
typedef detail::thread_id id;
|
||||
|
||||
id get_id() const;
|
||||
|
||||
bool joinable() const;
|
||||
void join();
|
||||
bool timed_join(const system_time& wait_until);
|
||||
|
||||
template<typename TimeDuration>
|
||||
inline bool timed_join(TimeDuration const& rel_time)
|
||||
{
|
||||
return timed_join(get_system_time()+rel_time);
|
||||
}
|
||||
void detach();
|
||||
|
||||
static unsigned hardware_concurrency();
|
||||
|
||||
// backwards compatibility
|
||||
bool operator==(const thread& other) const;
|
||||
bool operator!=(const thread& other) const;
|
||||
|
||||
static void sleep(const system_time& xt);
|
||||
static void yield();
|
||||
|
||||
// extensions
|
||||
void interrupt();
|
||||
bool interruption_requested() const;
|
||||
};
|
||||
|
||||
inline detail::thread_move_t<thread> move(thread& x)
|
||||
{
|
||||
return x.move();
|
||||
}
|
||||
|
||||
inline detail::thread_move_t<thread> move(detail::thread_move_t<thread> x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
template<typename F>
|
||||
struct thread::thread_data<boost::reference_wrapper<F> >:
|
||||
detail::thread_data_base
|
||||
{
|
||||
F& f;
|
||||
|
||||
thread_data(boost::reference_wrapper<F> f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
void run()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
class BOOST_THREAD_DECL disable_interruption
|
||||
{
|
||||
disable_interruption(const disable_interruption&);
|
||||
disable_interruption& operator=(const disable_interruption&);
|
||||
|
||||
bool interruption_was_enabled;
|
||||
friend class restore_interruption;
|
||||
public:
|
||||
disable_interruption();
|
||||
~disable_interruption();
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL restore_interruption
|
||||
{
|
||||
restore_interruption(const restore_interruption&);
|
||||
restore_interruption& operator=(const restore_interruption&);
|
||||
public:
|
||||
explicit restore_interruption(disable_interruption& d);
|
||||
~restore_interruption();
|
||||
};
|
||||
|
||||
inline thread::id get_id()
|
||||
{
|
||||
return thread::id(pthread_self());
|
||||
}
|
||||
|
||||
BOOST_THREAD_DECL void interruption_point();
|
||||
BOOST_THREAD_DECL bool interruption_enabled();
|
||||
BOOST_THREAD_DECL bool interruption_requested();
|
||||
|
||||
inline void yield()
|
||||
{
|
||||
thread::yield();
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
inline void sleep(TimeDuration const& rel_time)
|
||||
{
|
||||
thread::sleep(get_system_time()+rel_time);
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct thread_exit_function_base
|
||||
{
|
||||
virtual ~thread_exit_function_base()
|
||||
{}
|
||||
virtual void operator()() const=0;
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
struct thread_exit_function:
|
||||
thread_exit_function_base
|
||||
{
|
||||
F f;
|
||||
|
||||
thread_exit_function(F f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_THREAD_DECL void add_thread_exit_function(thread_exit_function_base*);
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
template<typename F>
|
||||
inline void at_thread_exit(F f)
|
||||
{
|
||||
detail::thread_exit_function_base* const thread_exit_func=new detail::thread_exit_function<F>(f);
|
||||
detail::add_thread_exit_function(thread_exit_func);
|
||||
}
|
||||
}
|
||||
|
||||
class BOOST_THREAD_DECL thread_group : private noncopyable
|
||||
{
|
||||
public:
|
||||
thread_group();
|
||||
~thread_group();
|
||||
|
||||
thread* create_thread(const function0<void>& threadfunc);
|
||||
void add_thread(thread* thrd);
|
||||
void remove_thread(thread* thrd);
|
||||
void join_all();
|
||||
void interrupt_all();
|
||||
int size() const;
|
||||
|
||||
private:
|
||||
std::list<thread*> m_threads;
|
||||
mutex m_mutex;
|
||||
};
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif
|
||||
95
include/boost/thread/pthread/thread_data.hpp
Normal file
95
include/boost/thread/pthread/thread_data.hpp
Normal file
@@ -0,0 +1,95 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
|
||||
#define BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <pthread.h>
|
||||
#include "condition_variable_fwd.hpp"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class thread_interrupted
|
||||
{};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct thread_exit_callback_node;
|
||||
struct tss_data_node;
|
||||
|
||||
struct thread_data_base
|
||||
{
|
||||
boost::shared_ptr<thread_data_base> self;
|
||||
pthread_t thread_handle;
|
||||
boost::mutex data_mutex;
|
||||
boost::condition_variable done_condition;
|
||||
boost::mutex sleep_mutex;
|
||||
boost::condition_variable sleep_condition;
|
||||
bool done;
|
||||
bool join_started;
|
||||
bool joined;
|
||||
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
|
||||
boost::detail::tss_data_node* tss_data;
|
||||
bool interrupt_enabled;
|
||||
bool interrupt_requested;
|
||||
pthread_cond_t* current_cond;
|
||||
|
||||
thread_data_base():
|
||||
done(false),join_started(false),joined(false),
|
||||
thread_exit_callbacks(0),tss_data(0),
|
||||
interrupt_enabled(true),
|
||||
interrupt_requested(false),
|
||||
current_cond(0)
|
||||
{}
|
||||
virtual ~thread_data_base()
|
||||
{}
|
||||
|
||||
virtual void run()=0;
|
||||
};
|
||||
|
||||
BOOST_THREAD_DECL thread_data_base* get_current_thread_data();
|
||||
|
||||
class interruption_checker
|
||||
{
|
||||
thread_data_base* const thread_info;
|
||||
|
||||
void check_for_interruption()
|
||||
{
|
||||
if(thread_info->interrupt_requested)
|
||||
{
|
||||
thread_info->interrupt_requested=false;
|
||||
throw thread_interrupted();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
explicit interruption_checker(pthread_cond_t* cond):
|
||||
thread_info(detail::get_current_thread_data())
|
||||
{
|
||||
if(thread_info && thread_info->interrupt_enabled)
|
||||
{
|
||||
lock_guard<mutex> guard(thread_info->data_mutex);
|
||||
check_for_interruption();
|
||||
thread_info->current_cond=cond;
|
||||
}
|
||||
}
|
||||
~interruption_checker()
|
||||
{
|
||||
if(thread_info && thread_info->interrupt_enabled)
|
||||
{
|
||||
lock_guard<mutex> guard(thread_info->data_mutex);
|
||||
thread_info->current_cond=NULL;
|
||||
check_for_interruption();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
28
include/boost/thread/pthread/timespec.hpp
Normal file
28
include/boost/thread/pthread/timespec.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_TIMESPEC_HPP
|
||||
#define BOOST_THREAD_PTHREAD_TIMESPEC_HPP
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline struct timespec get_timespec(boost::system_time const& abs_time)
|
||||
{
|
||||
struct timespec timeout={0};
|
||||
boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0);
|
||||
|
||||
timeout.tv_sec=time_since_epoch.total_seconds();
|
||||
timeout.tv_nsec=time_since_epoch.fractional_seconds()*(1000000000/time_since_epoch.ticks_per_second());
|
||||
return timeout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
103
include/boost/thread/pthread/tss.hpp
Normal file
103
include/boost/thread/pthread/tss.hpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_TSS_HPP
|
||||
#define BOOST_THREAD_PTHREAD_TSS_HPP
|
||||
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct tss_cleanup_function
|
||||
{
|
||||
virtual ~tss_cleanup_function()
|
||||
{}
|
||||
|
||||
virtual void operator()(void* data)=0;
|
||||
};
|
||||
|
||||
BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing);
|
||||
BOOST_THREAD_DECL void* get_tss_data(void const* key);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class thread_specific_ptr
|
||||
{
|
||||
private:
|
||||
thread_specific_ptr(thread_specific_ptr&);
|
||||
thread_specific_ptr& operator=(thread_specific_ptr&);
|
||||
|
||||
struct delete_data:
|
||||
detail::tss_cleanup_function
|
||||
{
|
||||
void operator()(void* data)
|
||||
{
|
||||
delete static_cast<T*>(data);
|
||||
}
|
||||
};
|
||||
|
||||
struct run_custom_cleanup_function:
|
||||
detail::tss_cleanup_function
|
||||
{
|
||||
void (*cleanup_function)(T*);
|
||||
|
||||
explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)):
|
||||
cleanup_function(cleanup_function_)
|
||||
{}
|
||||
|
||||
void operator()(void* data)
|
||||
{
|
||||
cleanup_function(data);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
boost::shared_ptr<detail::tss_cleanup_function> cleanup;
|
||||
|
||||
public:
|
||||
thread_specific_ptr():
|
||||
cleanup(new delete_data)
|
||||
{}
|
||||
explicit thread_specific_ptr(void (*func_)(T*)):
|
||||
cleanup(new run_custom_cleanup_function(func_))
|
||||
{}
|
||||
~thread_specific_ptr()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
T* get() const
|
||||
{
|
||||
return static_cast<T*>(detail::get_tss_data(this));
|
||||
}
|
||||
T* operator->() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
T& operator*() const
|
||||
{
|
||||
return *get();
|
||||
}
|
||||
T* release()
|
||||
{
|
||||
T* const temp=get();
|
||||
detail::set_tss_data(this,0,0,false);
|
||||
return temp;
|
||||
}
|
||||
void reset(T* new_value=0)
|
||||
{
|
||||
T* const current_value=get();
|
||||
if(current_value!=new_value)
|
||||
{
|
||||
detail::set_tss_data(this,cleanup,new_value,true);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -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.
|
||||
@@ -1,184 +1,21 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
#ifndef BOOST_THREAD_RECURSIVE_MUTEX_HPP
|
||||
#define BOOST_THREAD_RECURSIVE_MUTEX_HPP
|
||||
|
||||
// recursive_mutex.hpp
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 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)
|
||||
|
||||
#ifndef BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||
#define BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/detail/lock.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/recursive_mutex.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/recursive_mutex.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_MPTASKS)
|
||||
# include "scoped_critical_region.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
struct xtime;
|
||||
// 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
|
||||
class BOOST_THREAD_DECL recursive_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<recursive_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<recursive_mutex> scoped_lock;
|
||||
|
||||
recursive_mutex();
|
||||
~recursive_mutex();
|
||||
|
||||
private:
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
typedef std::size_t cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
long count;
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
bool m_critical_section;
|
||||
unsigned long m_count;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
unsigned m_count;
|
||||
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||
pthread_cond_t m_unlocked;
|
||||
pthread_t m_thread_id;
|
||||
bool m_valid_id;
|
||||
# endif
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
std::size_t m_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL recursive_try_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<recursive_try_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<recursive_try_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<
|
||||
recursive_try_mutex> scoped_try_lock;
|
||||
|
||||
recursive_try_mutex();
|
||||
~recursive_try_mutex();
|
||||
|
||||
private:
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
typedef std::size_t cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
long count;
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
bool do_trylock();
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
bool m_critical_section;
|
||||
unsigned long m_count;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
unsigned m_count;
|
||||
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
|
||||
pthread_cond_t m_unlocked;
|
||||
pthread_t m_thread_id;
|
||||
bool m_valid_id;
|
||||
# endif
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
std::size_t m_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL recursive_timed_mutex
|
||||
: private noncopyable
|
||||
{
|
||||
public:
|
||||
friend class detail::thread::lock_ops<recursive_timed_mutex>;
|
||||
|
||||
typedef detail::thread::scoped_lock<recursive_timed_mutex> scoped_lock;
|
||||
typedef detail::thread::scoped_try_lock<
|
||||
recursive_timed_mutex> scoped_try_lock;
|
||||
typedef detail::thread::scoped_timed_lock<
|
||||
recursive_timed_mutex> scoped_timed_lock;
|
||||
|
||||
recursive_timed_mutex();
|
||||
~recursive_timed_mutex();
|
||||
|
||||
private:
|
||||
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
|
||||
typedef std::size_t cv_state;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
struct cv_state
|
||||
{
|
||||
long count;
|
||||
pthread_mutex_t* pmutex;
|
||||
};
|
||||
#endif
|
||||
void do_lock();
|
||||
bool do_trylock();
|
||||
bool do_timedlock(const xtime& xt);
|
||||
void do_unlock();
|
||||
void do_lock(cv_state& state);
|
||||
void do_unlock(cv_state& state);
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_mutex;
|
||||
unsigned long m_count;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_mutex_t m_mutex;
|
||||
pthread_cond_t m_unlocked;
|
||||
pthread_t m_thread_id;
|
||||
bool m_valid_id;
|
||||
unsigned m_count;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
threads::mac::detail::scoped_critical_region m_mutex;
|
||||
threads::mac::detail::scoped_critical_region m_mutex_mutex;
|
||||
std::size_t m_count;
|
||||
#endif
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out
|
||||
// to three classes, mutex, try_mutex and timed_mutex.
|
||||
// 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
|
||||
21
include/boost/thread/shared_mutex.hpp
Normal file
21
include/boost/thread/shared_mutex.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef BOOST_THREAD_SHARED_MUTEX_HPP
|
||||
#define BOOST_THREAD_SHARED_MUTEX_HPP
|
||||
|
||||
// shared_mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/shared_mutex.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/shared_mutex.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,89 +1,22 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
#ifndef BOOST_THREAD_THREAD_HPP
|
||||
#define BOOST_THREAD_THREAD_HPP
|
||||
|
||||
// thread.hpp
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 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)
|
||||
|
||||
#ifndef BOOST_THREAD_WEK070601_HPP
|
||||
#define BOOST_THREAD_WEK070601_HPP
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
# include <boost/thread/condition.hpp>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <Multiprocessing.h>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/thread.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/thread.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
struct xtime;
|
||||
// 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
|
||||
class BOOST_THREAD_DECL thread : private noncopyable
|
||||
{
|
||||
public:
|
||||
thread();
|
||||
explicit thread(const function0<void>& threadfunc);
|
||||
~thread();
|
||||
|
||||
bool operator==(const thread& other) const;
|
||||
bool operator!=(const thread& other) const;
|
||||
|
||||
void join();
|
||||
|
||||
static void sleep(const xtime& xt);
|
||||
static void yield();
|
||||
|
||||
private:
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
void* m_thread;
|
||||
unsigned int m_id;
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
private:
|
||||
pthread_t m_thread;
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
MPQueueID m_pJoinQueueID;
|
||||
MPTaskID m_pTaskID;
|
||||
#endif
|
||||
bool m_joinable;
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL thread_group : private noncopyable
|
||||
{
|
||||
public:
|
||||
thread_group();
|
||||
~thread_group();
|
||||
|
||||
thread* create_thread(const function0<void>& threadfunc);
|
||||
void add_thread(thread* thrd);
|
||||
void remove_thread(thread* thrd);
|
||||
void join_all();
|
||||
int size() const;
|
||||
|
||||
private:
|
||||
std::list<thread*> m_threads;
|
||||
mutex m_mutex;
|
||||
};
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 1 Jun 01 WEKEMPF Added boost::thread initial implementation.
|
||||
// 3 Jul 01 WEKEMPF Redesigned boost::thread to be noncopyable.
|
||||
|
||||
#endif // BOOST_THREAD_WEK070601_HPP
|
||||
|
||||
46
include/boost/thread/thread_time.hpp
Normal file
46
include/boost/thread/thread_time.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef BOOST_THREAD_TIME_HPP
|
||||
#define BOOST_THREAD_TIME_HPP
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/date_time/microsec_time_clock.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
typedef boost::posix_time::ptime system_time;
|
||||
|
||||
inline system_time get_system_time()
|
||||
{
|
||||
return boost::date_time::microsec_clock<system_time>::universal_time();
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
inline system_time get_system_time_sentinel()
|
||||
{
|
||||
return system_time(boost::posix_time::pos_infin);
|
||||
}
|
||||
|
||||
inline unsigned long get_milliseconds_until(system_time const& target_time)
|
||||
{
|
||||
if(target_time.is_pos_infinity())
|
||||
{
|
||||
return ~(unsigned long)0;
|
||||
}
|
||||
system_time const now=get_system_time();
|
||||
if(target_time<=now)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return static_cast<unsigned long>((target_time-now).total_milliseconds()+1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,127 +1,18 @@
|
||||
// Copyright (C) 2001-2003 William E. Kempf
|
||||
// Copyright (C) 2006 Roland Schwarz
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_TSS_WEK070601_HPP
|
||||
#define BOOST_TSS_WEK070601_HPP
|
||||
#ifndef BOOST_THREAD_TSS_HPP
|
||||
#define BOOST_THREAD_TSS_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <Multiprocessing.h>
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/tss.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/tss.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
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 detail {
|
||||
|
||||
class BOOST_THREAD_DECL tss : private noncopyable
|
||||
{
|
||||
public:
|
||||
tss(boost::function1<void, void*>* pcleanup) {
|
||||
if (pcleanup == 0) throw boost::thread_resource_error();
|
||||
try
|
||||
{
|
||||
init(pcleanup);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
delete pcleanup;
|
||||
throw boost::thread_resource_error();
|
||||
}
|
||||
}
|
||||
~tss();
|
||||
void* get() const;
|
||||
void set(void* value);
|
||||
void cleanup(void* p);
|
||||
|
||||
private:
|
||||
unsigned int m_slot; //This is a "pseudo-slot", not a native slot
|
||||
|
||||
void init(boost::function1<void, void*>* pcleanup);
|
||||
};
|
||||
|
||||
#if defined(BOOST_HAS_MPTASKS)
|
||||
void thread_cleanup();
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
struct tss_adapter
|
||||
{
|
||||
template <typename F>
|
||||
tss_adapter(const F& cleanup) : m_cleanup(cleanup) { }
|
||||
void operator()(void* p) { m_cleanup(static_cast<T*>(p)); }
|
||||
boost::function1<void, T*> m_cleanup;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
class thread_specific_ptr : private noncopyable
|
||||
{
|
||||
public:
|
||||
thread_specific_ptr()
|
||||
: m_tss(new boost::function1<void, void*>(
|
||||
boost::detail::tss_adapter<T>(
|
||||
&thread_specific_ptr<T>::cleanup)))
|
||||
{
|
||||
}
|
||||
thread_specific_ptr(void (*clean)(T*))
|
||||
: m_tss(new boost::function1<void, void*>(
|
||||
boost::detail::tss_adapter<T>(clean)))
|
||||
{
|
||||
}
|
||||
~thread_specific_ptr() { reset(); }
|
||||
|
||||
T* get() const { return static_cast<T*>(m_tss.get()); }
|
||||
T* operator->() const { return get(); }
|
||||
T& operator*() const { return *get(); }
|
||||
T* release() { T* temp = get(); if (temp) m_tss.set(0); return temp; }
|
||||
void reset(T* p=0)
|
||||
{
|
||||
T* cur = get();
|
||||
if (cur == p) return;
|
||||
m_tss.set(p);
|
||||
if (cur) m_tss.cleanup(cur);
|
||||
}
|
||||
|
||||
private:
|
||||
static void cleanup(T* p) { delete p; }
|
||||
detail::tss m_tss;
|
||||
};
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif //BOOST_TSS_WEK070601_HPP
|
||||
|
||||
// Change Log:
|
||||
// 6 Jun 01
|
||||
// WEKEMPF Initial version.
|
||||
// 30 May 02 WEKEMPF
|
||||
// Added interface to set specific cleanup handlers.
|
||||
// Removed TLS slot limits from most implementations.
|
||||
// 22 Mar 04 GlassfordM for WEKEMPF
|
||||
// Fixed: thread_specific_ptr::reset() doesn't check error returned
|
||||
// by tss::set(); tss::set() now throws if it fails.
|
||||
// Fixed: calling thread_specific_ptr::reset() or
|
||||
// thread_specific_ptr::release() causes double-delete: once on
|
||||
// reset()/release() and once on ~thread_specific_ptr().
|
||||
|
||||
120
include/boost/thread/win32/basic_recursive_mutex.hpp
Normal file
120
include/boost/thread/win32/basic_recursive_mutex.hpp
Normal file
@@ -0,0 +1,120 @@
|
||||
#ifndef BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP
|
||||
#define BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP
|
||||
|
||||
// basic_recursive_mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "thread_primitives.hpp"
|
||||
#include "basic_timed_mutex.hpp"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename underlying_mutex_type>
|
||||
struct basic_recursive_mutex_impl
|
||||
{
|
||||
long recursion_count;
|
||||
long locking_thread_id;
|
||||
underlying_mutex_type mutex;
|
||||
|
||||
void initialize()
|
||||
{
|
||||
recursion_count=0;
|
||||
locking_thread_id=0;
|
||||
mutex.initialize();
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
mutex.destroy();
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
long const current_thread_id=win32::GetCurrentThreadId();
|
||||
return try_recursive_lock(current_thread_id) || try_basic_lock(current_thread_id);
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
long const current_thread_id=win32::GetCurrentThreadId();
|
||||
if(!try_recursive_lock(current_thread_id))
|
||||
{
|
||||
mutex.lock();
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
|
||||
recursion_count=1;
|
||||
}
|
||||
}
|
||||
bool timed_lock(::boost::system_time const& target)
|
||||
{
|
||||
long const current_thread_id=win32::GetCurrentThreadId();
|
||||
return try_recursive_lock(current_thread_id) || try_timed_lock(current_thread_id,target);
|
||||
}
|
||||
long get_active_count()
|
||||
{
|
||||
return mutex.get_active_count();
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
if(!--recursion_count)
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,0);
|
||||
mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool locked()
|
||||
{
|
||||
return mutex.locked();
|
||||
}
|
||||
|
||||
private:
|
||||
bool try_recursive_lock(long current_thread_id)
|
||||
{
|
||||
if(::boost::detail::interlocked_read_acquire(&locking_thread_id)==current_thread_id)
|
||||
{
|
||||
++recursion_count;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool try_basic_lock(long current_thread_id)
|
||||
{
|
||||
if(mutex.try_lock())
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
|
||||
recursion_count=1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool try_timed_lock(long current_thread_id,::boost::system_time const& target)
|
||||
{
|
||||
if(mutex.timed_lock(target))
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
|
||||
recursion_count=1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
typedef basic_recursive_mutex_impl<basic_timed_mutex> basic_recursive_mutex;
|
||||
typedef basic_recursive_mutex_impl<basic_timed_mutex> basic_recursive_timed_mutex;
|
||||
}
|
||||
}
|
||||
|
||||
#define BOOST_BASIC_RECURSIVE_MUTEX_INITIALIZER {0}
|
||||
|
||||
#endif
|
||||
157
include/boost/thread/win32/basic_timed_mutex.hpp
Normal file
157
include/boost/thread/win32/basic_timed_mutex.hpp
Normal file
@@ -0,0 +1,157 @@
|
||||
#ifndef BOOST_BASIC_TIMED_MUTEX_WIN32_HPP
|
||||
#define BOOST_BASIC_TIMED_MUTEX_WIN32_HPP
|
||||
|
||||
// basic_timed_mutex_win32.hpp
|
||||
//
|
||||
// (C) Copyright 2006 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include "thread_primitives.hpp"
|
||||
#include "interlocked_read.hpp"
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct basic_timed_mutex
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(long,lock_flag_value=0x80000000);
|
||||
long active_count;
|
||||
void* event;
|
||||
|
||||
void initialize()
|
||||
{
|
||||
active_count=0;
|
||||
event=0;
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
void* const old_event=BOOST_INTERLOCKED_EXCHANGE_POINTER(&event,0);
|
||||
if(old_event)
|
||||
{
|
||||
win32::CloseHandle(old_event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
long old_count=active_count&~lock_flag_value;
|
||||
do
|
||||
{
|
||||
long const current_count=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,(old_count+1)|lock_flag_value,old_count);
|
||||
if(current_count==old_count)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
old_count=current_count;
|
||||
}
|
||||
while(!(old_count&lock_flag_value));
|
||||
return false;
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
|
||||
}
|
||||
bool timed_lock(::boost::system_time const& wait_until)
|
||||
{
|
||||
long old_count=active_count;
|
||||
while(true)
|
||||
{
|
||||
long const current_count=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,(old_count+1)|lock_flag_value,old_count);
|
||||
if(current_count==old_count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_count=current_count;
|
||||
}
|
||||
|
||||
if(old_count&lock_flag_value)
|
||||
{
|
||||
bool lock_acquired=false;
|
||||
void* const sem=get_event();
|
||||
++old_count; // we're waiting, too
|
||||
do
|
||||
{
|
||||
old_count-=(lock_flag_value+1); // there will be one less active thread on this mutex when it gets unlocked
|
||||
if(win32::WaitForSingleObject(sem,::boost::detail::get_milliseconds_until(wait_until))!=0)
|
||||
{
|
||||
BOOST_INTERLOCKED_DECREMENT(&active_count);
|
||||
return false;
|
||||
}
|
||||
do
|
||||
{
|
||||
long const current_count=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,old_count|lock_flag_value,old_count);
|
||||
if(current_count==old_count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_count=current_count;
|
||||
}
|
||||
while(!(old_count&lock_flag_value));
|
||||
lock_acquired=!(old_count&lock_flag_value);
|
||||
}
|
||||
while(!lock_acquired);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
long get_active_count()
|
||||
{
|
||||
return ::boost::detail::interlocked_read_acquire(&active_count);
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
long const offset=lock_flag_value+1;
|
||||
long old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,(~offset)+1);
|
||||
|
||||
if(old_count>offset)
|
||||
{
|
||||
win32::SetEvent(get_event());
|
||||
}
|
||||
}
|
||||
|
||||
bool locked()
|
||||
{
|
||||
return get_active_count()>=lock_flag_value;
|
||||
}
|
||||
|
||||
private:
|
||||
void* get_event()
|
||||
{
|
||||
void* current_event=::boost::detail::interlocked_read_acquire(&event);
|
||||
|
||||
if(!current_event)
|
||||
{
|
||||
void* const new_event=win32::create_anonymous_event(win32::auto_reset_event,win32::event_initially_reset);
|
||||
void* const old_event=BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&event,new_event,0);
|
||||
if(old_event!=0)
|
||||
{
|
||||
win32::CloseHandle(new_event);
|
||||
return old_event;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new_event;
|
||||
}
|
||||
}
|
||||
return current_event;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#define BOOST_BASIC_TIMED_MUTEX_INITIALIZER {0}
|
||||
|
||||
#endif
|
||||
361
include/boost/thread/win32/condition_variable.hpp
Normal file
361
include/boost/thread/win32/condition_variable.hpp
Normal file
@@ -0,0 +1,361 @@
|
||||
#ifndef BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
|
||||
#define BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include "thread_primitives.hpp"
|
||||
#include <limits.h>
|
||||
#include <boost/assert.hpp>
|
||||
#include <algorithm>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include "interlocked_read.hpp"
|
||||
#include <boost/thread/xtime.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
class basic_condition_variable
|
||||
{
|
||||
boost::mutex internal_mutex;
|
||||
long total_count;
|
||||
unsigned active_generation_count;
|
||||
|
||||
struct list_entry
|
||||
{
|
||||
detail::win32::handle semaphore;
|
||||
long count;
|
||||
bool notified;
|
||||
|
||||
list_entry():
|
||||
semaphore(0),count(0),notified(0)
|
||||
{}
|
||||
};
|
||||
|
||||
BOOST_STATIC_CONSTANT(unsigned,generation_count=3);
|
||||
|
||||
list_entry generations[generation_count];
|
||||
detail::win32::handle wake_sem;
|
||||
|
||||
static bool no_waiters(list_entry const& entry)
|
||||
{
|
||||
return entry.count==0;
|
||||
}
|
||||
|
||||
void shift_generations_down()
|
||||
{
|
||||
list_entry* const last_active_entry=std::remove_if(generations,generations+generation_count,no_waiters);
|
||||
if(last_active_entry==generations+generation_count)
|
||||
{
|
||||
broadcast_entry(generations[generation_count-1],false);
|
||||
}
|
||||
else
|
||||
{
|
||||
active_generation_count=(last_active_entry-generations)+1;
|
||||
}
|
||||
|
||||
std::copy_backward(generations,generations+active_generation_count-1,generations+active_generation_count);
|
||||
generations[0]=list_entry();
|
||||
}
|
||||
|
||||
void broadcast_entry(list_entry& entry,bool wake)
|
||||
{
|
||||
long const count_to_wake=entry.count;
|
||||
detail::interlocked_write_release(&total_count,total_count-count_to_wake);
|
||||
if(wake)
|
||||
{
|
||||
detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0);
|
||||
}
|
||||
detail::win32::ReleaseSemaphore(entry.semaphore,count_to_wake,0);
|
||||
entry.count=0;
|
||||
dispose_entry(entry);
|
||||
}
|
||||
|
||||
|
||||
void dispose_entry(list_entry& entry)
|
||||
{
|
||||
if(entry.semaphore)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::CloseHandle(entry.semaphore));
|
||||
entry.semaphore=0;
|
||||
}
|
||||
entry.notified=false;
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
struct relocker
|
||||
{
|
||||
lock_type& lock;
|
||||
bool unlocked;
|
||||
|
||||
relocker(lock_type& lock_):
|
||||
lock(lock_),unlocked(false)
|
||||
{}
|
||||
void unlock()
|
||||
{
|
||||
lock.unlock();
|
||||
unlocked=true;
|
||||
}
|
||||
~relocker()
|
||||
{
|
||||
if(unlocked)
|
||||
{
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename lock_type>
|
||||
void start_wait_loop_first_time(relocker<lock_type>& locker,
|
||||
detail::win32::handle_manager& local_wake_sem)
|
||||
{
|
||||
locker.unlock();
|
||||
if(!wake_sem)
|
||||
{
|
||||
wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
BOOST_ASSERT(wake_sem);
|
||||
}
|
||||
local_wake_sem=detail::win32::duplicate_handle(wake_sem);
|
||||
|
||||
if(generations[0].notified)
|
||||
{
|
||||
shift_generations_down();
|
||||
}
|
||||
else if(!active_generation_count)
|
||||
{
|
||||
active_generation_count=1;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
void start_wait_loop(relocker<lock_type>& locker,
|
||||
detail::win32::handle_manager& local_wake_sem,
|
||||
detail::win32::handle_manager& sem)
|
||||
{
|
||||
boost::mutex::scoped_lock internal_lock(internal_mutex);
|
||||
detail::interlocked_write_release(&total_count,total_count+1);
|
||||
if(!local_wake_sem)
|
||||
{
|
||||
start_wait_loop_first_time(locker,local_wake_sem);
|
||||
}
|
||||
if(!generations[0].semaphore)
|
||||
{
|
||||
generations[0].semaphore=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
BOOST_ASSERT(generations[0].semaphore);
|
||||
}
|
||||
++generations[0].count;
|
||||
sem=detail::win32::duplicate_handle(generations[0].semaphore);
|
||||
}
|
||||
|
||||
protected:
|
||||
template<typename lock_type>
|
||||
bool do_wait(lock_type& lock,timeout wait_until)
|
||||
{
|
||||
detail::win32::handle_manager local_wake_sem;
|
||||
detail::win32::handle_manager sem;
|
||||
bool woken=false;
|
||||
|
||||
relocker<lock_type> locker(lock);
|
||||
|
||||
while(!woken)
|
||||
{
|
||||
start_wait_loop(locker,local_wake_sem,sem);
|
||||
|
||||
if(!this_thread::interruptible_wait(sem,wait_until))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned long const woken_result=detail::win32::WaitForSingleObject(local_wake_sem,0);
|
||||
BOOST_ASSERT(woken_result==detail::win32::timeout || woken_result==0);
|
||||
|
||||
woken=(woken_result==0);
|
||||
}
|
||||
return woken;
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool do_wait(lock_type& m,timeout const& wait_until,predicate_type pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if(!do_wait(m, wait_until))
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
basic_condition_variable(const basic_condition_variable& other);
|
||||
basic_condition_variable& operator=(const basic_condition_variable& other);
|
||||
public:
|
||||
basic_condition_variable():
|
||||
total_count(0),active_generation_count(0),wake_sem(0)
|
||||
{}
|
||||
|
||||
~basic_condition_variable()
|
||||
{
|
||||
for(unsigned i=0;i<generation_count;++i)
|
||||
{
|
||||
dispose_entry(generations[i]);
|
||||
}
|
||||
detail::win32::CloseHandle(wake_sem);
|
||||
}
|
||||
|
||||
|
||||
void notify_one()
|
||||
{
|
||||
if(detail::interlocked_read_acquire(&total_count))
|
||||
{
|
||||
boost::mutex::scoped_lock internal_lock(internal_mutex);
|
||||
detail::win32::ReleaseSemaphore(wake_sem,1,0);
|
||||
for(unsigned generation=active_generation_count;generation!=0;--generation)
|
||||
{
|
||||
list_entry& entry=generations[generation-1];
|
||||
if(entry.count)
|
||||
{
|
||||
detail::interlocked_write_release(&total_count,total_count-1);
|
||||
entry.notified=true;
|
||||
detail::win32::ReleaseSemaphore(entry.semaphore,1,0);
|
||||
if(!--entry.count)
|
||||
{
|
||||
dispose_entry(entry);
|
||||
if(generation==active_generation_count)
|
||||
{
|
||||
--active_generation_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void notify_all()
|
||||
{
|
||||
if(detail::interlocked_read_acquire(&total_count))
|
||||
{
|
||||
boost::mutex::scoped_lock internal_lock(internal_mutex);
|
||||
for(unsigned generation=active_generation_count;generation!=0;--generation)
|
||||
{
|
||||
list_entry& entry=generations[generation-1];
|
||||
if(entry.count)
|
||||
{
|
||||
broadcast_entry(entry,true);
|
||||
}
|
||||
}
|
||||
active_generation_count=0;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
class condition_variable:
|
||||
public detail::basic_condition_variable
|
||||
{
|
||||
public:
|
||||
void wait(unique_lock<mutex>& m)
|
||||
{
|
||||
do_wait(m,detail::timeout::sentinel());
|
||||
}
|
||||
|
||||
template<typename predicate_type>
|
||||
void wait(unique_lock<mutex>& m,predicate_type pred)
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until)
|
||||
{
|
||||
return do_wait(m,wait_until);
|
||||
}
|
||||
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until)
|
||||
{
|
||||
return do_wait(m,system_time(wait_until));
|
||||
}
|
||||
template<typename duration_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
|
||||
{
|
||||
return do_wait(m,wait_duration.total_milliseconds());
|
||||
}
|
||||
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,wait_until,pred);
|
||||
}
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,system_time(wait_until),pred);
|
||||
}
|
||||
template<typename duration_type,typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,wait_duration.total_milliseconds(),pred);
|
||||
}
|
||||
};
|
||||
|
||||
class condition_variable_any:
|
||||
public detail::basic_condition_variable
|
||||
{
|
||||
public:
|
||||
template<typename lock_type>
|
||||
void wait(lock_type& m)
|
||||
{
|
||||
do_wait(m,detail::timeout::sentinel());
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
void wait(lock_type& m,predicate_type pred)
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until)
|
||||
{
|
||||
return do_wait(m,wait_until);
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,boost::xtime const& wait_until)
|
||||
{
|
||||
return do_wait(m,system_time(wait_until));
|
||||
}
|
||||
|
||||
template<typename lock_type,typename duration_type>
|
||||
bool timed_wait(lock_type& m,duration_type const& wait_duration)
|
||||
{
|
||||
return do_wait(m,wait_duration.total_milliseconds());
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,wait_until,pred);
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,boost::xtime const& wait_until,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,system_time(wait_until),pred);
|
||||
}
|
||||
|
||||
template<typename lock_type,typename duration_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,wait_duration.total_milliseconds(),pred);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
77
include/boost/thread/win32/interlocked_read.hpp
Normal file
77
include/boost/thread/win32/interlocked_read.hpp
Normal file
@@ -0,0 +1,77 @@
|
||||
#ifndef BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP
|
||||
#define BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP
|
||||
|
||||
// interlocked_read_win32.hpp
|
||||
//
|
||||
// (C) Copyright 2005-7 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
|
||||
extern "C" void _ReadWriteBarrier(void);
|
||||
#pragma intrinsic(_ReadWriteBarrier)
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline long interlocked_read_acquire(long volatile* x)
|
||||
{
|
||||
long const res=*x;
|
||||
_ReadWriteBarrier();
|
||||
return res;
|
||||
}
|
||||
inline void* interlocked_read_acquire(void* volatile* x)
|
||||
{
|
||||
void* const res=*x;
|
||||
_ReadWriteBarrier();
|
||||
return res;
|
||||
}
|
||||
|
||||
inline void interlocked_write_release(long volatile* x,long value)
|
||||
{
|
||||
_ReadWriteBarrier();
|
||||
*x=value;
|
||||
}
|
||||
inline void interlocked_write_release(void* volatile* x,void* value)
|
||||
{
|
||||
_ReadWriteBarrier();
|
||||
*x=value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline long interlocked_read_acquire(long volatile* x)
|
||||
{
|
||||
return BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,0,0);
|
||||
}
|
||||
inline void* interlocked_read_acquire(void* volatile* x)
|
||||
{
|
||||
return BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(x,0,0);
|
||||
}
|
||||
inline void interlocked_write_release(long volatile* x,long value)
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(x,value);
|
||||
}
|
||||
inline void interlocked_write_release(void* volatile* x,void* value)
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE_POINTER(x,value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
61
include/boost/thread/win32/mutex.hpp
Normal file
61
include/boost/thread/win32/mutex.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef BOOST_THREAD_WIN32_MUTEX_HPP
|
||||
#define BOOST_THREAD_WIN32_MUTEX_HPP
|
||||
// (C) Copyright 2005-7 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "basic_timed_mutex.hpp"
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
typedef ::boost::detail::basic_timed_mutex underlying_mutex;
|
||||
}
|
||||
|
||||
class mutex:
|
||||
boost::noncopyable,
|
||||
public ::boost::detail::underlying_mutex
|
||||
{
|
||||
public:
|
||||
mutex()
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
~mutex()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
typedef unique_lock<mutex> scoped_lock;
|
||||
typedef scoped_lock scoped_try_lock;
|
||||
};
|
||||
|
||||
typedef mutex try_mutex;
|
||||
|
||||
class timed_mutex:
|
||||
boost::noncopyable,
|
||||
public ::boost::detail::basic_timed_mutex
|
||||
{
|
||||
public:
|
||||
timed_mutex()
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
||||
~timed_mutex()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
typedef unique_lock<timed_mutex> scoped_timed_lock;
|
||||
typedef scoped_timed_lock scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
130
include/boost/thread/win32/once.hpp
Normal file
130
include/boost/thread/win32/once.hpp
Normal file
@@ -0,0 +1,130 @@
|
||||
#ifndef BOOST_THREAD_WIN32_ONCE_HPP
|
||||
#define BOOST_THREAD_WIN32_ONCE_HPP
|
||||
|
||||
// once.hpp
|
||||
//
|
||||
// (C) Copyright 2005-7 Anthony Williams
|
||||
// (C) Copyright 2005 John Maddock
|
||||
//
|
||||
// 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 <cstring>
|
||||
#include <cstddef>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <boost/thread/win32/interlocked_read.hpp>
|
||||
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std
|
||||
{
|
||||
using ::memcpy;
|
||||
using ::ptrdiff_t;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
typedef long once_flag;
|
||||
|
||||
#define BOOST_ONCE_INIT 0
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct win32_mutex_scoped_lock
|
||||
{
|
||||
void* const mutex_handle;
|
||||
explicit win32_mutex_scoped_lock(void* mutex_handle_):
|
||||
mutex_handle(mutex_handle_)
|
||||
{
|
||||
BOOST_VERIFY(!win32::WaitForSingleObject(mutex_handle,win32::infinite));
|
||||
}
|
||||
~win32_mutex_scoped_lock()
|
||||
{
|
||||
BOOST_VERIFY(win32::ReleaseMutex(mutex_handle)!=0);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef BOOST_NO_ANSI_APIS
|
||||
template <class I>
|
||||
void int_to_string(I p, wchar_t* buf)
|
||||
{
|
||||
for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
|
||||
{
|
||||
*buf = L'A' + static_cast<wchar_t>((p >> (i*4)) & 0x0f);
|
||||
}
|
||||
*buf = 0;
|
||||
}
|
||||
#else
|
||||
template <class I>
|
||||
void int_to_string(I p, char* buf)
|
||||
{
|
||||
for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
|
||||
{
|
||||
*buf = 'A' + static_cast<char>((p >> (i*4)) & 0x0f);
|
||||
}
|
||||
*buf = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// create a named mutex. It doesn't really matter what this name is
|
||||
// as long as it is unique both to this process, and to the address of "flag":
|
||||
inline void* create_once_mutex(void* flag_address)
|
||||
{
|
||||
|
||||
#ifdef BOOST_NO_ANSI_APIS
|
||||
typedef wchar_t char_type;
|
||||
static const char_type fixed_mutex_name[]=L"{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
|
||||
#else
|
||||
typedef char char_type;
|
||||
static const char_type fixed_mutex_name[]="{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
|
||||
#endif
|
||||
unsigned const once_mutex_name_fixed_buffer_size=sizeof(fixed_mutex_name)/sizeof(char_type);
|
||||
unsigned const once_mutex_name_fixed_length=once_mutex_name_fixed_buffer_size-1;
|
||||
unsigned const once_mutex_name_length=once_mutex_name_fixed_buffer_size+sizeof(void*)*2+sizeof(unsigned long)*2;
|
||||
char_type mutex_name[once_mutex_name_length];
|
||||
|
||||
std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name));
|
||||
|
||||
BOOST_STATIC_ASSERT(sizeof(void*) == sizeof(std::ptrdiff_t));
|
||||
detail::int_to_string(reinterpret_cast<std::ptrdiff_t>(flag_address), mutex_name + once_mutex_name_fixed_length);
|
||||
detail::int_to_string(win32::GetCurrentProcessId(), mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2);
|
||||
|
||||
#ifdef BOOST_NO_ANSI_APIS
|
||||
return win32::CreateMutexW(NULL, 0, mutex_name);
|
||||
#else
|
||||
return win32::CreateMutexA(NULL, 0, mutex_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename Function>
|
||||
void call_once(once_flag& flag,Function f)
|
||||
{
|
||||
// Try for a quick win: if the procedure has already been called
|
||||
// just skip through:
|
||||
long const function_complete_flag_value=0xc15730e2;
|
||||
|
||||
if(::boost::detail::interlocked_read_acquire(&flag)!=function_complete_flag_value)
|
||||
{
|
||||
void* const mutex_handle(::boost::detail::create_once_mutex(&flag));
|
||||
BOOST_ASSERT(mutex_handle);
|
||||
detail::win32::handle_manager const closer(mutex_handle);
|
||||
detail::win32_mutex_scoped_lock const lock(mutex_handle);
|
||||
|
||||
if(flag!=function_complete_flag_value)
|
||||
{
|
||||
f();
|
||||
BOOST_INTERLOCKED_EXCHANGE(&flag,function_complete_flag_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
61
include/boost/thread/win32/recursive_mutex.hpp
Normal file
61
include/boost/thread/win32/recursive_mutex.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef BOOST_RECURSIVE_MUTEX_WIN32_HPP
|
||||
#define BOOST_RECURSIVE_MUTEX_WIN32_HPP
|
||||
|
||||
// recursive_mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include "basic_recursive_mutex.hpp"
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class recursive_mutex:
|
||||
boost::noncopyable,
|
||||
public ::boost::detail::basic_recursive_mutex
|
||||
{
|
||||
public:
|
||||
recursive_mutex()
|
||||
{
|
||||
::boost::detail::basic_recursive_mutex::initialize();
|
||||
}
|
||||
~recursive_mutex()
|
||||
{
|
||||
::boost::detail::basic_recursive_mutex::destroy();
|
||||
}
|
||||
|
||||
typedef unique_lock<recursive_mutex> scoped_lock;
|
||||
typedef scoped_lock scoped_try_lock;
|
||||
};
|
||||
|
||||
typedef recursive_mutex recursive_try_mutex;
|
||||
|
||||
class recursive_timed_mutex:
|
||||
boost::noncopyable,
|
||||
public ::boost::detail::basic_recursive_timed_mutex
|
||||
{
|
||||
public:
|
||||
recursive_timed_mutex()
|
||||
{
|
||||
::boost::detail::basic_recursive_timed_mutex::initialize();
|
||||
}
|
||||
~recursive_timed_mutex()
|
||||
{
|
||||
::boost::detail::basic_recursive_timed_mutex::destroy();
|
||||
}
|
||||
|
||||
typedef unique_lock<recursive_timed_mutex> scoped_timed_lock;
|
||||
typedef scoped_timed_lock scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
509
include/boost/thread/win32/shared_mutex.hpp
Normal file
509
include/boost/thread/win32/shared_mutex.hpp
Normal file
@@ -0,0 +1,509 @@
|
||||
#ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
|
||||
#define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
|
||||
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <limits.h>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class shared_mutex:
|
||||
private boost::noncopyable
|
||||
{
|
||||
private:
|
||||
struct state_data
|
||||
{
|
||||
unsigned shared_count:11;
|
||||
unsigned shared_waiting:11;
|
||||
unsigned exclusive:1;
|
||||
unsigned upgrade:1;
|
||||
unsigned exclusive_waiting:7;
|
||||
unsigned exclusive_waiting_blocked:1;
|
||||
|
||||
friend bool operator==(state_data const& lhs,state_data const& rhs)
|
||||
{
|
||||
return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
T interlocked_compare_exchange(T* target,T new_value,T comparand)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long));
|
||||
long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast<long*>(target),
|
||||
*reinterpret_cast<long*>(&new_value),
|
||||
*reinterpret_cast<long*>(&comparand));
|
||||
return *reinterpret_cast<T const*>(&res);
|
||||
}
|
||||
|
||||
state_data state;
|
||||
detail::win32::handle semaphores[2];
|
||||
detail::win32::handle &unlock_sem;
|
||||
detail::win32::handle &exclusive_sem;
|
||||
detail::win32::handle upgrade_sem;
|
||||
|
||||
void release_waiters(state_data old_state)
|
||||
{
|
||||
if(old_state.exclusive_waiting)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(exclusive_sem,1,NULL)!=0);
|
||||
}
|
||||
|
||||
if(old_state.shared_waiting || old_state.exclusive_waiting)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(unlock_sem,old_state.shared_waiting + (old_state.exclusive_waiting?1:0),NULL)!=0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
shared_mutex():
|
||||
unlock_sem(semaphores[0]),
|
||||
exclusive_sem(semaphores[1])
|
||||
{
|
||||
unlock_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
exclusive_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
upgrade_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
state_data state_={0};
|
||||
state=state_;
|
||||
}
|
||||
|
||||
~shared_mutex()
|
||||
{
|
||||
detail::win32::CloseHandle(upgrade_sem);
|
||||
detail::win32::CloseHandle(unlock_sem);
|
||||
detail::win32::CloseHandle(exclusive_sem);
|
||||
}
|
||||
|
||||
bool try_lock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(!new_state.exclusive && !new_state.exclusive_waiting_blocked)
|
||||
{
|
||||
++new_state.shared_count;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
|
||||
}
|
||||
|
||||
void lock_shared()
|
||||
{
|
||||
BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel()));
|
||||
}
|
||||
|
||||
bool timed_lock_shared(boost::system_time const& wait_until)
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
|
||||
{
|
||||
++new_state.shared_waiting;
|
||||
}
|
||||
else
|
||||
{
|
||||
++new_state.shared_count;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
|
||||
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned long const res=detail::win32::WaitForSingleObject(unlock_sem,::boost::detail::get_milliseconds_until(wait_until));
|
||||
if(res==detail::win32::timeout)
|
||||
{
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
|
||||
{
|
||||
if(new_state.shared_waiting)
|
||||
{
|
||||
--new_state.shared_waiting;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++new_state.shared_count;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
|
||||
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(res==0);
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
bool const last_reader=!--new_state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
if(new_state.upgrade)
|
||||
{
|
||||
new_state.upgrade=false;
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
}
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
if(last_reader)
|
||||
{
|
||||
if(old_state.upgrade)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,NULL)!=0);
|
||||
}
|
||||
else
|
||||
{
|
||||
release_waiters(old_state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
|
||||
}
|
||||
|
||||
bool timed_lock(boost::system_time const& wait_until)
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
state_data old_state=state;
|
||||
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.shared_count || new_state.exclusive)
|
||||
{
|
||||
++new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
|
||||
if(!old_state.shared_count && !old_state.exclusive)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,true,::boost::detail::get_milliseconds_until(wait_until));
|
||||
if(wait_res==detail::win32::timeout)
|
||||
{
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.shared_count || new_state.exclusive)
|
||||
{
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
if(!old_state.shared_count && !old_state.exclusive)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(wait_res<2);
|
||||
}
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.exclusive=false;
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
void lock_upgrade()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
|
||||
{
|
||||
++new_state.shared_waiting;
|
||||
}
|
||||
else
|
||||
{
|
||||
++new_state.shared_count;
|
||||
new_state.upgrade=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
|
||||
if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_VERIFY(!detail::win32::WaitForSingleObject(unlock_sem,detail::win32::infinite));
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_upgrade()
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.upgrade=false;
|
||||
bool const last_reader=!--new_state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
if(last_reader)
|
||||
{
|
||||
release_waiters(old_state);
|
||||
}
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock()
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
bool const last_reader=!--new_state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
new_state.upgrade=false;
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
if(!last_reader)
|
||||
{
|
||||
BOOST_VERIFY(!detail::win32::WaitForSingleObject(upgrade_sem,detail::win32::infinite));
|
||||
}
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
}
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.exclusive=false;
|
||||
new_state.upgrade=true;
|
||||
++new_state.shared_count;
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.exclusive=false;
|
||||
++new_state.shared_count;
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
do
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.upgrade=false;
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
while(true);
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
506
include/boost/thread/win32/thread.hpp
Normal file
506
include/boost/thread/win32/thread.hpp
Normal file
@@ -0,0 +1,506 @@
|
||||
#ifndef BOOST_THREAD_THREAD_WIN32_HPP
|
||||
#define BOOST_THREAD_THREAD_WIN32_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
|
||||
#include <exception>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <ostream>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include "thread_primitives.hpp"
|
||||
#include "thread_heap_alloc.hpp"
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class thread_interrupted
|
||||
{};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct thread_exit_callback_node;
|
||||
struct tss_data_node;
|
||||
|
||||
struct thread_data_base
|
||||
{
|
||||
long count;
|
||||
detail::win32::handle_manager thread_handle;
|
||||
detail::win32::handle_manager interruption_handle;
|
||||
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
|
||||
boost::detail::tss_data_node* tss_data;
|
||||
bool interruption_enabled;
|
||||
unsigned id;
|
||||
|
||||
thread_data_base():
|
||||
count(0),thread_handle(detail::win32::invalid_handle_value),
|
||||
interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)),
|
||||
thread_exit_callbacks(0),tss_data(0),
|
||||
interruption_enabled(true),
|
||||
id(0)
|
||||
{}
|
||||
virtual ~thread_data_base()
|
||||
{}
|
||||
|
||||
friend void intrusive_ptr_add_ref(thread_data_base * p)
|
||||
{
|
||||
BOOST_INTERLOCKED_INCREMENT(&p->count);
|
||||
}
|
||||
|
||||
friend void intrusive_ptr_release(thread_data_base * p)
|
||||
{
|
||||
if(!BOOST_INTERLOCKED_DECREMENT(&p->count))
|
||||
{
|
||||
detail::heap_delete(p);
|
||||
}
|
||||
}
|
||||
|
||||
void interrupt()
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0);
|
||||
}
|
||||
|
||||
|
||||
virtual void run()=0;
|
||||
};
|
||||
|
||||
typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr;
|
||||
|
||||
struct timeout
|
||||
{
|
||||
unsigned long start;
|
||||
uintmax_t milliseconds;
|
||||
bool relative;
|
||||
boost::system_time abs_time;
|
||||
|
||||
static unsigned long const max_non_infinite_wait=0xfffffffe;
|
||||
|
||||
timeout(uintmax_t milliseconds_):
|
||||
start(win32::GetTickCount()),
|
||||
milliseconds(milliseconds_),
|
||||
relative(true),
|
||||
abs_time(boost::get_system_time())
|
||||
{}
|
||||
|
||||
timeout(boost::system_time const& abs_time_):
|
||||
start(win32::GetTickCount()),
|
||||
milliseconds(0),
|
||||
relative(false),
|
||||
abs_time(abs_time_)
|
||||
{}
|
||||
|
||||
struct remaining_time
|
||||
{
|
||||
bool more;
|
||||
unsigned long milliseconds;
|
||||
|
||||
remaining_time(uintmax_t remaining):
|
||||
more(remaining>max_non_infinite_wait),
|
||||
milliseconds(more?max_non_infinite_wait:(unsigned long)remaining)
|
||||
{}
|
||||
};
|
||||
|
||||
remaining_time remaining_milliseconds() const
|
||||
{
|
||||
if(is_sentinel())
|
||||
{
|
||||
return remaining_time(win32::infinite);
|
||||
}
|
||||
else if(relative)
|
||||
{
|
||||
unsigned long const now=win32::GetTickCount();
|
||||
unsigned long const elapsed=now-start;
|
||||
return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0);
|
||||
}
|
||||
else
|
||||
{
|
||||
system_time const now=get_system_time();
|
||||
if(abs_time<=now)
|
||||
{
|
||||
return remaining_time(0);
|
||||
}
|
||||
return remaining_time((abs_time-now).total_milliseconds()+1);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_sentinel() const
|
||||
{
|
||||
return milliseconds==~uintmax_t(0);
|
||||
}
|
||||
|
||||
|
||||
static timeout sentinel()
|
||||
{
|
||||
return timeout(sentinel_type());
|
||||
}
|
||||
private:
|
||||
struct sentinel_type
|
||||
{};
|
||||
|
||||
explicit timeout(sentinel_type):
|
||||
start(0),milliseconds(~uintmax_t(0)),relative(true)
|
||||
{}
|
||||
};
|
||||
}
|
||||
|
||||
class BOOST_THREAD_DECL thread
|
||||
{
|
||||
private:
|
||||
thread(thread&);
|
||||
thread& operator=(thread&);
|
||||
|
||||
void release_handle();
|
||||
|
||||
template<typename F>
|
||||
struct thread_data:
|
||||
detail::thread_data_base
|
||||
{
|
||||
F f;
|
||||
|
||||
thread_data(F f_):
|
||||
f(f_)
|
||||
{}
|
||||
thread_data(detail::thread_move_t<F> f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
void run()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
|
||||
mutable boost::mutex thread_info_mutex;
|
||||
detail::thread_data_ptr thread_info;
|
||||
|
||||
static unsigned __stdcall thread_start_function(void* param);
|
||||
|
||||
void start_thread();
|
||||
|
||||
explicit thread(detail::thread_data_ptr data);
|
||||
|
||||
detail::thread_data_ptr get_thread_info() const;
|
||||
public:
|
||||
thread();
|
||||
~thread();
|
||||
|
||||
template <class F>
|
||||
explicit thread(F f):
|
||||
thread_info(detail::heap_new<thread_data<F> >(f))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
template <class F>
|
||||
thread(detail::thread_move_t<F> f):
|
||||
thread_info(detail::heap_new<thread_data<F> >(f))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
thread(detail::thread_move_t<thread> x);
|
||||
thread& operator=(detail::thread_move_t<thread> x);
|
||||
operator detail::thread_move_t<thread>();
|
||||
detail::thread_move_t<thread> move();
|
||||
|
||||
void swap(thread& x);
|
||||
|
||||
class id;
|
||||
id get_id() const;
|
||||
|
||||
|
||||
bool joinable() const;
|
||||
void join();
|
||||
bool timed_join(const system_time& wait_until);
|
||||
|
||||
template<typename TimeDuration>
|
||||
inline bool timed_join(TimeDuration const& rel_time)
|
||||
{
|
||||
return timed_join(get_system_time()+rel_time);
|
||||
}
|
||||
void detach();
|
||||
|
||||
static unsigned hardware_concurrency();
|
||||
|
||||
typedef detail::win32::handle native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
// backwards compatibility
|
||||
bool operator==(const thread& other) const;
|
||||
bool operator!=(const thread& other) const;
|
||||
|
||||
static void yield();
|
||||
static void sleep(const system_time& xt);
|
||||
|
||||
// extensions
|
||||
void interrupt();
|
||||
bool interruption_requested() const;
|
||||
};
|
||||
|
||||
inline detail::thread_move_t<thread> move(thread& x)
|
||||
{
|
||||
return x.move();
|
||||
}
|
||||
|
||||
inline detail::thread_move_t<thread> move(detail::thread_move_t<thread> x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
struct thread::thread_data<boost::reference_wrapper<F> >:
|
||||
detail::thread_data_base
|
||||
{
|
||||
F& f;
|
||||
|
||||
thread_data(boost::reference_wrapper<F> f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
void run()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
class BOOST_THREAD_DECL disable_interruption
|
||||
{
|
||||
disable_interruption(const disable_interruption&);
|
||||
disable_interruption& operator=(const disable_interruption&);
|
||||
|
||||
bool interruption_was_enabled;
|
||||
friend class restore_interruption;
|
||||
public:
|
||||
disable_interruption();
|
||||
~disable_interruption();
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL restore_interruption
|
||||
{
|
||||
restore_interruption(const restore_interruption&);
|
||||
restore_interruption& operator=(const restore_interruption&);
|
||||
public:
|
||||
explicit restore_interruption(disable_interruption& d);
|
||||
~restore_interruption();
|
||||
};
|
||||
|
||||
thread::id BOOST_THREAD_DECL get_id();
|
||||
|
||||
bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);
|
||||
inline bool interruptible_wait(unsigned long milliseconds)
|
||||
{
|
||||
return interruptible_wait(detail::win32::invalid_handle_value,milliseconds);
|
||||
}
|
||||
|
||||
void BOOST_THREAD_DECL interruption_point();
|
||||
bool BOOST_THREAD_DECL interruption_enabled();
|
||||
bool BOOST_THREAD_DECL interruption_requested();
|
||||
|
||||
void BOOST_THREAD_DECL yield();
|
||||
template<typename TimeDuration>
|
||||
void sleep(TimeDuration const& rel_time)
|
||||
{
|
||||
interruptible_wait(static_cast<unsigned long>(rel_time.total_milliseconds()));
|
||||
}
|
||||
}
|
||||
|
||||
class thread::id
|
||||
{
|
||||
private:
|
||||
detail::thread_data_ptr thread_data;
|
||||
|
||||
id(detail::thread_data_ptr thread_data_):
|
||||
thread_data(thread_data_)
|
||||
{}
|
||||
friend class thread;
|
||||
friend id this_thread::get_id();
|
||||
public:
|
||||
id():
|
||||
thread_data(0)
|
||||
{}
|
||||
|
||||
bool operator==(const id& y) const
|
||||
{
|
||||
return thread_data==y.thread_data;
|
||||
}
|
||||
|
||||
bool operator!=(const id& y) const
|
||||
{
|
||||
return thread_data!=y.thread_data;
|
||||
}
|
||||
|
||||
bool operator<(const id& y) const
|
||||
{
|
||||
return thread_data<y.thread_data;
|
||||
}
|
||||
|
||||
bool operator>(const id& y) const
|
||||
{
|
||||
return y.thread_data<thread_data;
|
||||
}
|
||||
|
||||
bool operator<=(const id& y) const
|
||||
{
|
||||
return !(y.thread_data<thread_data);
|
||||
}
|
||||
|
||||
bool operator>=(const id& y) const
|
||||
{
|
||||
return !(thread_data<y.thread_data);
|
||||
}
|
||||
|
||||
template<class charT, class traits>
|
||||
friend std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const id& x)
|
||||
{
|
||||
return os<<x.thread_data;
|
||||
}
|
||||
|
||||
void interrupt()
|
||||
{
|
||||
if(thread_data)
|
||||
{
|
||||
thread_data->interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline bool thread::operator==(const thread& other) const
|
||||
{
|
||||
return get_id()==other.get_id();
|
||||
}
|
||||
|
||||
inline bool thread::operator!=(const thread& other) const
|
||||
{
|
||||
return get_id()!=other.get_id();
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct thread_exit_function_base
|
||||
{
|
||||
virtual ~thread_exit_function_base()
|
||||
{}
|
||||
virtual void operator()() const=0;
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
struct thread_exit_function:
|
||||
thread_exit_function_base
|
||||
{
|
||||
F f;
|
||||
|
||||
thread_exit_function(F f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
void operator()() const
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
|
||||
void add_thread_exit_function(thread_exit_function_base*);
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
template<typename F>
|
||||
void at_thread_exit(F f)
|
||||
{
|
||||
detail::thread_exit_function_base* const thread_exit_func=detail::heap_new<detail::thread_exit_function<F> >(f);
|
||||
detail::add_thread_exit_function(thread_exit_func);
|
||||
}
|
||||
}
|
||||
|
||||
class thread_group:
|
||||
private noncopyable
|
||||
{
|
||||
public:
|
||||
~thread_group()
|
||||
{
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
thread* create_thread(F threadfunc)
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
thread* const new_thread=new thread(threadfunc);
|
||||
threads.push_back(new_thread);
|
||||
return new_thread;
|
||||
}
|
||||
|
||||
void add_thread(thread* thrd)
|
||||
{
|
||||
if(thrd)
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
threads.push_back(thrd);
|
||||
}
|
||||
}
|
||||
|
||||
void remove_thread(thread* thrd)
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
std::list<thread*>::iterator const it=std::find(threads.begin(),threads.end(),thrd);
|
||||
if(it!=threads.end())
|
||||
{
|
||||
threads.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void join_all()
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
(*it)->join();
|
||||
}
|
||||
}
|
||||
|
||||
void interrupt_all()
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
(*it)->interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
int size() const
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m);
|
||||
return threads.size();
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<thread*> threads;
|
||||
mutable mutex m;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
170
include/boost/thread/win32/thread_heap_alloc.hpp
Normal file
170
include/boost/thread/win32/thread_heap_alloc.hpp
Normal file
@@ -0,0 +1,170 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
#ifndef THREAD_HEAP_ALLOC_HPP
|
||||
#define THREAD_HEAP_ALLOC_HPP
|
||||
#include <new>
|
||||
#include "thread_primitives.hpp"
|
||||
#include <stdexcept>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
# include <windows.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
using ::GetProcessHeap;
|
||||
using ::HeapAlloc;
|
||||
using ::HeapFree;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
# ifdef HeapAlloc
|
||||
# undef HeapAlloc
|
||||
# endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
__declspec(dllimport) handle __stdcall GetProcessHeap();
|
||||
__declspec(dllimport) void* __stdcall HeapAlloc(handle,unsigned long,ulong_ptr);
|
||||
__declspec(dllimport) int __stdcall HeapFree(handle,unsigned long,void*);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline BOOST_THREAD_DECL void* allocate_raw_heap_memory(unsigned size)
|
||||
{
|
||||
void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,size);
|
||||
if(!heap_memory)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
return heap_memory;
|
||||
}
|
||||
|
||||
inline BOOST_THREAD_DECL void free_raw_heap_memory(void* heap_memory)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,heap_memory)!=0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* heap_new()
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
try
|
||||
{
|
||||
T* const data=new (heap_memory) T();
|
||||
return data;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T,typename A1>
|
||||
T* heap_new(A1 a1)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
try
|
||||
{
|
||||
T* const data=new (heap_memory) T(a1);
|
||||
return data;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2>
|
||||
T* heap_new(A1 a1,A2 a2)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
try
|
||||
{
|
||||
T* const data=new (heap_memory) T(a1,a2);
|
||||
return data;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
T* heap_new(A1 a1,A2 a2,A3 a3)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
try
|
||||
{
|
||||
T* const data=new (heap_memory) T(a1,a2,a3);
|
||||
return data;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
T* heap_new(A1 a1,A2 a2,A3 a3,A4 a4)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
try
|
||||
{
|
||||
T* const data=new (heap_memory) T(a1,a2,a3,a4);
|
||||
return data;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void heap_delete(T* data)
|
||||
{
|
||||
data->~T();
|
||||
free_raw_heap_memory(data);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct do_heap_delete
|
||||
{
|
||||
void operator()(T* data) const
|
||||
{
|
||||
detail::heap_delete(data);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
281
include/boost/thread/win32/thread_primitives.hpp
Normal file
281
include/boost/thread/win32/thread_primitives.hpp
Normal file
@@ -0,0 +1,281 @@
|
||||
#ifndef BOOST_WIN32_THREAD_PRIMITIVES_HPP
|
||||
#define BOOST_WIN32_THREAD_PRIMITIVES_HPP
|
||||
|
||||
// win32_thread_primitives.hpp
|
||||
//
|
||||
// (C) Copyright 2005-7 Anthony Williams
|
||||
// (C) Copyright 2007 David Deakins
|
||||
//
|
||||
// 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/config.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
# include <windows.h>
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
typedef ULONG_PTR ulong_ptr;
|
||||
typedef HANDLE handle;
|
||||
unsigned const infinite=INFINITE;
|
||||
unsigned const timeout=WAIT_TIMEOUT;
|
||||
handle const invalid_handle_value=INVALID_HANDLE_VALUE;
|
||||
|
||||
# ifdef BOOST_NO_ANSI_APIS
|
||||
using ::CreateMutexW;
|
||||
using ::CreateEventW;
|
||||
using ::CreateSemaphoreW;
|
||||
# else
|
||||
using ::CreateMutexA;
|
||||
using ::CreateEventA;
|
||||
using ::CreateSemaphoreA;
|
||||
# endif
|
||||
using ::CloseHandle;
|
||||
using ::ReleaseMutex;
|
||||
using ::ReleaseSemaphore;
|
||||
using ::SetEvent;
|
||||
using ::ResetEvent;
|
||||
using ::WaitForMultipleObjects;
|
||||
using ::WaitForSingleObject;
|
||||
using ::GetCurrentProcessId;
|
||||
using ::GetCurrentThreadId;
|
||||
using ::GetCurrentThread;
|
||||
using ::GetCurrentProcess;
|
||||
using ::DuplicateHandle;
|
||||
using ::SleepEx;
|
||||
using ::Sleep;
|
||||
using ::QueueUserAPC;
|
||||
using ::GetTickCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ )
|
||||
|
||||
# ifdef UNDER_CE
|
||||
# ifndef WINAPI
|
||||
# ifndef _WIN32_WCE_EMULATION
|
||||
# define WINAPI __cdecl // Note this doesn't match the desktop definition
|
||||
# else
|
||||
# define WINAPI __stdcall
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
typedef int BOOL;
|
||||
typedef unsigned long DWORD;
|
||||
typedef void* HANDLE;
|
||||
|
||||
# include <kfuncs.h>
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
|
||||
# ifdef _WIN64
|
||||
typedef unsigned __int64 ulong_ptr;
|
||||
# else
|
||||
typedef unsigned long ulong_ptr;
|
||||
# endif
|
||||
typedef void* handle;
|
||||
unsigned const infinite=~0U;
|
||||
unsigned const timeout=258U;
|
||||
handle const invalid_handle_value=(handle)(-1);
|
||||
|
||||
extern "C"
|
||||
{
|
||||
struct _SECURITY_ATTRIBUTES;
|
||||
# ifdef BOOST_NO_ANSI_APIS
|
||||
__declspec(dllimport) void* __stdcall CreateMutexW(_SECURITY_ATTRIBUTES*,int,wchar_t const*);
|
||||
__declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES*,long,long,wchar_t const*);
|
||||
__declspec(dllimport) void* __stdcall CreateEventW(_SECURITY_ATTRIBUTES*,int,int,wchar_t const*);
|
||||
# else
|
||||
__declspec(dllimport) void* __stdcall CreateMutexA(_SECURITY_ATTRIBUTES*,int,char const*);
|
||||
__declspec(dllimport) void* __stdcall CreateSemaphoreA(_SECURITY_ATTRIBUTES*,long,long,char const*);
|
||||
__declspec(dllimport) void* __stdcall CreateEventA(_SECURITY_ATTRIBUTES*,int,int,char const*);
|
||||
# endif
|
||||
__declspec(dllimport) int __stdcall CloseHandle(void*);
|
||||
__declspec(dllimport) int __stdcall ReleaseMutex(void*);
|
||||
__declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void*,unsigned long);
|
||||
__declspec(dllimport) unsigned long __stdcall WaitForMultipleObjects(unsigned long nCount,void* const * lpHandles,int bWaitAll,unsigned long dwMilliseconds);
|
||||
__declspec(dllimport) int __stdcall ReleaseSemaphore(void*,long,long*);
|
||||
__declspec(dllimport) int __stdcall DuplicateHandle(void*,void*,void*,void**,unsigned long,int,unsigned long);
|
||||
__declspec(dllimport) unsigned long __stdcall SleepEx(unsigned long,int);
|
||||
__declspec(dllimport) void __stdcall Sleep(unsigned long);
|
||||
typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr);
|
||||
__declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr);
|
||||
|
||||
__declspec(dllimport) unsigned long __stdcall GetTickCount();
|
||||
|
||||
# ifndef UNDER_CE
|
||||
__declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
|
||||
__declspec(dllimport) unsigned long __stdcall GetCurrentThreadId();
|
||||
__declspec(dllimport) void* __stdcall GetCurrentThread();
|
||||
__declspec(dllimport) void* __stdcall GetCurrentProcess();
|
||||
__declspec(dllimport) int __stdcall SetEvent(void*);
|
||||
__declspec(dllimport) int __stdcall ResetEvent(void*);
|
||||
# else
|
||||
using ::GetCurrentProcessId;
|
||||
using ::GetCurrentThreadId;
|
||||
using ::GetCurrentThread;
|
||||
using ::GetCurrentProcess;
|
||||
using ::SetEvent;
|
||||
using ::ResetEvent;
|
||||
# endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
# error "Win32 functions not available"
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
enum event_type
|
||||
{
|
||||
auto_reset_event=false,
|
||||
manual_reset_event=true
|
||||
};
|
||||
|
||||
enum initial_event_state
|
||||
{
|
||||
event_initially_reset=false,
|
||||
event_initially_set=true
|
||||
};
|
||||
|
||||
inline handle create_anonymous_event(event_type type,initial_event_state state)
|
||||
{
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
handle const res=win32::CreateEventA(0,type,state,0);
|
||||
#else
|
||||
handle const res=win32::CreateEventW(0,type,state,0);
|
||||
#endif
|
||||
if(!res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
inline handle create_anonymous_semaphore(long initial_count,long max_count)
|
||||
{
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
handle const res=CreateSemaphoreA(NULL,initial_count,max_count,NULL);
|
||||
#else
|
||||
handle const res=CreateSemaphoreW(NULL,initial_count,max_count,NULL);
|
||||
#endif
|
||||
if(!res)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
inline handle duplicate_handle(handle source)
|
||||
{
|
||||
handle const current_process=GetCurrentProcess();
|
||||
long const same_access_flag=2;
|
||||
handle new_handle=0;
|
||||
bool const success=DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0;
|
||||
if(!success)
|
||||
{
|
||||
throw thread_resource_error();
|
||||
}
|
||||
return new_handle;
|
||||
}
|
||||
|
||||
inline void release_semaphore(handle semaphore,long count)
|
||||
{
|
||||
BOOST_VERIFY(ReleaseSemaphore(semaphore,count,0)!=0);
|
||||
}
|
||||
|
||||
class handle_manager
|
||||
{
|
||||
private:
|
||||
handle handle_to_manage;
|
||||
handle_manager(handle_manager&);
|
||||
handle_manager& operator=(handle_manager&);
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
if(handle_to_manage && handle_to_manage!=invalid_handle_value)
|
||||
{
|
||||
BOOST_VERIFY(CloseHandle(handle_to_manage));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
explicit handle_manager(handle handle_to_manage_):
|
||||
handle_to_manage(handle_to_manage_)
|
||||
{}
|
||||
handle_manager():
|
||||
handle_to_manage(0)
|
||||
{}
|
||||
|
||||
handle_manager& operator=(handle new_handle)
|
||||
{
|
||||
cleanup();
|
||||
handle_to_manage=new_handle;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator handle() const
|
||||
{
|
||||
return handle_to_manage;
|
||||
}
|
||||
|
||||
handle duplicate() const
|
||||
{
|
||||
return duplicate_handle(handle_to_manage);
|
||||
}
|
||||
|
||||
void swap(handle_manager& other)
|
||||
{
|
||||
std::swap(handle_to_manage,other.handle_to_manage);
|
||||
}
|
||||
|
||||
handle release()
|
||||
{
|
||||
handle const res=handle_to_manage;
|
||||
handle_to_manage=0;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool operator!() const
|
||||
{
|
||||
return !handle_to_manage;
|
||||
}
|
||||
|
||||
~handle_manager()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
103
include/boost/thread/win32/tss.hpp
Normal file
103
include/boost/thread/win32/tss.hpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#ifndef BOOST_THREAD_WIN32_TSS_HPP
|
||||
#define BOOST_THREAD_WIN32_TSS_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include "thread_heap_alloc.hpp"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct tss_cleanup_function
|
||||
{
|
||||
virtual ~tss_cleanup_function()
|
||||
{}
|
||||
|
||||
virtual void operator()(void* data)=0;
|
||||
};
|
||||
|
||||
BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing);
|
||||
BOOST_THREAD_DECL void* get_tss_data(void const* key);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class thread_specific_ptr
|
||||
{
|
||||
private:
|
||||
thread_specific_ptr(thread_specific_ptr&);
|
||||
thread_specific_ptr& operator=(thread_specific_ptr&);
|
||||
|
||||
struct delete_data:
|
||||
detail::tss_cleanup_function
|
||||
{
|
||||
void operator()(void* data)
|
||||
{
|
||||
delete static_cast<T*>(data);
|
||||
}
|
||||
};
|
||||
|
||||
struct run_custom_cleanup_function:
|
||||
detail::tss_cleanup_function
|
||||
{
|
||||
void (*cleanup_function)(T*);
|
||||
|
||||
explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)):
|
||||
cleanup_function(cleanup_function_)
|
||||
{}
|
||||
|
||||
void operator()(void* data)
|
||||
{
|
||||
cleanup_function(data);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
boost::shared_ptr<detail::tss_cleanup_function> cleanup;
|
||||
|
||||
public:
|
||||
thread_specific_ptr():
|
||||
cleanup(detail::heap_new<delete_data>(),detail::do_heap_delete<delete_data>())
|
||||
{}
|
||||
explicit thread_specific_ptr(void (*func_)(T*)):
|
||||
cleanup(detail::heap_new<run_custom_cleanup_function>(func_),detail::do_heap_delete<run_custom_cleanup_function>())
|
||||
{}
|
||||
~thread_specific_ptr()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
T* get() const
|
||||
{
|
||||
return static_cast<T*>(detail::get_tss_data(this));
|
||||
}
|
||||
T* operator->() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
T& operator*() const
|
||||
{
|
||||
return *get();
|
||||
}
|
||||
T* release()
|
||||
{
|
||||
T* const temp=get();
|
||||
detail::set_tss_data(this,0,0,false);
|
||||
return temp;
|
||||
}
|
||||
void reset(T* new_value=0)
|
||||
{
|
||||
T* const current_value=get();
|
||||
if(current_value!=new_value)
|
||||
{
|
||||
detail::set_tss_data(this,cleanup,new_value,true);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -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)
|
||||
@@ -10,6 +11,8 @@
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
@@ -37,9 +40,40 @@ struct xtime
|
||||
|
||||
xtime_sec_t sec;
|
||||
xtime_nsec_t nsec;
|
||||
|
||||
operator system_time() const
|
||||
{
|
||||
return boost::posix_time::from_time_t(0)+
|
||||
boost::posix_time::seconds(static_cast<long>(sec))+
|
||||
#ifdef BOOST_DATE_TIME_HAS_NANOSECONDS
|
||||
boost::posix_time::nanoseconds(nsec);
|
||||
#else
|
||||
boost::posix_time::microseconds((nsec+500)/1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
int BOOST_THREAD_DECL xtime_get(struct xtime* xtp, int clock_type);
|
||||
inline xtime get_xtime(boost::system_time const& abs_time)
|
||||
{
|
||||
xtime res={0};
|
||||
boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0);
|
||||
|
||||
res.sec=static_cast<xtime::xtime_sec_t>(time_since_epoch.total_seconds());
|
||||
res.nsec=static_cast<xtime::xtime_nsec_t>(time_since_epoch.fractional_seconds()*(1000000000/time_since_epoch.ticks_per_second()));
|
||||
return res;
|
||||
}
|
||||
|
||||
inline int xtime_get(struct xtime* xtp, int clock_type)
|
||||
{
|
||||
if (clock_type == TIME_UTC)
|
||||
{
|
||||
*xtp=get_xtime(get_system_time());
|
||||
return clock_type;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
|
||||
{
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright (C) 2002-2003
|
||||
// David Moore, 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/barrier.hpp>
|
||||
#include <string> // see http://article.gmane.org/gmane.comp.lib.boost.devel/106981
|
||||
|
||||
namespace boost {
|
||||
|
||||
barrier::barrier(unsigned int count)
|
||||
: m_threshold(count), m_count(count), m_generation(0)
|
||||
{
|
||||
if (count == 0)
|
||||
throw std::invalid_argument("count cannot be zero.");
|
||||
}
|
||||
|
||||
barrier::~barrier()
|
||||
{
|
||||
}
|
||||
|
||||
bool barrier::wait()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
unsigned int gen = m_generation;
|
||||
|
||||
if (--m_count == 0)
|
||||
{
|
||||
m_generation++;
|
||||
m_count = m_threshold;
|
||||
m_cond.notify_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
while (gen == m_generation)
|
||||
m_cond.wait(lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
@@ -1,672 +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/condition.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <cassert>
|
||||
#include "timeconv.inl"
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
# ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
# endif
|
||||
# include <windows.h>
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
# include <errno.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <MacErrors.h>
|
||||
# include "mac/init.hpp"
|
||||
# include "mac/safe.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace detail {
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
condition_impl::condition_impl()
|
||||
: m_gone(0), m_blocked(0), m_waiting(0)
|
||||
{
|
||||
m_gate = reinterpret_cast<void*>(CreateSemaphore(0, 1, 1, 0));
|
||||
m_queue = reinterpret_cast<void*>(
|
||||
CreateSemaphore(0, 0, (std::numeric_limits<long>::max)(), 0));
|
||||
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
|
||||
|
||||
if (!m_gate || !m_queue || !m_mutex)
|
||||
{
|
||||
int res = 0;
|
||||
if (m_gate)
|
||||
{
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
|
||||
assert(res);
|
||||
}
|
||||
if (m_queue)
|
||||
{
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
|
||||
assert(res);
|
||||
}
|
||||
if (m_mutex)
|
||||
{
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
}
|
||||
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
condition_impl::~condition_impl()
|
||||
{
|
||||
int res = 0;
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
|
||||
assert(res);
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
|
||||
assert(res);
|
||||
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
}
|
||||
|
||||
void condition_impl::notify_one()
|
||||
{
|
||||
unsigned signals = 0;
|
||||
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
return;
|
||||
}
|
||||
|
||||
++m_waiting;
|
||||
--m_blocked;
|
||||
signals = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = 1;
|
||||
--m_blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (signals)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::notify_all()
|
||||
{
|
||||
unsigned signals = 0;
|
||||
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
return;
|
||||
}
|
||||
|
||||
m_waiting += (signals = m_blocked);
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = m_blocked;
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (signals)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::enter_wait()
|
||||
{
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
++m_blocked;
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
|
||||
void condition_impl::do_wait()
|
||||
{
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
unsigned was_waiting=0;
|
||||
unsigned was_gone=0;
|
||||
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
was_waiting = m_waiting;
|
||||
was_gone = m_gone;
|
||||
if (was_waiting != 0)
|
||||
{
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
|
||||
0); // open m_gate
|
||||
assert(res);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
m_blocked -= m_gone;
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
m_gone = 0;
|
||||
}
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (was_waiting == 1)
|
||||
{
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
||||
INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
}
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
}
|
||||
|
||||
bool condition_impl::do_timed_wait(const xtime& xt)
|
||||
{
|
||||
bool ret = false;
|
||||
unsigned int res = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int milliseconds;
|
||||
to_duration(xt, milliseconds);
|
||||
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
||||
milliseconds);
|
||||
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||
ret = (res == WAIT_OBJECT_0);
|
||||
|
||||
if (res == WAIT_TIMEOUT)
|
||||
{
|
||||
xtime cur;
|
||||
xtime_get(&cur, TIME_UTC);
|
||||
if (xtime_cmp(xt, cur) > 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned was_waiting=0;
|
||||
unsigned was_gone=0;
|
||||
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
was_waiting = m_waiting;
|
||||
was_gone = m_gone;
|
||||
if (was_waiting != 0)
|
||||
{
|
||||
if (!ret) // timeout
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
--m_blocked;
|
||||
else
|
||||
++m_gone; // count spurious wakeups
|
||||
}
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
|
||||
0); // open m_gate
|
||||
assert(res);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
m_blocked -= m_gone;
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
m_gone = 0;
|
||||
}
|
||||
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
|
||||
assert(res);
|
||||
|
||||
if (was_waiting == 1)
|
||||
{
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
|
||||
INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
}
|
||||
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
|
||||
assert(res);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
condition_impl::condition_impl()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_init(&m_condition, 0);
|
||||
if (res != 0)
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
condition_impl::~condition_impl()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_destroy(&m_condition);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void condition_impl::notify_one()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_signal(&m_condition);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void condition_impl::notify_all()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_broadcast(&m_condition);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void condition_impl::do_wait(pthread_mutex_t* pmutex)
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_cond_wait(&m_condition, pmutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
bool condition_impl::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
|
||||
{
|
||||
timespec ts;
|
||||
to_timespec(xt, ts);
|
||||
|
||||
int res = 0;
|
||||
res = pthread_cond_timedwait(&m_condition, pmutex, &ts);
|
||||
assert(res == 0 || res == ETIMEDOUT);
|
||||
|
||||
return res != ETIMEDOUT;
|
||||
}
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
|
||||
using threads::mac::detail::safe_enter_critical_region;
|
||||
using threads::mac::detail::safe_wait_on_semaphore;
|
||||
|
||||
condition_impl::condition_impl()
|
||||
: m_gone(0), m_blocked(0), m_waiting(0)
|
||||
{
|
||||
threads::mac::detail::thread_init();
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
|
||||
lStatus = MPCreateSemaphore(1, 1, &m_gate);
|
||||
if(lStatus == noErr)
|
||||
lStatus = MPCreateSemaphore(ULONG_MAX, 0, &m_queue);
|
||||
|
||||
if(lStatus != noErr || !m_gate || !m_queue)
|
||||
{
|
||||
if (m_gate)
|
||||
{
|
||||
lStatus = MPDeleteSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
if (m_queue)
|
||||
{
|
||||
lStatus = MPDeleteSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
condition_impl::~condition_impl()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPDeleteSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
lStatus = MPDeleteSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void condition_impl::notify_one()
|
||||
{
|
||||
unsigned signals = 0;
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
return;
|
||||
}
|
||||
|
||||
++m_waiting;
|
||||
--m_blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = 1;
|
||||
--m_blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
while (signals)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
--signals;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::notify_all()
|
||||
{
|
||||
unsigned signals = 0;
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (m_waiting != 0) // the m_gate is already closed
|
||||
{
|
||||
if (m_blocked == 0)
|
||||
{
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
return;
|
||||
}
|
||||
|
||||
m_waiting += (signals = m_blocked);
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
if (m_blocked > m_gone)
|
||||
{
|
||||
if (m_gone != 0)
|
||||
{
|
||||
m_blocked -= m_gone;
|
||||
m_gone = 0;
|
||||
}
|
||||
signals = m_waiting = m_blocked;
|
||||
m_blocked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
while (signals)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_queue);
|
||||
assert(lStatus == noErr);
|
||||
--signals;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void condition_impl::enter_wait()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
++m_blocked;
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void condition_impl::do_wait()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
unsigned was_waiting=0;
|
||||
unsigned was_gone=0;
|
||||
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = m_waiting;
|
||||
was_gone = m_gone;
|
||||
if (was_waiting != 0)
|
||||
{
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate); // open m_gate
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
m_blocked -= m_gone;
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
m_gone = 0;
|
||||
}
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (was_waiting == 1)
|
||||
{
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
}
|
||||
|
||||
bool condition_impl::do_timed_wait(const xtime& xt)
|
||||
{
|
||||
int milliseconds;
|
||||
to_duration(xt, milliseconds);
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_wait_on_semaphore(m_queue, milliseconds);
|
||||
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||
|
||||
bool ret = (lStatus == noErr);
|
||||
|
||||
unsigned was_waiting=0;
|
||||
unsigned was_gone=0;
|
||||
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = m_waiting;
|
||||
was_gone = m_gone;
|
||||
if (was_waiting != 0)
|
||||
{
|
||||
if (!ret) // timeout
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
--m_blocked;
|
||||
else
|
||||
++m_gone; // count spurious wakeups
|
||||
}
|
||||
if (--m_waiting == 0)
|
||||
{
|
||||
if (m_blocked != 0)
|
||||
{
|
||||
lStatus = MPSignalSemaphore(m_gate); // open m_gate
|
||||
assert(lStatus == noErr);
|
||||
was_waiting = 0;
|
||||
}
|
||||
else if (m_gone != 0)
|
||||
m_gone = 0;
|
||||
}
|
||||
}
|
||||
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
|
||||
{
|
||||
// timeout occured, normalize the m_gone count
|
||||
// this may occur if many calls to wait with a timeout are made and
|
||||
// no call to notify_* is made
|
||||
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
m_blocked -= m_gone;
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
m_gone = 0;
|
||||
}
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
if (was_waiting == 1)
|
||||
{
|
||||
for (/**/ ; was_gone; --was_gone)
|
||||
{
|
||||
// better now than spurious later
|
||||
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
lStatus = MPSignalSemaphore(m_gate);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
|
||||
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
|
||||
@@ -1,8 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#define TARGET_CARBON 1
|
||||
@@ -1,66 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "delivery_man.hpp"
|
||||
|
||||
#include "os.hpp"
|
||||
#include "execution_context.hpp"
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
delivery_man::delivery_man():
|
||||
m_pPackage(NULL),
|
||||
m_pSemaphore(kInvalidID),
|
||||
m_bPackageWaiting(false)
|
||||
{
|
||||
assert(at_st());
|
||||
|
||||
OSStatus lStatus = MPCreateSemaphore(1UL, 0UL, &m_pSemaphore);
|
||||
// TODO - throw on error here
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
delivery_man::~delivery_man()
|
||||
{
|
||||
assert(m_bPackageWaiting == false);
|
||||
|
||||
OSStatus lStatus = MPDeleteSemaphore(m_pSemaphore);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
|
||||
void delivery_man::accept_deliveries()
|
||||
{
|
||||
if(m_bPackageWaiting)
|
||||
{
|
||||
assert(m_pPackage != NULL);
|
||||
m_pPackage->accept();
|
||||
m_pPackage = NULL;
|
||||
m_bPackageWaiting = false;
|
||||
|
||||
// signal to the thread making the call that we're done
|
||||
OSStatus lStatus = MPSignalSemaphore(m_pSemaphore);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
@@ -1,84 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_DELIVERY_MAN_MJM012402_HPP
|
||||
#define BOOST_DELIVERY_MAN_MJM012402_HPP
|
||||
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include "package.hpp"
|
||||
|
||||
#include <Multiprocessing.h>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
// class delivery_man is intended to move boost::function objects from MP tasks to
|
||||
// other execution contexts (such as deferred task time or system task time).
|
||||
|
||||
class delivery_man: private noncopyable
|
||||
{
|
||||
public:
|
||||
delivery_man();
|
||||
~delivery_man();
|
||||
|
||||
public:
|
||||
template<class R>
|
||||
R deliver(function<R> &rFunctor);
|
||||
|
||||
void accept_deliveries();
|
||||
|
||||
private:
|
||||
base_package *m_pPackage;
|
||||
mutex m_oMutex;
|
||||
MPSemaphoreID m_pSemaphore;
|
||||
bool m_bPackageWaiting;
|
||||
};
|
||||
|
||||
|
||||
template<class R>
|
||||
R delivery_man::deliver(function<R> &rFunctor)
|
||||
{
|
||||
assert(at_mp());
|
||||
|
||||
// lock our mutex
|
||||
mutex::scoped_lock oLock(m_oMutex);
|
||||
|
||||
// create a package and save it
|
||||
package<R> oPackage(rFunctor);
|
||||
m_pPackage = &oPackage;
|
||||
m_bPackageWaiting = true;
|
||||
|
||||
// wait on the semaphore
|
||||
OSStatus lStatus = MPWaitOnSemaphore(m_pSemaphore, kDurationForever);
|
||||
assert(lStatus == noErr);
|
||||
|
||||
return(oPackage.return_value());
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_DELIVERY_MAN_MJM012402_HPP
|
||||
@@ -1,93 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "dt_scheduler.hpp"
|
||||
|
||||
#include "ot_context.hpp"
|
||||
|
||||
|
||||
#include <boost/thread/detail/singleton.hpp>
|
||||
|
||||
#include <OpenTransportProtocol.h>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
const OTTimeout k_ulTimerTaskDelay = 1UL;
|
||||
|
||||
|
||||
dt_scheduler::dt_scheduler():
|
||||
m_bReschedule(false),
|
||||
m_uppTask(NULL),
|
||||
m_lTask(0UL)
|
||||
{
|
||||
using ::boost::detail::thread::singleton;
|
||||
|
||||
ot_context &rContext(singleton<ot_context>::instance());
|
||||
|
||||
m_uppTask = NewOTProcessUPP(task_entry);
|
||||
m_lTask = OTCreateTimerTaskInContext(m_uppTask, this, rContext.get_context());
|
||||
}
|
||||
|
||||
dt_scheduler::~dt_scheduler()
|
||||
{
|
||||
OTDestroyTimerTask(m_lTask);
|
||||
m_lTask = 0UL;
|
||||
DisposeOTProcessUPP(m_uppTask);
|
||||
m_uppTask = NULL;
|
||||
}
|
||||
|
||||
|
||||
void dt_scheduler::start_polling()
|
||||
{
|
||||
m_bReschedule = true;
|
||||
schedule_task();
|
||||
}
|
||||
|
||||
void dt_scheduler::stop_polling()
|
||||
{
|
||||
m_bReschedule = false;
|
||||
}
|
||||
|
||||
|
||||
void dt_scheduler::schedule_task()
|
||||
{
|
||||
if(m_bReschedule)
|
||||
{
|
||||
OTScheduleTimerTask(m_lTask, k_ulTimerTaskDelay);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*static*/ pascal void dt_scheduler::task_entry(void *pRefCon)
|
||||
{
|
||||
dt_scheduler *pThis = reinterpret_cast<dt_scheduler *>(pRefCon);
|
||||
assert(pThis != NULL);
|
||||
pThis->task();
|
||||
}
|
||||
|
||||
void dt_scheduler::task()
|
||||
{
|
||||
periodic_function();
|
||||
schedule_task();
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
@@ -1,63 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_DT_SCHEDULER_MJM012402_HPP
|
||||
#define BOOST_DT_SCHEDULER_MJM012402_HPP
|
||||
|
||||
|
||||
#include "periodical.hpp"
|
||||
|
||||
#include <OpenTransport.h>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
// class dt_scheduler calls its pure-virtual periodic_function method periodically at
|
||||
// deferred task time. This is generally 1kHz under Mac OS 9.
|
||||
|
||||
class dt_scheduler
|
||||
{
|
||||
public:
|
||||
dt_scheduler();
|
||||
virtual ~dt_scheduler();
|
||||
|
||||
protected:
|
||||
void start_polling();
|
||||
void stop_polling();
|
||||
|
||||
private:
|
||||
virtual void periodic_function() = 0;
|
||||
|
||||
private:
|
||||
void schedule_task();
|
||||
static pascal void task_entry(void *pRefCon);
|
||||
void task();
|
||||
|
||||
private:
|
||||
bool m_bReschedule;
|
||||
OTProcessUPP m_uppTask;
|
||||
long m_lTask;
|
||||
};
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_DT_SCHEDULER_MJM012402_HPP
|
||||
@@ -1,60 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include <Debugging.h>
|
||||
#include <Multiprocessing.h>
|
||||
|
||||
#include "execution_context.hpp"
|
||||
#include "init.hpp"
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
|
||||
execution_context_t execution_context()
|
||||
{
|
||||
// make sure that MP services are available the first time through
|
||||
static bool bIgnored = detail::thread_init();
|
||||
|
||||
// first check if we're an MP task
|
||||
if(MPTaskIsPreemptive(kInvalidID))
|
||||
{
|
||||
return(k_eExecutionContextMPTask);
|
||||
}
|
||||
|
||||
#if TARGET_CARBON
|
||||
// Carbon has TaskLevel
|
||||
UInt32 ulLevel = TaskLevel();
|
||||
|
||||
if(ulLevel == 0UL)
|
||||
{
|
||||
return(k_eExecutionContextSystemTask);
|
||||
}
|
||||
|
||||
if(ulLevel & kInDeferredTaskMask)
|
||||
{
|
||||
return(k_eExecutionContextDeferredTask);
|
||||
}
|
||||
|
||||
return(k_eExecutionContextOther);
|
||||
#else
|
||||
// this can be implemented using TaskLevel if you don't mind linking against
|
||||
// DebugLib (and therefore breaking Mac OS 8.6 support), or CurrentExecutionLevel.
|
||||
# error execution_context unimplimented
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
@@ -1,47 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_EXECUTION_CONTEXT_MJM012402_HPP
|
||||
#define BOOST_EXECUTION_CONTEXT_MJM012402_HPP
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
|
||||
// utility functions for figuring out what context your code is executing in.
|
||||
// Bear in mind that at_mp and in_blue are the only functions guarenteed by
|
||||
// Apple to work. There is simply no way of being sure that you will not get
|
||||
// false readings about task level at interrupt time in blue.
|
||||
|
||||
typedef enum {
|
||||
k_eExecutionContextSystemTask,
|
||||
k_eExecutionContextDeferredTask,
|
||||
k_eExecutionContextMPTask,
|
||||
k_eExecutionContextOther
|
||||
} execution_context_t;
|
||||
|
||||
execution_context_t execution_context();
|
||||
|
||||
inline bool at_st()
|
||||
{ return(execution_context() == k_eExecutionContextSystemTask); }
|
||||
|
||||
inline bool at_mp()
|
||||
{ return(execution_context() == k_eExecutionContextMPTask); }
|
||||
inline bool in_blue()
|
||||
{ return(!at_mp()); }
|
||||
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_EXECUTION_CONTEXT_MJM012402_HPP
|
||||
@@ -1,58 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "init.hpp"
|
||||
|
||||
#include "remote_call_manager.hpp"
|
||||
|
||||
|
||||
#include <boost/thread/detail/singleton.hpp>
|
||||
|
||||
#include <Multiprocessing.h>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
// force these to get called by the end of static initialization time.
|
||||
static bool g_bInitialized = (thread_init() && create_singletons());
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool thread_init()
|
||||
{
|
||||
static bool bResult = MPLibraryIsLoaded();
|
||||
|
||||
return(bResult);
|
||||
}
|
||||
|
||||
bool create_singletons()
|
||||
{
|
||||
using ::boost::detail::thread::singleton;
|
||||
|
||||
singleton<remote_call_manager>::instance();
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
@@ -1,34 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_INIT_MJM012402_HPP
|
||||
#define BOOST_INIT_MJM012402_HPP
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
bool thread_init();
|
||||
bool create_singletons();
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_INIT_MJM012402_HPP
|
||||
@@ -1,24 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
#include <MacTypes.h>
|
||||
|
||||
#include "remote_calls.hpp"
|
||||
|
||||
// this function will be called when an assertion fails. We redirect the assertion
|
||||
// to DebugStr (MacsBug under Mac OS 1.x-9.x, Console under Mac OS X).
|
||||
void __assertion_failed(char const *pszAssertion, char const *pszFile, int nLine)
|
||||
{
|
||||
using std::snprintf;
|
||||
unsigned char strlDebug[sizeof(Str255) + 1];
|
||||
char *pszDebug = reinterpret_cast<char *>(&strlDebug[1]);
|
||||
strlDebug[0] = snprintf(pszDebug, sizeof(Str255), "assertion failed: \"%s\", %s, line %d", pszAssertion, pszFile, nLine);
|
||||
boost::threads::mac::dt_remote_call(DebugStr, static_cast<ConstStringPtr>(strlDebug));
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
//
|
||||
// includes
|
||||
//
|
||||
|
||||
#include <abort_exit.h>
|
||||
#include <console.h>
|
||||
#include <console_io.h>
|
||||
#include <misc_io.h>
|
||||
#include <SIOUX.h>
|
||||
|
||||
#include "remote_calls.hpp"
|
||||
|
||||
|
||||
//
|
||||
// using declarations
|
||||
//
|
||||
|
||||
using std::__file_handle;
|
||||
using std::__idle_proc;
|
||||
using std::__io_error;
|
||||
using std::__no_io_error;
|
||||
using std::size_t;
|
||||
|
||||
using boost::threads::mac::st_remote_call;
|
||||
|
||||
|
||||
//
|
||||
// prototypes
|
||||
//
|
||||
|
||||
static bool check_console();
|
||||
static int do_read_console(__file_handle ulHandle, unsigned char *pBuffer, size_t *pCount, __idle_proc pfnIdleProc);
|
||||
static int do_write_console(__file_handle ulHandle, unsigned char *pBuffer, size_t *pCount, __idle_proc pfnIdleProc);
|
||||
|
||||
|
||||
//
|
||||
// MSL function replacements
|
||||
//
|
||||
|
||||
// these two functions are called by cin and cout, respectively, as well as by (all?)
|
||||
// other functions in MSL that do console I/O. All that they do is as the remote
|
||||
// call manager to ensure that their guts are called at system task time.
|
||||
int __read_console(__file_handle handle, unsigned char * buffer, size_t * count, __idle_proc idle_proc)
|
||||
{
|
||||
return(st_remote_call(do_read_console, handle, buffer, count, idle_proc));
|
||||
}
|
||||
|
||||
int __write_console(__file_handle handle, unsigned char * buffer, size_t * count, __idle_proc idle_proc)
|
||||
{
|
||||
return(st_remote_call(do_write_console, handle, buffer, count, idle_proc));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// implementations
|
||||
//
|
||||
|
||||
static bool check_console()
|
||||
{
|
||||
static bool s_bHaveConsole(false);
|
||||
static bool s_bWontHaveConsole(false);
|
||||
|
||||
if(s_bHaveConsole)
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
|
||||
if(s_bWontHaveConsole == false)
|
||||
{
|
||||
__stdio_atexit();
|
||||
|
||||
if(InstallConsole(0) != 0)
|
||||
{
|
||||
s_bWontHaveConsole = true;
|
||||
return(false);
|
||||
}
|
||||
__console_exit = RemoveConsole;
|
||||
s_bHaveConsole = true;
|
||||
return(true);
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
int do_read_console(__file_handle /*ulHandle*/, unsigned char *pBuffer, size_t *pCount, __idle_proc /*pfnIdleProc*/)
|
||||
{
|
||||
assert(pCount != NULL);
|
||||
assert(pBuffer != NULL || *pCount == 0UL);
|
||||
|
||||
if(check_console() == false)
|
||||
{
|
||||
return(__io_error);
|
||||
}
|
||||
std::fflush(stdout);
|
||||
long lCount = ReadCharsFromConsole(reinterpret_cast<char *>(pBuffer), static_cast<long>(*pCount));
|
||||
*pCount = static_cast<size_t>(lCount);
|
||||
if(lCount == -1L)
|
||||
{
|
||||
return(__io_error);
|
||||
}
|
||||
|
||||
return(__no_io_error);
|
||||
}
|
||||
|
||||
int do_write_console(__file_handle /*ulHandle*/, unsigned char *pBuffer, size_t *pCount, __idle_proc /*pfnIdleProc*/)
|
||||
{
|
||||
if(check_console() == false)
|
||||
{
|
||||
return(__io_error);
|
||||
}
|
||||
|
||||
long lCount = WriteCharsToConsole(reinterpret_cast<char *>(pBuffer), static_cast<long>(*pCount));
|
||||
*pCount = static_cast<size_t>(lCount);
|
||||
if(lCount == -1L)
|
||||
{
|
||||
return(__io_error);
|
||||
}
|
||||
|
||||
return(__no_io_error);
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
//
|
||||
// includes
|
||||
//
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <Multiprocessing.h>
|
||||
|
||||
|
||||
//
|
||||
// using declarations
|
||||
//
|
||||
|
||||
using std::size_t;
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
//
|
||||
// prototypes
|
||||
//
|
||||
|
||||
void *malloc(size_t ulSize);
|
||||
void free(void *pBlock);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// MSL function replacements
|
||||
//
|
||||
|
||||
// all allocation/deallocation currently goes through MPAllocateAligned/MPFree. This
|
||||
// solution is sub-optimal at best, but will have to do for now.
|
||||
void *malloc(size_t ulSize)
|
||||
{
|
||||
static bool bIgnored = MPLibraryIsLoaded();
|
||||
return(MPAllocateAligned(ulSize, kMPAllocateDefaultAligned, 0UL));
|
||||
}
|
||||
|
||||
void free(void *pBlock)
|
||||
{
|
||||
if(pBlock == NULL) return;
|
||||
MPFree(pBlock);
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
//
|
||||
// includes
|
||||
//
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <Multiprocessing.h>
|
||||
|
||||
|
||||
//
|
||||
// using declarations
|
||||
//
|
||||
|
||||
using std::size_t;
|
||||
using std::bad_alloc;
|
||||
using std::nothrow_t;
|
||||
using std::nothrow;
|
||||
|
||||
|
||||
//
|
||||
// local utility functions
|
||||
//
|
||||
|
||||
// all allocation/deallocation currently goes through MPAllocateAligned/MPFree. This
|
||||
// solution is sub-optimal at best, but will have to do for now.
|
||||
inline static void *allocate(size_t ulSize, const nothrow_t &)
|
||||
{
|
||||
static bool bIgnored = MPLibraryIsLoaded();
|
||||
return(MPAllocateAligned(ulSize, kMPAllocateDefaultAligned, 0UL));
|
||||
}
|
||||
|
||||
inline static void *allocate(size_t ulSize)
|
||||
{
|
||||
void *pBlock = allocate(ulSize, nothrow);
|
||||
if(pBlock == NULL)
|
||||
throw(bad_alloc());
|
||||
return(pBlock);
|
||||
}
|
||||
|
||||
inline static void deallocate(void *pBlock)
|
||||
{
|
||||
if(pBlock == NULL) return;
|
||||
MPFree(pBlock);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// global operators
|
||||
//
|
||||
|
||||
void *operator new(size_t ulSize)
|
||||
{
|
||||
return(allocate(ulSize));
|
||||
}
|
||||
|
||||
void *operator new[](size_t ulSize)
|
||||
{
|
||||
return(allocate(ulSize));
|
||||
}
|
||||
|
||||
|
||||
void *operator new(size_t ulSize, const nothrow_t &rNoThrow)
|
||||
{
|
||||
return(allocate(ulSize, rNoThrow));
|
||||
}
|
||||
|
||||
void *operator new[](size_t ulSize, const nothrow_t &rNoThrow)
|
||||
{
|
||||
return(allocate(ulSize, rNoThrow));
|
||||
}
|
||||
|
||||
|
||||
void operator delete(void *pBlock)
|
||||
{
|
||||
deallocate(pBlock);
|
||||
}
|
||||
|
||||
void operator delete[](void *pBlock)
|
||||
{
|
||||
deallocate(pBlock);
|
||||
}
|
||||
|
||||
|
||||
void operator delete(void *pBlock, const nothrow_t &)
|
||||
{
|
||||
deallocate(pBlock);
|
||||
}
|
||||
|
||||
void operator delete[](void *pBlock, const nothrow_t &)
|
||||
{
|
||||
deallocate(pBlock);
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include <cassert>
|
||||
// we include timesize.mac.h to get whether or not __TIMESIZE_DOUBLE__ is
|
||||
// defined. This is not safe, given that __TIMESIZE_DOUBLE__ affects MSL
|
||||
// at MSL's compile time, not ours, so be forgiving if you have changed it
|
||||
// since you have built MSL.
|
||||
#include <timesize.mac.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <boost/thread/detail/force_cast.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
|
||||
#include "execution_context.hpp"
|
||||
|
||||
#include <DriverServices.h>
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
clock_t __get_clock();
|
||||
time_t __get_time();
|
||||
int __to_gm_time(time_t *pTime);
|
||||
int __is_dst();
|
||||
}
|
||||
|
||||
|
||||
static inline uint64_t get_nanoseconds()
|
||||
{
|
||||
using boost::detail::thread::force_cast;
|
||||
return(force_cast<uint64_t>(AbsoluteToNanoseconds(UpTime())));
|
||||
}
|
||||
|
||||
|
||||
#ifdef __TIMESIZE_DOUBLE__
|
||||
|
||||
// return number of microseconds since startup as a double
|
||||
clock_t __get_clock()
|
||||
{
|
||||
static const double k_dNanosecondsPerMicrosecond(1000.0);
|
||||
|
||||
return(get_nanoseconds() / k_dNanosecondsPerMicrosecond);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// return number of ticks (60th of a second) since startup as a long
|
||||
clock_t __get_clock()
|
||||
{
|
||||
static const uint64_t k_ullTicksPerSecond(60ULL);
|
||||
static const uint64_t k_ullNanosecondsPerSecond(1000ULL * 1000ULL * 1000ULL);
|
||||
static const uint64_t k_ullNanosecondsPerTick(k_ullNanosecondsPerSecond / k_ullTicksPerSecond);
|
||||
|
||||
return(get_nanoseconds() / k_ullNanosecondsPerTick);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// return number of seconds elapsed since Jan 1, 1970
|
||||
time_t __get_time()
|
||||
{
|
||||
boost::xtime sTime;
|
||||
int nType = boost::xtime_get(&sTime, boost::TIME_UTC);
|
||||
assert(nType == boost::TIME_UTC);
|
||||
return(static_cast<time_t>(sTime.sec));
|
||||
}
|
||||
|
||||
|
||||
static inline MachineLocation &read_location()
|
||||
{
|
||||
static MachineLocation s_sLocation;
|
||||
assert(boost::threads::mac::at_st());
|
||||
ReadLocation(&s_sLocation);
|
||||
return(s_sLocation);
|
||||
}
|
||||
|
||||
static inline MachineLocation &get_location()
|
||||
{
|
||||
static MachineLocation &s_rLocation(read_location());
|
||||
return(s_rLocation);
|
||||
}
|
||||
|
||||
|
||||
// force the machine location to be cached at static initlialization
|
||||
static MachineLocation &g_rIgnored(get_location());
|
||||
|
||||
static inline long calculate_delta()
|
||||
{
|
||||
MachineLocation &rLocation(get_location());
|
||||
|
||||
// gmtDelta is a 24-bit, signed integer. We need to strip out the lower 24 bits,
|
||||
// then sign-extend what we have.
|
||||
long lDelta = rLocation.u.gmtDelta & 0x00ffffffL;
|
||||
if((lDelta & 0x00800000L) != 0L)
|
||||
{
|
||||
lDelta |= 0xFF000000;
|
||||
}
|
||||
return(lDelta);
|
||||
}
|
||||
|
||||
static inline bool check_if_location_is_broken()
|
||||
{
|
||||
MachineLocation &rLocation(get_location());
|
||||
if(rLocation.latitude == 0 && rLocation.longitude == 0 && rLocation.u.gmtDelta == 0)
|
||||
return(true);
|
||||
return(false);
|
||||
}
|
||||
|
||||
static inline bool location_is_broken()
|
||||
{
|
||||
static bool s_bLocationIsBroken(check_if_location_is_broken());
|
||||
return(s_bLocationIsBroken);
|
||||
}
|
||||
|
||||
|
||||
// translate time to GMT
|
||||
int __to_gm_time(time_t *pTime)
|
||||
{
|
||||
if(location_is_broken())
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
static long s_lDelta(calculate_delta());
|
||||
*pTime -= s_lDelta;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static inline bool is_daylight_savings_time()
|
||||
{
|
||||
MachineLocation &rLocation(get_location());
|
||||
return(rLocation.u.dlsDelta != 0);
|
||||
}
|
||||
|
||||
// check if we're in daylight savings time
|
||||
int __is_dst()
|
||||
{
|
||||
if(location_is_broken())
|
||||
{
|
||||
return(-1);
|
||||
}
|
||||
static bool bIsDaylightSavingsTime(is_daylight_savings_time());
|
||||
return(static_cast<int>(bIsDaylightSavingsTime));
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "os.hpp"
|
||||
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <Gestalt.h>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace os {
|
||||
|
||||
|
||||
// read the OS version from Gestalt
|
||||
static inline long get_version()
|
||||
{
|
||||
long lVersion;
|
||||
OSErr nErr = Gestalt(gestaltSystemVersion, &lVersion);
|
||||
assert(nErr == noErr);
|
||||
return(lVersion);
|
||||
}
|
||||
|
||||
|
||||
// check if we're running under Mac OS X and cache that information
|
||||
bool x()
|
||||
{
|
||||
static bool bX = (version() >= 0x1000);
|
||||
return(bX);
|
||||
}
|
||||
|
||||
|
||||
// read the OS version and cache it
|
||||
long version()
|
||||
{
|
||||
static long lVersion = get_version();
|
||||
return(lVersion);
|
||||
}
|
||||
|
||||
|
||||
} // namespace os
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
@@ -1,37 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_OS_MJM012402_HPP
|
||||
#define BOOST_OS_MJM012402_HPP
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace os {
|
||||
|
||||
|
||||
// functions to determine the OS environment. With namespaces, you get a cute call:
|
||||
// mac::os::x
|
||||
|
||||
bool x();
|
||||
long version();
|
||||
|
||||
|
||||
} // namespace os
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_OS_MJM012402_HPP
|
||||
@@ -1,46 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "ot_context.hpp"
|
||||
|
||||
#include "execution_context.hpp"
|
||||
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
ot_context::ot_context()
|
||||
{
|
||||
assert(at_st());
|
||||
|
||||
OSStatus lStatus = InitOpenTransportInContext(0UL, &m_pContext);
|
||||
// TODO - throw on error
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
ot_context::~ot_context()
|
||||
{
|
||||
CloseOpenTransportInContext(m_pContext);
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
@@ -1,58 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_OT_CONTEXT_MJM012402_HPP
|
||||
#define BOOST_OT_CONTEXT_MJM012402_HPP
|
||||
|
||||
|
||||
#include <OpenTransport.h>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
// class ot_context is intended to be used only as a singleton. All that this class
|
||||
// does is ask OpenTransport to create him an OTClientContextPtr, and then doles
|
||||
// this out to anyone who wants it. ot_context should only be instantiated at
|
||||
// system task time.
|
||||
|
||||
class ot_context: private noncopyable
|
||||
{
|
||||
protected:
|
||||
ot_context();
|
||||
~ot_context();
|
||||
|
||||
public:
|
||||
OTClientContextPtr get_context();
|
||||
|
||||
private:
|
||||
OTClientContextPtr m_pContext;
|
||||
};
|
||||
|
||||
|
||||
inline OTClientContextPtr ot_context::get_context()
|
||||
{ return(m_pContext); }
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_OT_CONTEXT_MJM012402_HPP
|
||||
@@ -1,76 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_PACKAGE_MJM012402_HPP
|
||||
#define BOOST_PACKAGE_MJM012402_HPP
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
class base_package: private noncopyable
|
||||
{
|
||||
public:
|
||||
virtual void accept() = 0;
|
||||
};
|
||||
|
||||
template<class R>
|
||||
class package: public base_package
|
||||
{
|
||||
public:
|
||||
inline package(function<R> &rFunctor):
|
||||
m_rFunctor(rFunctor)
|
||||
{ /* no-op */ }
|
||||
inline ~package()
|
||||
{ /* no-op */ }
|
||||
|
||||
virtual void accept()
|
||||
{ m_oR = m_rFunctor(); }
|
||||
inline R return_value()
|
||||
{ return(m_oR); }
|
||||
|
||||
private:
|
||||
function<R> &m_rFunctor;
|
||||
R m_oR;
|
||||
};
|
||||
|
||||
template<>
|
||||
class package<void>: public base_package
|
||||
{
|
||||
public:
|
||||
inline package(function<void> &rFunctor):
|
||||
m_rFunctor(rFunctor)
|
||||
{ /* no-op */ }
|
||||
inline ~package()
|
||||
{ /* no-op */ }
|
||||
|
||||
virtual void accept()
|
||||
{ m_rFunctor(); }
|
||||
inline void return_value()
|
||||
{ return; }
|
||||
|
||||
private:
|
||||
function<void> &m_rFunctor;
|
||||
};
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_PACKAGE_MJM012402_HPP
|
||||
@@ -1,97 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_PERIODICAL_MJM012402_HPP
|
||||
#define BOOST_PERIODICAL_MJM012402_HPP
|
||||
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
// class periodical inherits from its template parameter, which should follow the
|
||||
// pattern set by classes dt_scheduler and st_scheduler. periodical knows how to
|
||||
// call a boost::function, where the xx_scheduler classes only know to to call a
|
||||
// member periodically.
|
||||
|
||||
template<class Scheduler>
|
||||
class periodical: private noncopyable, private Scheduler
|
||||
{
|
||||
public:
|
||||
periodical(function<void> &rFunction);
|
||||
~periodical();
|
||||
|
||||
public:
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
protected:
|
||||
virtual void periodic_function();
|
||||
|
||||
private:
|
||||
function<void> m_oFunction;
|
||||
};
|
||||
|
||||
|
||||
template<class Scheduler>
|
||||
periodical<Scheduler>::periodical(function<void> &rFunction):
|
||||
m_oFunction(rFunction)
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
template<class Scheduler>
|
||||
periodical<Scheduler>::~periodical()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
template<class Scheduler>
|
||||
void periodical<Scheduler>::start()
|
||||
{
|
||||
start_polling();
|
||||
}
|
||||
|
||||
template<class Scheduler>
|
||||
void periodical<Scheduler>::stop()
|
||||
{
|
||||
stop_polling();
|
||||
}
|
||||
|
||||
|
||||
template<class Scheduler>
|
||||
inline void periodical<Scheduler>::periodic_function()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_oFunction();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_PERIODICAL_MJM012402_HPP
|
||||
@@ -1,9 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#define NDEBUG
|
||||
#define TARGET_CARBON 1
|
||||
@@ -1,48 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "remote_call_manager.hpp"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
using detail::delivery_man;
|
||||
|
||||
|
||||
remote_call_manager::remote_call_manager():
|
||||
m_oDTDeliveryMan(),
|
||||
m_oSTDeliveryMan(),
|
||||
m_oDTFunction(bind(&delivery_man::accept_deliveries, &m_oDTDeliveryMan)),
|
||||
m_oSTFunction(bind(&delivery_man::accept_deliveries, &m_oSTDeliveryMan)),
|
||||
m_oDTPeriodical(m_oDTFunction),
|
||||
m_oSTPeriodical(m_oSTFunction)
|
||||
{
|
||||
m_oDTPeriodical.start();
|
||||
m_oSTPeriodical.start();
|
||||
}
|
||||
|
||||
remote_call_manager::~remote_call_manager()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
@@ -1,102 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_REMOTE_CALL_MANAGER_MJM012402_HPP
|
||||
#define BOOST_REMOTE_CALL_MANAGER_MJM012402_HPP
|
||||
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
#include "delivery_man.hpp"
|
||||
#include "dt_scheduler.hpp"
|
||||
#include "periodical.hpp"
|
||||
#include "execution_context.hpp"
|
||||
#include "st_scheduler.hpp"
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
// class remote_call_manager is used by the remote call functions (dt_remote_call and
|
||||
// st_remote_call) to execute functions in non-MP contexts.
|
||||
|
||||
class remote_call_manager: private noncopyable
|
||||
{
|
||||
protected:
|
||||
remote_call_manager();
|
||||
~remote_call_manager();
|
||||
|
||||
public:
|
||||
template<class R>
|
||||
R execute_at_dt(function<R> &rFunctor);
|
||||
template<class R>
|
||||
R execute_at_st(function<R> &rFunctor);
|
||||
|
||||
private:
|
||||
template<class R>
|
||||
static R execute_now(function<R> &rFunctor);
|
||||
|
||||
private:
|
||||
delivery_man m_oDTDeliveryMan;
|
||||
delivery_man m_oSTDeliveryMan;
|
||||
function<void> m_oDTFunction;
|
||||
function<void> m_oSTFunction;
|
||||
periodical<dt_scheduler> m_oDTPeriodical;
|
||||
periodical<st_scheduler> m_oSTPeriodical;
|
||||
};
|
||||
|
||||
|
||||
template<class R>
|
||||
/*static*/ inline R remote_call_manager::execute_now(function<R> &rFunctor)
|
||||
{
|
||||
return(rFunctor());
|
||||
}
|
||||
template<>
|
||||
/*static*/ inline void remote_call_manager::execute_now<void>(function<void> &rFunctor)
|
||||
{
|
||||
rFunctor();
|
||||
}
|
||||
|
||||
|
||||
template<class R>
|
||||
inline R remote_call_manager::execute_at_dt(function<R> &rFunctor)
|
||||
{
|
||||
if(at_mp())
|
||||
{
|
||||
return(m_oDTDeliveryMan.deliver(rFunctor));
|
||||
}
|
||||
return(execute_now(rFunctor));
|
||||
}
|
||||
|
||||
template<class R>
|
||||
inline R remote_call_manager::execute_at_st(function<R> &rFunctor)
|
||||
{
|
||||
if(at_mp())
|
||||
{
|
||||
return(m_oSTDeliveryMan.deliver(rFunctor));
|
||||
}
|
||||
assert(at_st());
|
||||
return(execute_now(rFunctor));
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_REMOTE_CALL_MANAGER_MJM012402_HPP
|
||||
@@ -1,157 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_REMOTE_CALLS_MJM012402_HPP
|
||||
#define BOOST_REMOTE_CALLS_MJM012402_HPP
|
||||
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#include "remote_call_manager.hpp"
|
||||
#include <boost/thread/detail/singleton.hpp>
|
||||
|
||||
|
||||
// this file contains macros to generate functions with the signatures:
|
||||
// ReturnType st_remote_call([pascal] ReturnType (*pfnFunction)(
|
||||
// [Argument1Type[, Argument2Type[...]]])
|
||||
// [, Argument1Type oArgument1[, Argument2Type oArgument2[...]]])
|
||||
// and
|
||||
// ReturnType dt_remote_call([pascal] ReturnType (*pfnFunction)(
|
||||
// [Argument1Type[, Argument2Type[...]]])
|
||||
// [, Argument1Type oArgument1[, Argument2Type oArgument2[...]]])
|
||||
// in other words, identical to the function pointer versions of boost::bind, but
|
||||
// with the return type returned. The purpose of these functions is to be able to
|
||||
// request that a function be called at system task time or deferred task time, then
|
||||
// sleep until it is called, and finally get back its return value.
|
||||
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_0
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_1 BOOST_REMOTE_CALL_CLASS_LIST_0, class A1
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_2 BOOST_REMOTE_CALL_CLASS_LIST_1, class A2
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_3 BOOST_REMOTE_CALL_CLASS_LIST_2, class A3
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_4 BOOST_REMOTE_CALL_CLASS_LIST_3, class A4
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_5 BOOST_REMOTE_CALL_CLASS_LIST_4, class A5
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_6 BOOST_REMOTE_CALL_CLASS_LIST_5, class A6
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_7 BOOST_REMOTE_CALL_CLASS_LIST_6, class A7
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_8 BOOST_REMOTE_CALL_CLASS_LIST_7, class A8
|
||||
#define BOOST_REMOTE_CALL_CLASS_LIST_9 BOOST_REMOTE_CALL_CLASS_LIST_8, class A9
|
||||
|
||||
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_0
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_1 BOOST_REMOTE_CALL_ARGUMENT_LIST_0 A1 oA1
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_2 BOOST_REMOTE_CALL_ARGUMENT_LIST_1, A2 oA2
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_3 BOOST_REMOTE_CALL_ARGUMENT_LIST_2, A3 oA3
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_4 BOOST_REMOTE_CALL_ARGUMENT_LIST_3, A4 oA4
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_5 BOOST_REMOTE_CALL_ARGUMENT_LIST_4, A5 oA5
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_6 BOOST_REMOTE_CALL_ARGUMENT_LIST_5, A6 oA6
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_7 BOOST_REMOTE_CALL_ARGUMENT_LIST_6, A7 oA7
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_8 BOOST_REMOTE_CALL_ARGUMENT_LIST_7, A8 oA8
|
||||
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_9 BOOST_REMOTE_CALL_ARGUMENT_LIST_8, A9 oA9
|
||||
|
||||
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_0
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_1 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_0, oA1
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_2 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_1, oA2
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_3 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_2, oA3
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_4 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_3, oA4
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_5 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_4, oA5
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_6 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_5, oA6
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_7 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_6, oA7
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_8 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_7, oA8
|
||||
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_9 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_8, oA9
|
||||
|
||||
|
||||
#define BOOST_REMOTE_CALL_COMMA_0
|
||||
#define BOOST_REMOTE_CALL_COMMA_1 ,
|
||||
#define BOOST_REMOTE_CALL_COMMA_2 ,
|
||||
#define BOOST_REMOTE_CALL_COMMA_3 ,
|
||||
#define BOOST_REMOTE_CALL_COMMA_4 ,
|
||||
#define BOOST_REMOTE_CALL_COMMA_5 ,
|
||||
#define BOOST_REMOTE_CALL_COMMA_6 ,
|
||||
#define BOOST_REMOTE_CALL_COMMA_7 ,
|
||||
#define BOOST_REMOTE_CALL_COMMA_8 ,
|
||||
#define BOOST_REMOTE_CALL_COMMA_9 ,
|
||||
|
||||
|
||||
// this is the macro that ties it all together. From here, we generate all forms of
|
||||
// dt_remote_call and st_remote_call.
|
||||
|
||||
#define BOOST_REMOTE_CALL(context, stack, n) \
|
||||
template<class R BOOST_REMOTE_CALL_CLASS_LIST_ ## n> \
|
||||
inline R context ## _remote_call(stack R (*pfnF)( \
|
||||
BOOST_REMOTE_CALL_ARGUMENT_LIST_ ## n) \
|
||||
BOOST_REMOTE_CALL_COMMA_ ## n \
|
||||
BOOST_REMOTE_CALL_ARGUMENT_LIST_ ## n) \
|
||||
{ \
|
||||
using ::boost::detail::thread::singleton; \
|
||||
using detail::remote_call_manager; \
|
||||
function<R> oFunc(bind(pfnF BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_ ## n)); \
|
||||
remote_call_manager &rManager(singleton<remote_call_manager>::instance()); \
|
||||
return(rManager.execute_at_ ## context(oFunc)); \
|
||||
}
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
|
||||
BOOST_REMOTE_CALL(st, , 0)
|
||||
BOOST_REMOTE_CALL(st, , 1)
|
||||
BOOST_REMOTE_CALL(st, , 2)
|
||||
BOOST_REMOTE_CALL(st, , 3)
|
||||
BOOST_REMOTE_CALL(st, , 4)
|
||||
BOOST_REMOTE_CALL(st, , 5)
|
||||
BOOST_REMOTE_CALL(st, , 6)
|
||||
BOOST_REMOTE_CALL(st, , 7)
|
||||
BOOST_REMOTE_CALL(st, , 8)
|
||||
BOOST_REMOTE_CALL(st, , 9)
|
||||
|
||||
BOOST_REMOTE_CALL(dt, , 0)
|
||||
BOOST_REMOTE_CALL(dt, , 1)
|
||||
BOOST_REMOTE_CALL(dt, , 2)
|
||||
BOOST_REMOTE_CALL(dt, , 3)
|
||||
BOOST_REMOTE_CALL(dt, , 4)
|
||||
BOOST_REMOTE_CALL(dt, , 5)
|
||||
BOOST_REMOTE_CALL(dt, , 6)
|
||||
BOOST_REMOTE_CALL(dt, , 7)
|
||||
BOOST_REMOTE_CALL(dt, , 8)
|
||||
BOOST_REMOTE_CALL(dt, , 9)
|
||||
|
||||
|
||||
BOOST_REMOTE_CALL(st, pascal, 0)
|
||||
BOOST_REMOTE_CALL(st, pascal, 1)
|
||||
BOOST_REMOTE_CALL(st, pascal, 2)
|
||||
BOOST_REMOTE_CALL(st, pascal, 3)
|
||||
BOOST_REMOTE_CALL(st, pascal, 4)
|
||||
BOOST_REMOTE_CALL(st, pascal, 5)
|
||||
BOOST_REMOTE_CALL(st, pascal, 6)
|
||||
BOOST_REMOTE_CALL(st, pascal, 7)
|
||||
BOOST_REMOTE_CALL(st, pascal, 8)
|
||||
BOOST_REMOTE_CALL(st, pascal, 9)
|
||||
|
||||
BOOST_REMOTE_CALL(dt, pascal, 0)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 1)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 2)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 3)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 4)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 5)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 6)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 7)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 8)
|
||||
BOOST_REMOTE_CALL(dt, pascal, 9)
|
||||
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_REMOTE_CALLS_MJM012402_HPP
|
||||
210
src/mac/safe.cpp
210
src/mac/safe.cpp
@@ -1,210 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include <DriverServices.h>
|
||||
#include <Events.h>
|
||||
#include <Multiprocessing.h>
|
||||
#include <Threads.h>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <boost/thread/detail/force_cast.hpp>
|
||||
#include <limits>
|
||||
#include "execution_context.hpp"
|
||||
|
||||
|
||||
using boost::detail::thread::force_cast;
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
static OSStatus safe_wait(function<OSStatus, Duration> &rFunction, Duration lDuration);
|
||||
|
||||
|
||||
// we call WNE to allow tasks that own the resource the blue is waiting on system
|
||||
// task time, in case they are blocked on an ST remote call (or a memory allocation
|
||||
// for that matter).
|
||||
static void idle()
|
||||
{
|
||||
if(at_st())
|
||||
{
|
||||
EventRecord sEvent;
|
||||
bool bEvent = WaitNextEvent(0U, &sEvent, 0UL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OSStatus safe_wait_on_semaphore(MPSemaphoreID pSemaphoreID, Duration lDuration)
|
||||
{
|
||||
function<OSStatus, Duration> oWaitOnSemaphore;
|
||||
oWaitOnSemaphore = bind(MPWaitOnSemaphore, pSemaphoreID, _1);
|
||||
return(safe_wait(oWaitOnSemaphore, lDuration));
|
||||
}
|
||||
|
||||
|
||||
OSStatus safe_enter_critical_region(MPCriticalRegionID pCriticalRegionID, Duration lDuration, MPCriticalRegionID pCriticalRegionCriticalRegionID/* = kInvalidID*/)
|
||||
{
|
||||
if(pCriticalRegionCriticalRegionID != kInvalidID)
|
||||
{
|
||||
if(at_mp())
|
||||
{
|
||||
// enter the critical region's critical region
|
||||
OSStatus lStatus = noErr;
|
||||
AbsoluteTime sExpiration;
|
||||
if(lDuration != kDurationImmediate && lDuration != kDurationForever)
|
||||
{
|
||||
sExpiration = AddDurationToAbsolute(lDuration, UpTime());
|
||||
}
|
||||
lStatus = MPEnterCriticalRegion(pCriticalRegionCriticalRegionID, lDuration);
|
||||
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||
if(lStatus == noErr)
|
||||
{
|
||||
// calculate a new duration
|
||||
if(lDuration != kDurationImmediate && lDuration != kDurationForever)
|
||||
{
|
||||
// check if we have any time left
|
||||
AbsoluteTime sUpTime(UpTime());
|
||||
if(force_cast<uint64_t>(sExpiration) > force_cast<uint64_t>(sUpTime))
|
||||
{
|
||||
// reset our duration to our remaining time
|
||||
lDuration = AbsoluteDeltaToDuration(sExpiration, sUpTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no time left
|
||||
lDuration = kDurationImmediate;
|
||||
}
|
||||
}
|
||||
// if we entered the critical region, exit it again
|
||||
lStatus = MPExitCriticalRegion(pCriticalRegionCriticalRegionID);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, give up
|
||||
return(lStatus);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we're at system task time, try to enter the critical region's critical
|
||||
// region until we succeed. MP tasks will block on this until we let it go.
|
||||
OSStatus lStatus;
|
||||
do
|
||||
{
|
||||
lStatus = MPEnterCriticalRegion(pCriticalRegionCriticalRegionID, kDurationImmediate);
|
||||
} while(lStatus == kMPTimeoutErr);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
}
|
||||
|
||||
// try to enter the critical region
|
||||
function<OSStatus, Duration> oEnterCriticalRegion;
|
||||
oEnterCriticalRegion = bind(MPEnterCriticalRegion, pCriticalRegionID, _1);
|
||||
OSStatus lStatus = safe_wait(oEnterCriticalRegion, lDuration);
|
||||
|
||||
// if we entered the critical region's critical region to get the critical region,
|
||||
// exit the critical region's critical region.
|
||||
if(pCriticalRegionCriticalRegionID != kInvalidID && at_mp() == false)
|
||||
{
|
||||
lStatus = MPExitCriticalRegion(pCriticalRegionCriticalRegionID);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
return(lStatus);
|
||||
}
|
||||
|
||||
OSStatus safe_wait_on_queue(MPQueueID pQueueID, void **pParam1, void **pParam2, void **pParam3, Duration lDuration)
|
||||
{
|
||||
function<OSStatus, Duration> oWaitOnQueue;
|
||||
oWaitOnQueue = bind(MPWaitOnQueue, pQueueID, pParam1, pParam2, pParam3, _1);
|
||||
return(safe_wait(oWaitOnQueue, lDuration));
|
||||
}
|
||||
|
||||
OSStatus safe_delay_until(AbsoluteTime *pWakeUpTime)
|
||||
{
|
||||
if(execution_context() == k_eExecutionContextMPTask)
|
||||
{
|
||||
return(MPDelayUntil(pWakeUpTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t ullWakeUpTime = force_cast<uint64_t>(*pWakeUpTime);
|
||||
|
||||
while(force_cast<uint64_t>(UpTime()) < ullWakeUpTime)
|
||||
{
|
||||
idle();
|
||||
}
|
||||
|
||||
return(noErr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OSStatus safe_wait(function<OSStatus, Duration> &rFunction, Duration lDuration)
|
||||
{
|
||||
if(execution_context() == k_eExecutionContextMPTask)
|
||||
{
|
||||
return(rFunction(lDuration));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t ullExpiration = 0ULL;
|
||||
|
||||
// get the expiration time in UpTime units
|
||||
if(lDuration == kDurationForever)
|
||||
{
|
||||
ullExpiration = (::std::numeric_limits<uint64_t>::max)();
|
||||
}
|
||||
else if(lDuration == kDurationImmediate)
|
||||
{
|
||||
ullExpiration = force_cast<uint64_t>(UpTime());
|
||||
}
|
||||
else
|
||||
{
|
||||
AbsoluteTime sExpiration = AddDurationToAbsolute(lDuration, UpTime());
|
||||
ullExpiration = force_cast<uint64_t>(sExpiration);
|
||||
}
|
||||
|
||||
OSStatus lStatus;
|
||||
bool bExpired = false;
|
||||
|
||||
do
|
||||
{
|
||||
lStatus = rFunction(kDurationImmediate);
|
||||
// mm - "if" #if 0'd out to allow task time to threads blocked on I/O
|
||||
#if 0
|
||||
if(lStatus == kMPTimeoutErr)
|
||||
#endif
|
||||
{
|
||||
idle();
|
||||
}
|
||||
if(lDuration != kDurationForever)
|
||||
{
|
||||
bExpired = (force_cast<uint64_t>(UpTime()) < ullExpiration);
|
||||
}
|
||||
} while(lStatus == kMPTimeoutErr && bExpired == false);
|
||||
|
||||
return(lStatus);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
@@ -1,41 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_SAFE_MJM012402_HPP
|
||||
#define BOOST_SAFE_MJM012402_HPP
|
||||
|
||||
|
||||
#include <Multiprocessing.h>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
// these functions are used to wain in an execution context-independent manor. All of these
|
||||
// functions are both MP- and ST-safe.
|
||||
|
||||
OSStatus safe_wait_on_semaphore(MPSemaphoreID pSemaphoreID, Duration lDuration);
|
||||
OSStatus safe_enter_critical_region(MPCriticalRegionID pCriticalRegionID, Duration lDuration, MPCriticalRegionID pCriticalRegionCriticalRegionID = kInvalidID);
|
||||
OSStatus safe_wait_on_queue(MPQueueID pQueueID, void **pParam1, void **pParam2, void **pParam3, Duration lDuration);
|
||||
OSStatus safe_delay_until(AbsoluteTime *pWakeUpTime);
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_SAFE_MJM012402_HPP
|
||||
@@ -1,47 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "scoped_critical_region.hpp"
|
||||
|
||||
#include "init.hpp"
|
||||
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
scoped_critical_region::scoped_critical_region():
|
||||
m_pCriticalRegionID(kInvalidID)
|
||||
{
|
||||
static bool bIgnored = thread_init();
|
||||
OSStatus lStatus = MPCreateCriticalRegion(&m_pCriticalRegionID);
|
||||
if(lStatus != noErr || m_pCriticalRegionID == kInvalidID)
|
||||
throw(thread_resource_error());
|
||||
}
|
||||
|
||||
scoped_critical_region::~scoped_critical_region()
|
||||
{
|
||||
OSStatus lStatus = MPDeleteCriticalRegion(m_pCriticalRegionID);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
@@ -1,63 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_SCOPED_CRITICAL_REGION_MJM012402_HPP
|
||||
#define BOOST_SCOPED_CRITICAL_REGION_MJM012402_HPP
|
||||
|
||||
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
|
||||
#include <Multiprocessing.h>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
// class scoped_critical_region probably needs a new name. Although the current name
|
||||
// is accurate, it can be read to mean that a critical region is entered for the
|
||||
// current scope. In reality, a critical region is _created_ for the current scope.
|
||||
// This class is intended as a replacement for MPCriticalRegionID that will
|
||||
// automatically create and dispose of itself.
|
||||
|
||||
class scoped_critical_region
|
||||
{
|
||||
public:
|
||||
scoped_critical_region();
|
||||
~scoped_critical_region();
|
||||
|
||||
public:
|
||||
operator const MPCriticalRegionID &() const;
|
||||
const MPCriticalRegionID &get() const;
|
||||
|
||||
private:
|
||||
MPCriticalRegionID m_pCriticalRegionID;
|
||||
};
|
||||
|
||||
|
||||
// these are inlined for speed.
|
||||
inline scoped_critical_region::operator const MPCriticalRegionID &() const
|
||||
{ return(m_pCriticalRegionID); }
|
||||
inline const MPCriticalRegionID &scoped_critical_region::get() const
|
||||
{ return(m_pCriticalRegionID); }
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_SCOPED_CRITICAL_REGION_MJM012402_HPP
|
||||
@@ -1,85 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "st_scheduler.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
#if TARGET_CARBON
|
||||
|
||||
st_scheduler::st_scheduler():
|
||||
m_uppTask(NULL),
|
||||
m_pTimer(NULL)
|
||||
{
|
||||
m_uppTask = NewEventLoopTimerUPP(task_entry);
|
||||
// TODO - throw on error
|
||||
assert(m_uppTask != NULL);
|
||||
}
|
||||
|
||||
st_scheduler::~st_scheduler()
|
||||
{
|
||||
DisposeEventLoopTimerUPP(m_uppTask);
|
||||
m_uppTask = NULL;
|
||||
}
|
||||
|
||||
|
||||
void st_scheduler::start_polling()
|
||||
{
|
||||
assert(m_pTimer == NULL);
|
||||
OSStatus lStatus = InstallEventLoopTimer(GetMainEventLoop(),
|
||||
0 * kEventDurationSecond,
|
||||
kEventDurationMillisecond,
|
||||
m_uppTask,
|
||||
this,
|
||||
&m_pTimer);
|
||||
// TODO - throw on error
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void st_scheduler::stop_polling()
|
||||
{
|
||||
assert(m_pTimer != NULL);
|
||||
OSStatus lStatus = RemoveEventLoopTimer(m_pTimer);
|
||||
assert(lStatus == noErr);
|
||||
m_pTimer = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ pascal void st_scheduler::task_entry(EventLoopTimerRef /*pTimer*/, void *pRefCon)
|
||||
{
|
||||
st_scheduler *pThis = reinterpret_cast<st_scheduler *>(pRefCon);
|
||||
assert(pThis != NULL);
|
||||
pThis->task();
|
||||
}
|
||||
|
||||
void st_scheduler::task()
|
||||
{
|
||||
periodic_function();
|
||||
}
|
||||
|
||||
#else
|
||||
# error st_scheduler unimplemented!
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
@@ -1,67 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_ST_SCHEDULER_MJM012402_HPP
|
||||
#define BOOST_ST_SCHEDULER_MJM012402_HPP
|
||||
|
||||
|
||||
#include <CarbonEvents.h>
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
// class st_scheduler calls its pure-virtual periodic_function method periodically at
|
||||
// system task time. This is generally 40Hz under Mac OS 9.
|
||||
|
||||
class st_scheduler
|
||||
{
|
||||
public:
|
||||
st_scheduler();
|
||||
virtual ~st_scheduler();
|
||||
|
||||
protected:
|
||||
void start_polling();
|
||||
void stop_polling();
|
||||
|
||||
private:
|
||||
virtual void periodic_function() = 0;
|
||||
|
||||
#if TARGET_CARBON
|
||||
// use event loop timers under Carbon
|
||||
private:
|
||||
static pascal void task_entry(EventLoopTimerRef pTimer, void *pRefCon);
|
||||
void task();
|
||||
|
||||
private:
|
||||
EventLoopTimerUPP m_uppTask;
|
||||
EventLoopTimerRef m_pTimer;
|
||||
#else
|
||||
// this can be implemented using OT system tasks. This would be mostly a copy-and-
|
||||
// paste of the dt_scheduler code, replacing DeferredTask with SystemTask and DT
|
||||
// with ST.
|
||||
# error st_scheduler unimplemented!
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_ST_SCHEDULER_MJM012402_HPP
|
||||
@@ -1,56 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#include "thread_cleanup.hpp"
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
TaskStorageIndex g_ulIndex(0UL);
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
void do_thread_startup()
|
||||
{
|
||||
if(g_ulIndex == 0UL)
|
||||
{
|
||||
OSStatus lStatus = MPAllocateTaskStorageIndex(&g_ulIndex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
set_thread_cleanup_task(NULL);
|
||||
}
|
||||
|
||||
void do_thread_cleanup()
|
||||
{
|
||||
void (*pfnTask)() = MPGetTaskValue(g_ulIndex)
|
||||
}
|
||||
|
||||
|
||||
void set_thread_cleanup_task(void (*pfnTask)())
|
||||
{
|
||||
lStatus = MPSetTaskValue(g_ulIndex, reinterpret_cast<TaskStorageValue>(pfnTask));
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
@@ -1,36 +0,0 @@
|
||||
// (C) Copyright Mac Murrett 2001.
|
||||
// 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)
|
||||
|
||||
// See http://www.boost.org for most recent version.
|
||||
|
||||
#ifndef BOOST_THREAD_CLEANUP_MJM012402_HPP
|
||||
#define BOOST_THREAD_CLEANUP_MJM012402_HPP
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace threads {
|
||||
|
||||
namespace mac {
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
void do_thread_startup();
|
||||
void do_thread_cleanup();
|
||||
|
||||
void set_thread_cleanup_task();
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mac
|
||||
|
||||
} // namespace threads
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_THREAD_CLEANUP_MJM012402_HPP
|
||||
561
src/mutex.cpp
561
src/mutex.cpp
@@ -1,561 +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/mutex.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
#include "timeconv.inl"
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
# include <new>
|
||||
# include <boost/thread/once.hpp>
|
||||
# include <windows.h>
|
||||
# include <time.h>
|
||||
# include "mutex.inl"
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
# include <errno.h>
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <MacErrors.h>
|
||||
# include "mac/init.hpp"
|
||||
# include "mac/safe.hpp"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
mutex::mutex()
|
||||
: m_mutex(0)
|
||||
, m_critical_section(false)
|
||||
{
|
||||
m_critical_section = true;
|
||||
if (m_critical_section)
|
||||
m_mutex = new_critical_section();
|
||||
else
|
||||
m_mutex = new_mutex(0);
|
||||
}
|
||||
|
||||
mutex::~mutex()
|
||||
{
|
||||
if (m_critical_section)
|
||||
delete_critical_section(m_mutex);
|
||||
else
|
||||
delete_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void mutex::do_lock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
wait_critical_section_infinite(m_mutex);
|
||||
else
|
||||
wait_mutex(m_mutex, INFINITE);
|
||||
}
|
||||
|
||||
void mutex::do_unlock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
release_critical_section(m_mutex);
|
||||
else
|
||||
release_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void mutex::do_lock(cv_state&)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void mutex::do_unlock(cv_state&)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
try_mutex::try_mutex()
|
||||
: m_mutex(0)
|
||||
, m_critical_section(false)
|
||||
{
|
||||
m_critical_section = has_TryEnterCriticalSection();
|
||||
if (m_critical_section)
|
||||
m_mutex = new_critical_section();
|
||||
else
|
||||
m_mutex = new_mutex(0);
|
||||
}
|
||||
|
||||
try_mutex::~try_mutex()
|
||||
{
|
||||
if (m_critical_section)
|
||||
delete_critical_section(m_mutex);
|
||||
else
|
||||
delete_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
wait_critical_section_infinite(m_mutex);
|
||||
else
|
||||
wait_mutex(m_mutex, INFINITE);
|
||||
}
|
||||
|
||||
bool try_mutex::do_trylock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
return wait_critical_section_try(m_mutex);
|
||||
else
|
||||
return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock()
|
||||
{
|
||||
if (m_critical_section)
|
||||
release_critical_section(m_mutex);
|
||||
else
|
||||
release_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock(cv_state&)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock(cv_state&)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
timed_mutex::timed_mutex()
|
||||
: m_mutex(0)
|
||||
{
|
||||
m_mutex = new_mutex(0);
|
||||
}
|
||||
|
||||
timed_mutex::~timed_mutex()
|
||||
{
|
||||
delete_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock()
|
||||
{
|
||||
wait_mutex(m_mutex, INFINITE);
|
||||
}
|
||||
|
||||
bool timed_mutex::do_trylock()
|
||||
{
|
||||
return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
bool timed_mutex::do_timedlock(const xtime& xt)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
int milliseconds;
|
||||
to_duration(xt, milliseconds);
|
||||
|
||||
int res = wait_mutex(m_mutex, milliseconds);
|
||||
|
||||
if (res == WAIT_TIMEOUT)
|
||||
{
|
||||
boost::xtime cur;
|
||||
boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
if (boost::xtime_cmp(xt, cur) > 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
return res == WAIT_OBJECT_0;
|
||||
}
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock()
|
||||
{
|
||||
release_mutex(m_mutex);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock(cv_state&)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock(cv_state&)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
|
||||
mutex::mutex()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_init(&m_mutex, 0);
|
||||
if (res != 0)
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
mutex::~mutex()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_destroy(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void mutex::do_lock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
if (res == EDEADLK) throw lock_error();
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void mutex::do_unlock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
if (res == EPERM) throw lock_error();
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void mutex::do_lock(cv_state&)
|
||||
{
|
||||
}
|
||||
|
||||
void mutex::do_unlock(cv_state& state)
|
||||
{
|
||||
state.pmutex = &m_mutex;
|
||||
}
|
||||
|
||||
try_mutex::try_mutex()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_init(&m_mutex, 0);
|
||||
if (res != 0)
|
||||
throw thread_resource_error();
|
||||
}
|
||||
|
||||
try_mutex::~try_mutex()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_destroy(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
if (res == EDEADLK) throw lock_error();
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
bool try_mutex::do_trylock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_trylock(&m_mutex);
|
||||
if (res == EDEADLK) throw lock_error();
|
||||
assert(res == 0 || res == EBUSY);
|
||||
return res == 0;
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
if (res == EPERM) throw lock_error();
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock(cv_state&)
|
||||
{
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock(cv_state& state)
|
||||
{
|
||||
state.pmutex = &m_mutex;
|
||||
}
|
||||
|
||||
timed_mutex::timed_mutex()
|
||||
: m_locked(false)
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_init(&m_mutex, 0);
|
||||
if (res != 0)
|
||||
throw thread_resource_error();
|
||||
|
||||
res = pthread_cond_init(&m_condition, 0);
|
||||
if (res != 0)
|
||||
{
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
timed_mutex::~timed_mutex()
|
||||
{
|
||||
assert(!m_locked);
|
||||
int res = 0;
|
||||
res = pthread_mutex_destroy(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
res = pthread_cond_destroy(&m_condition);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
while (m_locked)
|
||||
{
|
||||
res = pthread_cond_wait(&m_condition, &m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
assert(!m_locked);
|
||||
m_locked = true;
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
bool timed_mutex::do_trylock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
bool ret = false;
|
||||
if (!m_locked)
|
||||
{
|
||||
m_locked = true;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool timed_mutex::do_timedlock(const xtime& xt)
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
timespec ts;
|
||||
to_timespec(xt, ts);
|
||||
|
||||
while (m_locked)
|
||||
{
|
||||
res = pthread_cond_timedwait(&m_condition, &m_mutex, &ts);
|
||||
assert(res == 0 || res == ETIMEDOUT);
|
||||
|
||||
if (res == ETIMEDOUT)
|
||||
break;
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
if (!m_locked)
|
||||
{
|
||||
m_locked = true;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock()
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
assert(m_locked);
|
||||
m_locked = false;
|
||||
|
||||
res = pthread_cond_signal(&m_condition);
|
||||
assert(res == 0);
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock(cv_state&)
|
||||
{
|
||||
int res = 0;
|
||||
while (m_locked)
|
||||
{
|
||||
res = pthread_cond_wait(&m_condition, &m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
assert(!m_locked);
|
||||
m_locked = true;
|
||||
|
||||
res = pthread_mutex_unlock(&m_mutex);
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock(cv_state& state)
|
||||
{
|
||||
int res = 0;
|
||||
res = pthread_mutex_lock(&m_mutex);
|
||||
assert(res == 0);
|
||||
|
||||
assert(m_locked);
|
||||
m_locked = false;
|
||||
|
||||
res = pthread_cond_signal(&m_condition);
|
||||
assert(res == 0);
|
||||
|
||||
state.pmutex = &m_mutex;
|
||||
}
|
||||
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
|
||||
using threads::mac::detail::safe_enter_critical_region;
|
||||
|
||||
mutex::mutex()
|
||||
{
|
||||
}
|
||||
|
||||
mutex::~mutex()
|
||||
{
|
||||
}
|
||||
|
||||
void mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void mutex::do_unlock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void mutex::do_lock(cv_state& /*state*/)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void mutex::do_unlock(cv_state& /*state*/)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
try_mutex::try_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
try_mutex::~try_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
void try_mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
bool try_mutex::do_trylock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate);
|
||||
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||
return lStatus == noErr;
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void try_mutex::do_lock(cv_state& /*state*/)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void try_mutex::do_unlock(cv_state& /*state*/)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
timed_mutex::timed_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
timed_mutex::~timed_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
|
||||
m_mutex_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
bool timed_mutex::do_trylock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate);
|
||||
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||
return(lStatus == noErr);
|
||||
}
|
||||
|
||||
bool timed_mutex::do_timedlock(const xtime& xt)
|
||||
{
|
||||
int microseconds;
|
||||
to_microduration(xt, microseconds);
|
||||
Duration lDuration = kDurationMicrosecond * microseconds;
|
||||
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = safe_enter_critical_region(m_mutex, lDuration, m_mutex_mutex);
|
||||
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
|
||||
|
||||
return(lStatus == noErr);
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock()
|
||||
{
|
||||
OSStatus lStatus = noErr;
|
||||
lStatus = MPExitCriticalRegion(m_mutex);
|
||||
assert(lStatus == noErr);
|
||||
}
|
||||
|
||||
void timed_mutex::do_lock(cv_state& /*state*/)
|
||||
{
|
||||
do_lock();
|
||||
}
|
||||
|
||||
void timed_mutex::do_unlock(cv_state& /*state*/)
|
||||
{
|
||||
do_unlock();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
// Change Log:
|
||||
// 8 Feb 01 WEKEMPF Initial version.
|
||||
122
src/mutex.inl
122
src/mutex.inl
@@ -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)
|
||||
// boostinspect:nounnamed
|
||||
|
||||
namespace {
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
//:PREVENT THIS FROM BEING DUPLICATED
|
||||
typedef BOOL (WINAPI* TryEnterCriticalSection_type)(LPCRITICAL_SECTION lpCriticalSection);
|
||||
TryEnterCriticalSection_type g_TryEnterCriticalSection = 0;
|
||||
boost::once_flag once_init_TryEnterCriticalSection = BOOST_ONCE_INIT;
|
||||
|
||||
void init_TryEnterCriticalSection()
|
||||
{
|
||||
//TryEnterCriticalSection is only available on WinNT 4.0 or later;
|
||||
//it is not available on Win9x.
|
||||
|
||||
OSVERSIONINFO version_info = {sizeof(OSVERSIONINFO)};
|
||||
::GetVersionEx(&version_info);
|
||||
if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT &&
|
||||
version_info.dwMajorVersion >= 4)
|
||||
{
|
||||
if (HMODULE kernel_module = GetModuleHandle(TEXT("KERNEL32.DLL")))
|
||||
g_TryEnterCriticalSection = reinterpret_cast<TryEnterCriticalSection_type>(GetProcAddress(kernel_module, TEXT("TryEnterCriticalSection")));
|
||||
}
|
||||
}
|
||||
|
||||
inline bool has_TryEnterCriticalSection()
|
||||
{
|
||||
boost::call_once(init_TryEnterCriticalSection, once_init_TryEnterCriticalSection);
|
||||
return g_TryEnterCriticalSection != 0;
|
||||
}
|
||||
|
||||
inline HANDLE mutex_cast(void* p)
|
||||
{
|
||||
return reinterpret_cast<HANDLE>(p);
|
||||
}
|
||||
|
||||
inline LPCRITICAL_SECTION critical_section_cast(void* p)
|
||||
{
|
||||
return reinterpret_cast<LPCRITICAL_SECTION>(p);
|
||||
}
|
||||
|
||||
inline void* new_critical_section()
|
||||
{
|
||||
try
|
||||
{
|
||||
LPCRITICAL_SECTION critical_section = new CRITICAL_SECTION;
|
||||
if (critical_section == 0) throw boost::thread_resource_error();
|
||||
InitializeCriticalSection(critical_section);
|
||||
return critical_section;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
throw boost::thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
HANDLE mutex = CreateMutexW(0, 0, wide_name);
|
||||
#else
|
||||
HANDLE mutex = CreateMutexA(0, 0, name);
|
||||
#endif
|
||||
if (mutex == 0 || mutex == INVALID_HANDLE_VALUE) //:xxx (check for both values?)
|
||||
throw boost::thread_resource_error();
|
||||
return reinterpret_cast<void*>(mutex);
|
||||
}
|
||||
|
||||
inline void delete_critical_section(void* mutex)
|
||||
{
|
||||
DeleteCriticalSection(critical_section_cast(mutex));
|
||||
delete critical_section_cast(mutex);
|
||||
}
|
||||
|
||||
inline void delete_mutex(void* mutex)
|
||||
{
|
||||
int res = 0;
|
||||
res = CloseHandle(mutex_cast(mutex));
|
||||
assert(res);
|
||||
}
|
||||
|
||||
inline void wait_critical_section_infinite(void* mutex)
|
||||
{
|
||||
EnterCriticalSection(critical_section_cast(mutex)); //:xxx Can throw an exception under low memory conditions
|
||||
}
|
||||
|
||||
inline bool wait_critical_section_try(void* mutex)
|
||||
{
|
||||
BOOL res = g_TryEnterCriticalSection(critical_section_cast(mutex));
|
||||
return res != 0;
|
||||
}
|
||||
|
||||
inline int wait_mutex(void* mutex, int time)
|
||||
{
|
||||
unsigned int res = 0;
|
||||
res = WaitForSingleObject(mutex_cast(mutex), time);
|
||||
//:xxx assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
|
||||
return res;
|
||||
}
|
||||
|
||||
inline void release_critical_section(void* mutex)
|
||||
{
|
||||
LeaveCriticalSection(critical_section_cast(mutex));
|
||||
}
|
||||
|
||||
inline void release_mutex(void* mutex)
|
||||
{
|
||||
BOOL res = FALSE;
|
||||
res = ReleaseMutex(mutex_cast(mutex));
|
||||
assert(res);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
207
src/once.cpp
207
src/once.cpp
@@ -1,207 +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/detail/workaround.hpp>
|
||||
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
# if BOOST_WORKAROUND(__BORLANDC__,<= 0x551)
|
||||
using std::size_t;
|
||||
# endif
|
||||
# include <windows.h>
|
||||
# include "mutex.inl"
|
||||
# if defined(BOOST_NO_STRINGSTREAM)
|
||||
# include <strstream>
|
||||
|
||||
class unfreezer
|
||||
{
|
||||
public:
|
||||
unfreezer(std::ostrstream& s) : m_stream(s) {}
|
||||
~unfreezer() { m_stream.freeze(false); }
|
||||
private:
|
||||
std::ostrstream& m_stream;
|
||||
};
|
||||
|
||||
# else
|
||||
# include <sstream>
|
||||
# endif
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
# include <Multiprocessing.h>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std { using ::sprintf; }
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
namespace {
|
||||
pthread_key_t key;
|
||||
pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||
|
||||
typedef void (*once_callback)();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
static void key_init()
|
||||
{
|
||||
pthread_key_create(&key, 0);
|
||||
}
|
||||
|
||||
static void do_once()
|
||||
{
|
||||
once_callback* cb = reinterpret_cast<once_callback*>(
|
||||
pthread_getspecific(key));
|
||||
(**cb)();
|
||||
}
|
||||
|
||||
}
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
namespace {
|
||||
void *remote_call_proxy(void *pData)
|
||||
{
|
||||
std::pair<void (*)(), boost::once_flag *> &rData(
|
||||
*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
|
||||
|
||||
if(*rData.second == false)
|
||||
{
|
||||
rData.first();
|
||||
*rData.second = true;
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(BOOST_HAS_WINTHREADS)
|
||||
namespace {
|
||||
// The signature for InterlockedCompareExchange has changed with the
|
||||
// addition of Win64 support. I can't determine any (consistent and
|
||||
// portable) way of using conditional compilation to detect this, so
|
||||
// we use these type wrappers. Unfortunately, the various vendors
|
||||
// use different calling conventions and other signature anamolies,
|
||||
// and thus have unique types as well. This is known to work on VC6,
|
||||
// VC7, Borland 5.5.2 and gcc 3.2. Are there other signatures for
|
||||
// other platforms?
|
||||
inline LONG ice_wrapper(LONG (__stdcall *ice)(LONG*, LONG, LONG),
|
||||
volatile LONG* dest, LONG exch, LONG cmp)
|
||||
{
|
||||
return (*ice)(const_cast<LONG*>(dest), exch, cmp);
|
||||
}
|
||||
|
||||
inline LONG ice_wrapper(LONG (__stdcall *ice)(volatile LONG*, LONG, LONG),
|
||||
volatile LONG* dest, LONG exch, LONG cmp)
|
||||
{
|
||||
return (*ice)(dest, exch, cmp);
|
||||
}
|
||||
|
||||
inline LONG ice_wrapper(LPVOID (__stdcall *ice)(LPVOID*, LPVOID, LPVOID),
|
||||
volatile LONG* dest, LONG exch, LONG cmp)
|
||||
{
|
||||
return (LONG)(*ice)((LPVOID*)dest, (LPVOID)exch, (LPVOID)cmp);
|
||||
}
|
||||
|
||||
// The friendly form of InterlockedCompareExchange that defers
|
||||
// according to the above function type wrappers.
|
||||
inline LONG compare_exchange(volatile LPLONG dest, LONG exch, LONG cmp)
|
||||
{
|
||||
#ifdef _WIN64
|
||||
return InterlockedCompareExchange(dest, exch, cmp);
|
||||
#else
|
||||
return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
void call_once(void (*func)(), once_flag& flag)
|
||||
{
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
if (compare_exchange(&flag, 1, 1) == 0)
|
||||
{
|
||||
#if defined(BOOST_NO_STRINGSTREAM)
|
||||
std::ostrstream strm;
|
||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4"
|
||||
<< std::hex
|
||||
<< GetCurrentProcessId()
|
||||
<< &flag
|
||||
<< std::ends;
|
||||
unfreezer unfreeze(strm);
|
||||
HANDLE mutex=new_mutex(strm.str());
|
||||
#else
|
||||
# if defined (BOOST_NO_ANSI_APIS)
|
||||
std::wostringstream strm;
|
||||
strm << L"2AC1A572DB6944B0A65C38C4140AF2F4"
|
||||
<< std::hex
|
||||
<< GetCurrentProcessId()
|
||||
<< &flag;
|
||||
HANDLE mutex = CreateMutexW(NULL, FALSE, strm.str().c_str());
|
||||
# else
|
||||
std::ostringstream strm;
|
||||
strm << "2AC1A572DB6944B0A65C38C4140AF2F4"
|
||||
<< std::hex
|
||||
<< GetCurrentProcessId()
|
||||
<< &flag;
|
||||
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str().c_str());
|
||||
# endif
|
||||
#endif
|
||||
assert(mutex != NULL);
|
||||
|
||||
int res = 0;
|
||||
res = WaitForSingleObject(mutex, INFINITE);
|
||||
assert(res == WAIT_OBJECT_0);
|
||||
|
||||
if (compare_exchange(&flag, 1, 1) == 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
func();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
res = ReleaseMutex(mutex);
|
||||
assert(res);
|
||||
res = CloseHandle(mutex);
|
||||
assert(res);
|
||||
throw;
|
||||
}
|
||||
InterlockedExchange(&flag, 1);
|
||||
}
|
||||
|
||||
res = ReleaseMutex(mutex);
|
||||
assert(res);
|
||||
res = CloseHandle(mutex);
|
||||
assert(res);
|
||||
}
|
||||
#elif defined(BOOST_HAS_PTHREADS)
|
||||
pthread_once(&once, &key_init);
|
||||
pthread_setspecific(key, &func);
|
||||
pthread_once(&flag, do_once);
|
||||
#elif defined(BOOST_HAS_MPTASKS)
|
||||
if(flag == false)
|
||||
{
|
||||
// all we do here is make a remote call to blue, as blue is not
|
||||
// reentrant.
|
||||
std::pair<void (*)(), once_flag *> sData(func, &flag);
|
||||
MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext);
|
||||
assert(flag == true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Change Log:
|
||||
// 1 Aug 01 WEKEMPF Initial version.
|
||||
51
src/pthread/once.cpp
Executable file
51
src/pthread/once.cpp
Executable file
@@ -0,0 +1,51 @@
|
||||
// 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)
|
||||
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
BOOST_THREAD_DECL boost::uintmax_t once_global_epoch=UINTMAX_C(~0);
|
||||
BOOST_THREAD_DECL pthread_mutex_t once_epoch_mutex=PTHREAD_MUTEX_INITIALIZER;
|
||||
BOOST_THREAD_DECL pthread_cond_t once_epoch_cv = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
namespace
|
||||
{
|
||||
pthread_key_t epoch_tss_key;
|
||||
pthread_once_t epoch_tss_key_flag=PTHREAD_ONCE_INIT;
|
||||
|
||||
extern "C" void delete_epoch_tss_data(void* data)
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
extern "C" void create_epoch_tss_key()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_key_create(&epoch_tss_key,delete_epoch_tss_data));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
boost::uintmax_t& get_once_per_thread_epoch()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_once(&epoch_tss_key_flag,create_epoch_tss_key));
|
||||
void* data=pthread_getspecific(epoch_tss_key);
|
||||
if(!data)
|
||||
{
|
||||
data=malloc(sizeof(boost::uintmax_t));
|
||||
BOOST_VERIFY(!pthread_setspecific(epoch_tss_key,data));
|
||||
*static_cast<boost::uintmax_t*>(data)=UINTMAX_C(~0);
|
||||
}
|
||||
return *static_cast<boost::uintmax_t*>(data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
664
src/pthread/thread.cpp
Normal file
664
src/pthread/thread.cpp
Normal file
@@ -0,0 +1,664 @@
|
||||
// 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)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
|
||||
#include "timeconv.inl"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct thread_exit_callback_node
|
||||
{
|
||||
boost::detail::thread_exit_function_base* func;
|
||||
thread_exit_callback_node* next;
|
||||
|
||||
thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
|
||||
thread_exit_callback_node* next_):
|
||||
func(func_),next(next_)
|
||||
{}
|
||||
};
|
||||
|
||||
struct tss_data_node
|
||||
{
|
||||
void const* key;
|
||||
boost::shared_ptr<boost::detail::tss_cleanup_function> func;
|
||||
void* value;
|
||||
tss_data_node* next;
|
||||
|
||||
tss_data_node(void const* key_,boost::shared_ptr<boost::detail::tss_cleanup_function> func_,void* value_,
|
||||
tss_data_node* next_):
|
||||
key(key_),func(func_),value(value_),next(next_)
|
||||
{}
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
|
||||
pthread_key_t current_thread_tls_key;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void tls_destructor(void* data)
|
||||
{
|
||||
boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
|
||||
if(thread_info)
|
||||
{
|
||||
while(thread_info->tss_data || thread_info->thread_exit_callbacks)
|
||||
{
|
||||
while(thread_info->thread_exit_callbacks)
|
||||
{
|
||||
detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks;
|
||||
thread_info->thread_exit_callbacks=current_node->next;
|
||||
if(current_node->func)
|
||||
{
|
||||
(*current_node->func)();
|
||||
delete current_node->func;
|
||||
}
|
||||
delete current_node;
|
||||
}
|
||||
while(thread_info->tss_data)
|
||||
{
|
||||
detail::tss_data_node* const current_node=thread_info->tss_data;
|
||||
thread_info->tss_data=current_node->next;
|
||||
if(current_node->func)
|
||||
{
|
||||
(*current_node->func)(current_node->value);
|
||||
}
|
||||
delete current_node;
|
||||
}
|
||||
}
|
||||
thread_info->self.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void create_current_thread_tls_key()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_key_create(¤t_thread_tls_key,&tls_destructor));
|
||||
}
|
||||
}
|
||||
|
||||
boost::detail::thread_data_base* get_current_thread_data()
|
||||
{
|
||||
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
|
||||
return (boost::detail::thread_data_base*)pthread_getspecific(current_thread_tls_key);
|
||||
}
|
||||
|
||||
void set_current_thread_data(detail::thread_data_base* new_data)
|
||||
{
|
||||
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
|
||||
BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data));
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
void* thread_proxy(void* param)
|
||||
{
|
||||
boost::shared_ptr<boost::detail::thread_data_base> thread_info = static_cast<boost::detail::thread_data_base*>(param)->self;
|
||||
thread_info->self.reset();
|
||||
detail::set_current_thread_data(thread_info.get());
|
||||
try
|
||||
{
|
||||
thread_info->run();
|
||||
}
|
||||
catch(thread_interrupted const&)
|
||||
{
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
detail::tls_destructor(thread_info.get());
|
||||
detail::set_current_thread_data(0);
|
||||
boost::lock_guard<boost::mutex> lock(thread_info->data_mutex);
|
||||
thread_info->done=true;
|
||||
thread_info->done_condition.notify_all();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct externally_launched_thread:
|
||||
detail::thread_data_base
|
||||
{
|
||||
externally_launched_thread()
|
||||
{
|
||||
interrupt_enabled=false;
|
||||
}
|
||||
|
||||
void run()
|
||||
{}
|
||||
};
|
||||
|
||||
detail::thread_data_base* make_external_thread_data()
|
||||
{
|
||||
detail::thread_data_base* const me(new externally_launched_thread());
|
||||
me->self.reset(me);
|
||||
set_current_thread_data(me);
|
||||
return me;
|
||||
}
|
||||
|
||||
|
||||
detail::thread_data_base* get_or_make_current_thread_data()
|
||||
{
|
||||
detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
|
||||
if(!current_thread_data)
|
||||
{
|
||||
current_thread_data=make_external_thread_data();
|
||||
}
|
||||
return current_thread_data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
thread::thread()
|
||||
{}
|
||||
|
||||
void thread::start_thread()
|
||||
{
|
||||
thread_info->self=thread_info;
|
||||
int const res = pthread_create(&thread_info->thread_handle, 0, &thread_proxy, thread_info.get());
|
||||
if (res != 0)
|
||||
{
|
||||
thread_info->self.reset();
|
||||
throw thread_resource_error();
|
||||
}
|
||||
}
|
||||
|
||||
thread::~thread()
|
||||
{
|
||||
detach();
|
||||
}
|
||||
|
||||
thread::thread(detail::thread_move_t<thread> x)
|
||||
{
|
||||
lock_guard<mutex> lock(x->thread_info_mutex);
|
||||
thread_info=x->thread_info;
|
||||
x->thread_info.reset();
|
||||
}
|
||||
|
||||
thread& thread::operator=(detail::thread_move_t<thread> x)
|
||||
{
|
||||
thread new_thread(x);
|
||||
swap(new_thread);
|
||||
return *this;
|
||||
}
|
||||
|
||||
thread::operator detail::thread_move_t<thread>()
|
||||
{
|
||||
return move();
|
||||
}
|
||||
|
||||
detail::thread_move_t<thread> thread::move()
|
||||
{
|
||||
detail::thread_move_t<thread> x(*this);
|
||||
return x;
|
||||
}
|
||||
|
||||
void thread::swap(thread& x)
|
||||
{
|
||||
thread_info.swap(x.thread_info);
|
||||
}
|
||||
|
||||
|
||||
bool thread::operator==(const thread& other) const
|
||||
{
|
||||
return get_id()==other.get_id();
|
||||
}
|
||||
|
||||
bool thread::operator!=(const thread& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
boost::shared_ptr<detail::thread_data_base> thread::get_thread_info() const
|
||||
{
|
||||
lock_guard<mutex> l(thread_info_mutex);
|
||||
return thread_info;
|
||||
}
|
||||
|
||||
void thread::join()
|
||||
{
|
||||
boost::shared_ptr<detail::thread_data_base> const local_thread_info=get_thread_info();
|
||||
if(local_thread_info)
|
||||
{
|
||||
bool do_join=false;
|
||||
|
||||
{
|
||||
unique_lock<mutex> lock(local_thread_info->data_mutex);
|
||||
while(!local_thread_info->done)
|
||||
{
|
||||
local_thread_info->done_condition.wait(lock);
|
||||
}
|
||||
do_join=!local_thread_info->join_started;
|
||||
|
||||
if(do_join)
|
||||
{
|
||||
local_thread_info->join_started=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(!local_thread_info->joined)
|
||||
{
|
||||
local_thread_info->done_condition.wait(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(do_join)
|
||||
{
|
||||
void* result=0;
|
||||
BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
|
||||
lock_guard<mutex> lock(local_thread_info->data_mutex);
|
||||
local_thread_info->joined=true;
|
||||
local_thread_info->done_condition.notify_all();
|
||||
}
|
||||
|
||||
lock_guard<mutex> l1(thread_info_mutex);
|
||||
if(thread_info==local_thread_info)
|
||||
{
|
||||
thread_info.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool thread::timed_join(system_time const& wait_until)
|
||||
{
|
||||
boost::shared_ptr<detail::thread_data_base> const local_thread_info=get_thread_info();
|
||||
if(local_thread_info)
|
||||
{
|
||||
bool do_join=false;
|
||||
|
||||
{
|
||||
unique_lock<mutex> lock(local_thread_info->data_mutex);
|
||||
while(!local_thread_info->done)
|
||||
{
|
||||
if(!local_thread_info->done_condition.timed_wait(lock,wait_until))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
do_join=!local_thread_info->join_started;
|
||||
|
||||
if(do_join)
|
||||
{
|
||||
local_thread_info->join_started=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(!local_thread_info->joined)
|
||||
{
|
||||
local_thread_info->done_condition.wait(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(do_join)
|
||||
{
|
||||
void* result=0;
|
||||
BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
|
||||
lock_guard<mutex> lock(local_thread_info->data_mutex);
|
||||
local_thread_info->joined=true;
|
||||
local_thread_info->done_condition.notify_all();
|
||||
}
|
||||
|
||||
lock_guard<mutex> l1(thread_info_mutex);
|
||||
if(thread_info==local_thread_info)
|
||||
{
|
||||
thread_info.reset();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool thread::joinable() const
|
||||
{
|
||||
return get_thread_info();
|
||||
}
|
||||
|
||||
|
||||
void thread::detach()
|
||||
{
|
||||
boost::shared_ptr<detail::thread_data_base> local_thread_info;
|
||||
{
|
||||
lock_guard<mutex> l1(thread_info_mutex);
|
||||
thread_info.swap(local_thread_info);
|
||||
}
|
||||
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lock(local_thread_info->data_mutex);
|
||||
if(!local_thread_info->join_started)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
|
||||
local_thread_info->join_started=true;
|
||||
local_thread_info->joined=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void thread::sleep(const system_time& st)
|
||||
{
|
||||
detail::thread_data_base* const thread_info=detail::get_current_thread_data();
|
||||
|
||||
if(thread_info)
|
||||
{
|
||||
unique_lock<mutex> lk(thread_info->sleep_mutex);
|
||||
while(thread_info->sleep_condition.timed_wait(lk,st));
|
||||
}
|
||||
else
|
||||
{
|
||||
xtime const xt=get_xtime(st);
|
||||
|
||||
for (int foo=0; foo < 5; ++foo)
|
||||
{
|
||||
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
|
||||
timespec ts;
|
||||
to_timespec_duration(xt, ts);
|
||||
BOOST_VERIFY(!pthread_delay_np(&ts));
|
||||
# elif defined(BOOST_HAS_NANOSLEEP)
|
||||
timespec ts;
|
||||
to_timespec_duration(xt, ts);
|
||||
|
||||
// nanosleep takes a timespec that is an offset, not
|
||||
// an absolute time.
|
||||
nanosleep(&ts, 0);
|
||||
# else
|
||||
mutex mx;
|
||||
mutex::scoped_lock lock(mx);
|
||||
condition cond;
|
||||
cond.timed_wait(lock, xt);
|
||||
# endif
|
||||
xtime cur;
|
||||
xtime_get(&cur, TIME_UTC);
|
||||
if (xtime_cmp(xt, cur) <= 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void thread::yield()
|
||||
{
|
||||
# if defined(BOOST_HAS_SCHED_YIELD)
|
||||
BOOST_VERIFY(!sched_yield());
|
||||
# elif defined(BOOST_HAS_PTHREAD_YIELD)
|
||||
BOOST_VERIFY(!pthread_yield());
|
||||
# else
|
||||
xtime xt;
|
||||
xtime_get(&xt, TIME_UTC);
|
||||
sleep(xt);
|
||||
# endif
|
||||
}
|
||||
|
||||
unsigned thread::hardware_concurrency()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
thread::id thread::get_id() const
|
||||
{
|
||||
boost::shared_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
|
||||
if(local_thread_info)
|
||||
{
|
||||
return id(local_thread_info->thread_handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
return id();
|
||||
}
|
||||
}
|
||||
|
||||
void thread::interrupt()
|
||||
{
|
||||
boost::shared_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lk(local_thread_info->data_mutex);
|
||||
local_thread_info->interrupt_requested=true;
|
||||
if(local_thread_info->current_cond)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info->current_cond));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool thread::interruption_requested() const
|
||||
{
|
||||
boost::shared_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lk(local_thread_info->data_mutex);
|
||||
return local_thread_info->interrupt_requested;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
void interruption_point()
|
||||
{
|
||||
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
|
||||
if(thread_info && thread_info->interrupt_enabled)
|
||||
{
|
||||
lock_guard<mutex> lg(thread_info->data_mutex);
|
||||
if(thread_info->interrupt_requested)
|
||||
{
|
||||
thread_info->interrupt_requested=false;
|
||||
throw thread_interrupted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool interruption_enabled()
|
||||
{
|
||||
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
|
||||
return thread_info && thread_info->interrupt_enabled;
|
||||
}
|
||||
|
||||
bool interruption_requested()
|
||||
{
|
||||
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
|
||||
if(!thread_info)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
lock_guard<mutex> lg(thread_info->data_mutex);
|
||||
return thread_info->interrupt_requested;
|
||||
}
|
||||
}
|
||||
|
||||
disable_interruption::disable_interruption():
|
||||
interruption_was_enabled(interruption_enabled())
|
||||
{
|
||||
if(interruption_was_enabled)
|
||||
{
|
||||
detail::get_current_thread_data()->interrupt_enabled=false;
|
||||
}
|
||||
}
|
||||
|
||||
disable_interruption::~disable_interruption()
|
||||
{
|
||||
if(detail::get_current_thread_data())
|
||||
{
|
||||
detail::get_current_thread_data()->interrupt_enabled=interruption_was_enabled;
|
||||
}
|
||||
}
|
||||
|
||||
restore_interruption::restore_interruption(disable_interruption& d)
|
||||
{
|
||||
if(d.interruption_was_enabled)
|
||||
{
|
||||
detail::get_current_thread_data()->interrupt_enabled=true;
|
||||
}
|
||||
}
|
||||
|
||||
restore_interruption::~restore_interruption()
|
||||
{
|
||||
if(detail::get_current_thread_data())
|
||||
{
|
||||
detail::get_current_thread_data()->interrupt_enabled=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
void add_thread_exit_function(thread_exit_function_base* func)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
thread_exit_callback_node* const new_node=
|
||||
new thread_exit_callback_node(func,current_thread_data->thread_exit_callbacks);
|
||||
current_thread_data->thread_exit_callbacks=new_node;
|
||||
}
|
||||
|
||||
tss_data_node* find_tss_data(void const* key)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_current_thread_data());
|
||||
if(current_thread_data)
|
||||
{
|
||||
detail::tss_data_node* current_node=current_thread_data->tss_data;
|
||||
while(current_node)
|
||||
{
|
||||
if(current_node->key==key)
|
||||
{
|
||||
return current_node;
|
||||
}
|
||||
current_node=current_node->next;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* get_tss_data(void const* key)
|
||||
{
|
||||
if(tss_data_node* const current_node=find_tss_data(key))
|
||||
{
|
||||
return current_node->value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
|
||||
{
|
||||
if(tss_data_node* const current_node=find_tss_data(key))
|
||||
{
|
||||
if(cleanup_existing && current_node->func)
|
||||
{
|
||||
(*current_node->func)(current_node->value);
|
||||
}
|
||||
current_node->func=func;
|
||||
current_node->value=tss_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
tss_data_node* const new_node=new tss_data_node(key,func,tss_data,current_thread_data->tss_data);
|
||||
current_thread_data->tss_data=new_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thread_group::thread_group()
|
||||
{
|
||||
}
|
||||
|
||||
thread_group::~thread_group()
|
||||
{
|
||||
// We shouldn't have to scoped_lock here, since referencing this object
|
||||
// from another thread while we're deleting it in the current thread is
|
||||
// going to lead to undefined behavior any way.
|
||||
for (std::list<thread*>::iterator it = m_threads.begin();
|
||||
it != m_threads.end(); ++it)
|
||||
{
|
||||
delete (*it);
|
||||
}
|
||||
}
|
||||
|
||||
thread* thread_group::create_thread(const function0<void>& threadfunc)
|
||||
{
|
||||
// No scoped_lock required here since the only "shared data" that's
|
||||
// modified here occurs inside add_thread which does scoped_lock.
|
||||
std::auto_ptr<thread> thrd(new thread(threadfunc));
|
||||
add_thread(thrd.get());
|
||||
return thrd.release();
|
||||
}
|
||||
|
||||
void thread_group::add_thread(thread* thrd)
|
||||
{
|
||||
mutex::scoped_lock scoped_lock(m_mutex);
|
||||
|
||||
// For now we'll simply ignore requests to add a thread object multiple
|
||||
// times. Should we consider this an error and either throw or return an
|
||||
// error value?
|
||||
std::list<thread*>::iterator it = std::find(m_threads.begin(),
|
||||
m_threads.end(), thrd);
|
||||
BOOST_ASSERT(it == m_threads.end());
|
||||
if (it == m_threads.end())
|
||||
m_threads.push_back(thrd);
|
||||
}
|
||||
|
||||
void thread_group::remove_thread(thread* thrd)
|
||||
{
|
||||
mutex::scoped_lock scoped_lock(m_mutex);
|
||||
|
||||
// For now we'll simply ignore requests to remove a thread object that's
|
||||
// not in the group. Should we consider this an error and either throw or
|
||||
// return an error value?
|
||||
std::list<thread*>::iterator it = std::find(m_threads.begin(),
|
||||
m_threads.end(), thrd);
|
||||
BOOST_ASSERT(it != m_threads.end());
|
||||
if (it != m_threads.end())
|
||||
m_threads.erase(it);
|
||||
}
|
||||
|
||||
void thread_group::join_all()
|
||||
{
|
||||
mutex::scoped_lock scoped_lock(m_mutex);
|
||||
for (std::list<thread*>::iterator it = m_threads.begin();
|
||||
it != m_threads.end(); ++it)
|
||||
{
|
||||
(*it)->join();
|
||||
}
|
||||
}
|
||||
|
||||
void thread_group::interrupt_all()
|
||||
{
|
||||
boost::lock_guard<mutex> guard(m_mutex);
|
||||
|
||||
for(std::list<thread*>::iterator it=m_threads.begin(),end=m_threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
(*it)->interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int thread_group::size() const
|
||||
{
|
||||
return m_threads.size();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user