149 changes: 111 additions & 38 deletions include/boost/thread/pthread/condition_variable_fwd.hpp
Expand Up @@ -28,6 +28,26 @@

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
{
Expand Down Expand Up @@ -56,19 +76,19 @@ namespace boost
condition_variable()
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
int const res=pthread_mutex_init(&internal_mutex,NULL);
int res=pthread_mutex_init(&internal_mutex,NULL);
if(res)
{
boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in pthread_mutex_init"));
}
#endif
int const res2=pthread_cond_init(&cond,NULL);
if(res2)
res = detail::monotonic_pthread_cond_init(cond);
if (res)
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
#endif
boost::throw_exception(thread_resource_error(res2, "boost::condition_variable::condition_variable() constructor failed in pthread_cond_init"));
boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in detail::monotonic_pthread_cond_init"));
}
}
~condition_variable()
Expand All @@ -94,7 +114,6 @@ namespace boost
while(!pred()) wait(m);
}


#if defined BOOST_THREAD_USES_DATETIME
inline bool timed_wait(
unique_lock<mutex>& m,
Expand Down Expand Up @@ -174,6 +193,8 @@ namespace boost
}
#endif

#ifndef BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC

#ifdef BOOST_THREAD_USES_CHRONO

template <class Duration>
Expand Down Expand Up @@ -203,20 +224,6 @@ namespace boost
return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout;
}

template <class Clock, class Duration, class Predicate>
bool
wait_until(
unique_lock<mutex>& lock,
const chrono::time_point<Clock, Duration>& t,
Predicate pred)
{
while (!pred())
{
if (wait_until(lock, t) == cv_status::timeout)
return pred();
}
return true;
}


template <class Rep, class Period>
Expand All @@ -234,6 +241,90 @@ namespace boost

}

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
wait_until(
unique_lock<mutex>& lock,
const chrono::time_point<chrono::steady_clock, Duration>& t)
{
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;
}

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(
unique_lock<mutex>& lock,
const chrono::time_point<Clock, Duration>& t,
Predicate pred)
{
while (!pred())
{
if (wait_until(lock, t) == cv_status::timeout)
return pred();
}
return true;
}

template <class Rep, class Period, class Predicate>
bool
Expand All @@ -243,13 +334,6 @@ namespace boost
Predicate pred)
{
return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));

// while (!pred())
// {
// if (wait_for(lock, d) == cv_status::timeout)
// return pred();
// }
// return true;
}
#endif

Expand All @@ -263,18 +347,7 @@ namespace boost
void notify_one() BOOST_NOEXCEPT;
void notify_all() BOOST_NOEXCEPT;

#ifdef BOOST_THREAD_USES_CHRONO
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

};

BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
Expand Down
2 changes: 1 addition & 1 deletion include/boost/thread/v2/thread.hpp
Expand Up @@ -91,7 +91,7 @@ namespace boost
cv.wait_until(lk, t);
}

#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY
#if defined BOOST_THREAD_SLEEP_FOR_IS_STEADY && ! defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC

template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& d)
Expand Down
4 changes: 3 additions & 1 deletion include/boost/thread/win32/shared_mutex.hpp
Expand Up @@ -139,6 +139,7 @@ namespace boost

void lock_shared()
{

#if defined BOOST_THREAD_USES_DATETIME
BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel()));
#else
Expand Down Expand Up @@ -389,6 +390,7 @@ namespace boost

void lock()
{

#if defined BOOST_THREAD_USES_DATETIME
BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
#else
Expand Down Expand Up @@ -739,14 +741,14 @@ namespace boost
new_state.upgrade=false;
bool const last_reader=!--new_state.shared_count;

new_state.shared_waiting=0;
if(last_reader)
{
if(new_state.exclusive_waiting)
{
--new_state.exclusive_waiting;
new_state.exclusive_waiting_blocked=false;
}
new_state.shared_waiting=0;
}

state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
Expand Down
26 changes: 14 additions & 12 deletions include/boost/thread/win32/thread_data.hpp
Expand Up @@ -280,12 +280,13 @@ namespace boost
{
interruptible_wait(abs_time);
}
#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
// #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
namespace no_interruption_point
{
bool BOOST_THREAD_DECL non_interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);
Expand All @@ -306,12 +307,13 @@ namespace boost
{
non_interruptible_wait(abs_time);
}
#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
// #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
}
}

