2
0
mirror of https://github.com/boostorg/thread.git synced 2026-02-03 09:42:16 +00:00

Compare commits

...

305 Commits

Author SHA1 Message Date
Vicente J. Botet Escriba
042ce47e77 Merge branch 'develop' 2019-05-10 16:25:42 +02:00
Vicente J. Botet Escriba
65dcf92e48 Merge branch 'develop' of https://github.com/boostorg/thread into develop 2019-05-10 16:25:11 +02:00
Vicente J. Botet Escriba
3071b9e8b5 Merge pull request #282 from wyattoday/develop
Fix MSVC ARM64 build errors, issue #281
2019-05-10 07:42:25 +02:00
Wyatt O'Day
8190a50838 Fix MSVC ARM64 build errors, issue #281 2019-05-09 15:18:59 -04:00
Vicente J. Botet Escriba
23539a88c0 Merge branch 'develop' 2019-04-13 09:15:31 +02:00
Vicente J. Botet Escriba
6168f43db8 Merge branch 'develop' of https://github.com/boostorg/thread into develop 2019-04-13 09:14:43 +02:00
Vicente J. Botet Escriba
a05c37a997 Merge pull request #280 from chrullrich/fix-create-event
Fix operator precedence.
2019-04-13 09:14:20 +02:00
Vicente J. Botet Escriba
34e354be4c Merge branch 'develop' of https://github.com/boostorg/thread into develop 2019-04-13 09:13:45 +02:00
Vicente J. Botet Escriba
ccf70ce0aa typo. 2019-04-13 09:13:36 +02:00
Christian Ullrich
86b7ceb05a Fix operator precedence. 2019-04-12 19:35:39 +02:00
Vicente J. Botet Escriba
a645ef761d Merge pull request #277 from austin-beer/fix_sync_queue_time_jump_issues
Fix sync_timed_queue time jump issues
2019-04-03 20:41:52 +02:00
Vicente J. Botet Escriba
9a20debf11 Merge pull request #278 from austin-beer/fix_eintr_issue_275_b
Fix "variable set but not used" errors caused by previous commit
2019-04-03 20:38:17 +02:00
Austin Beer
2502b2741b Fix "variable set but not used" errors caused by previous commit 2019-04-03 10:49:16 -06:00
Vicente J. Botet Escriba
5c6180fa4f Merge pull request #276 from austin-beer/fix_eintr_issue_275
Fix Issue 275
2019-04-02 19:02:25 +02:00
Austin Beer
c6863c4b27 Improve the sync_timed_queue test so it is less likely to fail in
non-deterministic timing environments
2019-04-02 09:46:52 -06:00
Austin Beer
48a4a06f86 Fix Issue 275
* Re-fixed the EINTR bug that exists in some pthreads implementations.
It was originally fixed in https://svn.boost.org/trac10/ticket/6200 and
was accidentally disabled in 5b209c2e83.
* Made sure that the fix for the EINTR bug was consistently applied to
all code in the library.
* Made sure that all pthread_mutex_*() and pthread_cond_*() function
calls in the library were consistently decorated with
BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS.
2019-04-01 10:00:57 -06:00
Austin Beer
a0b255768e Fix time jump issues that were re-introduced while fixing issue 271
Also fix time jump issues with sync_timed_queue::push_for()
2019-03-30 20:40:24 -06:00
Austin Beer
e5eef80c28 Fix a couple of the sync_timed_queue::pull_for() time jump tests 2019-03-30 20:33:00 -06:00
Austin Beer
ff38aad946 Add pull_until() and pull_for() to test for Issue 271 2019-03-30 19:18:30 -06:00
Austin Beer
7966756ac4 Add missing sync_timed_queue::pull_for() time jump tests 2019-03-30 19:04:49 -06:00
Austin Beer
8aac9047ab Prevent mixing clock types in sync_timed_queue 2019-03-29 16:41:57 -06:00
Vicente J. Botet Escriba
f90bdfd2a5 Merge pull request #274 from austin-beer/fix-windows-header-case
Fix build on case-sensitive file system
2019-03-23 21:07:52 +01:00
Austin Beer
7b8fe78ccf Fix build on case-sensitive file system 2019-03-23 12:58:57 -06:00
Vicente J. Botet Escriba
d49236480f Merge pull request #273 from austin-beer/test-issue-271
Add test for Issue 271
2019-03-23 04:38:15 +01:00
Austin Beer
ea54f2ec4d Add test for Issue 271 2019-03-22 10:46:53 -06:00
Vicente J. Botet Escriba
2553ce4fa0 Merge pull request #272 from austin-beer/fix-issue-271
Fix Issue 271
2019-03-19 06:47:36 +01:00
Austin Beer
d4c2cef0a2 Fix Issue 271
* If thread A was waiting to pull the earliest element off of a
sync_timed_queue, and while it was waiting thread B added a new element with an
earlier time to the queue, thread A wouldn't reduce how long it waited before
pulling the earliest element off of the queue.

* Also refactored a function name and a variable name since their names no
longer accurately described what they do:
*** notify_not_empty_if_needed() -> notify_elem_added()
*** not_empty_ -> cond_

* Also deleted a no-longer-used function:
*** wait_until_closed_until()
2019-03-18 19:16:59 -06:00
Vicente J. Botet Escriba
ba02b3af42 Merge branch 'develop' 2019-01-21 08:05:18 +01:00
Vicente J. Botet Escriba
5d20f5b342 Fix missing includes files and make executors available by default in version 5. 2019-01-20 22:42:12 +01:00
Vicente J. Botet Escriba
52b742d001 Merge pull request #268 from Lastique/self_contained_headers
Add self contained header tests and fix discovered bugs
2019-01-19 21:04:39 +01:00
Andrey Semashev
e16786f173 Fixed bugs discovered by the standalone header tests.
- Added missing includes.
- Added missing namespace qualification for Boost.Chrono casts.
- Added typedefs renaming polymorphic lockable wrappers to a more consistent
  naming scheme. This fixes incorrect name references.
- Fixed incorrect duration casts in polymorphic lockable wrappers.
- Renamed upgrade_lockable_adapter to poly_upgrade_lockable_adapter, since
  upgrade_lockable_adapter already exists and has a different meaning.
- Use BOOST_THREAD_FUTURE instead of future in executors and task region.
- Disable serial_executor_cont when executors or future continuations
  are not enabled.
- Marked sync_queue_is_closed exception as visible.
2019-01-19 20:53:33 +03:00
Andrey Semashev
9342fe3f25 Added tests for self-contained headers.
The new set of tests iterates over Boost.Thread public headers and verifies that
each header is self-contained, i.e. doesn't have any missing includes and
contains syntactically correct content. On Windows and Cygwin, a second test
per each header is generated, which includes the header after windows.h. This
verifies that the header doesn't have conflicts with Windows SDK and that
includeing windows.h does not break platform detection in Boost.Thread.

This set of tests would have detected the bug fixed by
https://github.com/boostorg/thread/pull/263.
2019-01-19 19:04:25 +03:00
Vicente J. Botet Escriba
085c9c6ca8 Merge pull request #266 from Lastique/remove_linking_system
Remove linking with Boost.System
2019-01-16 22:59:30 +01:00
Andrey Semashev
7ba2f2cf5b Remove linking with Boost.System.
Since Boost.System is now header-only, no need to link with the library.
2019-01-14 20:19:46 +03:00
Vicente J. Botet Escriba
800d0ca597 Merge pull request #263 from Lastique/patch-6
Fix compilation of timed functions on Cygwin
2019-01-06 20:48:10 +01:00
Andrey Semashev
81d4e5a824 Select time-related API based on the threading platform API. 2019-01-06 21:58:09 +03:00
Andrey Semashev
c97b504925 Fix compilation of timed functions on Cygwin.
Cygwin includes both Windows and POSIX API and, depending on the included headers, may have WIN32 macros defined. Since Boost.Thread uses pthread API on Cygwin, it should also enable POSIX API for time units (i.e. timespec).
2019-01-06 17:57:35 +03:00
Vicente J. Botet Escriba
758d087662 Merge pull request #249 from Kojoley/feature/simplify-tss-cleanup
Simplify TSS cleanup routines. Fixes #236
2019-01-03 19:10:52 +01:00
Vicente J. Botet Escriba
f5133ab829 Merge pull request #260 from DesWurstes/patch-1
Fix "interruption_point" defined twice
2019-01-03 19:02:56 +01:00
Vicente J. Botet Escriba
c46da73e3a Merge pull request #262 from Lastique/fix_strict_aliasing_warnings
Fix MinGW warnings about violation of the strict aliasing rules
2019-01-03 19:01:42 +01:00
Andrey Semashev
e942774b90 Fix MinGW warnings about violation of the strict aliasing rules.
Use memcpy to convert between long and the bitfield structure and use
memcmp to compare the two bitfields. Compilers should be smart enough to
optimize away these string operations and generate virtually the same
code as before.
2019-01-03 19:47:48 +03:00
DesWurstes
c90ed87527 Declare "interruption_point" once 2019-01-01 12:49:39 +03:00
Nikita Kniazev
970dcb8afd Simplify TSS cleanup routines. Fixes #236
Instead of wrapping a default or user provided destructor into a virtual
class and placing it into a shared_ptr it is now stored directly with
an elided type, to not introduce UB it is not called directly but through
a helper function which casts it back to the original type before calling.
2018-11-17 15:25:27 +03:00
Vicente J. Botet Escriba
8d0f077ab2 Merge branch 'develop' 2018-11-15 06:45:24 +01:00
Vicente J. Botet Escriba
dfe6cc3c49 Remove Niall as maintainer 2018-11-15 06:44:45 +01:00
Vicente J. Botet Escriba
330a0a15e6 Merge branch 'develop' 2018-11-14 23:27:25 +01:00
Vicente J. Botet Escriba
f60dfdfad9 Merge pull request #247 from Romain-Geissler-1A/noexcept
Remove all "throw()" specification to prepare for C++20 where it is r…
2018-11-12 19:30:24 +01:00
Romain Geissler
ccb1b99e3f Remove all "throw()" specification to prepare for C++20 where it is removed. 2018-11-11 22:24:38 +00:00
Vicente J. Botet Escriba
aa444afc5c Merge branch 'develop' 2018-11-01 07:57:44 +01:00
Vicente J. Botet Escriba
f1d464d0d5 added cygwin platform configuration. 2018-10-25 04:18:27 +02:00
Vicente J. Botet Escriba
57161ddbb6 Merge pull request #246 from Kojoley/patch-1
DOC: Fixed a small typo
2018-10-25 03:45:06 +02:00
Nikita Kniazev
9a7d21444f DOC: Fixed a small typo 2018-10-24 23:13:43 +03:00
Vicente J. Botet Escriba
1b2bc4e451 Merge branch 'develop' 2018-10-20 19:04:45 +02:00
Vicente J. Botet Escriba
e1b5f9d786 Try to catch the CircleCi clang issues. 2018-10-18 18:59:49 +02:00
Vicente J. Botet Escriba
8b5cd5f02a Merge branch 'develop' of https://github.com/boostorg/thread into develop 2018-10-18 07:35:50 +02:00
Vicente J. Botet Escriba
5b2ffe7104 try to fix decay_copy issue with reference to functions: function cannot return function type 2018-10-17 20:54:21 +02:00
Vicente J. Botet Escriba
5af180ba36 Merge pull request #244 from boostorg/pr/fix-cygwin-win32
Fix uses of BOOST_HAS_WINTHREADS (not correct on Cygwin)
2018-10-16 21:52:45 +02:00
Vicente J. Botet Escriba
340cc5ab61 Try to catch the CircleCi clang issues. 2018-10-16 00:02:31 +02:00
Vicente J. Botet Escriba
9a3b8bb4b0 Try to catch the CircleCi issue. 2018-10-15 07:10:05 +02:00
Vicente J. Botet Escriba
79f955e229 Try to catch the CircleCi issue. 2018-10-14 09:55:47 +02:00
Vicente J. Botet Escriba
1da2a57124 Try to catch the CircleCi issue. 2018-10-13 15:24:58 +02:00
Peter Dimov
54871e21a1 Fix uses of BOOST_HAS_WINTHREADS (not correct on Cygwin) 2018-10-13 04:56:08 +03:00
Vicente J. Botet Escriba
00efec75d9 Merge branch 'develop' 2018-10-13 02:12:28 +02:00
Vicente J. Botet Escriba
c66c4b1c76 Don't report unusable-partial-specialization due to type_traits #93 issue. 2018-10-11 07:28:20 +02:00
Vicente J. Botet Escriba
6c70eccb01 Merge branch 'develop' 2018-10-11 06:58:26 +02:00
Vicente J. Botet Escriba
fbf8d58ad7 Set time limit to 60s 2018-10-10 18:54:23 +02:00
Vicente J. Botet Escriba
46a94dd8ba Extract test too long. 2018-10-10 06:04:17 +02:00
Vicente J. Botet Escriba
76c7b25d4b Extract test too long. 2018-10-09 21:17:24 +02:00
Vicente J. Botet Escriba
eb297ce86c Merge branch 'develop' 2018-10-09 20:59:21 +02:00
Vicente J. Botet Escriba
cc31d32b3f Merge pull request #243 from Kojoley/execution_monitor-use_mutex-sleep
execution_monitor::use_mutex sleeps the whole timeout duration
2018-10-09 06:25:40 +02:00
Nikita Kniazev
7f258e5da3 execution_monitor::use_mutex sleeps the whole timeout duration
Instead of sleeping the whole timeout duration, sleep for 500ms
in a loop and check every iteration if the job was already done.
2018-10-08 22:34:37 +03:00
Vicente J. Botet Escriba
c3897bea65 Merge pull request #242 from Kojoley/ci-added-tests-timeout
CI: Limit single test execution time to 30 seconds
2018-10-08 20:34:20 +02:00
Vicente J. Botet Escriba
502876f0e9 Merge branch 'develop' 2018-10-07 19:41:15 +02:00
Vicente J. Botet Escriba
e1e4cbf4be Merge pull request #240 from Kojoley/fix-lockable_traits
Fixed lockable_traits bugs
2018-10-07 19:07:49 +02:00
Nikita Kniazev
d2679fec89 CI: Limit single test execution time to 30 seconds
It should help identify hanging tests that push CI over build time limit.
2018-10-05 20:11:18 +03:00
Vicente J. Botet Escriba
ba5632e33a Merge pull request #241 from Kojoley/suppress-varadic-macro-warnings
Suppress variadic macro warnings
2018-10-05 06:59:50 +02:00
Nikita Kniazev
9a3b7ff859 Suppress variadic macro warnings
The workaround was stolen from `boost/static_assert.hpp` and works in Clang too
2018-10-05 00:47:03 +03:00
Nikita Kniazev
a35ffa3a83 lockable_traits: Use decltype based methods detection
Traits does not detect methods with `noexcept` qualifiers which are part of
function type in C++17 (P0012R1).
2018-10-04 18:36:38 +03:00
Vicente J. Botet Escriba
1a8229160e Merge branch 'develop' 2018-10-01 05:58:16 +02:00
Vicente J. Botet Escriba
acda67baf4 Merge pull request #234 from DjArt/develop
Fixing compiling on VS2017 for ARM & ARM64
2018-10-01 05:49:15 +02:00
Vicente J. Botet Escriba
f6609a42dc Merge pull request #235 from boostorg/pr/fix-detail-winapi
Fix boost::detail::winapi references
2018-09-27 20:42:07 +02:00
Peter Dimov
534f5af9e6 Fix boost::detail::winapi references 2018-09-27 08:58:47 +03:00
Vicente J. Botet Escriba
2be8908dcd Merge branch 'develop' 2018-09-23 15:54:09 +02:00
Vicente J. Botet Escriba
aaca72e34b Fix __attribute(()) syntax typo. 2018-09-23 15:53:28 +02:00
Vicente J. Botet Escriba
24404dcae4 Merge branch 'develop' 2018-09-15 21:03:10 +02:00
Vicente J. Botet Escriba
f4b239bab1 fix <:: 2018-09-15 10:17:54 +02:00
Vicente J. Botet Escriba
bf7e79c709 fix <:: 2018-09-15 10:16:25 +02:00
Vicente J. Botet Escriba
526e2d6554 Merge branch 'develop' 2018-09-15 08:56:22 +02:00
Vicente J. Botet Escriba
8c1d232b8c try to manage with #11477. 2018-09-15 07:11:37 +02:00
Vicente J. Botet Escriba
92a5bc4300 manage with #232 2018-09-15 07:10:05 +02:00
Dj Art
0389f58f23 Fixing compiling on VS2017 for ARM & ARM64 2018-09-15 03:15:04 +08:00
Vicente J. Botet Escriba
5b209c2e83 try to fix thread safety issues raised on FreeBSD. 2018-09-10 23:52:48 +02:00
Vicente J. Botet Escriba
33ad8b1834 Merge branch 'develop' of https://github.com/boostorg/thread into develop 2018-09-06 21:12:13 +02:00
Vicente J. Botet Escriba
8fb92dfb52 Merge pull request #231 from ffontaine/develop
fix static detection of lock-free atomic ints
2018-09-06 21:03:20 +02:00
Vicente J. Botet Escriba
c550979eff Merge branch 'develop' of https://github.com/boostorg/thread into develop 2018-09-06 07:16:29 +02:00
Vicente J. Botet Escriba
15f2d7a21c fix test not returning boost::report_errors(). 2018-09-06 07:16:17 +02:00
Vicente J. Botet Escriba
371fb42709 Merge pull request #229 from huangqinjin/develop
fix compilation with BOOST_NO_EXCEPTIONS
2018-09-06 06:54:27 +02:00
Fabrice Fontaine
f7581a3662 fix static detection of lock-free atomic ints
When build statically, boost is unable to detect lock-free atomics ints
because it tries to link dynamically with boost_system, see
output/build/boost-1.67.0/bin.v2/config.log (with -d5 option):

Using shell: /bin/sh -c
    argv[0] = '/bin/sh'
    argv[1] = '-c'
    argv[2] = '
    "/home/fabrice/buildroot/output/host/bin/arm-linux-g++"   -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os   -Wl,-elf2flt -static  -Wl,-elf2flt -static -fPIC -pthread -O0 -fno-inline -Wall -pedantic -g -Wextra -Wno-long-long -Wno-unused-parameter -Wunused-function -pedantic -DBOOST_ALL_NO_LIB=1 -DBOOST_SYSTEM_DYN_LINK=1 -DBOOST_THREAD_BUILD_DLL=1  -I"." -c -o "bin.v2/libs/thread/build/gcc-6.4.0/debug/threading-multi/has_atomic_flag_lockfree_test.o" "libs/thread/src/../build/has_atomic_flag_lockfree_test.cpp"
'
gcc.compile.c++ bin.v2/libs/thread/build/gcc-6.4.0/debug/threading-multi/has_atomic_flag_lockfree_test.o

    "/home/fabrice/buildroot/output/host/bin/arm-linux-g++"   -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os   -Wl,-elf2flt -static  -Wl,-elf2flt -static -fPIC -pthread -O0 -fno-inline -Wall -pedantic -g -Wextra -Wno-long-long -Wno-unused-parameter -Wunused-function -pedantic -DBOOST_ALL_NO_LIB=1 -DBOOST_SYSTEM_DYN_LINK=1 -DBOOST_THREAD_BUILD_DLL=1  -I"." -c -o "bin.v2/libs/thread/build/gcc-6.4.0/debug/threading-multi/has_atomic_flag_lockfree_test.o" "libs/thread/src/../build/has_atomic_flag_lockfree_test.cpp"

0.033561 sec system; 0.126314 sec user; 288.682473 sec clock
gcc.compile.c++ bin.v2/libs/system/build/gcc-6.4.0/debug/threading-multi/error_code.o

    "/home/fabrice/buildroot/output/host/bin/arm-linux-g++"   -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os   -Wl,-elf2flt -static  -Wl,-elf2flt -static -fPIC -pthread -O0 -fno-inline -Wall -pedantic -g  -DBOOST_ALL_NO_LIB=1 -DBOOST_SYSTEM_DYN_LINK=1  -I"." -c -o "bin.v2/libs/system/build/gcc-6.4.0/debug/threading-multi/error_code.o" "libs/system/src/error_code.cpp"

0.084060 sec system; 0.644133 sec user; 8.858824 sec clock
SEM: <s>gcc-link-semaphore now used by <pbin.v2/libs/system/build/gcc-6.4.0/debug/threading-multi>libboost_system.so.1.67.0
Using shell: /bin/sh -c
    argv[0] = '/bin/sh'
    argv[1] = '-c'
    argv[2] = '
    "/home/fabrice/buildroot/output/host/bin/arm-linux-g++"    -o "bin.v2/libs/system/build/gcc-6.4.0/debug/threading-multi/libboost_system.so.1.67.0" -Wl,-h -Wl,libboost_system.so.1.67.0 -shared -Wl,--start-group "bin.v2/libs/system/build/gcc-6.4.0/debug/threading-multi/error_code.o"  -Wl,-Bstatic  -Wl,-Bdynamic -lrt -Wl,--end-group -fPIC -pthread -g  -Wl,-elf2flt -static
'
gcc.link.dll bin.v2/libs/system/build/gcc-6.4.0/debug/threading-multi/libboost_system.so.1.67.0

    "/home/fabrice/buildroot/output/host/bin/arm-linux-g++"    -o "bin.v2/libs/system/build/gcc-6.4.0/debug/threading-multi/libboost_system.so.1.67.0" -Wl,-h -Wl,libboost_system.so.1.67.0 -shared -Wl,--start-group "bin.v2/libs/system/build/gcc-6.4.0/debug/threading-multi/error_code.o"  -Wl,-Bstatic  -Wl,-Bdynamic -lrt -Wl,--end-group -fPIC -pthread -g  -Wl,-elf2flt -static

ld (ld-elf2flt): -shared used without passing a shared library ID
collect2: error: ld a retourné le statut de sortie 1
0.003123 sec system; 0.004732 sec user; 15.646509 sec clock
...failed gcc.link.dll bin.v2/libs/system/build/gcc-6.4.0/debug/threading-multi/libboost_system.so.1.67.0...

To fix this, move the exe statement before the boost/thread project

Fixes:
 - http://autobuild.buildroot.org/results/f46d38991385cbc2a4fa14eb31074e770cd79803

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
2018-09-05 12:24:04 +02:00
huangqinjin
e54f7e3960 fix warning: comparison of unsigned expression < 0 2018-08-31 13:53:54 +08:00
huangqinjin
d1284b02ad fix compilation with BOOST_NO_EXCEPTIONS 2018-08-31 10:54:35 +08:00
Vicente J. Botet Escriba
c5e756d196 Merge pull request #227 from kivadiu/develop
Fixed warning cast between incompatible function types from FARPROC_ to gettickcount64_t
2018-08-09 22:52:06 +02:00
Frédéric Bron
ee607c86d4 Fixed warning cast between incompatible function types from FARPROC_ to gettickcount64_t
On Windows, GetProcAddress must be cast to something useful which
generates a warning with gcc. This patch silents the warning.

Fixes issue #225
2018-08-09 10:16:05 +02:00
Vicente J. Botet Escriba
68eef9240f try to fix it for C++98. 2018-08-07 17:02:04 +02:00
Vicente J. Botet Escriba
de7608f067 manage #224: thread::physical_concurrency() allocates a buffer that is bigger than necessary. 2018-08-07 14:19:32 +02:00
Vicente J. Botet Escriba
743f2a0348 manage #226: 1.68 thread pool join do interruption. 2018-08-07 14:15:18 +02:00
Vicente J. Botet Escriba
d8d549cf3e manage #13561. 2018-08-07 13:54:35 +02:00
Vicente J. Botet Escriba
fc08c1fe28 Merge pull request #220 from thughes/feature/test_measure_sleep_time
Account for sleep time in timing tests
2018-04-28 17:47:37 +02:00
Tom Hughes
dce24d5b43 Use default test timing, except mac
The condition variable wait tests are still a little flaky on CircleCI
since we can't account for overwaiting with pthread_cond_timedwait

See https://circleci.com/gh/thughes/thread/483
2018-04-27 12:03:49 -07:00
Tom Hughes
b45ae62791 Use macro for comparison so times are printed on failure 2018-04-27 12:03:49 -07:00
Tom Hughes
b0485bafdd Reduce parallel build jobs on CircleCI
The Linux executors have 2 CPUs and the macOS executors have 4. The
build time does speed up as we increase the number of parallel jobs to
10, but the tests that rely on timing measurements start to fail.
2018-04-27 12:03:49 -07:00
Tom Hughes
3b52a8950f Subtract measured sleep time instead of constant 250 ms
boost::this_thread::sleep_for is allowed to sleep longer than the
requested sleep time. This seems to happen especially on virtualized
systems, such as CircleCI.
2018-04-27 12:03:49 -07:00
Vicente J. Botet Escriba
e60f66e023 Merge pull request #219 from thughes/feature/remove_racy_checks
Remove racy checks
2018-04-27 14:43:14 +02:00
Tom Hughes
2a68582676 Remove racy check
This check may or may not be true depending on how long it takes pt1 to
finish executing. You can verify this by adding a sleep before the check
in which case "is_ready()" is always true.
2018-04-26 07:30:43 -07:00
Tom Hughes
b7ebda0f15 Remove racy check
This check may or may not be true depending on how long it takes p1 to
finish executing. You can verify this by adding a sleep before the check
in which case "is_ready()" is always true.
2018-04-26 07:30:33 -07:00
Vicente J. Botet Escriba
7b2289a1c5 Merge pull request #212 from thughes/feature/add_thread_safety_annotations
Add clang thread-safety annotations to boost::mutex (pthread-only)
2018-04-25 19:13:05 +02:00
Vicente J. Botet Escriba
377bb87ad5 Merge branch 'develop' 2018-04-18 17:51:46 +02:00
Vicente J. Botet Escriba
180ca01c97 Merge pull request #217 from jschueller/patch-1
Windows.h > windows.h
2018-04-15 10:37:11 +02:00
Julien Schueller
a6dede8199 Windows.h > windows.h
Fixes build on case-sensitive fs
2018-04-15 08:33:56 +02:00
Vicente J. Botet Escriba
25b915308a Added test for 13480. 2018-04-14 09:26:31 +02:00
Vicente J. Botet Escriba
079871ffac Merge branch 'develop' of github.com:boostorg/thread into develop 2018-04-13 20:06:50 +02:00
Vicente J. Botet Escriba
4d62627668 Make it possible to compile with BOOST_NO_EXCEPTIONS defined 2018-04-13 20:06:03 +02:00
Vicente J. Botet Escriba
2b88759f43 fix unused local vars. 2018-04-13 13:50:49 +02:00
Vicente J. Botet Escriba
d60968b61c Update boost-1.67 history. 2018-04-13 11:23:10 +02:00
Vicente J. Botet Escriba
5aad4ac056 Merge pull request #216 from gjasny/android-monotonic
pthread_condattr_setclock must not be used prior to Android 21
2018-04-12 09:06:51 +02:00
Gregor Jasny
2ef70e02a5 pthread_condattr_setclock must not be used prior to Android 21
Fixes #215
2018-04-12 08:51:44 +02:00
Vicente J. Botet Escriba
f525a18239 Merge pull request #214 from Lastique/patch-6
Update GetTickCount64 calling convention macro.
2018-03-11 08:45:31 -05:00
Andrey Semashev
5c2dd21508 Update GetTickCount64 calling convention macro.
Boost.WinAPI no longer defines WINAPI calling convention macro and instead defines its own equivalent macro BOOST_WINAPI_WINAPI_CC.
2018-03-11 02:13:36 +03:00
Vicente J. Botet Escriba
6d9aaff58a Increase the time for CircleCI/linux-xxx to 100ms :( 2018-03-08 23:30:53 +01:00
Vicente J. Botet Escriba
db72b0477d Increase the time for CircleCI/mac-clang to 170ms :( 2018-03-08 22:29:39 +01:00
Vicente J. Botet Escriba
1f08b38461 Make the timing check configurable. 2018-03-08 20:39:09 +01:00
Vicente J. Botet Escriba
8cffb15e1e add missing test file. 2018-03-08 07:50:45 +01:00
Vicente J. Botet Escriba
3f1590bce7 fix CircleCI script. 2018-03-08 00:42:31 +01:00
Vicente J. Botet Escriba
37e5c6513c Make configurable the timing. Set 100ms for MacOs and 75ms for Linux on CircleCI. 2018-03-08 00:28:51 +01:00
Vicente J. Botet Escriba
7585187d1c dump delta timing to see when there is a timing issue. 2018-03-07 23:20:36 +01:00
Vicente J. Botet Escriba
8764a5b3dd Merge pull request #213 from thughes/feature/add_circleci
Add CircleCI build
2018-03-07 19:53:35 +01:00
Tom Hughes
9f9feca70c Add CircleCI build 2018-03-05 09:11:04 -08:00
Vicente J. Botet Escriba
d268106bf8 Merge branch 'develop' 2018-03-04 23:12:43 +01:00
Tom Hughes
1874018c12 Add thread safety annotations for lock_guard 2018-03-01 15:57:00 -08:00
Tom Hughes
d78a0ca53f Remove clang toolset from target requirements
This forces clang to be used regardless of the toolset configured
2018-02-28 15:51:38 -08:00
Tom Hughes
d1ef6369d9 Fix bjam thread safety compile rules so they only build with clang 2018-02-28 13:33:09 -08:00
Vicente J. Botet Escriba
040481760c avoid defining twice BOOST_THREAD_WIN32. 2018-02-28 22:16:50 +01:00
Vicente J. Botet Escriba
e848363029 Added define for WIN32 when threadapi is win32. 2018-02-28 18:32:27 +01:00
Tom Hughes
8ce9826d98 Prefix macros with BOOST_THREAD 2018-02-27 16:51:10 -08:00
Tom Hughes
5fa7ae14b9 Add clang thread-safety annotations to boost::mutex (pthread-only) 2018-02-27 09:30:49 -08:00
Vicente J. Botet Escriba
e3358e0925 Merge branch 'develop' of github.com:boostorg/thread into develop 2018-02-26 16:23:41 +01:00
Vicente J. Botet Escriba
13a1f3daaa Merge pull request #211 from Lastique/rewrite_gettickcount64
Rewrite GetTickCount64 emulation implementation.
2018-02-26 16:22:54 +01:00
Andrey Semashev
3a95ba8559 Added periodic refresh calls to emulated GetTickCount64.
Periodic refreshes make sure that the 32-bit GetTickCount wraparounds are
properly counted even if the user doesn't call GetTickCount64 for extended
periods of time.
2018-02-21 20:05:45 +03:00
Vicente J. Botet Escriba
0871d0b0a6 Merge branch 'develop' of github.com:boostorg/thread into develop 2018-02-21 02:13:26 +01:00
Vicente J. Botet Escriba
7edd340995 Merge pull request #210 from austin-beer/final_cleanup_1
Remove unnecessary inline keyword from templated functions
2018-02-21 02:12:43 +01:00
Andrey Semashev
8633d7532d Rewritten GetTickCount64 emulation implementation.
This is to resolve the possible license violation as the previous
implementation has been taken from StackOverflow and was not licensed
under the Boost Software License. The new implementation was adopted from
Boost.Log:

1cc577cbf5/src/timestamp.cpp (L66-L86)

The legal issue has been raised in:

https://lists.boost.org/Archives/boost/2018/02/241453.php

Fixes https://github.com/boostorg/thread/issues/209.
2018-02-21 00:44:20 +03:00
Vicente J. Botet Escriba
03acfa57a2 Merge branch 'master' into develop 2018-02-20 18:04:56 +01:00
Vicente J. Botet Escriba
9be0996062 merge develop (timespec_clocks). 2018-02-20 17:52:51 +01:00
Austin Beer
71231fb2ae Remove unnecessary inline keyword from templated functions 2018-02-16 11:38:45 -07:00
Vicente J. Botet Escriba
526c72cb4b Merge pull request #142 from boostorg/feature/timespec_clocks
Feature/timespec clocks
2018-02-16 07:10:41 +01:00
Vicente J. Botet Escriba
ff5031db9e Merge branch 'develop' into feature/timespec_clocks 2018-02-14 19:05:50 +01:00
Vicente J. Botet Escriba
581558868d Merge pull request #207 from austin-beer/feature/timespec_clocks_pr24_cleanup
Final Cleanup
2018-02-14 04:38:29 +01:00
Austin Beer
96484ac57f Replace hard-coded poll interval with BOOST_THREAD_POLL_INTERVAL_MILLISECONDS 2018-02-12 16:52:22 -07:00
Austin Beer
7de4a7046a Add test code for time jump issue 2018-02-12 13:54:50 -07:00
Austin Beer
3b7ca04408 Improve when and where the inline keyword is used. 2018-02-12 13:54:50 -07:00
Vicente J. Botet Escriba
473648ce6c fix ODR issue when future continuations are enabled. #193 future_then unit test contains two different implementations of do_continuation function. 2018-02-10 14:12:25 +01:00
Vicente J. Botet Escriba
426636b1d0 Merge pull request #204 from shinobu-x/wip-future-0002
Missing destructor
2018-02-03 09:26:55 +01:00
Shinobu Kinjo
cb322cfa86 Missing destructor 2018-02-02 17:38:27 +09:00
Vicente J. Botet Escriba
51d3030a1f Add trace. 2018-01-31 00:40:14 +01:00
Vicente J. Botet Escriba
26f1b6d237 dump diff duration on failing test. 2018-01-30 19:10:11 +01:00
Vicente J. Botet Escriba
5ed197748e Move from 50ms to 75 ms as MacOS runs (on virtual machines?) are failing. 2018-01-30 13:21:03 +01:00
Vicente J. Botet Escriba
79a523390f Added a nex duration trace. 2018-01-30 06:27:08 +01:00
Vicente J. Botet Escriba
f01b7b5013 print diff for some timeouts. 2018-01-29 19:44:25 +01:00
Vicente J. Botet Escriba
f855cb31d1 merge from develop with some winapp merge issues. 2018-01-28 14:37:53 +01:00
Vicente J. Botet Escriba
99c2dd9cbc fix : terminating with uncaught exception of type boost::unit_test::framework::setup_error. 2018-01-28 11:33:19 +01:00
Vicente J. Botet Escriba
36807a438a Merge pull request #203 from shinobu-x/wip-thread-0001
Not *_FUNTION_* but *_FUNCTION_*
2018-01-26 07:08:36 +01:00
Shinobu Kinjo
f83e887d53 Not *_FUNTION_* but *_FUNCTION_* 2018-01-26 10:03:16 +09:00
Vicente J. Botet Escriba
57d991c36b Merge pull request #202 from shinobu-x/wip-future-0001
future.hpp: remove some unneeded declarations
2018-01-22 23:37:58 +01:00
Shinobu Kinjo
072bbee63e future.hpp:
1) Removed redundant access specifiers and unused variables in future_deferred_shared_state
2) check lock before unlock
2018-01-23 04:58:13 +09:00
Vicente J. Botet Escriba
a3cc3a016c Merge pull request #200 from kuhlenough/develop
Add CPU count for VxWorks
2018-01-12 20:43:44 +01:00
Brian Kuhl
669f652f4d Add CPU count for VxWorks 2018-01-12 01:08:11 -05:00
Vicente J. Botet Escriba
c61f3a97e2 Merge pull request #198 from Kojoley/fix-future-name-shadowing
future.hpp: Fixed name shadowing
2017-12-30 10:23:45 +01:00
Vicente J. Botet Escriba
349ec68c0f Merge pull request #199 from DanielaE/fix/no-iterator-inheritance
Inheriting std::iterator is deprecated in c++17
2017-12-30 01:48:34 +01:00
Daniela Engert
2eb9f1eb86 Inheriting std::iterator is deprecated in c++17
Therefore get rid of that and replace inheritance by lifting std::iterator's members into the derived class.

Signed-off-by: Daniela Engert <dani@ngrt.de>
2017-12-29 17:30:59 +01:00
Nikita Kniazev
7ab14ac4a3 future.hpp: Fixed name shadowing 2017-12-24 03:28:43 +03:00
Vicente J. Botet Escriba
0183e3feb8 Merge pull request #196 from austin-beer/feature/timespec_clocks_pr23_win32_time_jump_fixes
Fix final time jump issues
2017-12-21 18:41:01 +01:00
Vicente J. Botet Escriba
a0c23a608a Merge pull request #189 from gureedo/sync_patch
allow sync policy for future then continuation (fix #111)
2017-12-21 18:40:27 +01:00
Austin Beer
610c3ae071 Fix issues with v2/shared_mutex.hpp
* Fixed try_unlock_shared_and_lock_until/for() and
  try_unlock_shared_and_lock_upgrade_until/for() so that they wait on the
  correct condition variable for the associated predicate.
* Fixed try_unlock_shared_and_lock_until/for() and
  try_unlock_upgrade_and_lock_until/for() so that they take the
  write_entered_ flag before waiting for all shared readers to unlock. This
  prevents new readers from taking a shared lock or new writers from taking
  the exclusive lock while these functions are waiting to take the
  exclusive lock.
* Changed notify_all() calls to occur while the mutex is being held to be
  consistent with the notify_one() calls and the existing
  pthread/shared_mutex.hpp implementation.
* Added BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS ifdefs.
* Added BOOST_ASSERT() statements to verify correct usage and operation.
* Fixed an incorrect test case that the BOOST_ASSERT() statements
  uncovered.
* Added comments to explain certain design decisions.
2017-12-20 12:26:09 -07:00
Austin Beer
b2903a5d14 Fix v2/shared_mutex.hpp time jump issues 2017-12-20 12:14:59 -07:00
Austin Beer
81f3a78b8a Rearrange v2/shared_mutex.hpp so related functions appear together
* Added checks for BOOST_THREAD_USES_CHRONO
* Rearranged the order of the functions in v2/shared_mutex.hpp
* No changes were made to the contents of any functions
2017-12-19 14:14:17 -07:00
Vicente J. Botet Escriba
56c17adf7e Merge branch 'develop' 2017-12-19 22:04:59 +01:00
Austin Beer
e5224ee27a Fix win32 shared_mutex time jump issues 2017-12-19 09:42:54 -07:00
Austin Beer
d77affc6f5 Fix win32 mutex and recursive_mutex time jump issues
* Also added comments to the win32 mutex implementations to clarify
  how the existing code works
* Also removed a few unnecessary intermediate variables
2017-12-19 09:42:46 -07:00
Vicente J. Botet Escriba
984ec57446 Merge pull request #191 from austin-beer/feature/timespec_clocks_pr22_sync_queue_fixes
Sync queue fixes, take 2
2017-11-09 00:55:46 +01:00
Austin Beer
e96516d10d Fix sync queue time jump issues
* Used the predicate version of condition_variable::wait_until() which
  correctly handles time jump events.

* Fixed an issue with sync_timed_queue::pull_until()/pull_for() where
  they could incorrectly return queue_op_status::timeout instead of
  queue_op_status::success.

* Changed sync_timed_queue::wait_pull() to return
  queue_op_status::success instead of queue_op_status::closed when the
  queue has been closed but an item is available and is ready to be
  pulled off the queue.

* Changed sync_priority_queue::pull_until()/pull_for() and
  sync_timed_queue::pull_until()/pull_for() to return
  queue_op_status::closed instead of throwing an exception when the
  queue is closed since they have a queue_op_status return type.
2017-11-07 21:14:35 -07:00
Austin Beer
907e827046 Add support for BOOST_THREAD_V2_SHARED_MUTEX
BOOST_THREAD_V2_SHARED_MUTEX allows users to use v2/shared_mutex.hpp
instead of pthread/shared_mutex.hpp or win32/shared_mutex.hpp.
2017-11-07 16:48:59 -07:00
Aleksey Katargin
609d1a7be0 allow sync policy for future then continuation (fix #111) 2017-11-01 11:40:50 +03:00
Vicente J. Botet Escriba
d19a2499cd Merge pull request #188 from austin-beer/feature/timespec_clocks_pr20_cleanup
Cleanup
2017-10-27 08:10:05 +02:00
Vicente J. Botet Escriba
08619ef517 make use of --abbreviate-paths for windows names. 2017-10-27 08:09:04 +02:00
Vicente J. Botet Escriba
5141adee96 make use of --abbreviate-paths for windows names. 2017-10-27 08:06:12 +02:00
Austin Beer
1e84b978b2 Use CLOCK_MONOTONIC by default
- Eliminated BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC.
- CLOCK_MONOTONIC is now always used whenever it is available.
2017-10-26 08:07:49 -06:00
Austin Beer
a0f216bb2b Update timed tests to use stricter threshold with pthreads 2017-10-26 07:54:37 -06:00
Austin Beer
2de04292da Rename CD to common_duration to match Boost Chrono
See https://github.com/boostorg/chrono/pull/23
2017-10-26 07:54:04 -06:00
Austin Beer
c50428f612 Use direct initialization instead of assignment 2017-10-26 07:53:49 -06:00
Austin Beer
b4348b3cff Clean up detail/thread.hpp so all of the chrono functions are together 2017-10-26 07:53:37 -06:00
Austin Beer
fea3e33128 Remove empty v2/thread.hpp file 2017-10-26 07:53:24 -06:00
Austin Beer
d60a11a75b Delete unused file: pthread/shared_mutex_assert.hpp 2017-10-26 07:53:15 -06:00
Austin Beer
cfd93c7747 Correct a fix that I previously implemented incorrectly 2017-10-26 07:52:42 -06:00
Vicente J. Botet Escriba
6d8c0676a1 Merge pull request #187 from Lastique/update_winapi
Update Boost.WinAPI usage to the new location and namespace
2017-10-25 19:36:05 +02:00
Andrey Semashev
343230cd78 Updated Boost.WinAPI usage to the new location and namespace. 2017-10-25 01:09:24 +03:00
Vicente J. Botet Escriba
44080a444c update release notes. 2017-10-24 21:02:01 +02:00
Vicente J. Botet Escriba
6d7bc558d0 Implement mono_platform_clock and mono_platform_timepoint fro MacOs. 2017-10-23 22:40:49 +02:00
Vicente J. Botet Escriba
007738d22c Merge branch 'feature/timespec_clocks' of github.com:boostorg/thread into feature/timespec_clocks 2017-10-15 18:28:05 +02:00
Vicente J. Botet Escriba
6ddf6a8acf Merge pull request #180 from austin-beer/feature/timespec_clocks_pr19_no_int_sleep_on_win
Add and fix sleep functions
2017-10-15 18:27:19 +02:00
Vicente J. Botet Escriba
f9e97a68bb Merge branch 'feature/timespec_clocks' of github.com:boostorg/thread into feature/timespec_clocks 2017-10-15 10:17:12 +02:00
Vicente J. Botet Escriba
44d410f067 disable C4459 on msvc. 2017-10-15 10:14:39 +02:00
Vicente J. Botet Escriba
48ceff1e65 Merge pull request #179 from austin-beer/feature/timespec_clocks_pr18_use_pred_overloads
Fix shared_mutex and future time jump tests
2017-10-14 19:10:36 +02:00
Vicente J. Botet Escriba
883637e0f4 try to avoid warning c4244 for msvc. 2017-10-14 13:09:17 +02:00
Austin Beer
3c01e39481 Add and fix sleep functions
- Added no_interruption_point::sleep() functions to pthreads to be
  consistent with Windows.
- Fixed an issue where the no_interruption_point::sleep_*() functions
  were still interruptible on Windows.
2017-10-13 11:48:05 -06:00
Austin Beer
eef7293932 Updated pthread/shared_mutex and future to use predicate wait functions.
- This allowed these classes to take advantage of the time jump fixes in condition_variable.
Fixed a minor issue where, if a thread was waiting after calling one of the following functions and it timed out at the same time it was given the lock, it would return false (failure) rather than succeeding.
- mutex::timed_lock()
- mutex::try_lock_for()
- mutex::try_lock_until()
- recursive_mutex::timed_lock()
- recursive_mutex::try_lock_for()
- recursive_mutex::try_lock_until()
- shared_mutex::timed_lock_shared()
- shared_mutex::try_lock_shared_for()
- shared_mutex::try_lock_shared_until()
2017-10-13 11:47:46 -06:00
Austin Beer
b65b2f3fea Reverted future.hpp and pthread/shared_mutex.hpp back to the versions in the develop branch. This discarded all changes made to these two files in the feature/timespec_clocks branch to date. 2017-10-13 11:47:46 -06:00
Vicente J. Botet Escriba
d70e1aad77 Merge pull request #178 from austin-beer/feature/timespec_clocks_pr17
Update tests to consistently pass on Windows (hopefully)
2017-10-13 19:35:52 +02:00
Austin Beer
2272e9e3f5 Updated more tests to pass consistently on Windows. 2017-10-12 10:48:01 -06:00
Austin Beer
d259e0fde4 Increased the time thresholds on a bunch of tests to be more forgiving so they pass consistently on Windows.
Reduced the time thresholds on a bunch of tests that were TOO forgiving.
2017-10-11 21:40:38 -06:00
Vicente J. Botet Escriba
ac99313228 Merge pull request #177 from austin-beer/feature/timespec_clocks_pr16
Fixing lost notification bugs, part 1 (again)
2017-10-11 22:08:25 +02:00
Austin Beer
7069c97a8b Fixing lost notification bugs, part 1
- Updated all of the functions in all of the condition variable classes to ensure that they don't lose notifications
- Re-enabled notification tests
2017-10-11 10:03:04 -06:00
Vicente J. Botet Escriba
3b5d0c8d7f fix meger issues from develop. Disable notification_lost test as need to be fixed for macos. 2017-10-11 09:32:19 +02:00
Vicente J. Botet Escriba
d2498547a7 Merge pull request #176 from austin-beer/feature/timespec_clocks_pr15
Added tests to check for lost notifications.
2017-10-11 08:31:56 +02:00
Austin Beer
c91c9e6d52 Added tests to check for lost notifications. 2017-10-10 12:06:29 -06:00
Vicente J. Botet Escriba
f794d5a9d1 Merge pull request #168 from austin-beer/feature/timespec_clocks_pr13
Renaming timespec to platform
2017-10-03 07:29:06 +02:00
Vicente J. Botet Escriba
e3f586836a check > 480 instead of > 500. 2017-10-02 19:06:52 +02:00
Austin Beer
82e2c82e95 Renaming timespec to platform 2017-10-02 09:23:54 -06:00
Vicente J. Botet Escriba
3479524845 trace elapsed time. 2017-10-02 13:18:33 +02:00
Vicente J. Botet Escriba
178e0661ab fix bad clock:: use, shoudl be chrono::steady_clock. 2017-10-02 08:59:41 +02:00
Vicente J. Botet Escriba
b94c36f960 move to 650 ms to see if the test pass. 2017-10-02 08:41:39 +02:00
Vicente J. Botet Escriba
9f7e37c892 Merge branch 'develop' into feature/timespec_clocks 2017-10-01 13:28:57 +02:00
Vicente J. Botet Escriba
e7d6055ed3 Merge pull request #167 from austin-beer/feature/timespec_clocks_pr12
Fixes and Cleanup
2017-10-01 10:15:31 +02:00
Austin Beer
659d309206 Re-enabled tests on Windows that had been temporarily disabled. 2017-09-29 15:53:21 -06:00
Austin Beer
847dcbf237 Removed unnecessary explicit qualifiers. 2017-09-29 15:28:04 -06:00
Austin Beer
35d25851ce * Reverted some of my Windows updates to get a condition variable test on Windows to pass again. Further analysis is needed to determine why the updates didn't work.
* Increased the range of one test so it passes on Windows.
2017-09-29 14:52:42 -06:00
Austin Beer
5ffca91e60 * Hopefully fixed the build failure on Mac OS.
* Refactored to use timespec as the internal storage with pthread and intmax_t with Windows.
2017-09-29 10:22:01 -06:00
Austin Beer
51e6e654e3 Re-disabled the three move_ctor_upgrade_lock tests on Windows that are still failing. 2017-09-29 02:17:58 -06:00
Austin Beer
3c25ad09ce Attempting to fix build errors on Windows. 2017-09-29 00:34:47 -06:00
Austin Beer
a2e037bb54 Fixes and Cleanup
- Fixed build failures on Windows. The timespec struct is not supported by older versions of Visual Studio. I changed the internal representation inside of the *_timespec_timepoint classes to a boost::intmax_t representing the number of nanoseconds since the epoch.
- Fixed some functions that wouldn't execute at all if they were provided a negative time duration or an absolute time that was in the past. From what I understand, they should instead execute once and then return immediately.
- Moved pthread/timespec.hpp to detail/timespec.hpp.
- Deleted detail/internal_clock.hpp and moved the seven relevant lines into detail/timespec.hpp. This keeps all of the internal clock declarations in one place.
- Renamed thread_detail::internal_clock_t to detail::internal_chrono_clock to be consistent with and yet clearly differentiated from detail::internal_timespec_clock.
- Removed "using namespace chrono" to eliminate ambiguious namespace resolution when referencing detail::internal_chrono_clock.
- Re-enabled a few tests on Windows that had previously been disabled. I want to see whether or not they still need to be disabled.
2017-09-28 22:27:37 -06:00
Vicente J. Botet Escriba
a4a21b1c12 Merge pull request #166 from austin-beer/feature/timespec_clocks_pr11
Switching the Windows condition_variable and interruptible_wait functions over to using internal_timespec_clock.
2017-09-29 01:56:58 +02:00
Austin Beer
c2b207faa4 Switching the Windows condition_variable and interruptible_wait functions over to using internal_timespec_clock. 2017-09-28 13:24:21 -06:00
Vicente J. Botet Escriba
68abb96818 Merge pull request #165 from austin-beer/feature/timespec_clocks_pr10
Added support for getting time on Windows to the timespec classes.
2017-09-28 08:17:23 +02:00
Austin Beer
29c3b48da0 Switching over to using the existing GetTickCount64() code for reporting monotonic time on Windows. This code is less precise than QueryPerformanceCounter(), but it's more reliable on older versions of Windows (e.g. XP and Server 2003). 2017-09-27 15:40:50 -06:00
Austin Beer
13713f3b9c Added support for getting time on Windows to the timespec classes. 2017-09-27 10:52:53 -06:00
Vicente J. Botet Escriba
776d42f6cb Merge branch 'develop' into feature/timespec_clocks 2017-09-26 08:01:28 +02:00
Vicente J. Botet Escriba
46c1ae6f96 Merge branch 'develop' into feature/timespec_clocks 2017-09-26 05:55:40 +02:00
Vicente J. Botet Escriba
fb0317ec7d Merge pull request #164 from austin-beer/feature/timespec_clocks_pr8
Fixed compile issue on Windows
2017-09-25 19:25:38 +02:00
Austin Beer
417a2d8a46 Fixed compile issue on Windows. 2017-09-25 11:15:09 -06:00
Vicente J. Botet Escriba
ce7f2b09cc try to use again pthread/shared_mutex.hpp on windows. Comment not used functions in timespec. 2017-09-25 12:52:25 +02:00
Vicente J. Botet Escriba
e6226a95ba try to fix future wait on posix duration. 2017-09-25 08:39:45 +02:00
Vicente J. Botet Escriba
aa221d02b5 try to fix issues on linu-mono mutex operation on system_time. 2017-09-25 00:18:12 +02:00
Vicente J. Botet Escriba
de4ee72554 disable some failing unique_lock/upgrade_lock tests on windows. 2017-09-24 20:21:43 +02:00
Vicente J. Botet Escriba
ad5ea75ddd disable tsome failing unique_lock/upgrade_lock tests on windows. 2017-09-24 19:38:34 +02:00
Vicente J. Botet Escriba
dd1b5282b2 try to fix issues with windows and shared_mutex. 2017-09-24 17:29:27 +02:00
Vicente J. Botet Escriba
45321f0570 try to fix issues with new pthread/shared_mutex.hpp on windows by disabling the use of the pthread version that now depends on timespec. 2017-09-24 16:31:42 +02:00
Vicente J. Botet Escriba
bafc9f43a5 try to fix DateTime time related issues on pthread/shared_mutex.hpp. 2017-09-24 08:12:02 +02:00
Vicente J. Botet Escriba
b98d022d40 try to fix DatTime related functions for mutex/recursive_mutex. 2017-09-23 08:42:02 +02:00
Vicente J. Botet Escriba
f2d6d99d54 Merge pull request #161 from austin-beer/feature/timespec_clocks_pr7
Finished fixing the condition_variable[_any] timed_wait() functions.
2017-09-23 07:00:11 +02:00
Austin Beer
aeb54ddbe5 Finished fixing the condition_variable[_any] timed_wait() functions. 2017-09-22 14:22:06 -06:00
Vicente J. Botet Escriba
4d385bedd3 try to fix condition_variable::timed_wait for pthread. 2017-09-22 04:18:55 +02:00
Vicente J. Botet Escriba
03a2ea4612 Merge pull request #159 from austin-beer/feature/timespec_clocks_pr6
Fixed try_join_* and timed_join functions that were failing time jump tests
2017-09-22 00:37:20 +02:00
Austin Beer
c290fc5f98 Deleted an unused function and added some fixme comments. 2017-09-21 12:59:09 -06:00
Austin Beer
23861b9608 Fixed try_lock_*for() and wait_for() functions that were failing time jump tests. 2017-09-21 12:08:20 -06:00
Austin Beer
24fd5953c9 Fixed timed_join on Windows when the system clock jumps. 2017-09-21 11:27:36 -06:00
Austin Beer
8f51d9c4a7 Fixed try_join_* and timed_join functions that were failing time jump tests 2017-09-21 10:56:53 -06:00
Vicente J. Botet Escriba
5dcc5f6d26 Merge branch 'develop' into feature/timespec_clocks 2017-09-21 18:53:52 +02:00
Vicente J. Botet Escriba
70a4ce8eb3 Merge pull request #158 from austin-beer/feature/timespec_clocks_pr5
Timespec Improvements, Minor Cleanup
2017-09-21 18:50:42 +02:00
Austin Beer
8207b88e97 Made function static 2017-09-21 10:48:58 -06:00
Austin Beer
de7e354a8e Improved the timespec implementation
* Added a constructor to timespec_duration, real_timespec_timepoint, and mono_timespec_timepoint that takes an intmax_t representing the number of nanoseconds in the timespec.
* Added a getNs() function to timespec_duration, real_timespec_timepoint, and mono_timespec_timepoint that returns an intmax_t representing the number of nanoseconds in the timespec.
* Added a timespec_milliseconds() function that takes an integer representing milliseconds and returns a timespec_duration.
* Removed some unnecessary BOOST_SYMBOL_VISIBLE declarations.
* Removed the unnecessary d100 variable declarations.
2017-09-21 09:28:18 -06:00
Vicente J. Botet Escriba
bad686d620 Merge pull request #155 from austin-beer/feature/timespec_clocks_pr4
Chrono-related optimizations
2017-09-21 07:57:12 +02:00
Austin Beer
2f1b1c4d44 Missed a file in the previous commit. 2017-09-20 12:49:22 -06:00
Austin Beer
d8f24d9183 Fixed an issue where the results of Chrono arithmetic operations weren't being assigned to a common type that's guaranteed to compile. 2017-09-20 12:49:22 -06:00
Austin Beer
0fa843532e Eliminated unnecessary convertions to chrono::nanoseconds 2017-09-20 12:49:21 -06:00
Vicente J. Botet Escriba
7b49f3f354 Merge pull request #154 from austin-beer/feature/timespec_clocks_pr3
Cleanup
2017-09-20 20:43:36 +02:00
Austin Beer
e6f876e830 More Cleanup
* Deleted unused sleep_for() overload in pthread/thread_data.hpp.
* Deleted unused and disabled sleep_for() overloads in win32/thread_data.hpp.
2017-09-20 10:10:17 -06:00
Austin Beer
285d35f43f Cleanup
* Deleted a couple of unnecessary calls to internal_clock_t::now() in v2/thread.hpp.
* Deleted the hidden::sleep_until() functions, which are no longer being used.
* Deleted the condition_variable::do_wait_for() function, which is no longer being used.
* Deleted the sleep_mutex and sleep_condition variables in pthread/thread_data.hpp, which are no longer being used.
2017-09-19 16:12:22 -06:00
Vicente J. Botet Escriba
a18dfa1fea Merge branch 'feature/timespec_clocks' of github.com:boostorg/thread into feature/timespec_clocks 2017-09-19 23:46:45 +02:00
Vicente J. Botet Escriba
f5ccff5b6e Merge pull request #153 from austin-beer/feature/timespec_clocks_pr2
Fixed sleep(TimeDuration const& rel_time)
2017-09-19 23:45:45 +02:00
Austin Beer
a9706f0745 Fixed sleep(TimeDuration const& rel_time) when internal clock is not monotonic but CLOCK_MONOTONIC is available. 2017-09-19 15:06:06 -06:00
Vicente J. Botet Escriba
8e718893e5 Merge branch 'feature/timespec_clocks' of github.com:boostorg/thread into feature/timespec_clocks 2017-09-19 22:09:38 +02:00
Vicente J. Botet Escriba
f56bc930bc Merge pull request #151 from austin-beer/timespec_clocks_pr1
Updates to fix interruption-point inconsistencies.
2017-09-19 22:08:48 +02:00
Austin Beer
f1dec7935f Rearranged a couple of functions to simplify the #if/#else logic. 2017-09-19 13:22:13 -06:00
Austin Beer
aebbcda3fe Updates to fix interruption-point inconsistencies.
* Fixed the interruption-point versions of sleep_for/sleep_until() to always use condition variables.
* Fixed the no-interruption-point versions of sleep_for/sleep_until() to use pthread_delay_np or nanosleep whenever possible.
* Updated hidden::sleep_for() to always use a condition variable.
* Updated no_interruption_point::hidden::sleep_for() to use pthread_delay_np or nanosleep whenever possible.
2017-09-19 09:04:57 -06:00
Vicente J. Botet Escriba
5b4d230d4a Merge branch 'develop' into feature/timespec_clocks 2017-09-19 13:01:20 +02:00
Vicente J. Botet Escriba
6b174a3419 Merge branch 'develop' into feature/timespec_clocks 2017-09-18 19:11:38 +02:00
Vicente J. Botet Escriba
9813c81ef3 Added missing include. 2017-09-18 02:44:37 +02:00
Vicente J. Botet Escriba
e2b9ce78c2 use -j3 with appveyor. 2017-09-17 23:06:40 +02:00
Vicente J. Botet Escriba
576231942d Merge branch 'develop' into feature/timespec_clocks 2017-09-17 22:40:59 +02:00
Vicente J. Botet Escriba
82eed2ca6d make use of do_wait_until when BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC is defined as proposed by Austin Beer.. 2017-09-17 19:09:09 +02:00
Vicente J. Botet Escriba
56016e8348 reinplement sleep(system_time) as proposed by Austin Beer. 2017-09-17 19:08:51 +02:00
Vicente J. Botet Escriba
b6b6a6944a remove redundant chrono:: 2017-09-17 18:45:05 +02:00
Vicente J. Botet Escriba
14deba107f minor chnages. 2017-09-07 22:41:31 +02:00
Vicente J. Botet Escriba
ef81bd2e0b Merge branch 'develop' into feature/timespec_clocks 2017-09-07 00:31:40 +02:00
Vicente J. Botet Escriba
99e2867a21 add missing t-d100 as reported by Autin. 2017-09-06 23:39:29 +02:00
Vicente J. Botet Escriba
6805c7fcb6 fix timed mutex chrono time related functions. 2017-09-06 22:57:34 +02:00
Vicente J. Botet Escriba
24b1636615 try a fix for sleep_for/sleep_until on linux. 2017-09-06 12:57:09 +02:00
Vicente J. Botet Escriba
c67f4b08a0 try to fix QOI issues reported by Austin Bear for condition_variable/condition_variable_any with chrono interface. 2017-09-06 00:06:33 +02:00
Vicente J. Botet Escriba
5c51abc92f fix windows issues reported by Austin Bear. 2017-09-05 23:39:50 +02:00
Vicente J. Botet Escriba
078bd570c8 Iterate while waiting until on condition variables. 2017-09-05 12:49:41 +02:00
Vicente J. Botet Escriba
b1991924b7 fix compile issue on windows. 2017-09-05 12:48:13 +02:00
Vicente J. Botet Escriba
fa1965a87c comment unuseful/redundant code 2017-09-05 12:47:32 +02:00
Vicente J. Botet Escriba
d00933d5f4 Windows has an internal steady clock. 2017-09-05 12:46:34 +02:00
Vicente J. Botet Escriba
81fe14fda2 Update after test from brainwave64. 2017-09-04 07:35:33 +02:00
Vicente J. Botet Escriba
13d293829c Update after test from brainwave64. 2017-09-04 01:48:36 +02:00
Vicente J. Botet Escriba
a6d5b5e576 Use internal clock whenever possible. 2017-09-03 16:17:45 +02:00
Vicente J. Botet Escriba
1063638763 Replace timespec by specific clock/timepoint/duration like classes that represent the monotonic, the real or the one used internaly at the platform level. Make use of these clocks/timepoints/durations almost all around. Need to replace yet all the occurrences of get_system_time(). 2017-09-02 14:42:25 +02:00
191 changed files with 8903 additions and 4535 deletions

View File

@@ -30,7 +30,7 @@ matrix:
include:
- os: linux
compiler: g++
env: TOOLSET=gcc COMPILER=g++ CXXSTD=c++11
env: TOOLSET=gcc COMPILER=g++ CXXSTD=c++11 SELF_CONTAINED_HEADER_TESTS=1
# - os: linux
# compiler: g++-4.7
@@ -331,38 +331,43 @@ matrix:
- os: osx
compiler: clang++
env: TOOLSET=clang COMPILER=clang++ CXXSTD=c++98
env: TOOLSET=clang COMPILER=clang++ CXXSTD=c++98 SELF_CONTAINED_HEADER_TESTS=1
- os: osx
compiler: clang++
env: TOOLSET=clang COMPILER=clang++ CXXSTD=c++11
# - os: osx
# compiler: clang++
# env: TOOLSET=clang COMPILER=clang++ CXXSTD=c++11
- os: osx
compiler: clang++
env: TOOLSET=clang COMPILER=clang++ CXXSTD=c++14
# - os: osx
# compiler: clang++
# env: TOOLSET=clang COMPILER=clang++ CXXSTD=c++14
- os: osx
compiler: clang++
env: TOOLSET=clang COMPILER=clang++ CXXSTD=c++1z
install:
- BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
- GIT_FETCH_JOBS=8
- BOOST_BRANCH=develop
- if [ "$TRAVIS_BRANCH" = "master" ]; then BOOST_BRANCH=master; fi
- cd ..
- git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
- cd boost-root
- git submodule update --init tools/build
- git submodule update --init libs/config
- git submodule update --init tools/boostdep
- git submodule init tools/build
- git submodule init libs/config
- git submodule init tools/boostdep
- git submodule update --jobs $GIT_FETCH_JOBS
- mkdir -p libs/thread
- cp -r $TRAVIS_BUILD_DIR/* libs/thread
- python tools/boostdep/depinst/depinst.py thread
- python tools/boostdep/depinst/depinst.py --git_args "--jobs $GIT_FETCH_JOBS" thread
- ./bootstrap.sh
- ./b2 headers
script:
- |-
echo "using $TOOLSET : : $COMPILER : <cxxflags>-std=$CXXSTD ;" > ~/user-config.jam
- ./b2 -j3 libs/thread/test toolset=$TOOLSET
- BUILD_JOBS=`(nproc || sysctl -n hw.ncpu) 2> /dev/null`
- if [ -z "$SELF_CONTAINED_HEADER_TESTS" ]; then export BOOST_THREAD_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS=1; fi
- ./b2 -j $BUILD_JOBS -l60 libs/thread/test toolset=$TOOLSET
notifications:
email:

View File

@@ -1,4 +1,5 @@
# Copyright 2016, 2017 Peter Dimov
# Copyright 2016-2018 Peter Dimov
# Copyright 2018 Vicente Botet
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
@@ -12,68 +13,61 @@ branches:
- develop
- /feature\/.*/
platform:
- x64
environment:
matrix:
- ARGS: --toolset=msvc-9.0 address-model=32
- ARGS: --toolset=msvc-10.0 address-model=32
- ARGS: --toolset=msvc-11.0 address-model=32
- ARGS: --toolset=msvc-12.0 address-model=32
- ARGS: --toolset=msvc-14.0 address-model=32
- ARGS: --toolset=msvc-12.0 address-model=64
- ARGS: --toolset=msvc-14.0 address-model=64
- ARGS: --toolset=msvc-14.0 address-model=64 cxxflags=-std:c++latest
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
# TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0,msvc-12.0
TOOLSET: msvc-12.0
SELF_CONTAINED_HEADER_TESTS: 1
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
TOOLSET: msvc-14.0
ADDRMD: 32
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
ARGS: --toolset=msvc-14.1 address-model=64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
ARGS: --toolset=msvc-14.1 address-model=32
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
ARGS: --toolset=msvc-14.1 address-model=64 cxxflags=-std:c++latest
- ARGS: --toolset=gcc address-model=64
PATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin;%PATH%
- ARGS: --toolset=gcc address-model=64 cxxflags=-std=gnu++1z
PATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin;%PATH%
- ARGS: --toolset=gcc address-model=32
PATH: C:\mingw-w64\i686-5.3.0-posix-dwarf-rt_v4-rev0\mingw32\bin;%PATH%
- ARGS: --toolset=gcc address-model=32 linkflags=-Wl,-allow-multiple-definition
PATH: C:\MinGW\bin;%PATH%
# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
# ARGS: --toolset=msvc-9.0
# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
# ARGS: --toolset=msvc-10.0
# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
# ARGS: --toolset=msvc-11.0
# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
# ARGS: --toolset=msvc-12.0
# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
# ARGS: --toolset=msvc-14.0
# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
# ARGS: --toolset=msvc-14.1
TOOLSET: msvc-14.1
CXXSTD: 17
ADDRMD: 64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
ADDPATH: C:\cygwin\bin;
TOOLSET: gcc
CXXSTD: 14
SELF_CONTAINED_HEADER_TESTS: 1
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
ADDPATH: C:\cygwin64\bin;
TOOLSET: gcc
CXXSTD: 14
SELF_CONTAINED_HEADER_TESTS: 1
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
ADDPATH: C:\mingw\bin;
TOOLSET: gcc
CXXSTD: 14
SELF_CONTAINED_HEADER_TESTS: 1
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
ADDPATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin;
TOOLSET: gcc
CXXSTD: 14
SELF_CONTAINED_HEADER_TESTS: 1
install:
- set GIT_FETCH_JOBS=8
- set BOOST_BRANCH=develop
- if "%APPVEYOR_REPO_BRANCH%" == "master" set BOOST_BRANCH=master
- cd ..
- git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
- cd boost-root
- git submodule update --init tools/build
- git submodule update --init libs/config
- git submodule update --init tools/boostdep
- xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\thread\
- python tools/boostdep/depinst/depinst.py thread
- git submodule init tools/build
- git submodule init libs/config
- git submodule init tools/boostdep
- git submodule update --jobs %GIT_FETCH_JOBS%
- xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\thread
- python tools/boostdep/depinst/depinst.py --git_args "--jobs %GIT_FETCH_JOBS%" thread
- cmd /c bootstrap
- b2 headers
- b2 -d0 headers
build: off
test_script:
- cd libs\config\test
- ..\..\..\b2 config_info_travis_install %ARGS%
- config_info_travis
- cd ..\..\thread\test
- ..\..\..\b2 -j3 %ARGS%
- PATH=%ADDPATH%%PATH%
- if "%SELF_CONTAINED_HEADER_TESTS%" == "" set BOOST_THREAD_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS=1
- if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
- if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
- b2 -j %NUMBER_OF_PROCESSORS% libs/thread/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release

View File

@@ -38,6 +38,8 @@ import path ;
import configure ;
import threadapi-feature ;
exe has_atomic_flag_lockfree : ../build/has_atomic_flag_lockfree_test.cpp ;
project boost/thread
: source-location ../src
: requirements <threading>multi
@@ -52,7 +54,6 @@ project boost/thread
#<define>BOOST_SYSTEM_NO_DEPRECATED
#<define>BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
<library>/boost/system//boost_system
#-pedantic -ansi -std=gnu++0x -Wextra -fpermissive
<warnings>all
<toolset>gcc:<cxxflags>-Wextra
@@ -138,11 +139,8 @@ project boost/thread
#<define>BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
#<define>BOOST_SYSTEM_NO_DEPRECATED
#<define>BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
<library>/boost/system//boost_system
;
exe has_atomic_flag_lockfree : ../build/has_atomic_flag_lockfree_test.cpp ;
rule tag ( name : type ? : property-set )
{
local result = $(name) ;
@@ -238,6 +236,10 @@ rule usage-requirements ( properties * )
# in that case?
}
}
if <threadapi>win32 in $(properties)
{
result += <define>BOOST_THREAD_WIN32 ;
}
#if ! <toolset>vacpp in $(properties) || <toolset-vacpp:version>11.1 in $(properties) || <toolset-vacpp:version>12.1.0.1 in $(properties) || <toolset-vacpp:version>12.1 in $(properties)
#{
@@ -272,6 +274,10 @@ rule requirements ( properties * )
result += <library>/boost/atomic//boost_atomic ;
}
} else {
if <threadapi>win32 in $(properties)
{
result += <define>BOOST_THREAD_WIN32 ;
}
result += <define>BOOST_THREAD_USES_CHRONO ;
result += <library>/boost/chrono//boost_chrono ;
}
@@ -284,6 +290,7 @@ alias thread_sources
win32/thread.cpp
win32/tss_dll.cpp
win32/tss_pe.cpp
win32/thread_primitives.cpp
future.cpp
: ## requirements ##
<threadapi>win32

177
circle.yml Normal file
View File

@@ -0,0 +1,177 @@
# Copyright 2018 Tom Hughes
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
build_steps: &build_steps
steps:
- run:
name: Setup
command: |
PLATFORM=`uname`
if [ "${PLATFORM}" == "Linux" ]; then
sudo apt-get install -y software-properties-common apt-transport-https
# https://github.com/ilikenwf/apt-fast
sudo add-apt-repository -y ppa:apt-fast/stable
sudo apt-get update
sudo apt-get -y install apt-fast
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
echo "deb https://apt.llvm.org/trusty/ llvm-toolchain-trusty-4.0 main" | sudo tee -a /etc/apt/sources.list
echo "deb https://apt.llvm.org/trusty/ llvm-toolchain-trusty-5.0 main" | sudo tee -a /etc/apt/sources.list
echo "deb https://apt.llvm.org/trusty/ llvm-toolchain-trusty-6.0 main" | sudo tee -a /etc/apt/sources.list
sudo apt-fast update
sudo apt-fast install -y $COMPILER
fi
- checkout
- run:
name: Install
command: |
BOOST_BRANCH=develop && [ "$CIRCLE_BRANCH" == "master" ] && BOOST_BRANCH=master || true
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
git submodule update --init tools/build
git submodule update --init libs/config
git submodule update --init tools/boostdep
mkdir -p libs/thread
cp -r $HOME/project/* libs/thread
python tools/boostdep/depinst/depinst.py thread
./bootstrap.sh
./b2 headers
- run:
name: Build
command: |
echo "using $TOOLSET : : $COMPILER : <cxxflags>-std=$CXXSTD <cxxflags>$CXXFLAGS <cxxflags>$DEFINES ;" > ~/user-config.jam
cd ../boost-root
./b2 -d2 -j8 -l60 libs/thread/test toolset=$TOOLSET
mac_build: &mac_build
macos:
xcode: "9.2.0"
<<: *build_steps
linux_build: &linux_build
docker:
- image: circleci/buildpack-deps:trusty
<<: *build_steps
version: 2
jobs:
linux-g++-c++11:
<<: *linux_build
environment:
- TOOLSET: "gcc"
- COMPILER: "g++"
- CXXSTD: "c++11"
linux-g++-7-c++98:
<<: *linux_build
environment:
- TOOLSET: "gcc"
- COMPILER: "g++-7"
- CXXSTD: "c++98"
linux-g++-7-c++11:
<<: *linux_build
environment:
- TOOLSET: "gcc"
- COMPILER: "g++-7"
- CXXSTD: "c++11"
linux-g++-7-c++14:
<<: *linux_build
environment:
- TOOLSET: "gcc"
- COMPILER: "g++-7"
- CXXSTD: "c++14"
linux-g++-7-c++1z:
<<: *linux_build
environment:
- TOOLSET: "gcc"
- COMPILER: "g++-7"
- CXXSTD: "c++1z"
linux-clang++-4.0-c++98:
<<: *linux_build
environment:
- TOOLSET: "clang"
- COMPILER: "clang++-4.0"
- CXXSTD: "c++98"
linux-clang++-4.0-c++11:
<<: *linux_build
environment:
- TOOLSET: "clang"
- COMPILER: "clang++-4.0"
- CXXSTD: "c++11"
linux-clang++-4.0-c++14:
<<: *linux_build
environment:
- TOOLSET: "clang"
- COMPILER: "clang++-4.0"
- CXXSTD: "c++14"
linux-clang++-4.0-c++1z:
<<: *linux_build
environment:
- TOOLSET: "clang"
- COMPILER: "clang++-4.0"
- CXXSTD: "c++1z"
mac-clang++-c++98:
<<: *mac_build
environment:
- TOOLSET: "clang"
- COMPILER: "clang++"
- CXXSTD: "c++98"
- DEFINES: "-DBOOST_THREAD_TEST_TIME_MS=100"
mac-clang++-c++11:
<<: *mac_build
environment:
- TOOLSET: "clang"
- COMPILER: "clang++"
- CXXSTD: "c++11"
- CXXFLAGS: "-Wno-unusable-partial-specialization"
- DEFINES: "-DBOOST_THREAD_TEST_TIME_MS=100"
mac-clang++-c++14:
<<: *mac_build
environment:
- TOOLSET: "clang"
- COMPILER: "clang++"
- CXXSTD: "c++14"
- DEFINES: "-DBOOST_THREAD_TEST_TIME_MS=100"
mac-clang++-c++1z:
<<: *mac_build
environment:
- TOOLSET: "clang"
- COMPILER: "clang++"
- CXXSTD: "c++1z"
- CXXFLAGS: "-Wno-unusable-partial-specialization"
- DEFINES: "-DBOOST_THREAD_TEST_TIME_MS=100"
workflows:
version: 2
continous:
jobs:
- linux-g++-c++11
- linux-g++-7-c++98
- linux-g++-7-c++11
- linux-g++-7-c++14
- linux-g++-7-c++1z
- linux-clang++-4.0-c++98
- linux-clang++-4.0-c++11
- linux-clang++-4.0-c++14
- linux-clang++-4.0-c++1z
- mac-clang++-c++98
- mac-clang++-c++11
- mac-clang++-c++14
- mac-clang++-c++1z

View File

@@ -1526,7 +1526,7 @@ A thread pool with up to a fixed number of threads.
[variablelist
[[Effects:] [Destroys the thread pool.]]
[[Effects:] [Interrupts and joins all the threads and then destroys the threads.]]
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]

View File

@@ -1,6 +1,6 @@
[/
(C) Copyright 2007-11 Anthony Williams.
(C) Copyright 2011-17 Vicente J. Botet Escriba.
(C) Copyright 2011-18 Vicente J. Botet Escriba.
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).
@@ -8,6 +8,57 @@
[section:changes History]
[heading Version 4.9.0 - boost 1.70]
[*Know Bugs:]
* [@http://svn.boost.org/trac/boost/ticket/3926 #3926] thread_specific_ptr + dlopen library causes a SIGSEGV.
* [@http://svn.boost.org/trac/boost/ticket/10964 #10964] future<future<T>>::unwrap().then() Deadlocks
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state.
Please take a look at [@http://www.boost.org/development/tests/master/developer/thread.html thread master regression test] to see the last regression test snapshot.
[*Fixed Bugs:]
* [@https://github.com/boostorg/thread/pull/268] Add self contained header tests and fix discovered bugs
* Improvements support for cygwin platform using the pthread interface.
* [@https://github.com/boostorg/thread/pull/263] Fix compilation of timed functions on Cygwin
$ [@https://github.com/boostorg/thread/pull/262] Fix MinGW warnings about violation of the strict aliasing rules
* [@https://github.com/boostorg/thread/pull/260] Fix "interruption_point" defined twice.
* [@https://github.com/boostorg/thread/pull/249] Simplify TSS cleanup routines. Fixes #236
[*New Experimental Features:]
* Since BOOST_THREAD_VERSION 5, BOOST_THREAD_USES_EXECUTOR is defined by default.
* [@https://github.com/boostorg/thread/pull/266] Remove linking with Boost.System
[heading Version 4.8.1 - boost 1.67]
[*Know Bugs:]
* [@http://svn.boost.org/trac/boost/ticket/3926 #3926] thread_specific_ptr + dlopen library causes a SIGSEGV.
* [@http://svn.boost.org/trac/boost/ticket/10964 #10964] future<future<T>>::unwrap().then() Deadlocks
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state.
Please take a look at [@http://www.boost.org/development/tests/master/developer/thread.html thread master regression test] to see the last regression test snapshot.
[*Fixed Bugs:]
* [@https://github.com/boostorg/thread/issues/162 #162] fix as much time-related issues as possible and improve the QOI
* [@https://github.com/boostorg/thread/issues/193 #193] future_then unit test contains two different implementations of do_continuation function
* [@https://github.com/boostorg/thread/issues/209 #209] Legal problem with `win32/thread_primitives.hpp`
[heading Version 4.8.0 - boost 1.66]
[*Know Bugs:]
@@ -22,14 +73,29 @@ Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&s
Please take a look at [@http://www.boost.org/development/tests/master/developer/thread.html thread master regression test] to see the last regression test snapshot.
[*Fixed Bugs:]
* [@http://svn.boost.org/trac/boost/ticket/12323 #12323] windows - boost/thread/win32/mfc_thread_init.hpp has wrong signature for _pRawDllMainOrig
* [@http://svn.boost.org/trac/boost/ticket/12730 #12730] windows - static threads library is incompatible with MSVC 2017 RC
* [@http://svn.boost.org/trac/boost/ticket/12976 #12976] Boost Thread Executors documentation mistakes
* [@http://svn.boost.org/trac/boost/ticket/12949 #12949] using sleep_for in a thread context without including boost/thread/thread.hpp yields incorrect behaviour when BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC is defined
* [@http://svn.boost.org/trac/boost/ticket/13019 #13019] ABI compatibility for BOOST_THREAD_PROVIDES_INTERRUPTIONS incomplete
* [@http://svn.boost.org/trac/boost/ticket/13069 #13069] Boost unit test "sync_pq_multi_thread_p_lib.exe" hung in thread library
* [@http://svn.boost.org/trac/boost/ticket/13163 #13163] boost::detail::heap_new does not have a variadic variant
* [@http://svn.boost.org/trac/boost/ticket/13226 #13226] getpagesize() is deprecated since 199506L
* [@https://github.com/boostorg/thread/issues/132 #132] VS 2017.4 Preview deadlocks on Test 10964
* [@https://github.com/boostorg/thread/issues/133 #133] windows - Spurious timing test failures on windows
* [@https://github.com/boostorg/thread/issues/134 #134] VS 2017.4 Preview deadlock in sync_pq_multi_thread_p_lib.exe
* [@https://github.com/boostorg/thread/issues/135 #135] VS 2017.4 Preview test_scheduled_tp_p.exe deadlock
* [@https://github.com/boostorg/thread/issues/136 #136] VS 2017.4 Preview test_scheduler_p.exe deadlock
* [@https://github.com/boostorg/thread/issues/137 #137] VS 2017.4 Preview executor_ex.exe deadlock
* [@https://github.com/boostorg/thread/issues/143 #143] Failures on msvc-12.0
* [@https://github.com/boostorg/thread/issues/145 #145] Clang build error with BOOST_THREAD_ATTRIBUTE_MAY_ALIAS
[*New Experimental Features:]
* [@https://github.com/boostorg/thread/issues/116 #116] [Proposal] Add APIs for deferred set_value/exception
[heading Version 4.7.5 - boost 1.65.1]

View File

@@ -10,37 +10,37 @@
[table Default Values for Configurable Features
[[Feature] [Anti-Feature] [V2] [V3] [V4] ]
[[USES_CHRONO] [DONT_USE_CHRONO] [YES/NO] [YES/NO] [YES/NO] ]
[[PROVIDES_INTERRUPTIONS] [DONT_PROVIDE_INTERRUPTIONS] [YES] [YES] [YES] ]
[[THROW_IF_PRECONDITION_NOT_SATISFIED] [-] [NO] [NO] [NO] ]
[[Feature] [Anti-Feature] [V2] [V3] [V4] [V5] ]
[[USES_CHRONO] [DONT_USE_CHRONO] [YES/NO] [YES/NO] [YES/NO] [YES/NO] ]
[[PROVIDES_INTERRUPTIONS] [DONT_PROVIDE_INTERRUPTIONS] [YES] [YES] [YES] [YES] ]
[[THROW_IF_PRECONDITION_NOT_SATISFIED] [-] [NO] [NO] [NO] [NO] ]
[[PROVIDES_PROMISE_LAZY] [DONT_PROVIDE_PROMISE_LAZY] [YES] [NO] [NO] ]
[[PROVIDES_PROMISE_LAZY] [DONT_PROVIDE_PROMISE_LAZY] [YES] [NO] [NO] [NO] ]
[[PROVIDES_BASIC_THREAD_ID] [DONT_PROVIDE_BASIC_THREAD_ID] [NO] [YES] [YES] ]
[[PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN] [DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN] [NO] [YES] [YES] ]
[[PROVIDES_BASIC_THREAD_ID] [DONT_PROVIDE_BASIC_THREAD_ID] [NO] [YES] [YES] [YES] ]
[[PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN] [DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN] [NO] [YES] [YES] [YES] ]
[[PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION] [DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSION] [NO] [YES] [YES] ]
[[PROVIDES_EXECUTORS] [-] [NO] [NO] [NO] ]
[[PROVIDES_EXPLICIT_LOCK_CONVERSION] [DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION] [NO] [YES] [YES] ]
[[PROVIDES_FUTURE] [DONT_PROVIDE_FUTURE] [NO] [YES] [YES] ]
[[PROVIDES_FUTURE_CTOR_ALLOCATORS] [DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS] [NO] [YES] [YES] ]
[[PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE] [DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE] [NO] [YES] [YES] ]
[[PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE] [DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE] [NO] [YES] [YES] ]
[[PROVIDES_ONCE_CXX11] [DONT_PROVIDE_ONCE_CXX11] [NO] [YES] [YES] ]
[[USES_MOVE] [DONT_USE_MOVE] [NO] [YES] [YES] ]
[[PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION] [DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSION] [NO] [YES] [YES] [YES] ]
[[PROVIDES_EXECUTORS] [-] [NO] [NO] [NO] [YES] ]
[[PROVIDES_EXPLICIT_LOCK_CONVERSION] [DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION] [NO] [YES] [YES] [YES] ]
[[PROVIDES_FUTURE] [DONT_PROVIDE_FUTURE] [NO] [YES] [YES] [YES] ]
[[PROVIDES_FUTURE_CTOR_ALLOCATORS] [DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS] [NO] [YES] [YES] [YES] ]
[[PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE] [DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE] [NO] [YES] [YES] [YES] ]
[[PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE] [DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE] [NO] [YES] [YES] [YES] ]
[[PROVIDES_ONCE_CXX11] [DONT_PROVIDE_ONCE_CXX11] [NO] [YES] [YES] [YES] ]
[[USES_MOVE] [DONT_USE_MOVE] [NO] [YES] [YES] [YES] ]
[[USES_DATETIME] [DONT_USE_DATETIME] [YES/NO] [YES/NO] [YES/NO] ]
[[PROVIDES_THREAD_EQ] [DONT_PROVIDE_THREAD_EQ] [YES] [YES] [NO] ]
[[PROVIDES_CONDITION] [DONT_PROVIDE_CONDITION] [YES] [YES] [NO] ]
[[PROVIDES_NESTED_LOCKS] [DONT_PROVIDE_NESTED_LOCKS] [YES] [YES] [NO] ]
[[PROVIDES_SIGNATURE_PACKAGED_TASK] [DONT_PROVIDE_SIGNATURE_PACKAGED_TASK] [NO] [NO] [YES] ]
[[PROVIDES_FUTURE_INVALID_AFTER_GET] [DONT_PROVIDE_FUTURE_INVALID_AFTER_GET] [NO] [NO] [YES] ]
[/ [[PROVIDES_FUTURE_CONTINUATION] [DONT_PROVIDE_FUTURE_CONTINUATION] [NO] [NO] [YES] ] ]
[[USES_DATETIME] [DONT_USE_DATETIME] [YES/NO] [YES/NO] [YES/NO] [YES/NO] ]
[[PROVIDES_THREAD_EQ] [DONT_PROVIDE_THREAD_EQ] [YES] [YES] [NO] [NO] ]
[[PROVIDES_CONDITION] [DONT_PROVIDE_CONDITION] [YES] [YES] [NO] [NO] ]
[[PROVIDES_NESTED_LOCKS] [DONT_PROVIDE_NESTED_LOCKS] [YES] [YES] [NO] [NO] ]
[[PROVIDES_SIGNATURE_PACKAGED_TASK] [DONT_PROVIDE_SIGNATURE_PACKAGED_TASK] [NO] [NO] [YES] [YES] ]
[[PROVIDES_FUTURE_INVALID_AFTER_GET] [DONT_PROVIDE_FUTURE_INVALID_AFTER_GET] [NO] [NO] [YES] [YES] ]
[/ [[PROVIDES_FUTURE_CONTINUATION] [DONT_PROVIDE_FUTURE_CONTINUATION] [NO] [NO] [YES] [YES] ] ]
[[PROVIDES_VARIADIC_THREAD] [DONT_PROVIDE_VARIADIC_THREAD] [NO] [NO] [C++11] ]
[[PROVIDES_VARIADIC_THREAD] [DONT_PROVIDE_VARIADIC_THREAD] [NO] [NO] [C++11] [C++11] ]
]

View File

@@ -33,7 +33,7 @@
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
struct once_flag
{
constexprr once_flag() noexcept;
constexpr once_flag() noexcept;
once_flag(const once_flag&) = delete;
once_flag& operator=(const once_flag&) = delete;
};

View File

@@ -8,8 +8,7 @@
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif
#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_PROVIDES_EXECUTORS
#define BOOST_THREAD_VERSION 5
#define BOOST_THREAD_USES_LOG_THREAD_ID
#include <boost/thread/caller_context.hpp>

View File

@@ -5,7 +5,7 @@
#include <boost/config.hpp>
#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_VERSION 5
//#define BOOST_THREAD_USES_LOG
#define BOOST_THREAD_USES_LOG_THREAD_ID
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
@@ -15,6 +15,7 @@
#include <boost/thread/detail/log.hpp>
#include <boost/thread/executors/basic_thread_pool.hpp>
#include <boost/thread/thread_only.hpp>
#include <boost/assert.hpp>
#include <string>

View File

@@ -5,7 +5,7 @@
#include <boost/config.hpp>
#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_VERSION 5
//#define BOOST_THREAD_USES_LOG
#define BOOST_THREAD_USES_LOG_THREAD_ID
#if ! defined BOOST_NO_CXX11_DECLTYPE

View File

@@ -11,6 +11,8 @@
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/bind.hpp>
#include <boost/thread/detail/config.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/detail/move.hpp>
@@ -61,7 +63,7 @@ namespace detail
protected:
mutable mutex mtx_;
condition_variable not_empty_;
condition_variable cond_;
underlying_queue_type data_;
bool closed_;
@@ -84,18 +86,19 @@ namespace detail
inline void throw_if_closed(unique_lock<mutex>&);
inline void throw_if_closed(lock_guard<mutex>&);
inline void wait_until_not_empty(unique_lock<mutex>& lk);
inline bool not_empty_or_closed(unique_lock<mutex>& ) const;
inline bool wait_until_not_empty_or_closed(unique_lock<mutex>& lk);
template <class WClock, class Duration>
queue_op_status wait_until_not_empty_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&);
queue_op_status wait_until_not_empty_or_closed_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp);
inline void notify_not_empty_if_needed(unique_lock<mutex>& )
inline void notify_elem_added(unique_lock<mutex>& )
{
not_empty_.notify_one();
cond_.notify_all();
}
inline void notify_not_empty_if_needed(lock_guard<mutex>& )
inline void notify_elem_added(lock_guard<mutex>& )
{
not_empty_.notify_one();
cond_.notify_all();
}
};
@@ -119,7 +122,7 @@ namespace detail
lock_guard<mutex> lk(mtx_);
closed_ = true;
}
not_empty_.notify_all();
cond_.notify_all();
}
template <class ValueType, class Queue>
@@ -176,40 +179,29 @@ namespace detail
}
template <class ValueType, class Queue>
void sync_deque_base<ValueType, Queue>::wait_until_not_empty(unique_lock<mutex>& lk)
bool sync_deque_base<ValueType, Queue>::not_empty_or_closed(unique_lock<mutex>& ) const
{
for (;;)
{
if (! empty(lk)) break;
throw_if_closed(lk);
not_empty_.wait(lk);
}
return ! data_.empty() || closed_;
}
template <class ValueType, class Queue>
bool sync_deque_base<ValueType, Queue>::wait_until_not_empty_or_closed(unique_lock<mutex>& lk)
{
for (;;)
{
if (! empty(lk)) break;
if (closed(lk)) return true;
not_empty_.wait(lk);
}
return false;
cond_.wait(lk, boost::bind(&sync_deque_base<ValueType, Queue>::not_empty_or_closed, boost::ref(*this), boost::ref(lk)));
if (! empty(lk)) return false; // success
return true; // closed
}
template <class ValueType, class Queue>
template <class WClock, class Duration>
queue_op_status sync_deque_base<ValueType, Queue>::wait_until_not_empty_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp)
queue_op_status sync_deque_base<ValueType, Queue>::wait_until_not_empty_or_closed_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp)
{
for (;;)
{
if (! empty(lk)) return queue_op_status::success;
throw_if_closed(lk);
if (not_empty_.wait_until(lk, tp) == cv_status::timeout ) return queue_op_status::timeout;
}
if (! cond_.wait_until(lk, tp, boost::bind(&sync_deque_base<ValueType, Queue>::not_empty_or_closed, boost::ref(*this), boost::ref(lk))))
return queue_op_status::timeout;
if (! empty(lk)) return queue_op_status::success;
return queue_op_status::closed;
}
} // detail
} // concurrent
} // boost

View File

@@ -11,6 +11,8 @@
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/bind.hpp>
#include <boost/thread/detail/config.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/detail/move.hpp>
@@ -61,7 +63,7 @@ namespace detail
protected:
mutable mutex mtx_;
condition_variable not_empty_;
condition_variable cond_;
underlying_queue_type data_;
bool closed_;
@@ -84,18 +86,19 @@ namespace detail
inline void throw_if_closed(unique_lock<mutex>&);
inline void throw_if_closed(lock_guard<mutex>&);
inline void wait_until_not_empty(unique_lock<mutex>& lk);
inline bool not_empty_or_closed(unique_lock<mutex>& ) const;
inline bool wait_until_not_empty_or_closed(unique_lock<mutex>& lk);
template <class WClock, class Duration>
queue_op_status wait_until_not_empty_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&);
queue_op_status wait_until_not_empty_or_closed_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp);
inline void notify_not_empty_if_needed(unique_lock<mutex>& )
inline void notify_elem_added(unique_lock<mutex>& )
{
not_empty_.notify_one();
cond_.notify_all();
}
inline void notify_not_empty_if_needed(lock_guard<mutex>& )
inline void notify_elem_added(lock_guard<mutex>& )
{
not_empty_.notify_one();
cond_.notify_all();
}
};
@@ -119,7 +122,7 @@ namespace detail
lock_guard<mutex> lk(mtx_);
closed_ = true;
}
not_empty_.notify_all();
cond_.notify_all();
}
template <class ValueType, class Queue>
@@ -176,40 +179,29 @@ namespace detail
}
template <class ValueType, class Queue>
void sync_queue_base<ValueType, Queue>::wait_until_not_empty(unique_lock<mutex>& lk)
bool sync_queue_base<ValueType, Queue>::not_empty_or_closed(unique_lock<mutex>& ) const
{
for (;;)
{
if (! empty(lk)) break;
throw_if_closed(lk);
not_empty_.wait(lk);
}
return ! data_.empty() || closed_;
}
template <class ValueType, class Queue>
bool sync_queue_base<ValueType, Queue>::wait_until_not_empty_or_closed(unique_lock<mutex>& lk)
{
for (;;)
{
if (! empty(lk)) break;
if (closed(lk)) return true;
not_empty_.wait(lk);
}
return false;
cond_.wait(lk, boost::bind(&sync_queue_base<ValueType, Queue>::not_empty_or_closed, boost::ref(*this), boost::ref(lk)));
if (! empty(lk)) return false; // success
return true; // closed
}
template <class ValueType, class Queue>
template <class WClock, class Duration>
queue_op_status sync_queue_base<ValueType, Queue>::wait_until_not_empty_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp)
queue_op_status sync_queue_base<ValueType, Queue>::wait_until_not_empty_or_closed_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp)
{
for (;;)
{
if (! empty(lk)) return queue_op_status::success;
throw_if_closed(lk);
if (not_empty_.wait_until(lk, tp) == cv_status::timeout ) return queue_op_status::timeout;
}
if (! cond_.wait_until(lk, tp, boost::bind(&sync_queue_base<ValueType, Queue>::not_empty_or_closed, boost::ref(*this), boost::ref(lk))))
return queue_op_status::timeout;
if (! empty(lk)) return queue_op_status::success;
return queue_op_status::closed;
}
} // detail
} // concurrent
} // boost

View File

@@ -11,6 +11,8 @@
//
//////////////////////////////////////////////////////////////////////////////
#include <exception>
#include <boost/core/scoped_enum.hpp>
#include <boost/thread/detail/config.hpp>
#include <boost/thread/detail/move.hpp>
@@ -25,7 +27,7 @@ namespace concurrent
{ success = 0, empty, full, closed, busy, timeout, not_ready }
BOOST_SCOPED_ENUM_DECLARE_END(queue_op_status)
struct sync_queue_is_closed : std::exception
struct BOOST_SYMBOL_VISIBLE sync_queue_is_closed : std::exception
{
};

View File

@@ -92,13 +92,13 @@ namespace concurrent
inline void push_back(const value_type& elem, unique_lock<mutex>& lk)
{
super::data_.push_back(elem);
super::notify_not_empty_if_needed(lk);
super::notify_elem_added(lk);
}
inline void push_back(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
{
super::data_.push_back(boost::move(elem));
super::notify_not_empty_if_needed(lk);
super::notify_elem_added(lk);
}
};
@@ -122,7 +122,7 @@ namespace concurrent
// {
// data_.push(boost::move(*cur));;
// }
// notify_not_empty_if_needed(lk);
// notify_elem_added(lk);
// }
// catch (...)
// {
@@ -149,11 +149,7 @@ namespace concurrent
template <class ValueType, class Container>
queue_op_status sync_deque<ValueType, Container>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk)
{
if (super::empty(lk))
{
if (super::closed(lk)) return queue_op_status::closed;
}
bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
if (has_been_closed) return queue_op_status::closed;
pull_front(elem, lk);
return queue_op_status::success;
@@ -188,7 +184,8 @@ namespace concurrent
void sync_deque<ValueType, Container>::pull_front(ValueType& elem)
{
unique_lock<mutex> lk(super::mtx_);
super::wait_until_not_empty(lk);
const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
if (has_been_closed) super::throw_if_closed(lk);
pull_front(elem, lk);
}
@@ -197,7 +194,8 @@ namespace concurrent
ValueType sync_deque<ValueType, Container>::pull_front()
{
unique_lock<mutex> lk(super::mtx_);
super::wait_until_not_empty(lk);
const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
if (has_been_closed) super::throw_if_closed(lk);
return pull_front(lk);
}

View File

@@ -82,7 +82,7 @@ namespace detail {
return boost::move(result);
}
Type const& top()
Type const& top() const
{
return _elements.front();
}
@@ -174,14 +174,14 @@ namespace concurrent
{
super::throw_if_closed(lk);
super::data_.push(elem);
super::notify_not_empty_if_needed(lk);
super::notify_elem_added(lk);
}
template <class T, class Container,class Cmp>
void sync_priority_queue<T,Container,Cmp>::push(lock_guard<mutex>& lk, const T& elem)
{
super::throw_if_closed(lk);
super::data_.push(elem);
super::notify_not_empty_if_needed(lk);
super::notify_elem_added(lk);
}
template <class T, class Container,class Cmp>
void sync_priority_queue<T,Container,Cmp>::push(const T& elem)
@@ -196,14 +196,14 @@ namespace concurrent
{
super::throw_if_closed(lk);
super::data_.push(boost::move(elem));
super::notify_not_empty_if_needed(lk);
super::notify_elem_added(lk);
}
template <class T, class Container,class Cmp>
void sync_priority_queue<T,Container,Cmp>::push(lock_guard<mutex>& lk, BOOST_THREAD_RV_REF(T) elem)
{
super::throw_if_closed(lk);
super::data_.push(boost::move(elem));
super::notify_not_empty_if_needed(lk);
super::notify_elem_added(lk);
}
template <class T, class Container,class Cmp>
void sync_priority_queue<T,Container,Cmp>::push(BOOST_THREAD_RV_REF(T) elem)
@@ -249,7 +249,8 @@ namespace concurrent
T sync_priority_queue<T,Container,Cmp>::pull()
{
unique_lock<mutex> lk(super::mtx_);
super::wait_until_not_empty(lk);
const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
if (has_been_closed) super::throw_if_closed(lk);
return pull(lk);
}
@@ -269,7 +270,8 @@ namespace concurrent
void sync_priority_queue<T,Container,Cmp>::pull(T& elem)
{
unique_lock<mutex> lk(super::mtx_);
super::wait_until_not_empty(lk);
const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
if (has_been_closed) super::throw_if_closed(lk);
pull(lk, elem);
}
@@ -280,10 +282,9 @@ namespace concurrent
sync_priority_queue<T,Cont,Cmp>::pull_until(const chrono::time_point<WClock,Duration>& tp, T& elem)
{
unique_lock<mutex> lk(super::mtx_);
if (queue_op_status::timeout == super::wait_until_not_empty_until(lk, tp))
return queue_op_status::timeout;
pull(lk, elem);
return queue_op_status::success;
const queue_op_status rc = super::wait_until_not_empty_or_closed_until(lk, tp);
if (rc == queue_op_status::success) pull(lk, elem);
return rc;
}
//////////////////////
@@ -292,7 +293,7 @@ namespace concurrent
queue_op_status
sync_priority_queue<T,Cont,Cmp>::pull_for(const chrono::duration<Rep,Period>& dura, T& elem)
{
return pull_until(clock::now() + dura, elem);
return pull_until(chrono::steady_clock::now() + dura, elem);
}
//////////////////////
@@ -334,11 +335,7 @@ namespace concurrent
template <class T,class Container, class Cmp>
queue_op_status sync_priority_queue<T,Container,Cmp>::wait_pull(unique_lock<mutex>& lk, T& elem)
{
if (super::empty(lk))
{
if (super::closed(lk)) return queue_op_status::closed;
}
bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
if (has_been_closed) return queue_op_status::closed;
pull(lk, elem);
return queue_op_status::success;
@@ -352,7 +349,6 @@ namespace concurrent
}
//////////////////////
template <class T,class Container, class Cmp>
queue_op_status sync_priority_queue<T,Container,Cmp>::nonblocking_pull(T& elem)
{

View File

@@ -10,7 +10,6 @@
// See http://www.boost.org/libs/thread for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <boost/thread/detail/config.hpp>
#include <boost/thread/concurrent_queues/detail/sync_queue_base.hpp>
@@ -51,7 +50,6 @@ namespace concurrent
inline ~sync_queue();
// Modifiers
inline void push(const value_type& x);
inline queue_op_status try_push(const value_type& x);
inline queue_op_status nonblocking_push(const value_type& x);
@@ -94,13 +92,13 @@ namespace concurrent
inline void push(const value_type& elem, unique_lock<mutex>& lk)
{
super::data_.push_back(elem);
super::notify_not_empty_if_needed(lk);
super::notify_elem_added(lk);
}
inline void push(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
{
super::data_.push_back(boost::move(elem));
super::notify_not_empty_if_needed(lk);
super::notify_elem_added(lk);
}
};
@@ -124,7 +122,7 @@ namespace concurrent
// {
// data_.push(boost::move(*cur));;
// }
// notify_not_empty_if_needed(lk);
// notify_elem_added(lk);
// }
// catch (...)
// {
@@ -151,19 +149,9 @@ namespace concurrent
template <class ValueType, class Container>
queue_op_status sync_queue<ValueType, Container>::wait_pull(ValueType& elem, unique_lock<mutex>& lk)
{
//std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
if (super::empty(lk))
{
//std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
if (super::closed(lk)) return queue_op_status::closed;
}
//std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
//std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
if (has_been_closed) return queue_op_status::closed;
//std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
pull(elem, lk);
//std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
return queue_op_status::success;
}
@@ -196,7 +184,8 @@ namespace concurrent
void sync_queue<ValueType, Container>::pull(ValueType& elem)
{
unique_lock<mutex> lk(super::mtx_);
super::wait_until_not_empty(lk);
const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
if (has_been_closed) super::throw_if_closed(lk);
pull(elem, lk);
}
@@ -205,7 +194,8 @@ namespace concurrent
ValueType sync_queue<ValueType, Container>::pull()
{
unique_lock<mutex> lk(super::mtx_);
super::wait_until_not_empty(lk);
const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
if (has_been_closed) super::throw_if_closed(lk);
return pull(lk);
}

View File

@@ -16,6 +16,8 @@
#include <boost/chrono/system_clocks.hpp>
#include <boost/chrono/chrono_io.hpp>
#include <algorithm> // std::min
#include <boost/config/abi_prefix.hpp>
namespace boost
@@ -53,17 +55,51 @@ namespace detail
return *this;
}
bool time_not_reached() const
{
return time > clock::now();
}
bool operator <(const scheduled_type & other) const
{
return this->time > other.time;
}
}; //end struct
template <class Duration>
chrono::time_point<chrono::steady_clock,Duration>
limit_timepoint(chrono::time_point<chrono::steady_clock,Duration> const& tp)
{
// Clock == chrono::steady_clock
return tp;
}
template <class Clock, class Duration>
chrono::time_point<Clock,Duration>
limit_timepoint(chrono::time_point<Clock,Duration> const& tp)
{
// Clock != chrono::steady_clock
// The system time may jump while wait_until() is waiting. To compensate for this and time out near
// the correct time, we limit how long wait_until() can wait before going around the loop again.
const chrono::time_point<Clock,Duration> tpmax(chrono::time_point_cast<Duration>(Clock::now() + chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
return (std::min)(tp, tpmax);
}
template <class Duration>
chrono::steady_clock::time_point
convert_to_steady_clock_timepoint(chrono::time_point<chrono::steady_clock,Duration> const& tp)
{
// Clock == chrono::steady_clock
return chrono::time_point_cast<chrono::steady_clock::duration>(tp);
}
template <class Clock, class Duration>
chrono::steady_clock::time_point
convert_to_steady_clock_timepoint(chrono::time_point<Clock,Duration> const& tp)
{
// Clock != chrono::steady_clock
// The system time may jump while wait_until() is waiting. To compensate for this and time out near
// the correct time, we limit how long wait_until() can wait before going around the loop again.
const chrono::steady_clock::duration dura(chrono::duration_cast<chrono::steady_clock::duration>(tp - Clock::now()));
const chrono::steady_clock::duration duramax(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
return chrono::steady_clock::now() + (std::min)(dura, duramax);
}
} //end detail namespace
template <class T, class Clock = chrono::steady_clock, class TimePoint=typename Clock::time_point>
@@ -93,8 +129,8 @@ namespace detail
T pull();
void pull(T& elem);
template <class WClock, class Duration>
queue_op_status pull_until(chrono::time_point<WClock,Duration> const& tp, T& elem);
template <class Duration>
queue_op_status pull_until(chrono::time_point<clock,Duration> const& tp, T& elem);
template <class Rep, class Period>
queue_op_status pull_for(chrono::duration<Rep,Period> const& dura, T& elem);
@@ -123,6 +159,14 @@ namespace detail
queue_op_status try_push(BOOST_THREAD_RV_REF(T) elem, chrono::duration<Rep,Period> const& dura);
private:
inline bool not_empty_and_time_reached(unique_lock<mutex>& lk) const;
inline bool not_empty_and_time_reached(lock_guard<mutex>& lk) const;
bool wait_to_pull(unique_lock<mutex>&);
queue_op_status wait_to_pull_until(unique_lock<mutex>&, TimePoint const& tp);
template <class Rep, class Period>
queue_op_status wait_to_pull_for(unique_lock<mutex>& lk, chrono::duration<Rep,Period> const& dura);
T pull(unique_lock<mutex>&);
T pull(lock_guard<mutex>&);
@@ -134,15 +178,6 @@ namespace detail
queue_op_status wait_pull(unique_lock<mutex>& lk, T& elem);
bool wait_until_not_empty_time_reached_or_closed(unique_lock<mutex>&);
T pull_when_time_reached(unique_lock<mutex>&);
template <class WClock, class Duration>
queue_op_status pull_when_time_reached_until(unique_lock<mutex>&, chrono::time_point<WClock,Duration> const& tp, T& elem);
bool time_not_reached(unique_lock<mutex>&);
bool time_not_reached(lock_guard<mutex>&);
bool empty_or_time_not_reached(unique_lock<mutex>&);
bool empty_or_time_not_reached(lock_guard<mutex>&);
sync_timed_queue(const sync_timed_queue&);
sync_timed_queue& operator=(const sync_timed_queue&);
sync_timed_queue(BOOST_THREAD_RV_REF(sync_timed_queue));
@@ -210,82 +245,76 @@ namespace detail
///////////////////////////
template <class T, class Clock, class TimePoint>
bool sync_timed_queue<T, Clock, TimePoint>::time_not_reached(unique_lock<mutex>&)
bool sync_timed_queue<T, Clock, TimePoint>::not_empty_and_time_reached(unique_lock<mutex>& lk) const
{
return super::data_.top().time_not_reached();
return ! super::empty(lk) && clock::now() >= super::data_.top().time;
}
template <class T, class Clock, class TimePoint>
bool sync_timed_queue<T, Clock, TimePoint>::time_not_reached(lock_guard<mutex>&)
bool sync_timed_queue<T, Clock, TimePoint>::not_empty_and_time_reached(lock_guard<mutex>& lk) const
{
return super::data_.top().time_not_reached();
return ! super::empty(lk) && clock::now() >= super::data_.top().time;
}
///////////////////////////
template <class T, class Clock, class TimePoint>
bool sync_timed_queue<T, Clock, TimePoint>::wait_until_not_empty_time_reached_or_closed(unique_lock<mutex>& lk)
bool sync_timed_queue<T, Clock, TimePoint>::wait_to_pull(unique_lock<mutex>& lk)
{
for (;;)
{
if (super::closed(lk)) return true;
while (! super::empty(lk)) {
if (! time_not_reached(lk)) return false;
time_point tp = super::data_.top().time;
super::not_empty_.wait_until(lk, tp);
if (super::closed(lk)) return true;
}
if (super::closed(lk)) return true;
super::not_empty_.wait(lk);
if (not_empty_and_time_reached(lk)) return false; // success
if (super::closed(lk)) return true; // closed
super::wait_until_not_empty_or_closed(lk);
if (not_empty_and_time_reached(lk)) return false; // success
if (super::closed(lk)) return true; // closed
const time_point tpmin(detail::limit_timepoint(super::data_.top().time));
super::cond_.wait_until(lk, tpmin);
}
//return false;
}
///////////////////////////
template <class T, class Clock, class TimePoint>
T sync_timed_queue<T, Clock, TimePoint>::pull_when_time_reached(unique_lock<mutex>& lk)
queue_op_status sync_timed_queue<T, Clock, TimePoint>::wait_to_pull_until(unique_lock<mutex>& lk, TimePoint const& tp)
{
while (time_not_reached(lk))
for (;;)
{
super::throw_if_closed(lk);
time_point tp = super::data_.top().time;
super::not_empty_.wait_until(lk,tp);
super::wait_until_not_empty(lk);
if (not_empty_and_time_reached(lk)) return queue_op_status::success;
if (super::closed(lk)) return queue_op_status::closed;
if (clock::now() >= tp) return super::empty(lk) ? queue_op_status::timeout : queue_op_status::not_ready;
super::wait_until_not_empty_or_closed_until(lk, tp);
if (not_empty_and_time_reached(lk)) return queue_op_status::success;
if (super::closed(lk)) return queue_op_status::closed;
if (clock::now() >= tp) return super::empty(lk) ? queue_op_status::timeout : queue_op_status::not_ready;
const time_point tpmin((std::min)(tp, detail::limit_timepoint(super::data_.top().time)));
super::cond_.wait_until(lk, tpmin);
}
return pull(lk);
}
template <class T, class Clock, class TimePoint>
template <class WClock, class Duration>
queue_op_status
sync_timed_queue<T, Clock, TimePoint>::pull_when_time_reached_until(unique_lock<mutex>& lk, chrono::time_point<WClock, Duration> const& tp, T& elem)
template <class Rep, class Period>
queue_op_status sync_timed_queue<T, Clock, TimePoint>::wait_to_pull_for(unique_lock<mutex>& lk, chrono::duration<Rep,Period> const& dura)
{
chrono::time_point<WClock, Duration> tpmin = (tp < super::data_.top().time) ? tp : super::data_.top().time;
while (time_not_reached(lk))
const chrono::steady_clock::time_point tp(chrono::steady_clock::now() + chrono::duration_cast<chrono::steady_clock::duration>(dura));
for (;;)
{
super::throw_if_closed(lk);
if (cv_status::timeout == super::not_empty_.wait_until(lk, tpmin)) {
if (time_not_reached(lk)) return queue_op_status::not_ready;
return queue_op_status::timeout;
}
}
pull(lk, elem);
return queue_op_status::success;
}
if (not_empty_and_time_reached(lk)) return queue_op_status::success;
if (super::closed(lk)) return queue_op_status::closed;
if (chrono::steady_clock::now() >= tp) return super::empty(lk) ? queue_op_status::timeout : queue_op_status::not_ready;
///////////////////////////
template <class T, class Clock, class TimePoint>
bool sync_timed_queue<T, Clock, TimePoint>::empty_or_time_not_reached(unique_lock<mutex>& lk)
{
if ( super::empty(lk) ) return true;
if ( time_not_reached(lk) ) return true;
return false;
}
template <class T, class Clock, class TimePoint>
bool sync_timed_queue<T, Clock, TimePoint>::empty_or_time_not_reached(lock_guard<mutex>& lk)
{
if ( super::empty(lk) ) return true;
if ( time_not_reached(lk) ) return true;
return false;
super::wait_until_not_empty_or_closed_until(lk, tp);
if (not_empty_and_time_reached(lk)) return queue_op_status::success;
if (super::closed(lk)) return queue_op_status::closed;
if (chrono::steady_clock::now() >= tp) return super::empty(lk) ? queue_op_status::timeout : queue_op_status::not_ready;
const chrono::steady_clock::time_point tpmin((std::min)(tp, detail::convert_to_steady_clock_timepoint(super::data_.top().time)));
super::cond_.wait_until(lk, tpmin);
}
}
///////////////////////////
@@ -312,8 +341,9 @@ namespace detail
T sync_timed_queue<T, Clock, TimePoint>::pull()
{
unique_lock<mutex> lk(super::mtx_);
super::wait_until_not_empty(lk);
return pull_when_time_reached(lk);
const bool has_been_closed = wait_to_pull(lk);
if (has_been_closed) super::throw_if_closed(lk);
return pull(lk);
}
///////////////////////////
@@ -341,21 +371,21 @@ namespace detail
void sync_timed_queue<T, Clock, TimePoint>::pull(T& elem)
{
unique_lock<mutex> lk(super::mtx_);
super::wait_until_not_empty(lk);
elem = pull_when_time_reached(lk);
const bool has_been_closed = wait_to_pull(lk);
if (has_been_closed) super::throw_if_closed(lk);
pull(lk, elem);
}
//////////////////////
template <class T, class Clock, class TimePoint>
template <class WClock, class Duration>
template <class Duration>
queue_op_status
sync_timed_queue<T, Clock, TimePoint>::pull_until(chrono::time_point<WClock, Duration> const& tp, T& elem)
sync_timed_queue<T, Clock, TimePoint>::pull_until(chrono::time_point<clock,Duration> const& tp, T& elem)
{
unique_lock<mutex> lk(super::mtx_);
if (queue_op_status::timeout == super::wait_until_not_empty_until(lk, tp))
return queue_op_status::timeout;
return pull_when_time_reached_until(lk, tp, elem);
const queue_op_status rc = wait_to_pull_until(lk, chrono::time_point_cast<typename time_point::duration>(tp));
if (rc == queue_op_status::success) pull(lk, elem);
return rc;
}
//////////////////////
@@ -364,42 +394,36 @@ namespace detail
queue_op_status
sync_timed_queue<T, Clock, TimePoint>::pull_for(chrono::duration<Rep,Period> const& dura, T& elem)
{
return pull_until(chrono::steady_clock::now() + dura, elem);
unique_lock<mutex> lk(super::mtx_);
const queue_op_status rc = wait_to_pull_for(lk, dura);
if (rc == queue_op_status::success) pull(lk, elem);
return rc;
}
///////////////////////////
template <class T, class Clock, class TimePoint>
queue_op_status sync_timed_queue<T, Clock, TimePoint>::try_pull(unique_lock<mutex>& lk, T& elem)
{
if ( super::empty(lk) )
if (not_empty_and_time_reached(lk))
{
if (super::closed(lk)) return queue_op_status::closed;
return queue_op_status::empty;
pull(lk, elem);
return queue_op_status::success;
}
if ( time_not_reached(lk) )
{
if (super::closed(lk)) return queue_op_status::closed;
return queue_op_status::not_ready;
}
pull(lk, elem);
return queue_op_status::success;
if (super::closed(lk)) return queue_op_status::closed;
if (super::empty(lk)) return queue_op_status::empty;
return queue_op_status::not_ready;
}
template <class T, class Clock, class TimePoint>
queue_op_status sync_timed_queue<T, Clock, TimePoint>::try_pull(lock_guard<mutex>& lk, T& elem)
{
if ( super::empty(lk) )
if (not_empty_and_time_reached(lk))
{
if (super::closed(lk)) return queue_op_status::closed;
return queue_op_status::empty;
pull(lk, elem);
return queue_op_status::success;
}
if ( time_not_reached(lk) )
{
if (super::closed(lk)) return queue_op_status::closed;
return queue_op_status::not_ready;
}
pull(lk, elem);
return queue_op_status::success;
if (super::closed(lk)) return queue_op_status::closed;
if (super::empty(lk)) return queue_op_status::empty;
return queue_op_status::not_ready;
}
template <class T, class Clock, class TimePoint>
@@ -413,11 +437,7 @@ namespace detail
template <class T, class Clock, class TimePoint>
queue_op_status sync_timed_queue<T, Clock, TimePoint>::wait_pull(unique_lock<mutex>& lk, T& elem)
{
if (super::empty(lk))
{
if (super::closed(lk)) return queue_op_status::closed;
}
bool has_been_closed = wait_until_not_empty_time_reached_or_closed(lk);
const bool has_been_closed = wait_to_pull(lk);
if (has_been_closed) return queue_op_status::closed;
pull(lk, elem);
return queue_op_status::success;
@@ -430,26 +450,6 @@ namespace detail
return wait_pull(lk, elem);
}
// ///////////////////////////
// template <class T, class Clock, class TimePoint>
// queue_op_status sync_timed_queue<T, Clock, TimePoint>::wait_pull(unique_lock<mutex> &lk, T& elem)
// {
// if (super::empty(lk))
// {
// if (super::closed(lk)) return queue_op_status::closed;
// }
// bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
// if (has_been_closed) return queue_op_status::closed;
// pull(lk, elem);
// return queue_op_status::success;
// }
// template <class T, class Clock, class TimePoint>
// queue_op_status sync_timed_queue<T, Clock, TimePoint>::wait_pull(T& elem)
// {
// unique_lock<mutex> lk(super::mtx_);
// return wait_pull(lk, elem);
// }
///////////////////////////
template <class T, class Clock, class TimePoint>
queue_op_status sync_timed_queue<T, Clock, TimePoint>::nonblocking_pull(T& elem)

View File

@@ -5,7 +5,7 @@
//
// 2013/10 Vicente J. Botet Escriba
// Creation.
#if 0
#ifndef BOOST_CSBL_QUEUE_HPP
#define BOOST_CSBL_QUEUE_HPP
@@ -43,3 +43,4 @@ namespace boost
}
}
#endif // header
#endif

View File

@@ -11,8 +11,8 @@
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/thread/detail/platform.hpp>
#include <boost/thread/detail/thread_safety.hpp>
//#define BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
//#define BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
// ATTRIBUTE_MAY_ALIAS
@@ -30,6 +30,34 @@
#define BOOST_THREAD_ATTRIBUTE_MAY_ALIAS
#endif
#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
# warning Boost.Thread will use the Windows API for time
#elif defined(BOOST_THREAD_CHRONO_MAC_API)
# warning Boost.Thread will use the Mac API for time
#elif defined(BOOST_THREAD_CHRONO_POSIX_API)
# warning Boost.Thread will use the POSIX API for time
#endif
# if defined( BOOST_THREAD_CHRONO_WINDOWS_API ) && defined( BOOST_THREAD_CHRONO_POSIX_API )
# error both BOOST_THREAD_CHRONO_WINDOWS_API and BOOST_THREAD_CHRONO_POSIX_API are defined
# elif defined( BOOST_THREAD_CHRONO_WINDOWS_API ) && defined( BOOST_THREAD_CHRONO_MAC_API )
# error both BOOST_THREAD_CHRONO_WINDOWS_API and BOOST_THREAD_CHRONO_MAC_API are defined
# elif defined( BOOST_THREAD_CHRONO_MAC_API ) && defined( BOOST_THREAD_CHRONO_POSIX_API )
# error both BOOST_THREAD_CHRONO_MAC_API and BOOST_THREAD_CHRONO_POSIX_API are defined
# elif !defined( BOOST_THREAD_CHRONO_WINDOWS_API ) && !defined( BOOST_THREAD_CHRONO_MAC_API ) && !defined( BOOST_THREAD_CHRONO_POSIX_API )
# if defined(BOOST_THREAD_PLATFORM_WIN32)
# define BOOST_THREAD_CHRONO_WINDOWS_API
# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
# define BOOST_THREAD_CHRONO_MAC_API
# else
# define BOOST_THREAD_CHRONO_POSIX_API
# endif
# endif
#if !defined(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)
#define BOOST_THREAD_POLL_INTERVAL_MILLISECONDS 100
#endif
#if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
#define BOOST_THREAD_ASSERT_PRECONDITION(EXPR, EX) \
if (EXPR) {} else boost::throw_exception(EX)
@@ -96,7 +124,7 @@
/// RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
//#if defined BOOST_NO_CXX11_RVALUE_REFERENCES || defined BOOST_MSVC
#define BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
#define BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR
//#endif
// Default version
@@ -310,10 +338,18 @@
#if BOOST_THREAD_VERSION>=5
//#define BOOST_THREAD_FUTURE_BLOCKING
#if ! defined BOOST_THREAD_PROVIDES_EXECUTORS \
&& ! defined BOOST_THREAD_DONT_PROVIDE_EXECUTORS
#define BOOST_THREAD_PROVIDES_EXECUTORS
#endif
#else
//#define BOOST_THREAD_FUTURE_BLOCKING
#define BOOST_THREAD_ASYNC_FUTURE_WAITS
#endif
// INTERRUPTIONS
#if ! defined BOOST_THREAD_PROVIDES_INTERRUPTIONS \
&& ! defined BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
@@ -385,6 +421,34 @@
# endif
#endif
#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
#define BOOST_THREAD_HAS_MONO_CLOCK
#define BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
#elif defined(BOOST_THREAD_CHRONO_MAC_API)
#define BOOST_THREAD_HAS_MONO_CLOCK
#elif defined(__ANDROID__)
#define BOOST_THREAD_HAS_MONO_CLOCK
#if defined(__ANDROID_API__) && __ANDROID_API__ >= 21
#define BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
#endif
#else
#include <time.h> // check for CLOCK_MONOTONIC
#if defined(CLOCK_MONOTONIC)
#define BOOST_THREAD_HAS_MONO_CLOCK
#define BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
#endif
#endif
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#elif ! defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
#if defined BOOST_PTHREAD_HAS_TIMEDLOCK
#define BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
#elif (defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS-0)>=200112L) \
|| (defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21)
#define BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
#endif
#endif
// provided for backwards compatibility, since this
// macro was used for several releases by mistake.
#if defined(BOOST_THREAD_DYN_DLL) && ! defined(BOOST_THREAD_DYN_LINK)

View File

@@ -350,12 +350,19 @@ namespace boost
#endif
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
template <class T>
typename decay<T>::type
decay_copy(T&& t)
{
return boost::forward<T>(t);
}
template <class T>
typename decay<T>::type
decay_copy(T&& t)
{
return boost::forward<T>(t);
}
typedef void (*void_fct_ptr)();
// inline void_fct_ptr
// decay_copy(void (&t)())
// {
// return &t;
// }
#else
template <class T>
typename decay<T>::type

View File

@@ -3,7 +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)
//
// 2013/09 Vicente J. Botet Escriba
// 2013,2018 Vicente J. Botet Escriba
// Adapt to boost from CCIA C++11 implementation
// Make use of Boost.Move
@@ -15,6 +15,7 @@
#include <boost/thread/detail/move.hpp>
#include <boost/thread/csbl/memory/shared_ptr.hpp>
#include <boost/type_traits/decay.hpp>
#include <boost/type_traits/is_same.hpp>
namespace boost
{
@@ -72,12 +73,16 @@ namespace boost
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
template<typename F>
explicit nullary_function(F& f):
explicit nullary_function(F& f
, typename disable_if<is_same<typename decay<F>::type, nullary_function>, int* >::type=0
):
impl(new impl_type<F>(f))
{}
#endif
template<typename F>
nullary_function(BOOST_THREAD_RV_REF(F) f):
nullary_function(BOOST_THREAD_RV_REF(F) f
, typename disable_if<is_same<typename decay<F>::type, nullary_function>, int* >::type=0
):
impl(new impl_type<typename decay<F>::type>(thread_detail::decay_copy(boost::forward<F>(f))))
{}

View File

@@ -31,7 +31,9 @@
#elif defined(__CYGWIN__)
# define BOOST_THREAD_CYGWIN
#elif (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) && !defined(BOOST_DISABLE_WIN32)
#if ! defined BOOST_THREAD_WIN32
# define BOOST_THREAD_WIN32
#endif
#elif defined(__BEOS__)
# define BOOST_THREAD_BEOS
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)

View File

@@ -0,0 +1,478 @@
#ifndef BOOST_THREAD_DETAIL_PLATFORM_TIME_HPP
#define BOOST_THREAD_DETAIL_PLATFORM_TIME_HPP
// (C) Copyright 2007-8 Anthony Williams
// (C) Copyright 2012 Vicente J. Botet Escriba
//
// 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_time.hpp>
#if defined BOOST_THREAD_USES_DATETIME
#include <boost/date_time/posix_time/conversion.hpp>
#endif
#ifndef _WIN32
#include <unistd.h>
#endif
#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono/duration.hpp>
#include <boost/chrono/system_clocks.hpp>
#include <boost/chrono/ceil.hpp>
#endif
#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
#include <boost/detail/winapi/time.hpp>
#include <boost/detail/winapi/timers.hpp>
#include <boost/thread/win32/thread_primitives.hpp>
#elif defined(BOOST_THREAD_CHRONO_MAC_API)
#include <sys/time.h> //for gettimeofday and timeval
#include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info_data_t
#else
#include <time.h> // for clock_gettime
#endif
#include <limits>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
//typedef boost::int_least64_t time_max_t;
typedef boost::intmax_t time_max_t;
#if defined BOOST_THREAD_CHRONO_MAC_API
namespace threads
{
namespace chrono_details
{
// steady_clock
// Note, in this implementation steady_clock and high_resolution_clock
// are the same clock. They are both based on mach_absolute_time().
// mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of
// nanoseconds since the computer booted up. MachInfo.numer and MachInfo.denom
// are run time constants supplied by the OS. This clock has no relationship
// to the Gregorian calendar. It's main use is as a high resolution timer.
// MachInfo.numer / MachInfo.denom is often 1 on the latest equipment. Specialize
// for that case as an optimization.
inline time_max_t
steady_simplified()
{
return mach_absolute_time();
}
inline double compute_steady_factor(kern_return_t& err)
{
mach_timebase_info_data_t MachInfo;
err = mach_timebase_info(&MachInfo);
if ( err != 0 ) {
return 0;
}
return static_cast<double>(MachInfo.numer) / MachInfo.denom;
}
inline time_max_t steady_full()
{
kern_return_t err;
const double factor = chrono_details::compute_steady_factor(err);
if (err != 0)
{
BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
}
return static_cast<time_max_t>(mach_absolute_time() * factor);
}
typedef time_max_t (*FP)();
inline FP init_steady_clock(kern_return_t & err)
{
mach_timebase_info_data_t MachInfo;
err = mach_timebase_info(&MachInfo);
if ( err != 0 )
{
return 0;
}
if (MachInfo.numer == MachInfo.denom)
{
return &chrono_details::steady_simplified;
}
return &chrono_details::steady_full;
}
}
}
#endif
namespace detail
{
#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
inline timespec ns_to_timespec(boost::time_max_t const& ns)
{
boost::time_max_t s = ns / 1000000000l;
timespec ts;
ts.tv_sec = static_cast<long> (s);
ts.tv_nsec = static_cast<long> (ns - s * 1000000000l);
return ts;
}
inline boost::time_max_t timespec_to_ns(timespec const& ts)
{
return static_cast<boost::time_max_t>(ts.tv_sec) * 1000000000l + ts.tv_nsec;
}
#endif
struct platform_duration
{
#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
explicit platform_duration(timespec const& v) : ts_val(v) {}
timespec const& getTs() const { return ts_val; }
explicit platform_duration(boost::time_max_t const& ns = 0) : ts_val(ns_to_timespec(ns)) {}
boost::time_max_t getNs() const { return timespec_to_ns(ts_val); }
#else
explicit platform_duration(boost::time_max_t const& ns = 0) : ns_val(ns) {}
boost::time_max_t getNs() const { return ns_val; }
#endif
#if defined BOOST_THREAD_USES_DATETIME
platform_duration(boost::posix_time::time_duration const& rel_time)
{
#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
ts_val.tv_sec = rel_time.total_seconds();
ts_val.tv_nsec = static_cast<long>(rel_time.fractional_seconds() * (1000000000l / rel_time.ticks_per_second()));
#else
ns_val = static_cast<boost::time_max_t>(rel_time.total_seconds()) * 1000000000l;
ns_val += rel_time.fractional_seconds() * (1000000000l / rel_time.ticks_per_second());
#endif
}
#endif
#if defined BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
platform_duration(chrono::duration<Rep, Period> const& d)
{
#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
ts_val = ns_to_timespec(chrono::ceil<chrono::nanoseconds>(d).count());
#else
ns_val = chrono::ceil<chrono::nanoseconds>(d).count();
#endif
}
#endif
boost::time_max_t getMs() const
{
const boost::time_max_t ns = getNs();
// ceil/floor away from zero
if (ns >= 0)
{
// return ceiling of positive numbers
return (ns + 999999) / 1000000;
}
else
{
// return floor of negative numbers
return (ns - 999999) / 1000000;
}
}
static platform_duration zero()
{
return platform_duration(0);
}
private:
#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
timespec ts_val;
#else
boost::time_max_t ns_val;
#endif
};
inline bool operator==(platform_duration const& lhs, platform_duration const& rhs)
{
return lhs.getNs() == rhs.getNs();
}
inline bool operator!=(platform_duration const& lhs, platform_duration const& rhs)
{
return lhs.getNs() != rhs.getNs();
}
inline bool operator<(platform_duration const& lhs, platform_duration const& rhs)
{
return lhs.getNs() < rhs.getNs();
}
inline bool operator<=(platform_duration const& lhs, platform_duration const& rhs)
{
return lhs.getNs() <= rhs.getNs();
}
inline bool operator>(platform_duration const& lhs, platform_duration const& rhs)
{
return lhs.getNs() > rhs.getNs();
}
inline bool operator>=(platform_duration const& lhs, platform_duration const& rhs)
{
return lhs.getNs() >= rhs.getNs();
}
static inline platform_duration platform_milliseconds(long const& ms)
{
return platform_duration(ms * 1000000l);
}
struct real_platform_timepoint
{
#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
explicit real_platform_timepoint(timespec const& v) : dur(v) {}
timespec const& getTs() const { return dur.getTs(); }
#endif
explicit real_platform_timepoint(boost::time_max_t const& ns) : dur(ns) {}
boost::time_max_t getNs() const { return dur.getNs(); }
#if defined BOOST_THREAD_USES_DATETIME
real_platform_timepoint(boost::system_time const& abs_time)
: dur(abs_time - boost::posix_time::from_time_t(0)) {}
#endif
#if defined BOOST_THREAD_USES_CHRONO
template <class Duration>
real_platform_timepoint(chrono::time_point<chrono::system_clock, Duration> const& abs_time)
: dur(abs_time.time_since_epoch()) {}
#endif
private:
platform_duration dur;
};
inline bool operator==(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
{
return lhs.getNs() == rhs.getNs();
}
inline bool operator!=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
{
return lhs.getNs() != rhs.getNs();
}
inline bool operator<(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
{
return lhs.getNs() < rhs.getNs();
}
inline bool operator<=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
{
return lhs.getNs() <= rhs.getNs();
}
inline bool operator>(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
{
return lhs.getNs() > rhs.getNs();
}
inline bool operator>=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
{
return lhs.getNs() >= rhs.getNs();
}
inline real_platform_timepoint operator+(real_platform_timepoint const& lhs, platform_duration const& rhs)
{
return real_platform_timepoint(lhs.getNs() + rhs.getNs());
}
inline real_platform_timepoint operator+(platform_duration const& lhs, real_platform_timepoint const& rhs)
{
return real_platform_timepoint(lhs.getNs() + rhs.getNs());
}
inline platform_duration operator-(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
{
return platform_duration(lhs.getNs() - rhs.getNs());
}
struct real_platform_clock
{
static real_platform_timepoint now()
{
#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
boost::detail::winapi::FILETIME_ ft;
boost::detail::winapi::GetSystemTimeAsFileTime(&ft); // never fails
boost::time_max_t ns = ((((static_cast<boost::time_max_t>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime) - 116444736000000000LL) * 100LL);
return real_platform_timepoint(ns);
#elif defined(BOOST_THREAD_CHRONO_MAC_API)
timeval tv;
::gettimeofday(&tv, 0);
timespec ts;
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec * 1000;
return real_platform_timepoint(ts);
#else
timespec ts;
if ( ::clock_gettime( CLOCK_REALTIME, &ts ) )
{
BOOST_ASSERT(0 && "Boost::Thread - clock_gettime(CLOCK_REALTIME) Internal Error");
return real_platform_timepoint(0);
}
return real_platform_timepoint(ts);
#endif
}
};
#if defined(BOOST_THREAD_HAS_MONO_CLOCK)
struct mono_platform_timepoint
{
#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
explicit mono_platform_timepoint(timespec const& v) : dur(v) {}
timespec const& getTs() const { return dur.getTs(); }
#endif
explicit mono_platform_timepoint(boost::time_max_t const& ns) : dur(ns) {}
boost::time_max_t getNs() const { return dur.getNs(); }
#if defined BOOST_THREAD_USES_CHRONO
// This conversion assumes that chrono::steady_clock::time_point and mono_platform_timepoint share the same epoch.
template <class Duration>
mono_platform_timepoint(chrono::time_point<chrono::steady_clock, Duration> const& abs_time)
: dur(abs_time.time_since_epoch()) {}
#endif
// can't name this max() since that is a macro on some Windows systems
static mono_platform_timepoint getMax()
{
#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
timespec ts;
ts.tv_sec = (std::numeric_limits<time_t>::max)();
ts.tv_nsec = 999999999;
return mono_platform_timepoint(ts);
#else
boost::time_max_t ns = (std::numeric_limits<boost::time_max_t>::max)();
return mono_platform_timepoint(ns);
#endif
}
private:
platform_duration dur;
};
inline bool operator==(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
{
return lhs.getNs() == rhs.getNs();
}
inline bool operator!=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
{
return lhs.getNs() != rhs.getNs();
}
inline bool operator<(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
{
return lhs.getNs() < rhs.getNs();
}
inline bool operator<=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
{
return lhs.getNs() <= rhs.getNs();
}
inline bool operator>(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
{
return lhs.getNs() > rhs.getNs();
}
inline bool operator>=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
{
return lhs.getNs() >= rhs.getNs();
}
inline mono_platform_timepoint operator+(mono_platform_timepoint const& lhs, platform_duration const& rhs)
{
return mono_platform_timepoint(lhs.getNs() + rhs.getNs());
}
inline mono_platform_timepoint operator+(platform_duration const& lhs, mono_platform_timepoint const& rhs)
{
return mono_platform_timepoint(lhs.getNs() + rhs.getNs());
}
inline platform_duration operator-(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
{
return platform_duration(lhs.getNs() - rhs.getNs());
}
struct mono_platform_clock
{
static mono_platform_timepoint now()
{
#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
#if defined(BOOST_THREAD_USES_CHRONO)
// Use QueryPerformanceCounter() to match the implementation in Boost
// Chrono so that chrono::steady_clock::now() and this function share the
// same epoch and so can be converted between each other.
boost::detail::winapi::LARGE_INTEGER_ freq;
if ( !boost::detail::winapi::QueryPerformanceFrequency( &freq ) )
{
BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceFrequency Internal Error");
return mono_platform_timepoint(0);
}
if ( freq.QuadPart <= 0 )
{
BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceFrequency Internal Error");
return mono_platform_timepoint(0);
}
boost::detail::winapi::LARGE_INTEGER_ pcount;
unsigned times=0;
while ( ! boost::detail::winapi::QueryPerformanceCounter( &pcount ) )
{
if ( ++times > 3 )
{
BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceCounter Internal Error");
return mono_platform_timepoint(0);
}
}
long double ns = 1000000000.0L * pcount.QuadPart / freq.QuadPart;
return mono_platform_timepoint(static_cast<boost::time_max_t>(ns));
#else
// Use GetTickCount64() because it's more reliable on older
// systems like Windows XP and Windows Server 2003.
win32::ticks_type msec = win32::gettickcount64();
return mono_platform_timepoint(msec * 1000000);
#endif
#elif defined(BOOST_THREAD_CHRONO_MAC_API)
kern_return_t err;
threads::chrono_details::FP fp = threads::chrono_details::init_steady_clock(err);
if ( err != 0 )
{
BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
}
return mono_platform_timepoint(fp());
#else
timespec ts;
if ( ::clock_gettime( CLOCK_MONOTONIC, &ts ) )
{
BOOST_ASSERT(0 && "Boost::Thread - clock_gettime(CLOCK_MONOTONIC) Internal Error");
return mono_platform_timepoint(0);
}
return mono_platform_timepoint(ts);
#endif
}
};
#endif
#if defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
typedef mono_platform_clock internal_platform_clock;
typedef mono_platform_timepoint internal_platform_timepoint;
#else
typedef real_platform_clock internal_platform_clock;
typedef real_platform_timepoint internal_platform_timepoint;
#endif
#ifdef BOOST_THREAD_USES_CHRONO
#ifdef BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
typedef chrono::steady_clock internal_chrono_clock;
#else
typedef chrono::system_clock internal_chrono_clock;
#endif
#endif
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -18,6 +18,9 @@
#if defined BOOST_THREAD_USES_DATETIME
#include <boost/thread/xtime.hpp>
#endif
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
#include <boost/thread/interruption.hpp>
#endif
#include <boost/thread/detail/thread_heap_alloc.hpp>
#include <boost/thread/detail/make_tuple_indices.hpp>
#include <boost/thread/detail/invoke.hpp>
@@ -36,6 +39,7 @@
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/decay.hpp>
#include <boost/functional/hash.hpp>
#include <boost/thread/detail/platform_time.hpp>
#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono/system_clocks.hpp>
#include <boost/chrono/ceil.hpp>
@@ -155,15 +159,7 @@ namespace boost
};
#endif
}
namespace thread_detail {
#ifdef BOOST_THREAD_USES_CHRONO
#if defined(BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC)
typedef chrono::steady_clock internal_clock_t;
#else
typedef chrono::system_clock internal_clock_t;
#endif
#endif
}
class BOOST_THREAD_DECL thread
{
public:
@@ -462,105 +458,80 @@ namespace thread_detail {
}
class id;
#ifdef BOOST_THREAD_PLATFORM_PTHREAD
inline id get_id() const BOOST_NOEXCEPT;
#else
id get_id() const BOOST_NOEXCEPT;
#endif
bool joinable() const BOOST_NOEXCEPT;
private:
bool join_noexcept();
bool do_try_join_until_noexcept(detail::internal_platform_timepoint const &timeout, bool& res);
bool do_try_join_until(detail::internal_platform_timepoint const &timeout);
public:
inline void join();
void join();
#ifdef BOOST_THREAD_USES_CHRONO
#if defined(BOOST_THREAD_PLATFORM_WIN32)
template <class Rep, class Period>
bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
template <class Duration>
bool try_join_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
{
chrono::milliseconds rel_time2= chrono::ceil<chrono::milliseconds>(rel_time);
return do_try_join_until(rel_time2.count());
return do_try_join_until(boost::detail::internal_platform_timepoint(t));
}
#else
template <class Clock, class Duration>
bool try_join_until(const chrono::time_point<Clock, Duration>& t)
{
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
common_duration d(t - Clock::now());
d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
while ( ! try_join_until(detail::internal_chrono_clock::now() + d) )
{
d = t - Clock::now();
if ( d <= common_duration::zero() ) return false; // timeout occurred
d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
}
return true;
}
template <class Rep, class Period>
bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
{
return try_join_until(chrono::steady_clock::now() + rel_time);
}
#endif
template <class Clock, class Duration>
bool try_join_until(const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
bool joined= false;
do {
thread_detail::internal_clock_t::time_point s_now = thread_detail::internal_clock_t::now();
typename Clock::duration d = ceil<nanoseconds>(t-Clock::now());
if (d <= Clock::duration::zero()) return false; // in case the Clock::time_point t is already reached
joined = try_join_until(s_now + d);
} while (! joined);
return true;
}
template <class Duration>
bool try_join_until(const chrono::time_point<thread_detail::internal_clock_t, Duration>& t)
{
using namespace chrono;
typedef time_point<thread_detail::internal_clock_t, nanoseconds> nano_sys_tmpt;
return try_join_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
}
#endif
#if defined(BOOST_THREAD_PLATFORM_WIN32)
private:
bool do_try_join_until_noexcept(uintmax_t milli, bool& res);
inline bool do_try_join_until(uintmax_t milli);
public:
bool timed_join(const system_time& abs_time);
//{
// return do_try_join_until(get_milliseconds_until(wait_until));
//}
#ifdef BOOST_THREAD_USES_CHRONO
bool try_join_until(const chrono::time_point<thread_detail::internal_clock_t, chrono::nanoseconds>& tp)
{
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
return do_try_join_until(rel_time.count());
}
#endif
#else
private:
bool do_try_join_until_noexcept(struct timespec const &timeout, bool& res);
inline bool do_try_join_until(struct timespec const &timeout);
public:
#if defined BOOST_THREAD_USES_DATETIME
bool timed_join(const system_time& abs_time)
{
struct timespec const ts=detail::to_timespec(abs_time);
const detail::real_platform_timepoint ts(abs_time);
#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
detail::platform_duration d(ts - detail::real_platform_clock::now());
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
while ( ! do_try_join_until(detail::internal_platform_clock::now() + d) )
{
d = ts - detail::real_platform_clock::now();
if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
}
return true;
#else
return do_try_join_until(ts);
#endif
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
bool try_join_until(const chrono::time_point<thread_detail::internal_clock_t, chrono::nanoseconds>& tp)
{
using namespace chrono;
nanoseconds d = tp.time_since_epoch();
timespec ts = boost::detail::to_timespec(d);
return do_try_join_until(ts);
}
#endif
#endif
public:
#if defined BOOST_THREAD_USES_DATETIME
template<typename TimeDuration>
inline bool timed_join(TimeDuration const& rel_time)
bool timed_join(TimeDuration const& rel_time)
{
return timed_join(get_system_time()+rel_time);
detail::platform_duration d(rel_time);
#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
while ( ! do_try_join_until(detail::internal_platform_clock::now() + d) )
{
d = ts - detail::mono_platform_clock::now();
if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
}
return true;
#else
return do_try_join_until(detail::internal_platform_clock::now() + d);
#endif
}
#endif
void detach();
@@ -614,19 +585,13 @@ namespace thread_detail {
namespace this_thread
{
#ifdef BOOST_THREAD_PLATFORM_PTHREAD
inline thread::id get_id() BOOST_NOEXCEPT;
thread::id get_id() BOOST_NOEXCEPT;
#else
thread::id BOOST_THREAD_DECL get_id() BOOST_NOEXCEPT;
#endif
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
void BOOST_THREAD_DECL interruption_point();
bool BOOST_THREAD_DECL interruption_enabled() BOOST_NOEXCEPT;
bool BOOST_THREAD_DECL interruption_requested() BOOST_NOEXCEPT;
#endif
#if defined BOOST_THREAD_USES_DATETIME
inline BOOST_SYMBOL_VISIBLE void sleep(xtime const& abs_time)
inline BOOST_SYMBOL_VISIBLE void sleep(::boost::xtime const& abs_time)
{
sleep(system_time(abs_time));
}
@@ -745,7 +710,7 @@ namespace thread_detail {
};
#ifdef BOOST_THREAD_PLATFORM_PTHREAD
thread::id thread::get_id() const BOOST_NOEXCEPT
inline thread::id thread::get_id() const BOOST_NOEXCEPT
{
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
return const_cast<thread*>(this)->native_handle();
@@ -768,7 +733,7 @@ namespace thread_detail {
}
}
#endif
void thread::join() {
inline void thread::join() {
if (this_thread::get_id() == get_id())
boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself"));
@@ -777,11 +742,7 @@ namespace thread_detail {
);
}
#ifdef BOOST_THREAD_PLATFORM_PTHREAD
bool thread::do_try_join_until(struct timespec const &timeout)
#else
bool thread::do_try_join_until(uintmax_t timeout)
#endif
inline bool thread::do_try_join_until(detail::internal_platform_timepoint const &timeout)
{
if (this_thread::get_id() == get_id())
boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself"));
@@ -847,6 +808,7 @@ namespace thread_detail {
};
void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*);
//#ifndef BOOST_NO_EXCEPTIONS
struct shared_state_base;
#if defined(BOOST_THREAD_PLATFORM_WIN32)
inline void make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
@@ -860,6 +822,7 @@ namespace thread_detail {
#else
void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as);
#endif
//#endif
}
namespace this_thread

View File

@@ -0,0 +1,160 @@
#ifndef BOOST_THREAD_DETAIL_THREAD_SAFETY_HPP
#define BOOST_THREAD_DETAIL_THREAD_SAFETY_HPP
#if defined(__GNUC__) && !defined(__GXX_EXPERIMENTAL_CXX0X__)
//
// This is horrible, but it seems to be the only we can shut up the
// "anonymous variadic macros were introduced in C99 [-Wvariadic-macros]"
// warning that get spewed out otherwise in non-C++11 mode.
//
#pragma GCC system_header
#endif
// See https://clang.llvm.org/docs/ThreadSafetyAnalysis.html
// Un-comment to enable Thread Safety Analysis
//#define BOOST_THREAD_ENABLE_THREAD_SAFETY_ANALYSIS
// Enable thread safety attributes only with clang.
// The attributes can be safely erased when compiling with other compilers.
#if defined (BOOST_THREAD_ENABLE_THREAD_SAFETY_ANALYSIS) && defined(__clang__) && (!defined(SWIG))
#define BOOST_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
#define BOOST_THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
#endif
#define BOOST_THREAD_CAPABILITY(x) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
#define BOOST_THREAD_SCOPED_CAPABILITY \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
#define BOOST_THREAD_GUARDED_BY(x) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
#define BOOST_THREAD_PT_GUARDED_BY(x) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
#define BOOST_THREAD_ACQUIRED_BEFORE(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
#define BOOST_THREAD_ACQUIRED_AFTER(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
#define BOOST_THREAD_REQUIRES(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
#define BOOST_THREAD_REQUIRES_SHARED(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
#define BOOST_THREAD_ACQUIRE(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
#define BOOST_THREAD_ACQUIRE_SHARED(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
#define BOOST_THREAD_RELEASE(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
#define BOOST_THREAD_RELEASE_SHARED(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
#define BOOST_THREAD_TRY_ACQUIRE(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
#define BOOST_THREAD_TRY_ACQUIRE_SHARED(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
#define BOOST_THREAD_EXCLUDES(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
#define BOOST_THREAD_ASSERT_CAPABILITY(x) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
#define BOOST_THREAD_ASSERT_SHARED_CAPABILITY(x) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
#define BOOST_THREAD_RETURN_CAPABILITY(x) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
#define BOOST_THREAD_NO_THREAD_SAFETY_ANALYSIS \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
#if defined(__clang__) && (!defined(SWIG)) && defined(__FreeBSD__)
#if __has_attribute(no_thread_safety_analysis)
#define BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis))
#else
#define BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
#endif
#else
#define BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
#endif
#ifdef USE_LOCK_STYLE_THREAD_SAFETY_ATTRIBUTES
// The original version of thread safety analysis the following attribute
// definitions. These use a lock-based terminology. They are still in use
// by existing thread safety code, and will continue to be supported.
// Deprecated.
#define BOOST_THREAD_PT_GUARDED_VAR \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_var)
// Deprecated.
#define BOOST_THREAD_GUARDED_VAR \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(guarded_var)
// Replaced by REQUIRES
#define BOOST_THREAD_EXCLUSIVE_LOCKS_REQUIRED(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
// Replaced by REQUIRES_SHARED
#define BOOST_THREAD_SHARED_LOCKS_REQUIRED(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
// Replaced by CAPABILITY
#define BOOST_THREAD_LOCKABLE \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(lockable)
// Replaced by SCOPED_CAPABILITY
#define BOOST_THREAD_SCOPED_LOCKABLE \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
// Replaced by ACQUIRE
#define BOOST_THREAD_EXCLUSIVE_LOCK_FUNCTION(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
// Replaced by ACQUIRE_SHARED
#define BOOST_THREAD_SHARED_LOCK_FUNCTION(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
// Replaced by RELEASE and RELEASE_SHARED
#define BOOST_THREAD_UNLOCK_FUNCTION(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
// Replaced by TRY_ACQUIRE
#define BOOST_THREAD_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
// Replaced by TRY_ACQUIRE_SHARED
#define BOOST_THREAD_SHARED_TRYLOCK_FUNCTION(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
// Replaced by ASSERT_CAPABILITY
#define BOOST_THREAD_ASSERT_EXCLUSIVE_LOCK(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
// Replaced by ASSERT_SHARED_CAPABILITY
#define BOOST_THREAD_ASSERT_SHARED_LOCK(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))
// Replaced by EXCLUDE_CAPABILITY.
#define BOOST_THREAD_LOCKS_EXCLUDED(...) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
// Replaced by RETURN_CAPABILITY
#define BOOST_THREAD_LOCK_RETURNED(x) \
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
#endif // USE_LOCK_STYLE_THREAD_SAFETY_ATTRIBUTES
#endif // BOOST_THREAD_DETAIL_THREAD_SAFETY_HPP

View File

@@ -10,7 +10,7 @@
#include <boost/config/abi_prefix.hpp>
#if defined(BOOST_HAS_WINTHREADS)
#if defined(BOOST_THREAD_WIN32)
namespace boost
{
@@ -58,7 +58,7 @@ namespace boost
//it to be linked into the Boost.Threads library.
}
#endif //defined(BOOST_HAS_WINTHREADS)
#endif //defined(BOOST_THREAD_WIN32)
#include <boost/config/abi_suffix.hpp>

View File

@@ -56,7 +56,7 @@ namespace boost
{
}
~thread_exception() throw()
~thread_exception() BOOST_NOEXCEPT_OR_NOTHROW
{}
@@ -113,7 +113,7 @@ namespace boost
{
}
~lock_error() throw()
~lock_error() BOOST_NOEXCEPT_OR_NOTHROW
{}
};
@@ -141,7 +141,7 @@ namespace boost
}
~thread_resource_error() throw()
~thread_resource_error() BOOST_NOEXCEPT_OR_NOTHROW
{}
};

View File

@@ -11,6 +11,8 @@
#define BOOST_THREAD_EXECUTORS_BASIC_THREAD_POOL_HPP
#include <boost/thread/detail/config.hpp>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/thread.hpp>
@@ -231,13 +233,36 @@ namespace executors
// signal to all the worker threads that there will be no more submissions.
close();
// joins all the threads before destroying the thread pool resources (e.g. the queue).
join();
interrupt_and_join();
}
/**
* \b Effects: join all the threads.
*/
void join()
{
for (unsigned i = 0; i < threads.size(); ++i)
{
//threads[i].interrupt();
threads[i].join();
}
}
/**
* \b Effects: interrupt all the threads.
*/
void interrupt()
{
for (unsigned i = 0; i < threads.size(); ++i)
{
threads[i].interrupt();
}
}
/**
* \b Effects: interrupt and join all the threads.
*/
void interrupt_and_join()
{
for (unsigned i = 0; i < threads.size(); ++i)
{
@@ -324,3 +349,4 @@ using executors::basic_thread_pool;
#include <boost/config/abi_suffix.hpp>
#endif
#endif

View File

@@ -10,6 +10,7 @@
#define BOOST_THREAD_EXECUTORS_EXECUTOR_HPP
#include <boost/thread/detail/config.hpp>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/move.hpp>
@@ -146,3 +147,4 @@ namespace boost
#include <boost/config/abi_suffix.hpp>
#endif
#endif

View File

@@ -10,6 +10,7 @@
#define BOOST_THREAD_EXECUTORS_EXECUTOR_ADAPTOR_HPP
#include <boost/thread/detail/config.hpp>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
#include <boost/thread/executors/executor.hpp>
@@ -134,3 +135,4 @@ using executors::executor_adaptor;
#include <boost/config/abi_suffix.hpp>
#endif
#endif

View File

@@ -8,6 +8,7 @@
#define BOOST_THREAD_EXECUTORS_GENERIC_EXECUTOR_REF_HPP
#include <boost/thread/detail/config.hpp>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/move.hpp>
@@ -211,3 +212,4 @@ namespace boost
#include <boost/config/abi_suffix.hpp>
#endif
#endif

View File

@@ -10,9 +10,16 @@
#define BOOST_THREAD_INLINE_EXECUTOR_HPP
#include <boost/thread/detail/config.hpp>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
#include <exception> // std::terminate
#include <boost/throw_exception.hpp>
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/executors/work.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/lock_guard.hpp>
#include <boost/thread/concurrent_queues/queue_op_status.hpp> // sync_queue_is_closed
#include <boost/config/abi_prefix.hpp>
@@ -169,3 +176,4 @@ using executors::inline_executor;
#include <boost/config/abi_suffix.hpp>
#endif
#endif

View File

@@ -12,6 +12,9 @@
#define BOOST_THREAD_EXECUTORS_LOOP_EXECUTOR_HPP
#include <boost/thread/detail/config.hpp>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/concurrent_queues/sync_queue.hpp>
@@ -205,5 +208,6 @@ using executors::loop_executor;
}
#include <boost/config/abi_suffix.hpp>
#endif
#endif

View File

@@ -8,6 +8,9 @@
#ifndef BOOST_THREAD_EXECUTORS_SCHEDULED_THREAD_POOL_HPP
#define BOOST_THREAD_EXECUTORS_SCHEDULED_THREAD_POOL_HPP
#include <boost/thread/detail/config.hpp>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
#include <boost/thread/executors/detail/scheduled_executor_base.hpp>
namespace boost
@@ -46,4 +49,5 @@ using executors::scheduled_thread_pool;
} //end boost
#endif
#endif

View File

@@ -8,6 +8,7 @@
#define BOOST_THREAD_EXECUTORS_SCHEDULER_HPP
#include <boost/thread/detail/config.hpp>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
#include <boost/thread/executors/detail/scheduled_executor_base.hpp>
#include <boost/chrono/time_point.hpp>
@@ -279,3 +280,4 @@ namespace boost
#include <boost/config/abi_suffix.hpp>
#endif
#endif

View File

@@ -8,6 +8,8 @@
#ifndef BOOST_THREAD_EXECUTORS_SCHEDULING_ADAPTOR_HPP
#define BOOST_THREAD_EXECUTORS_SCHEDULING_ADAPTOR_HPP
#include <boost/thread/detail/config.hpp>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
#include <boost/thread/executors/detail/scheduled_executor_base.hpp>
#if defined(BOOST_MSVC)
@@ -60,3 +62,4 @@ namespace executors
#endif
#endif
#endif

View File

@@ -10,6 +10,9 @@
#define BOOST_THREAD_SERIAL_EXECUTOR_HPP
#include <boost/thread/detail/config.hpp>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
#include <exception>
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/concurrent_queues/sync_queue.hpp>
@@ -223,3 +226,4 @@ using executors::serial_executor;
#include <boost/config/abi_suffix.hpp>
#endif
#endif

View File

@@ -10,13 +10,19 @@
#define BOOST_THREAD_SERIAL_EXECUTOR_CONT_HPP
#include <boost/thread/detail/config.hpp>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
#include <exception> // std::terminate
#include <boost/throw_exception.hpp>
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/concurrent_queues/sync_queue.hpp>
#include <boost/thread/executors/work.hpp>
#include <boost/thread/executors/generic_executor_ref.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/future.hpp>
#include <boost/thread/scoped_thread.hpp>
#include <boost/thread/lock_guard.hpp>
#include <boost/config/abi_prefix.hpp>
@@ -32,7 +38,7 @@ namespace executors
private:
generic_executor_ref ex_;
future<void> fut_; // protected by mtx_
BOOST_THREAD_FUTURE<void> fut_; // protected by mtx_
bool closed_; // protected by mtx_
mutex mtx_;
@@ -44,7 +50,7 @@ namespace executors
};
continuation(BOOST_THREAD_RV_REF(work) tsk)
: task(boost::move(tsk)) {}
void operator()(future<void> f)
void operator()(BOOST_THREAD_FUTURE<void> f)
{
try {
task();
@@ -168,3 +174,4 @@ using executors::serial_executor_cont;
#include <boost/config/abi_suffix.hpp>
#endif
#endif

View File

@@ -10,10 +10,15 @@
#define BOOST_THREAD_THREAD_EXECUTOR_HPP
#include <boost/thread/detail/config.hpp>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
#include <boost/throw_exception.hpp>
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/executors/work.hpp>
#include <boost/thread/executors/executor.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/lock_guard.hpp>
#include <boost/thread/thread_only.hpp>
#include <boost/thread/scoped_thread.hpp>
#include <boost/thread/csbl/vector.hpp>
@@ -155,3 +160,4 @@ using executors::thread_executor;
#include <boost/config/abi_suffix.hpp>
#endif
#endif

View File

@@ -8,6 +8,8 @@
#define BOOST_THREAD_EXECUTORS_WORK_HPP
#include <boost/thread/detail/config.hpp>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
#include <boost/thread/detail/nullary_function.hpp>
#include <boost/thread/csbl/functional.hpp>
@@ -26,5 +28,5 @@ namespace boost
}
} // namespace boost
#endif
#endif // BOOST_THREAD_EXECUTORS_WORK_HPP

View File

@@ -10,6 +10,9 @@
// See http://www.boost.org/libs/thread for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#include <exception>
#include <boost/throw_exception.hpp>
#include <boost/thread/detail/config.hpp>
#include <boost/thread/future.hpp>
@@ -18,6 +21,7 @@
#endif
#include <boost/thread/experimental/exception_list.hpp>
#include <boost/thread/experimental/parallel/v2/inline_namespace.hpp>
#include <boost/thread/csbl/vector.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/config/abi_prefix.hpp>
@@ -126,7 +130,7 @@ BOOST_THREAD_INLINE_NAMESPACE(v2)
for (group_type::iterator it = group.begin(); it != group.end(); ++it)
{
future<void>& f = *it;
BOOST_THREAD_FUTURE<void>& f = *it;
if (f.has_exception())
{
try
@@ -191,7 +195,7 @@ protected:
Executor* ex;
#endif
exception_list exs;
typedef csbl::vector<future<void> > group_type;
typedef csbl::vector<BOOST_THREAD_FUTURE<void> > group_type;
group_type group;
public:

View File

@@ -24,6 +24,7 @@
namespace boost
{
class mutex;
/**
* externally_locked cloaks an object of type T, and actually provides full

View File

@@ -15,7 +15,16 @@
//#define BOOST_THREAD_CONTINUATION_SYNC
#ifndef BOOST_NO_EXCEPTIONS
#ifdef BOOST_NO_EXCEPTIONS
namespace boost
{
namespace detail {
struct shared_state_base {
void notify_deferred() {}
};
}
}
#else
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/detail/move.hpp>
@@ -109,6 +118,7 @@ namespace boost
namespace executors {
class executor;
}
using executors::executor;
#endif
typedef shared_ptr<executor> executor_ptr_type;
@@ -159,7 +169,7 @@ namespace boost
boost::function<void()> callback;
// This declaration should be only included conditionally, but is included to maintain the same layout.
continuations_type continuations;
executor_ptr_type ex;
executor_ptr_type ex_;
// This declaration should be only included conditionally, but is included to maintain the same layout.
virtual void launch_continuation()
@@ -173,43 +183,49 @@ namespace boost
is_constructed(false),
policy_(launch::none),
continuations(),
ex()
ex_()
{}
shared_state_base(exceptional_ptr const& ex_):
exception(ex_.ptr_),
shared_state_base(exceptional_ptr const& ex):
exception(ex.ptr_),
done(true),
is_valid_(true),
is_deferred_(false),
is_constructed(false),
policy_(launch::none),
continuations(),
ex()
ex_()
{}
virtual ~shared_state_base()
{
}
bool is_done()
{
return done;
}
executor_ptr_type get_executor()
{
return ex;
return ex_;
}
void set_executor_policy(executor_ptr_type aex)
{
set_executor();
ex = aex;
ex_ = aex;
}
void set_executor_policy(executor_ptr_type aex, boost::lock_guard<boost::mutex>&)
{
set_executor();
ex = aex;
ex_ = aex;
}
void set_executor_policy(executor_ptr_type aex, boost::unique_lock<boost::mutex>&)
{
set_executor();
ex = aex;
ex_ = aex;
}
bool valid(boost::unique_lock<boost::mutex>&) { return is_valid_; }
@@ -262,6 +278,10 @@ namespace boost
external_waiters.erase(it);
}
#if 0
// this inline definition results in ODR. See https://github.com/boostorg/thread/issues/193
// to avoid it, we define the function on the derived templates using the macro BOOST_THREAD_DO_CONTINUATION
#define BOOST_THREAD_DO_CONTINUATION
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
void do_continuation(boost::unique_lock<boost::mutex>& lock)
{
@@ -279,6 +299,31 @@ namespace boost
{
}
#endif
#else
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
#define BOOST_THREAD_DO_CONTINUATION \
void do_continuation(boost::unique_lock<boost::mutex>& lock) \
{ \
if (! this->continuations.empty()) { \
continuations_type the_continuations = this->continuations; \
this->continuations.clear(); \
relocker rlk(lock); \
for (continuations_type::iterator it = the_continuations.begin(); it != the_continuations.end(); ++it) { \
(*it)->launch_continuation(); \
} \
} \
}
#else
#define BOOST_THREAD_DO_CONTINUATION \
void do_continuation(boost::unique_lock<boost::mutex>&) \
{ \
}
#endif
virtual void do_continuation(boost::unique_lock<boost::mutex>&) = 0;
#endif
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
virtual void set_continuation_ptr(continuation_ptr_type continuation, boost::unique_lock<boost::mutex>& lock)
{
@@ -348,10 +393,7 @@ namespace boost
is_deferred_=false;
execute(lk);
}
while(!done)
{
waiters.wait(lk);
}
waiters.wait(lk, boost::bind(&shared_state_base::is_done, boost::ref(*this)));
if(rethrow && exception)
{
boost::rethrow_exception(exception);
@@ -370,6 +412,17 @@ namespace boost
}
#if defined BOOST_THREAD_USES_DATETIME
template<typename Duration>
bool timed_wait(Duration const& rel_time)
{
boost::unique_lock<boost::mutex> lock(this->mutex);
if (is_deferred_)
return false;
do_callback(lock);
return waiters.timed_wait(lock, rel_time, boost::bind(&shared_state_base::is_done, boost::ref(*this)));
}
bool timed_wait_until(boost::system_time const& target_time)
{
boost::unique_lock<boost::mutex> lock(this->mutex);
@@ -377,15 +430,7 @@ namespace boost
return false;
do_callback(lock);
while(!done)
{
bool const success=waiters.timed_wait(lock,target_time);
if(!success && !done)
{
return false;
}
}
return true;
return waiters.timed_wait(lock, target_time, boost::bind(&shared_state_base::is_done, boost::ref(*this)));
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
@@ -398,13 +443,9 @@ namespace boost
if (is_deferred_)
return future_status::deferred;
do_callback(lock);
while(!done)
if(!waiters.wait_until(lock, abs_time, boost::bind(&shared_state_base::is_done, boost::ref(*this))))
{
cv_status const st=waiters.wait_until(lock,abs_time);
if(st==cv_status::timeout && !done)
{
return future_status::timeout;
}
return future_status::timeout;
}
return future_status::ready;
}
@@ -546,10 +587,8 @@ namespace boost
detail::shared_state_base(ex), result()
{}
~shared_state()
{
}
// locating this definition on the template avoid the ODR issue. See https://github.com/boostorg/thread/issues/193
BOOST_THREAD_DO_CONTINUATION
void mark_finished_with_result_internal(source_reference_type result_, boost::unique_lock<boost::mutex>& lock)
{
@@ -732,9 +771,8 @@ namespace boost
detail::shared_state_base(ex), result(0)
{}
~shared_state()
{
}
// locating this definition on the template avoid the ODR issue. See https://github.com/boostorg/thread/issues/193
BOOST_THREAD_DO_CONTINUATION
void mark_finished_with_result_internal(source_reference_type result_, boost::unique_lock<boost::mutex>& lock)
{
@@ -811,6 +849,9 @@ namespace boost
detail::shared_state_base(ex)
{}
// locating this definition on the template avoid the ODR issue. See https://github.com/boostorg/thread/issues/193
BOOST_THREAD_DO_CONTINUATION
void mark_finished_with_result_internal(boost::unique_lock<boost::mutex>& lock)
{
mark_finished_internal(lock);
@@ -899,10 +940,7 @@ namespace boost
join();
#elif defined BOOST_THREAD_ASYNC_FUTURE_WAITS
unique_lock<boost::mutex> lk(this->mutex);
while(!this->done)
{
this->waiters.wait(lk);
}
this->waiters.wait(lk, boost::bind(&shared_state_base::is_done, boost::ref(*this)));
#endif
}
@@ -1007,10 +1045,8 @@ namespace boost
template<typename Rp, typename Fp>
struct future_deferred_shared_state: shared_state<Rp>
{
typedef shared_state<Rp> base_type;
Fp func_;
public:
explicit future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f)
: func_(boost::move(f))
{
@@ -1035,10 +1071,8 @@ namespace boost
template<typename Rp, typename Fp>
struct future_deferred_shared_state<Rp&,Fp>: shared_state<Rp&>
{
typedef shared_state<Rp&> base_type;
Fp func_;
public:
explicit future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f)
: func_(boost::move(f))
{
@@ -1060,10 +1094,8 @@ namespace boost
template<typename Fp>
struct future_deferred_shared_state<void,Fp>: shared_state<void>
{
typedef shared_state<void> base_type;
Fp func_;
public:
explicit future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f)
: func_(boost::move(f))
{
@@ -1091,7 +1123,6 @@ namespace boost
public:
typedef std::vector<int>::size_type count_type;
private:
struct registered_waiter;
struct registered_waiter
{
boost::shared_ptr<detail::shared_state_base> future_;
@@ -1452,7 +1483,11 @@ namespace boost
template<typename Duration>
bool timed_wait(Duration const& rel_time) const
{
return timed_wait_until(boost::get_system_time()+rel_time);
if(!future_)
{
boost::throw_exception(future_uninitialized());
}
return future_->timed_wait(rel_time);
}
bool timed_wait_until(boost::system_time const& abs_time) const
@@ -3155,7 +3190,7 @@ namespace boost
}
};
#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR)
#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR)
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
@@ -3497,7 +3532,7 @@ namespace boost
{}
// construction and destruction
#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR)
#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR)
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
@@ -3587,7 +3622,7 @@ namespace boost
#endif
#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS
#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR)
#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR)
template <class Allocator>
packaged_task(boost::allocator_arg_t, Allocator a, R(*f)())
{
@@ -3608,7 +3643,7 @@ namespace boost
task = task_ptr(::new(a2.allocate(1)) task_shared_state_type(f), D(a2, 1) );
future_obtained = false;
}
#endif // BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
#endif // BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
template <class F, class Allocator>
@@ -3825,7 +3860,7 @@ namespace detail
// future<R> async(launch policy, F&&, ArgTypes&&...);
////////////////////////////////
#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
template <class R, class... ArgTypes>
@@ -3884,7 +3919,7 @@ namespace detail
}
}
#endif
#endif // defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR)
#endif // defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR)
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
@@ -4113,7 +4148,7 @@ namespace detail {
//#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#if defined(BOOST_THREAD_PROVIDES_INVOKE) && ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ! defined(BOOST_NO_CXX11_HDR_TUPLE)
#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR
template <class Executor, class R, class... ArgTypes>
BOOST_THREAD_FUTURE<R>
@@ -4129,7 +4164,7 @@ namespace detail {
)
));
}
#endif // defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
#endif // defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR
template <class Executor, class F, class ...ArgTypes>
BOOST_THREAD_FUTURE<typename boost::result_of<typename decay<F>::type(
@@ -4148,7 +4183,7 @@ namespace detail {
}
#else // ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR
template <class Executor, class R>
BOOST_THREAD_FUTURE<R>
@@ -4178,7 +4213,7 @@ namespace detail {
)
));
}
#endif // defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
#endif // defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR
template <class Executor, class F>
BOOST_THREAD_FUTURE<typename boost::result_of<typename decay<F>::type()>::type>
@@ -4234,7 +4269,7 @@ namespace detail {
// future<R> async(F&&, ArgTypes&&...);
////////////////////////////////
#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
template <class R, class... ArgTypes>
BOOST_THREAD_FUTURE<R>
@@ -4956,6 +4991,10 @@ namespace detail {
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type>(
lock, boost::move(*this), boost::forward<F>(func)
)));
} else if (underlying_cast<int>(policy) & int(launch::sync)) {
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_sync_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type>(
lock, boost::move(*this), boost::forward<F>(func)
)));
#ifdef BOOST_THREAD_PROVIDES_EXECUTORS
} else if (underlying_cast<int>(policy) & int(launch::executor)) {
assert(this->future_->get_executor());
@@ -4976,6 +5015,10 @@ namespace detail {
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type>(
lock, boost::move(*this), boost::forward<F>(func)
)));
} else if (underlying_cast<int>(policy_) & int(launch::sync)) {
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_sync_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type>(
lock, boost::move(*this), boost::forward<F>(func)
)));
#ifdef BOOST_THREAD_PROVIDES_EXECUTORS
} else if (underlying_cast<int>(policy_) & int(launch::executor)) {
assert(this->future_->get_executor());

View File

@@ -14,6 +14,7 @@
#include <boost/thread/futures/is_future_type.hpp>
#include <boost/thread/lock_algorithms.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/core/enable_if.hpp>
#include <boost/next_prior.hpp>

View File

@@ -0,0 +1,22 @@
// (C) Copyright 2013 Vicente J. Botet Escriba
// 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_INTERRUPTION_HPP
#define BOOST_THREAD_INTERRUPTION_HPP
#include <boost/thread/detail/config.hpp>
namespace boost
{
namespace this_thread
{
void BOOST_THREAD_DECL interruption_point();
bool BOOST_THREAD_DECL interruption_enabled() BOOST_NOEXCEPT;
bool BOOST_THREAD_DECL interruption_requested() BOOST_NOEXCEPT;
}
}
#endif // header

View File

@@ -23,7 +23,7 @@ namespace boost
{
template <typename Mutex>
class lock_guard
class BOOST_THREAD_SCOPED_CAPABILITY lock_guard
{
private:
Mutex& m;
@@ -32,13 +32,13 @@ namespace boost
typedef Mutex mutex_type;
BOOST_THREAD_NO_COPYABLE( lock_guard )
explicit lock_guard(Mutex& m_) :
explicit lock_guard(Mutex& m_) BOOST_THREAD_ACQUIRE(m_) :
m(m_)
{
m.lock();
}
lock_guard(Mutex& m_, adopt_lock_t) :
lock_guard(Mutex& m_, adopt_lock_t) BOOST_THREAD_REQUIRES(m_) :
m(m_)
{
#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
@@ -62,7 +62,7 @@ namespace boost
}
#endif
~lock_guard()
~lock_guard() BOOST_THREAD_RELEASE()
{
m.unlock();
}

View File

@@ -11,7 +11,12 @@
#include <boost/assert.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/type_traits/integral_constant.hpp>
#ifdef BOOST_NO_CXX11_SFINAE_EXPR
#include <boost/type_traits/is_class.hpp>
#else
#include <boost/type_traits/declval.hpp>
#endif
#include <boost/config/abi_prefix.hpp>
@@ -33,6 +38,7 @@ namespace boost
#ifndef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES
namespace detail
{
#ifdef BOOST_NO_CXX11_SFINAE_EXPR
#define BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(member_name) \
template<typename T, bool=boost::is_class<T>::value> \
struct has_member_called_##member_name \
@@ -142,6 +148,31 @@ namespace boost
BOOST_STATIC_CONSTANT(
bool,value=sizeof(has_member_try_lock<T>::has_member(&T::try_lock))==sizeof(true_type));
};
#else
template<typename T,typename Enabled=void>
struct has_member_lock : false_type {};
template<typename T>
struct has_member_lock<T,
decltype(void(boost::declval<T&>().lock()))
> : true_type {};
template<typename T,typename Enabled=void>
struct has_member_unlock : false_type {};
template<typename T>
struct has_member_unlock<T,
decltype(void(boost::declval<T&>().unlock()))
> : true_type {};
template<typename T,typename Enabled=bool>
struct has_member_try_lock : false_type {};
template<typename T>
struct has_member_try_lock<T,
decltype(bool(boost::declval<T&>().try_lock()))
> : true_type {};
#endif
}

View File

@@ -30,6 +30,9 @@ namespace boost
};
//]
// A proper name for basic_poly_lockable, consistent with naming scheme of other polymorphic wrappers
typedef basic_poly_lockable poly_basic_lockable;
//[poly_lockable
class poly_lockable : public basic_poly_lockable
{
@@ -51,18 +54,20 @@ namespace boost
template <typename Clock, typename Duration>
bool try_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
{
return try_lock_until(time_point_cast<Clock::time_point>(abs_time));
return try_lock_until(chrono::time_point_cast<Clock::time_point>(abs_time));
}
virtual bool try_lock_for(chrono::nanoseconds const & relative_time)=0;
template <typename Rep, typename Period>
bool try_lock_for(chrono::duration<Rep, Period> const & rel_time)
{
return try_lock_for(duration_cast<Clock::duration>(rel_time));
return try_lock_for(chrono::duration_cast<chrono::nanoseconds>(rel_time));
}
};
//]
// A proper name for timed_poly_lockable, consistent with naming scheme of other polymorphic wrappers
typedef timed_poly_lockable poly_timed_lockable;
}
#endif

View File

@@ -33,20 +33,22 @@ namespace boost
template <typename Clock, typename Duration>
bool try_lock_shared_until(chrono::time_point<Clock, Duration> const & abs_time)
{
return try_lock_shared_until(time_point_cast<Clock::time_point>(abs_time));
return try_lock_shared_until(chrono::time_point_cast<Clock::time_point>(abs_time));
}
virtual bool try_lock_shared_for(chrono::nanoseconds const & relative_time)=0;
template <typename Rep, typename Period>
bool try_lock_shared_for(chrono::duration<Rep, Period> const & rel_time)
{
return try_lock_shared_for(duration_cast<Clock::duration>(rel_time));
return try_lock_shared_for(chrono::duration_cast<chrono::nanoseconds>(rel_time));
}
};
//]
// A proper name for shared_poly_lockable, consistent with naming scheme of other polymorphic wrappers
typedef shared_poly_lockable poly_shared_lockable;
//[upgrade_poly_lockable
class upgrade_poly_lockable: public shared_poly_lockable
{
@@ -62,14 +64,14 @@ namespace boost
template <typename Clock, typename Duration>
bool try_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time)
{
return try_lock_upgrade_until(time_point_cast<Clock::time_point>(abs_time));
return try_lock_upgrade_until(chrono::time_point_cast<Clock::time_point>(abs_time));
}
virtual bool try_lock_upgrade_for(chrono::nanoseconds const & relative_time)=0;
template <typename Rep, typename Period>
bool try_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time)
{
return try_lock_upgrade_for(duration_cast<Clock::duration>(rel_time));
return try_lock_upgrade_for(chrono::duration_cast<chrono::nanoseconds>(rel_time));
}
virtual bool try_unlock_shared_and_lock() = 0;
@@ -79,14 +81,14 @@ namespace boost
template <typename Clock, typename Duration>
bool try_unlock_shared_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
{
return try_unlock_shared_and_lock_until(time_point_cast<Clock::time_point>(abs_time));
return try_unlock_shared_and_lock_until(chrono::time_point_cast<Clock::time_point>(abs_time));
}
virtual bool try_unlock_shared_and_lock_for(chrono::nanoseconds const & relative_time)=0;
template <typename Rep, typename Period>
bool try_unlock_shared_and_lock_for(chrono::duration<Rep, Period> const & rel_time)
{
return try_unlock_shared_and_lock_for(duration_cast<Clock::duration>(rel_time));
return try_unlock_shared_and_lock_for(chrono::duration_cast<chrono::nanoseconds>(rel_time));
}
virtual void unlock_and_lock_shared() = 0;
@@ -97,14 +99,14 @@ namespace boost
template <typename Clock, typename Duration>
bool try_unlock_shared_and_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time)
{
return try_unlock_shared_and_lock_upgrade_until(time_point_cast<Clock::time_point>(abs_time));
return try_unlock_shared_and_lock_upgrade_until(chrono::time_point_cast<Clock::time_point>(abs_time));
}
virtual bool try_unlock_shared_and_lock_upgrade_for(chrono::nanoseconds const & relative_time)=0;
template <typename Rep, typename Period>
bool try_unlock_shared_and_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time)
{
return try_unlock_shared_and_lock_upgrade_for(duration_cast<Clock::duration>(rel_time));
return try_unlock_shared_and_lock_upgrade_for(chrono::duration_cast<chrono::nanoseconds>(rel_time));
}
virtual void unlock_and_lock_upgrade() = 0;
@@ -116,20 +118,22 @@ namespace boost
template <typename Clock, typename Duration>
bool try_unlock_upgrade_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
{
return try_unlock_upgrade_and_lock_until(time_point_cast<Clock::time_point>(abs_time));
return try_unlock_upgrade_and_lock_until(chrono::time_point_cast<Clock::time_point>(abs_time));
}
virtual bool try_unlock_upgrade_and_lock_for(chrono::nanoseconds const & relative_time)=0;
template <typename Rep, typename Period>
bool try_unlock_upgrade_and_lock_for(chrono::duration<Rep, Period> const & rel_time)
{
return try_unlock_upgrade_and_lock_for(duration_cast<Clock::duration>(rel_time));
return try_unlock_upgrade_and_lock_for(chrono::duration_cast<chrono::nanoseconds>(rel_time));
}
virtual void unlock_upgrade_and_lock_shared() = 0;
};
//]
//]
// A proper name for upgrade_poly_lockable, consistent with naming scheme of other polymorphic wrappers
typedef upgrade_poly_lockable poly_upgrade_lockable;
}
#endif

View File

@@ -17,7 +17,7 @@
namespace boost
{
//[shared_lockable_adapter
//[poly_shared_lockable_adapter
template <typename Mutex, typename Base=poly_shared_lockable>
class poly_shared_lockable_adapter: public poly_timed_lockable_adapter<Mutex, Base>
{
@@ -54,9 +54,9 @@ namespace boost
//]
//[upgrade_lockable_adapter
//[poly_upgrade_lockable_adapter
template <typename Mutex, typename Base=poly_shared_lockable>
class upgrade_lockable_adapter: public shared_lockable_adapter<Mutex, Base>
class poly_upgrade_lockable_adapter: public poly_shared_lockable_adapter<Mutex, Base>
{
public:
typedef Mutex mutex_type;
@@ -102,7 +102,6 @@ namespace boost
{
return this->mtx().try_unlock_shared_and_lock_until(abs_time);
}
template <typename Rep, typename Period>
bool try_unlock_shared_and_lock_for(chrono::nanoseconds const & rel_time)
{
return this->mtx().try_unlock_shared_and_lock_for(rel_time);

View File

@@ -6,9 +6,12 @@
// (C) Copyright 2007-10 Anthony Williams
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
#include <boost/thread/pthread/timespec.hpp>
#include <boost/thread/detail/platform_time.hpp>
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
#include <boost/thread/pthread/pthread_helpers.hpp>
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
#include <boost/thread/interruption.hpp>
#include <boost/thread/pthread/thread_data.hpp>
#endif
#include <boost/thread/pthread/condition_variable_fwd.hpp>
@@ -18,17 +21,12 @@
#endif
#include <boost/thread/detail/delete.hpp>
#include <algorithm>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
namespace this_thread
{
void BOOST_THREAD_DECL interruption_point();
}
#endif
namespace thread_cv_detail
{
template<typename MutexType>
@@ -78,26 +76,35 @@ namespace boost
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
pthread_mutex_t* the_mutex = &internal_mutex;
guard.activate(m);
res = pthread_cond_wait(&cond,the_mutex);
res = posix::pthread_cond_wait(&cond,the_mutex);
check_for_interruption.unlock_if_locked();
guard.deactivate();
#else
pthread_mutex_t* the_mutex = m.mutex()->native_handle();
res = pthread_cond_wait(&cond,the_mutex);
res = posix::pthread_cond_wait(&cond,the_mutex);
#endif
}
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
this_thread::interruption_point();
#endif
if(res && res != EINTR)
if(res)
{
boost::throw_exception(condition_error(res, "boost::condition_variable::wait failed in pthread_cond_wait"));
}
}
// When this function returns true:
// * A notification (or sometimes a spurious OS signal) has been received
// * Do not assume that the timeout has not been reached
// * Do not assume that the predicate has been changed
//
// When this function returns false:
// * The timeout has been reached
// * Do not assume that a notification has not been received
// * Do not assume that the predicate has not been changed
inline bool condition_variable::do_wait_until(
unique_lock<mutex>& m,
struct timespec const &timeout)
detail::internal_platform_timepoint const &timeout)
{
#if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
if (!m.owns_lock())
@@ -112,12 +119,12 @@ namespace boost
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
pthread_mutex_t* the_mutex = &internal_mutex;
guard.activate(m);
cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout);
cond_res=posix::pthread_cond_timedwait(&cond,the_mutex,&timeout.getTs());
check_for_interruption.unlock_if_locked();
guard.deactivate();
#else
pthread_mutex_t* the_mutex = m.mutex()->native_handle();
cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout);
cond_res=posix::pthread_cond_timedwait(&cond,the_mutex,&timeout.getTs());
#endif
}
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
@@ -139,7 +146,7 @@ namespace boost
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
#endif
BOOST_VERIFY(!pthread_cond_signal(&cond));
BOOST_VERIFY(!posix::pthread_cond_signal(&cond));
}
inline void condition_variable::notify_all() BOOST_NOEXCEPT
@@ -147,7 +154,7 @@ namespace boost
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
#endif
BOOST_VERIFY(!pthread_cond_broadcast(&cond));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&cond));
}
class condition_variable_any
@@ -159,22 +166,22 @@ namespace boost
BOOST_THREAD_NO_COPYABLE(condition_variable_any)
condition_variable_any()
{
int const res=pthread_mutex_init(&internal_mutex,NULL);
int const res=posix::pthread_mutex_init(&internal_mutex);
if(res)
{
boost::throw_exception(thread_resource_error(res, "boost::condition_variable_any::condition_variable_any() failed in pthread_mutex_init"));
}
int const res2 = detail::monotonic_pthread_cond_init(cond);
int const res2 = posix::pthread_cond_init(&cond);
if(res2)
{
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
boost::throw_exception(thread_resource_error(res2, "boost::condition_variable_any::condition_variable_any() failed in detail::monotonic_pthread_cond_init"));
BOOST_VERIFY(!posix::pthread_mutex_destroy(&internal_mutex));
boost::throw_exception(thread_resource_error(res2, "boost::condition_variable_any::condition_variable_any() failed in pthread_cond_init"));
}
}
~condition_variable_any()
{
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
BOOST_VERIFY(!pthread_cond_destroy(&cond));
BOOST_VERIFY(!posix::pthread_mutex_destroy(&internal_mutex));
BOOST_VERIFY(!posix::pthread_cond_destroy(&cond));
}
template<typename lock_type>
@@ -189,7 +196,7 @@ namespace boost
boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
#endif
guard.activate(m);
res=pthread_cond_wait(&cond,&internal_mutex);
res=posix::pthread_cond_wait(&cond,&internal_mutex);
check_for_interruption.unlock_if_locked();
guard.deactivate();
}
@@ -205,18 +212,38 @@ namespace boost
template<typename lock_type,typename predicate_type>
void wait(lock_type& m,predicate_type pred)
{
while(!pred()) wait(m);
while (!pred())
{
wait(m);
}
}
#if defined BOOST_THREAD_USES_DATETIME
template<typename lock_type>
bool timed_wait(lock_type& m,boost::system_time const& abs_time)
{
struct timespec const timeout=detail::to_timespec(abs_time);
return do_wait_until(m, timeout);
#if defined BOOST_THREAD_WAIT_BUG
const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG);
#else
const detail::real_platform_timepoint ts(abs_time);
#endif
#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
// The system time may jump while this function is waiting. To compensate for this and time
// out near the correct time, we could call do_wait_until() in a loop with a short timeout
// and recheck the time remaining each time through the loop. However, because we can't
// check the predicate each time do_wait_until() completes, this introduces the possibility
// of not exiting the function when a notification occurs, since do_wait_until() may report
// that it timed out even though a notification was received. The best this function can do
// is report correctly whether or not it reached the timeout time.
const detail::platform_duration d(ts - detail::real_platform_clock::now());
do_wait_until(m, detail::internal_platform_clock::now() + d);
return ts > detail::real_platform_clock::now();
#else
return do_wait_until(m, ts);
#endif
}
template<typename lock_type>
bool timed_wait(lock_type& m,xtime const& abs_time)
bool timed_wait(lock_type& m,::boost::xtime const& abs_time)
{
return timed_wait(m,system_time(abs_time));
}
@@ -224,22 +251,59 @@ namespace boost
template<typename lock_type,typename duration_type>
bool timed_wait(lock_type& m,duration_type const& wait_duration)
{
return timed_wait(m,get_system_time()+wait_duration);
if (wait_duration.is_pos_infinity())
{
wait(m);
return true;
}
if (wait_duration.is_special())
{
return true;
}
detail::platform_duration d(wait_duration);
#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
// The system time may jump while this function is waiting. To compensate for this and time
// out near the correct time, we could call do_wait_until() in a loop with a short timeout
// and recheck the time remaining each time through the loop. However, because we can't
// check the predicate each time do_wait_until() completes, this introduces the possibility
// of not exiting the function when a notification occurs, since do_wait_until() may report
// that it timed out even though a notification was received. The best this function can do
// is report correctly whether or not it reached the timeout time.
const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
do_wait_until(m, detail::internal_platform_clock::now() + d);
return ts > detail::mono_platform_clock::now();
#else
return do_wait_until(m, detail::internal_platform_clock::now() + d);
#endif
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,boost::system_time const& abs_time, predicate_type pred)
{
#if defined BOOST_THREAD_WAIT_BUG
const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG);
#else
const detail::real_platform_timepoint ts(abs_time);
#endif
while (!pred())
{
if(!timed_wait(m, abs_time))
return pred();
#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
// The system time may jump while this function is waiting. To compensate for this
// and time out near the correct time, we call do_wait_until() in a loop with a
// short timeout and recheck the time remaining each time through the loop.
detail::platform_duration d(ts - detail::real_platform_clock::now());
if (d <= detail::platform_duration::zero()) break; // timeout occurred
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
do_wait_until(m, detail::internal_platform_clock::now() + d);
#else
if (!do_wait_until(m, ts)) break; // timeout occurred
#endif
}
return true;
return pred();
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,xtime const& abs_time, predicate_type pred)
bool timed_wait(lock_type& m,::boost::xtime const& abs_time, predicate_type pred)
{
return timed_wait(m,system_time(abs_time),pred);
}
@@ -247,24 +311,52 @@ namespace boost
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);
if (wait_duration.is_pos_infinity())
{
while (!pred())
{
wait(m);
}
return true;
}
if (wait_duration.is_special())
{
return pred();
}
detail::platform_duration d(wait_duration);
#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
// The system time may jump while this function is waiting. To compensate for this
// and time out near the correct time, we call do_wait_until() in a loop with a
// short timeout and recheck the time remaining each time through the loop.
const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
while (!pred())
{
if (d <= detail::platform_duration::zero()) break; // timeout occurred
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
do_wait_until(m, detail::internal_platform_clock::now() + d);
d = ts - detail::mono_platform_clock::now();
}
#else
const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d);
while (!pred())
{
if (!do_wait_until(m, ts)) break; // timeout occurred
}
#endif
return pred();
}
#endif
#ifndef BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
#ifdef BOOST_THREAD_USES_CHRONO
template <class lock_type,class Duration>
cv_status
wait_until(
lock_type& lock,
const chrono::time_point<chrono::system_clock, Duration>& t)
const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
{
using namespace chrono;
typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
wait_until(lock,
nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
return system_clock::now() < t ? cv_status::no_timeout :
cv_status::timeout;
const boost::detail::internal_platform_timepoint ts(t);
if (do_wait_until(lock, ts)) return cv_status::no_timeout;
else return cv_status::timeout;
}
template <class lock_type, class Clock, class Duration>
@@ -273,11 +365,18 @@ namespace boost
lock_type& lock,
const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
system_clock::time_point s_now = system_clock::now();
typename Clock::time_point c_now = Clock::now();
wait_until(lock, s_now + ceil<nanoseconds>(t - c_now));
return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout;
// The system time may jump while this function is waiting. To compensate for this and time
// out near the correct time, we could call do_wait_until() in a loop with a short timeout
// and recheck the time remaining each time through the loop. However, because we can't
// check the predicate each time do_wait_until() completes, this introduces the possibility
// of not exiting the function when a notification occurs, since do_wait_until() may report
// that it timed out even though a notification was received. The best this function can do
// is report correctly whether or not it reached the timeout time.
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
common_duration d(t - Clock::now());
do_wait_until(lock, detail::internal_chrono_clock::now() + d);
if (t > Clock::now()) return cv_status::no_timeout;
else return cv_status::timeout;
}
template <class lock_type, class Rep, class Period>
@@ -286,86 +385,24 @@ namespace boost
lock_type& lock,
const chrono::duration<Rep, Period>& d)
{
using namespace chrono;
system_clock::time_point s_now = system_clock::now();
steady_clock::time_point c_now = steady_clock::now();
wait_until(lock, s_now + ceil<nanoseconds>(d));
return steady_clock::now() - c_now < d ? cv_status::no_timeout :
cv_status::timeout;
return wait_until(lock, chrono::steady_clock::now() + d);
}
template <class lock_type>
cv_status wait_until(
lock_type& lk,
chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp)
{
using namespace chrono;
nanoseconds d = tp.time_since_epoch();
timespec ts = boost::detail::to_timespec(d);
if (do_wait_until(lk, ts)) return cv_status::no_timeout;
else return cv_status::timeout;
}
#endif
#else // defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
#ifdef BOOST_THREAD_USES_CHRONO
template <class lock_type, class Duration>
cv_status
template <class lock_type, class Duration, class Predicate>
bool
wait_until(
lock_type& lock,
const chrono::time_point<chrono::steady_clock, Duration>& t)
lock_type& lock,
const chrono::time_point<detail::internal_chrono_clock, Duration>& t,
Predicate pred)
{
using namespace chrono;
typedef time_point<steady_clock, nanoseconds> nano_sys_tmpt;
wait_until(lock,
nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
return steady_clock::now() < t ? cv_status::no_timeout :
cv_status::timeout;
const detail::internal_platform_timepoint ts(t);
while (!pred())
{
if (!do_wait_until(lock, ts)) break; // timeout occurred
}
return pred();
}
template <class lock_type, class Clock, class Duration>
cv_status
wait_until(
lock_type& lock,
const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
steady_clock::time_point s_now = steady_clock::now();
typename Clock::time_point c_now = Clock::now();
wait_until(lock, s_now + ceil<nanoseconds>(t - c_now));
return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout;
}
template <class lock_type, class Rep, class Period>
cv_status
wait_for(
lock_type& lock,
const chrono::duration<Rep, Period>& d)
{
using namespace chrono;
steady_clock::time_point c_now = steady_clock::now();
wait_until(lock, c_now + ceil<nanoseconds>(d));
return steady_clock::now() - c_now < d ? cv_status::no_timeout :
cv_status::timeout;
}
template <class lock_type>
inline cv_status wait_until(
lock_type& lock,
chrono::time_point<chrono::steady_clock, chrono::nanoseconds> tp)
{
using namespace chrono;
nanoseconds d = tp.time_since_epoch();
timespec ts = boost::detail::to_timespec(d);
if (do_wait_until(lock, ts)) return cv_status::no_timeout;
else return cv_status::timeout;
}
#endif
#endif // defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
#ifdef BOOST_THREAD_USES_CHRONO
template <class lock_type, class Clock, class Duration, class Predicate>
bool
wait_until(
@@ -373,12 +410,18 @@ namespace boost
const chrono::time_point<Clock, Duration>& t,
Predicate pred)
{
// The system time may jump while this function is waiting. To compensate for this
// and time out near the correct time, we call do_wait_until() in a loop with a
// short timeout and recheck the time remaining each time through the loop.
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
while (!pred())
{
if (wait_until(lock, t) == cv_status::timeout)
return pred();
common_duration d(t - Clock::now());
if (d <= common_duration::zero()) break; // timeout occurred
d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d));
}
return true;
return pred();
}
template <class lock_type, class Rep, class Period, class Predicate>
@@ -388,27 +431,36 @@ namespace boost
const chrono::duration<Rep, Period>& d,
Predicate pred)
{
return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
}
#endif
void notify_one() BOOST_NOEXCEPT
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
BOOST_VERIFY(!pthread_cond_signal(&cond));
BOOST_VERIFY(!posix::pthread_cond_signal(&cond));
}
void notify_all() BOOST_NOEXCEPT
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
BOOST_VERIFY(!pthread_cond_broadcast(&cond));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&cond));
}
private: // used by boost::thread::try_join_until
private:
// When this function returns true:
// * A notification (or sometimes a spurious OS signal) has been received
// * Do not assume that the timeout has not been reached
// * Do not assume that the predicate has been changed
//
// When this function returns false:
// * The timeout has been reached
// * Do not assume that a notification has not been received
// * Do not assume that the predicate has not been changed
template <class lock_type>
bool do_wait_until(
lock_type& m,
struct timespec const &timeout)
detail::internal_platform_timepoint const &timeout)
{
int res=0;
{
@@ -419,7 +471,7 @@ namespace boost
boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
#endif
guard.activate(m);
res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
res=posix::pthread_cond_timedwait(&cond,&internal_mutex,&timeout.getTs());
check_for_interruption.unlock_if_locked();
guard.deactivate();
}
@@ -437,7 +489,6 @@ namespace boost
return true;
}
};
}
#include <boost/config/abi_suffix.hpp>

View File

@@ -13,7 +13,9 @@
#include <boost/thread/mutex.hpp>
#include <boost/thread/lock_types.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/pthread/timespec.hpp>
#include <boost/thread/detail/platform_time.hpp>
#include <boost/thread/pthread/pthread_helpers.hpp>
#if defined BOOST_THREAD_USES_DATETIME
#include <boost/thread/xtime.hpp>
#endif
@@ -25,31 +27,12 @@
#include <boost/thread/detail/delete.hpp>
#include <boost/date_time/posix_time/posix_time_duration.hpp>
#include <algorithm>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail {
inline int monotonic_pthread_cond_init(pthread_cond_t& cond) {
#ifdef BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
pthread_condattr_t attr;
int res = pthread_condattr_init(&attr);
if (res)
{
return res;
}
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
res=pthread_cond_init(&cond,&attr);
pthread_condattr_destroy(&attr);
return res;
#else
return pthread_cond_init(&cond,NULL);
#endif
}
}
class condition_variable
{
private:
@@ -61,21 +44,9 @@ namespace boost
public:
//private: // used by boost::thread::try_join_until
inline bool do_wait_until(
bool do_wait_until(
unique_lock<mutex>& lock,
struct timespec const &timeout);
bool do_wait_for(
unique_lock<mutex>& lock,
struct timespec const &timeout)
{
#if defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now_monotonic()));
#else
// old behavior was fine for monotonic
return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now_realtime()));
#endif
}
detail::internal_platform_timepoint const &timeout);
public:
BOOST_THREAD_NO_COPYABLE(condition_variable)
@@ -87,36 +58,29 @@ namespace boost
// above) and must be initialized (etc) in case some
// compilation units provide interruptions and others
// don't.
res=pthread_mutex_init(&internal_mutex,NULL);
res=posix::pthread_mutex_init(&internal_mutex);
if(res)
{
boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in pthread_mutex_init"));
}
//#endif
res = detail::monotonic_pthread_cond_init(cond);
res = posix::pthread_cond_init(&cond);
if (res)
{
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
// ditto
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
BOOST_VERIFY(!posix::pthread_mutex_destroy(&internal_mutex));
//#endif
boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in detail::monotonic_pthread_cond_init"));
boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in pthread_cond_init"));
}
}
~condition_variable()
{
int ret;
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
// ditto
do {
ret = pthread_mutex_destroy(&internal_mutex);
} while (ret == EINTR);
BOOST_ASSERT(!ret);
BOOST_VERIFY(!posix::pthread_mutex_destroy(&internal_mutex));
//#endif
do {
ret = pthread_cond_destroy(&cond);
} while (ret == EINTR);
BOOST_ASSERT(!ret);
BOOST_VERIFY(!posix::pthread_cond_destroy(&cond));
}
void wait(unique_lock<mutex>& m);
@@ -124,25 +88,40 @@ namespace boost
template<typename predicate_type>
void wait(unique_lock<mutex>& m,predicate_type pred)
{
while(!pred()) wait(m);
while (!pred())
{
wait(m);
}
}
#if defined BOOST_THREAD_USES_DATETIME
inline bool timed_wait(
bool timed_wait(
unique_lock<mutex>& m,
boost::system_time const& abs_time)
{
#if defined BOOST_THREAD_WAIT_BUG
struct timespec const timeout=detail::to_timespec(abs_time + BOOST_THREAD_WAIT_BUG);
return do_wait_until(m, timeout);
const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG);
#else
struct timespec const timeout=detail::to_timespec(abs_time);
return do_wait_until(m, timeout);
const detail::real_platform_timepoint ts(abs_time);
#endif
#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
// The system time may jump while this function is waiting. To compensate for this and time
// out near the correct time, we could call do_wait_until() in a loop with a short timeout
// and recheck the time remaining each time through the loop. However, because we can't
// check the predicate each time do_wait_until() completes, this introduces the possibility
// of not exiting the function when a notification occurs, since do_wait_until() may report
// that it timed out even though a notification was received. The best this function can do
// is report correctly whether or not it reached the timeout time.
const detail::platform_duration d(ts - detail::real_platform_clock::now());
do_wait_until(m, detail::internal_platform_clock::now() + d);
return ts > detail::real_platform_clock::now();
#else
return do_wait_until(m, ts);
#endif
}
bool timed_wait(
unique_lock<mutex>& m,
xtime const& abs_time)
::boost::xtime const& abs_time)
{
return timed_wait(m,system_time(abs_time));
}
@@ -154,14 +133,28 @@ namespace boost
{
if (wait_duration.is_pos_infinity())
{
wait(m); // or do_wait(m,detail::timeout::sentinel());
wait(m);
return true;
}
if (wait_duration.is_special())
{
return true;
}
return timed_wait(m,get_system_time()+wait_duration);
detail::platform_duration d(wait_duration);
#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
// The system time may jump while this function is waiting. To compensate for this and time
// out near the correct time, we could call do_wait_until() in a loop with a short timeout
// and recheck the time remaining each time through the loop. However, because we can't
// check the predicate each time do_wait_until() completes, this introduces the possibility
// of not exiting the function when a notification occurs, since do_wait_until() may report
// that it timed out even though a notification was received. The best this function can do
// is report correctly whether or not it reached the timeout time.
const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
do_wait_until(m, detail::internal_platform_clock::now() + d);
return ts > detail::mono_platform_clock::now();
#else
return do_wait_until(m, detail::internal_platform_clock::now() + d);
#endif
}
template<typename predicate_type>
@@ -169,18 +162,32 @@ namespace boost
unique_lock<mutex>& m,
boost::system_time const& abs_time,predicate_type pred)
{
#if defined BOOST_THREAD_WAIT_BUG
const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG);
#else
const detail::real_platform_timepoint ts(abs_time);
#endif
while (!pred())
{
if(!timed_wait(m, abs_time))
return pred();
#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
// The system time may jump while this function is waiting. To compensate for this
// and time out near the correct time, we call do_wait_until() in a loop with a
// short timeout and recheck the time remaining each time through the loop.
detail::platform_duration d(ts - detail::real_platform_clock::now());
if (d <= detail::platform_duration::zero()) break; // timeout occurred
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
do_wait_until(m, detail::internal_platform_clock::now() + d);
#else
if (!do_wait_until(m, ts)) break; // timeout occurred
#endif
}
return true;
return pred();
}
template<typename predicate_type>
bool timed_wait(
unique_lock<mutex>& m,
xtime const& abs_time,predicate_type pred)
::boost::xtime const& abs_time,predicate_type pred)
{
return timed_wait(m,system_time(abs_time),pred);
}
@@ -194,7 +201,7 @@ namespace boost
{
while (!pred())
{
wait(m); // or do_wait(m,detail::timeout::sentinel());
wait(m);
}
return true;
}
@@ -202,26 +209,41 @@ namespace boost
{
return pred();
}
return timed_wait(m,get_system_time()+wait_duration,pred);
detail::platform_duration d(wait_duration);
#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
// The system time may jump while this function is waiting. To compensate for this
// and time out near the correct time, we call do_wait_until() in a loop with a
// short timeout and recheck the time remaining each time through the loop.
const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
while (!pred())
{
if (d <= detail::platform_duration::zero()) break; // timeout occurred
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
do_wait_until(m, detail::internal_platform_clock::now() + d);
d = ts - detail::mono_platform_clock::now();
}
#else
const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d);
while (!pred())
{
if (!do_wait_until(m, ts)) break; // timeout occurred
}
#endif
return pred();
}
#endif
#ifndef BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
#ifdef BOOST_THREAD_USES_CHRONO
template <class Duration>
cv_status
wait_until(
unique_lock<mutex>& lock,
const chrono::time_point<chrono::system_clock, Duration>& t)
const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
{
using namespace chrono;
typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
wait_until(lock,
nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
return system_clock::now() < t ? cv_status::no_timeout :
cv_status::timeout;
const detail::internal_platform_timepoint ts(t);
if (do_wait_until(lock, ts)) return cv_status::no_timeout;
else return cv_status::timeout;
}
template <class Clock, class Duration>
@@ -230,100 +252,44 @@ namespace boost
unique_lock<mutex>& lock,
const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
system_clock::time_point s_now = system_clock::now();
typename Clock::time_point c_now = Clock::now();
wait_until(lock, s_now + ceil<nanoseconds>(t - c_now));
return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout;
// The system time may jump while this function is waiting. To compensate for this and time
// out near the correct time, we could call do_wait_until() in a loop with a short timeout
// and recheck the time remaining each time through the loop. However, because we can't
// check the predicate each time do_wait_until() completes, this introduces the possibility
// of not exiting the function when a notification occurs, since do_wait_until() may report
// that it timed out even though a notification was received. The best this function can do
// is report correctly whether or not it reached the timeout time.
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
common_duration d(t - Clock::now());
do_wait_until(lock, detail::internal_chrono_clock::now() + d);
if (t > Clock::now()) return cv_status::no_timeout;
else return cv_status::timeout;
}
template <class Rep, class Period>
cv_status
wait_for(
unique_lock<mutex>& lock,
const chrono::duration<Rep, Period>& d)
{
using namespace chrono;
system_clock::time_point s_now = system_clock::now();
steady_clock::time_point c_now = steady_clock::now();
wait_until(lock, s_now + ceil<nanoseconds>(d));
return steady_clock::now() - c_now < d ? cv_status::no_timeout :
cv_status::timeout;
return wait_until(lock, chrono::steady_clock::now() + d);
}
inline cv_status wait_until(
unique_lock<mutex>& lk,
chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp)
{
using namespace chrono;
nanoseconds d = tp.time_since_epoch();
timespec ts = boost::detail::to_timespec(d);
if (do_wait_until(lk, ts)) return cv_status::no_timeout;
else return cv_status::timeout;
}
#endif
#else // defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
#ifdef BOOST_THREAD_USES_CHRONO
template <class Duration>
cv_status
template <class Duration, class Predicate>
bool
wait_until(
unique_lock<mutex>& lock,
const chrono::time_point<chrono::steady_clock, Duration>& t)
unique_lock<mutex>& lock,
const chrono::time_point<detail::internal_chrono_clock, Duration>& t,
Predicate pred)
{
using namespace chrono;
typedef time_point<steady_clock, nanoseconds> nano_sys_tmpt;
wait_until(lock,
nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
return steady_clock::now() < t ? cv_status::no_timeout :
cv_status::timeout;
const detail::internal_platform_timepoint ts(t);
while (!pred())
{
if (!do_wait_until(lock, ts)) break; // timeout occurred
}
return pred();
}
template <class Clock, class Duration>
cv_status
wait_until(
unique_lock<mutex>& lock,
const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
steady_clock::time_point s_now = steady_clock::now();
typename Clock::time_point c_now = Clock::now();
wait_until(lock, s_now + ceil<nanoseconds>(t - c_now));
return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout;
}
template <class Rep, class Period>
cv_status
wait_for(
unique_lock<mutex>& lock,
const chrono::duration<Rep, Period>& d)
{
using namespace chrono;
steady_clock::time_point c_now = steady_clock::now();
wait_until(lock, c_now + ceil<nanoseconds>(d));
return steady_clock::now() - c_now < d ? cv_status::no_timeout :
cv_status::timeout;
}
inline cv_status wait_until(
unique_lock<mutex>& lk,
chrono::time_point<chrono::steady_clock, chrono::nanoseconds> tp)
{
using namespace chrono;
nanoseconds d = tp.time_since_epoch();
timespec ts = boost::detail::to_timespec(d);
if (do_wait_until(lk, ts)) return cv_status::no_timeout;
else return cv_status::timeout;
}
#endif
#endif // defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
#ifdef BOOST_THREAD_USES_CHRONO
template <class Clock, class Duration, class Predicate>
bool
wait_until(
@@ -331,12 +297,18 @@ namespace boost
const chrono::time_point<Clock, Duration>& t,
Predicate pred)
{
// The system time may jump while this function is waiting. To compensate for this
// and time out near the correct time, we call do_wait_until() in a loop with a
// short timeout and recheck the time remaining each time through the loop.
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
while (!pred())
{
if (wait_until(lock, t) == cv_status::timeout)
return pred();
common_duration d(t - Clock::now());
if (d <= common_duration::zero()) break; // timeout occurred
d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d));
}
return true;
return pred();
}
template <class Rep, class Period, class Predicate>
@@ -346,7 +318,7 @@ namespace boost
const chrono::duration<Rep, Period>& d,
Predicate pred)
{
return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
}
#endif
@@ -359,15 +331,11 @@ namespace boost
void notify_one() BOOST_NOEXCEPT;
void notify_all() BOOST_NOEXCEPT;
};
BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -16,80 +16,27 @@
#include <boost/thread/lock_types.hpp>
#endif
#include <boost/thread/thread_time.hpp>
#if defined BOOST_THREAD_USES_DATETIME
#include <boost/thread/xtime.hpp>
#endif
#include <boost/assert.hpp>
#include <errno.h>
#include <boost/thread/pthread/timespec.hpp>
#include <boost/thread/detail/platform_time.hpp>
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
#include <boost/thread/pthread/pthread_helpers.hpp>
#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono/system_clocks.hpp>
#include <boost/chrono/ceil.hpp>
#endif
#include <boost/thread/detail/delete.hpp>
#if (defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS-0)>=200112L) \
|| (defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21)
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
#define BOOST_PTHREAD_HAS_TIMEDLOCK
#endif
#endif
#include <boost/config/abi_prefix.hpp>
#ifndef BOOST_THREAD_HAS_NO_EINTR_BUG
#define BOOST_THREAD_HAS_EINTR_BUG
#endif
namespace boost
{
namespace posix {
#ifdef BOOST_THREAD_HAS_EINTR_BUG
BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m)
{
int ret;
do
{
ret = ::pthread_mutex_destroy(m);
} while (ret == EINTR);
return ret;
}
BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m)
{
int ret;
do
{
ret = ::pthread_mutex_lock(m);
} while (ret == EINTR);
return ret;
}
BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m)
{
int ret;
do
{
ret = ::pthread_mutex_unlock(m);
} while (ret == EINTR);
return ret;
}
#else
BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m)
{
return ::pthread_mutex_destroy(m);
}
BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m)
{
return ::pthread_mutex_lock(m);
}
BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m)
{
return ::pthread_mutex_unlock(m);
}
#endif
}
class mutex
class BOOST_THREAD_CAPABILITY("mutex") mutex
{
private:
pthread_mutex_t m;
@@ -98,7 +45,7 @@ namespace boost
mutex()
{
int const res=pthread_mutex_init(&m,NULL);
int const res=posix::pthread_mutex_init(&m);
if(res)
{
boost::throw_exception(thread_resource_error(res, "boost:: mutex constructor failed in pthread_mutex_init"));
@@ -106,12 +53,10 @@ namespace boost
}
~mutex()
{
int const res = posix::pthread_mutex_destroy(&m);
boost::ignore_unused(res);
BOOST_ASSERT(!res);
BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
}
void lock()
void lock() BOOST_THREAD_ACQUIRE()
{
int res = posix::pthread_mutex_lock(&m);
if (res)
@@ -120,24 +65,14 @@ namespace boost
}
}
void unlock()
void unlock() BOOST_THREAD_RELEASE()
{
int res = posix::pthread_mutex_unlock(&m);
(void)res;
BOOST_ASSERT(res == 0);
// if (res)
// {
// boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock"));
// }
BOOST_VERIFY(!posix::pthread_mutex_unlock(&m));
}
bool try_lock()
bool try_lock() BOOST_THREAD_TRY_ACQUIRE(true)
{
int res;
do
{
res = pthread_mutex_trylock(&m);
} while (res == EINTR);
int res = posix::pthread_mutex_trylock(&m);
if (res==EBUSY)
{
return false;
@@ -165,7 +100,7 @@ namespace boost
{
private:
pthread_mutex_t m;
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
#ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
pthread_cond_t cond;
bool is_locked;
#endif
@@ -173,17 +108,16 @@ namespace boost
BOOST_THREAD_NO_COPYABLE(timed_mutex)
timed_mutex()
{
int const res=pthread_mutex_init(&m,NULL);
int const res=posix::pthread_mutex_init(&m);
if(res)
{
boost::throw_exception(thread_resource_error(res, "boost:: timed_mutex constructor failed in pthread_mutex_init"));
}
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
int const res2=pthread_cond_init(&cond,NULL);
#ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
int const res2=posix::pthread_cond_init(&cond);
if(res2)
{
BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
//BOOST_VERIFY(!pthread_mutex_destroy(&m));
boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init"));
}
is_locked=false;
@@ -192,8 +126,8 @@ namespace boost
~timed_mutex()
{
BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
BOOST_VERIFY(!pthread_cond_destroy(&cond));
#ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
BOOST_VERIFY(!posix::pthread_cond_destroy(&cond));
#endif
}
@@ -201,14 +135,36 @@ namespace boost
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time)
{
return timed_lock(get_system_time()+relative_time);
if (relative_time.is_pos_infinity())
{
lock();
return true;
}
if (relative_time.is_special())
{
return true;
}
detail::platform_duration d(relative_time);
#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) )
{
d = ts - detail::mono_platform_clock::now();
if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
}
return true;
#else
return do_try_lock_until(detail::internal_platform_clock::now() + d);
#endif
}
bool timed_lock(boost::xtime const & absolute_time)
{
return timed_lock(system_time(absolute_time));
}
#endif
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
#ifdef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
void lock()
{
int res = posix::pthread_mutex_lock(&m);
@@ -220,22 +176,12 @@ namespace boost
void unlock()
{
int res = posix::pthread_mutex_unlock(&m);
(void)res;
BOOST_ASSERT(res == 0);
// if (res)
// {
// boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock"));
// }
BOOST_VERIFY(!posix::pthread_mutex_unlock(&m));
}
bool try_lock()
{
int res;
do
{
res = pthread_mutex_trylock(&m);
} while (res == EINTR);
int res = posix::pthread_mutex_trylock(&m);
if (res==EBUSY)
{
return false;
@@ -246,9 +192,9 @@ namespace boost
private:
bool do_try_lock_until(struct timespec const &timeout)
bool do_try_lock_until(detail::internal_platform_timepoint const &timeout)
{
int const res=pthread_mutex_timedlock(&m,&timeout);
int const res=pthread_mutex_timedlock(&m,&timeout.getTs());
BOOST_ASSERT(!res || res==ETIMEDOUT);
return !res;
}
@@ -260,7 +206,7 @@ namespace boost
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
while(is_locked)
{
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
BOOST_VERIFY(!posix::pthread_cond_wait(&cond,&m));
}
is_locked=true;
}
@@ -269,7 +215,7 @@ namespace boost
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
is_locked=false;
BOOST_VERIFY(!pthread_cond_signal(&cond));
BOOST_VERIFY(!posix::pthread_cond_signal(&cond));
}
bool try_lock()
@@ -284,18 +230,22 @@ namespace boost
}
private:
bool do_try_lock_until(struct timespec const &timeout)
bool do_try_lock_until(detail::internal_platform_timepoint const &timeout)
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
while(is_locked)
{
int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
int const cond_res=posix::pthread_cond_timedwait(&cond,&m,&timeout.getTs());
if(cond_res==ETIMEDOUT)
{
return false;
break;
}
BOOST_ASSERT(!cond_res);
}
if(is_locked)
{
return false;
}
is_locked=true;
return true;
}
@@ -305,8 +255,20 @@ namespace boost
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock(system_time const & abs_time)
{
struct timespec const ts=boost::detail::to_timespec(abs_time);
const detail::real_platform_timepoint ts(abs_time);
#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
detail::platform_duration d(ts - detail::real_platform_clock::now());
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) )
{
d = ts - detail::real_platform_clock::now();
if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
}
return true;
#else
return do_try_lock_until(ts);
#endif
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
@@ -318,23 +280,21 @@ namespace boost
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
system_clock::time_point s_now = system_clock::now();
typename Clock::time_point c_now = Clock::now();
return try_lock_until(s_now + ceil<nanoseconds>(t - c_now));
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
common_duration d(t - Clock::now());
d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
while ( ! try_lock_until(detail::internal_chrono_clock::now() + d))
{
d = t - Clock::now();
if ( d <= common_duration::zero() ) return false; // timeout occurred
d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
}
return true;
}
template <class Duration>
bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
bool try_lock_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
{
using namespace chrono;
typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
return try_lock_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
}
bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
{
//using namespace chrono;
chrono::nanoseconds d = tp.time_since_epoch();
timespec ts = boost::detail::to_timespec(d);
detail::internal_platform_timepoint ts(t);
return do_try_lock_until(ts);
}
#endif
@@ -352,7 +312,6 @@ namespace boost
typedef scoped_timed_lock scoped_lock;
#endif
};
}
#include <boost/config/abi_suffix.hpp>

View File

@@ -14,6 +14,7 @@
#include <boost/thread/detail/move.hpp>
#include <boost/thread/detail/invoke.hpp>
#include <boost/thread/pthread/pthread_helpers.hpp>
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
#include <boost/thread/detail/delete.hpp>
#include <boost/core/no_exceptions_support.hpp>
@@ -149,18 +150,18 @@ namespace boost
BOOST_CATCH (...)
{
flag.epoch=uninitialized_flag;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_RETHROW
}
BOOST_CATCH_END
flag.epoch=--thread_detail::once_global_epoch;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
}
else
{
while(flag.epoch==being_initialized)
{
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
}
}
}
@@ -194,18 +195,18 @@ namespace boost
BOOST_CATCH (...)
{
flag.epoch=uninitialized_flag;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_RETHROW
}
BOOST_CATCH_END
flag.epoch=--thread_detail::once_global_epoch;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
}
else
{
while(flag.epoch==being_initialized)
{
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
}
}
}
@@ -238,18 +239,18 @@ namespace boost
BOOST_CATCH (...)
{
flag.epoch=uninitialized_flag;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_RETHROW
}
BOOST_CATCH_END
flag.epoch=--thread_detail::once_global_epoch;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
}
else
{
while(flag.epoch==being_initialized)
{
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
}
}
}
@@ -281,18 +282,18 @@ namespace boost
BOOST_CATCH (...)
{
flag.epoch=uninitialized_flag;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_RETHROW
}
BOOST_CATCH_END
flag.epoch=--thread_detail::once_global_epoch;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
}
else
{
while(flag.epoch==being_initialized)
{
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
}
}
}
@@ -325,18 +326,18 @@ namespace boost
BOOST_CATCH (...)
{
flag.epoch=uninitialized_flag;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_RETHROW
}
BOOST_CATCH_END
flag.epoch=--thread_detail::once_global_epoch;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
}
else
{
while(flag.epoch==being_initialized)
{
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
}
}
}
@@ -369,18 +370,18 @@ namespace boost
BOOST_CATCH (...)
{
flag.epoch=uninitialized_flag;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_RETHROW
}
BOOST_CATCH_END
flag.epoch=--thread_detail::once_global_epoch;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
}
else
{
while(flag.epoch==being_initialized)
{
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
}
}
}
@@ -416,18 +417,18 @@ namespace boost
BOOST_CATCH (...)
{
flag.epoch=uninitialized_flag;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_RETHROW
}
BOOST_CATCH_END
flag.epoch=--thread_detail::once_global_epoch;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
}
else
{
while(flag.epoch==being_initialized)
{
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
}
}
}
@@ -463,18 +464,18 @@ namespace boost
BOOST_CATCH (...)
{
flag.epoch=uninitialized_flag;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_RETHROW
}
BOOST_CATCH_END
flag.epoch=--thread_detail::once_global_epoch;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
}
else
{
while(flag.epoch==being_initialized)
{
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
}
}
}
@@ -512,18 +513,18 @@ namespace boost
BOOST_CATCH (...)
{
flag.epoch=uninitialized_flag;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_RETHROW
}
BOOST_CATCH_END
flag.epoch=--thread_detail::once_global_epoch;
BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv));
}
else
{
while(flag.epoch==being_initialized)
{
BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex));
}
}
}

View File

@@ -0,0 +1,187 @@
#ifndef BOOST_THREAD_PTHREAD_PTHREAD_HELPERS_HPP
#define BOOST_THREAD_PTHREAD_PTHREAD_HELPERS_HPP
// Copyright (C) 2017
// Vicente J. Botet Escriba
//
// 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/throw_exception.hpp>
#include <pthread.h>
#include <errno.h>
#include <boost/config/abi_prefix.hpp>
#ifndef BOOST_THREAD_HAS_NO_EINTR_BUG
#define BOOST_THREAD_HAS_EINTR_BUG
#endif
namespace boost
{
namespace posix
{
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_mutex_init(pthread_mutex_t* m, const pthread_mutexattr_t* attr = NULL)
{
return ::pthread_mutex_init(m, attr);
}
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_cond_init(pthread_cond_t* c)
{
#ifdef BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
pthread_condattr_t attr;
int res = pthread_condattr_init(&attr);
if (res)
{
return res;
}
BOOST_VERIFY(!pthread_condattr_setclock(&attr, CLOCK_MONOTONIC));
res = ::pthread_cond_init(c, &attr);
BOOST_VERIFY(!pthread_condattr_destroy(&attr));
return res;
#else
return ::pthread_cond_init(c, NULL);
#endif
}
#ifdef BOOST_THREAD_HAS_EINTR_BUG
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_mutex_destroy(pthread_mutex_t* m)
{
int ret;
do
{
ret = ::pthread_mutex_destroy(m);
} while (ret == EINTR);
return ret;
}
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_cond_destroy(pthread_cond_t* c)
{
int ret;
do
{
ret = ::pthread_cond_destroy(c);
} while (ret == EINTR);
return ret;
}
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_mutex_lock(pthread_mutex_t* m)
{
int ret;
do
{
ret = ::pthread_mutex_lock(m);
} while (ret == EINTR);
return ret;
}
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_mutex_trylock(pthread_mutex_t* m)
{
int ret;
do
{
ret = ::pthread_mutex_trylock(m);
} while (ret == EINTR);
return ret;
}
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_mutex_unlock(pthread_mutex_t* m)
{
int ret;
do
{
ret = ::pthread_mutex_unlock(m);
} while (ret == EINTR);
return ret;
}
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_cond_wait(pthread_cond_t* c, pthread_mutex_t* m)
{
int ret;
do
{
ret = ::pthread_cond_wait(c, m);
} while (ret == EINTR);
return ret;
}
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_cond_timedwait(pthread_cond_t* c, pthread_mutex_t* m, const struct timespec* t)
{
int ret;
do
{
ret = ::pthread_cond_timedwait(c, m, t);
} while (ret == EINTR);
return ret;
}
#else
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_mutex_destroy(pthread_mutex_t* m)
{
return ::pthread_mutex_destroy(m);
}
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_cond_destroy(pthread_cond_t* c)
{
return ::pthread_cond_destroy(c);
}
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_mutex_lock(pthread_mutex_t* m)
{
return ::pthread_mutex_lock(m);
}
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_mutex_trylock(pthread_mutex_t* m)
{
return ::pthread_mutex_trylock(m);
}
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_mutex_unlock(pthread_mutex_t* m)
{
return ::pthread_mutex_unlock(m);
}
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_cond_wait(pthread_cond_t* c, pthread_mutex_t* m)
{
return ::pthread_cond_wait(c, m);
}
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_cond_timedwait(pthread_cond_t* c, pthread_mutex_t* m, const struct timespec* t)
{
return ::pthread_cond_timedwait(c, m, t);
}
#endif
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_cond_signal(pthread_cond_t* c)
{
return ::pthread_cond_signal(c);
}
BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
int pthread_cond_broadcast(pthread_cond_t* c)
{
return ::pthread_cond_broadcast(c);
}
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -8,6 +8,7 @@
#include <pthread.h>
#include <boost/assert.hpp>
#include <boost/thread/pthread/pthread_helpers.hpp>
#include <boost/config/abi_prefix.hpp>
@@ -23,11 +24,11 @@ namespace boost
explicit pthread_mutex_scoped_lock(pthread_mutex_t* m_) BOOST_NOEXCEPT:
m(m_),locked(true)
{
BOOST_VERIFY(!pthread_mutex_lock(m));
BOOST_VERIFY(!posix::pthread_mutex_lock(m));
}
void unlock() BOOST_NOEXCEPT
{
BOOST_VERIFY(!pthread_mutex_unlock(m));
BOOST_VERIFY(!posix::pthread_mutex_unlock(m));
locked=false;
}
void unlock_if_locked() BOOST_NOEXCEPT
@@ -54,11 +55,11 @@ namespace boost
explicit pthread_mutex_scoped_unlock(pthread_mutex_t* m_) BOOST_NOEXCEPT:
m(m_)
{
BOOST_VERIFY(!pthread_mutex_unlock(m));
BOOST_VERIFY(!posix::pthread_mutex_unlock(m));
}
~pthread_mutex_scoped_unlock() BOOST_NOEXCEPT
{
BOOST_VERIFY(!pthread_mutex_lock(m));
BOOST_VERIFY(!posix::pthread_mutex_lock(m));
}
};

View File

@@ -19,27 +19,22 @@
#endif
#include <boost/date_time/posix_time/conversion.hpp>
#include <errno.h>
#include <boost/thread/pthread/timespec.hpp>
#include <boost/thread/detail/platform_time.hpp>
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
#include <boost/thread/pthread/pthread_helpers.hpp>
#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono/system_clocks.hpp>
#include <boost/chrono/ceil.hpp>
#endif
#include <boost/thread/detail/delete.hpp>
#if (defined _POSIX_TIMEOUTS && (_POSIX_TIMEOUTS-0)>=200112L) \
|| (defined __ANDROID__ && defined __ANDROID_API__ && __ANDROID_API__ >= 21)
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
#define BOOST_PTHREAD_HAS_TIMEDLOCK
#endif
#endif
#if defined BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE \
|| defined __ANDROID__
#define BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE
#endif
#if defined BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE && defined BOOST_PTHREAD_HAS_TIMEDLOCK
#if defined BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE && defined BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
#define BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
#endif
@@ -76,7 +71,7 @@ namespace boost
boost::throw_exception(thread_resource_error(set_attr_res, "boost:: recursive_mutex constructor failed in pthread_mutexattr_settype"));
}
int const res=pthread_mutex_init(&m,&attr);
int const res=posix::pthread_mutex_init(&m,&attr);
if(res)
{
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
@@ -84,15 +79,15 @@ namespace boost
}
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
#else
int const res=pthread_mutex_init(&m,NULL);
int const res=posix::pthread_mutex_init(&m);
if(res)
{
boost::throw_exception(thread_resource_error(res, "boost:: recursive_mutex constructor failed in pthread_mutex_init"));
}
int const res2=pthread_cond_init(&cond,NULL);
int const res2=posix::pthread_cond_init(&cond);
if(res2)
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
boost::throw_exception(thread_resource_error(res2, "boost:: recursive_mutex constructor failed in pthread_cond_init"));
}
is_locked=false;
@@ -101,26 +96,26 @@ namespace boost
}
~recursive_mutex()
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
#ifndef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE
BOOST_VERIFY(!pthread_cond_destroy(&cond));
BOOST_VERIFY(!posix::pthread_cond_destroy(&cond));
#endif
}
#ifdef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE
void lock()
{
BOOST_VERIFY(!pthread_mutex_lock(&m));
BOOST_VERIFY(!posix::pthread_mutex_lock(&m));
}
void unlock()
{
BOOST_VERIFY(!pthread_mutex_unlock(&m));
BOOST_VERIFY(!posix::pthread_mutex_unlock(&m));
}
bool try_lock() BOOST_NOEXCEPT
{
int const res=pthread_mutex_trylock(&m);
int const res=posix::pthread_mutex_trylock(&m);
BOOST_ASSERT(!res || res==EBUSY);
return !res;
}
@@ -143,7 +138,7 @@ namespace boost
while(is_locked)
{
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
BOOST_VERIFY(!posix::pthread_cond_wait(&cond,&m));
}
is_locked=true;
++count;
@@ -157,7 +152,7 @@ namespace boost
{
is_locked=false;
}
BOOST_VERIFY(!pthread_cond_signal(&cond));
BOOST_VERIFY(!posix::pthread_cond_signal(&cond));
}
bool try_lock()
@@ -211,7 +206,7 @@ namespace boost
boost::throw_exception(thread_resource_error(set_attr_res, "boost:: recursive_timed_mutex constructor failed in pthread_mutexattr_settype"));
}
int const res=pthread_mutex_init(&m,&attr);
int const res=posix::pthread_mutex_init(&m,&attr);
if(res)
{
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
@@ -219,15 +214,15 @@ namespace boost
}
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
#else
int const res=pthread_mutex_init(&m,NULL);
int const res=posix::pthread_mutex_init(&m);
if(res)
{
boost::throw_exception(thread_resource_error(res, "boost:: recursive_timed_mutex constructor failed in pthread_mutex_init"));
}
int const res2=pthread_cond_init(&cond,NULL);
int const res2=posix::pthread_cond_init(&cond);
if(res2)
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
boost::throw_exception(thread_resource_error(res2, "boost:: recursive_timed_mutex constructor failed in pthread_cond_init"));
}
is_locked=false;
@@ -236,9 +231,9 @@ namespace boost
}
~recursive_timed_mutex()
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
#ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
BOOST_VERIFY(!pthread_cond_destroy(&cond));
BOOST_VERIFY(!posix::pthread_cond_destroy(&cond));
#endif
}
@@ -246,31 +241,53 @@ namespace boost
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time)
{
return timed_lock(get_system_time()+relative_time);
if (relative_time.is_pos_infinity())
{
lock();
return true;
}
if (relative_time.is_special())
{
return true;
}
detail::platform_duration d(relative_time);
#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) )
{
d = ts - detail::mono_platform_clock::now();
if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
}
return true;
#else
return do_try_lock_until(detail::internal_platform_clock::now() + d);
#endif
}
#endif
#ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
void lock()
{
BOOST_VERIFY(!pthread_mutex_lock(&m));
BOOST_VERIFY(!posix::pthread_mutex_lock(&m));
}
void unlock()
{
BOOST_VERIFY(!pthread_mutex_unlock(&m));
BOOST_VERIFY(!posix::pthread_mutex_unlock(&m));
}
bool try_lock()
{
int const res=pthread_mutex_trylock(&m);
int const res=posix::pthread_mutex_trylock(&m);
BOOST_ASSERT(!res || res==EBUSY);
return !res;
}
private:
bool do_try_lock_until(struct timespec const &timeout)
bool do_try_lock_until(detail::internal_platform_timepoint const &timeout)
{
int const res=pthread_mutex_timedlock(&m,&timeout);
int const res=pthread_mutex_timedlock(&m,&timeout.getTs());
BOOST_ASSERT(!res || res==ETIMEDOUT);
return !res;
}
@@ -289,7 +306,7 @@ namespace boost
while(is_locked)
{
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
BOOST_VERIFY(!posix::pthread_cond_wait(&cond,&m));
}
is_locked=true;
++count;
@@ -303,7 +320,7 @@ namespace boost
{
is_locked=false;
}
BOOST_VERIFY(!pthread_cond_signal(&cond));
BOOST_VERIFY(!posix::pthread_cond_signal(&cond));
}
bool try_lock() BOOST_NOEXCEPT
@@ -320,7 +337,7 @@ namespace boost
}
private:
bool do_try_lock_until(struct timespec const &timeout)
bool do_try_lock_until(detail::internal_platform_timepoint const &timeout)
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
if(is_locked && pthread_equal(owner,pthread_self()))
@@ -330,13 +347,17 @@ namespace boost
}
while(is_locked)
{
int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
int const cond_res=posix::pthread_cond_timedwait(&cond,&m,&timeout.getTs());
if(cond_res==ETIMEDOUT)
{
return false;
break;
}
BOOST_ASSERT(!cond_res);
}
if(is_locked)
{
return false;
}
is_locked=true;
++count;
owner=pthread_self();
@@ -349,8 +370,20 @@ namespace boost
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock(system_time const & abs_time)
{
struct timespec const ts=detail::to_timespec(abs_time);
const detail::real_platform_timepoint ts(abs_time);
#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
detail::platform_duration d(ts - detail::real_platform_clock::now());
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) )
{
d = ts - detail::real_platform_clock::now();
if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
}
return true;
#else
return do_try_lock_until(ts);
#endif
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
@@ -362,23 +395,22 @@ namespace boost
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
system_clock::time_point s_now = system_clock::now();
typename Clock::time_point c_now = Clock::now();
return try_lock_until(s_now + ceil<nanoseconds>(t - c_now));
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
common_duration d(t - Clock::now());
d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
while ( ! try_lock_until(detail::internal_chrono_clock::now() + d))
{
d = t - Clock::now();
if ( d <= common_duration::zero() ) return false; // timeout occurred
d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
}
return true;
}
template <class Duration>
bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
bool try_lock_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
{
using namespace chrono;
typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
return try_lock_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
}
bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
{
//using namespace chrono;
chrono::nanoseconds d = tp.time_since_epoch();
timespec ts = boost::detail::to_timespec(d);
detail::internal_platform_timepoint ts(t);
return do_try_lock_until(ts);
}
#endif

View File

@@ -9,6 +9,7 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/assert.hpp>
#include <boost/bind.hpp>
#include <boost/static_assert.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
@@ -78,11 +79,6 @@ namespace boost
return ! (shared_count || exclusive);
}
void exclusive_blocked (bool blocked)
{
exclusive_waiting_blocked = blocked;
}
void lock ()
{
exclusive = true;
@@ -99,17 +95,19 @@ namespace boost
return ! (exclusive || exclusive_waiting_blocked);
}
bool more_shared () const
bool no_shared () const
{
return shared_count > 0 ;
return shared_count==0;
}
unsigned get_shared_count () const
bool one_shared () const
{
return shared_count ;
return shared_count==1;
}
unsigned lock_shared ()
void lock_shared ()
{
return ++shared_count;
++shared_count;
}
@@ -118,18 +116,6 @@ namespace boost
--shared_count;
}
bool unlock_shared_downgrades()
{
if (upgrade) {
upgrade=false;
exclusive=true;
return true;
} else {
exclusive_waiting_blocked=false;
return false;
}
}
void lock_upgrade ()
{
++shared_count;
@@ -185,10 +171,7 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(!state.can_lock_shared())
{
shared_cond.wait(lk);
}
shared_cond.wait(lk, boost::bind(&state_data::can_lock_shared, boost::ref(state)));
state.lock_shared();
}
@@ -211,13 +194,9 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(!state.can_lock_shared())
if(!shared_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock_shared, boost::ref(state))))
{
if(!shared_cond.timed_wait(lk,timeout))
{
return false;
}
return false;
}
state.lock_shared();
return true;
@@ -226,7 +205,16 @@ namespace boost
template<typename TimeDuration>
bool timed_lock_shared(TimeDuration const & relative_time)
{
return timed_lock_shared(get_system_time()+relative_time);
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
if(!shared_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock_shared, boost::ref(state))))
{
return false;
}
state.lock_shared();
return true;
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
@@ -242,14 +230,9 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(!state.can_lock_shared())
//while(state.exclusive || state.exclusive_waiting_blocked)
if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_shared, boost::ref(state))))
{
if(cv_status::timeout==shared_cond.wait_until(lk,abs_time))
{
return false;
}
return false;
}
state.lock_shared();
return true;
@@ -260,11 +243,11 @@ namespace boost
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
state.unlock_shared();
if (! state.more_shared())
if (state.no_shared())
{
if (state.upgrade)
{
// As there is a thread doing a unlock_upgrade_and_lock that is waiting for ! state.more_shared()
// As there is a thread doing a unlock_upgrade_and_lock that is waiting for state.no_shared()
// avoid other threads to lock, lock_upgrade or lock_shared, so only this thread is notified.
state.upgrade=false;
state.exclusive=true;
@@ -286,12 +269,8 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while (state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=true;
exclusive_cond.wait(lk);
}
state.exclusive_waiting_blocked=true;
exclusive_cond.wait(lk, boost::bind(&state_data::can_lock, boost::ref(state)));
state.exclusive=true;
}
@@ -302,20 +281,12 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(state.shared_count || state.exclusive)
state.exclusive_waiting_blocked=true;
if(!exclusive_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock, boost::ref(state))))
{
state.exclusive_waiting_blocked=true;
if(!exclusive_cond.timed_wait(lk,timeout))
{
if(state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=false;
release_waiters();
return false;
}
break;
}
state.exclusive_waiting_blocked=false;
release_waiters();
return false;
}
state.exclusive=true;
return true;
@@ -324,7 +295,19 @@ namespace boost
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time)
{
return timed_lock(get_system_time()+relative_time);
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
state.exclusive_waiting_blocked=true;
if(!exclusive_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock, boost::ref(state))))
{
state.exclusive_waiting_blocked=false;
release_waiters();
return false;
}
state.exclusive=true;
return true;
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
@@ -340,20 +323,12 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(state.shared_count || state.exclusive)
state.exclusive_waiting_blocked=true;
if(!exclusive_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock, boost::ref(state))))
{
state.exclusive_waiting_blocked=true;
if(cv_status::timeout == exclusive_cond.wait_until(lk,abs_time))
{
if(state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=false;
release_waiters();
return false;
}
break;
}
state.exclusive_waiting_blocked=false;
release_waiters();
return false;
}
state.exclusive=true;
return true;
@@ -363,17 +338,12 @@ namespace boost
bool try_lock()
{
boost::unique_lock<boost::mutex> lk(state_change);
if(state.shared_count || state.exclusive)
if(!state.can_lock())
{
return false;
}
else
{
state.exclusive=true;
return true;
}
state.exclusive=true;
return true;
}
void unlock()
@@ -392,10 +362,7 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
{
shared_cond.wait(lk);
}
shared_cond.wait(lk, boost::bind(&state_data::can_lock_upgrade, boost::ref(state)));
state.lock_shared();
state.upgrade=true;
}
@@ -407,16 +374,9 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
if(!shared_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))))
{
if(!shared_cond.timed_wait(lk,timeout))
{
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
{
return false;
}
break;
}
return false;
}
state.lock_shared();
state.upgrade=true;
@@ -426,7 +386,17 @@ namespace boost
template<typename TimeDuration>
bool timed_lock_upgrade(TimeDuration const & relative_time)
{
return timed_lock_upgrade(get_system_time()+relative_time);
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
if(!shared_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))))
{
return false;
}
state.lock_shared();
state.upgrade=true;
return true;
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
@@ -442,16 +412,9 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))))
{
if(cv_status::timeout == shared_cond.wait_until(lk,abs_time))
{
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
{
return false;
}
break;
}
return false;
}
state.lock_shared();
state.upgrade=true;
@@ -461,17 +424,14 @@ namespace boost
bool try_lock_upgrade()
{
boost::unique_lock<boost::mutex> lk(state_change);
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
if(!state.can_lock_upgrade())
{
return false;
}
else
{
state.lock_shared();
state.upgrade=true;
state.assert_lock_upgraded();
return true;
}
state.lock_shared();
state.upgrade=true;
state.assert_lock_upgraded();
return true;
}
void unlock_upgrade()
@@ -479,7 +439,7 @@ namespace boost
boost::unique_lock<boost::mutex> lk(state_change);
//state.upgrade=false;
state.unlock_upgrade();
if(! state.more_shared() )
if(state.no_shared())
{
state.exclusive_waiting_blocked=false;
release_waiters();
@@ -497,10 +457,7 @@ namespace boost
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_upgraded();
state.unlock_shared();
while (state.more_shared())
{
upgrade_cond.wait(lk);
}
upgrade_cond.wait(lk, boost::bind(&state_data::no_shared, boost::ref(state)));
state.upgrade=false;
state.exclusive=true;
state.assert_locked();
@@ -554,16 +511,9 @@ namespace boost
#endif
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_upgraded();
if (state.shared_count != 1)
if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::one_shared, boost::ref(state))))
{
for (;;)
{
cv_status status = shared_cond.wait_until(lk,abs_time);
if (state.shared_count == 1)
break;
if(status == cv_status::timeout)
return false;
}
return false;
}
state.upgrade=false;
state.exclusive=true;
@@ -619,16 +569,9 @@ namespace boost
#endif
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
if (state.shared_count != 1)
if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::one_shared, boost::ref(state))))
{
for (;;)
{
cv_status status = shared_cond.wait_until(lk,abs_time);
if (state.shared_count == 1)
break;
if(status == cv_status::timeout)
return false;
}
return false;
}
state.upgrade=false;
state.exclusive=true;
@@ -654,10 +597,7 @@ namespace boost
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
if( !state.exclusive
&& !state.exclusive_waiting_blocked
&& !state.upgrade
)
if(state.can_lock_upgrade())
{
state.upgrade=true;
return true;
@@ -683,22 +623,9 @@ namespace boost
#endif
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
if( state.exclusive
|| state.exclusive_waiting_blocked
|| state.upgrade
)
if(!exclusive_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))))
{
for (;;)
{
cv_status status = exclusive_cond.wait_until(lk,abs_time);
if( ! state.exclusive
&& ! state.exclusive_waiting_blocked
&& ! state.upgrade
)
break;
if(status == cv_status::timeout)
return false;
}
return false;
}
state.upgrade=true;
return true;

View File

@@ -1,724 +0,0 @@
#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
// (C) Copyright 2006-8 Anthony Williams
// (C) Copyright 2012 Vicente J. Botet Escriba
//
// 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/condition_variable.hpp>
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
#include <boost/thread/detail/thread_interruption.hpp>
#endif
#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono/system_clocks.hpp>
#include <boost/chrono/ceil.hpp>
#endif
#include <boost/thread/detail/delete.hpp>
#include <boost/assert.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class shared_mutex
{
private:
class state_data
{
public:
state_data () :
shared_count(0),
exclusive(false),
upgrade(false),
exclusive_waiting_blocked(false)
{}
void assert_free() const
{
BOOST_ASSERT( ! exclusive );
BOOST_ASSERT( ! upgrade );
BOOST_ASSERT( shared_count==0 );
}
void assert_locked() const
{
BOOST_ASSERT( exclusive );
BOOST_ASSERT( shared_count==0 );
BOOST_ASSERT( ! upgrade );
}
void assert_lock_shared () const
{
BOOST_ASSERT( ! exclusive );
BOOST_ASSERT( shared_count>0 );
//BOOST_ASSERT( (! upgrade) || (shared_count>1));
// if upgraded there are at least 2 threads sharing the mutex,
// except when unlock_upgrade_and_lock has decreased the number of readers but has not taken yet exclusive ownership.
}
void assert_lock_upgraded () const
{
BOOST_ASSERT( ! exclusive );
BOOST_ASSERT( upgrade );
BOOST_ASSERT( shared_count>0 );
}
void assert_lock_not_upgraded () const
{
BOOST_ASSERT( ! upgrade );
}
bool can_lock () const
{
return ! (shared_count || exclusive);
}
void exclusive_blocked (bool blocked)
{
exclusive_waiting_blocked = blocked;
}
void lock ()
{
exclusive = true;
}
void unlock ()
{
exclusive = false;
exclusive_waiting_blocked = false;
}
bool can_lock_shared () const
{
return ! (exclusive || exclusive_waiting_blocked);
}
bool is_last_shared () const
{
return !shared_count ;
}
unsigned get_shared_count () const
{
return shared_count ;
}
unsigned lock_shared ()
{
return ++shared_count;
}
void unlock_shared ()
{
--shared_count;
}
bool unlock_shared_downgrades()
{
if (upgrade) {
upgrade=false;
exclusive=true;
return true;
} else {
exclusive_waiting_blocked=false;
return false;
}
}
void lock_upgrade ()
{
lock_shared ();
upgrade=true;
}
bool can_lock_upgrade () const
{
return ! (exclusive || exclusive_waiting_blocked || upgrade);
}
void unlock_upgrade ()
{
upgrade=false;
unlock_shared();
}
//private:
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:
BOOST_THREAD_NO_COPYABLE(shared_mutex)
shared_mutex()
{
}
~shared_mutex()
{
}
void lock_shared()
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(!state.can_lock_shared())
{
shared_cond.wait(lk);
}
state.lock_shared();
}
bool try_lock_shared()
{
boost::unique_lock<boost::mutex> lk(state_change);
if(!state.can_lock_shared())
{
return false;
}
else
{
state.lock_shared();
return true;
}
}
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock_shared(system_time const& timeout)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(!state.can_lock_shared())
{
if(!shared_cond.timed_wait(lk,timeout))
{
return false;
}
}
state.lock_shared();
return true;
}
template<typename TimeDuration>
bool timed_lock_shared(TimeDuration const & relative_time)
{
return timed_lock_shared(get_system_time()+relative_time);
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
{
return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(!state.can_lock_shared())
{
if(cv_status::timeout==shared_cond.wait_until(lk,abs_time))
{
return false;
}
}
state.lock_shared();
return true;
}
#endif
void unlock_shared()
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
state.unlock_shared();
if (state.get_shared_count () == 0)
{
if (state.unlock_shared_downgrades())
{
lk.unlock();
upgrade_cond.notify_one();
} else {
lk.unlock();
}
release_waiters();
}
}
void lock()
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(!state.can_lock())
{
state.exclusive_blocked(true);
exclusive_cond.wait(lk);
}
state.lock();
}
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock(system_time const& timeout)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(!state.can_lock())
{
state.exclusive_blocked(true);
if(!exclusive_cond.timed_wait(lk,timeout))
{
if(!state.can_lock())
{
state.exclusive_blocked(false);
release_waiters();
return false;
}
break;
}
}
state.exclusive=true;
//state.lock();
return true;
}
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time)
{
return timed_lock(get_system_time()+relative_time);
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
{
return try_lock_until(chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(!state.can_lock())
{
state.exclusive_blocked(true);
if(cv_status::timeout == exclusive_cond.wait_until(lk,abs_time))
{
if(!state.can_lock())
{
state.exclusive_blocked(false);
release_waiters();
return false;
}
break;
}
}
state.exclusive=true;
//state.lock();
return true;
}
#endif
bool try_lock()
{
boost::unique_lock<boost::mutex> lk(state_change);
if(!state.can_lock())
{
return false;
}
else
{
state.lock();
return true;
}
}
void unlock()
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_locked();
state.unlock();
state.assert_free();
release_waiters();
}
void lock_upgrade()
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(!state.can_lock_upgrade())
{
shared_cond.wait(lk);
}
state.lock_upgrade();
}
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock_upgrade(system_time const& timeout)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(!state.can_lock_upgrade())
{
if(!shared_cond.timed_wait(lk,timeout))
{
if(!state.can_lock_upgrade())
{
return false;
}
break;
}
}
state.lock_upgrade();
return true;
}
template<typename TimeDuration>
bool timed_lock_upgrade(TimeDuration const & relative_time)
{
return timed_lock_upgrade(get_system_time()+relative_time);
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time)
{
return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
while(!state.can_lock_upgrade())
{
if(cv_status::timeout == shared_cond.wait_until(lk,abs_time))
{
if(!state.can_lock_upgrade())
{
return false;
}
break;
}
}
state.lock_upgrade();
return true;
}
#endif
bool try_lock_upgrade()
{
boost::unique_lock<boost::mutex> lk(state_change);
if(!state.can_lock_upgrade())
{
return false;
}
else
{
state.lock_upgrade();
state.assert_lock_upgraded();
return true;
}
}
void unlock_upgrade()
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_upgraded();
state.unlock_upgrade();
state.assert_lock_not_upgraded ();
if(state.get_shared_count () == 0)
{
state.exclusive_blocked(false);
lk.unlock();
release_waiters();
} else {
lk.unlock();
shared_cond.notify_all();
}
}
// Upgrade <-> Exclusive
void unlock_upgrade_and_lock()
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_upgraded();
// assert state.get_shared_count() >=1
while(
//! state.exclusive_waiting_blocked // Fixme: is this needed?
//&&
state.get_shared_count()!=1)
{
upgrade_cond.wait(lk);
}
state.unlock_upgrade();
state.lock();
state.assert_locked();
}
void unlock_and_lock_upgrade()
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_locked();
state.unlock();
state.lock_upgrade();
state.assert_lock_upgraded();
release_waiters();
}
bool try_unlock_upgrade_and_lock()
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_upgraded();
if( //!state.exclusive // this should be removed once the assertion work
! state.exclusive_waiting_blocked // Fixme: why this is needed?
//&& state.upgrade // this should be removed once the assertion work
&& state.get_shared_count()==1)
{
state.unlock_upgrade();
state.lock();
state.assert_locked();
return true;
}
return false;
}
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool
try_unlock_upgrade_and_lock_for(
const chrono::duration<Rep, Period>& rel_time)
{
return try_unlock_upgrade_and_lock_until(
chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
bool
try_unlock_upgrade_and_lock_until(
const chrono::time_point<Clock, Duration>& abs_time)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_upgraded();
if (//state.exclusive // this should be removed once the assertion work
state.exclusive_waiting_blocked // Fixme: is this needed?
//|| ! state.upgrade // this should be removed once the assertion work
|| state.get_shared_count() != 1)
{
for (;;)
{
//cv_status status = shared_cond.wait_until(lk,abs_time);
cv_status status = upgrade_cond.wait_until(lk,abs_time);
if (//!state.exclusive // this should be removed once the assertion work
! state.exclusive_waiting_blocked // Fixme: is this needed?
//&& ! state.upgrade // this should be removed once the assertion work
&& state.get_shared_count() == 1)
break;
if(status == cv_status::timeout)
return false;
}
}
state.unlock_upgrade();
state.lock();
return true;
}
#endif
// Shared <-> Exclusive
void unlock_and_lock_shared()
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_locked();
state.unlock();
state.lock_shared();
release_waiters();
}
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
bool try_unlock_shared_and_lock()
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
if( //!state.exclusive // this should be removed once the assertion work
! state.exclusive_waiting_blocked // Fixme: why this is needed?
//&& ! state.upgrade // Fixme: why this is needed if state.get_shared_count()==1?
&& state.get_shared_count()==1)
{
state.unlock_shared();
state.lock();
return true;
}
return false;
}
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool
try_unlock_shared_and_lock_for(
const chrono::duration<Rep, Period>& rel_time)
{
return try_unlock_shared_and_lock_until(
chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
bool
try_unlock_shared_and_lock_until(
const chrono::time_point<Clock, Duration>& abs_time)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
if ( // !state.exclusive // this should be removed once the assertion work
state.exclusive_waiting_blocked // Fixme: is this needed?
//|| state.upgrade // Fixme: why this is needed if state.get_shared_count()==1?
|| state.get_shared_count() != 1)
{
for (;;)
{
cv_status status = shared_cond.wait_until(lk,abs_time);
if ( //! state.exclusive // this should be removed once the assertion work
! state.exclusive_waiting_blocked // Fixme: is this needed?
//&& ! state.upgrade
&& state.get_shared_count() == 1)
break;
if(status == cv_status::timeout)
return false;
}
}
state.unlock_shared();
state.lock();
state.upgrade=false; // Is this absolutely needed?
state.exclusive_waiting_blocked=false; // Is this absolutely needed?
return true;
}
#endif
#endif
// Shared <-> Upgrade
void unlock_upgrade_and_lock_shared()
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_upgraded();
//state.unlock_upgrade();
//state.lock_shared(); // less efficient
state.upgrade=false;
state.exclusive_waiting_blocked=false; // Is this absolutely needed?
release_waiters();
}
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
bool try_unlock_shared_and_lock_upgrade()
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
if( //! state.exclusive // this should be removed once the assertion work
! state.exclusive_waiting_blocked // Fixme: is this needed?
&& ! state.upgrade
)
{
state.upgrade=true;
return true;
}
return false;
}
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool
try_unlock_shared_and_lock_upgrade_for(
const chrono::duration<Rep, Period>& rel_time)
{
return try_unlock_shared_and_lock_upgrade_until(
chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
bool
try_unlock_shared_and_lock_upgrade_until(
const chrono::time_point<Clock, Duration>& abs_time)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
if( //state.exclusive // this should be removed once the assertion work
state.exclusive_waiting_blocked // Fixme: is this needed?
|| state.upgrade
)
{
for (;;)
{
cv_status status = exclusive_cond.wait_until(lk,abs_time);
if( //! state.exclusive // this should be removed once the assertion work
! state.exclusive_waiting_blocked // Fixme: is this needed?
&& ! state.upgrade
)
break;
if(status == cv_status::timeout)
return false;
}
}
//state.unlock_shared();
//state.lock_upgrade(); // less efficient
state.upgrade=true;
return true;
}
#endif
#endif
};
typedef shared_mutex upgrade_mutex;
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -12,10 +12,12 @@
#include <boost/thread/lock_types.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/pthread/condition_variable_fwd.hpp>
#include <boost/thread/pthread/pthread_helpers.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/assert.hpp>
#include <boost/thread/detail/platform_time.hpp>
#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono/system_clocks.hpp>
#endif
@@ -55,7 +57,7 @@ namespace boost
#else
std::size_t page_size = ::sysconf( _SC_PAGESIZE);
#endif
#ifdef PTHREAD_STACK_MIN
#if PTHREAD_STACK_MIN > 0
if (size<PTHREAD_STACK_MIN) size=PTHREAD_STACK_MIN;
#endif
size = ((size+page_size-1)/page_size)*page_size;
@@ -92,12 +94,15 @@ namespace boost
struct thread_exit_callback_node;
struct tss_data_node
{
boost::shared_ptr<boost::detail::tss_cleanup_function> func;
typedef void(*cleanup_func_t)(void*);
typedef void(*cleanup_caller_t)(cleanup_func_t, void*);
cleanup_caller_t caller;
cleanup_func_t func;
void* value;
tss_data_node(boost::shared_ptr<boost::detail::tss_cleanup_function> func_,
void* value_):
func(func_),value(value_)
tss_data_node(cleanup_caller_t caller_,cleanup_func_t func_,void* value_):
caller(caller_),func(func_),value(value_)
{}
};
@@ -111,8 +116,6 @@ namespace boost
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;
@@ -131,9 +134,10 @@ namespace boost
> notify_list_t;
notify_list_t notify;
//#ifndef BOOST_NO_EXCEPTIONS
typedef std::vector<shared_ptr<shared_state_base> > async_states_t;
async_states_t async_states_;
//#endif
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
// These data must be at the end so that the access to the other fields doesn't change
// when BOOST_THREAD_PROVIDES_INTERRUPTIONS is defined.
@@ -149,8 +153,10 @@ namespace boost
cond_mutex(0),
current_cond(0),
//#endif
notify(),
async_states_()
notify()
//#ifndef BOOST_NO_EXCEPTIONS
, async_states_()
//#endif
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
, interrupt_enabled(true)
, interrupt_requested(false)
@@ -166,11 +172,12 @@ namespace boost
notify.push_back(std::pair<condition_variable*, mutex*>(cv, m));
}
//#ifndef BOOST_NO_EXCEPTIONS
void make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
{
async_states_.push_back(as);
}
//#endif
};
BOOST_THREAD_DECL thread_data_base* get_current_thread_data();
@@ -206,11 +213,11 @@ namespace boost
check_for_interruption();
thread_info->cond_mutex=cond_mutex;
thread_info->current_cond=cond;
BOOST_VERIFY(!pthread_mutex_lock(m));
BOOST_VERIFY(!posix::pthread_mutex_lock(m));
}
else
{
BOOST_VERIFY(!pthread_mutex_lock(m));
BOOST_VERIFY(!posix::pthread_mutex_lock(m));
}
}
void unlock_if_locked()
@@ -218,14 +225,14 @@ namespace boost
if ( ! done) {
if (set)
{
BOOST_VERIFY(!pthread_mutex_unlock(m));
BOOST_VERIFY(!posix::pthread_mutex_unlock(m));
lock_guard<mutex> guard(thread_info->data_mutex);
thread_info->cond_mutex=NULL;
thread_info->current_cond=NULL;
}
else
{
BOOST_VERIFY(!pthread_mutex_unlock(m));
BOOST_VERIFY(!posix::pthread_mutex_unlock(m));
}
done = true;
}
@@ -241,49 +248,15 @@ namespace boost
namespace this_thread
{
void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT;
namespace hidden
{
void BOOST_THREAD_DECL sleep_for(const timespec& ts);
void BOOST_THREAD_DECL sleep_until_realtime(const timespec& ts);
}
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& d);
#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY
inline
void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns)
{
return boost::this_thread::hidden::sleep_for(boost::detail::to_timespec(ns));
}
#endif
#endif // BOOST_THREAD_USES_CHRONO
namespace no_interruption_point
{
namespace hidden
inline bool always_false()
{
void BOOST_THREAD_DECL sleep_for(const timespec& ts);
void BOOST_THREAD_DECL sleep_until_realtime(const timespec& ts);
return false;
}
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& d);
#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY
inline
void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns)
{
return boost::this_thread::no_interruption_point::hidden::sleep_for(boost::detail::to_timespec(ns));
}
#endif
#endif // BOOST_THREAD_USES_CHRONO
} // no_interruption_point
void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT;
}
#if defined BOOST_THREAD_USES_DATETIME
#ifdef __DECXXX
@@ -292,15 +265,141 @@ namespace boost
#endif
inline void sleep(system_time const& abs_time)
{
return boost::this_thread::hidden::sleep_until_realtime(boost::detail::to_timespec(abs_time));
mutex mx;
unique_lock<mutex> lock(mx);
condition_variable cond;
cond.timed_wait(lock, abs_time, hidden::always_false);
}
template<typename TimeDuration>
inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
void sleep(TimeDuration const& rel_time)
{
this_thread::sleep(get_system_time()+rel_time);
mutex mx;
unique_lock<mutex> lock(mx);
condition_variable cond;
cond.timed_wait(lock, rel_time, hidden::always_false);
}
#endif // BOOST_THREAD_USES_DATETIME
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Clock, class Duration>
void sleep_until(const chrono::time_point<Clock, Duration>& t)
{
mutex mut;
unique_lock<mutex> lk(mut);
condition_variable cv;
cv.wait_until(lk, t, hidden::always_false);
}
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& d)
{
mutex mut;
unique_lock<mutex> lk(mut);
condition_variable cv;
cv.wait_for(lk, d, hidden::always_false);
}
#endif
namespace no_interruption_point
{
#if defined BOOST_THREAD_SLEEP_FOR_IS_STEADY
// Use pthread_delay_np or nanosleep when available
// because they do not provide an interruption point.
namespace hidden
{
void BOOST_THREAD_DECL sleep_for_internal(const detail::platform_duration& ts);
}
#if defined BOOST_THREAD_USES_DATETIME
#ifdef __DECXXX
/// Workaround of DECCXX issue of incorrect template substitution
template<>
#endif
inline void sleep(system_time const& abs_time)
{
const detail::real_platform_timepoint ts(abs_time);
detail::platform_duration d(ts - detail::real_platform_clock::now());
while (d > detail::platform_duration::zero())
{
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
hidden::sleep_for_internal(d);
d = ts - detail::real_platform_clock::now();
}
}
template<typename TimeDuration>
void sleep(TimeDuration const& rel_time)
{
hidden::sleep_for_internal(detail::platform_duration(rel_time));
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& d)
{
hidden::sleep_for_internal(detail::platform_duration(d));
}
template <class Duration>
void sleep_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
{
sleep_for(t - chrono::steady_clock::now());
}
template <class Clock, class Duration>
void sleep_until(const chrono::time_point<Clock, Duration>& t)
{
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
common_duration d(t - Clock::now());
while (d > common_duration::zero())
{
d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
hidden::sleep_for_internal(detail::platform_duration(d));
d = t - Clock::now();
}
}
#endif
#else // BOOST_THREAD_SLEEP_FOR_IS_STEADY
// When pthread_delay_np and nanosleep are not available,
// fall back to using the interruptible sleep functions.
#if defined BOOST_THREAD_USES_DATETIME
#ifdef __DECXXX
/// Workaround of DECCXX issue of incorrect template substitution
template<>
#endif
inline void sleep(system_time const& abs_time)
{
this_thread::sleep(abs_time);
}
template<typename TimeDuration>
void sleep(TimeDuration const& rel_time)
{
this_thread::sleep(rel_time);
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Clock, class Duration>
void sleep_until(const chrono::time_point<Clock, Duration>& t)
{
this_thread::sleep_until(t);
}
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& d)
{
this_thread::sleep_for(d);
}
#endif
#endif // BOOST_THREAD_SLEEP_FOR_IS_STEADY
} // no_interruption_point
} // this_thread
}

View File

@@ -1,138 +0,0 @@
#ifndef BOOST_THREAD_PTHREAD_TIMESPEC_HPP
#define BOOST_THREAD_PTHREAD_TIMESPEC_HPP
// (C) Copyright 2007-8 Anthony Williams
// (C) Copyright 2012 Vicente J. Botet Escriba
//
// 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_time.hpp>
#if defined BOOST_THREAD_USES_DATETIME
#include <boost/date_time/posix_time/conversion.hpp>
#endif
#include <pthread.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono/duration.hpp>
#endif
#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
# define BOOST_THREAD_TIMESPEC_MAC_API
#include <sys/time.h> //for gettimeofday and timeval
#else
#include <time.h> // for clock_gettime
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
#if defined BOOST_THREAD_USES_DATETIME
inline struct timespec to_timespec(boost::system_time const& abs_time)
{
struct timespec timeout = { 0,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=(long)(time_since_epoch.fractional_seconds()*(1000000000l/time_since_epoch.ticks_per_second()));
return timeout;
}
#endif
#if defined BOOST_THREAD_USES_CHRONO
inline timespec to_timespec(chrono::nanoseconds const& ns)
{
struct timespec ts;
ts.tv_sec = static_cast<long>(chrono::duration_cast<chrono::seconds>(ns).count());
ts.tv_nsec = static_cast<long>((ns - chrono::duration_cast<chrono::seconds>(ns)).count());
return ts;
}
#endif
inline timespec to_timespec(boost::intmax_t const& ns)
{
boost::intmax_t s = ns / 1000000000l;
struct timespec ts;
ts.tv_sec = static_cast<long> (s);
ts.tv_nsec = static_cast<long> (ns - s * 1000000000l);
return ts;
}
inline boost::intmax_t to_nanoseconds_int_max(timespec const& ts)
{
return static_cast<boost::intmax_t>(ts.tv_sec) * 1000000000l + ts.tv_nsec;
}
inline bool timespec_ge_zero(timespec const& ts)
{
return (ts.tv_sec >= 0) || (ts.tv_nsec >= 0);
}
#if defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
inline timespec timespec_now_monotonic()
{
timespec ts;
if ( ::clock_gettime( CLOCK_MONOTONIC, &ts ) )
{
ts.tv_sec = 0;
ts.tv_nsec = 0;
BOOST_ASSERT(0 && "Boost::Thread - Internal Error");
}
return ts;
}
#endif
inline timespec timespec_now_realtime()
{
timespec ts;
#if defined(BOOST_THREAD_TIMESPEC_MAC_API)
timeval tv;
::gettimeofday(&tv, 0);
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec * 1000;
#else
if ( ::clock_gettime( CLOCK_REALTIME, &ts ) )
{
ts.tv_sec = 0;
ts.tv_nsec = 0;
BOOST_ASSERT(0 && "Boost::Thread - Internal Error");
}
#endif
return ts;
}
inline timespec timespec_zero()
{
timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 0;
return ts;
}
inline timespec timespec_plus(timespec const& lhs, timespec const& rhs)
{
return to_timespec(to_nanoseconds_int_max(lhs) + to_nanoseconds_int_max(rhs));
}
inline timespec timespec_minus(timespec const& lhs, timespec const& rhs)
{
return to_timespec(to_nanoseconds_int_max(lhs) - to_nanoseconds_int_max(rhs));
}
inline bool timespec_gt(timespec const& lhs, timespec const& rhs)
{
return to_nanoseconds_int_max(lhs) > to_nanoseconds_int_max(rhs);
}
inline bool timespec_ge(timespec const& lhs, timespec const& rhs)
{
return to_nanoseconds_int_max(lhs) >= to_nanoseconds_int_max(rhs);
}
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -13,13 +13,20 @@
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#if defined(BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN)
#if defined(BOOST_THREAD_V2_SHARED_MUTEX)
#include <boost/thread/v2/shared_mutex.hpp>
#else
#include <boost/thread/pthread/shared_mutex.hpp>
#endif
#else
#include <boost/thread/win32/shared_mutex.hpp>
#endif
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
//#include <boost/thread/v2/shared_mutex.hpp>
#if defined(BOOST_THREAD_V2_SHARED_MUTEX)
#include <boost/thread/v2/shared_mutex.hpp>
#else
#include <boost/thread/pthread/shared_mutex.hpp>
#endif
#else
#error "Boost threads unavailable on this platform"
#endif

View File

@@ -23,7 +23,7 @@
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
#include <boost/thread/detail/thread_interruption.hpp>
#endif
#include <boost/thread/v2/thread.hpp>
#include <boost/thread/condition_variable.hpp>
#endif

View File

@@ -6,8 +6,8 @@
// (C) Copyright 2007-8 Anthony Williams
#include <boost/thread/detail/config.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread/detail/thread_heap_alloc.hpp>
#include <boost/type_traits/add_reference.hpp>
#include <boost/config/abi_prefix.hpp>
@@ -15,15 +15,13 @@ namespace boost
{
namespace detail
{
struct tss_cleanup_function
namespace thread
{
virtual ~tss_cleanup_function()
{}
typedef void(*cleanup_func_t)(void*);
typedef void(*cleanup_caller_t)(cleanup_func_t, void*);
}
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 set_tss_data(void const* key,detail::thread::cleanup_caller_t caller,detail::thread::cleanup_func_t func,void* tss_data,bool cleanup_existing);
BOOST_THREAD_DECL void* get_tss_data(void const* key);
}
@@ -34,49 +32,33 @@ namespace boost
thread_specific_ptr(thread_specific_ptr&);
thread_specific_ptr& operator=(thread_specific_ptr&);
struct delete_data:
detail::tss_cleanup_function
typedef void(*original_cleanup_func_t)(T*);
static void default_deleter(T* data)
{
void operator()(void* data)
{
delete static_cast<T*>(data);
}
};
delete data;
}
struct run_custom_cleanup_function:
detail::tss_cleanup_function
static void cleanup_caller(detail::thread::cleanup_func_t cleanup_function,void* data)
{
void (*cleanup_function)(T*);
explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)):
cleanup_function(cleanup_function_)
{}
void operator()(void* data)
{
cleanup_function(static_cast<T*>(data));
}
};
reinterpret_cast<original_cleanup_func_t>(cleanup_function)(static_cast<T*>(data));
}
boost::shared_ptr<detail::tss_cleanup_function> cleanup;
detail::thread::cleanup_func_t cleanup;
public:
typedef T element_type;
thread_specific_ptr():
cleanup(detail::heap_new<delete_data>(),detail::do_heap_delete<delete_data>())
cleanup(reinterpret_cast<detail::thread::cleanup_func_t>(&default_deleter))
{}
explicit thread_specific_ptr(void (*func_)(T*))
{
if(func_)
{
cleanup.reset(detail::heap_new<run_custom_cleanup_function>(func_),detail::do_heap_delete<run_custom_cleanup_function>());
}
}
: cleanup(reinterpret_cast<detail::thread::cleanup_func_t>(func_))
{}
~thread_specific_ptr()
{
detail::set_tss_data(this,boost::shared_ptr<detail::tss_cleanup_function>(),0,true);
detail::set_tss_data(this,0,0,0,true);
}
T* get() const
@@ -87,14 +69,14 @@ namespace boost
{
return get();
}
typename boost::detail::sp_dereference< T >::type operator*() const
typename add_reference<T>::type operator*() const
{
return *get();
}
T* release()
{
T* const temp=get();
detail::set_tss_data(this,boost::shared_ptr<detail::tss_cleanup_function>(),0,false);
detail::set_tss_data(this,0,0,0,false);
return temp;
}
void reset(T* new_value=0)
@@ -102,7 +84,7 @@ namespace boost
T* const current_value=get();
if(current_value!=new_value)
{
detail::set_tss_data(this,cleanup,new_value,true);
detail::set_tss_data(this,&cleanup_caller,cleanup,new_value,true);
}
}
};

View File

@@ -10,6 +10,8 @@
#define BOOST_THREAD_USER_SCHEDULER_HPP
#include <boost/thread/detail/config.hpp>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/concurrent_queues/sync_queue.hpp>
@@ -200,3 +202,4 @@ namespace boost
#include <boost/config/abi_suffix.hpp>
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,155 +0,0 @@
// 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 2011 Vicente J. Botet Escriba
#ifndef BOOST_THREAD_V2_THREAD_HPP
#define BOOST_THREAD_V2_THREAD_HPP
#include <boost/thread/detail/config.hpp>
#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono/system_clocks.hpp>
#include <boost/chrono/ceil.hpp>
#endif
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/lock_types.hpp>
namespace boost
{
namespace this_thread
{
namespace no_interruption_point
{
#ifdef BOOST_THREAD_USES_CHRONO
template <class Clock, class Duration>
void sleep_until(const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
mutex mut;
condition_variable cv;
unique_lock<mutex> lk(mut);
while (Clock::now() < t)
cv.wait_until(lk, t);
}
#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& d)
{
using namespace chrono;
if (d > duration<Rep, Period>::zero())
{
duration<long double> Max = nanoseconds::max BOOST_PREVENT_MACRO_SUBSTITUTION ();
nanoseconds ns;
if (d < Max)
{
ns = duration_cast<nanoseconds>(d);
if (ns < d)
++ns;
}
else
ns = nanoseconds:: max BOOST_PREVENT_MACRO_SUBSTITUTION ();
sleep_for(ns);
}
}
template <class Duration>
inline BOOST_SYMBOL_VISIBLE
void sleep_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
{
using namespace chrono;
sleep_for(t - steady_clock::now());
}
#else
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& d)
{
using namespace chrono;
if (d > duration<Rep, Period>::zero())
{
steady_clock::time_point c_timeout = steady_clock::now() + ceil<nanoseconds>(d);
sleep_until(c_timeout);
}
}
#endif
#endif
}
#ifdef BOOST_THREAD_USES_CHRONO
template <class Clock, class Duration>
void sleep_until(const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
mutex mut;
condition_variable cv;
unique_lock<mutex> lk(mut);
while (Clock::now() < t)
cv.wait_until(lk, t);
}
#if defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC && defined BOOST_CHRONO_HAS_CLOCK_STEADY
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& d)
{
using namespace chrono;
if (d > duration<Rep, Period>::zero())
{
steady_clock::time_point c_timeout = steady_clock::now() + ceil<nanoseconds>(d);
sleep_until(c_timeout);
}
}
#elif defined BOOST_THREAD_SLEEP_FOR_IS_STEADY
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& d)
{
using namespace chrono;
if (d > duration<Rep, Period>::zero())
{
duration<long double> Max = nanoseconds::max BOOST_PREVENT_MACRO_SUBSTITUTION ();
nanoseconds ns;
if (d < Max)
{
ns = duration_cast<nanoseconds>(d);
if (ns < d)
++ns;
}
else
ns = nanoseconds:: max BOOST_PREVENT_MACRO_SUBSTITUTION ();
sleep_for(ns);
}
}
template <class Duration>
inline BOOST_SYMBOL_VISIBLE
void sleep_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
{
using namespace chrono;
sleep_for(t - steady_clock::now());
}
#else
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& d)
{
using namespace chrono;
if (d > duration<Rep, Period>::zero())
{
//system_clock::time_point c_timeout = time_point_cast<system_clock::duration>(system_clock::now() + ceil<nanoseconds>(d));
system_clock::time_point c_timeout = system_clock::now() + ceil<system_clock::duration>(d);
sleep_until(c_timeout);
}
}
#endif
#endif
}
}
#endif

View File

@@ -4,7 +4,7 @@
// basic_recursive_mutex.hpp
//
// (C) Copyright 2006-8 Anthony Williams
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
// (C) Copyright 2011-2012,2017-2018 Vicente J. Botet Escriba
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -44,13 +44,13 @@ namespace boost
bool try_lock() BOOST_NOEXCEPT
{
long const current_thread_id=boost::detail::winapi::GetCurrentThreadId();
long const current_thread_id=boost::winapi::GetCurrentThreadId();
return try_recursive_lock(current_thread_id) || try_basic_lock(current_thread_id);
}
void lock()
{
long const current_thread_id=boost::detail::winapi::GetCurrentThreadId();
long const current_thread_id=boost::winapi::GetCurrentThreadId();
if(!try_recursive_lock(current_thread_id))
{
mutex.lock();
@@ -61,29 +61,30 @@ namespace boost
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock(::boost::system_time const& target)
{
long const current_thread_id=boost::detail::winapi::GetCurrentThreadId();
long const current_thread_id=boost::winapi::GetCurrentThreadId();
return try_recursive_lock(current_thread_id) || try_timed_lock(current_thread_id,target);
}
template<typename Duration>
bool timed_lock(Duration const& timeout)
bool timed_lock(Duration const& target)
{
return timed_lock(get_system_time()+timeout);
long const current_thread_id=boost::winapi::GetCurrentThreadId();
return try_recursive_lock(current_thread_id) || try_timed_lock(current_thread_id,target);
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
{
long const current_thread_id=boost::detail::winapi::GetCurrentThreadId();
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
{
long const current_thread_id=boost::winapi::GetCurrentThreadId();
return try_recursive_lock(current_thread_id) || try_timed_lock_for(current_thread_id,rel_time);
}
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
{
long const current_thread_id=boost::detail::winapi::GetCurrentThreadId();
}
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
{
long const current_thread_id=boost::winapi::GetCurrentThreadId();
return try_recursive_lock(current_thread_id) || try_timed_lock_until(current_thread_id,t);
}
}
#endif
void unlock()
{
@@ -127,6 +128,17 @@ namespace boost
}
return false;
}
template<typename Duration>
bool try_timed_lock(long current_thread_id,Duration const& target)
{
if(mutex.timed_lock(target))
{
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
recursion_count=1;
return true;
}
return false;
}
#endif
template <typename TP>
bool try_timed_lock_until(long current_thread_id,TP const& target)

View File

@@ -22,6 +22,8 @@
#include <boost/chrono/system_clocks.hpp>
#include <boost/chrono/ceil.hpp>
#endif
#include <boost/thread/detail/platform_time.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
@@ -59,7 +61,7 @@ namespace boost
}
}
// Take the lock flag if it's available
bool try_lock() BOOST_NOEXCEPT
{
return !win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit);
@@ -76,21 +78,21 @@ namespace boost
if(old_count&lock_flag_value)
{
bool lock_acquired=false;
void* const sem=get_event();
do
{
unsigned const retval(winapi::WaitForSingleObjectEx(sem, ::boost::detail::win32::infinite,0));
BOOST_VERIFY(0 == retval || ::boost::detail::win32::wait_abandoned == retval);
// BOOST_VERIFY(winapi::WaitForSingleObject(
// sem,::boost::detail::win32::infinite)==0);
clear_waiting_and_try_lock(old_count);
lock_acquired=!(old_count&lock_flag_value);
if(winapi::WaitForSingleObjectEx(sem,::boost::detail::win32::infinite,0)==0)
{
clear_waiting_and_try_lock(old_count);
}
}
while(!lock_acquired);
while(old_count&lock_flag_value);
}
}
// Loop until the number of waiters has been incremented or we've taken the lock flag
// The loop is necessary since this function may be called by multiple threads simultaneously
void mark_waiting_and_try_lock(long& old_count)
{
for(;;)
@@ -102,12 +104,19 @@ namespace boost
{
if(was_locked)
old_count=new_count;
// else we've taken the lock flag
// don't update old_count so that the calling function can see that
// the old lock flag was 0 and know that we've taken the lock flag
break;
}
old_count=current;
}
}
// Loop until someone else has taken the lock flag and cleared the event set flag or
// until we've taken the lock flag and cleared the event set flag and decremented the
// number of waiters
// The loop is necessary since this function may be called by multiple threads simultaneously
void clear_waiting_and_try_lock(long& old_count)
{
old_count&=~lock_flag_value;
@@ -118,117 +127,124 @@ namespace boost
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count);
if(current==old_count)
{
// if someone else has taken the lock flag
// no need to update old_count since old_count == new_count (ignoring
// event_set_flag_value which the calling function doesn't care about)
// else we've taken the lock flag
// don't update old_count so that the calling function can see that
// the old lock flag was 0 and know that we've taken the lock flag
break;
}
old_count=current;
}
}
private:
unsigned long getMs(detail::platform_duration const& d)
{
return static_cast<unsigned long>(d.getMs());
}
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock(::boost::system_time const& wait_until)
template <typename Duration>
unsigned long getMs(Duration const& d)
{
return static_cast<unsigned long>(chrono::ceil<chrono::milliseconds>(d).count());
}
template <typename Clock, typename Timepoint, typename Duration>
bool do_lock_until(Timepoint const& t, Duration const& max)
{
if(try_lock())
{
return true;
}
long old_count=active_count;
mark_waiting_and_try_lock(old_count);
if(old_count&lock_flag_value)
{
bool lock_acquired=false;
void* const sem=get_event();
// If the clock is the system clock, it may jump while this function
// is waiting. To compensate for this and time out near the correct
// time, we call WaitForSingleObjectEx() in a loop with a short
// timeout and recheck the time remaining each time through the loop.
do
{
if(winapi::WaitForSingleObjectEx(sem,::boost::detail::get_milliseconds_until(wait_until),0)!=0)
Duration d(t - Clock::now());
if(d <= Duration::zero()) // timeout occurred
{
BOOST_INTERLOCKED_DECREMENT(&active_count);
return false;
}
clear_waiting_and_try_lock(old_count);
lock_acquired=!(old_count&lock_flag_value);
if(max != Duration::zero())
{
d = (std::min)(d, max);
}
if(winapi::WaitForSingleObjectEx(sem,getMs(d),0)==0)
{
clear_waiting_and_try_lock(old_count);
}
}
while(!lock_acquired);
while(old_count&lock_flag_value);
}
return true;
}
public:
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock(::boost::system_time const& wait_until)
{
const detail::real_platform_timepoint t(wait_until);
return do_lock_until<detail::real_platform_clock>(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
}
template<typename Duration>
bool timed_lock(Duration const& timeout)
{
return timed_lock(get_system_time()+timeout);
const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(timeout));
// The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
return do_lock_until<detail::mono_platform_clock>(t, detail::platform_duration::zero());
}
bool timed_lock(boost::xtime const& timeout)
{
return timed_lock(system_time(timeout));
return timed_lock(boost::system_time(timeout));
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
{
return try_lock_until(chrono::steady_clock::now() + rel_time);
const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time);
typedef typename chrono::duration<Rep, Period> Duration;
typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
// The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
return do_lock_until<chrono::steady_clock>(t, common_duration::zero());
}
template <class Duration>
bool try_lock_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
{
typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
// The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
return do_lock_until<chrono::steady_clock>(t, common_duration::zero());
}
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
system_clock::time_point s_now = system_clock::now();
typename Clock::time_point c_now = Clock::now();
return try_lock_until(s_now + ceil<system_clock::duration>(t - c_now));
}
template <class Duration>
bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
{
using namespace chrono;
typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt;
return try_lock_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch())));
}
bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp)
{
if(try_lock())
{
return true;
}
long old_count=active_count;
mark_waiting_and_try_lock(old_count);
if(old_count&lock_flag_value)
{
bool lock_acquired=false;
void* const sem=get_event();
do
{
chrono::time_point<chrono::system_clock, chrono::system_clock::duration> now = chrono::system_clock::now();
if (tp<=now) {
BOOST_INTERLOCKED_DECREMENT(&active_count);
return false;
}
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-now);
if(winapi::WaitForSingleObjectEx(sem,static_cast<unsigned long>(rel_time.count()),0)!=0)
{
BOOST_INTERLOCKED_DECREMENT(&active_count);
return false;
}
clear_waiting_and_try_lock(old_count);
lock_acquired=!(old_count&lock_flag_value);
}
while(!lock_acquired);
}
return true;
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
return do_lock_until<Clock>(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
}
#endif
void unlock()
{
long const offset=lock_flag_value;
// Clear the lock flag using atomic addition (works since long is always 32 bits on Windows)
long const old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,lock_flag_value);
if(!(old_count&event_set_flag_value) && (old_count>offset))
// If someone is waiting to take the lock, set the event set flag and, if
// the event set flag hadn't already been set, send an event.
if(!(old_count&event_set_flag_value) && (old_count>lock_flag_value))
{
if(!win32::interlocked_bit_test_and_set(&active_count,event_set_flag_bit))
{
@@ -238,6 +254,8 @@ namespace boost
}
private:
// Create an event in a thread-safe way
// The first thread to create the event wins and all other thread will use that event
void* get_event()
{
void* current_event=::boost::detail::interlocked_read_acquire(&event);

View File

@@ -18,6 +18,7 @@
#include <boost/thread/thread_time.hpp>
#include <boost/thread/lock_guard.hpp>
#include <boost/thread/lock_types.hpp>
#include <boost/thread/detail/platform_time.hpp>
#include <boost/assert.hpp>
#include <boost/intrusive_ptr.hpp>
@@ -76,7 +77,7 @@ namespace boost
void release(unsigned count_to_release)
{
notified=true;
detail::winapi::ReleaseSemaphore(semaphore,count_to_release,0);
winapi::ReleaseSemaphore(semaphore,count_to_release,0);
}
void release_waiters()
@@ -89,14 +90,14 @@ namespace boost
return notified;
}
bool wait(timeout abs_time)
bool interruptible_wait(detail::internal_platform_timepoint const &timeout)
{
return this_thread::interruptible_wait(semaphore,abs_time);
return this_thread::interruptible_wait(semaphore, timeout);
}
bool woken()
{
unsigned long const woken_result=detail::winapi::WaitForSingleObjectEx(wake_sem,0,0);
unsigned long const woken_result=winapi::WaitForSingleObjectEx(wake_sem,0,0);
BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0));
return woken_result==0;
}
@@ -135,7 +136,7 @@ namespace boost
void wake_waiters(long count_to_wake)
{
detail::interlocked_write_release(&total_count,total_count-count_to_wake);
detail::winapi::ReleaseSemaphore(wake_sem,count_to_wake,0);
winapi::ReleaseSemaphore(wake_sem,count_to_wake,0);
}
template<typename lock_type>
@@ -230,42 +231,7 @@ namespace boost
}
};
protected:
template<typename lock_type>
bool do_wait(lock_type& lock,timeout abs_time)
{
relocker<lock_type> locker(lock);
entry_manager entry(get_wait_entry(), internal_mutex);
locker.unlock();
bool woken=false;
while(!woken)
{
if(!entry->wait(abs_time))
{
return false;
}
woken=entry->woken();
}
// do it here to avoid throwing on the destructor
entry.remove_waiter_and_reset();
locker.lock();
return woken;
}
template<typename lock_type,typename predicate_type>
bool do_wait(lock_type& m,timeout const& abs_time,predicate_type pred)
{
while (!pred())
{
if(!do_wait(m, abs_time))
return pred();
}
return true;
}
basic_condition_variable(const basic_condition_variable& other);
basic_condition_variable& operator=(const basic_condition_variable& other);
@@ -277,6 +243,38 @@ namespace boost
~basic_condition_variable()
{}
// When this function returns true:
// * A notification (or sometimes a spurious OS signal) has been received
// * Do not assume that the timeout has not been reached
// * Do not assume that the predicate has been changed
//
// When this function returns false:
// * The timeout has been reached
// * Do not assume that a notification has not been received
// * Do not assume that the predicate has not been changed
template<typename lock_type>
bool do_wait_until(lock_type& lock, detail::internal_platform_timepoint const &timeout)
{
relocker<lock_type> locker(lock);
entry_manager entry(get_wait_entry(), internal_mutex);
locker.unlock();
bool woken=false;
while(!woken)
{
if(!entry->interruptible_wait(timeout))
{
return false;
}
woken=entry->woken();
}
// do it here to avoid throwing on the destructor
entry.remove_waiter_and_reset();
locker.lock();
return true;
}
void notify_one() BOOST_NOEXCEPT
{
if(detail::interlocked_read_acquire(&total_count))
@@ -330,75 +328,115 @@ namespace boost
condition_variable()
{}
using detail::basic_condition_variable::do_wait_until;
using detail::basic_condition_variable::notify_one;
using detail::basic_condition_variable::notify_all;
void wait(unique_lock<mutex>& m)
{
do_wait(m,detail::timeout::sentinel());
do_wait_until(m, detail::internal_platform_timepoint::getMax());
}
template<typename predicate_type>
void wait(unique_lock<mutex>& m,predicate_type pred)
{
while(!pred()) wait(m);
while (!pred())
{
wait(m);
}
}
#if defined BOOST_THREAD_USES_DATETIME
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time)
{
return do_wait(m,abs_time);
// The system time may jump while this function is waiting. To compensate for this and time
// out near the correct time, we could call do_wait_until() in a loop with a short timeout
// and recheck the time remaining each time through the loop. However, because we can't
// check the predicate each time do_wait_until() completes, this introduces the possibility
// of not exiting the function when a notification occurs, since do_wait_until() may report
// that it timed out even though a notification was received. The best this function can do
// is report correctly whether or not it reached the timeout time.
const detail::real_platform_timepoint ts(abs_time);
const detail::platform_duration d(ts - detail::real_platform_clock::now());
do_wait_until(m, detail::internal_platform_clock::now() + d);
return ts > detail::real_platform_clock::now();
}
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time)
{
return do_wait(m,system_time(abs_time));
return timed_wait(m, system_time(abs_time));
}
template<typename duration_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
{
if (wait_duration.is_pos_infinity())
{
wait(m); // or do_wait(m,detail::timeout::sentinel());
return true;
}
if (wait_duration.is_special())
{
return true;
}
return do_wait(m,wait_duration.total_milliseconds());
if (wait_duration.is_pos_infinity())
{
wait(m);
return true;
}
if (wait_duration.is_special())
{
return true;
}
const detail::platform_duration d(wait_duration);
return do_wait_until(m, detail::internal_platform_clock::now() + d);
}
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time,predicate_type pred)
{
return do_wait(m,abs_time,pred);
// The system time may jump while this function is waiting. To compensate for this
// and time out near the correct time, we call do_wait_until() in a loop with a
// short timeout and recheck the time remaining each time through the loop.
const detail::real_platform_timepoint ts(abs_time);
while (!pred())
{
detail::platform_duration d(ts - detail::real_platform_clock::now());
if (d <= detail::platform_duration::zero()) break; // timeout occurred
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
do_wait_until(m, detail::internal_platform_clock::now() + d);
}
return pred();
}
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time,predicate_type pred)
{
return do_wait(m,system_time(abs_time),pred);
return timed_wait(m, system_time(abs_time), pred);
}
template<typename duration_type,typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
{
if (wait_duration.is_pos_infinity())
{
while (!pred())
{
wait(m); // or do_wait(m,detail::timeout::sentinel());
}
return true;
while (!pred())
{
wait(m);
}
return true;
}
if (wait_duration.is_special())
{
return pred();
return pred();
}
return do_wait(m,wait_duration.total_milliseconds(),pred);
const detail::platform_duration d(wait_duration);
const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d);
while (!pred())
{
if (!do_wait_until(m, ts)) break; // timeout occurred
}
return pred();
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Duration>
cv_status
wait_until(
unique_lock<mutex>& lock,
const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
{
const detail::internal_platform_timepoint ts(t);
if (do_wait_until(lock, ts)) return cv_status::no_timeout;
else return cv_status::timeout;
}
template <class Clock, class Duration>
cv_status
@@ -406,14 +444,18 @@ namespace boost
unique_lock<mutex>& lock,
const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
chrono::time_point<Clock, Duration> now = Clock::now();
if (t<=now) {
return cv_status::timeout;
}
do_wait(lock, ceil<milliseconds>(t-now).count());
return Clock::now() < t ? cv_status::no_timeout :
cv_status::timeout;
// The system time may jump while this function is waiting. To compensate for this and time
// out near the correct time, we could call do_wait_until() in a loop with a short timeout
// and recheck the time remaining each time through the loop. However, because we can't
// check the predicate each time do_wait_until() completes, this introduces the possibility
// of not exiting the function when a notification occurs, since do_wait_until() may report
// that it timed out even though a notification was received. The best this function can do
// is report correctly whether or not it reached the timeout time.
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
common_duration d(t - Clock::now());
do_wait_until(lock, detail::internal_chrono_clock::now() + d);
if (t > Clock::now()) return cv_status::no_timeout;
else return cv_status::timeout;
}
template <class Rep, class Period>
@@ -422,15 +464,22 @@ namespace boost
unique_lock<mutex>& lock,
const chrono::duration<Rep, Period>& d)
{
using namespace chrono;
if (d<=chrono::duration<Rep, Period>::zero()) {
return cv_status::timeout;
}
return wait_until(lock, chrono::steady_clock::now() + d);
}
steady_clock::time_point c_now = steady_clock::now();
do_wait(lock, ceil<milliseconds>(d).count());
return steady_clock::now() - c_now < d ? cv_status::no_timeout :
cv_status::timeout;
template <class Duration, class Predicate>
bool
wait_until(
unique_lock<mutex>& lock,
const chrono::time_point<detail::internal_chrono_clock, Duration>& t,
Predicate pred)
{
const detail::internal_platform_timepoint ts(t);
while (!pred())
{
if (!do_wait_until(lock, ts)) break; // timeout occurred
}
return pred();
}
template <class Clock, class Duration, class Predicate>
@@ -440,13 +489,20 @@ namespace boost
const chrono::time_point<Clock, Duration>& t,
Predicate pred)
{
// The system time may jump while this function is waiting. To compensate for this
// and time out near the correct time, we call do_wait_until() in a loop with a
// short timeout and recheck the time remaining each time through the loop.
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
while (!pred())
{
if (wait_until(lock, t) == cv_status::timeout)
return pred();
common_duration d(t - Clock::now());
if (d <= common_duration::zero()) break; // timeout occurred
d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d));
}
return true;
return pred();
}
template <class Rep, class Period, class Predicate>
bool
wait_for(
@@ -467,59 +523,122 @@ namespace boost
condition_variable_any()
{}
using detail::basic_condition_variable::do_wait_until;
using detail::basic_condition_variable::notify_one;
using detail::basic_condition_variable::notify_all;
template<typename lock_type>
void wait(lock_type& m)
{
do_wait(m,detail::timeout::sentinel());
do_wait_until(m, detail::internal_platform_timepoint::getMax());
}
template<typename lock_type,typename predicate_type>
void wait(lock_type& m,predicate_type pred)
{
while(!pred()) wait(m);
while (!pred())
{
wait(m);
}
}
#if defined BOOST_THREAD_USES_DATETIME
template<typename lock_type>
bool timed_wait(lock_type& m,boost::system_time const& abs_time)
{
return do_wait(m,abs_time);
// The system time may jump while this function is waiting. To compensate for this and time
// out near the correct time, we could call do_wait_until() in a loop with a short timeout
// and recheck the time remaining each time through the loop. However, because we can't
// check the predicate each time do_wait_until() completes, this introduces the possibility
// of not exiting the function when a notification occurs, since do_wait_until() may report
// that it timed out even though a notification was received. The best this function can do
// is report correctly whether or not it reached the timeout time.
const detail::real_platform_timepoint ts(abs_time);
const detail::platform_duration d(ts - detail::real_platform_clock::now());
do_wait_until(m, detail::internal_platform_clock::now() + d);
return ts > detail::real_platform_clock::now();
}
template<typename lock_type>
bool timed_wait(lock_type& m,boost::xtime const& abs_time)
{
return do_wait(m,system_time(abs_time));
return timed_wait(m, system_time(abs_time));
}
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());
if (wait_duration.is_pos_infinity())
{
wait(m);
return true;
}
if (wait_duration.is_special())
{
return true;
}
const detail::platform_duration d(wait_duration);
return do_wait_until(m, detail::internal_platform_clock::now() + d);
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,boost::system_time const& abs_time,predicate_type pred)
{
return do_wait(m,abs_time,pred);
// The system time may jump while this function is waiting. To compensate for this
// and time out near the correct time, we call do_wait_until() in a loop with a
// short timeout and recheck the time remaining each time through the loop.
const detail::real_platform_timepoint ts(abs_time);
while (!pred())
{
detail::platform_duration d(ts - detail::real_platform_clock::now());
if (d <= detail::platform_duration::zero()) break; // timeout occurred
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
do_wait_until(m, detail::internal_platform_clock::now() + d);
}
return pred();
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,boost::xtime const& abs_time,predicate_type pred)
{
return do_wait(m,system_time(abs_time),pred);
return timed_wait(m, system_time(abs_time), 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);
if (wait_duration.is_pos_infinity())
{
while (!pred())
{
wait(m);
}
return true;
}
if (wait_duration.is_special())
{
return pred();
}
const detail::platform_duration d(wait_duration);
const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d);
while (!pred())
{
if (!do_wait_until(m, ts)) break; // timeout occurred
}
return pred();
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class lock_type,class Duration>
cv_status
wait_until(
lock_type& lock,
const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
{
const detail::internal_platform_timepoint ts(t);
if (do_wait_until(lock, ts)) return cv_status::no_timeout;
else return cv_status::timeout;
}
template <class lock_type, class Clock, class Duration>
cv_status
@@ -527,14 +646,18 @@ namespace boost
lock_type& lock,
const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
chrono::time_point<Clock, Duration> now = Clock::now();
if (t<=now) {
return cv_status::timeout;
}
do_wait(lock, ceil<milliseconds>(t-now).count());
return Clock::now() < t ? cv_status::no_timeout :
cv_status::timeout;
// The system time may jump while this function is waiting. To compensate for this and time
// out near the correct time, we could call do_wait_until() in a loop with a short timeout
// and recheck the time remaining each time through the loop. However, because we can't
// check the predicate each time do_wait_until() completes, this introduces the possibility
// of not exiting the function when a notification occurs, since do_wait_until() may report
// that it timed out even though a notification was received. The best this function can do
// is report correctly whether or not it reached the timeout time.
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
common_duration d(t - Clock::now());
do_wait_until(lock, detail::internal_chrono_clock::now() + d);
if (t > Clock::now()) return cv_status::no_timeout;
else return cv_status::timeout;
}
template <class lock_type, class Rep, class Period>
@@ -543,14 +666,22 @@ namespace boost
lock_type& lock,
const chrono::duration<Rep, Period>& d)
{
using namespace chrono;
if (d<=chrono::duration<Rep, Period>::zero()) {
return cv_status::timeout;
}
steady_clock::time_point c_now = steady_clock::now();
do_wait(lock, ceil<milliseconds>(d).count());
return steady_clock::now() - c_now < d ? cv_status::no_timeout :
cv_status::timeout;
return wait_until(lock, chrono::steady_clock::now() + d);
}
template <class lock_type, class Clock, class Duration, class Predicate>
bool
wait_until(
lock_type& lock,
const chrono::time_point<detail::internal_chrono_clock, Duration>& t,
Predicate pred)
{
const detail::internal_platform_timepoint ts(t);
while (!pred())
{
if (!do_wait_until(lock, ts)) break; // timeout occurred
}
return pred();
}
template <class lock_type, class Clock, class Duration, class Predicate>
@@ -560,12 +691,18 @@ namespace boost
const chrono::time_point<Clock, Duration>& t,
Predicate pred)
{
// The system time may jump while this function is waiting. To compensate for this
// and time out near the correct time, we call do_wait_until() in a loop with a
// short timeout and recheck the time remaining each time through the loop.
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
while (!pred())
{
if (wait_until(lock, t) == cv_status::timeout)
return pred();
common_duration d(t - Clock::now());
if (d <= common_duration::zero()) break; // timeout occurred
d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d));
}
return true;
return pred();
}
template <class lock_type, class Rep, class Period, class Predicate>

View File

@@ -87,9 +87,9 @@ namespace boost
{
void* const res=
#if defined(_M_ARM64)
__iso_volatile_load64((const volatile __int64*)x);
(void*)__iso_volatile_load64((const volatile __int64*)x);
#else
__iso_volatile_load32((const volatile __int32*)x);
(void*)__iso_volatile_load32((const volatile __int32*)x);
#endif
BOOST_THREAD_DETAIL_COMPILER_BARRIER();
__dmb(0xB); // _ARM_BARRIER_ISH, see armintr.h from MSVC 11 and later

View File

@@ -136,9 +136,9 @@ namespace boost
}
#ifdef BOOST_NO_ANSI_APIS
return ::boost::detail::winapi::OpenEventW(
return ::boost::winapi::OpenEventW(
#else
return ::boost::detail::winapi::OpenEventA(
return ::boost::winapi::OpenEventA(
#endif
::boost::detail::win32::synchronize |
::boost::detail::win32::event_modify_state,
@@ -186,7 +186,7 @@ namespace boost
}
if(ctx.event_handle)
{
::boost::detail::winapi::ResetEvent(ctx.event_handle);
::boost::winapi::ResetEvent(ctx.event_handle);
}
return true;
}
@@ -207,7 +207,7 @@ namespace boost
}
if(ctx.event_handle)
{
::boost::detail::winapi::SetEvent(ctx.event_handle);
::boost::winapi::SetEvent(ctx.event_handle);
}
}
inline void rollback_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT
@@ -219,13 +219,13 @@ namespace boost
}
if(ctx.event_handle)
{
::boost::detail::winapi::SetEvent(ctx.event_handle);
::boost::winapi::SetEvent(ctx.event_handle);
}
}
}
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
//#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR)
//#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR)
inline void call_once(once_flag& flag, void (*f)())
{
// Try for a quick win: if the procedure has already been called
@@ -264,7 +264,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite, 0));
}
}
@@ -308,7 +308,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
@@ -355,7 +355,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
@@ -400,7 +400,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
@@ -443,7 +443,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
@@ -486,7 +486,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
@@ -529,7 +529,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
@@ -574,7 +574,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
@@ -617,7 +617,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
@@ -660,7 +660,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
@@ -703,13 +703,13 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
#endif
#if 1
#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR)
#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR)
inline void call_once(once_flag& flag, void (*f)())
{
// Try for a quick win: if the procedure has already been called
@@ -748,7 +748,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
@@ -793,7 +793,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
@@ -839,7 +839,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
@@ -886,7 +886,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
@@ -930,7 +930,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
@@ -977,7 +977,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
@@ -1024,7 +1024,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
@@ -1073,7 +1073,7 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx(
BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}

View File

@@ -2,12 +2,13 @@
#define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
// (C) Copyright 2006-8 Anthony Williams
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
// (C) Copyright 2011-2012,2017-2018 Vicente J. Botet Escriba
//
// 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 <boost/assert.hpp>
#include <boost/detail/interlocked.hpp>
#include <boost/thread/win32/thread_primitives.hpp>
@@ -19,6 +20,7 @@
#include <boost/chrono/ceil.hpp>
#endif
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/platform_time.hpp>
#include <boost/config/abi_prefix.hpp>
@@ -29,7 +31,7 @@ namespace boost
private:
struct state_data
{
unsigned shared_count:11,
unsigned long shared_count:11,
shared_waiting:11,
exclusive:1,
upgrade:1,
@@ -38,19 +40,22 @@ namespace boost
friend bool operator==(state_data const& lhs,state_data const& rhs)
{
return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs);
return std::memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
}
};
template<typename T>
T interlocked_compare_exchange(T* target,T new_value,T comparand)
static state_data interlocked_compare_exchange(state_data* target, state_data new_value, state_data comparand)
{
BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long));
BOOST_STATIC_ASSERT(sizeof(state_data) == sizeof(long));
long new_val, comp;
std::memcpy(&new_val, &new_value, sizeof(new_value));
std::memcpy(&comp, &comparand, sizeof(comparand));
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);
new_val,
comp);
state_data result;
std::memcpy(&result, &res, sizeof(result));
return result;
}
enum
@@ -67,19 +72,19 @@ namespace boost
{
if(old_state.exclusive_waiting)
{
BOOST_VERIFY(detail::winapi::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0);
BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0);
}
if(old_state.shared_waiting || old_state.exclusive_waiting)
{
BOOST_VERIFY(detail::winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
}
}
void release_shared_waiters(state_data old_state)
{
if(old_state.shared_waiting || old_state.exclusive_waiting)
{
BOOST_VERIFY(detail::winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
}
}
@@ -107,9 +112,9 @@ namespace boost
~shared_mutex()
{
detail::winapi::CloseHandle(upgrade_sem);
detail::winapi::CloseHandle(semaphores[unlock_sem]);
detail::winapi::CloseHandle(semaphores[exclusive_sem]);
winapi::CloseHandle(upgrade_sem);
winapi::CloseHandle(semaphores[unlock_sem]);
winapi::CloseHandle(semaphores[exclusive_sem]);
}
bool try_lock_shared()
@@ -139,21 +144,60 @@ namespace boost
void lock_shared()
{
for(;;)
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
{
++new_state.shared_waiting;
if(!new_state.shared_waiting)
{
boost::throw_exception(boost::lock_error());
}
}
else
{
++new_state.shared_count;
if(!new_state.shared_count)
{
boost::throw_exception(boost::lock_error());
}
}
#if defined BOOST_THREAD_USES_DATETIME
BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel()));
#else
BOOST_VERIFY(try_lock_shared_until(chrono::steady_clock::now()));
#endif
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
{
return;
}
BOOST_VERIFY(winapi::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::win32::infinite,0)==0);
}
}
#if defined BOOST_THREAD_USES_DATETIME
template<typename TimeDuration>
bool timed_lock_shared(TimeDuration const & relative_time)
private:
unsigned long getMs(detail::platform_duration const& d)
{
return timed_lock_shared(get_system_time()+relative_time);
return static_cast<unsigned long>(d.getMs());
}
bool timed_lock_shared(boost::system_time const& wait_until)
template <typename Duration>
unsigned long getMs(Duration const& d)
{
return static_cast<unsigned long>(chrono::ceil<chrono::milliseconds>(d).count());
}
template <typename Clock, typename Timepoint, typename Duration>
bool do_lock_shared_until(Timepoint const& t, Duration const& max)
{
for(;;)
{
@@ -191,7 +235,30 @@ namespace boost
return true;
}
unsigned long const res=detail::winapi::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until), 0);
// If the clock is the system clock, it may jump while this function
// is waiting. To compensate for this and time out near the correct
// time, we call WaitForSingleObjectEx() in a loop with a short
// timeout and recheck the time remaining each time through the loop.
unsigned long res=0;
for(;;)
{
Duration d(t - Clock::now());
if(d <= Duration::zero()) // timeout occurred
{
res=detail::win32::timeout;
break;
}
if(max != Duration::zero())
{
d = (std::min)(d, max);
}
res=winapi::WaitForSingleObjectEx(semaphores[unlock_sem],getMs(d),0);
if(res!=detail::win32::timeout) // semaphore released
{
break;
}
}
if(res==detail::win32::timeout)
{
for(;;)
@@ -231,114 +298,45 @@ namespace boost
BOOST_ASSERT(res==0);
}
}
public:
#if defined BOOST_THREAD_USES_DATETIME
template<typename TimeDuration>
bool timed_lock_shared(TimeDuration const & relative_time)
{
const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(relative_time));
// The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
return do_lock_shared_until<detail::mono_platform_clock>(t, detail::platform_duration::zero());
}
bool timed_lock_shared(boost::system_time const& wait_until)
{
const detail::real_platform_timepoint t(wait_until);
return do_lock_shared_until<detail::real_platform_clock>(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
{
return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time);
typedef typename chrono::duration<Rep, Period> Duration;
typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
// The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
return do_lock_shared_until<chrono::steady_clock>(t, common_duration::zero());
}
template <class Duration>
bool try_lock_shared_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
{
typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
// The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
return do_lock_shared_until<chrono::steady_clock>(t, common_duration::zero());
}
template <class Clock, class Duration>
bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
system_clock::time_point s_now = system_clock::now();
typename Clock::time_point c_now = Clock::now();
return try_lock_shared_until(s_now + ceil<system_clock::duration>(t - c_now));
}
template <class Duration>
bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, Duration>& t)
{
using namespace chrono;
typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt;
return try_lock_shared_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch())));
}
bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp)
{
for(;;)
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
{
++new_state.shared_waiting;
if(!new_state.shared_waiting)
{
boost::throw_exception(boost::lock_error());
}
}
else
{
++new_state.shared_count;
if(!new_state.shared_count)
{
boost::throw_exception(boost::lock_error());
}
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
{
return true;
}
chrono::system_clock::time_point n = chrono::system_clock::now();
unsigned long res;
if (tp>n) {
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-n);
res=detail::winapi::WaitForSingleObjectEx(semaphores[unlock_sem],
static_cast<unsigned long>(rel_time.count()), 0);
} else {
res=detail::win32::timeout;
}
if(res==detail::win32::timeout)
{
for(;;)
{
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;
if(!new_state.shared_count)
{
return false;
}
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
{
return true;
}
return false;
}
BOOST_ASSERT(res==0);
}
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
return do_lock_shared_until<Clock>(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
}
#endif
@@ -375,7 +373,7 @@ namespace boost
{
if(old_state.upgrade)
{
BOOST_VERIFY(detail::winapi::ReleaseSemaphore(upgrade_sem,1,0)!=0);
BOOST_VERIFY(winapi::ReleaseSemaphore(upgrade_sem,1,0)!=0);
}
else
{
@@ -388,24 +386,6 @@ namespace boost
}
}
void lock()
{
#if defined BOOST_THREAD_USES_DATETIME
BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
#else
BOOST_VERIFY(try_lock_until(chrono::steady_clock::now()));
#endif
}
#if defined BOOST_THREAD_USES_DATETIME
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time)
{
return timed_lock(get_system_time()+relative_time);
}
#endif
bool try_lock()
{
state_data old_state=state;
@@ -431,14 +411,58 @@ namespace boost
return true;
}
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock(boost::system_time const& wait_until)
void lock()
{
for(;;)
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
if(new_state.shared_count || new_state.exclusive)
{
++new_state.exclusive_waiting;
if(!new_state.exclusive_waiting)
{
boost::throw_exception(boost::lock_error());
}
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;
}
if(!old_state.shared_count && !old_state.exclusive)
{
return;
}
#ifndef UNDER_CE
const bool wait_all = true;
#else
const bool wait_all = false;
#endif
BOOST_VERIFY(winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::win32::infinite,0)<2);
}
}
private:
template <typename Clock, typename Timepoint, typename Duration>
bool do_lock_until(Timepoint const& t, Duration const& max)
{
for(;;)
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
@@ -469,12 +493,37 @@ namespace boost
{
return true;
}
#ifndef UNDER_CE
const bool wait_all = true;
#else
const bool wait_all = false;
#endif
unsigned long const wait_res=detail::winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until), 0);
// If the clock is the system clock, it may jump while this function
// is waiting. To compensate for this and time out near the correct
// time, we call WaitForMultipleObjectsEx() in a loop with a short
// timeout and recheck the time remaining each time through the loop.
unsigned long wait_res=0;
for(;;)
{
Duration d(t - Clock::now());
if(d <= Duration::zero()) // timeout occurred
{
wait_res=detail::win32::timeout;
break;
}
if(max != Duration::zero())
{
d = (std::min)(d, max);
}
#ifndef UNDER_CE
wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,true,getMs(d),0);
#else
wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,false,getMs(d),0);
#endif
//wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,getMs(d), 0);
if(wait_res!=detail::win32::timeout) // semaphore released
{
break;
}
}
if(wait_res==detail::win32::timeout)
{
for(;;)
@@ -500,7 +549,7 @@ namespace boost
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if (must_notify)
{
BOOST_VERIFY(detail::winapi::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
}
if(current_state==old_state)
@@ -515,123 +564,48 @@ namespace boost
}
return false;
}
BOOST_ASSERT(wait_res<2);
}
}
public:
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock(boost::system_time const& wait_until)
{
const detail::real_platform_timepoint t(wait_until);
return do_lock_until<detail::real_platform_clock>(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
}
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time)
{
const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(relative_time));
// The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
return do_lock_until<detail::mono_platform_clock>(t, detail::platform_duration::zero());
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
{
return try_lock_until(chrono::steady_clock::now() + rel_time);
const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time);
typedef typename chrono::duration<Rep, Period> Duration;
typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
// The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
return do_lock_until<chrono::steady_clock>(t, common_duration::zero());
}
template <class Duration>
bool try_lock_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
{
typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
// The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
return do_lock_until<chrono::steady_clock>(t, common_duration::zero());
}
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
system_clock::time_point s_now = system_clock::now();
typename Clock::time_point c_now = Clock::now();
return try_lock_until(s_now + ceil<system_clock::duration>(t - c_now));
}
template <class Duration>
bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
{
using namespace chrono;
typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt;
return try_lock_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch())));
}
bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp)
{
for(;;)
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
if(new_state.shared_count || new_state.exclusive)
{
++new_state.exclusive_waiting;
if(!new_state.exclusive_waiting)
{
boost::throw_exception(boost::lock_error());
}
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;
}
if(!old_state.shared_count && !old_state.exclusive)
{
return true;
}
#ifndef UNDER_CE
const bool wait_all = true;
#else
const bool wait_all = false;
#endif
chrono::system_clock::time_point n = chrono::system_clock::now();
unsigned long wait_res;
if (tp>n) {
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
wait_res=detail::winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,
static_cast<unsigned long>(rel_time.count()), 0);
} else {
wait_res=detail::win32::timeout;
}
if(wait_res==detail::win32::timeout)
{
for(;;)
{
bool must_notify = false;
state_data new_state=old_state;
if(new_state.shared_count || new_state.exclusive)
{
if(new_state.exclusive_waiting)
{
if(!--new_state.exclusive_waiting)
{
new_state.exclusive_waiting_blocked=false;
must_notify = true;
}
}
}
else
{
new_state.exclusive=true;
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if (must_notify)
{
BOOST_VERIFY(detail::winapi::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
}
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
if(!old_state.shared_count && !old_state.exclusive)
{
return true;
}
return false;
}
BOOST_ASSERT(wait_res<2);
}
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
return do_lock_until<Clock>(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
}
#endif
@@ -698,7 +672,7 @@ namespace boost
return;
}
BOOST_VERIFY(!detail::winapi::WaitForSingleObjectEx(semaphores[unlock_sem],detail::winapi::infinite, 0));
BOOST_VERIFY(winapi::WaitForSingleObjectEx(semaphores[unlock_sem],winapi::infinite,0)==0);
}
}
@@ -790,7 +764,7 @@ namespace boost
{
if(!last_reader)
{
BOOST_VERIFY(!detail::winapi::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite, 0));
BOOST_VERIFY(winapi::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite,0)==0);
}
break;
}
@@ -823,27 +797,6 @@ namespace boost
}
release_waiters(old_state);
}
// bool try_unlock_upgrade_and_lock()
// {
// return false;
// }
//#ifdef BOOST_THREAD_USES_CHRONO
// template <class Rep, class Period>
// bool
// try_unlock_upgrade_and_lock_for(
// const chrono::duration<Rep, Period>& rel_time)
// {
// return try_unlock_upgrade_and_lock_until(
// chrono::steady_clock::now() + rel_time);
// }
// template <class Clock, class Duration>
// bool
// try_unlock_upgrade_and_lock_until(
// const chrono::time_point<Clock, Duration>& abs_time)
// {
// return false;
// }
//#endif
void unlock_and_lock_shared()
{

View File

@@ -10,6 +10,7 @@
#include <boost/thread/thread_time.hpp>
#include <boost/thread/win32/thread_primitives.hpp>
#include <boost/thread/win32/thread_heap_alloc.hpp>
#include <boost/thread/detail/platform_time.hpp>
#include <boost/predef/platform.h>
@@ -79,12 +80,15 @@ namespace boost
struct thread_exit_callback_node;
struct tss_data_node
{
boost::shared_ptr<boost::detail::tss_cleanup_function> func;
typedef void(*cleanup_func_t)(void*);
typedef void(*cleanup_caller_t)(cleanup_func_t, void*);
cleanup_caller_t caller;
cleanup_func_t func;
void* value;
tss_data_node(boost::shared_ptr<boost::detail::tss_cleanup_function> func_,
void* value_):
func(func_),value(value_)
tss_data_node(cleanup_caller_t caller_,cleanup_func_t func_,void* value_):
caller(caller_),func(func_),value(value_)
{}
};
@@ -112,8 +116,10 @@ namespace boost
> notify_list_t;
notify_list_t notify;
//#ifndef BOOST_NO_EXCEPTIONS
typedef std::vector<shared_ptr<shared_state_base> > async_states_t;
async_states_t async_states_;
//#endif
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
// These data must be at the end so that the access to the other fields doesn't change
// when BOOST_THREAD_PROVIDES_INTERRUPTIONS is defined
@@ -128,8 +134,10 @@ namespace boost
thread_exit_callbacks(0),
id(0),
tss_data(),
notify(),
async_states_()
notify()
//#ifndef BOOST_NO_EXCEPTIONS
, async_states_()
//#endif
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
, interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset))
, interruption_enabled(true)
@@ -153,7 +161,7 @@ namespace boost
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
void interrupt()
{
BOOST_VERIFY(detail::winapi::SetEvent(interruption_handle)!=0);
BOOST_VERIFY(winapi::SetEvent(interruption_handle)!=0);
}
#endif
typedef detail::win32::handle native_handle_type;
@@ -165,155 +173,121 @@ namespace boost
notify.push_back(std::pair<condition_variable*, mutex*>(cv, m));
}
//#ifndef BOOST_NO_EXCEPTIONS
void make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
{
async_states_.push_back(as);
}
//#endif
};
BOOST_THREAD_DECL thread_data_base* get_current_thread_data();
typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr;
struct BOOST_SYMBOL_VISIBLE timeout
{
win32::ticks_type 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::GetTickCount64_()()),
milliseconds(milliseconds_),
relative(true)
//,
// abs_time(boost::get_system_time())
{}
timeout(boost::system_time const& abs_time_):
start(win32::GetTickCount64_()()),
milliseconds(0),
relative(false),
abs_time(abs_time_)
{}
struct BOOST_SYMBOL_VISIBLE 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)
{
win32::ticks_type const now=win32::GetTickCount64_()();
win32::ticks_type 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)
{}
};
inline uintmax_t pin_to_zero(intmax_t value)
{
return (value<0)?0u:(uintmax_t)value;
}
}
namespace this_thread
{
void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT;
bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);
inline void interruptible_wait(uintmax_t milliseconds)
{
interruptible_wait(detail::win32::invalid_handle_value,milliseconds);
}
inline BOOST_SYMBOL_VISIBLE void interruptible_wait(system_time const& abs_time)
{
interruptible_wait(detail::win32::invalid_handle_value,abs_time);
}
bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout);
#if defined BOOST_THREAD_USES_DATETIME
template<typename TimeDuration>
inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
{
interruptible_wait(detail::pin_to_zero(rel_time.total_milliseconds()));
interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + detail::platform_duration(rel_time));
}
inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time)
{
interruptible_wait(abs_time);
const detail::real_platform_timepoint ts(abs_time);
detail::platform_duration d(ts - detail::real_platform_clock::now());
while (d > detail::platform_duration::zero())
{
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + d);
d = ts - detail::real_platform_clock::now();
}
}
// #11322 sleep_for() nanoseconds overload will always return too early on windows
//#ifdef BOOST_THREAD_USES_CHRONO
// inline void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns)
// {
// interruptible_wait(chrono::duration_cast<chrono::milliseconds>(ns).count());
// }
//#endif
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& d)
{
interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + detail::platform_duration(d));
}
template <class Duration>
void sleep_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
{
sleep_for(t - chrono::steady_clock::now());
}
template <class Clock, class Duration>
void sleep_until(const chrono::time_point<Clock, Duration>& t)
{
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
common_duration d(t - Clock::now());
while (d > common_duration::zero())
{
d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
sleep_for(d);
d = t - Clock::now();
}
}
#endif
namespace no_interruption_point
{
bool BOOST_THREAD_DECL non_interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);
inline void non_interruptible_wait(uintmax_t milliseconds)
{
non_interruptible_wait(detail::win32::invalid_handle_value,milliseconds);
}
inline BOOST_SYMBOL_VISIBLE void non_interruptible_wait(system_time const& abs_time)
{
non_interruptible_wait(detail::win32::invalid_handle_value,abs_time);
}
bool BOOST_THREAD_DECL non_interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout);
#if defined BOOST_THREAD_USES_DATETIME
template<typename TimeDuration>
inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
{
non_interruptible_wait(detail::pin_to_zero(rel_time.total_milliseconds()));
non_interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + detail::platform_duration(rel_time));
}
inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time)
{
non_interruptible_wait(abs_time);
const detail::real_platform_timepoint ts(abs_time);
detail::platform_duration d(ts - detail::real_platform_clock::now());
while (d > detail::platform_duration::zero())
{
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
non_interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + d);
d = ts - detail::real_platform_clock::now();
}
}
// #11322 sleep_for() nanoseconds overload will always return too early on windows
//#ifdef BOOST_THREAD_USES_CHRONO
// inline void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns)
// {
// non_interruptible_wait(chrono::duration_cast<chrono::milliseconds>(ns).count());
// }
//#endif
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& d)
{
non_interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + detail::platform_duration(d));
}
template <class Duration>
void sleep_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
{
sleep_for(t - chrono::steady_clock::now());
}
template <class Clock, class Duration>
void sleep_until(const chrono::time_point<Clock, Duration>& t)
{
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
common_duration d(t - Clock::now());
while (d > common_duration::zero())
{
d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
sleep_for(d);
d = t - Clock::now();
}
}
#endif
}
}

View File

@@ -12,7 +12,7 @@
#include <boost/throw_exception.hpp>
#include <boost/core/no_exceptions_support.hpp>
#include <boost/detail/winapi/heap_memory.hpp>
#include <boost/winapi/heap_memory.hpp>
#include <boost/config/abi_prefix.hpp>
@@ -22,7 +22,7 @@ namespace boost
{
inline void* allocate_raw_heap_memory(unsigned size)
{
void* const heap_memory=detail::winapi::HeapAlloc(detail::winapi::GetProcessHeap(),0,size);
void* const heap_memory=winapi::HeapAlloc(winapi::GetProcessHeap(),0,size);
if(!heap_memory)
{
boost::throw_exception(std::bad_alloc());
@@ -32,7 +32,7 @@ namespace boost
inline void free_raw_heap_memory(void* heap_memory)
{
BOOST_VERIFY(detail::winapi::HeapFree(detail::winapi::GetProcessHeap(),0,heap_memory)!=0);
BOOST_VERIFY(winapi::HeapFree(winapi::GetProcessHeap(),0,heap_memory)!=0);
}
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) && ! defined (BOOST_NO_CXX11_RVALUE_REFERENCES)
template<typename T,typename... Args>

View File

@@ -16,23 +16,22 @@
#include <boost/assert.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/detail/interlocked.hpp>
#include <boost/detail/winapi/config.hpp>
#include <boost/detail/winapi/semaphore.hpp>
#include <boost/detail/winapi/dll.hpp>
#include <boost/detail/winapi/system.hpp>
#include <boost/detail/winapi/time.hpp>
#include <boost/detail/winapi/event.hpp>
#include <boost/detail/winapi/thread.hpp>
#include <boost/detail/winapi/get_current_thread.hpp>
#include <boost/detail/winapi/get_current_thread_id.hpp>
#include <boost/detail/winapi/get_current_process.hpp>
#include <boost/detail/winapi/get_current_process_id.hpp>
#include <boost/detail/winapi/wait.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/access_rights.hpp>
#include <boost/winapi/config.hpp>
#include <boost/winapi/basic_types.hpp>
#include <boost/winapi/semaphore.hpp>
#include <boost/winapi/system.hpp>
#include <boost/winapi/event.hpp>
#include <boost/winapi/thread.hpp>
#include <boost/winapi/get_current_thread.hpp>
#include <boost/winapi/get_current_thread_id.hpp>
#include <boost/winapi/get_current_process.hpp>
#include <boost/winapi/get_current_process_id.hpp>
#include <boost/winapi/wait.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/access_rights.hpp>
//#include <boost/detail/winapi/synchronization.hpp>
//#include <boost/winapi/synchronization.hpp>
#include <boost/thread/win32/interlocked_read.hpp>
#include <algorithm>
@@ -46,20 +45,19 @@ namespace boost
{
namespace win32
{
typedef ::boost::detail::winapi::HANDLE_ handle;
typedef ::boost::detail::winapi::SYSTEM_INFO_ system_info;
typedef unsigned __int64 ticks_type;
typedef ::boost::detail::winapi::FARPROC_ farproc_t;
unsigned const infinite=::boost::detail::winapi::INFINITE_;
unsigned const timeout=::boost::detail::winapi::WAIT_TIMEOUT_;
handle const invalid_handle_value=::boost::detail::winapi::INVALID_HANDLE_VALUE_;
unsigned const event_modify_state=::boost::detail::winapi::EVENT_MODIFY_STATE_;
unsigned const synchronize=::boost::detail::winapi::SYNCHRONIZE_;
unsigned const wait_abandoned=::boost::detail::winapi::WAIT_ABANDONED_;
typedef ::boost::winapi::HANDLE_ handle;
typedef ::boost::winapi::SYSTEM_INFO_ system_info;
typedef ::boost::winapi::ULONGLONG_ ticks_type;
unsigned const infinite=::boost::winapi::INFINITE_;
unsigned const timeout=::boost::winapi::WAIT_TIMEOUT_;
handle const invalid_handle_value=::boost::winapi::INVALID_HANDLE_VALUE_;
unsigned const event_modify_state=::boost::winapi::EVENT_MODIFY_STATE_;
unsigned const synchronize=::boost::winapi::SYNCHRONIZE_;
unsigned const wait_abandoned=::boost::winapi::WAIT_ABANDONED_;
unsigned const create_event_initial_set = 0x00000002;
unsigned const create_event_manual_reset = 0x00000001;
unsigned const event_all_access = ::boost::detail::winapi::EVENT_ALL_ACCESS_;
unsigned const semaphore_all_access = boost::detail::winapi::SEMAPHORE_ALL_ACCESS_;
unsigned const event_all_access = ::boost::winapi::EVENT_ALL_ACCESS_;
unsigned const semaphore_all_access = boost::winapi::SEMAPHORE_ALL_ACCESS_;
}
}
}
@@ -72,96 +70,8 @@ namespace boost
{
namespace win32
{
namespace detail { typedef ticks_type (__stdcall *gettickcount64_t)(); }
#if !BOOST_PLAT_WINDOWS_RUNTIME
extern "C"
{
#ifdef _MSC_VER
long _InterlockedCompareExchange(long volatile *, long, long);
#pragma intrinsic(_InterlockedCompareExchange)
#elif defined(__MINGW64_VERSION_MAJOR)
long _InterlockedCompareExchange(long volatile *, long, long);
#else
// Mingw doesn't provide intrinsics
#define _InterlockedCompareExchange InterlockedCompareExchange
#endif
}
// Borrowed from https://stackoverflow.com/questions/8211820/userland-interrupt-timer-access-such-as-via-kequeryinterrupttime-or-similar
inline ticks_type __stdcall GetTickCount64emulation()
{
static long count = -1l;
unsigned long previous_count, current_tick32, previous_count_zone, current_tick32_zone;
ticks_type current_tick64;
previous_count = (unsigned long) boost::detail::interlocked_read_acquire(&count);
current_tick32 = ::boost::detail::winapi::GetTickCount();
if(previous_count == (unsigned long)-1l)
{
// count has never been written
unsigned long initial_count;
initial_count = current_tick32 >> 28;
previous_count = (unsigned long) _InterlockedCompareExchange(&count, (long)initial_count, -1l);
current_tick64 = initial_count;
current_tick64 <<= 28;
current_tick64 += current_tick32 & 0x0FFFFFFF;
return current_tick64;
}
previous_count_zone = previous_count & 15;
current_tick32_zone = current_tick32 >> 28;
if(current_tick32_zone == previous_count_zone)
{
// The top four bits of the 32-bit tick count haven't changed since count was last written.
current_tick64 = previous_count;
current_tick64 <<= 28;
current_tick64 += current_tick32 & 0x0FFFFFFF;
return current_tick64;
}
if(current_tick32_zone == previous_count_zone + 1 || (current_tick32_zone == 0 && previous_count_zone == 15))
{
// The top four bits of the 32-bit tick count have been incremented since count was last written.
unsigned long new_count = previous_count + 1;
_InterlockedCompareExchange(&count, (long)new_count, (long)previous_count);
current_tick64 = new_count;
current_tick64 <<= 28;
current_tick64 += current_tick32 & 0x0FFFFFFF;
return current_tick64;
}
// Oops, we weren't called often enough, we're stuck
return 0xFFFFFFFF;
}
#else
#endif
inline detail::gettickcount64_t GetTickCount64_()
{
static detail::gettickcount64_t gettickcount64impl;
if(gettickcount64impl)
return gettickcount64impl;
// GetTickCount and GetModuleHandle are not allowed in the Windows Runtime,
// and kernel32 isn't used in Windows Phone.
#if BOOST_PLAT_WINDOWS_RUNTIME
gettickcount64impl = &::boost::detail::winapi::GetTickCount64;
#else
farproc_t addr=GetProcAddress(
#if !defined(BOOST_NO_ANSI_APIS)
::boost::detail::winapi::GetModuleHandleA("KERNEL32.DLL"),
#else
::boost::detail::winapi::GetModuleHandleW(L"KERNEL32.DLL"),
#endif
"GetTickCount64");
if(addr)
gettickcount64impl=(detail::gettickcount64_t) addr;
else
gettickcount64impl=&GetTickCount64emulation;
#endif
return gettickcount64impl;
}
namespace detail { typedef ticks_type (BOOST_WINAPI_WINAPI_CC *gettickcount64_t)(); }
extern BOOST_THREAD_DECL boost::detail::win32::detail::gettickcount64_t gettickcount64;
enum event_type
{
@@ -185,14 +95,14 @@ namespace boost
initial_event_state state)
{
#if !defined(BOOST_NO_ANSI_APIS)
handle const res = ::boost::detail::winapi::CreateEventA(0, type, state, mutex_name);
handle const res = ::boost::winapi::CreateEventA(0, type, state, mutex_name);
#elif BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA
handle const res = ::boost::detail::winapi::CreateEventW(0, type, state, mutex_name);
handle const res = ::boost::winapi::CreateEventW(0, type, state, mutex_name);
#else
handle const res = ::boost::detail::winapi::CreateEventExW(
handle const res = ::boost::winapi::CreateEventExW(
0,
mutex_name,
type ? create_event_manual_reset : 0 | state ? create_event_initial_set : 0,
(type ? create_event_manual_reset : 0) | (state ? create_event_initial_set : 0),
event_all_access);
#endif
return res;
@@ -211,12 +121,12 @@ namespace boost
inline handle create_anonymous_semaphore_nothrow(long initial_count,long max_count)
{
#if !defined(BOOST_NO_ANSI_APIS)
handle const res=::boost::detail::winapi::CreateSemaphoreA(0,initial_count,max_count,0);
handle const res=::boost::winapi::CreateSemaphoreA(0,initial_count,max_count,0);
#else
#if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA
handle const res=::boost::detail::winapi::CreateSemaphoreEx(0,initial_count,max_count,0,0);
handle const res=::boost::winapi::CreateSemaphoreEx(0,initial_count,max_count,0,0);
#else
handle const res=::boost::detail::winapi::CreateSemaphoreExW(0,initial_count,max_count,0,0,semaphore_all_access);
handle const res=::boost::winapi::CreateSemaphoreExW(0,initial_count,max_count,0,0,semaphore_all_access);
#endif
#endif
return res;
@@ -234,10 +144,10 @@ namespace boost
inline handle duplicate_handle(handle source)
{
handle const current_process=::boost::detail::winapi::GetCurrentProcess();
handle const current_process=::boost::winapi::GetCurrentProcess();
long const same_access_flag=2;
handle new_handle=0;
bool const success=::boost::detail::winapi::DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0;
bool const success=::boost::winapi::DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0;
if(!success)
{
boost::throw_exception(thread_resource_error());
@@ -247,15 +157,15 @@ namespace boost
inline void release_semaphore(handle semaphore,long count)
{
BOOST_VERIFY(::boost::detail::winapi::ReleaseSemaphore(semaphore,count,0)!=0);
BOOST_VERIFY(::boost::winapi::ReleaseSemaphore(semaphore,count,0)!=0);
}
inline void get_system_info(system_info *info)
{
#if BOOST_PLAT_WINDOWS_RUNTIME
::boost::detail::winapi::GetNativeSystemInfo(info);
::boost::winapi::GetNativeSystemInfo(info);
#else
::boost::detail::winapi::GetSystemInfo(info);
::boost::winapi::GetSystemInfo(info);
#endif
}
@@ -266,15 +176,15 @@ namespace boost
#if BOOST_PLAT_WINDOWS_RUNTIME
std::this_thread::yield();
#else
::boost::detail::winapi::Sleep(0);
::boost::winapi::Sleep(0);
#endif
}
else
{
#if BOOST_PLAT_WINDOWS_RUNTIME
::boost::detail::winapi::WaitForSingleObjectEx(::boost::detail::winapi::GetCurrentThread(), milliseconds, 0);
::boost::winapi::WaitForSingleObjectEx(::boost::winapi::GetCurrentThread(), milliseconds, 0);
#else
::boost::detail::winapi::Sleep(milliseconds);
::boost::winapi::Sleep(milliseconds);
#endif
}
}
@@ -290,7 +200,7 @@ namespace boost
{
if (m_completionHandle != ::boost::detail::win32::invalid_handle_value)
{
::boost::detail::winapi::CloseHandle(m_completionHandle);
::boost::winapi::CloseHandle(m_completionHandle);
}
}
@@ -318,7 +228,7 @@ namespace boost
{
if(handle_to_manage && handle_to_manage!=invalid_handle_value)
{
BOOST_VERIFY(::boost::detail::winapi::CloseHandle(handle_to_manage));
BOOST_VERIFY(::boost::winapi::CloseHandle(handle_to_manage));
}
}

View File

@@ -57,17 +57,17 @@ struct xtime
};
inline xtime get_xtime(boost::system_time const& abs_time)
inline ::boost::xtime get_xtime(boost::system_time const& abs_time)
{
xtime res;
::boost::xtime res;
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()));
res.sec=static_cast< ::boost::xtime::xtime_sec_t>(time_since_epoch.total_seconds());
res.nsec=static_cast< ::boost::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)
inline int xtime_get(struct ::boost::xtime* xtp, int clock_type)
{
if (clock_type == TIME_UTC_)
{
@@ -78,7 +78,7 @@ inline int xtime_get(struct xtime* xtp, int clock_type)
}
inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
inline int xtime_cmp(const ::boost::xtime& xt1, const ::boost::xtime& xt2)
{
if (xt1.sec == xt2.sec)
return (int)(xt1.nsec - xt2.nsec);

View File

@@ -7,11 +7,10 @@
"Vicente J. Botet Escriba"
],
"maintainers": [
"Vicente J. Botet Escriba <vicente.botet -at- wanadoo.fr>",
"Niall Douglas <niall -at- nedprod.com>"
"Vicente J. Botet Escriba <vicente.botet -at- wanadoo.fr>"
],
"description":
"Portable C++ multi-threading. C++11, C++14.",
"Portable C++ multi-threading. C++03, C++11, C++14, C++17.",
"std": [ "proposal" ],
"category": [
"Concurrent", "System"

View File

@@ -4,8 +4,8 @@
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/config.hpp>
#ifndef BOOST_NO_EXCEPTIONS
#ifndef BOOST_NO_EXCEPTIONS
#include <boost/thread/futures/future_error_code.hpp>
#include <string>

View File

@@ -8,7 +8,6 @@
#include "./once_atomic.cpp"
#else
#define __STDC_CONSTANT_MACROS
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
#include <boost/thread/once.hpp>
#include <boost/assert.hpp>
#include <boost/throw_exception.hpp>

View File

@@ -7,6 +7,7 @@
//#define __STDC_CONSTANT_MACROS
#include <boost/thread/detail/config.hpp>
#include <boost/thread/once.hpp>
#include <boost/thread/pthread/pthread_helpers.hpp>
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
@@ -57,7 +58,7 @@ namespace boost
{
// Wait until the initialization is complete
//pthread::pthread_mutex_scoped_lock lk(&once_mutex);
BOOST_VERIFY(!pthread_cond_wait(&once_cv, &once_mutex));
BOOST_VERIFY(!posix::pthread_cond_wait(&once_cv, &once_mutex));
}
}
}
@@ -72,7 +73,7 @@ namespace boost
pthread::pthread_mutex_scoped_lock lk(&once_mutex);
f.store(initialized, memory_order_release);
}
BOOST_VERIFY(!pthread_cond_broadcast(&once_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&once_cv));
}
BOOST_THREAD_DECL void rollback_once_region(once_flag& flag) BOOST_NOEXCEPT
@@ -82,7 +83,7 @@ namespace boost
pthread::pthread_mutex_scoped_lock lk(&once_mutex);
f.store(uninitialized, memory_order_release);
}
BOOST_VERIFY(!pthread_cond_broadcast(&once_cv));
BOOST_VERIFY(!posix::pthread_cond_broadcast(&once_cv));
}
} // namespace thread_detail

View File

@@ -17,6 +17,8 @@
#include <boost/thread/once.hpp>
#include <boost/thread/tss.hpp>
#include <boost/thread/future.hpp>
#include <boost/thread/pthread/pthread_helpers.hpp>
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
#ifdef __GLIBC__
#include <sys/sysinfo.h>
@@ -27,6 +29,10 @@
#include <unistd.h>
#endif
#if defined(__VXWORKS__)
#include <vxCpuLib.h>
#endif
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/lexical_cast.hpp>
@@ -49,11 +55,13 @@ namespace boost
i->second->unlock();
i->first->notify_all();
}
//#ifndef BOOST_NO_EXCEPTIONS
for (async_states_t::iterator i = async_states_.begin(), e = async_states_.end();
i != e; ++i)
{
(*i)->notify_deferred();
}
//#endif
}
struct thread_exit_callback_node
@@ -105,7 +113,7 @@ namespace boost
= thread_info->tss_data.begin();
if(current->second.func && (current->second.value!=0))
{
(*current->second.func)(current->second.value);
(*current->second.caller)(current->second.func,current->second.value);
}
thread_info->tss_data.erase(current);
}
@@ -143,7 +151,7 @@ namespace boost
boost::detail::thread_data_base* get_current_thread_data()
{
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
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);
}
@@ -209,8 +217,10 @@ namespace boost
~externally_launched_thread() {
BOOST_ASSERT(notify.empty());
notify.clear();
//#ifndef BOOST_NO_EXCEPTIONS
BOOST_ASSERT(async_states_.empty());
async_states_.clear();
//#endif
}
void run()
{}
@@ -350,7 +360,7 @@ namespace boost
}
}
bool thread::do_try_join_until_noexcept(struct timespec const &timeout, bool& res)
bool thread::do_try_join_until_noexcept(detail::internal_platform_timepoint const &timeout, bool& res)
{
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
if(local_thread_info)
@@ -361,11 +371,12 @@ namespace boost
unique_lock<mutex> lock(local_thread_info->data_mutex);
while(!local_thread_info->done)
{
if(!local_thread_info->done_condition.do_wait_until(lock,timeout))
{
res=false;
return true;
}
if(!local_thread_info->done_condition.do_wait_until(lock,timeout)) break; // timeout occurred
}
if(!local_thread_info->done)
{
res=false;
return true;
}
do_join=!local_thread_info->join_started;
@@ -432,99 +443,28 @@ namespace boost
{
namespace hidden
{
void BOOST_THREAD_DECL sleep_for(const timespec& ts)
void BOOST_THREAD_DECL sleep_for_internal(const detail::platform_duration& ts)
{
if (boost::detail::timespec_ge(ts, boost::detail::timespec_zero()))
if (ts > detail::platform_duration::zero())
{
// Use pthread_delay_np or nanosleep whenever possible here in the no_interruption_point
// namespace because they do not provide an interruption point.
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
# if defined(__IBMCPP__) || defined(_AIX)
BOOST_VERIFY(!pthread_delay_np(const_cast<timespec*>(&ts)));
BOOST_VERIFY(!pthread_delay_np(const_cast<timespec*>(&ts.getTs())));
# else
BOOST_VERIFY(!pthread_delay_np(&ts));
BOOST_VERIFY(!pthread_delay_np(&ts.getTs()));
# endif
# elif defined(BOOST_HAS_NANOSLEEP)
// nanosleep takes a timespec that is an offset, not
// an absolute time.
nanosleep(&ts, 0);
nanosleep(&ts.getTs(), 0);
# else
mutex mx;
unique_lock<mutex> lock(mx);
condition_variable cond;
cond.do_wait_for(lock, ts);
// This should never be reached due to BOOST_THREAD_SLEEP_FOR_IS_STEADY
# endif
}
}
void BOOST_THREAD_DECL sleep_until_realtime(const timespec& ts)
{
timespec now = boost::detail::timespec_now_realtime();
if (boost::detail::timespec_gt(ts, now))
{
for (int foo=0; foo < 5; ++foo)
{
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
timespec d = boost::detail::timespec_minus(ts, now);
BOOST_VERIFY(!pthread_delay_np(&d));
# elif defined(BOOST_HAS_NANOSLEEP)
// nanosleep takes a timespec that is an offset, not
// an absolute time.
timespec d = boost::detail::timespec_minus(ts, now);
nanosleep(&d, 0);
# else
mutex mx;
unique_lock<mutex> lock(mx);
condition_variable cond;
cond.do_wait_until(lock, ts);
# endif
timespec now2 = boost::detail::timespec_now_realtime();
if (boost::detail::timespec_ge(now2, ts))
{
return;
}
}
}
}
}
}
namespace hidden
{
void BOOST_THREAD_DECL sleep_for(const timespec& ts)
{
boost::detail::thread_data_base* const thread_info=boost::detail::get_current_thread_data();
if(thread_info)
{
unique_lock<mutex> lk(thread_info->sleep_mutex);
while( thread_info->sleep_condition.do_wait_for(lk,ts)) {}
}
else
{
boost::this_thread::no_interruption_point::hidden::sleep_for(ts);
}
}
void BOOST_THREAD_DECL sleep_until_realtime(const timespec& ts)
{
boost::detail::thread_data_base* const thread_info=boost::detail::get_current_thread_data();
if(thread_info)
{
unique_lock<mutex> lk(thread_info->sleep_mutex);
while(thread_info->sleep_condition.do_wait_until(lk,ts)) {}
}
else
{
boost::this_thread::no_interruption_point::hidden::sleep_until_realtime(ts);
}
}
} // hidden
} // this_thread
namespace this_thread
{
void yield() BOOST_NOEXCEPT
{
# if defined(BOOST_HAS_SCHED_YIELD)
@@ -532,16 +472,15 @@ namespace boost
# elif defined(BOOST_HAS_PTHREAD_YIELD)
BOOST_VERIFY(!pthread_yield());
//# elif defined BOOST_THREAD_USES_DATETIME
// xtime xt;
// ::boost::xtime xt;
// xtime_get(&xt, TIME_UTC_);
// sleep(xt);
// sleep_for(chrono::milliseconds(0));
# else
#error
timespec ts;
ts.tv_sec= 0;
ts.tv_nsec= 0;
hidden::sleep_for(ts);
mutex mx;
unique_lock<mutex> lock(mx);
condition_variable cond;
cond.do_wait_until(lock, detail::internal_platform_clock::now());
# endif
}
}
@@ -556,6 +495,18 @@ namespace boost
#elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN)
int const count=sysconf(_SC_NPROCESSORS_ONLN);
return (count>0)?count:0;
#elif defined(__VXWORKS__)
cpuset_t set = ::vxCpuEnabledGet();
#ifdef __DCC__
int i;
for( i = 0; set; ++i)
{
set &= set -1;
}
return(i);
#else
return (__builtin_popcount(set) );
#endif
#elif defined(__GLIBC__)
return get_nprocs();
#else
@@ -632,7 +583,7 @@ namespace boost
if(local_thread_info->current_cond)
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(local_thread_info->cond_mutex);
BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info->current_cond));
BOOST_VERIFY(!posix::pthread_cond_broadcast(local_thread_info->current_cond));
}
}
}
@@ -777,11 +728,12 @@ namespace boost
}
void add_new_tss_node(void const* key,
boost::shared_ptr<tss_cleanup_function> func,
detail::tss_data_node::cleanup_caller_t caller,
detail::tss_data_node::cleanup_func_t func,
void* tss_data)
{
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(func,tss_data)));
current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(caller,func,tss_data)));
}
void erase_tss_node(void const* key)
@@ -794,17 +746,19 @@ namespace boost
}
void set_tss_data(void const* key,
boost::shared_ptr<tss_cleanup_function> func,
detail::tss_data_node::cleanup_caller_t caller,
detail::tss_data_node::cleanup_func_t 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->value!=0))
{
(*current_node->func)(current_node->value);
(*current_node->caller)(current_node->func,current_node->value);
}
if(func || (tss_data!=0))
{
current_node->caller=caller;
current_node->func=func;
current_node->value=tss_data;
}
@@ -815,7 +769,7 @@ namespace boost
}
else if(func || (tss_data!=0))
{
add_new_tss_node(key,func,tss_data);
add_new_tss_node(key,caller,func,tss_data);
}
}
}
@@ -828,6 +782,8 @@ namespace boost
current_thread_data->notify_all_at_thread_exit(&cond, lk.release());
}
}
//#ifndef BOOST_NO_EXCEPTIONS
namespace detail {
void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
@@ -839,7 +795,7 @@ namespace detail {
}
}
}
//#endif
}

View File

@@ -6,7 +6,7 @@
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_WINTHREADS) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST) || defined(UNDER_CE)) && (!defined(_MSC_VER) || defined(UNDER_CE))
#if defined(BOOST_THREAD_WIN32) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST) || defined(UNDER_CE)) && (!defined(_MSC_VER) || defined(UNDER_CE))
namespace boost
{
@@ -35,4 +35,4 @@ namespace boost
}
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) && !defined(_MSC_VER)
#endif //defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_LIB) && !defined(_MSC_VER)

View File

@@ -3,11 +3,11 @@
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2007 David Deakins
// (C) Copyright 2011-2017 Vicente J. Botet Escriba
// (C) Copyright 2011-2018 Vicente J. Botet Escriba
//#define BOOST_THREAD_VERSION 3
#include <boost/detail/winapi/config.hpp>
#include <boost/winapi/config.hpp>
#include <boost/thread/thread_only.hpp>
#include <boost/thread/once.hpp>
#include <boost/thread/tss.hpp>
@@ -54,11 +54,13 @@ namespace boost
i->second->unlock();
i->first->notify_all();
}
//#ifndef BOOST_NO_EXCEPTIONS
for (async_states_t::iterator i = async_states_.begin(), e = async_states_.end();
i != e; ++i)
{
(*i)->notify_deferred();
}
//#endif
}
}
@@ -274,7 +276,7 @@ namespace boost
= current_thread_data->tss_data.begin();
if(current->second.func && (current->second.value!=0))
{
(*current->second.func)(current->second.value);
(*current->second.caller)(current->second.func,current->second.value);
}
current_thread_data->tss_data.erase(current);
}
@@ -370,8 +372,10 @@ namespace boost
~externally_launched_thread() {
BOOST_ASSERT(notify.empty());
notify.clear();
//#ifndef BOOST_NO_EXCEPTIONS
BOOST_ASSERT(async_states_.empty());
async_states_.clear();
//#endif
}
void run()
@@ -439,7 +443,7 @@ namespace boost
detail::thread_data_ptr local_thread_info=(get_thread_info)();
if(local_thread_info)
{
this_thread::interruptible_wait(this->native_handle(),detail::timeout::sentinel());
this_thread::interruptible_wait(this->native_handle(), detail::internal_platform_timepoint::getMax());
release_handle();
return true;
}
@@ -449,18 +453,12 @@ namespace boost
}
}
#if defined BOOST_THREAD_USES_DATETIME
bool thread::timed_join(boost::system_time const& wait_until)
{
return do_try_join_until(boost::detail::get_milliseconds_until(wait_until));
}
#endif
bool thread::do_try_join_until_noexcept(uintmax_t milli, bool& res)
bool thread::do_try_join_until_noexcept(detail::internal_platform_timepoint const &timeout, bool& res)
{
detail::thread_data_ptr local_thread_info=(get_thread_info)();
if(local_thread_info)
{
if(!this_thread::interruptible_wait(this->native_handle(),milli))
if(!this_thread::interruptible_wait(this->native_handle(), timeout))
{
res=false;
return true;
@@ -498,7 +496,7 @@ namespace boost
bool thread::interruption_requested() const BOOST_NOEXCEPT
{
detail::thread_data_ptr local_thread_info=(get_thread_info)();
return local_thread_info.get() && (detail::winapi::WaitForSingleObjectEx(local_thread_info->interruption_handle,0,0)==0);
return local_thread_info.get() && (winapi::WaitForSingleObjectEx(local_thread_info->interruption_handle,0,0)==0);
}
#endif
@@ -524,12 +522,12 @@ namespace boost
GetLogicalProcessorInformation(NULL, &size);
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
return 0;
const size_t Elements = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(size);
std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(Elements);
if (GetLogicalProcessorInformation(&buffer.front(), &size) == FALSE)
return 0;
const size_t Elements = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
for (size_t i = 0; i < Elements; ++i) {
if (buffer[i].Relationship == RelationProcessorCore)
@@ -561,62 +559,6 @@ namespace boost
namespace this_thread
{
namespace
{
LARGE_INTEGER get_due_time(detail::timeout const& target_time)
{
LARGE_INTEGER due_time={{0,0}};
if(target_time.relative)
{
detail::win32::ticks_type const elapsed_milliseconds=detail::win32::GetTickCount64_()()-target_time.start;
LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds);
LONGLONG const hundred_nanoseconds_in_one_millisecond=10000;
if(remaining_milliseconds>0)
{
due_time.QuadPart=-(remaining_milliseconds*hundred_nanoseconds_in_one_millisecond);
}
}
else
{
SYSTEMTIME target_system_time={0,0,0,0,0,0,0,0};
target_system_time.wYear=target_time.abs_time.date().year();
target_system_time.wMonth=target_time.abs_time.date().month();
target_system_time.wDay=target_time.abs_time.date().day();
target_system_time.wHour=(WORD)target_time.abs_time.time_of_day().hours();
target_system_time.wMinute=(WORD)target_time.abs_time.time_of_day().minutes();
target_system_time.wSecond=(WORD)target_time.abs_time.time_of_day().seconds();
if(!SystemTimeToFileTime(&target_system_time,((FILETIME*)&due_time)))
{
due_time.QuadPart=0;
}
else
{
long const hundred_nanoseconds_in_one_second=10000000;
posix_time::time_duration::tick_type const ticks_per_second=
target_time.abs_time.time_of_day().ticks_per_second();
if(ticks_per_second>hundred_nanoseconds_in_one_second)
{
posix_time::time_duration::tick_type const
ticks_per_hundred_nanoseconds=
ticks_per_second/hundred_nanoseconds_in_one_second;
due_time.QuadPart+=
target_time.abs_time.time_of_day().fractional_seconds()/
ticks_per_hundred_nanoseconds;
}
else
{
due_time.QuadPart+=
target_time.abs_time.time_of_day().fractional_seconds()*
(hundred_nanoseconds_in_one_second/ticks_per_second);
}
}
}
return due_time;
}
}
#ifndef UNDER_CE
#if !BOOST_PLAT_WINDOWS_RUNTIME
namespace detail_
@@ -667,7 +609,7 @@ namespace boost
}
#endif
#endif
bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
bool interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout)
{
detail::win32::handle handles[4]={0};
unsigned handle_count=0;
@@ -693,16 +635,20 @@ namespace boost
#ifndef UNDER_CE
#if !BOOST_PLAT_WINDOWS_RUNTIME
// Preferentially use coalescing timers for better power consumption and timer accuracy
if(!target_time.is_sentinel())
if(timeout != detail::internal_platform_timepoint::getMax())
{
detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
boost::intmax_t const time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
timer_handle=CreateWaitableTimer(NULL,false,NULL);
if(timer_handle!=0)
{
ULONG tolerable=32; // Empirical testing shows Windows ignores this when <= 26
if(time_left.milliseconds/20>tolerable) // 5%
tolerable=time_left.milliseconds/20;
LARGE_INTEGER due_time=get_due_time(target_time);
if(time_left_msec/20>tolerable) // 5%
tolerable=static_cast<ULONG>(time_left_msec/20);
LARGE_INTEGER due_time={{0,0}};
if(time_left_msec>0)
{
due_time.QuadPart=-(time_left_msec*10000); // negative indicates relative time
}
bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,NULL,tolerable)!=0;
if(set_time_succeeded)
{
@@ -715,18 +661,21 @@ namespace boost
#endif
bool const using_timer=timeout_index!=~0u;
detail::timeout::remaining_time time_left(0);
boost::intmax_t time_left_msec(INFINITE);
if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
{
time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
if(time_left_msec < 0)
{
time_left_msec = 0;
}
}
do
{
if(!using_timer)
{
time_left=target_time.remaining_milliseconds();
}
if(handle_count)
{
unsigned long const notified_index=detail::winapi::WaitForMultipleObjectsEx(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds, 0);
unsigned long const notified_index=winapi::WaitForMultipleObjectsEx(handle_count,handles,false,static_cast<DWORD>(time_left_msec), 0);
if(notified_index<handle_count)
{
if(notified_index==wait_handle_index)
@@ -736,7 +685,7 @@ namespace boost
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
else if(notified_index==interruption_index)
{
detail::winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle);
winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle);
throw thread_interrupted();
}
#endif
@@ -748,20 +697,21 @@ namespace boost
}
else
{
detail::win32::sleep(time_left.milliseconds);
detail::win32::sleep(static_cast<unsigned long>(time_left_msec));
}
if(target_time.relative)
if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
{
target_time.milliseconds-=detail::timeout::max_non_infinite_wait;
time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
}
}
while(time_left.more);
while(time_left_msec == INFINITE || time_left_msec > 0);
return false;
}
namespace no_interruption_point
{
bool non_interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
bool non_interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout)
{
detail::win32::handle handles[3]={0};
unsigned handle_count=0;
@@ -777,16 +727,20 @@ namespace boost
#ifndef UNDER_CE
#if !BOOST_PLAT_WINDOWS_RUNTIME
// Preferentially use coalescing timers for better power consumption and timer accuracy
if(!target_time.is_sentinel())
if(timeout != detail::internal_platform_timepoint::getMax())
{
detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
boost::intmax_t const time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
timer_handle=CreateWaitableTimer(NULL,false,NULL);
if(timer_handle!=0)
{
ULONG tolerable=32; // Empirical testing shows Windows ignores this when <= 26
if(time_left.milliseconds/20>tolerable) // 5%
tolerable=time_left.milliseconds/20;
LARGE_INTEGER due_time=get_due_time(target_time);
if(time_left_msec/20>tolerable) // 5%
tolerable=static_cast<ULONG>(time_left_msec/20);
LARGE_INTEGER due_time={{0,0}};
if(time_left_msec>0)
{
due_time.QuadPart=-(time_left_msec*10000); // negative indicates relative time
}
bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,NULL,tolerable)!=0;
if(set_time_succeeded)
{
@@ -799,18 +753,21 @@ namespace boost
#endif
bool const using_timer=timeout_index!=~0u;
detail::timeout::remaining_time time_left(0);
boost::intmax_t time_left_msec(INFINITE);
if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
{
time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
if(time_left_msec < 0)
{
time_left_msec = 0;
}
}
do
{
if(!using_timer)
{
time_left=target_time.remaining_milliseconds();
}
if(handle_count)
{
unsigned long const notified_index=detail::winapi::WaitForMultipleObjectsEx(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds, 0);
unsigned long const notified_index=winapi::WaitForMultipleObjectsEx(handle_count,handles,false,static_cast<DWORD>(time_left_msec), 0);
if(notified_index<handle_count)
{
if(notified_index==wait_handle_index)
@@ -825,14 +782,15 @@ namespace boost
}
else
{
detail::win32::sleep(time_left.milliseconds);
detail::win32::sleep(static_cast<unsigned long>(time_left_msec));
}
if(target_time.relative)
if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
{
target_time.milliseconds-=detail::timeout::max_non_infinite_wait;
time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
}
}
while(time_left.more);
while(time_left_msec == INFINITE || time_left_msec > 0);
return false;
}
}
@@ -847,7 +805,7 @@ namespace boost
return current_thread_data->id;
}
#endif
return detail::winapi::GetCurrentThreadId();
return winapi::GetCurrentThreadId();
#else
return thread::id(get_or_make_current_thread_data());
#endif
@@ -858,7 +816,7 @@ namespace boost
{
if(interruption_enabled() && interruption_requested())
{
detail::winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle);
winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle);
throw thread_interrupted();
}
}
@@ -870,7 +828,7 @@ namespace boost
bool interruption_requested() BOOST_NOEXCEPT
{
return detail::get_current_thread_data() && (detail::winapi::WaitForSingleObjectEx(detail::get_current_thread_data()->interruption_handle,0,0)==0);
return detail::get_current_thread_data() && (winapi::WaitForSingleObjectEx(detail::get_current_thread_data()->interruption_handle,0,0)==0);
}
#endif
@@ -951,11 +909,12 @@ namespace boost
}
void add_new_tss_node(void const* key,
boost::shared_ptr<tss_cleanup_function> func,
detail::tss_data_node::cleanup_caller_t caller,
detail::tss_data_node::cleanup_func_t func,
void* tss_data)
{
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(func,tss_data)));
current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(caller,func,tss_data)));
}
void erase_tss_node(void const* key)
@@ -965,17 +924,19 @@ namespace boost
}
void set_tss_data(void const* key,
boost::shared_ptr<tss_cleanup_function> func,
detail::tss_data_node::cleanup_caller_t caller,
detail::tss_data_node::cleanup_func_t 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->value!=0))
{
(*current_node->func)(current_node->value);
(*current_node->caller)(current_node->func,current_node->value);
}
if(func || (tss_data!=0))
{
current_node->caller=caller;
current_node->func=func;
current_node->value=tss_data;
}
@@ -986,7 +947,7 @@ namespace boost
}
else if(func || (tss_data!=0))
{
add_new_tss_node(key,func,tss_data);
add_new_tss_node(key,caller,func,tss_data);
}
}
}

View File

@@ -0,0 +1,156 @@
// thread_primitives.cpp
//
// (C) Copyright 2018 Andrey Semashev
//
// 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/winapi/config.hpp>
#include <boost/winapi/dll.hpp>
#include <boost/winapi/time.hpp>
#include <boost/winapi/event.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/thread_pool.hpp>
#include <cstdlib>
#include <boost/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/memory_order.hpp>
#include <boost/atomic/atomic.hpp>
#include <boost/thread/win32/interlocked_read.hpp>
#include <boost/thread/win32/thread_primitives.hpp>
namespace boost {
namespace detail {
namespace win32 {
#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
// Directly use API from Vista and later
BOOST_THREAD_DECL boost::detail::win32::detail::gettickcount64_t gettickcount64 = &::boost::winapi::GetTickCount64;
#else // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
namespace {
enum init_state
{
uninitialized = 0,
in_progress,
initialized
};
struct get_tick_count64_state
{
boost::atomic< uint64_t > ticks;
boost::atomic< init_state > init;
boost::winapi::HANDLE_ wait_event;
boost::winapi::HANDLE_ wait_handle;
};
// Zero-initialized initially
BOOST_ALIGNMENT(64) static get_tick_count64_state g_state;
//! Artifical implementation of GetTickCount64
ticks_type WINAPI get_tick_count64()
{
uint64_t old_state = g_state.ticks.load(boost::memory_order_acquire);
uint32_t new_ticks = boost::winapi::GetTickCount();
uint32_t old_ticks = static_cast< uint32_t >(old_state & UINT64_C(0x00000000ffffffff));
uint64_t new_state = ((old_state & UINT64_C(0xffffffff00000000)) + (static_cast< uint64_t >(new_ticks < old_ticks) << 32)) | static_cast< uint64_t >(new_ticks);
g_state.ticks.store(new_state, boost::memory_order_release);
return new_state;
}
//! The function is called periodically in the system thread pool to make sure g_state.ticks is timely updated
void NTAPI refresh_get_tick_count64(boost::winapi::PVOID_, boost::winapi::BOOLEAN_)
{
get_tick_count64();
}
//! Cleanup function to stop get_tick_count64 refreshes
void cleanup_get_tick_count64()
{
if (g_state.wait_handle)
{
boost::winapi::UnregisterWait(g_state.wait_handle);
g_state.wait_handle = NULL;
}
if (g_state.wait_event)
{
boost::winapi::CloseHandle(g_state.wait_event);
g_state.wait_event = NULL;
}
}
ticks_type WINAPI get_tick_count_init()
{
boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll");
if (hKernel32)
{
// GetProcAddress returns a pointer to some function. It can return
// pointers to different functions, so it has to return something that is
// suitable to store any pointer to function. Microsoft chose FARPROC,
// which is int (WINAPI *)() on 32-bit Windows. The user is supposed to
// know the signature of the function he requests and perform a cast
// (which is a nop on this platform). The result is a pointer to function
// with the required signature, which is bitwise equal to what
// GetProcAddress returned.
// However, gcc >= 8 warns about that.
#if defined(BOOST_GCC) && BOOST_GCC >= 80000
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
#endif
boost::detail::win32::detail::gettickcount64_t p =
(boost::detail::win32::detail::gettickcount64_t)boost::winapi::get_proc_address(hKernel32, "GetTickCount64");
#if defined(BOOST_GCC) && BOOST_GCC >= 80000
#pragma GCC diagnostic pop
#endif
if (p)
{
// Use native API
boost::detail::interlocked_write_release((void**)&gettickcount64, (void*)p);
return p();
}
}
// No native API available. Use emulation with periodic refreshes to make sure the GetTickCount wrap arounds are properly counted.
init_state old_init = uninitialized;
if (g_state.init.compare_exchange_strong(old_init, in_progress, boost::memory_order_acq_rel, boost::memory_order_relaxed))
{
if (!g_state.wait_event)
g_state.wait_event = boost::winapi::create_anonymous_event(NULL, false, false);
if (g_state.wait_event)
{
boost::winapi::BOOL_ res = boost::winapi::RegisterWaitForSingleObject(&g_state.wait_handle, g_state.wait_event, &refresh_get_tick_count64, NULL, 0x7fffffff, boost::winapi::WT_EXECUTEINWAITTHREAD_);
if (res)
{
std::atexit(&cleanup_get_tick_count64);
boost::detail::interlocked_write_release((void**)&gettickcount64, (void*)&get_tick_count64);
g_state.init.store(initialized, boost::memory_order_release);
goto finish;
}
}
g_state.init.store(uninitialized, boost::memory_order_release);
}
finish:
return get_tick_count64();
}
} // namespace
BOOST_THREAD_DECL boost::detail::win32::detail::gettickcount64_t gettickcount64 = &get_tick_count_init;
#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
} // namespace win32
} // namespace detail
} // namespace boost

View File

@@ -3,11 +3,11 @@
// 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/detail/winapi/config.hpp>
#include <boost/winapi/config.hpp>
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
#if defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_DLL)
#include <boost/thread/detail/tss_hooks.hpp>
@@ -73,7 +73,7 @@ namespace boost
}
}
#else //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
#else //defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_DLL)
#ifdef _MSC_VER
// Prevent LNK4221 warning with link=static
@@ -82,4 +82,4 @@ namespace boost { namespace link_static_warning_inhibit {
} }
#endif
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
#endif //defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_DLL)

View File

@@ -7,10 +7,10 @@
// 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/detail/winapi/config.hpp>
#include <boost/winapi/config.hpp>
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
#if defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_LIB)
#if (defined(__MINGW32__) && !defined(_WIN64)) || defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR)
@@ -98,11 +98,11 @@ extern BOOL (WINAPI * const _pRawDllMainOrig)(HINSTANCE, DWORD, LPVOID);
extern BOOL (WINAPI * const _pDefaultRawDllMainOrig)(HINSTANCE, DWORD, LPVOID) = NULL;
#if defined (_M_IX86)
#pragma comment(linker, "/alternatename:__pRawDllMainOrig=__pDefaultRawDllMainOrig")
#elif defined (_M_X64) || defined (_M_ARM)
#elif defined (_M_X64) || defined (_M_ARM) || defined (_M_ARM64)
#pragma comment(linker, "/alternatename:_pRawDllMainOrig=_pDefaultRawDllMainOrig")
#else /* defined (_M_X64) || defined (_M_ARM) */
#else /* unknown Windows target (not x86, x64, ARM, ARM64) */
#error Unsupported platform
#endif /* defined (_M_X64) || defined (_M_ARM) */
#endif /* defined (_M_X64) || defined (_M_ARM) || defined (_M_ARM64) */
}
#endif
@@ -334,4 +334,4 @@ namespace boost
#endif //defined(_MSC_VER) && !defined(UNDER_CE)
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
#endif //defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_LIB)

View File

@@ -18,6 +18,9 @@
# bring in rules for testing
import testing ;
import regex ;
import path ;
import os ;
project
: requirements
@@ -180,7 +183,6 @@ rule thread-run2-h ( sources : name )
sources = $(sources) winrt_init.cpp ;
return
[ run $(sources) : : :
<library>/boost/system//boost_system
<define>BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
<define>BOOST_THREAD_VERSION=3
: $(name)_h ]
@@ -208,6 +210,36 @@ rule thread-compile-fail ( sources : reqs * : name )
;
}
rule clang-thread-safety ( properties * )
{
if <toolset>clang in $(properties)
{
return <cxxflags>-Werror=thread-safety <define>BOOST_THREAD_ENABLE_THREAD_SAFETY_ANALYSIS ;
}
else
{
return <build>no ;
}
}
rule thread-safety-compile ( sources : reqs * : name )
{
return
[ compile $(sources)
: $(reqs) <conditional>@clang-thread-safety
: $(name) ]
;
}
rule thread-safety-compile-fail ( sources : reqs * : name )
{
return
[ compile-fail $(sources)
: $(reqs) <conditional>@clang-thread-safety
: $(name) ]
;
}
rule thread-compile ( sources : reqs * : name )
{
return
@@ -217,6 +249,42 @@ rule thread-compile ( sources : reqs * : name )
;
}
rule windows-cygwin-specific ( properties * )
{
if <target-os>windows in $(properties) || <target-os>cygwin in $(properties)
{
return <build>yes ;
}
else
{
return <build>no ;
}
}
rule generate_self_contained_header_tests
{
local all_rules ;
local file ;
if ! [ os.environ BOOST_THREAD_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS ]
{
local headers_path = [ path.make $(BOOST_ROOT)/libs/thread/include/boost/thread ] ;
for file in [ path.glob-tree $(headers_path) : *.hpp : detail pthread win32 ]
{
local rel_file = [ path.relative-to $(headers_path) $(file) ] ;
# Note: The test name starts with '~' in order to group these tests in the test report table, preferably at the end.
# All '/' are replaced with '-' because apparently test scripts have a problem with test names containing slashes.
local test_name = [ regex.replace ~hdr/$(rel_file) "/" "-" ] ;
#ECHO $(rel_file) ;
all_rules += [ compile self_contained_header.cpp : <define>"BOOST_THREAD_TEST_HEADER=$(rel_file)" <dependency>$(file) : $(test_name) ] ;
all_rules += [ compile self_contained_header.cpp : <define>"BOOST_THREAD_TEST_HEADER=$(rel_file)" <define>"BOOST_THREAD_TEST_POST_WINDOWS_H" <dependency>$(file) <conditional>@windows-cygwin-specific : $(test_name)-post_winh ] ;
}
}
#ECHO All rules: $(all_rules) ;
return $(all_rules) ;
}
{
test-suite t_threads
:
@@ -266,8 +334,8 @@ rule thread-compile ( sources : reqs * : name )
#[ thread-test test_vhh_shared_mutex_timed_locks.cpp ]
;
#explicit t_futures ;
test-suite t_futures
explicit t_futures_too_long ;
test-suite t_futures_too_long
:
[ thread-test test_futures.cpp ]
;
@@ -325,6 +393,7 @@ rule thread-compile ( sources : reqs * : name )
[ thread-run2-noit ./sync/conditions/condition_variable/wait_for_pred_pass.cpp : condition_variable__wait_for_pred_p ]
[ thread-run2-noit ./sync/conditions/condition_variable/wait_until_pass.cpp : condition_variable__wait_until_p ]
[ thread-run2-noit ./sync/conditions/condition_variable/wait_until_pred_pass.cpp : condition_variable__wait_until_pred_p ]
[ thread-run2-noit ./sync/conditions/condition_variable/lost_notif_pass.cpp : condition_variable__lost_notif_p ]
[ thread-compile-fail ./sync/conditions/condition_variable_any/assign_fail.cpp : : condition_variable_any__assign_f ]
[ thread-compile-fail ./sync/conditions/condition_variable_any/copy_fail.cpp : : condition_variable_any__copy_f ]
@@ -334,6 +403,7 @@ rule thread-compile ( sources : reqs * : name )
[ thread-run2-noit ./sync/conditions/condition_variable_any/wait_for_pred_pass.cpp : condition_variable_any__wait_for_pred_p ]
[ thread-run2-noit ./sync/conditions/condition_variable_any/wait_until_pass.cpp : condition_variable_any__wait_until_p ]
[ thread-run2-noit ./sync/conditions/condition_variable_any/wait_until_pred_pass.cpp : condition_variable_any__wait_until_pred_p ]
[ thread-run2-noit ./sync/conditions/condition_variable_any/lost_notif_pass.cpp : condition_variable_any__lost_notif_p ]
[ thread-run2-noit ./sync/conditions/cv_status/cv_status_pass.cpp : cv_status__cv_status_p ]
[ thread-run2-noit ./sync/conditions/notify_all_at_thread_exit_pass.cpp : notify_all_at_thread_exit_p ]
;
@@ -459,6 +529,10 @@ rule thread-compile ( sources : reqs * : name )
:
[ thread-compile-fail ./sync/mutual_exclusion/locks/lock_guard/copy_assign_fail.cpp : : lock_guard__cons__copy_assign_f ]
[ thread-compile-fail ./sync/mutual_exclusion/locks/lock_guard/copy_ctor_fail.cpp : : lock_guard__cons__copy_ctor_f ]
[ thread-safety-compile ./sync/mutual_exclusion/locks/lock_guard/lock_guard_compile_pass.cpp : : lock_guard__lock_compile_p ]
[ thread-safety-compile-fail ./sync/mutual_exclusion/locks/lock_guard/lock_guard_compile_fail.cpp : : lock_guard__lock_compile_f ]
[ thread-safety-compile ./sync/mutual_exclusion/locks/lock_guard/lock_guard_adopt_lock_compile_pass.cpp : : lock_guard__adopt_lock_compile_p ]
[ thread-safety-compile-fail ./sync/mutual_exclusion/locks/lock_guard/lock_guard_adopt_lock_compile_fail.cpp : : lock_guard__adopt_lock_compile_f ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/lock_guard/adopt_lock_pass.cpp : lock_guard__cons__adopt_lock_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/lock_guard/default_pass.cpp : lock_guard__cons__default_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/lock_guard/types_pass.cpp : lock_guard__types_p ]
@@ -613,6 +687,12 @@ rule thread-compile ( sources : reqs * : name )
:
[ thread-compile-fail ./sync/mutual_exclusion/mutex/assign_fail.cpp : : mutex__assign_f ]
[ thread-compile-fail ./sync/mutual_exclusion/mutex/copy_fail.cpp : : mutex__copy_f ]
[ thread-safety-compile ./sync/mutual_exclusion/mutex/lock_compile_pass.cpp : : mutex__lock_compile_p ]
[ thread-safety-compile-fail ./sync/mutual_exclusion/mutex/lock_compile_fail.cpp : : mutex__lock_compile_f ]
# https://bugs.llvm.org/show_bug.cgi?id=32954
# http://clang-developers.42468.n3.nabble.com/thread-safety-warnings-specifically-try-acquire-capability-td4059337.html
#[ thread-safety-compile ./sync/mutual_exclusion/mutex/try_lock_compile_pass.cpp : : mutex__try_lock_compile_p ]
[ thread-safety-compile-fail ./sync/mutual_exclusion/mutex/try_lock_compile_fail.cpp : : mutex__try_lock_compile_f ]
[ thread-run2-noit ./sync/mutual_exclusion/mutex/default_pass.cpp : mutex__default_p ]
[ thread-run2-noit ./sync/mutual_exclusion/mutex/lock_pass.cpp : mutex__lock_p ]
[ thread-run2-noit-pthread ./sync/mutual_exclusion/mutex/native_handle_pass.cpp : mutex__native_handle_p ]
@@ -709,7 +789,7 @@ rule thread-compile ( sources : reqs * : name )
test-suite ts_sync_tq
:
[ thread-run2-noit ./sync/mutual_exclusion/sync_pq/tq_single_thread_pass.cpp : sync_tq_single_thread_p ]
#[ thread-run2-noit ./sync/mutual_exclusion/sync_pq/tq_multi_thread_pass.cpp : sync_tq_multi_thread_p ]
[ thread-run2-noit ./sync/mutual_exclusion/sync_pq/tq_multi_thread_pass.cpp : sync_tq_multi_thread_p ]
;
test-suite ts_scheduler
@@ -773,6 +853,12 @@ rule thread-compile ( sources : reqs * : name )
[ thread-run2-noit ./threads/container/thread_ptr_list_pass.cpp : container__thread_ptr_list_p ]
;
explicit ts_examples_too_long ;
test-suite ts_examples_too_long
:
[ thread-run2 ../example/shared_mutex.cpp : ex_shared_mutex ]
;
#explicit ts_examples ;
test-suite ts_examples
:
@@ -788,7 +874,6 @@ rule thread-compile ( sources : reqs * : name )
[ thread-run2-noit ../example/tss.cpp : ex_tss ]
[ thread-run2 ../example/xtime.cpp : ex_xtime ]
[ thread-run2 ../example/shared_monitor.cpp : ex_shared_monitor ]
[ thread-run2 ../example/shared_mutex.cpp : ex_shared_mutex ]
#[ thread-run ../example/vhh_shared_monitor.cpp ]
#[ thread-run ../example/vhh_shared_mutex.cpp ]
[ thread-run2 ../example/make_future.cpp : ex_make_future ]
@@ -968,9 +1053,46 @@ rule thread-compile ( sources : reqs * : name )
#[ thread-run test_11818.cpp ]
#[ thread-run test_11796.cpp ]
#[ thread-run test_12293.cpp ]
[ thread-run test_12949.cpp ]
#[ thread-run test_12949.cpp ]
#[ thread-run test_13480b.cpp ]
[ thread-run test_13561.cpp ]
;
explicit test_time_jumps_1_obj ;
obj test_time_jumps_1_obj : test_time_jumps.cpp :
# BOOST_THREAD_USES_MOVE is required to prevent ambiguity between the two definitions
# of boost::move when using sync_priority_queue/sync_timed_queue with POD data types.
<define>BOOST_THREAD_USES_MOVE
<define>BOOST_THREAD_PROVIDES_FUTURE
;
explicit test_time_jumps_2_obj ;
obj test_time_jumps_2_obj : test_time_jumps.cpp :
# BOOST_THREAD_USES_MOVE is required to prevent ambiguity between the two definitions
# of boost::move when using sync_priority_queue/sync_timed_queue with POD data types.
<define>BOOST_THREAD_USES_MOVE
<define>BOOST_THREAD_PROVIDES_FUTURE
<define>BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
;
explicit test_time_jumps_3_obj ;
obj test_time_jumps_3_obj : test_time_jumps.cpp :
# BOOST_THREAD_USES_MOVE is required to prevent ambiguity between the two definitions
# of boost::move when using sync_priority_queue/sync_timed_queue with POD data types.
<define>BOOST_THREAD_USES_MOVE
<define>BOOST_THREAD_PROVIDES_FUTURE
<define>BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
<define>BOOST_THREAD_V2_SHARED_MUTEX
;
explicit test_time_jumps ;
test-suite test_time_jumps
:
[ exe test_time_jumps_1 : test_time_jumps_1_obj ../build//boost_thread ]
[ exe test_time_jumps_2 : test_time_jumps_2_obj ../build//boost_thread ]
[ exe test_time_jumps_3 : test_time_jumps_3_obj ../build//boost_thread ]
;
test-suite test_self_contained_headers : [ generate_self_contained_header_tests ] ;
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright Andrey Semashev 2019.
* 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)
*/
/*!
* \file self_contained_header.cpp
* \author Andrey Semashev
* \date 2019-01-19
*
* \brief This file contains a test boilerplate for checking that every public header is self-contained and does not have any missing #includes.
*/
#if defined(BOOST_THREAD_TEST_POST_WINDOWS_H)
#include <windows.h>
#endif
#define BOOST_THREAD_TEST_INCLUDE_HEADER() <boost/thread/BOOST_THREAD_TEST_HEADER>
#include BOOST_THREAD_TEST_INCLUDE_HEADER()
int main(int, char*[])
{
return 0;
}

View File

@@ -0,0 +1,241 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Copyright (C) 2017 Austin J. Beer
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// <boost/thread/condition_variable>
// class condition_variable;
// condition_variable(const condition_variable&) = delete;
#include <iostream>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <cassert>
// Summary of each test:
// 1. Start the test thread and wait for it to start up.
// The test thread waits for the flag to be set using a large timeout.
// 2. The main thread takes the lock and then sleeps for a long time while holding
// the lock before setting the flag and calling notify_one(). If the wait
// function being tested is polling pthread_cond_timedwait() internally, any
// notifications sent after pthread_cond_timedwait() times out but before it can
// reacquire the lock may be "lost". pthread_cond_timedwait() will report that
// it timed out and the wait function may incorrectly assume that no
// notification was received. This test ensures that that doesn't happen.
// 3. Measure how it takes the test thread to return. If it received the
// notification, it will return fairly quickly. If it missed the notification,
// the test thread won't return until the wait function being tested times out.
//------------------------------------------------------------------------------
boost::condition_variable cv;
boost::mutex mut;
bool flag;
bool waiting;
bool flagIsSet()
{
return flag;
}
bool threadIsWaiting()
{
return waiting;
}
//------------------------------------------------------------------------------
#ifdef BOOST_THREAD_USES_DATETIME
boost::posix_time::milliseconds posix_wait_time(1000);
template <typename F>
void test_posix_wait_function(F f)
{
flag = false;
waiting = false;
boost::thread t(f);
while (!threadIsWaiting())
{
boost::this_thread::sleep(boost::posix_time::milliseconds(1));
}
boost::unique_lock<boost::mutex> lk(mut);
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
boost::posix_time::ptime t0 = boost::posix_time::microsec_clock::universal_time();
flag = true;
cv.notify_one();
lk.unlock();
t.join();
boost::posix_time::ptime t1 = boost::posix_time::microsec_clock::universal_time();
BOOST_TEST(t1 - t0 < boost::posix_time::milliseconds(250));
}
//------------------------------------------------------------------------------
void timed_wait_absolute_without_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
while (!flagIsSet())
{
cv.timed_wait(lk, boost::posix_time::microsec_clock::universal_time() + posix_wait_time);
}
}
void timed_wait_absolute_with_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
cv.timed_wait(lk, boost::posix_time::microsec_clock::universal_time() + posix_wait_time, flagIsSet);
}
//------------------------------------------------------------------------------
void timed_wait_relative_without_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
while (!flagIsSet())
{
cv.timed_wait(lk, posix_wait_time);
}
}
void timed_wait_relative_with_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
cv.timed_wait(lk, posix_wait_time, flagIsSet);
}
#else
#error "Test not applicable: BOOST_THREAD_USES_DATETIME not defined for this platform as not supported"
#endif
//------------------------------------------------------------------------------
#ifdef BOOST_THREAD_USES_CHRONO
boost::chrono::milliseconds chrono_wait_time(1000);
template <typename F>
void test_chrono_wait_function(F f)
{
flag = false;
waiting = false;
boost::thread t(f);
while (!threadIsWaiting())
{
boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
}
boost::unique_lock<boost::mutex> lk(mut);
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
boost::chrono::steady_clock::time_point t0 = boost::chrono::steady_clock::now();
flag = true;
cv.notify_one();
lk.unlock();
t.join();
boost::chrono::steady_clock::time_point t1 = boost::chrono::steady_clock::now();
BOOST_TEST(t1 - t0 < boost::chrono::milliseconds(250));
}
//------------------------------------------------------------------------------
void wait_until_system_without_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
while (!flagIsSet())
{
cv.wait_until(lk, boost::chrono::system_clock::now() + chrono_wait_time);
}
}
void wait_until_system_with_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
cv.wait_until(lk, boost::chrono::system_clock::now() + chrono_wait_time, flagIsSet);
}
//------------------------------------------------------------------------------
void wait_until_steady_without_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
while (!flagIsSet())
{
cv.wait_until(lk, boost::chrono::steady_clock::now() + chrono_wait_time);
}
}
void wait_until_steady_with_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
cv.wait_until(lk, boost::chrono::steady_clock::now() + chrono_wait_time, flagIsSet);
}
//------------------------------------------------------------------------------
void wait_for_without_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
while (!flagIsSet())
{
cv.wait_for(lk, chrono_wait_time);
}
}
void wait_for_with_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
cv.wait_for(lk, chrono_wait_time, flagIsSet);
}
#else
#error "Test not applicable: BOOST_THREAD_USES_CHRONO not defined for this platform as not supported"
#endif
//------------------------------------------------------------------------------
int main()
{
#ifdef BOOST_THREAD_USES_DATETIME
test_posix_wait_function(timed_wait_absolute_without_pred);
test_posix_wait_function(timed_wait_absolute_with_pred);
test_posix_wait_function(timed_wait_relative_without_pred);
test_posix_wait_function(timed_wait_relative_with_pred);
#endif
#ifdef BOOST_THREAD_USES_CHRONO
test_chrono_wait_function(wait_until_system_without_pred);
test_chrono_wait_function(wait_until_system_with_pred);
test_chrono_wait_function(wait_until_steady_without_pred);
test_chrono_wait_function(wait_until_steady_with_pred);
test_chrono_wait_function(wait_for_without_pred);
test_chrono_wait_function(wait_for_with_pred);
#endif
return boost::report_errors();
}

View File

@@ -23,6 +23,7 @@
#include <boost/thread/thread.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <cassert>
#include "../../../timming.hpp"
#if defined BOOST_THREAD_USES_CHRONO
@@ -34,29 +35,36 @@ int test2 = 0;
int runs = 0;
typedef boost::chrono::steady_clock Clock;
typedef boost::chrono::milliseconds milliseconds;
typedef boost::chrono::nanoseconds nanoseconds;
typedef boost::chrono::milliseconds ms;
typedef boost::chrono::nanoseconds ns;
const ms max_diff(BOOST_THREAD_TEST_TIME_MS);
void f()
{
try {
typedef boost::chrono::steady_clock Clock;
typedef boost::chrono::milliseconds milliseconds;
boost::unique_lock<boost::mutex> lk(mut);
assert(test2 == 0);
test1 = 1;
cv.notify_one();
Clock::time_point t0 = Clock::now();
int count=0;
while (test2 == 0 && cv.wait_for(lk, milliseconds(250)) == boost::cv_status::no_timeout)
count++;
Clock::time_point t = t0 + milliseconds(250);
while (test2 == 0 && cv.wait_for(lk, t - Clock::now()) == boost::cv_status::no_timeout) {}
Clock::time_point t1 = Clock::now();
if (runs == 0)
{
assert(t1 - t0 < milliseconds(250));
assert(t1 - t0 < max_diff);
assert(test2 != 0);
}
else
{
// This test is spurious as it depends on the time the thread system switches the threads
assert(t1 - t0 - milliseconds(250) < milliseconds(count*250+5+1000));
nanoseconds d = t1 - t0 - milliseconds(250);
std::cout << "diff= " << d.count() << std::endl;
std::cout << "max_diff= " << max_diff.count() << std::endl;
assert( d < max_diff);
assert(test2 == 0);
}
++runs;

View File

@@ -23,6 +23,7 @@
#include <boost/detail/lightweight_test.hpp>
#include <cassert>
#include <iostream>
#include "../../../timming.hpp"
#if defined BOOST_THREAD_USES_CHRONO
@@ -49,30 +50,31 @@ int test2 = 0;
int runs = 0;
typedef boost::chrono::system_clock Clock;
typedef boost::chrono::milliseconds milliseconds;
typedef boost::chrono::milliseconds ms;
typedef boost::chrono::nanoseconds ns;
const ms max_diff(BOOST_THREAD_TEST_TIME_MS);
void f()
{
try {
typedef boost::chrono::system_clock Clock;
typedef boost::chrono::milliseconds milliseconds;
boost::unique_lock < boost::mutex > lk(mut);
assert(test2 == 0);
test1 = 1;
cv.notify_one();
Clock::time_point t0 = Clock::now();
int count=0;
//bool r =
(void)cv.wait_for(lk, milliseconds(250), Pred(test2));
count++;
cv.wait_for(lk, milliseconds(250), Pred(test2));
Clock::time_point t1 = Clock::now();
if (runs == 0)
{
// This test is spurious as it depends on the time the thread system switches the threads
assert(t1 - t0 < milliseconds(250+1000));
assert(t1 - t0 < max_diff);
assert(test2 != 0);
}
else
{
assert(t1 - t0 - milliseconds(250) < milliseconds(count*250+2));
assert(t1 - t0 - milliseconds(250) < max_diff);
assert(test2 == 0);
}
++runs;

View File

@@ -23,9 +23,11 @@
#include <boost/detail/lightweight_test.hpp>
#include <iostream>
#include <cassert>
#include "../../../timming.hpp"
#if defined BOOST_THREAD_USES_CHRONO
typedef boost::chrono::milliseconds ms;
typedef boost::chrono::nanoseconds ns;
struct Clock
{
typedef boost::chrono::milliseconds duration;
@@ -44,11 +46,14 @@ struct Clock
boost::condition_variable cv;
boost::mutex mut;
int test1 = 0;
int test2 = 0;
int runs = 0;
const ms max_diff(BOOST_THREAD_TEST_TIME_MS);
void f()
{
try {
@@ -58,19 +63,18 @@ void f()
cv.notify_one();
Clock::time_point t0 = Clock::now();
Clock::time_point t = t0 + Clock::duration(250);
int count=0;
while (test2 == 0 && cv.wait_until(lk, t) == boost::cv_status::no_timeout)
count++;
while (test2 == 0 && cv.wait_until(lk, t) == boost::cv_status::no_timeout) {}
Clock::time_point t1 = Clock::now();
if (runs == 0)
{
assert(t1 - t0 < Clock::duration(250));
ns d = t1 - t0;
BOOST_THREAD_TEST_IT(d, ns(max_diff));
assert(test2 != 0);
}
else
{
// This test is spurious as it depends on the time the thread system switches the threads
assert(t1 - t0 - Clock::duration(250) < Clock::duration(count*250+5+1000));
ns d = t1 - t0 - Clock::duration(250);
BOOST_THREAD_TEST_IT(d, ns(max_diff));
assert(test2 == 0);
}
++runs;

View File

@@ -23,9 +23,13 @@
#include <boost/detail/lightweight_test.hpp>
#include <cassert>
#include <iostream>
#include "../../../timming.hpp"
#if defined BOOST_THREAD_USES_CHRONO
typedef boost::chrono::milliseconds milliseconds;
typedef boost::chrono::nanoseconds nanoseconds;
typedef boost::chrono::milliseconds ms;
typedef boost::chrono::nanoseconds ns;
struct Clock
{
typedef boost::chrono::milliseconds duration;
@@ -64,6 +68,8 @@ int test2 = 0;
int runs = 0;
const ms max_diff(BOOST_THREAD_TEST_TIME_MS);
void f()
{
try {
@@ -74,17 +80,19 @@ void f()
Clock::time_point t0 = Clock::now();
Clock::time_point t = t0 + Clock::duration(250);
bool r = cv.wait_until(lk, t, Pred(test2));
(void)r;
Clock::time_point t1 = Clock::now();
if (runs == 0)
{
assert(t1 - t0 < Clock::duration(250));
assert(t1 - t0 < max_diff);
assert(test2 != 0);
assert(r);
}
else
{
assert(t1 - t0 - Clock::duration(250) < Clock::duration(250+2));
const nanoseconds d = t1 - t0 - milliseconds(250);
std::cout << "diff= " << d.count() << std::endl;
std::cout << "max_diff= " << max_diff.count() << std::endl;
assert(d < max_diff);
assert(test2 == 0);
assert(!r);
}

View File

@@ -0,0 +1,241 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Copyright (C) 2017 Austin J. Beer
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// <boost/thread/condition_variable>
// class condition_variable;
// condition_variable(const condition_variable&) = delete;
#include <iostream>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <cassert>
// Summary of each test:
// 1. Start the test thread and wait for it to start up.
// The test thread waits for the flag to be set using a large timeout.
// 2. The main thread takes the lock and then sleeps for a long time while holding
// the lock before setting the flag and calling notify_one(). If the wait
// function being tested is polling pthread_cond_timedwait() internally, any
// notifications sent after pthread_cond_timedwait() times out but before it can
// reacquire the lock may be "lost". pthread_cond_timedwait() will report that
// it timed out and the wait function may incorrectly assume that no
// notification was received. This test ensures that that doesn't happen.
// 3. Measure how it takes the test thread to return. If it received the
// notification, it will return fairly quickly. If it missed the notification,
// the test thread won't return until the wait function being tested times out.
//------------------------------------------------------------------------------
boost::condition_variable_any cv;
boost::mutex mut;
bool flag;
bool waiting;
bool flagIsSet()
{
return flag;
}
bool threadIsWaiting()
{
return waiting;
}
//------------------------------------------------------------------------------
#ifdef BOOST_THREAD_USES_DATETIME
boost::posix_time::milliseconds posix_wait_time(1000);
template <typename F>
void test_posix_wait_function(F f)
{
flag = false;
waiting = false;
boost::thread t(f);
while (!threadIsWaiting())
{
boost::this_thread::sleep(boost::posix_time::milliseconds(1));
}
boost::unique_lock<boost::mutex> lk(mut);
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
boost::posix_time::ptime t0 = boost::posix_time::microsec_clock::universal_time();
flag = true;
cv.notify_one();
lk.unlock();
t.join();
boost::posix_time::ptime t1 = boost::posix_time::microsec_clock::universal_time();
BOOST_TEST(t1 - t0 < boost::posix_time::milliseconds(250));
}
//------------------------------------------------------------------------------
void timed_wait_absolute_without_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
while (!flagIsSet())
{
cv.timed_wait(lk, boost::posix_time::microsec_clock::universal_time() + posix_wait_time);
}
}
void timed_wait_absolute_with_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
cv.timed_wait(lk, boost::posix_time::microsec_clock::universal_time() + posix_wait_time, flagIsSet);
}
//------------------------------------------------------------------------------
void timed_wait_relative_without_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
while (!flagIsSet())
{
cv.timed_wait(lk, posix_wait_time);
}
}
void timed_wait_relative_with_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
cv.timed_wait(lk, posix_wait_time, flagIsSet);
}
#else
#error "Test not applicable: BOOST_THREAD_USES_DATETIME not defined for this platform as not supported"
#endif
//------------------------------------------------------------------------------
#ifdef BOOST_THREAD_USES_CHRONO
boost::chrono::milliseconds chrono_wait_time(1000);
template <typename F>
void test_chrono_wait_function(F f)
{
flag = false;
waiting = false;
boost::thread t(f);
while (!threadIsWaiting())
{
boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
}
boost::unique_lock<boost::mutex> lk(mut);
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
boost::chrono::steady_clock::time_point t0 = boost::chrono::steady_clock::now();
flag = true;
cv.notify_one();
lk.unlock();
t.join();
boost::chrono::steady_clock::time_point t1 = boost::chrono::steady_clock::now();
BOOST_TEST(t1 - t0 < boost::chrono::milliseconds(250));
}
//------------------------------------------------------------------------------
void wait_until_system_without_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
while (!flagIsSet())
{
cv.wait_until(lk, boost::chrono::system_clock::now() + chrono_wait_time);
}
}
void wait_until_system_with_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
cv.wait_until(lk, boost::chrono::system_clock::now() + chrono_wait_time, flagIsSet);
}
//------------------------------------------------------------------------------
void wait_until_steady_without_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
while (!flagIsSet())
{
cv.wait_until(lk, boost::chrono::steady_clock::now() + chrono_wait_time);
}
}
void wait_until_steady_with_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
cv.wait_until(lk, boost::chrono::steady_clock::now() + chrono_wait_time, flagIsSet);
}
//------------------------------------------------------------------------------
void wait_for_without_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
while (!flagIsSet())
{
cv.wait_for(lk, chrono_wait_time);
}
}
void wait_for_with_pred()
{
boost::unique_lock<boost::mutex> lk(mut);
waiting = true;
cv.wait_for(lk, chrono_wait_time, flagIsSet);
}
#else
#error "Test not applicable: BOOST_THREAD_USES_CHRONO not defined for this platform as not supported"
#endif
//------------------------------------------------------------------------------
int main()
{
#ifdef BOOST_THREAD_USES_DATETIME
test_posix_wait_function(timed_wait_absolute_without_pred);
test_posix_wait_function(timed_wait_absolute_with_pred);
test_posix_wait_function(timed_wait_relative_without_pred);
test_posix_wait_function(timed_wait_relative_with_pred);
#endif
#ifdef BOOST_THREAD_USES_CHRONO
test_chrono_wait_function(wait_until_system_without_pred);
test_chrono_wait_function(wait_until_system_with_pred);
test_chrono_wait_function(wait_until_steady_without_pred);
test_chrono_wait_function(wait_until_steady_with_pred);
test_chrono_wait_function(wait_for_without_pred);
test_chrono_wait_function(wait_for_with_pred);
#endif
return boost::report_errors();
}

View File

@@ -21,6 +21,7 @@
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/detail/lightweight_test.hpp>
#include "../../../timming.hpp"
#if defined BOOST_THREAD_USES_CHRONO
@@ -36,29 +37,33 @@ int test2 = 0;
int runs = 0;
typedef boost::chrono::system_clock Clock;
typedef boost::chrono::milliseconds milliseconds;
typedef boost::chrono::milliseconds ms;
typedef boost::chrono::nanoseconds ns;
const ms max_diff(BOOST_THREAD_TEST_TIME_MS);
void f()
{
typedef boost::chrono::system_clock Clock;
typedef boost::chrono::milliseconds milliseconds;
L1 lk(m0);
BOOST_TEST(test2 == 0);
test1 = 1;
cv.notify_one();
int count=0;
Clock::time_point t0 = Clock::now();
while (test2 == 0 &&
cv.wait_for(lk, milliseconds(250)) == boost::cv_status::no_timeout)
count++;
Clock::time_point t = t0 + milliseconds(250);
while (test2 == 0 && cv.wait_for(lk, t - Clock::now()) == boost::cv_status::no_timeout) {}
Clock::time_point t1 = Clock::now();
if (runs == 0)
{
BOOST_TEST(t1 - t0 < milliseconds(250));
ns d = t1 - t0;
BOOST_THREAD_TEST_IT(d, ns(max_diff));
BOOST_TEST(test2 != 0);
}
else
{
// This test is spurious as it depends on the time the thread system switches the threads
BOOST_TEST(t1 - t0 - milliseconds(250) < milliseconds(count*250+5+1000));
ns d = t1 - t0 - ms(250);
BOOST_THREAD_TEST_IT(d, ns(max_diff));
BOOST_TEST(test2 == 0);
}
++runs;

View File

@@ -21,6 +21,7 @@
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/detail/lightweight_test.hpp>
#include "../../../timming.hpp"
#if defined BOOST_THREAD_USES_CHRONO
@@ -51,27 +52,33 @@ int test2 = 0;
int runs = 0;
typedef boost::chrono::system_clock Clock;
typedef boost::chrono::milliseconds milliseconds;
typedef boost::chrono::milliseconds ms;
typedef boost::chrono::nanoseconds ns;
const ms max_diff(BOOST_THREAD_TEST_TIME_MS);
void f()
{
typedef boost::chrono::system_clock Clock;
typedef boost::chrono::milliseconds milliseconds;
L1 lk(m0);
BOOST_TEST(test2 == 0);
test1 = 1;
cv.notify_one();
Clock::time_point t0 = Clock::now();
//bool r =
(void)cv.wait_for(lk, milliseconds(250), Pred(test2));
cv.wait_for(lk, milliseconds(250), Pred(test2));
Clock::time_point t1 = Clock::now();
if (runs == 0)
{
BOOST_TEST(t1 - t0 < milliseconds(250));
BOOST_TEST(test2 != 0);
ns d = t1 - t0 ;
BOOST_THREAD_TEST_IT(d, ns(max_diff));
BOOST_TEST(test2 != 0);
}
else
{
BOOST_TEST(t1 - t0 - milliseconds(250) < milliseconds(250+5));
BOOST_TEST(test2 == 0);
ns d = t1 - t0 - ms(250);
BOOST_THREAD_TEST_IT(d, ns(max_diff));
BOOST_TEST(test2 == 0);
}
++runs;
}

View File

@@ -21,9 +21,11 @@
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/detail/lightweight_test.hpp>
#include "../../../timming.hpp"
#if defined BOOST_THREAD_USES_CHRONO
typedef boost::chrono::milliseconds ms;
typedef boost::chrono::nanoseconds ns;
struct Clock
{
typedef boost::chrono::milliseconds duration;
@@ -51,6 +53,8 @@ int test2 = 0;
int runs = 0;
const ms max_diff(BOOST_THREAD_TEST_TIME_MS);
void f()
{
L1 lk(m0);
@@ -59,20 +63,19 @@ void f()
cv.notify_one();
Clock::time_point t0 = Clock::now();
Clock::time_point t = t0 + Clock::duration(250);
int count=0;
while (test2 == 0 && cv.wait_until(lk, t) == boost::cv_status::no_timeout)
count++;
while (test2 == 0 && cv.wait_until(lk, t) == boost::cv_status::no_timeout) {}
Clock::time_point t1 = Clock::now();
if (runs == 0)
{
BOOST_TEST(t1 - t0 < Clock::duration(250));
BOOST_TEST(test2 != 0);
ns d = t1 - t0;
BOOST_THREAD_TEST_IT(d, ns(max_diff));
BOOST_TEST(test2 != 0);
}
else
{
// This test is spurious as it depends on the time the thread system switches the threads
BOOST_TEST(t1 - t0 - Clock::duration(250) < Clock::duration(250*count+5+1000));
BOOST_TEST(test2 == 0);
ns d = t1 - t0 - ms(250);
BOOST_THREAD_TEST_IT(d, ns(max_diff));
BOOST_TEST(test2 == 0);
}
++runs;
}

View File

@@ -21,9 +21,13 @@
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/detail/lightweight_test.hpp>
#include "../../../timming.hpp"
#if defined BOOST_THREAD_USES_CHRONO
typedef boost::chrono::milliseconds ms;
typedef boost::chrono::nanoseconds ns;
struct Clock
{
typedef boost::chrono::milliseconds duration;
@@ -66,6 +70,8 @@ int test2 = 0;
int runs = 0;
const ms max_diff(BOOST_THREAD_TEST_TIME_MS);
void f()
{
L1 lk(m0);
@@ -78,13 +84,15 @@ void f()
Clock::time_point t1 = Clock::now();
if (runs == 0)
{
BOOST_TEST(t1 - t0 < Clock::duration(250));
ns d = t1 - t0;
BOOST_THREAD_TEST_IT(d, ns(max_diff));
BOOST_TEST(test2 != 0);
BOOST_TEST(r);
}
else
{
BOOST_TEST(t1 - t0 - Clock::duration(250) < Clock::duration(250+2));
ns d = t1 - t0 - ms(250);
BOOST_THREAD_TEST_IT(d, ns(max_diff));
BOOST_TEST(test2 == 0);
BOOST_TEST(!r);
}

Some files were not shown because too many files have changed in this diff Show More