Skip to content

Instantly share code, notes, and snippets.

@lukasm91
Last active February 23, 2017 08:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lukasm91/9732228f33e92963bb8762dac519e79f to your computer and use it in GitHub Desktop.
Save lukasm91/9732228f33e92963bb8762dac519e79f to your computer and use it in GitHub Desktop.
Local fix for #12519
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 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();
}
#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