Local fix for #12519
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff -p -ruN ./boost2/boost/thread/detail/thread.hpp ./boost1/boost/thread/detail/thread.hpp | |
--- ./boost2/boost/thread/detail/thread.hpp 2016-05-05 23:14:50.000000000 +0200 | |
+++ ./boost1/boost/thread/detail/thread.hpp 2017-02-22 14:47:05.051474829 +0100 | |
@@ -482,13 +482,18 @@ namespace boost | |
return try_join_until(chrono::steady_clock::now() + rel_time); | |
} | |
#endif | |
+#if defined(BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC) and defined(USEFIXES) | |
+ typedef chrono::steady_clock my_clock_t; | |
+#else | |
+ typedef chrono::system_clock my_clock_t; | |
+#endif | |
template <class Clock, class Duration> | |
bool try_join_until(const chrono::time_point<Clock, Duration>& t) | |
{ | |
using namespace chrono; | |
bool joined= false; | |
do { | |
- system_clock::time_point s_now = system_clock::now(); | |
+ my_clock_t::time_point s_now = my_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); | |
@@ -496,10 +501,10 @@ namespace boost | |
return true; | |
} | |
template <class Duration> | |
- bool try_join_until(const chrono::time_point<chrono::system_clock, Duration>& t) | |
+ bool try_join_until(const chrono::time_point<my_clock_t, Duration>& t) | |
{ | |
using namespace chrono; | |
- typedef time_point<system_clock, nanoseconds> nano_sys_tmpt; | |
+ typedef time_point<my_clock_t, nanoseconds> nano_sys_tmpt; | |
return try_join_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); | |
} | |
#endif | |
@@ -535,7 +540,7 @@ namespace boost | |
} | |
#endif | |
#ifdef BOOST_THREAD_USES_CHRONO | |
- bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp) | |
+ bool try_join_until(const chrono::time_point<my_clock_t, chrono::nanoseconds>& tp) | |
{ | |
using namespace chrono; | |
nanoseconds d = tp.time_since_epoch(); | |
diff -p -ruN ./boost2/boost/thread/pthread/condition_variable_fwd.hpp ./boost1/boost/thread/pthread/condition_variable_fwd.hpp | |
--- ./boost2/boost/thread/pthread/condition_variable_fwd.hpp 2016-05-05 23:14:50.000000000 +0200 | |
+++ ./boost1/boost/thread/pthread/condition_variable_fwd.hpp 2017-02-22 14:41:30.949455306 +0100 | |
@@ -17,10 +17,8 @@ | |
#if defined BOOST_THREAD_USES_DATETIME | |
#include <boost/thread/xtime.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/date_time/posix_time/posix_time_duration.hpp> | |
@@ -68,7 +66,23 @@ namespace boost | |
unique_lock<mutex>& lock, | |
struct timespec const &timeout) | |
{ | |
+#ifndef USEFIXES | |
+// old behaviour | |
+ return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now())); | |
+#else | |
+#ifndef BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC | |
+ using namespace chrono; | |
+ nanoseconds ns = chrono::system_clock::now().time_since_epoch(); | |
+ | |
+ 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 do_wait_until(lock, boost::detail::timespec_plus(timeout, ts)); | |
+#else | |
+// old behavior was fine for monotonic | |
return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now())); | |
+#endif | |
+#endif | |
} | |
public: | |
diff -p -ruN ./boost2/boost/thread/pthread/timespec.hpp ./boost1/boost/thread/pthread/timespec.hpp | |
--- ./boost2/boost/thread/pthread/timespec.hpp 2016-05-05 23:14:50.000000000 +0200 | |
+++ ./boost1/boost/thread/pthread/timespec.hpp 2017-02-22 14:42:13.973457820 +0100 | |
@@ -75,7 +75,14 @@ namespace boost | |
{ | |
timespec ts; | |
-#if defined(BOOST_THREAD_TIMESPEC_MAC_API) | |
+#ifdef CLOCK_MONOTONIC | |
+ if ( ::clock_gettime( CLOCK_MONOTONIC, &ts ) ) | |
+ { | |
+ ts.tv_sec = 0; | |
+ ts.tv_nsec = 0; | |
+ BOOST_ASSERT(0 && "Boost::Thread - Internal Error"); | |
+ } | |
+#elif defined(BOOST_THREAD_TIMESPEC_MAC_API) | |
timeval tv; | |
::gettimeofday(&tv, 0); | |
ts.tv_sec = tv.tv_sec; | |
@@ -83,11 +90,14 @@ namespace boost | |
#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; | |
diff -p -ruN ./boost2/libs/thread/src/pthread/thread.cpp ./boost/libs/thread/src/pthread/thread.cpp | |
--- ./boost2/libs/thread/src/pthread/thread.cpp 2016-05-05 23:14:50.000000000 +0200 | |
+++ ./boost1/libs/thread/src/pthread/thread.cpp 2017-02-22 14:44:03.116464198 +0100 | |
@@ -6,6 +6,12 @@ | |
// 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) | |
+// defines need to be inserted here in order to compile the | |
+// correct template specializations | |
+#define BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC | |
+#define USEFIXES | |
+ | |
+ | |
#include <boost/thread/detail/config.hpp> | |
#include <boost/thread/thread_only.hpp> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This test has lots of duplicates - this is on purpopse of course ;-) | |
// NOTE: This is the test that works with my fix. BUT: Without the #define, I am not sure whether this is the | |
// intended behavior, i.e., I am not sure, whether sleep_for::SetTimeBackward really should take 100 ms when this | |
// define is not set. | |
// You will need to be able to run settimeofday. So probably you will need to have root access. | |
#define USEFIXES | |
// #define BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC | |
#include <boost/thread.hpp> | |
#include <chrono> | |
#include <thread> | |
#include <gtest/gtest.h> | |
#include <sys/time.h> | |
int set_time_backwards() { | |
struct timeval tv; | |
struct timezone tz; | |
gettimeofday(&tv, &tz); | |
tv.tv_sec -= 60 * 60; | |
int ret = settimeofday(&tv, &tz); | |
return ret; | |
} | |
int set_time_forwards() { | |
struct timeval tv; | |
struct timezone tz; | |
gettimeofday(&tv, &tz); | |
tv.tv_sec += 60 * 60; | |
int ret = settimeofday(&tv, &tz); | |
return ret; | |
} | |
TEST(sleep_until, SimpleTest) { | |
using namespace std::chrono; | |
const auto start = steady_clock::now(); | |
boost::this_thread::sleep_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(100)); | |
const auto stop = steady_clock::now(); | |
const auto duration = stop - start; | |
const auto milliseconds = duration_cast<microseconds>(duration).count(); | |
EXPECT_LT(milliseconds, 110000); | |
EXPECT_GT(milliseconds, 90000); | |
} | |
TEST(sleep_for, SimpleTest) { | |
using namespace std::chrono; | |
const auto start = steady_clock::now(); | |
boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); | |
const auto stop = steady_clock::now(); | |
const auto duration = stop - start; | |
const auto milliseconds = duration_cast<microseconds>(duration).count(); | |
EXPECT_LT(milliseconds, 110000); | |
EXPECT_GT(milliseconds, 90000); | |
} | |
TEST(sleep_for, SetTimeBackwards) { | |
using namespace std::chrono; | |
std::thread t([]() { | |
std::this_thread::sleep_for(milliseconds(50)); | |
ASSERT_EQ(0, set_time_backwards()); | |
}); | |
const auto start = steady_clock::now(); | |
boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); | |
const auto stop = steady_clock::now(); | |
const auto duration = stop - start; | |
const auto milliseconds = duration_cast<microseconds>(duration).count(); | |
t.join(); | |
EXPECT_LT(milliseconds, 110000); | |
EXPECT_GT(milliseconds, 90000); | |
ASSERT_EQ(0, set_time_forwards()); | |
} | |
TEST(sleep_for, SetTimeForwards) { | |
using namespace std::chrono; | |
std::thread t([]() { | |
std::this_thread::sleep_for(milliseconds(50)); | |
ASSERT_EQ(0, set_time_forwards()); | |
}); | |
const auto start = steady_clock::now(); | |
boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); | |
const auto stop = steady_clock::now(); | |
const auto duration = stop - start; | |
const auto milliseconds = duration_cast<microseconds>(duration).count(); | |
t.join(); | |
EXPECT_LT(milliseconds, 110000); | |
EXPECT_GT(milliseconds, 90000); | |
ASSERT_EQ(0, set_time_backwards()); | |
} | |
TEST(try_join_for_timeout, SimpleTest) { | |
using namespace std::chrono; | |
boost::thread t([]() { | |
std::this_thread::sleep_for(milliseconds(200)); | |
}); | |
const auto start = steady_clock::now(); | |
EXPECT_FALSE(t.try_join_for(boost::chrono::milliseconds(100))); | |
const auto stop = steady_clock::now(); | |
const auto duration = stop - start; | |
const auto milliseconds = duration_cast<microseconds>(duration).count(); | |
EXPECT_LT(milliseconds, 110000); | |
EXPECT_GT(milliseconds, 90000); | |
} | |
TEST(try_join_for_timeout, SetTimeBackwards) { | |
using namespace std::chrono; | |
std::thread t_settime([]() { | |
std::this_thread::sleep_for(milliseconds(50)); | |
ASSERT_EQ(0, set_time_backwards()); | |
}); | |
boost::thread t([]() { | |
std::this_thread::sleep_for(milliseconds(200)); | |
}); | |
const auto start = steady_clock::now(); | |
#ifdef BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC | |
EXPECT_FALSE(t.try_join_for(boost::chrono::milliseconds(100))); | |
#else | |
EXPECT_TRUE(t.try_join_for(boost::chrono::milliseconds(100))); | |
#endif | |
const auto stop = steady_clock::now(); | |
const auto duration = stop - start; | |
const auto milliseconds = duration_cast<microseconds>(duration).count(); | |
t.join(); | |
t_settime.join(); | |
#ifdef BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC | |
EXPECT_LT(milliseconds, 110000); | |
EXPECT_GT(milliseconds, 90000); | |
#else | |
EXPECT_LT(milliseconds, 210000); | |
EXPECT_GT(milliseconds, 190000); | |
#endif | |
ASSERT_EQ(0, set_time_forwards()); | |
} | |
TEST(try_join_for_timeout, SetTimeForwards) { | |
using namespace std::chrono; | |
std::thread t_settime([]() { | |
std::this_thread::sleep_for(milliseconds(50)); | |
ASSERT_EQ(0, set_time_forwards()); | |
}); | |
boost::thread t([]() { | |
std::this_thread::sleep_for(milliseconds(200)); | |
}); | |
const auto start = steady_clock::now(); | |
EXPECT_FALSE(t.try_join_for(boost::chrono::milliseconds(100))); | |
const auto stop = steady_clock::now(); | |
const auto duration = stop - start; | |
const auto milliseconds = duration_cast<microseconds>(duration).count(); | |
t.join(); | |
t_settime.join(); | |
EXPECT_LT(milliseconds, 110000); | |
EXPECT_GT(milliseconds, 90000); | |
ASSERT_EQ(0, set_time_backwards()); | |
} | |
TEST(try_join_for_succeeds, SimpleTest) { | |
using namespace std::chrono; | |
boost::thread t([]() { | |
std::this_thread::sleep_for(milliseconds(100)); | |
}); | |
const auto start = steady_clock::now(); | |
EXPECT_TRUE(t.try_join_for(boost::chrono::milliseconds(200))); | |
const auto stop = steady_clock::now(); | |
const auto duration = stop - start; | |
const auto milliseconds = duration_cast<microseconds>(duration).count(); | |
EXPECT_LT(milliseconds, 110000); | |
EXPECT_GT(milliseconds, 90000); | |
} | |
TEST(try_join_for_succeeds, SetTimeBackwards) { | |
using namespace std::chrono; | |
std::thread t_settime([]() { | |
std::this_thread::sleep_for(milliseconds(50)); | |
ASSERT_EQ(0, set_time_backwards()); | |
}); | |
boost::thread t([]() { | |
std::this_thread::sleep_for(milliseconds(100)); | |
}); | |
const auto start = steady_clock::now(); | |
EXPECT_TRUE(t.try_join_for(boost::chrono::milliseconds(200))); | |
const auto stop = steady_clock::now(); | |
const auto duration = stop - start; | |
const auto milliseconds = duration_cast<microseconds>(duration).count(); | |
t.join(); | |
t_settime.join(); | |
EXPECT_LT(milliseconds, 110000); | |
EXPECT_GT(milliseconds, 90000); | |
ASSERT_EQ(0, set_time_forwards()); | |
} | |
TEST(try_join_for_succeeds, SetTimeForwards) { | |
using namespace std::chrono; | |
std::thread t_settime([]() { | |
std::this_thread::sleep_for(milliseconds(50)); | |
ASSERT_EQ(0, set_time_forwards()); | |
}); | |
boost::thread t([]() { | |
std::this_thread::sleep_for(milliseconds(100)); | |
}); | |
const auto start = steady_clock::now(); | |
EXPECT_TRUE(t.try_join_for(boost::chrono::milliseconds(200))); | |
const auto stop = steady_clock::now(); | |
const auto duration = stop - start; | |
const auto milliseconds = duration_cast<microseconds>(duration).count(); | |
t.join(); | |
t_settime.join(); | |
EXPECT_LT(milliseconds, 110000); | |
EXPECT_GT(milliseconds, 90000); | |
ASSERT_EQ(0, set_time_backwards()); | |
} | |
int main(int argc, char** argv) | |
{ | |
::testing::InitGoogleTest(&argc, argv); | |
return RUN_ALL_TESTS(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define USEFIXES | |
// When you undefine BOOST_THREAD_... this also needs to be done in libs/thread/src/pthread/thread.cpp | |
#define BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC | |
#include <iostream> | |
#include <boost/thread.hpp> | |
void test_func() | |
{ | |
boost::this_thread::sleep_for(boost::chrono::milliseconds(10000)); | |
std::cout << boost::this_thread::get_id() << " test_func done" << std::endl; | |
} | |
int main() | |
{ | |
boost::thread t(test_func); | |
if (!t.try_join_for(boost::chrono::milliseconds(50))) { | |
std::cout << boost::this_thread::get_id() << " OK" << std::endl; | |
} else { | |
std::cout << boost::this_thread::get_id() << " FAILED" << std::endl; | |
} | |
if (t.try_join_for(boost::chrono::milliseconds(15000))) { | |
std::cout << boost::this_thread::get_id() << " OK" << std::endl; | |
} else { | |
std::cout << boost::this_thread::get_id() << " FAILED" << std::endl; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment