#ifndef BOOST_BASIC_TIMED_MUTEX_WIN32_HPP #define BOOST_BASIC_TIMED_MUTEX_WIN32_HPP // basic_timed_mutex_win32.hpp // // (C) Copyright 2006-8 Anthony Williams // (C) Copyright 2011-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 #include #include #include #if defined BOOST_THREAD_USES_DATETIME #include #endif #include #ifdef BOOST_THREAD_USES_CHRONO #include #include #endif #include namespace boost { namespace detail { struct basic_timed_mutex { BOOST_STATIC_CONSTANT(unsigned char,lock_flag_bit=31); BOOST_STATIC_CONSTANT(unsigned char,event_set_flag_bit=30); BOOST_STATIC_CONSTANT(long,lock_flag_value=1< bool timed_lock(Duration const& timeout) { return timed_lock(get_system_time()+timeout); } bool timed_lock(boost::xtime const& timeout) { return timed_lock(system_time(timeout)); } #endif #ifdef BOOST_THREAD_USES_CHRONO template bool try_lock_for(const chrono::duration& rel_time) { return try_lock_until(chrono::steady_clock::now() + rel_time); } template bool try_lock_until(const chrono::time_point& 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(t - c_now)); } template bool try_lock_until(const chrono::time_point& t) { using namespace chrono; typedef time_point sys_tmpt; return try_lock_until(sys_tmpt(chrono::ceil(t.time_since_epoch()))); } bool try_lock_until(const chrono::time_point& 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 now = chrono::system_clock::now(); if (tp<=now) { BOOST_INTERLOCKED_DECREMENT(&active_count); return false; } chrono::milliseconds rel_time= chrono::ceil(tp-now); if(win32::WaitForSingleObjectEx(sem,static_cast(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; } #endif void unlock() { long const offset=lock_flag_value; long const old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,lock_flag_value); if(!(old_count&event_set_flag_value) && (old_count>offset)) { if(!win32::interlocked_bit_test_and_set(&active_count,event_set_flag_bit)) { win32::SetEvent(get_event()); } } } private: void* get_event() { void* current_event=::boost::detail::interlocked_read_acquire(&event); if(!current_event) { void* const new_event=win32::create_anonymous_event(win32::auto_reset_event,win32::event_initially_reset); #ifdef BOOST_MSVC #pragma warning(push) #pragma warning(disable:4311) #pragma warning(disable:4312) #endif void* const old_event=BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&event,new_event,0); #ifdef BOOST_MSVC #pragma warning(pop) #endif if(old_event!=0) { win32::CloseHandle(new_event); return old_event; } else { return new_event; } } return current_event; } }; } } #define BOOST_BASIC_TIMED_MUTEX_INITIALIZER {0} #include #endif