Expand Down
4 changes: 0 additions & 4 deletions src/pthread/once.cpp
Expand Up @@ -15,9 +15,7 @@
#include <pthread.h>
#include <stdlib.h>
#include <memory>
#if defined BOOST_THREAD_PATCH
#include <string.h> // memcmp.
#endif
namespace boost
{
namespace thread_detail
Expand All @@ -44,7 +42,6 @@ namespace boost
}
}

#if defined BOOST_THREAD_PATCH
const pthread_once_t pthread_once_init_value=PTHREAD_ONCE_INIT;
struct BOOST_THREAD_DECL delete_epoch_tss_key_on_dlclose_t
{
Expand All @@ -60,7 +57,6 @@ namespace boost
}
};
delete_epoch_tss_key_on_dlclose_t delete_epoch_tss_key_on_dlclose;
#endif
}

uintmax_atomic_t& get_once_per_thread_epoch()
Expand Down
4 changes: 1 addition & 3 deletions src/pthread/thread.cpp
Expand Up @@ -35,6 +35,7 @@
#include <string>
#include <set>
#include <vector>
#include <string.h> // memcmp.

namespace boost
{
Expand Down Expand Up @@ -117,8 +118,6 @@ namespace boost
}
}

#if defined BOOST_THREAD_PATCH

struct delete_current_thread_tls_key_on_dlclose_t
{
delete_current_thread_tls_key_on_dlclose_t()
Expand All @@ -134,7 +133,6 @@ namespace boost
}
};
delete_current_thread_tls_key_on_dlclose_t delete_current_thread_tls_key_on_dlclose;
#endif

void create_current_thread_tls_key()
{
Expand Down
3 changes: 2 additions & 1 deletion src/win32/thread.cpp
Expand Up @@ -25,6 +25,7 @@
#if defined BOOST_THREAD_USES_DATETIME
#include <boost/date_time/posix_time/conversion.hpp>
#endif
#include <boost/thread/csbl/memory/unique_ptr.hpp>
#include <memory>
#include <algorithm>
#ifndef UNDER_CE
Expand Down Expand Up @@ -153,7 +154,7 @@ namespace boost

DWORD WINAPI ThreadProxy(LPVOID args)
{
std::auto_ptr<ThreadProxyData> data(reinterpret_cast<ThreadProxyData*>(args));
boost::csbl::unique_ptr<ThreadProxyData> data(reinterpret_cast<ThreadProxyData*>(args));
DWORD ret=data->start_address_(data->arglist_);
return ret;
}
Expand Down
3 changes: 2 additions & 1 deletion test/Jamfile.v2
Expand Up @@ -959,7 +959,8 @@ rule thread-compile ( sources : reqs * : name )
test-suite ts_
:
#[ thread-run test_11256.cpp ]
[ thread-run test_11499.cpp ]
#[ thread-run test_11499.cpp ]
[ thread-run test_11611.cpp ]
;


Expand Down
48 changes: 48 additions & 0 deletions test/test_11611.cpp
@@ -0,0 +1,48 @@
// Copyright (C) 2014 Vicente Botet
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

//#define BOOST_THREAD_VERSION 4

#include <iostream>
//#include <thread>

#define BOOST_THREAD_PROVIDES_FUTURE
#define BOOST_THREAD_PROVIDES_EXECUTORS
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
#include <boost/thread/executors/loop_executor.hpp>
#include <boost/thread/executors/serial_executor_cont.hpp>
#include <boost/thread/executors/serial_executor.hpp>
#include <boost/thread/thread.hpp>

using namespace std;

int main()
{
boost::loop_executor ex;

//thread t([&ex]()
boost::thread t([&ex]()
{
ex.loop();
});

{
//boost::serial_executor_cont serial(ex);
boost::serial_executor serial(ex);

for (size_t i = 0; i < 100000; i++)
serial.submit([i] {
//std::cout << i << ".";
});

serial.close();
}

ex.close();

t.join();
std::cout << "end" << std::endl;
return 0;
}