diff --git a/build/.cvsignore b/build/.cvsignore deleted file mode 100644 index 76bf5bcd..00000000 --- a/build/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -bin* -*.pdb diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index cc97011b..1ec9ffc6 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -1,39 +1,205 @@ -# (C) Copyright Vladimir Prus, David Abrahams, Michael Stevens, Hartmut Kaiser, -# William E Kempf 2002-2006 -# Use, modification and distribution are subject to 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) +# $Id$ +# Copyright 2006-2007 Roland Schwarz. +# Copyright 2007 Anthony Williams +# 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) + +######################################################################### +# The boost threading library can be built on top of different API's +# Currently this is the win32 API and the pthreads API. +# Pthread is native on unix variants. +# To get pthread on windows you need the pthread win32 library +# http://sourceware.org/pthreads-win32 which is available under LGPL. +# +# You need to provide the include path and lib path in the variables +# PTW32_INCLUDE and PTW32_LIB respectively. You can specify these +# paths in site-config.jam, user-config.jam or in the environment. +# A new feature is provided to request a specific API: +# win32 and shared:BOOST_THREAD_BUILD_DLL=1 multi + : source-location ../src + : requirements multi + static:BOOST_THREAD_BUILD_LIB=1 + shared:BOOST_THREAD_BUILD_DLL=1 + -@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag + @$(__name__).tag : default-build multi ; -CPP_SOURCES = - barrier - condition - exceptions - mutex - once - recursive_mutex -# read_write_mutex - thread - tss_hooks - tss_dll - tss_pe - tss - xtime +local rule default_threadapi ( ) +{ + local api = pthread ; + if [ os.name ] = "NT" { api = win32 ; } + return $(api) ; +} + +feature.feature threadapi : pthread win32 : propagated ; +feature.set-default threadapi : [ default_threadapi ] ; + +rule tag ( name : type ? : property-set ) +{ + local result = $(name) ; + + if $(type) in STATIC_LIB SHARED_LIB IMPORT_LIB + { + local api = [ $(property-set).get ] ; + + # non native api gets additional tag + if $(api) != [ default_threadapi ] { + result = $(result)_$(api) ; + } + } + + # forward to the boost tagging rule + return [ indirect.call $(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag + $(result) : $(type) : $(property-set) ] ; +} + +rule win32_pthread_paths ( properties * ) +{ + local result ; + local PTW32_INCLUDE ; + local PTW32_LIB ; + PTW32_INCLUDE = [ modules.peek : PTW32_INCLUDE ] ; + PTW32_LIB = [ modules.peek : PTW32_LIB ] ; + PTW32_INCLUDE ?= [ modules.peek user-config : PTW32_INCLUDE ] ; + PTW32_LIB ?= [ modules.peek user-config : PTW32_LIB ] ; + PTW32_INCLUDE ?= [ modules.peek site-config : PTW32_INCLUDE ] ; + PTW32_LIB ?= [ modules.peek site-config : PTW32_LIB ] ; + + if ! ( $(PTW32_INCLUDE) && $(PTW32_LIB) ) + { + if ! $(.notified) + { + echo "************************************************************" ; + echo "Trying to build Boost.Thread with pthread support." ; + echo "If you need pthread you should specify the paths." ; + echo "You can specify them in site-config.jam, user-config.jam" ; + echo "or in the environment." ; + echo "For example:" ; + echo "PTW32_INCLUDE=C:\\Program Files\\ptw32\\Pre-built2\\include" ; + echo "PTW32_LIB=C:\\Program Files\\ptw32\\Pre-built2\\lib" ; + echo "************************************************************" ; + .notified = true ; + } + } + else + { + local include_path = [ path.make $(PTW32_INCLUDE) ] ; + local lib_path = [ path.make $(PTW32_LIB) ] ; + local libname = pthread ; + if msvc in $(properties) + { + libname = $(libname)VC2.lib ; + } + if gcc in $(properties) + { + libname = lib$(libname)GC2.a ; + } + lib_path = [ path.glob $(lib_path) : $(libname) ] ; + if ! $(lib_path) + { + if ! $(.notified) + { + echo "************************************************************" ; + echo "Trying to build Boost.Thread with pthread support." ; + echo "But the library" $(libname) "could not be found in path" ; + echo $(PTW32_LIB) ; + echo "************************************************************" ; + .notified = true ; + } + } + else + { + result += $(include_path) ; + result += $(lib_path) ; + } + } + return $(result) ; +} + +rule usage-requirements ( properties * ) +{ + local result ; + if pthread in $(properties) + { + result += BOOST_THREAD_POSIX ; + if windows in $(properties) + { + result += [ win32_pthread_paths $(properties) ] ; + # TODO: What is for static linking? Is the also needed + # in that case? + } + } + return $(result) ; +} + +rule requirements ( properties * ) +{ + local result ; + if pthread in $(properties) + { + result += BOOST_THREAD_POSIX ; + if windows in $(properties) + { + local paths = [ win32_pthread_paths $(properties) ] ; + if $(paths) + { + result += $(paths) ; + } + else + { + result = no ; + } + } + } + return $(result) ; +} + +alias thread_sources + : ## win32 sources ## + win32/thread.cpp + win32/exceptions.cpp + win32/tss_dll.cpp + win32/tss_pe.cpp + : ## requirements ## + win32 ; +alias thread_sources + : ## pthread sources ## + pthread/thread.cpp + pthread/exceptions.cpp + pthread/once.cpp + : ## requirements ## + pthread + ; + +explicit thread_sources ; + lib boost_thread - : $(CPP_SOURCES).cpp - : shared:BOOST_THREAD_BUILD_DLL=1 - static:BOOST_THREAD_BUILD_LIB=1 - : # default build - : shared:BOOST_THREAD_BUILD_DLL=1 - static:BOOST_THREAD_BUILD_LIB=1 - ; + : thread_sources + : @requirements + : + : @usage-requirements + ; diff --git a/doc/once-ref.xml b/doc/once-ref.xml index ba6b5ffc..12480f57 100644 --- a/doc/once-ref.xml +++ b/doc/once-ref.xml @@ -65,25 +65,23 @@ void init() void thread_proc() { - boost::call_once(&init, once); + boost::call_once(once, &init); } - - void (*func)() - - once_flag& - - The function func shall not throw - exceptions. + + + Function func + As if (in an atomic fashion): - if (flag == BOOST_ONCE_INIT) func(); + if (flag == BOOST_ONCE_INIT) func();. If func() throws an exception, it shall be as if this +thread never invoked call_once - flag != BOOST_ONCE_INIT + flag != BOOST_ONCE_INIT unless func() throws an exception. diff --git a/example/.cvsignore b/example/.cvsignore deleted file mode 100644 index cdbfc82a..00000000 --- a/example/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -bin -*.pdb diff --git a/src/barrier.cpp b/src/barrier.cpp deleted file mode 100644 index e0c94930..00000000 --- a/src/barrier.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (C) 2002-2003 -// David Moore, William E. Kempf -// -// 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 // see http://article.gmane.org/gmane.comp.lib.boost.devel/106981 - -namespace boost { - -barrier::barrier(unsigned int count) - : m_threshold(count), m_count(count), m_generation(0) -{ - if (count == 0) - throw std::invalid_argument("count cannot be zero."); -} - -barrier::~barrier() -{ -} - -bool barrier::wait() -{ - boost::mutex::scoped_lock lock(m_mutex); - unsigned int gen = m_generation; - - if (--m_count == 0) - { - m_generation++; - m_count = m_threshold; - m_cond.notify_all(); - return true; - } - - while (gen == m_generation) - m_cond.wait(lock); - return false; -} - -} // namespace boost diff --git a/src/condition.cpp b/src/condition.cpp deleted file mode 100644 index ffccad05..00000000 --- a/src/condition.cpp +++ /dev/null @@ -1,692 +0,0 @@ -// Copyright (C) 2001-2003 -// William E. Kempf -// -// 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 -#include -#include -#include -#include "timeconv.inl" - -#if defined(BOOST_HAS_WINTHREADS) -# ifndef NOMINMAX -# define NOMINMAX -# endif -# include -#elif defined(BOOST_HAS_PTHREADS) -# include -#elif defined(BOOST_HAS_MPTASKS) -# include -# include "mac/init.hpp" -# include "mac/safe.hpp" -#endif - -// The following include can be removed after the bug on QNX -// has been tracked down. I need this only for debugging -//#if !defined(NDEBUG) && defined(BOOST_HAS_PTHREADS) -#include -//#endif - -namespace boost { - -namespace detail { - -#if defined(BOOST_HAS_WINTHREADS) -condition_impl::condition_impl() - : m_gone(0), m_blocked(0), m_waiting(0) -{ - m_gate = reinterpret_cast(CreateSemaphore(0, 1, 1, 0)); - m_queue = reinterpret_cast( - CreateSemaphore(0, 0, (std::numeric_limits::max)(), 0)); - m_mutex = reinterpret_cast(CreateMutex(0, 0, 0)); - - if (!m_gate || !m_queue || !m_mutex) - { - int res = 0; - if (m_gate) - { - res = CloseHandle(reinterpret_cast(m_gate)); - assert(res); - } - if (m_queue) - { - res = CloseHandle(reinterpret_cast(m_queue)); - assert(res); - } - if (m_mutex) - { - res = CloseHandle(reinterpret_cast(m_mutex)); - assert(res); - } - - throw thread_resource_error(); - } -} - -condition_impl::~condition_impl() -{ - int res = 0; - res = CloseHandle(reinterpret_cast(m_gate)); - assert(res); - res = CloseHandle(reinterpret_cast(m_queue)); - assert(res); - res = CloseHandle(reinterpret_cast(m_mutex)); - assert(res); -} - -void condition_impl::notify_one() -{ - unsigned signals = 0; - - int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_mutex), INFINITE); - assert(res == WAIT_OBJECT_0); - - if (m_waiting != 0) // the m_gate is already closed - { - if (m_blocked == 0) - { - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); - return; - } - - ++m_waiting; - --m_blocked; - signals = 1; - } - else - { - res = WaitForSingleObject(reinterpret_cast(m_gate), INFINITE); - assert(res == WAIT_OBJECT_0); - if (m_blocked > m_gone) - { - if (m_gone != 0) - { - m_blocked -= m_gone; - m_gone = 0; - } - signals = m_waiting = 1; - --m_blocked; - } - else - { - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, 0); - assert(res); - } - } - - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); - - if (signals) - { - res = ReleaseSemaphore(reinterpret_cast(m_queue), signals, 0); - assert(res); - } -} - -void condition_impl::notify_all() -{ - unsigned signals = 0; - - int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_mutex), INFINITE); - assert(res == WAIT_OBJECT_0); - - if (m_waiting != 0) // the m_gate is already closed - { - if (m_blocked == 0) - { - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); - return; - } - - m_waiting += (signals = m_blocked); - m_blocked = 0; - } - else - { - res = WaitForSingleObject(reinterpret_cast(m_gate), INFINITE); - assert(res == WAIT_OBJECT_0); - if (m_blocked > m_gone) - { - if (m_gone != 0) - { - m_blocked -= m_gone; - m_gone = 0; - } - signals = m_waiting = m_blocked; - m_blocked = 0; - } - else - { - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, 0); - assert(res); - } - } - - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); - - if (signals) - { - res = ReleaseSemaphore(reinterpret_cast(m_queue), signals, 0); - assert(res); - } -} - -void condition_impl::enter_wait() -{ - int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_gate), INFINITE); - assert(res == WAIT_OBJECT_0); - ++m_blocked; - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, 0); - assert(res); -} - -void condition_impl::do_wait() -{ - int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_queue), INFINITE); - assert(res == WAIT_OBJECT_0); - - unsigned was_waiting=0; - unsigned was_gone=0; - - res = WaitForSingleObject(reinterpret_cast(m_mutex), INFINITE); - assert(res == WAIT_OBJECT_0); - was_waiting = m_waiting; - was_gone = m_gone; - if (was_waiting != 0) - { - if (--m_waiting == 0) - { - if (m_blocked != 0) - { - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, - 0); // open m_gate - assert(res); - was_waiting = 0; - } - else if (m_gone != 0) - m_gone = 0; - } - } - else if (++m_gone == ((std::numeric_limits::max)() / 2)) - { - // timeout occured, normalize the m_gone count - // this may occur if many calls to wait with a timeout are made and - // no call to notify_* is made - res = WaitForSingleObject(reinterpret_cast(m_gate), INFINITE); - assert(res == WAIT_OBJECT_0); - m_blocked -= m_gone; - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, 0); - assert(res); - m_gone = 0; - } - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); - - if (was_waiting == 1) - { - for (/**/ ; was_gone; --was_gone) - { - // better now than spurious later - res = WaitForSingleObject(reinterpret_cast(m_queue), - INFINITE); - assert(res == WAIT_OBJECT_0); - } - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, 0); - assert(res); - } -} - -bool condition_impl::do_timed_wait(const xtime& xt) -{ - bool ret = false; - unsigned int res = 0; - - for (;;) - { - int milliseconds; - to_duration(xt, milliseconds); - - res = WaitForSingleObject(reinterpret_cast(m_queue), - milliseconds); - assert(res != WAIT_FAILED && res != WAIT_ABANDONED); - ret = (res == WAIT_OBJECT_0); - - if (res == WAIT_TIMEOUT) - { - xtime cur; - xtime_get(&cur, TIME_UTC); - if (xtime_cmp(xt, cur) > 0) - continue; - } - - break; - } - - unsigned was_waiting=0; - unsigned was_gone=0; - - res = WaitForSingleObject(reinterpret_cast(m_mutex), INFINITE); - assert(res == WAIT_OBJECT_0); - was_waiting = m_waiting; - was_gone = m_gone; - if (was_waiting != 0) - { - if (!ret) // timeout - { - if (m_blocked != 0) - --m_blocked; - else - ++m_gone; // count spurious wakeups - } - if (--m_waiting == 0) - { - if (m_blocked != 0) - { - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, - 0); // open m_gate - assert(res); - was_waiting = 0; - } - else if (m_gone != 0) - m_gone = 0; - } - } - else if (++m_gone == ((std::numeric_limits::max)() / 2)) - { - // timeout occured, normalize the m_gone count - // this may occur if many calls to wait with a timeout are made and - // no call to notify_* is made - res = WaitForSingleObject(reinterpret_cast(m_gate), INFINITE); - assert(res == WAIT_OBJECT_0); - m_blocked -= m_gone; - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, 0); - assert(res); - m_gone = 0; - } - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); - - if (was_waiting == 1) - { - for (/**/ ; was_gone; --was_gone) - { - // better now than spurious later - res = WaitForSingleObject(reinterpret_cast(m_queue), - INFINITE); - assert(res == WAIT_OBJECT_0); - } - res = ReleaseSemaphore(reinterpret_cast(m_gate), 1, 0); - assert(res); - } - - return ret; -} -#elif defined(BOOST_HAS_PTHREADS) -condition_impl::condition_impl() -{ - int res = 0; - res = pthread_cond_init(&m_condition, 0); - if (res != 0) - throw thread_resource_error(); -} - -condition_impl::~condition_impl() -{ - int res = 0; - res = pthread_cond_destroy(&m_condition); - assert(res == 0); -} - -void condition_impl::notify_one() -{ - int res = 0; - res = pthread_cond_signal(&m_condition); - assert(res == 0); -} - -void condition_impl::notify_all() -{ - int res = 0; - res = pthread_cond_broadcast(&m_condition); - assert(res == 0); -} - -void condition_impl::do_wait(pthread_mutex_t* pmutex) -{ - int res = 0; - res = pthread_cond_wait(&m_condition, pmutex); - assert(res == 0); -} - -bool condition_impl::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex) -{ - timespec ts; - to_timespec(xt, ts); - - int res = 0; - res = pthread_cond_timedwait(&m_condition, pmutex, &ts); -// Test code for QNX debugging, to get information during regressions -#ifndef NDEBUG - if (res == EINVAL) { - boost::xtime now; - boost::xtime_get(&now, boost::TIME_UTC); - std::cerr << "now: " << now.sec << " " << now.nsec << std::endl; - std::cerr << "time: " << time(0) << std::endl; - std::cerr << "xtime: " << xt.sec << " " << xt.nsec << std::endl; - std::cerr << "ts: " << ts.tv_sec << " " << ts.tv_nsec << std::endl; - std::cerr << "pmutex: " << pmutex << std::endl; - std::cerr << "condition: " << &m_condition << std::endl; - assert(res != EINVAL); - } -#endif - assert(res == 0 || res == ETIMEDOUT); - - return res != ETIMEDOUT; -} -#elif defined(BOOST_HAS_MPTASKS) - -using threads::mac::detail::safe_enter_critical_region; -using threads::mac::detail::safe_wait_on_semaphore; - -condition_impl::condition_impl() - : m_gone(0), m_blocked(0), m_waiting(0) -{ - threads::mac::detail::thread_init(); - - OSStatus lStatus = noErr; - - lStatus = MPCreateSemaphore(1, 1, &m_gate); - if(lStatus == noErr) - lStatus = MPCreateSemaphore(ULONG_MAX, 0, &m_queue); - - if(lStatus != noErr || !m_gate || !m_queue) - { - if (m_gate) - { - lStatus = MPDeleteSemaphore(m_gate); - assert(lStatus == noErr); - } - if (m_queue) - { - lStatus = MPDeleteSemaphore(m_queue); - assert(lStatus == noErr); - } - - throw thread_resource_error(); - } -} - -condition_impl::~condition_impl() -{ - OSStatus lStatus = noErr; - lStatus = MPDeleteSemaphore(m_gate); - assert(lStatus == noErr); - lStatus = MPDeleteSemaphore(m_queue); - assert(lStatus == noErr); -} - -void condition_impl::notify_one() -{ - unsigned signals = 0; - - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); - - if (m_waiting != 0) // the m_gate is already closed - { - if (m_blocked == 0) - { - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - return; - } - - ++m_waiting; - --m_blocked; - } - else - { - lStatus = safe_wait_on_semaphore(m_gate, kDurationForever); - assert(lStatus == noErr); - if (m_blocked > m_gone) - { - if (m_gone != 0) - { - m_blocked -= m_gone; - m_gone = 0; - } - signals = m_waiting = 1; - --m_blocked; - } - else - { - lStatus = MPSignalSemaphore(m_gate); - assert(lStatus == noErr); - } - - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - - while (signals) - { - lStatus = MPSignalSemaphore(m_queue); - assert(lStatus == noErr); - --signals; - } - } -} - -void condition_impl::notify_all() -{ - unsigned signals = 0; - - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); - - if (m_waiting != 0) // the m_gate is already closed - { - if (m_blocked == 0) - { - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - return; - } - - m_waiting += (signals = m_blocked); - m_blocked = 0; - } - else - { - lStatus = safe_wait_on_semaphore(m_gate, kDurationForever); - assert(lStatus == noErr); - if (m_blocked > m_gone) - { - if (m_gone != 0) - { - m_blocked -= m_gone; - m_gone = 0; - } - signals = m_waiting = m_blocked; - m_blocked = 0; - } - else - { - lStatus = MPSignalSemaphore(m_gate); - assert(lStatus == noErr); - } - - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - - while (signals) - { - lStatus = MPSignalSemaphore(m_queue); - assert(lStatus == noErr); - --signals; - } - } -} - -void condition_impl::enter_wait() -{ - OSStatus lStatus = noErr; - lStatus = safe_wait_on_semaphore(m_gate, kDurationForever); - assert(lStatus == noErr); - ++m_blocked; - lStatus = MPSignalSemaphore(m_gate); - assert(lStatus == noErr); -} - -void condition_impl::do_wait() -{ - OSStatus lStatus = noErr; - lStatus = safe_wait_on_semaphore(m_queue, kDurationForever); - assert(lStatus == noErr); - - unsigned was_waiting=0; - unsigned was_gone=0; - - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); - was_waiting = m_waiting; - was_gone = m_gone; - if (was_waiting != 0) - { - if (--m_waiting == 0) - { - if (m_blocked != 0) - { - lStatus = MPSignalSemaphore(m_gate); // open m_gate - assert(lStatus == noErr); - was_waiting = 0; - } - else if (m_gone != 0) - m_gone = 0; - } - } - else if (++m_gone == ((std::numeric_limits::max)() / 2)) - { - // timeout occured, normalize the m_gone count - // this may occur if many calls to wait with a timeout are made and - // no call to notify_* is made - lStatus = safe_wait_on_semaphore(m_gate, kDurationForever); - assert(lStatus == noErr); - m_blocked -= m_gone; - lStatus = MPSignalSemaphore(m_gate); - assert(lStatus == noErr); - m_gone = 0; - } - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - - if (was_waiting == 1) - { - for (/**/ ; was_gone; --was_gone) - { - // better now than spurious later - lStatus = safe_wait_on_semaphore(m_queue, kDurationForever); - assert(lStatus == noErr); - } - lStatus = MPSignalSemaphore(m_gate); - assert(lStatus == noErr); - } -} - -bool condition_impl::do_timed_wait(const xtime& xt) -{ - int milliseconds; - to_duration(xt, milliseconds); - - OSStatus lStatus = noErr; - lStatus = safe_wait_on_semaphore(m_queue, milliseconds); - assert(lStatus == noErr || lStatus == kMPTimeoutErr); - - bool ret = (lStatus == noErr); - - unsigned was_waiting=0; - unsigned was_gone=0; - - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); - was_waiting = m_waiting; - was_gone = m_gone; - if (was_waiting != 0) - { - if (!ret) // timeout - { - if (m_blocked != 0) - --m_blocked; - else - ++m_gone; // count spurious wakeups - } - if (--m_waiting == 0) - { - if (m_blocked != 0) - { - lStatus = MPSignalSemaphore(m_gate); // open m_gate - assert(lStatus == noErr); - was_waiting = 0; - } - else if (m_gone != 0) - m_gone = 0; - } - } - else if (++m_gone == ((std::numeric_limits::max)() / 2)) - { - // timeout occured, normalize the m_gone count - // this may occur if many calls to wait with a timeout are made and - // no call to notify_* is made - lStatus = safe_wait_on_semaphore(m_gate, kDurationForever); - assert(lStatus == noErr); - m_blocked -= m_gone; - lStatus = MPSignalSemaphore(m_gate); - assert(lStatus == noErr); - m_gone = 0; - } - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - - if (was_waiting == 1) - { - for (/**/ ; was_gone; --was_gone) - { - // better now than spurious later - lStatus = safe_wait_on_semaphore(m_queue, kDurationForever); - assert(lStatus == noErr); - } - lStatus = MPSignalSemaphore(m_gate); - assert(lStatus == noErr); - } - - return ret; -} -#endif - -} // namespace detail - -} // namespace boost - -// Change Log: -// 8 Feb 01 WEKEMPF Initial version. -// 22 May 01 WEKEMPF Modified to use xtime for time outs. -// 3 Jan 03 WEKEMPF Modified for DLL implementation. diff --git a/src/mac/debug_prefix.hpp b/src/mac/debug_prefix.hpp deleted file mode 100644 index 08202289..00000000 --- a/src/mac/debug_prefix.hpp +++ /dev/null @@ -1,8 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#define TARGET_CARBON 1 diff --git a/src/mac/delivery_man.cpp b/src/mac/delivery_man.cpp deleted file mode 100644 index a1ab0381..00000000 --- a/src/mac/delivery_man.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#include "delivery_man.hpp" - -#include "os.hpp" -#include "execution_context.hpp" - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -delivery_man::delivery_man(): - m_pPackage(NULL), - m_pSemaphore(kInvalidID), - m_bPackageWaiting(false) -{ - assert(at_st()); - - OSStatus lStatus = MPCreateSemaphore(1UL, 0UL, &m_pSemaphore); -// TODO - throw on error here - assert(lStatus == noErr); -} - -delivery_man::~delivery_man() -{ - assert(m_bPackageWaiting == false); - - OSStatus lStatus = MPDeleteSemaphore(m_pSemaphore); - assert(lStatus == noErr); -} - - -void delivery_man::accept_deliveries() -{ - if(m_bPackageWaiting) - { - assert(m_pPackage != NULL); - m_pPackage->accept(); - m_pPackage = NULL; - m_bPackageWaiting = false; - - // signal to the thread making the call that we're done - OSStatus lStatus = MPSignalSemaphore(m_pSemaphore); - assert(lStatus == noErr); - } -} - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost diff --git a/src/mac/delivery_man.hpp b/src/mac/delivery_man.hpp deleted file mode 100644 index c03173ed..00000000 --- a/src/mac/delivery_man.hpp +++ /dev/null @@ -1,84 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#ifndef BOOST_DELIVERY_MAN_MJM012402_HPP -#define BOOST_DELIVERY_MAN_MJM012402_HPP - - -#include -#include - -#include - -#include "package.hpp" - -#include - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -// class delivery_man is intended to move boost::function objects from MP tasks to -// other execution contexts (such as deferred task time or system task time). - -class delivery_man: private noncopyable -{ - public: - delivery_man(); - ~delivery_man(); - - public: - template - R deliver(function &rFunctor); - - void accept_deliveries(); - - private: - base_package *m_pPackage; - mutex m_oMutex; - MPSemaphoreID m_pSemaphore; - bool m_bPackageWaiting; -}; - - -template -R delivery_man::deliver(function &rFunctor) -{ - assert(at_mp()); - -// lock our mutex - mutex::scoped_lock oLock(m_oMutex); - -// create a package and save it - package oPackage(rFunctor); - m_pPackage = &oPackage; - m_bPackageWaiting = true; - -// wait on the semaphore - OSStatus lStatus = MPWaitOnSemaphore(m_pSemaphore, kDurationForever); - assert(lStatus == noErr); - - return(oPackage.return_value()); -} - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost - - -#endif // BOOST_DELIVERY_MAN_MJM012402_HPP diff --git a/src/mac/dt_scheduler.cpp b/src/mac/dt_scheduler.cpp deleted file mode 100644 index 9c626a95..00000000 --- a/src/mac/dt_scheduler.cpp +++ /dev/null @@ -1,93 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#include "dt_scheduler.hpp" - -#include "ot_context.hpp" - - -#include - -#include - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -const OTTimeout k_ulTimerTaskDelay = 1UL; - - -dt_scheduler::dt_scheduler(): - m_bReschedule(false), - m_uppTask(NULL), - m_lTask(0UL) -{ - using ::boost::detail::thread::singleton; - - ot_context &rContext(singleton::instance()); - - m_uppTask = NewOTProcessUPP(task_entry); - m_lTask = OTCreateTimerTaskInContext(m_uppTask, this, rContext.get_context()); -} - -dt_scheduler::~dt_scheduler() -{ - OTDestroyTimerTask(m_lTask); - m_lTask = 0UL; - DisposeOTProcessUPP(m_uppTask); - m_uppTask = NULL; -} - - -void dt_scheduler::start_polling() -{ - m_bReschedule = true; - schedule_task(); -} - -void dt_scheduler::stop_polling() -{ - m_bReschedule = false; -} - - -void dt_scheduler::schedule_task() -{ - if(m_bReschedule) - { - OTScheduleTimerTask(m_lTask, k_ulTimerTaskDelay); - } -} - - -/*static*/ pascal void dt_scheduler::task_entry(void *pRefCon) -{ - dt_scheduler *pThis = reinterpret_cast(pRefCon); - assert(pThis != NULL); - pThis->task(); -} - -void dt_scheduler::task() -{ - periodic_function(); - schedule_task(); -} - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost diff --git a/src/mac/dt_scheduler.hpp b/src/mac/dt_scheduler.hpp deleted file mode 100644 index 6d91b0be..00000000 --- a/src/mac/dt_scheduler.hpp +++ /dev/null @@ -1,63 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#ifndef BOOST_DT_SCHEDULER_MJM012402_HPP -#define BOOST_DT_SCHEDULER_MJM012402_HPP - - -#include "periodical.hpp" - -#include - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -// class dt_scheduler calls its pure-virtual periodic_function method periodically at -// deferred task time. This is generally 1kHz under Mac OS 9. - -class dt_scheduler -{ - public: - dt_scheduler(); - virtual ~dt_scheduler(); - - protected: - void start_polling(); - void stop_polling(); - - private: - virtual void periodic_function() = 0; - - private: - void schedule_task(); - static pascal void task_entry(void *pRefCon); - void task(); - - private: - bool m_bReschedule; - OTProcessUPP m_uppTask; - long m_lTask; -}; - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost - - -#endif // BOOST_DT_SCHEDULER_MJM012402_HPP diff --git a/src/mac/execution_context.cpp b/src/mac/execution_context.cpp deleted file mode 100644 index 5bc81472..00000000 --- a/src/mac/execution_context.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#include -#include - -#include "execution_context.hpp" -#include "init.hpp" - - -namespace boost { - -namespace threads { - -namespace mac { - - -execution_context_t execution_context() -{ -// make sure that MP services are available the first time through - static bool bIgnored = detail::thread_init(); - -// first check if we're an MP task - if(MPTaskIsPreemptive(kInvalidID)) - { - return(k_eExecutionContextMPTask); - } - -#if TARGET_CARBON -// Carbon has TaskLevel - UInt32 ulLevel = TaskLevel(); - - if(ulLevel == 0UL) - { - return(k_eExecutionContextSystemTask); - } - - if(ulLevel & kInDeferredTaskMask) - { - return(k_eExecutionContextDeferredTask); - } - - return(k_eExecutionContextOther); -#else -// this can be implemented using TaskLevel if you don't mind linking against -// DebugLib (and therefore breaking Mac OS 8.6 support), or CurrentExecutionLevel. -# error execution_context unimplimented -#endif -} - - -} // namespace mac - -} // namespace threads - -} // namespace boost diff --git a/src/mac/execution_context.hpp b/src/mac/execution_context.hpp deleted file mode 100644 index 162a2a75..00000000 --- a/src/mac/execution_context.hpp +++ /dev/null @@ -1,47 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#ifndef BOOST_EXECUTION_CONTEXT_MJM012402_HPP -#define BOOST_EXECUTION_CONTEXT_MJM012402_HPP - -namespace boost { - -namespace threads { - -namespace mac { - - -// utility functions for figuring out what context your code is executing in. -// Bear in mind that at_mp and in_blue are the only functions guarenteed by -// Apple to work. There is simply no way of being sure that you will not get -// false readings about task level at interrupt time in blue. - -typedef enum { - k_eExecutionContextSystemTask, - k_eExecutionContextDeferredTask, - k_eExecutionContextMPTask, - k_eExecutionContextOther -} execution_context_t; - -execution_context_t execution_context(); - -inline bool at_st() - { return(execution_context() == k_eExecutionContextSystemTask); } - -inline bool at_mp() - { return(execution_context() == k_eExecutionContextMPTask); } -inline bool in_blue() - { return(!at_mp()); } - - -} // namespace mac - -} // namespace threads - -} // namespace boost - -#endif // BOOST_EXECUTION_CONTEXT_MJM012402_HPP diff --git a/src/mac/init.cpp b/src/mac/init.cpp deleted file mode 100644 index 82006ae3..00000000 --- a/src/mac/init.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#include "init.hpp" - -#include "remote_call_manager.hpp" - - -#include - -#include - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -namespace { - -// force these to get called by the end of static initialization time. -static bool g_bInitialized = (thread_init() && create_singletons()); - -} - - -bool thread_init() -{ - static bool bResult = MPLibraryIsLoaded(); - - return(bResult); -} - -bool create_singletons() -{ - using ::boost::detail::thread::singleton; - - singleton::instance(); - - return(true); -} - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost diff --git a/src/mac/init.hpp b/src/mac/init.hpp deleted file mode 100644 index 77a3211e..00000000 --- a/src/mac/init.hpp +++ /dev/null @@ -1,34 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#ifndef BOOST_INIT_MJM012402_HPP -#define BOOST_INIT_MJM012402_HPP - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -bool thread_init(); -bool create_singletons(); - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost - - -#endif // BOOST_INIT_MJM012402_HPP diff --git a/src/mac/msl_replacements/assert.cpp b/src/mac/msl_replacements/assert.cpp deleted file mode 100644 index d34b4098..00000000 --- a/src/mac/msl_replacements/assert.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#include -#include - -#include - -#include "remote_calls.hpp" - -// this function will be called when an assertion fails. We redirect the assertion -// to DebugStr (MacsBug under Mac OS 1.x-9.x, Console under Mac OS X). -void __assertion_failed(char const *pszAssertion, char const *pszFile, int nLine) -{ - using std::snprintf; - unsigned char strlDebug[sizeof(Str255) + 1]; - char *pszDebug = reinterpret_cast(&strlDebug[1]); - strlDebug[0] = snprintf(pszDebug, sizeof(Str255), "assertion failed: \"%s\", %s, line %d", pszAssertion, pszFile, nLine); - boost::threads::mac::dt_remote_call(DebugStr, static_cast(strlDebug)); -} diff --git a/src/mac/msl_replacements/console_io.cpp b/src/mac/msl_replacements/console_io.cpp deleted file mode 100644 index 7ac82207..00000000 --- a/src/mac/msl_replacements/console_io.cpp +++ /dev/null @@ -1,128 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -// -// includes -// - -#include -#include -#include -#include -#include - -#include "remote_calls.hpp" - - -// -// using declarations -// - -using std::__file_handle; -using std::__idle_proc; -using std::__io_error; -using std::__no_io_error; -using std::size_t; - -using boost::threads::mac::st_remote_call; - - -// -// prototypes -// - -static bool check_console(); -static int do_read_console(__file_handle ulHandle, unsigned char *pBuffer, size_t *pCount, __idle_proc pfnIdleProc); -static int do_write_console(__file_handle ulHandle, unsigned char *pBuffer, size_t *pCount, __idle_proc pfnIdleProc); - - -// -// MSL function replacements -// - -// these two functions are called by cin and cout, respectively, as well as by (all?) -// other functions in MSL that do console I/O. All that they do is as the remote -// call manager to ensure that their guts are called at system task time. -int __read_console(__file_handle handle, unsigned char * buffer, size_t * count, __idle_proc idle_proc) -{ - return(st_remote_call(do_read_console, handle, buffer, count, idle_proc)); -} - -int __write_console(__file_handle handle, unsigned char * buffer, size_t * count, __idle_proc idle_proc) -{ - return(st_remote_call(do_write_console, handle, buffer, count, idle_proc)); -} - - -// -// implementations -// - -static bool check_console() -{ - static bool s_bHaveConsole(false); - static bool s_bWontHaveConsole(false); - - if(s_bHaveConsole) - { - return(true); - } - - if(s_bWontHaveConsole == false) - { - __stdio_atexit(); - - if(InstallConsole(0) != 0) - { - s_bWontHaveConsole = true; - return(false); - } - __console_exit = RemoveConsole; - s_bHaveConsole = true; - return(true); - } - - return(false); -} - - -int do_read_console(__file_handle /*ulHandle*/, unsigned char *pBuffer, size_t *pCount, __idle_proc /*pfnIdleProc*/) -{ - assert(pCount != NULL); - assert(pBuffer != NULL || *pCount == 0UL); - - if(check_console() == false) - { - return(__io_error); - } - std::fflush(stdout); - long lCount = ReadCharsFromConsole(reinterpret_cast(pBuffer), static_cast(*pCount)); - *pCount = static_cast(lCount); - if(lCount == -1L) - { - return(__io_error); - } - - return(__no_io_error); -} - -int do_write_console(__file_handle /*ulHandle*/, unsigned char *pBuffer, size_t *pCount, __idle_proc /*pfnIdleProc*/) -{ - if(check_console() == false) - { - return(__io_error); - } - - long lCount = WriteCharsToConsole(reinterpret_cast(pBuffer), static_cast(*pCount)); - *pCount = static_cast(lCount); - if(lCount == -1L) - { - return(__io_error); - } - - return(__no_io_error); -} diff --git a/src/mac/msl_replacements/malloc.cpp b/src/mac/msl_replacements/malloc.cpp deleted file mode 100644 index da6d258a..00000000 --- a/src/mac/msl_replacements/malloc.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -// -// includes -// - -#include - -#include - - -// -// using declarations -// - -using std::size_t; - - -extern "C" { - -// -// prototypes -// - -void *malloc(size_t ulSize); -void free(void *pBlock); - -} - - -// -// MSL function replacements -// - -// all allocation/deallocation currently goes through MPAllocateAligned/MPFree. This -// solution is sub-optimal at best, but will have to do for now. -void *malloc(size_t ulSize) -{ - static bool bIgnored = MPLibraryIsLoaded(); - return(MPAllocateAligned(ulSize, kMPAllocateDefaultAligned, 0UL)); -} - -void free(void *pBlock) -{ - if(pBlock == NULL) return; - MPFree(pBlock); -} diff --git a/src/mac/msl_replacements/news_and_deletes.cpp b/src/mac/msl_replacements/news_and_deletes.cpp deleted file mode 100644 index ba14cd1e..00000000 --- a/src/mac/msl_replacements/news_and_deletes.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -// -// includes -// - -#include - -#include - - -// -// using declarations -// - -using std::size_t; -using std::bad_alloc; -using std::nothrow_t; -using std::nothrow; - - -// -// local utility functions -// - -// all allocation/deallocation currently goes through MPAllocateAligned/MPFree. This -// solution is sub-optimal at best, but will have to do for now. -inline static void *allocate(size_t ulSize, const nothrow_t &) -{ - static bool bIgnored = MPLibraryIsLoaded(); - return(MPAllocateAligned(ulSize, kMPAllocateDefaultAligned, 0UL)); -} - -inline static void *allocate(size_t ulSize) -{ - void *pBlock = allocate(ulSize, nothrow); - if(pBlock == NULL) - throw(bad_alloc()); - return(pBlock); -} - -inline static void deallocate(void *pBlock) -{ - if(pBlock == NULL) return; - MPFree(pBlock); -} - - -// -// global operators -// - -void *operator new(size_t ulSize) -{ - return(allocate(ulSize)); -} - -void *operator new[](size_t ulSize) -{ - return(allocate(ulSize)); -} - - -void *operator new(size_t ulSize, const nothrow_t &rNoThrow) -{ - return(allocate(ulSize, rNoThrow)); -} - -void *operator new[](size_t ulSize, const nothrow_t &rNoThrow) -{ - return(allocate(ulSize, rNoThrow)); -} - - -void operator delete(void *pBlock) -{ - deallocate(pBlock); -} - -void operator delete[](void *pBlock) -{ - deallocate(pBlock); -} - - -void operator delete(void *pBlock, const nothrow_t &) -{ - deallocate(pBlock); -} - -void operator delete[](void *pBlock, const nothrow_t &) -{ - deallocate(pBlock); -} diff --git a/src/mac/msl_replacements/time.cpp b/src/mac/msl_replacements/time.cpp deleted file mode 100644 index 9100a9c2..00000000 --- a/src/mac/msl_replacements/time.cpp +++ /dev/null @@ -1,150 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#include -// we include timesize.mac.h to get whether or not __TIMESIZE_DOUBLE__ is -// defined. This is not safe, given that __TIMESIZE_DOUBLE__ affects MSL -// at MSL's compile time, not ours, so be forgiving if you have changed it -// since you have built MSL. -#include -#include - -#include -#include - -#include "execution_context.hpp" - -#include - - -extern "C" -{ - clock_t __get_clock(); - time_t __get_time(); - int __to_gm_time(time_t *pTime); - int __is_dst(); -} - - -static inline uint64_t get_nanoseconds() -{ - using boost::detail::thread::force_cast; - return(force_cast(AbsoluteToNanoseconds(UpTime()))); -} - - -#ifdef __TIMESIZE_DOUBLE__ - -// return number of microseconds since startup as a double -clock_t __get_clock() -{ - static const double k_dNanosecondsPerMicrosecond(1000.0); - - return(get_nanoseconds() / k_dNanosecondsPerMicrosecond); -} - -#else - -// return number of ticks (60th of a second) since startup as a long -clock_t __get_clock() -{ - static const uint64_t k_ullTicksPerSecond(60ULL); - static const uint64_t k_ullNanosecondsPerSecond(1000ULL * 1000ULL * 1000ULL); - static const uint64_t k_ullNanosecondsPerTick(k_ullNanosecondsPerSecond / k_ullTicksPerSecond); - - return(get_nanoseconds() / k_ullNanosecondsPerTick); -} - -#endif - -// return number of seconds elapsed since Jan 1, 1970 -time_t __get_time() -{ - boost::xtime sTime; - int nType = boost::xtime_get(&sTime, boost::TIME_UTC); - assert(nType == boost::TIME_UTC); - return(static_cast(sTime.sec)); -} - - -static inline MachineLocation &read_location() -{ - static MachineLocation s_sLocation; - assert(boost::threads::mac::at_st()); - ReadLocation(&s_sLocation); - return(s_sLocation); -} - -static inline MachineLocation &get_location() -{ - static MachineLocation &s_rLocation(read_location()); - return(s_rLocation); -} - - -// force the machine location to be cached at static initlialization -static MachineLocation &g_rIgnored(get_location()); - -static inline long calculate_delta() -{ - MachineLocation &rLocation(get_location()); - -// gmtDelta is a 24-bit, signed integer. We need to strip out the lower 24 bits, -// then sign-extend what we have. - long lDelta = rLocation.u.gmtDelta & 0x00ffffffL; - if((lDelta & 0x00800000L) != 0L) - { - lDelta |= 0xFF000000; - } - return(lDelta); -} - -static inline bool check_if_location_is_broken() -{ - MachineLocation &rLocation(get_location()); - if(rLocation.latitude == 0 && rLocation.longitude == 0 && rLocation.u.gmtDelta == 0) - return(true); - return(false); -} - -static inline bool location_is_broken() -{ - static bool s_bLocationIsBroken(check_if_location_is_broken()); - return(s_bLocationIsBroken); -} - - -// translate time to GMT -int __to_gm_time(time_t *pTime) -{ - if(location_is_broken()) - { - return(0); - } - - static long s_lDelta(calculate_delta()); - *pTime -= s_lDelta; - return(1); -} - - -static inline bool is_daylight_savings_time() -{ - MachineLocation &rLocation(get_location()); - return(rLocation.u.dlsDelta != 0); -} - -// check if we're in daylight savings time -int __is_dst() -{ - if(location_is_broken()) - { - return(-1); - } - static bool bIsDaylightSavingsTime(is_daylight_savings_time()); - return(static_cast(bIsDaylightSavingsTime)); -} diff --git a/src/mac/os.cpp b/src/mac/os.cpp deleted file mode 100644 index 6a47d178..00000000 --- a/src/mac/os.cpp +++ /dev/null @@ -1,57 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#include "os.hpp" - - -#include - -#include - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace os { - - -// read the OS version from Gestalt -static inline long get_version() -{ - long lVersion; - OSErr nErr = Gestalt(gestaltSystemVersion, &lVersion); - assert(nErr == noErr); - return(lVersion); -} - - -// check if we're running under Mac OS X and cache that information -bool x() -{ - static bool bX = (version() >= 0x1000); - return(bX); -} - - -// read the OS version and cache it -long version() -{ - static long lVersion = get_version(); - return(lVersion); -} - - -} // namespace os - -} // namespace mac - -} // namespace threads - -} // namespace boost diff --git a/src/mac/os.hpp b/src/mac/os.hpp deleted file mode 100644 index c631ca1d..00000000 --- a/src/mac/os.hpp +++ /dev/null @@ -1,37 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#ifndef BOOST_OS_MJM012402_HPP -#define BOOST_OS_MJM012402_HPP - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace os { - - -// functions to determine the OS environment. With namespaces, you get a cute call: -// mac::os::x - -bool x(); -long version(); - - -} // namespace os - -} // namespace mac - -} // namespace threads - -} // namespace boost - - -#endif // BOOST_OS_MJM012402_HPP diff --git a/src/mac/ot_context.cpp b/src/mac/ot_context.cpp deleted file mode 100644 index de61e6f8..00000000 --- a/src/mac/ot_context.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#include "ot_context.hpp" - -#include "execution_context.hpp" - - -#include - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -ot_context::ot_context() -{ - assert(at_st()); - - OSStatus lStatus = InitOpenTransportInContext(0UL, &m_pContext); -// TODO - throw on error - assert(lStatus == noErr); -} - -ot_context::~ot_context() -{ - CloseOpenTransportInContext(m_pContext); -} - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost diff --git a/src/mac/ot_context.hpp b/src/mac/ot_context.hpp deleted file mode 100644 index 0d640105..00000000 --- a/src/mac/ot_context.hpp +++ /dev/null @@ -1,58 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#ifndef BOOST_OT_CONTEXT_MJM012402_HPP -#define BOOST_OT_CONTEXT_MJM012402_HPP - - -#include - -#include - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -// class ot_context is intended to be used only as a singleton. All that this class -// does is ask OpenTransport to create him an OTClientContextPtr, and then doles -// this out to anyone who wants it. ot_context should only be instantiated at -// system task time. - -class ot_context: private noncopyable -{ - protected: - ot_context(); - ~ot_context(); - - public: - OTClientContextPtr get_context(); - - private: - OTClientContextPtr m_pContext; -}; - - -inline OTClientContextPtr ot_context::get_context() - { return(m_pContext); } - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost - - -#endif // BOOST_OT_CONTEXT_MJM012402_HPP diff --git a/src/mac/package.hpp b/src/mac/package.hpp deleted file mode 100644 index a52d7a51..00000000 --- a/src/mac/package.hpp +++ /dev/null @@ -1,76 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#ifndef BOOST_PACKAGE_MJM012402_HPP -#define BOOST_PACKAGE_MJM012402_HPP - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -class base_package: private noncopyable -{ - public: - virtual void accept() = 0; -}; - -template -class package: public base_package -{ - public: - inline package(function &rFunctor): - m_rFunctor(rFunctor) - { /* no-op */ } - inline ~package() - { /* no-op */ } - - virtual void accept() - { m_oR = m_rFunctor(); } - inline R return_value() - { return(m_oR); } - - private: - function &m_rFunctor; - R m_oR; -}; - -template<> -class package: public base_package -{ - public: - inline package(function &rFunctor): - m_rFunctor(rFunctor) - { /* no-op */ } - inline ~package() - { /* no-op */ } - - virtual void accept() - { m_rFunctor(); } - inline void return_value() - { return; } - - private: - function &m_rFunctor; -}; - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost - - -#endif // BOOST_PACKAGE_MJM012402_HPP diff --git a/src/mac/periodical.hpp b/src/mac/periodical.hpp deleted file mode 100644 index 7eb3d552..00000000 --- a/src/mac/periodical.hpp +++ /dev/null @@ -1,97 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#ifndef BOOST_PERIODICAL_MJM012402_HPP -#define BOOST_PERIODICAL_MJM012402_HPP - - -#include -#include - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -// class periodical inherits from its template parameter, which should follow the -// pattern set by classes dt_scheduler and st_scheduler. periodical knows how to -// call a boost::function, where the xx_scheduler classes only know to to call a -// member periodically. - -template -class periodical: private noncopyable, private Scheduler -{ - public: - periodical(function &rFunction); - ~periodical(); - - public: - void start(); - void stop(); - - protected: - virtual void periodic_function(); - - private: - function m_oFunction; -}; - - -template -periodical::periodical(function &rFunction): - m_oFunction(rFunction) -{ -// no-op -} - -template -periodical::~periodical() -{ - stop(); -} - -template -void periodical::start() -{ - start_polling(); -} - -template -void periodical::stop() -{ - stop_polling(); -} - - -template -inline void periodical::periodic_function() -{ - try - { - m_oFunction(); - } - catch(...) - { - } -} - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost - - -#endif // BOOST_PERIODICAL_MJM012402_HPP diff --git a/src/mac/prefix.hpp b/src/mac/prefix.hpp deleted file mode 100644 index b96ce9c5..00000000 --- a/src/mac/prefix.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#define NDEBUG -#define TARGET_CARBON 1 diff --git a/src/mac/remote_call_manager.cpp b/src/mac/remote_call_manager.cpp deleted file mode 100644 index b7191eee..00000000 --- a/src/mac/remote_call_manager.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#include "remote_call_manager.hpp" - -#include - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -using detail::delivery_man; - - -remote_call_manager::remote_call_manager(): - m_oDTDeliveryMan(), - m_oSTDeliveryMan(), - m_oDTFunction(bind(&delivery_man::accept_deliveries, &m_oDTDeliveryMan)), - m_oSTFunction(bind(&delivery_man::accept_deliveries, &m_oSTDeliveryMan)), - m_oDTPeriodical(m_oDTFunction), - m_oSTPeriodical(m_oSTFunction) -{ - m_oDTPeriodical.start(); - m_oSTPeriodical.start(); -} - -remote_call_manager::~remote_call_manager() -{ -} - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost diff --git a/src/mac/remote_call_manager.hpp b/src/mac/remote_call_manager.hpp deleted file mode 100644 index 2f62c3d2..00000000 --- a/src/mac/remote_call_manager.hpp +++ /dev/null @@ -1,102 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#ifndef BOOST_REMOTE_CALL_MANAGER_MJM012402_HPP -#define BOOST_REMOTE_CALL_MANAGER_MJM012402_HPP - - -#include - -#include "delivery_man.hpp" -#include "dt_scheduler.hpp" -#include "periodical.hpp" -#include "execution_context.hpp" -#include "st_scheduler.hpp" - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -// class remote_call_manager is used by the remote call functions (dt_remote_call and -// st_remote_call) to execute functions in non-MP contexts. - -class remote_call_manager: private noncopyable -{ - protected: - remote_call_manager(); - ~remote_call_manager(); - - public: - template - R execute_at_dt(function &rFunctor); - template - R execute_at_st(function &rFunctor); - - private: - template - static R execute_now(function &rFunctor); - - private: - delivery_man m_oDTDeliveryMan; - delivery_man m_oSTDeliveryMan; - function m_oDTFunction; - function m_oSTFunction; - periodical m_oDTPeriodical; - periodical m_oSTPeriodical; -}; - - -template -/*static*/ inline R remote_call_manager::execute_now(function &rFunctor) -{ - return(rFunctor()); -} -template<> -/*static*/ inline void remote_call_manager::execute_now(function &rFunctor) -{ - rFunctor(); -} - - -template -inline R remote_call_manager::execute_at_dt(function &rFunctor) -{ - if(at_mp()) - { - return(m_oDTDeliveryMan.deliver(rFunctor)); - } - return(execute_now(rFunctor)); -} - -template -inline R remote_call_manager::execute_at_st(function &rFunctor) -{ - if(at_mp()) - { - return(m_oSTDeliveryMan.deliver(rFunctor)); - } - assert(at_st()); - return(execute_now(rFunctor)); -} - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost - - -#endif // BOOST_REMOTE_CALL_MANAGER_MJM012402_HPP diff --git a/src/mac/remote_calls.hpp b/src/mac/remote_calls.hpp deleted file mode 100644 index 41e67863..00000000 --- a/src/mac/remote_calls.hpp +++ /dev/null @@ -1,157 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#ifndef BOOST_REMOTE_CALLS_MJM012402_HPP -#define BOOST_REMOTE_CALLS_MJM012402_HPP - - -#include - -#include "remote_call_manager.hpp" -#include - - -// this file contains macros to generate functions with the signatures: -// ReturnType st_remote_call([pascal] ReturnType (*pfnFunction)( -// [Argument1Type[, Argument2Type[...]]]) -// [, Argument1Type oArgument1[, Argument2Type oArgument2[...]]]) -// and -// ReturnType dt_remote_call([pascal] ReturnType (*pfnFunction)( -// [Argument1Type[, Argument2Type[...]]]) -// [, Argument1Type oArgument1[, Argument2Type oArgument2[...]]]) -// in other words, identical to the function pointer versions of boost::bind, but -// with the return type returned. The purpose of these functions is to be able to -// request that a function be called at system task time or deferred task time, then -// sleep until it is called, and finally get back its return value. - -#define BOOST_REMOTE_CALL_CLASS_LIST_0 -#define BOOST_REMOTE_CALL_CLASS_LIST_1 BOOST_REMOTE_CALL_CLASS_LIST_0, class A1 -#define BOOST_REMOTE_CALL_CLASS_LIST_2 BOOST_REMOTE_CALL_CLASS_LIST_1, class A2 -#define BOOST_REMOTE_CALL_CLASS_LIST_3 BOOST_REMOTE_CALL_CLASS_LIST_2, class A3 -#define BOOST_REMOTE_CALL_CLASS_LIST_4 BOOST_REMOTE_CALL_CLASS_LIST_3, class A4 -#define BOOST_REMOTE_CALL_CLASS_LIST_5 BOOST_REMOTE_CALL_CLASS_LIST_4, class A5 -#define BOOST_REMOTE_CALL_CLASS_LIST_6 BOOST_REMOTE_CALL_CLASS_LIST_5, class A6 -#define BOOST_REMOTE_CALL_CLASS_LIST_7 BOOST_REMOTE_CALL_CLASS_LIST_6, class A7 -#define BOOST_REMOTE_CALL_CLASS_LIST_8 BOOST_REMOTE_CALL_CLASS_LIST_7, class A8 -#define BOOST_REMOTE_CALL_CLASS_LIST_9 BOOST_REMOTE_CALL_CLASS_LIST_8, class A9 - - -#define BOOST_REMOTE_CALL_ARGUMENT_LIST_0 -#define BOOST_REMOTE_CALL_ARGUMENT_LIST_1 BOOST_REMOTE_CALL_ARGUMENT_LIST_0 A1 oA1 -#define BOOST_REMOTE_CALL_ARGUMENT_LIST_2 BOOST_REMOTE_CALL_ARGUMENT_LIST_1, A2 oA2 -#define BOOST_REMOTE_CALL_ARGUMENT_LIST_3 BOOST_REMOTE_CALL_ARGUMENT_LIST_2, A3 oA3 -#define BOOST_REMOTE_CALL_ARGUMENT_LIST_4 BOOST_REMOTE_CALL_ARGUMENT_LIST_3, A4 oA4 -#define BOOST_REMOTE_CALL_ARGUMENT_LIST_5 BOOST_REMOTE_CALL_ARGUMENT_LIST_4, A5 oA5 -#define BOOST_REMOTE_CALL_ARGUMENT_LIST_6 BOOST_REMOTE_CALL_ARGUMENT_LIST_5, A6 oA6 -#define BOOST_REMOTE_CALL_ARGUMENT_LIST_7 BOOST_REMOTE_CALL_ARGUMENT_LIST_6, A7 oA7 -#define BOOST_REMOTE_CALL_ARGUMENT_LIST_8 BOOST_REMOTE_CALL_ARGUMENT_LIST_7, A8 oA8 -#define BOOST_REMOTE_CALL_ARGUMENT_LIST_9 BOOST_REMOTE_CALL_ARGUMENT_LIST_8, A9 oA9 - - -#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_0 -#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_1 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_0, oA1 -#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_2 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_1, oA2 -#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_3 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_2, oA3 -#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_4 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_3, oA4 -#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_5 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_4, oA5 -#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_6 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_5, oA6 -#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_7 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_6, oA7 -#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_8 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_7, oA8 -#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_9 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_8, oA9 - - -#define BOOST_REMOTE_CALL_COMMA_0 -#define BOOST_REMOTE_CALL_COMMA_1 , -#define BOOST_REMOTE_CALL_COMMA_2 , -#define BOOST_REMOTE_CALL_COMMA_3 , -#define BOOST_REMOTE_CALL_COMMA_4 , -#define BOOST_REMOTE_CALL_COMMA_5 , -#define BOOST_REMOTE_CALL_COMMA_6 , -#define BOOST_REMOTE_CALL_COMMA_7 , -#define BOOST_REMOTE_CALL_COMMA_8 , -#define BOOST_REMOTE_CALL_COMMA_9 , - - -// this is the macro that ties it all together. From here, we generate all forms of -// dt_remote_call and st_remote_call. - -#define BOOST_REMOTE_CALL(context, stack, n) \ -template \ -inline R context ## _remote_call(stack R (*pfnF)( \ - BOOST_REMOTE_CALL_ARGUMENT_LIST_ ## n) \ - BOOST_REMOTE_CALL_COMMA_ ## n \ - BOOST_REMOTE_CALL_ARGUMENT_LIST_ ## n) \ -{ \ - using ::boost::detail::thread::singleton; \ - using detail::remote_call_manager; \ - function oFunc(bind(pfnF BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_ ## n)); \ - remote_call_manager &rManager(singleton::instance()); \ - return(rManager.execute_at_ ## context(oFunc)); \ -} - - -namespace boost { - -namespace threads { - -namespace mac { - - -BOOST_REMOTE_CALL(st, , 0) -BOOST_REMOTE_CALL(st, , 1) -BOOST_REMOTE_CALL(st, , 2) -BOOST_REMOTE_CALL(st, , 3) -BOOST_REMOTE_CALL(st, , 4) -BOOST_REMOTE_CALL(st, , 5) -BOOST_REMOTE_CALL(st, , 6) -BOOST_REMOTE_CALL(st, , 7) -BOOST_REMOTE_CALL(st, , 8) -BOOST_REMOTE_CALL(st, , 9) - -BOOST_REMOTE_CALL(dt, , 0) -BOOST_REMOTE_CALL(dt, , 1) -BOOST_REMOTE_CALL(dt, , 2) -BOOST_REMOTE_CALL(dt, , 3) -BOOST_REMOTE_CALL(dt, , 4) -BOOST_REMOTE_CALL(dt, , 5) -BOOST_REMOTE_CALL(dt, , 6) -BOOST_REMOTE_CALL(dt, , 7) -BOOST_REMOTE_CALL(dt, , 8) -BOOST_REMOTE_CALL(dt, , 9) - - -BOOST_REMOTE_CALL(st, pascal, 0) -BOOST_REMOTE_CALL(st, pascal, 1) -BOOST_REMOTE_CALL(st, pascal, 2) -BOOST_REMOTE_CALL(st, pascal, 3) -BOOST_REMOTE_CALL(st, pascal, 4) -BOOST_REMOTE_CALL(st, pascal, 5) -BOOST_REMOTE_CALL(st, pascal, 6) -BOOST_REMOTE_CALL(st, pascal, 7) -BOOST_REMOTE_CALL(st, pascal, 8) -BOOST_REMOTE_CALL(st, pascal, 9) - -BOOST_REMOTE_CALL(dt, pascal, 0) -BOOST_REMOTE_CALL(dt, pascal, 1) -BOOST_REMOTE_CALL(dt, pascal, 2) -BOOST_REMOTE_CALL(dt, pascal, 3) -BOOST_REMOTE_CALL(dt, pascal, 4) -BOOST_REMOTE_CALL(dt, pascal, 5) -BOOST_REMOTE_CALL(dt, pascal, 6) -BOOST_REMOTE_CALL(dt, pascal, 7) -BOOST_REMOTE_CALL(dt, pascal, 8) -BOOST_REMOTE_CALL(dt, pascal, 9) - - -} // namespace mac - -} // namespace threads - -} // namespace boost - - -#endif // BOOST_REMOTE_CALLS_MJM012402_HPP diff --git a/src/mac/safe.cpp b/src/mac/safe.cpp deleted file mode 100644 index 8c2cfc51..00000000 --- a/src/mac/safe.cpp +++ /dev/null @@ -1,210 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include "execution_context.hpp" - - -using boost::detail::thread::force_cast; - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -static OSStatus safe_wait(function &rFunction, Duration lDuration); - - -// we call WNE to allow tasks that own the resource the blue is waiting on system -// task time, in case they are blocked on an ST remote call (or a memory allocation -// for that matter). -static void idle() -{ - if(at_st()) - { - EventRecord sEvent; - bool bEvent = WaitNextEvent(0U, &sEvent, 0UL, NULL); - } -} - - -OSStatus safe_wait_on_semaphore(MPSemaphoreID pSemaphoreID, Duration lDuration) -{ - function oWaitOnSemaphore; - oWaitOnSemaphore = bind(MPWaitOnSemaphore, pSemaphoreID, _1); - return(safe_wait(oWaitOnSemaphore, lDuration)); -} - - -OSStatus safe_enter_critical_region(MPCriticalRegionID pCriticalRegionID, Duration lDuration, MPCriticalRegionID pCriticalRegionCriticalRegionID/* = kInvalidID*/) -{ - if(pCriticalRegionCriticalRegionID != kInvalidID) - { - if(at_mp()) - { - // enter the critical region's critical region - OSStatus lStatus = noErr; - AbsoluteTime sExpiration; - if(lDuration != kDurationImmediate && lDuration != kDurationForever) - { - sExpiration = AddDurationToAbsolute(lDuration, UpTime()); - } - lStatus = MPEnterCriticalRegion(pCriticalRegionCriticalRegionID, lDuration); - assert(lStatus == noErr || lStatus == kMPTimeoutErr); - if(lStatus == noErr) - { - // calculate a new duration - if(lDuration != kDurationImmediate && lDuration != kDurationForever) - { - // check if we have any time left - AbsoluteTime sUpTime(UpTime()); - if(force_cast(sExpiration) > force_cast(sUpTime)) - { - // reset our duration to our remaining time - lDuration = AbsoluteDeltaToDuration(sExpiration, sUpTime); - } - else - { - // no time left - lDuration = kDurationImmediate; - } - } - // if we entered the critical region, exit it again - lStatus = MPExitCriticalRegion(pCriticalRegionCriticalRegionID); - assert(lStatus == noErr); - } - else - { - // otherwise, give up - return(lStatus); - } - } - else - { - // if we're at system task time, try to enter the critical region's critical - // region until we succeed. MP tasks will block on this until we let it go. - OSStatus lStatus; - do - { - lStatus = MPEnterCriticalRegion(pCriticalRegionCriticalRegionID, kDurationImmediate); - } while(lStatus == kMPTimeoutErr); - assert(lStatus == noErr); - } - } - -// try to enter the critical region - function oEnterCriticalRegion; - oEnterCriticalRegion = bind(MPEnterCriticalRegion, pCriticalRegionID, _1); - OSStatus lStatus = safe_wait(oEnterCriticalRegion, lDuration); - -// if we entered the critical region's critical region to get the critical region, -// exit the critical region's critical region. - if(pCriticalRegionCriticalRegionID != kInvalidID && at_mp() == false) - { - lStatus = MPExitCriticalRegion(pCriticalRegionCriticalRegionID); - assert(lStatus == noErr); - } - return(lStatus); -} - -OSStatus safe_wait_on_queue(MPQueueID pQueueID, void **pParam1, void **pParam2, void **pParam3, Duration lDuration) -{ - function oWaitOnQueue; - oWaitOnQueue = bind(MPWaitOnQueue, pQueueID, pParam1, pParam2, pParam3, _1); - return(safe_wait(oWaitOnQueue, lDuration)); -} - -OSStatus safe_delay_until(AbsoluteTime *pWakeUpTime) -{ - if(execution_context() == k_eExecutionContextMPTask) - { - return(MPDelayUntil(pWakeUpTime)); - } - else - { - uint64_t ullWakeUpTime = force_cast(*pWakeUpTime); - - while(force_cast(UpTime()) < ullWakeUpTime) - { - idle(); - } - - return(noErr); - } -} - - -OSStatus safe_wait(function &rFunction, Duration lDuration) -{ - if(execution_context() == k_eExecutionContextMPTask) - { - return(rFunction(lDuration)); - } - else - { - uint64_t ullExpiration = 0ULL; - - // get the expiration time in UpTime units - if(lDuration == kDurationForever) - { - ullExpiration = (::std::numeric_limits::max)(); - } - else if(lDuration == kDurationImmediate) - { - ullExpiration = force_cast(UpTime()); - } - else - { - AbsoluteTime sExpiration = AddDurationToAbsolute(lDuration, UpTime()); - ullExpiration = force_cast(sExpiration); - } - - OSStatus lStatus; - bool bExpired = false; - - do - { - lStatus = rFunction(kDurationImmediate); -// mm - "if" #if 0'd out to allow task time to threads blocked on I/O -#if 0 - if(lStatus == kMPTimeoutErr) -#endif - { - idle(); - } - if(lDuration != kDurationForever) - { - bExpired = (force_cast(UpTime()) < ullExpiration); - } - } while(lStatus == kMPTimeoutErr && bExpired == false); - - return(lStatus); - } -} - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost diff --git a/src/mac/safe.hpp b/src/mac/safe.hpp deleted file mode 100644 index c0409fcb..00000000 --- a/src/mac/safe.hpp +++ /dev/null @@ -1,41 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#ifndef BOOST_SAFE_MJM012402_HPP -#define BOOST_SAFE_MJM012402_HPP - - -#include - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -// these functions are used to wain in an execution context-independent manor. All of these -// functions are both MP- and ST-safe. - -OSStatus safe_wait_on_semaphore(MPSemaphoreID pSemaphoreID, Duration lDuration); -OSStatus safe_enter_critical_region(MPCriticalRegionID pCriticalRegionID, Duration lDuration, MPCriticalRegionID pCriticalRegionCriticalRegionID = kInvalidID); -OSStatus safe_wait_on_queue(MPQueueID pQueueID, void **pParam1, void **pParam2, void **pParam3, Duration lDuration); -OSStatus safe_delay_until(AbsoluteTime *pWakeUpTime); - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost - -#endif // BOOST_SAFE_MJM012402_HPP diff --git a/src/mac/scoped_critical_region.cpp b/src/mac/scoped_critical_region.cpp deleted file mode 100644 index fa12b1d1..00000000 --- a/src/mac/scoped_critical_region.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#include "scoped_critical_region.hpp" - -#include "init.hpp" - - -#include - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -scoped_critical_region::scoped_critical_region(): - m_pCriticalRegionID(kInvalidID) -{ - static bool bIgnored = thread_init(); - OSStatus lStatus = MPCreateCriticalRegion(&m_pCriticalRegionID); - if(lStatus != noErr || m_pCriticalRegionID == kInvalidID) - throw(thread_resource_error()); -} - -scoped_critical_region::~scoped_critical_region() -{ - OSStatus lStatus = MPDeleteCriticalRegion(m_pCriticalRegionID); - assert(lStatus == noErr); -} - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost diff --git a/src/mac/scoped_critical_region.hpp b/src/mac/scoped_critical_region.hpp deleted file mode 100644 index 74ac9d83..00000000 --- a/src/mac/scoped_critical_region.hpp +++ /dev/null @@ -1,63 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#ifndef BOOST_SCOPED_CRITICAL_REGION_MJM012402_HPP -#define BOOST_SCOPED_CRITICAL_REGION_MJM012402_HPP - - -#include - -#include - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -// class scoped_critical_region probably needs a new name. Although the current name -// is accurate, it can be read to mean that a critical region is entered for the -// current scope. In reality, a critical region is _created_ for the current scope. -// This class is intended as a replacement for MPCriticalRegionID that will -// automatically create and dispose of itself. - -class scoped_critical_region -{ - public: - scoped_critical_region(); - ~scoped_critical_region(); - - public: - operator const MPCriticalRegionID &() const; - const MPCriticalRegionID &get() const; - - private: - MPCriticalRegionID m_pCriticalRegionID; -}; - - -// these are inlined for speed. -inline scoped_critical_region::operator const MPCriticalRegionID &() const - { return(m_pCriticalRegionID); } -inline const MPCriticalRegionID &scoped_critical_region::get() const - { return(m_pCriticalRegionID); } - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost - - -#endif // BOOST_SCOPED_CRITICAL_REGION_MJM012402_HPP diff --git a/src/mac/st_scheduler.cpp b/src/mac/st_scheduler.cpp deleted file mode 100644 index 8dfc37ad..00000000 --- a/src/mac/st_scheduler.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#include "st_scheduler.hpp" - -#include - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -#if TARGET_CARBON - -st_scheduler::st_scheduler(): - m_uppTask(NULL), - m_pTimer(NULL) -{ - m_uppTask = NewEventLoopTimerUPP(task_entry); -// TODO - throw on error - assert(m_uppTask != NULL); -} - -st_scheduler::~st_scheduler() -{ - DisposeEventLoopTimerUPP(m_uppTask); - m_uppTask = NULL; -} - - -void st_scheduler::start_polling() -{ - assert(m_pTimer == NULL); - OSStatus lStatus = InstallEventLoopTimer(GetMainEventLoop(), - 0 * kEventDurationSecond, - kEventDurationMillisecond, - m_uppTask, - this, - &m_pTimer); -// TODO - throw on error - assert(lStatus == noErr); -} - -void st_scheduler::stop_polling() -{ - assert(m_pTimer != NULL); - OSStatus lStatus = RemoveEventLoopTimer(m_pTimer); - assert(lStatus == noErr); - m_pTimer = NULL; -} - - -/*static*/ pascal void st_scheduler::task_entry(EventLoopTimerRef /*pTimer*/, void *pRefCon) -{ - st_scheduler *pThis = reinterpret_cast(pRefCon); - assert(pThis != NULL); - pThis->task(); -} - -void st_scheduler::task() -{ - periodic_function(); -} - -#else -# error st_scheduler unimplemented! -#endif - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost diff --git a/src/mac/st_scheduler.hpp b/src/mac/st_scheduler.hpp deleted file mode 100644 index becf1c79..00000000 --- a/src/mac/st_scheduler.hpp +++ /dev/null @@ -1,67 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#ifndef BOOST_ST_SCHEDULER_MJM012402_HPP -#define BOOST_ST_SCHEDULER_MJM012402_HPP - - -#include - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -// class st_scheduler calls its pure-virtual periodic_function method periodically at -// system task time. This is generally 40Hz under Mac OS 9. - -class st_scheduler -{ - public: - st_scheduler(); - virtual ~st_scheduler(); - - protected: - void start_polling(); - void stop_polling(); - - private: - virtual void periodic_function() = 0; - -#if TARGET_CARBON -// use event loop timers under Carbon - private: - static pascal void task_entry(EventLoopTimerRef pTimer, void *pRefCon); - void task(); - - private: - EventLoopTimerUPP m_uppTask; - EventLoopTimerRef m_pTimer; -#else -// this can be implemented using OT system tasks. This would be mostly a copy-and- -// paste of the dt_scheduler code, replacing DeferredTask with SystemTask and DT -// with ST. -# error st_scheduler unimplemented! -#endif -}; - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost - - -#endif // BOOST_ST_SCHEDULER_MJM012402_HPP diff --git a/src/mac/thread_cleanup.cpp b/src/mac/thread_cleanup.cpp deleted file mode 100644 index 478b4fe7..00000000 --- a/src/mac/thread_cleanup.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#include "thread_cleanup.hpp" - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -namespace { - -TaskStorageIndex g_ulIndex(0UL); - -} // anonymous namespace - - -void do_thread_startup() -{ - if(g_ulIndex == 0UL) - { - OSStatus lStatus = MPAllocateTaskStorageIndex(&g_ulIndex); - assert(lStatus == noErr); - } - set_thread_cleanup_task(NULL); -} - -void do_thread_cleanup() -{ - void (*pfnTask)() = MPGetTaskValue(g_ulIndex) -} - - -void set_thread_cleanup_task(void (*pfnTask)()) -{ - lStatus = MPSetTaskValue(g_ulIndex, reinterpret_cast(pfnTask)); - assert(lStatus == noErr); -} - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost diff --git a/src/mac/thread_cleanup.hpp b/src/mac/thread_cleanup.hpp deleted file mode 100644 index c28763d4..00000000 --- a/src/mac/thread_cleanup.hpp +++ /dev/null @@ -1,36 +0,0 @@ -// (C) Copyright Mac Murrett 2001. -// Use, modification and distribution are subject to 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) - -// See http://www.boost.org for most recent version. - -#ifndef BOOST_THREAD_CLEANUP_MJM012402_HPP -#define BOOST_THREAD_CLEANUP_MJM012402_HPP - - -namespace boost { - -namespace threads { - -namespace mac { - -namespace detail { - - -void do_thread_startup(); -void do_thread_cleanup(); - -void set_thread_cleanup_task(); - - -} // namespace detail - -} // namespace mac - -} // namespace threads - -} // namespace boost - - -#endif // BOOST_THREAD_CLEANUP_MJM012402_HPP diff --git a/src/mutex.cpp b/src/mutex.cpp deleted file mode 100644 index bb73b9ce..00000000 --- a/src/mutex.cpp +++ /dev/null @@ -1,561 +0,0 @@ -// Copyright (C) 2001-2003 -// William E. Kempf -// -// 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 -#include -#include -#include -#include -#include -#include "timeconv.inl" - -#if defined(BOOST_HAS_WINTHREADS) -# include -# include -# include -# include -# include "mutex.inl" -#elif defined(BOOST_HAS_PTHREADS) -# include -#elif defined(BOOST_HAS_MPTASKS) -# include -# include "mac/init.hpp" -# include "mac/safe.hpp" -#endif - -namespace boost { - -#if defined(BOOST_HAS_WINTHREADS) - -mutex::mutex() - : m_mutex(0) - , m_critical_section(false) -{ - m_critical_section = true; - if (m_critical_section) - m_mutex = new_critical_section(); - else - m_mutex = new_mutex(0); -} - -mutex::~mutex() -{ - if (m_critical_section) - delete_critical_section(m_mutex); - else - delete_mutex(m_mutex); -} - -void mutex::do_lock() -{ - if (m_critical_section) - wait_critical_section_infinite(m_mutex); - else - wait_mutex(m_mutex, INFINITE); -} - -void mutex::do_unlock() -{ - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); -} - -void mutex::do_lock(cv_state&) -{ - do_lock(); -} - -void mutex::do_unlock(cv_state&) -{ - do_unlock(); -} - -try_mutex::try_mutex() - : m_mutex(0) - , m_critical_section(false) -{ - m_critical_section = has_TryEnterCriticalSection(); - if (m_critical_section) - m_mutex = new_critical_section(); - else - m_mutex = new_mutex(0); -} - -try_mutex::~try_mutex() -{ - if (m_critical_section) - delete_critical_section(m_mutex); - else - delete_mutex(m_mutex); -} - -void try_mutex::do_lock() -{ - if (m_critical_section) - wait_critical_section_infinite(m_mutex); - else - wait_mutex(m_mutex, INFINITE); -} - -bool try_mutex::do_trylock() -{ - if (m_critical_section) - return wait_critical_section_try(m_mutex); - else - return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0; -} - -void try_mutex::do_unlock() -{ - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); -} - -void try_mutex::do_lock(cv_state&) -{ - do_lock(); -} - -void try_mutex::do_unlock(cv_state&) -{ - do_unlock(); -} - -timed_mutex::timed_mutex() - : m_mutex(0) -{ - m_mutex = new_mutex(0); -} - -timed_mutex::~timed_mutex() -{ - delete_mutex(m_mutex); -} - -void timed_mutex::do_lock() -{ - wait_mutex(m_mutex, INFINITE); -} - -bool timed_mutex::do_trylock() -{ - return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0; -} - -bool timed_mutex::do_timedlock(const xtime& xt) -{ - for (;;) - { - int milliseconds; - to_duration(xt, milliseconds); - - int res = wait_mutex(m_mutex, milliseconds); - - if (res == WAIT_TIMEOUT) - { - boost::xtime cur; - boost::xtime_get(&cur, boost::TIME_UTC); - if (boost::xtime_cmp(xt, cur) > 0) - continue; - } - - return res == WAIT_OBJECT_0; - } -} - -void timed_mutex::do_unlock() -{ - release_mutex(m_mutex); -} - -void timed_mutex::do_lock(cv_state&) -{ - do_lock(); -} - -void timed_mutex::do_unlock(cv_state&) -{ - do_unlock(); -} - -#elif defined(BOOST_HAS_PTHREADS) - -mutex::mutex() -{ - int res = 0; - res = pthread_mutex_init(&m_mutex, 0); - if (res != 0) - throw thread_resource_error(); -} - -mutex::~mutex() -{ - int res = 0; - res = pthread_mutex_destroy(&m_mutex); - assert(res == 0); -} - -void mutex::do_lock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - if (res == EDEADLK) throw lock_error(); - assert(res == 0); -} - -void mutex::do_unlock() -{ - int res = 0; - res = pthread_mutex_unlock(&m_mutex); - if (res == EPERM) throw lock_error(); - assert(res == 0); -} - -void mutex::do_lock(cv_state&) -{ -} - -void mutex::do_unlock(cv_state& state) -{ - state.pmutex = &m_mutex; -} - -try_mutex::try_mutex() -{ - int res = 0; - res = pthread_mutex_init(&m_mutex, 0); - if (res != 0) - throw thread_resource_error(); -} - -try_mutex::~try_mutex() -{ - int res = 0; - res = pthread_mutex_destroy(&m_mutex); - assert(res == 0); -} - -void try_mutex::do_lock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - if (res == EDEADLK) throw lock_error(); - assert(res == 0); -} - -bool try_mutex::do_trylock() -{ - int res = 0; - res = pthread_mutex_trylock(&m_mutex); - if (res == EDEADLK) throw lock_error(); - assert(res == 0 || res == EBUSY); - return res == 0; -} - -void try_mutex::do_unlock() -{ - int res = 0; - res = pthread_mutex_unlock(&m_mutex); - if (res == EPERM) throw lock_error(); - assert(res == 0); -} - -void try_mutex::do_lock(cv_state&) -{ -} - -void try_mutex::do_unlock(cv_state& state) -{ - state.pmutex = &m_mutex; -} - -timed_mutex::timed_mutex() - : m_locked(false) -{ - int res = 0; - res = pthread_mutex_init(&m_mutex, 0); - if (res != 0) - throw thread_resource_error(); - - res = pthread_cond_init(&m_condition, 0); - if (res != 0) - { - pthread_mutex_destroy(&m_mutex); - throw thread_resource_error(); - } -} - -timed_mutex::~timed_mutex() -{ - assert(!m_locked); - int res = 0; - res = pthread_mutex_destroy(&m_mutex); - assert(res == 0); - - res = pthread_cond_destroy(&m_condition); - assert(res == 0); -} - -void timed_mutex::do_lock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - while (m_locked) - { - res = pthread_cond_wait(&m_condition, &m_mutex); - assert(res == 0); - } - - assert(!m_locked); - m_locked = true; - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -} - -bool timed_mutex::do_trylock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - bool ret = false; - if (!m_locked) - { - m_locked = true; - ret = true; - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - return ret; -} - -bool timed_mutex::do_timedlock(const xtime& xt) -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - timespec ts; - to_timespec(xt, ts); - - while (m_locked) - { - res = pthread_cond_timedwait(&m_condition, &m_mutex, &ts); - assert(res == 0 || res == ETIMEDOUT); - - if (res == ETIMEDOUT) - break; - } - - bool ret = false; - if (!m_locked) - { - m_locked = true; - ret = true; - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - return ret; -} - -void timed_mutex::do_unlock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - assert(m_locked); - m_locked = false; - - res = pthread_cond_signal(&m_condition); - assert(res == 0); - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -} - -void timed_mutex::do_lock(cv_state&) -{ - int res = 0; - while (m_locked) - { - res = pthread_cond_wait(&m_condition, &m_mutex); - assert(res == 0); - } - - assert(!m_locked); - m_locked = true; - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -} - -void timed_mutex::do_unlock(cv_state& state) -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - assert(m_locked); - m_locked = false; - - res = pthread_cond_signal(&m_condition); - assert(res == 0); - - state.pmutex = &m_mutex; -} - -#elif defined(BOOST_HAS_MPTASKS) - -using threads::mac::detail::safe_enter_critical_region; - -mutex::mutex() -{ -} - -mutex::~mutex() -{ -} - -void mutex::do_lock() -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); -} - -void mutex::do_unlock() -{ - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); -} - -void mutex::do_lock(cv_state& /*state*/) -{ - do_lock(); -} - -void mutex::do_unlock(cv_state& /*state*/) -{ - do_unlock(); -} - -try_mutex::try_mutex() -{ -} - -try_mutex::~try_mutex() -{ -} - -void try_mutex::do_lock() -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); -} - -bool try_mutex::do_trylock() -{ - OSStatus lStatus = noErr; - lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate); - assert(lStatus == noErr || lStatus == kMPTimeoutErr); - return lStatus == noErr; -} - -void try_mutex::do_unlock() -{ - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); -} - -void try_mutex::do_lock(cv_state& /*state*/) -{ - do_lock(); -} - -void try_mutex::do_unlock(cv_state& /*state*/) -{ - do_unlock(); -} - -timed_mutex::timed_mutex() -{ -} - -timed_mutex::~timed_mutex() -{ -} - -void timed_mutex::do_lock() -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); -} - -bool timed_mutex::do_trylock() -{ - OSStatus lStatus = noErr; - lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate); - assert(lStatus == noErr || lStatus == kMPTimeoutErr); - return(lStatus == noErr); -} - -bool timed_mutex::do_timedlock(const xtime& xt) -{ - int microseconds; - to_microduration(xt, microseconds); - Duration lDuration = kDurationMicrosecond * microseconds; - - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, lDuration, m_mutex_mutex); - assert(lStatus == noErr || lStatus == kMPTimeoutErr); - - return(lStatus == noErr); -} - -void timed_mutex::do_unlock() -{ - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); -} - -void timed_mutex::do_lock(cv_state& /*state*/) -{ - do_lock(); -} - -void timed_mutex::do_unlock(cv_state& /*state*/) -{ - do_unlock(); -} - -#endif - -} // namespace boost - -// Change Log: -// 8 Feb 01 WEKEMPF Initial version. diff --git a/src/mutex.inl b/src/mutex.inl deleted file mode 100644 index fcf55b8e..00000000 --- a/src/mutex.inl +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (C) 2001-2003 -// William E. Kempf -// -// 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) -// boostinspect:nounnamed - -namespace { - -#if defined(BOOST_HAS_WINTHREADS) -//:PREVENT THIS FROM BEING DUPLICATED -typedef BOOL (WINAPI* TryEnterCriticalSection_type)(LPCRITICAL_SECTION lpCriticalSection); -TryEnterCriticalSection_type g_TryEnterCriticalSection = 0; -boost::once_flag once_init_TryEnterCriticalSection = BOOST_ONCE_INIT; - -void init_TryEnterCriticalSection() -{ - //TryEnterCriticalSection is only available on WinNT 4.0 or later; - //it is not available on Win9x. - - OSVERSIONINFO version_info = {sizeof(OSVERSIONINFO)}; - ::GetVersionEx(&version_info); - if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT && - version_info.dwMajorVersion >= 4) - { - if (HMODULE kernel_module = GetModuleHandle(TEXT("KERNEL32.DLL"))) - { - g_TryEnterCriticalSection = reinterpret_cast( -#if defined(BOOST_NO_ANSI_APIS) - GetProcAddressW(kernel_module, L"TryEnterCriticalSection") -#else - GetProcAddress(kernel_module, "TryEnterCriticalSection") -#endif - ); - } - } -} - -inline bool has_TryEnterCriticalSection() -{ - boost::call_once(init_TryEnterCriticalSection, once_init_TryEnterCriticalSection); - return g_TryEnterCriticalSection != 0; -} - -inline HANDLE mutex_cast(void* p) -{ - return reinterpret_cast(p); -} - -inline LPCRITICAL_SECTION critical_section_cast(void* p) -{ - return reinterpret_cast(p); -} - -inline void* new_critical_section() -{ - try - { - LPCRITICAL_SECTION critical_section = new CRITICAL_SECTION; - if (critical_section == 0) throw boost::thread_resource_error(); - InitializeCriticalSection(critical_section); - return critical_section; - } - catch(...) - { - throw boost::thread_resource_error(); - } -} - -inline void* new_mutex(const char* name) -{ -#if defined(BOOST_NO_ANSI_APIS) - USES_CONVERSION; - HANDLE mutex = CreateMutexW(0, 0, A2CW(name)); -#else - HANDLE mutex = CreateMutexA(0, 0, name); -#endif - if (mutex == 0 || mutex == INVALID_HANDLE_VALUE) //:xxx (check for both values?) - throw boost::thread_resource_error(); - return reinterpret_cast(mutex); -} - -inline void delete_critical_section(void* mutex) -{ - DeleteCriticalSection(critical_section_cast(mutex)); - delete critical_section_cast(mutex); -} - -inline void delete_mutex(void* mutex) -{ - int res = 0; - res = CloseHandle(mutex_cast(mutex)); - assert(res); -} - -inline void wait_critical_section_infinite(void* mutex) -{ - EnterCriticalSection(critical_section_cast(mutex)); //:xxx Can throw an exception under low memory conditions -} - -inline bool wait_critical_section_try(void* mutex) -{ - BOOL res = g_TryEnterCriticalSection(critical_section_cast(mutex)); - return res != 0; -} - -inline int wait_mutex(void* mutex, int time) -{ - unsigned int res = 0; - res = WaitForSingleObject(mutex_cast(mutex), time); -//:xxx assert(res != WAIT_FAILED && res != WAIT_ABANDONED); - return res; -} - -inline void release_critical_section(void* mutex) -{ - LeaveCriticalSection(critical_section_cast(mutex)); -} - -inline void release_mutex(void* mutex) -{ - BOOL res = FALSE; - res = ReleaseMutex(mutex_cast(mutex)); - assert(res); -} -#endif - -} diff --git a/src/once.cpp b/src/once.cpp deleted file mode 100644 index 4c881e6a..00000000 --- a/src/once.cpp +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright (C) 2001-2003 -// William E. Kempf -// -// 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 -#include - - -#if defined(BOOST_HAS_WINTHREADS) -# if BOOST_WORKAROUND(__BORLANDC__,<= 0x551) - using std::size_t; -# endif -# include -# if defined(BOOST_NO_STRINGSTREAM) -# include - -class unfreezer -{ -public: - unfreezer(std::ostrstream& s) : m_stream(s) {} - ~unfreezer() { m_stream.freeze(false); } -private: - std::ostrstream& m_stream; -}; - -# else -# include -# endif -#elif defined(BOOST_HAS_MPTASKS) -# include -#endif - -#ifdef BOOST_NO_STDC_NAMESPACE -namespace std { using ::sprintf; } -#endif - -#if defined(BOOST_HAS_PTHREADS) -namespace { -pthread_key_t key; -pthread_once_t once = PTHREAD_ONCE_INIT; - -typedef void (*once_callback)(); -} - -extern "C" { - - static void key_init() - { - pthread_key_create(&key, 0); - } - - static void do_once() - { - once_callback* cb = reinterpret_cast( - pthread_getspecific(key)); - (**cb)(); - } - -} -#elif defined(BOOST_HAS_MPTASKS) -namespace { -void *remote_call_proxy(void *pData) -{ - std::pair &rData( - *reinterpret_cast *>(pData)); - - if(*rData.second == false) - { - rData.first(); - *rData.second = true; - } - - return(NULL); -} -} - -#elif defined(BOOST_HAS_WINTHREADS) -namespace { -// The signature for InterlockedCompareExchange has changed with the -// addition of Win64 support. I can't determine any (consistent and -// portable) way of using conditional compilation to detect this, so -// we use these type wrappers. Unfortunately, the various vendors -// use different calling conventions and other signature anamolies, -// and thus have unique types as well. This is known to work on VC6, -// VC7, Borland 5.5.2 and gcc 3.2. Are there other signatures for -// other platforms? -inline LONG ice_wrapper(LONG (__stdcall *ice)(LONG*, LONG, LONG), - volatile LONG* dest, LONG exch, LONG cmp) -{ - return (*ice)(const_cast(dest), exch, cmp); -} - -inline LONG ice_wrapper(LONG (__stdcall *ice)(volatile LONG*, LONG, LONG), - volatile LONG* dest, LONG exch, LONG cmp) -{ - return (*ice)(dest, exch, cmp); -} - -inline LONG ice_wrapper(LPVOID (__stdcall *ice)(LPVOID*, LPVOID, LPVOID), - volatile LONG* dest, LONG exch, LONG cmp) -{ - return (LONG)(*ice)((LPVOID*)dest, (LPVOID)exch, (LPVOID)cmp); -} - -// The friendly form of InterlockedCompareExchange that defers -// according to the above function type wrappers. -inline LONG compare_exchange(volatile LPLONG dest, LONG exch, LONG cmp) -{ -#ifdef _WIN64 - // Original patch from Anthony Williams. - // I (Roland Schwarz) am trying this for RC_1_34_0, since x64 regressions are - // currently not run on x64 platforms for HEAD - return InterlockedCompareExchange(dest, exch,cmp); -#else - return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp); -#endif -} -} -#endif - -namespace boost { - -void call_once(void (*func)(), once_flag& flag) -{ -#if defined(BOOST_HAS_WINTHREADS) - if (compare_exchange(&flag, 1, 1) == 0) - { -#if defined(BOOST_NO_STRINGSTREAM) - std::ostrstream strm; - strm << "2AC1A572DB6944B0A65C38C4140AF2F4" - << std::hex - << GetCurrentProcessId() - << &flag - << std::ends; - unfreezer unfreeze(strm); -# if defined (BOOST_NO_ANSI_APIS) - USES_CONVERSION; - HANDLE mutex = CreateMutexW(NULL, FALSE, A2CW(strm.str())); -# else - HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str()); -# endif -#else -# if defined (BOOST_NO_ANSI_APIS) - std::wostringstream strm; - strm << L"2AC1A572DB6944B0A65C38C4140AF2F4" - << std::hex - << GetCurrentProcessId() - << &flag; - HANDLE mutex = CreateMutexW(NULL, FALSE, strm.str().c_str()); -# else - std::ostringstream strm; - strm << "2AC1A572DB6944B0A65C38C4140AF2F4" - << std::hex - << GetCurrentProcessId() - << &flag; - HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str().c_str()); -# endif -#endif - assert(mutex != NULL); - - int res = 0; - res = WaitForSingleObject(mutex, INFINITE); - assert(res == WAIT_OBJECT_0); - - if (compare_exchange(&flag, 1, 1) == 0) - { - try - { - func(); - } - catch (...) - { - res = ReleaseMutex(mutex); - assert(res); - res = CloseHandle(mutex); - assert(res); - throw; - } - InterlockedExchange(&flag, 1); - } - - res = ReleaseMutex(mutex); - assert(res); - res = CloseHandle(mutex); - assert(res); - } -#elif defined(BOOST_HAS_PTHREADS) - pthread_once(&once, &key_init); - pthread_setspecific(key, &func); - pthread_once(&flag, do_once); -#elif defined(BOOST_HAS_MPTASKS) - if(flag == false) - { - // all we do here is make a remote call to blue, as blue is not - // reentrant. - std::pair sData(func, &flag); - MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext); - assert(flag == true); - } -#endif -} - -} - -// Change Log: -// 1 Aug 01 WEKEMPF Initial version. diff --git a/src/exceptions.cpp b/src/pthread/exceptions.cpp similarity index 100% rename from src/exceptions.cpp rename to src/pthread/exceptions.cpp diff --git a/src/pthread/once.cpp b/src/pthread/once.cpp new file mode 100755 index 00000000..b893a0b5 --- /dev/null +++ b/src/pthread/once.cpp @@ -0,0 +1,51 @@ +// Copyright (C) 2007 Anthony Williams +// +// 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 + +namespace boost +{ + namespace detail + { + boost::uintmax_t once_global_epoch=0; + pthread_mutex_t once_epoch_mutex=PTHREAD_MUTEX_INITIALIZER; + pthread_cond_t once_epoch_cv = PTHREAD_COND_INITIALIZER; + + namespace + { + pthread_key_t epoch_tss_key; + pthread_once_t epoch_tss_key_flag=PTHREAD_ONCE_INIT; + + extern "C" void delete_epoch_tss_data(void* data) + { + free(data); + } + + extern "C" void create_epoch_tss_key() + { + BOOST_VERIFY(!pthread_key_create(&epoch_tss_key,delete_epoch_tss_data)); + } + + } + + boost::uintmax_t& get_once_per_thread_epoch() + { + BOOST_VERIFY(!pthread_once(&epoch_tss_key_flag,create_epoch_tss_key)); + void* data=pthread_getspecific(epoch_tss_key); + if(!data) + { + data=malloc(sizeof(boost::uintmax_t)); + BOOST_VERIFY(!pthread_setspecific(epoch_tss_key,data)); + *static_cast(data)=0; + } + return *static_cast(data); + } + + } + +} diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp new file mode 100644 index 00000000..8a074db4 --- /dev/null +++ b/src/pthread/thread.cpp @@ -0,0 +1,633 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// Copyright (C) 2007 Anthony Williams +// +// 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 +#include +#include +#include + +#include "timeconv.inl" + +namespace boost +{ + namespace detail + { + struct thread_exit_callback_node + { + boost::detail::thread_exit_function_base* func; + thread_exit_callback_node* next; + + thread_exit_callback_node(boost::detail::thread_exit_function_base* func_, + thread_exit_callback_node* next_): + func(func_),next(next_) + {} + }; + + struct tss_data_node + { + void const* key; + boost::shared_ptr func; + void* value; + tss_data_node* next; + + tss_data_node(void const* key_,boost::shared_ptr func_,void* value_, + tss_data_node* next_): + key(key_),func(func_),value(value_),next(next_) + {} + }; + + namespace + { + boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT; + pthread_key_t current_thread_tls_key; + + extern "C" + { + void tls_destructor(void* data) + { + boost::detail::thread_data_base* thread_info=static_cast(data); + if(thread_info) + { + while(thread_info->tss_data || thread_info->thread_exit_callbacks) + { + while(thread_info->thread_exit_callbacks) + { + detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks; + thread_info->thread_exit_callbacks=current_node->next; + if(current_node->func) + { + (*current_node->func)(); + delete current_node->func; + } + delete current_node; + } + while(thread_info->tss_data) + { + detail::tss_data_node* const current_node=thread_info->tss_data; + thread_info->tss_data=current_node->next; + if(current_node->func) + { + (*current_node->func)(current_node->value); + } + delete current_node; + } + } + thread_info->self.reset(); + } + } + } + + + void create_current_thread_tls_key() + { + BOOST_VERIFY(!pthread_key_create(¤t_thread_tls_key,&tls_destructor)); + } + } + + boost::detail::thread_data_base* get_current_thread_data() + { + 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); + } + + void set_current_thread_data(detail::thread_data_base* new_data) + { + boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key); + BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data)); + } + } + + namespace + { + extern "C" + { + void* thread_proxy(void* param) + { + boost::shared_ptr thread_info = static_cast(param)->self; + thread_info->self.reset(); + detail::set_current_thread_data(thread_info.get()); + try + { + thread_info->run(); + } + catch(thread_interrupted const&) + { + } + catch(...) + { + std::terminate(); + } + + detail::tls_destructor(thread_info.get()); + detail::set_current_thread_data(0); + boost::lock_guard lock(thread_info->data_mutex); + thread_info->done=true; + thread_info->done_condition.notify_all(); + return 0; + } + } + + struct externally_launched_thread: + detail::thread_data_base + { + externally_launched_thread() + { + interrupt_enabled=false; + } + + void run() + {} + }; + + detail::thread_data_base* make_external_thread_data() + { + detail::thread_data_base* const me(new externally_launched_thread()); + me->self.reset(me); + set_current_thread_data(me); + return me; + } + + + detail::thread_data_base* get_or_make_current_thread_data() + { + detail::thread_data_base* current_thread_data(detail::get_current_thread_data()); + if(!current_thread_data) + { + current_thread_data=make_external_thread_data(); + } + return current_thread_data; + } + + } + + + thread::thread() + {} + + void thread::start_thread() + { + thread_info->self=thread_info; + int const res = pthread_create(&thread_info->thread_handle, 0, &thread_proxy, thread_info.get()); + if (res != 0) + { + thread_info->self.reset(); + throw thread_resource_error(); + } + } + + thread::~thread() + { + detach(); + } + + bool thread::operator==(const thread& other) const + { + return get_id()==other.get_id(); + } + + bool thread::operator!=(const thread& other) const + { + return !operator==(other); + } + + boost::shared_ptr thread::get_thread_info() const + { + lock_guard l(thread_info_mutex); + return thread_info; + } + + void thread::join() + { + boost::shared_ptr const local_thread_info=get_thread_info(); + if(local_thread_info) + { + bool do_join=false; + + { + unique_lock lock(local_thread_info->data_mutex); + while(!local_thread_info->done) + { + local_thread_info->done_condition.wait(lock); + } + do_join=!local_thread_info->join_started; + + if(do_join) + { + local_thread_info->join_started=true; + } + else + { + while(!local_thread_info->joined) + { + local_thread_info->done_condition.wait(lock); + } + } + } + if(do_join) + { + void* result=0; + BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result)); + lock_guard lock(local_thread_info->data_mutex); + local_thread_info->joined=true; + local_thread_info->done_condition.notify_all(); + } + + lock_guard l1(thread_info_mutex); + if(thread_info==local_thread_info) + { + thread_info.reset(); + } + } + } + + bool thread::timed_join(system_time const& wait_until) + { + boost::shared_ptr const local_thread_info=get_thread_info(); + if(local_thread_info) + { + bool do_join=false; + + { + unique_lock lock(local_thread_info->data_mutex); + while(!local_thread_info->done) + { + if(!local_thread_info->done_condition.timed_wait(lock,wait_until)) + { + return false; + } + } + do_join=!local_thread_info->join_started; + + if(do_join) + { + local_thread_info->join_started=true; + } + else + { + while(!local_thread_info->joined) + { + local_thread_info->done_condition.wait(lock); + } + } + } + if(do_join) + { + void* result=0; + BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result)); + lock_guard lock(local_thread_info->data_mutex); + local_thread_info->joined=true; + local_thread_info->done_condition.notify_all(); + } + + lock_guard l1(thread_info_mutex); + if(thread_info==local_thread_info) + { + thread_info.reset(); + } + } + return true; + } + + bool thread::joinable() const + { + return get_thread_info(); + } + + + void thread::detach() + { + boost::shared_ptr local_thread_info; + { + lock_guard l1(thread_info_mutex); + thread_info.swap(local_thread_info); + } + + if(local_thread_info) + { + lock_guard lock(local_thread_info->data_mutex); + if(!local_thread_info->join_started) + { + BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle)); + local_thread_info->join_started=true; + local_thread_info->joined=true; + } + } + } + + void thread::sleep(const system_time& st) + { + detail::thread_data_base* const thread_info=detail::get_current_thread_data(); + + if(thread_info) + { + unique_lock lk(thread_info->sleep_mutex); + while(thread_info->sleep_condition.timed_wait(lk,st)); + } + else + { + xtime const xt=get_xtime(st); + + for (int foo=0; foo < 5; ++foo) + { +# if defined(BOOST_HAS_PTHREAD_DELAY_NP) + timespec ts; + to_timespec_duration(xt, ts); + BOOST_VERIFY(!pthread_delay_np(&ts)); +# elif defined(BOOST_HAS_NANOSLEEP) + timespec ts; + to_timespec_duration(xt, ts); + + // nanosleep takes a timespec that is an offset, not + // an absolute time. + nanosleep(&ts, 0); +# else + mutex mx; + mutex::scoped_lock lock(mx); + condition cond; + cond.timed_wait(lock, xt); +# endif + xtime cur; + xtime_get(&cur, TIME_UTC); + if (xtime_cmp(xt, cur) <= 0) + return; + } + } + } + + void thread::yield() + { +# if defined(BOOST_HAS_SCHED_YIELD) + BOOST_VERIFY(!sched_yield()); +# elif defined(BOOST_HAS_PTHREAD_YIELD) + BOOST_VERIFY(!pthread_yield()); +# else + xtime xt; + xtime_get(&xt, TIME_UTC); + sleep(xt); +# endif + } + + unsigned thread::hardware_concurrency() + { + return 1; + } + + thread::id thread::get_id() const + { + boost::shared_ptr local_thread_info=get_thread_info(); + if(local_thread_info) + { + return id(local_thread_info->thread_handle); + } + else + { + return id(); + } + } + + void thread::interrupt() + { + boost::shared_ptr local_thread_info=get_thread_info(); + if(local_thread_info) + { + lock_guard lk(local_thread_info->data_mutex); + local_thread_info->interrupt_requested=true; + if(local_thread_info->current_cond) + { + BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info->current_cond)); + } + } + } + + bool thread::interruption_requested() const + { + boost::shared_ptr local_thread_info=get_thread_info(); + if(local_thread_info) + { + lock_guard lk(local_thread_info->data_mutex); + return local_thread_info->interrupt_requested; + } + else + { + return false; + } + } + + + namespace this_thread + { + void interruption_point() + { + boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data(); + if(thread_info && thread_info->interrupt_enabled) + { + lock_guard lg(thread_info->data_mutex); + if(thread_info->interrupt_requested) + { + thread_info->interrupt_requested=false; + throw thread_interrupted(); + } + } + } + + bool interruption_enabled() + { + boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data(); + return thread_info && thread_info->interrupt_enabled; + } + + bool interruption_requested() + { + boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data(); + if(!thread_info) + { + return false; + } + else + { + lock_guard lg(thread_info->data_mutex); + return thread_info->interrupt_requested; + } + } + + disable_interruption::disable_interruption(): + interruption_was_enabled(interruption_enabled()) + { + if(interruption_was_enabled) + { + detail::get_current_thread_data()->interrupt_enabled=false; + } + } + + disable_interruption::~disable_interruption() + { + if(detail::get_current_thread_data()) + { + detail::get_current_thread_data()->interrupt_enabled=interruption_was_enabled; + } + } + + restore_interruption::restore_interruption(disable_interruption& d) + { + if(d.interruption_was_enabled) + { + detail::get_current_thread_data()->interrupt_enabled=true; + } + } + + restore_interruption::~restore_interruption() + { + if(detail::get_current_thread_data()) + { + detail::get_current_thread_data()->interrupt_enabled=false; + } + } + } + + namespace detail + { + void add_thread_exit_function(thread_exit_function_base* func) + { + detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); + thread_exit_callback_node* const new_node= + new thread_exit_callback_node(func,current_thread_data->thread_exit_callbacks); + current_thread_data->thread_exit_callbacks=new_node; + } + + tss_data_node* find_tss_data(void const* key) + { + detail::thread_data_base* const current_thread_data(get_current_thread_data()); + if(current_thread_data) + { + detail::tss_data_node* current_node=current_thread_data->tss_data; + while(current_node) + { + if(current_node->key==key) + { + return current_node; + } + current_node=current_node->next; + } + } + return NULL; + } + + void* get_tss_data(void const* key) + { + if(tss_data_node* const current_node=find_tss_data(key)) + { + return current_node->value; + } + return NULL; + } + + void set_tss_data(void const* key,boost::shared_ptr 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->func)(current_node->value); + } + current_node->func=func; + current_node->value=tss_data; + } + else + { + detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); + tss_data_node* const new_node=new tss_data_node(key,func,tss_data,current_thread_data->tss_data); + current_thread_data->tss_data=new_node; + } + } + } + + thread_group::thread_group() + { + } + + thread_group::~thread_group() + { + // We shouldn't have to scoped_lock here, since referencing this object + // from another thread while we're deleting it in the current thread is + // going to lead to undefined behavior any way. + for (std::list::iterator it = m_threads.begin(); + it != m_threads.end(); ++it) + { + delete (*it); + } + } + + thread* thread_group::create_thread(const function0& threadfunc) + { + // No scoped_lock required here since the only "shared data" that's + // modified here occurs inside add_thread which does scoped_lock. + std::auto_ptr thrd(new thread(threadfunc)); + add_thread(thrd.get()); + return thrd.release(); + } + + void thread_group::add_thread(thread* thrd) + { + mutex::scoped_lock scoped_lock(m_mutex); + + // For now we'll simply ignore requests to add a thread object multiple + // times. Should we consider this an error and either throw or return an + // error value? + std::list::iterator it = std::find(m_threads.begin(), + m_threads.end(), thrd); + BOOST_ASSERT(it == m_threads.end()); + if (it == m_threads.end()) + m_threads.push_back(thrd); + } + + void thread_group::remove_thread(thread* thrd) + { + mutex::scoped_lock scoped_lock(m_mutex); + + // For now we'll simply ignore requests to remove a thread object that's + // not in the group. Should we consider this an error and either throw or + // return an error value? + std::list::iterator it = std::find(m_threads.begin(), + m_threads.end(), thrd); + BOOST_ASSERT(it != m_threads.end()); + if (it != m_threads.end()) + m_threads.erase(it); + } + + void thread_group::join_all() + { + mutex::scoped_lock scoped_lock(m_mutex); + for (std::list::iterator it = m_threads.begin(); + it != m_threads.end(); ++it) + { + (*it)->join(); + } + } + + void thread_group::interrupt_all() + { + boost::lock_guard guard(m_mutex); + + for(std::list::iterator it=m_threads.begin(),end=m_threads.end(); + it!=end; + ++it) + { + (*it)->interrupt(); + } + } + + + int thread_group::size() const + { + return m_threads.size(); + } + +} diff --git a/src/timeconv.inl b/src/pthread/timeconv.inl similarity index 100% rename from src/timeconv.inl rename to src/pthread/timeconv.inl diff --git a/src/recursive_mutex.cpp b/src/recursive_mutex.cpp deleted file mode 100644 index ebe17c1a..00000000 --- a/src/recursive_mutex.cpp +++ /dev/null @@ -1,1040 +0,0 @@ -// Copyright (C) 2001-2003 -// William E. Kempf -// -// 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 -#include -#include -#include -#include -#include "timeconv.inl" - -#if defined(BOOST_HAS_WINTHREADS) -# include -# include -# include -# include -# include "mutex.inl" -#elif defined(BOOST_HAS_PTHREADS) -# include -#elif defined(BOOST_HAS_MPTASKS) -# include -# include "safe.hpp" -#endif - -namespace boost { - -#if defined(BOOST_HAS_WINTHREADS) - -recursive_mutex::recursive_mutex() - : m_mutex(0) - , m_critical_section(false) - , m_count(0) -{ - m_critical_section = true; - if (m_critical_section) - m_mutex = new_critical_section(); - else - m_mutex = new_mutex(0); -} - -recursive_mutex::~recursive_mutex() -{ - if (m_critical_section) - delete_critical_section(m_mutex); - else - delete_mutex(m_mutex); -} - -void recursive_mutex::do_lock() -{ - if (m_critical_section) - wait_critical_section_infinite(m_mutex); - else - wait_mutex(m_mutex, INFINITE); - - if (++m_count > 1) - { - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); - } -} - -void recursive_mutex::do_unlock() -{ - if (--m_count == 0) - { - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); - } -} - -void recursive_mutex::do_lock(cv_state& state) -{ - if (m_critical_section) - wait_critical_section_infinite(m_mutex); - else - wait_mutex(m_mutex, INFINITE); - - m_count = state; -} - -void recursive_mutex::do_unlock(cv_state& state) -{ - state = m_count; - m_count = 0; - - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); -} - -recursive_try_mutex::recursive_try_mutex() - : m_mutex(0) - , m_critical_section(false) - , m_count(0) -{ - m_critical_section = has_TryEnterCriticalSection(); - if (m_critical_section) - m_mutex = new_critical_section(); - else - m_mutex = new_mutex(0); -} - -recursive_try_mutex::~recursive_try_mutex() -{ - if (m_critical_section) - delete_critical_section(m_mutex); - else - delete_mutex(m_mutex); -} - -void recursive_try_mutex::do_lock() -{ - if (m_critical_section) - wait_critical_section_infinite(m_mutex); - else - wait_mutex(m_mutex, INFINITE); - - if (++m_count > 1) - { - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); - } -} - -bool recursive_try_mutex::do_trylock() -{ - bool res = false; - if (m_critical_section) - res = wait_critical_section_try(m_mutex); - else - res = wait_mutex(m_mutex, 0) == WAIT_OBJECT_0; - - if (res) - { - if (++m_count > 1) - { - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); - } - return true; - } - return false; -} - -void recursive_try_mutex::do_unlock() -{ - if (--m_count == 0) - { - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); - } -} - -void recursive_try_mutex::do_lock(cv_state& state) -{ - if (m_critical_section) - wait_critical_section_infinite(m_mutex); - else - wait_mutex(m_mutex, INFINITE); - - m_count = state; -} - -void recursive_try_mutex::do_unlock(cv_state& state) -{ - state = m_count; - m_count = 0; - - if (m_critical_section) - release_critical_section(m_mutex); - else - release_mutex(m_mutex); -} - -recursive_timed_mutex::recursive_timed_mutex() - : m_mutex(0) - , m_count(0) -{ - m_mutex = new_mutex(0); -} - -recursive_timed_mutex::~recursive_timed_mutex() -{ - delete_mutex(m_mutex); -} - -void recursive_timed_mutex::do_lock() -{ - wait_mutex(m_mutex, INFINITE); - - if (++m_count > 1) - release_mutex(m_mutex); -} - -bool recursive_timed_mutex::do_trylock() -{ - bool res = wait_mutex(m_mutex, 0) == WAIT_OBJECT_0; - - if (res) - { - if (++m_count > 1) - release_mutex(m_mutex); - return true; - } - return false; -} - -bool recursive_timed_mutex::do_timedlock(const xtime& xt) -{ - for (;;) - { - int milliseconds; - to_duration(xt, milliseconds); - - unsigned int res = wait_mutex(m_mutex, milliseconds); - - if (res == WAIT_TIMEOUT) - { - xtime cur; - xtime_get(&cur, TIME_UTC); - if (xtime_cmp(xt, cur) > 0) - continue; - } - - if (res == WAIT_OBJECT_0) - { - if (++m_count > 1) - release_mutex(m_mutex); - return true; - } - - return false; - } -} - -void recursive_timed_mutex::do_unlock() -{ - if (--m_count == 0) - release_mutex(m_mutex); -} - -void recursive_timed_mutex::do_lock(cv_state& state) -{ - wait_mutex(m_mutex, INFINITE); - - m_count = state; -} - -void recursive_timed_mutex::do_unlock(cv_state& state) -{ - state = m_count; - m_count = 0; - - release_mutex(m_mutex); -} - -#elif defined(BOOST_HAS_PTHREADS) - -recursive_mutex::recursive_mutex() - : m_count(0) -# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - , m_valid_id(false) -# endif -{ - pthread_mutexattr_t attr; - int res = pthread_mutexattr_init(&attr); - assert(res == 0); - -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - res = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - assert(res == 0); -# endif - - res = pthread_mutex_init(&m_mutex, &attr); - { - int res = 0; - res = pthread_mutexattr_destroy(&attr); - assert(res == 0); - } - if (res != 0) - throw thread_resource_error(); - -# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - res = pthread_cond_init(&m_unlocked, 0); - if (res != 0) - { - pthread_mutex_destroy(&m_mutex); - throw thread_resource_error(); - } -# endif -} - -recursive_mutex::~recursive_mutex() -{ - int res = 0; - res = pthread_mutex_destroy(&m_mutex); - assert(res == 0); - -# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - res = pthread_cond_destroy(&m_unlocked); - assert(res == 0); -# endif -} - -void recursive_mutex::do_lock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - if (++m_count > 1) - { - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - } -# else - pthread_t tid = pthread_self(); - if (m_valid_id && pthread_equal(m_thread_id, tid)) - ++m_count; - else - { - while (m_valid_id) - { - res = pthread_cond_wait(&m_unlocked, &m_mutex); - assert(res == 0); - } - - m_thread_id = tid; - m_valid_id = true; - m_count = 1; - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -# endif -} - -void recursive_mutex::do_unlock() -{ -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - if (--m_count == 0) - { - int res = 0; - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - } -# else - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - pthread_t tid = pthread_self(); - if (m_valid_id && !pthread_equal(m_thread_id, tid)) - { - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - throw lock_error(); - } - - if (--m_count == 0) - { - assert(m_valid_id); - m_valid_id = false; - - res = pthread_cond_signal(&m_unlocked); - assert(res == 0); - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -# endif -} - -void recursive_mutex::do_lock(cv_state& state) -{ -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - m_count = state.count; -# else - int res = 0; - - while (m_valid_id) - { - res = pthread_cond_wait(&m_unlocked, &m_mutex); - assert(res == 0); - } - - m_thread_id = pthread_self(); - m_valid_id = true; - m_count = state.count; - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -# endif -} - -void recursive_mutex::do_unlock(cv_state& state) -{ -# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - assert(m_valid_id); - m_valid_id = false; - - res = pthread_cond_signal(&m_unlocked); - assert(res == 0); -# endif - - state.pmutex = &m_mutex; - state.count = m_count; - m_count = 0; -} - -recursive_try_mutex::recursive_try_mutex() - : m_count(0) -# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - , m_valid_id(false) -# endif -{ - pthread_mutexattr_t attr; - int res = pthread_mutexattr_init(&attr); - assert(res == 0); - -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - res = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - assert(res == 0); -# endif - - res = pthread_mutex_init(&m_mutex, &attr); - { - int res = 0; - res = pthread_mutexattr_destroy(&attr); - assert(res == 0); - } - if (res != 0) - throw thread_resource_error(); - -# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - res = pthread_cond_init(&m_unlocked, 0); - if (res != 0) - { - pthread_mutex_destroy(&m_mutex); - throw thread_resource_error(); - } -# endif -} - -recursive_try_mutex::~recursive_try_mutex() -{ - int res = 0; - res = pthread_mutex_destroy(&m_mutex); - assert(res == 0); - -# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - res = pthread_cond_destroy(&m_unlocked); - assert(res == 0); -# endif -} - -void recursive_try_mutex::do_lock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - if (++m_count > 1) - { - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - } -# else - pthread_t tid = pthread_self(); - if (m_valid_id && pthread_equal(m_thread_id, tid)) - ++m_count; - else - { - while (m_valid_id) - { - res = pthread_cond_wait(&m_unlocked, &m_mutex); - assert(res == 0); - } - - m_thread_id = tid; - m_valid_id = true; - m_count = 1; - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -# endif -} - -bool recursive_try_mutex::do_trylock() -{ -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - int res = 0; - res = pthread_mutex_trylock(&m_mutex); - assert(res == 0 || res == EBUSY); - - if (res == 0) - { - if (++m_count > 1) - { - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - } - return true; - } - - return false; -# else - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - bool ret = false; - pthread_t tid = pthread_self(); - if (m_valid_id && pthread_equal(m_thread_id, tid)) - { - ++m_count; - ret = true; - } - else if (!m_valid_id) - { - m_thread_id = tid; - m_valid_id = true; - m_count = 1; - ret = true; - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - return ret; -# endif -} - -void recursive_try_mutex::do_unlock() -{ -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - if (--m_count == 0) - { - int res = 0; - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - } -# else - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - pthread_t tid = pthread_self(); - if (m_valid_id && !pthread_equal(m_thread_id, tid)) - { - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - throw lock_error(); - } - - if (--m_count == 0) - { - assert(m_valid_id); - m_valid_id = false; - - res = pthread_cond_signal(&m_unlocked); - assert(res == 0); - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -# endif -} - -void recursive_try_mutex::do_lock(cv_state& state) -{ -# if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - m_count = state.count; -# else - int res = 0; - - while (m_valid_id) - { - res = pthread_cond_wait(&m_unlocked, &m_mutex); - assert(res == 0); - } - - m_thread_id = pthread_self(); - m_valid_id = true; - m_count = state.count; - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -# endif -} - -void recursive_try_mutex::do_unlock(cv_state& state) -{ -# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - assert(m_valid_id); - m_valid_id = false; - - res = pthread_cond_signal(&m_unlocked); - assert(res == 0); -# endif - - state.pmutex = &m_mutex; - state.count = m_count; - m_count = 0; -} - -recursive_timed_mutex::recursive_timed_mutex() - : m_valid_id(false), m_count(0) -{ - int res = 0; - res = pthread_mutex_init(&m_mutex, 0); - if (res != 0) - throw thread_resource_error(); - - res = pthread_cond_init(&m_unlocked, 0); - if (res != 0) - { - pthread_mutex_destroy(&m_mutex); - throw thread_resource_error(); - } -} - -recursive_timed_mutex::~recursive_timed_mutex() -{ - int res = 0; - res = pthread_mutex_destroy(&m_mutex); - assert(res == 0); - - res = pthread_cond_destroy(&m_unlocked); - assert(res == 0); -} - -void recursive_timed_mutex::do_lock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - pthread_t tid = pthread_self(); - if (m_valid_id && pthread_equal(m_thread_id, tid)) - ++m_count; - else - { - while (m_valid_id) - { - res = pthread_cond_wait(&m_unlocked, &m_mutex); - assert(res == 0); - } - - m_thread_id = tid; - m_valid_id = true; - m_count = 1; - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -} - -bool recursive_timed_mutex::do_trylock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - bool ret = false; - pthread_t tid = pthread_self(); - if (m_valid_id && pthread_equal(m_thread_id, tid)) - { - ++m_count; - ret = true; - } - else if (!m_valid_id) - { - m_thread_id = tid; - m_valid_id = true; - m_count = 1; - ret = true; - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - return ret; -} - -bool recursive_timed_mutex::do_timedlock(const xtime& xt) -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - bool ret = false; - pthread_t tid = pthread_self(); - if (m_valid_id && pthread_equal(m_thread_id, tid)) - { - ++m_count; - ret = true; - } - else - { - timespec ts; - to_timespec(xt, ts); - - while (m_valid_id) - { - res = pthread_cond_timedwait(&m_unlocked, &m_mutex, &ts); - if (res == ETIMEDOUT) - break; - assert(res == 0); - } - - if (!m_valid_id) - { - m_thread_id = tid; - m_valid_id = true; - m_count = 1; - ret = true; - } - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - return ret; -} - -void recursive_timed_mutex::do_unlock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - pthread_t tid = pthread_self(); - if (m_valid_id && !pthread_equal(m_thread_id, tid)) - { - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); - throw lock_error(); - } - - if (--m_count == 0) - { - assert(m_valid_id); - m_valid_id = false; - - res = pthread_cond_signal(&m_unlocked); - assert(res == 0); - } - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -} - -void recursive_timed_mutex::do_lock(cv_state& state) -{ - int res = 0; - - while (m_valid_id) - { - res = pthread_cond_wait(&m_unlocked, &m_mutex); - assert(res == 0); - } - - m_thread_id = pthread_self(); - m_valid_id = true; - m_count = state.count; - - res = pthread_mutex_unlock(&m_mutex); - assert(res == 0); -} - -void recursive_timed_mutex::do_unlock(cv_state& state) -{ - int res = 0; - res = pthread_mutex_lock(&m_mutex); - assert(res == 0); - - assert(m_valid_id); - m_valid_id = false; - - res = pthread_cond_signal(&m_unlocked); - assert(res == 0); - - state.pmutex = &m_mutex; - state.count = m_count; - m_count = 0; -} -#elif defined(BOOST_HAS_MPTASKS) - -using threads::mac::detail::safe_enter_critical_region; - - -recursive_mutex::recursive_mutex() - : m_count(0) -{ -} - -recursive_mutex::~recursive_mutex() -{ -} - -void recursive_mutex::do_lock() -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); - - if (++m_count > 1) - { - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } -} - -void recursive_mutex::do_unlock() -{ - if (--m_count == 0) - { - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } -} - -void recursive_mutex::do_lock(cv_state& state) -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); - - m_count = state; -} - -void recursive_mutex::do_unlock(cv_state& state) -{ - state = m_count; - m_count = 0; - - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); -} - -recursive_try_mutex::recursive_try_mutex() - : m_count(0) -{ -} - -recursive_try_mutex::~recursive_try_mutex() -{ -} - -void recursive_try_mutex::do_lock() -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); - - if (++m_count > 1) - { - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } -} - -bool recursive_try_mutex::do_trylock() -{ - OSStatus lStatus = noErr; - lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate); - assert(lStatus == noErr || lStatus == kMPTimeoutErr); - - if (lStatus == noErr) - { - if (++m_count > 1) - { - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } - return true; - } - return false; -} - -void recursive_try_mutex::do_unlock() -{ - if (--m_count == 0) - { - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } -} - -void recursive_try_mutex::do_lock(cv_state& state) -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); - - m_count = state; -} - -void recursive_try_mutex::do_unlock(cv_state& state) -{ - state = m_count; - m_count = 0; - - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); -} - -recursive_timed_mutex::recursive_timed_mutex() - : m_count(0) -{ -} - -recursive_timed_mutex::~recursive_timed_mutex() -{ -} - -void recursive_timed_mutex::do_lock() -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); - - if (++m_count > 1) - { - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } -} - -bool recursive_timed_mutex::do_trylock() -{ - OSStatus lStatus = noErr; - lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate); - assert(lStatus == noErr || lStatus == kMPTimeoutErr); - - if (lStatus == noErr) - { - if (++m_count > 1) - { - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } - return true; - } - return false; -} - -bool recursive_timed_mutex::do_timedlock(const xtime& xt) -{ - int microseconds; - to_microduration(xt, microseconds); - Duration lDuration = kDurationMicrosecond * microseconds; - - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, lDuration, m_mutex_mutex); - assert(lStatus == noErr || lStatus == kMPTimeoutErr); - - if (lStatus == noErr) - { - if (++m_count > 1) - { - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } - return true; - } - return false; -} - -void recursive_timed_mutex::do_unlock() -{ - if (--m_count == 0) - { - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); - } -} - -void recursive_timed_mutex::do_lock(cv_state& state) -{ - OSStatus lStatus = noErr; - lStatus = safe_enter_critical_region(m_mutex, kDurationForever, - m_mutex_mutex); - assert(lStatus == noErr); - - m_count = state; -} - -void recursive_timed_mutex::do_unlock(cv_state& state) -{ - state = m_count; - m_count = 0; - - OSStatus lStatus = noErr; - lStatus = MPExitCriticalRegion(m_mutex); - assert(lStatus == noErr); -} -#endif - -} // namespace boost - -// Change Log: -// 8 Feb 01 WEKEMPF Initial version. diff --git a/src/thread.cpp b/src/thread.cpp deleted file mode 100644 index 67d5870c..00000000 --- a/src/thread.cpp +++ /dev/null @@ -1,371 +0,0 @@ -// Copyright (C) 2001-2003 -// William E. Kempf -// -// 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 -#include - -#if defined(BOOST_HAS_WINTHREADS) -# include -# if !defined(BOOST_NO_THREADEX) -# include -# endif -#elif defined(BOOST_HAS_MPTASKS) -# include - -# include "init.hpp" -# include "safe.hpp" -# include -#endif - -#include "timeconv.inl" - -#if defined(BOOST_HAS_WINTHREADS) -# include "boost/thread/detail/tss_hooks.hpp" -#endif - -namespace { - -#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_NO_THREADEX) -// Windows CE doesn't define _beginthreadex - -struct ThreadProxyData -{ - typedef unsigned (__stdcall* func)(void*); - func start_address_; - void* arglist_; - ThreadProxyData(func start_address,void* arglist) : start_address_(start_address), arglist_(arglist) {} -}; - -DWORD WINAPI ThreadProxy(LPVOID args) -{ - ThreadProxyData* data=reinterpret_cast(args); - DWORD ret=data->start_address_(data->arglist_); - delete data; - return ret; -} - -inline unsigned _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*), -void* arglist, unsigned initflag,unsigned* thrdaddr) -{ - DWORD threadID; - HANDLE hthread=CreateThread(static_cast(security),stack_size,ThreadProxy, - new ThreadProxyData(start_address,arglist),initflag,&threadID); - if (hthread!=0) - *thrdaddr=threadID; - return reinterpret_cast(hthread); -} -#endif - -class thread_param -{ -public: - thread_param(const boost::function0& threadfunc) - : m_threadfunc(threadfunc), m_started(false) - { - } - void wait() - { - boost::mutex::scoped_lock scoped_lock(m_mutex); - while (!m_started) - m_condition.wait(scoped_lock); - } - void started() - { - boost::mutex::scoped_lock scoped_lock(m_mutex); - m_started = true; - m_condition.notify_one(); - } - - boost::mutex m_mutex; - boost::condition m_condition; - const boost::function0& m_threadfunc; - bool m_started; -}; - -} // unnamed namespace - -extern "C" { -#if defined(BOOST_HAS_WINTHREADS) - unsigned __stdcall thread_proxy(void* param) -#elif defined(BOOST_HAS_PTHREADS) - static void* thread_proxy(void* param) -#elif defined(BOOST_HAS_MPTASKS) - static OSStatus thread_proxy(void* param) -#endif - { - //try - //{ - thread_param* p = static_cast(param); - boost::function0 threadfunc = p->m_threadfunc; - p->started(); - threadfunc(); -#if defined(BOOST_HAS_WINTHREADS) - on_thread_exit(); -#endif - //} - //catch (...) - //{ -#if defined(BOOST_HAS_WINTHREADS) - // on_thread_exit(); -#endif - //} -#if defined(BOOST_HAS_MPTASKS) - ::boost::detail::thread_cleanup(); -#endif - return 0; - } - -} - -namespace boost { - -thread::thread() - : m_joinable(false) -{ -#if defined(BOOST_HAS_WINTHREADS) - m_thread = reinterpret_cast(GetCurrentThread()); - m_id = GetCurrentThreadId(); -#elif defined(BOOST_HAS_PTHREADS) - m_thread = pthread_self(); -#elif defined(BOOST_HAS_MPTASKS) - threads::mac::detail::thread_init(); - threads::mac::detail::create_singletons(); - m_pTaskID = MPCurrentTaskID(); - m_pJoinQueueID = kInvalidID; -#endif -} - -thread::thread(const function0& threadfunc) - : m_joinable(true) -{ - thread_param param(threadfunc); -#if defined(BOOST_HAS_WINTHREADS) - m_thread = reinterpret_cast(_beginthreadex(0, 0, &thread_proxy, - ¶m, 0, &m_id)); - if (!m_thread) - throw thread_resource_error(); -#elif defined(BOOST_HAS_PTHREADS) - int res = 0; - res = pthread_create(&m_thread, 0, &thread_proxy, ¶m); - if (res != 0) - throw thread_resource_error(); -#elif defined(BOOST_HAS_MPTASKS) - threads::mac::detail::thread_init(); - threads::mac::detail::create_singletons(); - OSStatus lStatus = noErr; - - m_pJoinQueueID = kInvalidID; - m_pTaskID = kInvalidID; - - lStatus = MPCreateQueue(&m_pJoinQueueID); - if (lStatus != noErr) throw thread_resource_error(); - - lStatus = MPCreateTask(&thread_proxy, ¶m, 0UL, m_pJoinQueueID, NULL, - NULL, 0UL, &m_pTaskID); - if (lStatus != noErr) - { - lStatus = MPDeleteQueue(m_pJoinQueueID); - assert(lStatus == noErr); - throw thread_resource_error(); - } -#endif - param.wait(); -} - -thread::~thread() -{ - if (m_joinable) - { -#if defined(BOOST_HAS_WINTHREADS) - int res = 0; - res = CloseHandle(reinterpret_cast(m_thread)); - assert(res); -#elif defined(BOOST_HAS_PTHREADS) - pthread_detach(m_thread); -#elif defined(BOOST_HAS_MPTASKS) - assert(m_pJoinQueueID != kInvalidID); - OSStatus lStatus = MPDeleteQueue(m_pJoinQueueID); - assert(lStatus == noErr); -#endif - } -} - -bool thread::operator==(const thread& other) const -{ -#if defined(BOOST_HAS_WINTHREADS) - return other.m_id == m_id; -#elif defined(BOOST_HAS_PTHREADS) - return pthread_equal(m_thread, other.m_thread) != 0; -#elif defined(BOOST_HAS_MPTASKS) - return other.m_pTaskID == m_pTaskID; -#endif -} - -bool thread::operator!=(const thread& other) const -{ - return !operator==(other); -} - -void thread::join() -{ - assert(m_joinable); //See race condition comment below - int res = 0; -#if defined(BOOST_HAS_WINTHREADS) - res = WaitForSingleObject(reinterpret_cast(m_thread), INFINITE); - assert(res == WAIT_OBJECT_0); - res = CloseHandle(reinterpret_cast(m_thread)); - assert(res); -#elif defined(BOOST_HAS_PTHREADS) - res = pthread_join(m_thread, 0); - assert(res == 0); -#elif defined(BOOST_HAS_MPTASKS) - OSStatus lStatus = threads::mac::detail::safe_wait_on_queue( - m_pJoinQueueID, NULL, NULL, NULL, kDurationForever); - assert(lStatus == noErr); -#endif - // This isn't a race condition since any race that could occur would - // have us in undefined behavior territory any way. - m_joinable = false; -} - -void thread::sleep(const xtime& xt) -{ - for (int foo=0; foo < 5; ++foo) - { -#if defined(BOOST_HAS_WINTHREADS) - int milliseconds; - to_duration(xt, milliseconds); - Sleep(milliseconds); -#elif defined(BOOST_HAS_PTHREADS) -# if defined(BOOST_HAS_PTHREAD_DELAY_NP) - timespec ts; - to_timespec_duration(xt, ts); - int res = 0; - res = pthread_delay_np(&ts); - assert(res == 0); -# elif defined(BOOST_HAS_NANOSLEEP) - timespec ts; - to_timespec_duration(xt, ts); - - // nanosleep takes a timespec that is an offset, not - // an absolute time. - nanosleep(&ts, 0); -# else - mutex mx; - mutex::scoped_lock lock(mx); - condition cond; - cond.timed_wait(lock, xt); -# endif -#elif defined(BOOST_HAS_MPTASKS) - int microseconds; - to_microduration(xt, microseconds); - Duration lMicroseconds(kDurationMicrosecond * microseconds); - AbsoluteTime sWakeTime(DurationToAbsolute(lMicroseconds)); - threads::mac::detail::safe_delay_until(&sWakeTime); -#endif - xtime cur; - xtime_get(&cur, TIME_UTC); - if (xtime_cmp(xt, cur) <= 0) - return; - } -} - -void thread::yield() -{ -#if defined(BOOST_HAS_WINTHREADS) - Sleep(0); -#elif defined(BOOST_HAS_PTHREADS) -# if defined(BOOST_HAS_SCHED_YIELD) - int res = 0; - res = sched_yield(); - assert(res == 0); -# elif defined(BOOST_HAS_PTHREAD_YIELD) - int res = 0; - res = pthread_yield(); - assert(res == 0); -# else - xtime xt; - xtime_get(&xt, TIME_UTC); - sleep(xt); -# endif -#elif defined(BOOST_HAS_MPTASKS) - MPYield(); -#endif -} - -thread_group::thread_group() -{ -} - -thread_group::~thread_group() -{ - // We shouldn't have to scoped_lock here, since referencing this object - // from another thread while we're deleting it in the current thread is - // going to lead to undefined behavior any way. - for (std::list::iterator it = m_threads.begin(); - it != m_threads.end(); ++it) - { - delete (*it); - } -} - -thread* thread_group::create_thread(const function0& threadfunc) -{ - // No scoped_lock required here since the only "shared data" that's - // modified here occurs inside add_thread which does scoped_lock. - std::auto_ptr thrd(new thread(threadfunc)); - add_thread(thrd.get()); - return thrd.release(); -} - -void thread_group::add_thread(thread* thrd) -{ - mutex::scoped_lock scoped_lock(m_mutex); - - // For now we'll simply ignore requests to add a thread object multiple - // times. Should we consider this an error and either throw or return an - // error value? - std::list::iterator it = std::find(m_threads.begin(), - m_threads.end(), thrd); - assert(it == m_threads.end()); - if (it == m_threads.end()) - m_threads.push_back(thrd); -} - -void thread_group::remove_thread(thread* thrd) -{ - mutex::scoped_lock scoped_lock(m_mutex); - - // For now we'll simply ignore requests to remove a thread object that's - // not in the group. Should we consider this an error and either throw or - // return an error value? - std::list::iterator it = std::find(m_threads.begin(), - m_threads.end(), thrd); - assert(it != m_threads.end()); - if (it != m_threads.end()) - m_threads.erase(it); -} - -void thread_group::join_all() -{ - mutex::scoped_lock scoped_lock(m_mutex); - for (std::list::iterator it = m_threads.begin(); - it != m_threads.end(); ++it) - { - (*it)->join(); - } -} - -int thread_group::size() -{ - return m_threads.size(); -} - -} // namespace boost diff --git a/src/tss.cpp b/src/tss.cpp deleted file mode 100644 index 5c77bb52..00000000 --- a/src/tss.cpp +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright (C) 2001-2003 William E. Kempf -// Copyright (C) 2006 Roland Schwarz -// -// 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 -#ifndef BOOST_THREAD_NO_TSS_CLEANUP - -#include -#include -#include -#include -#include -#include -#include - -#if defined(BOOST_HAS_WINTHREADS) -# include -# include -#endif - -namespace { - -typedef std::vector tss_slots; -typedef std::vector*> tss_data_cleanup_handlers_type; - -boost::once_flag tss_data_once = BOOST_ONCE_INIT; -boost::mutex* tss_data_mutex = 0; -tss_data_cleanup_handlers_type* tss_data_cleanup_handlers = 0; -#if defined(BOOST_HAS_WINTHREADS) - DWORD tss_data_native_key=TLS_OUT_OF_INDEXES; -#elif defined(BOOST_HAS_PTHREADS) - pthread_key_t tss_data_native_key; -#elif defined(BOOST_HAS_MPTASKS) - TaskStorageIndex tss_data_native_key; -#endif -int tss_data_use = 0; - -void tss_data_inc_use(boost::mutex::scoped_lock& lk) -{ - ++tss_data_use; -} - -void tss_data_dec_use(boost::mutex::scoped_lock& lk) -{ - if (0 == --tss_data_use) - { - tss_data_cleanup_handlers_type::size_type i; - for (i = 0; i < tss_data_cleanup_handlers->size(); ++i) - { - delete (*tss_data_cleanup_handlers)[i]; - } - delete tss_data_cleanup_handlers; - tss_data_cleanup_handlers = 0; - lk.unlock(); - delete tss_data_mutex; - tss_data_mutex = 0; -#if defined(BOOST_HAS_WINTHREADS) - TlsFree(tss_data_native_key); - tss_data_native_key=TLS_OUT_OF_INDEXES; -#elif defined(BOOST_HAS_PTHREADS) - pthread_key_delete(tss_data_native_key); -#elif defined(BOOST_HAS_MPTASKS) - // Don't know what to put here. - // But MPTASKS isn't currently maintained anyways... -#endif - } -} - -extern "C" void cleanup_slots(void* p) -{ - tss_slots* slots = static_cast(p); - boost::mutex::scoped_lock lock(*tss_data_mutex); - for (tss_slots::size_type i = 0; i < slots->size(); ++i) - { - (*(*tss_data_cleanup_handlers)[i])((*slots)[i]); - (*slots)[i] = 0; - } -#if defined(BOOST_HAS_WINTHREADS) - TlsSetValue(tss_data_native_key,0); -#endif - tss_data_dec_use(lock); - delete slots; -} - -void init_tss_data() -{ - std::auto_ptr - temp(new tss_data_cleanup_handlers_type); - - std::auto_ptr temp_mutex(new boost::mutex); - if (temp_mutex.get() == 0) - throw boost::thread_resource_error(); - -#if defined(BOOST_HAS_WINTHREADS) - //Force the cleanup implementation library to be linked in - tss_cleanup_implemented(); - - //Allocate tls slot - tss_data_native_key = TlsAlloc(); - if (tss_data_native_key == TLS_OUT_OF_INDEXES) - return; -#elif defined(BOOST_HAS_PTHREADS) - int res = pthread_key_create(&tss_data_native_key, &cleanup_slots); - if (res != 0) - return; -#elif defined(BOOST_HAS_MPTASKS) - OSStatus status = MPAllocateTaskStorageIndex(&tss_data_native_key); - if (status != noErr) - return; -#endif - - // The life time of cleanup handlers and mutex is beeing - // managed by a reference counting technique. - // This avoids a memory leak by releasing the global data - // after last use only, since the execution order of cleanup - // handlers is unspecified on any platform with regards to - // C++ destructor ordering rules. - tss_data_cleanup_handlers = temp.release(); - tss_data_mutex = temp_mutex.release(); -} - -#if defined(BOOST_HAS_WINTHREADS) -tss_slots* get_slots(bool alloc); - -void __cdecl tss_thread_exit() -{ - tss_slots* slots = get_slots(false); - if (slots) - cleanup_slots(slots); -} -#endif - -tss_slots* get_slots(bool alloc) -{ - tss_slots* slots = 0; - -#if defined(BOOST_HAS_WINTHREADS) - slots = static_cast( - TlsGetValue(tss_data_native_key)); -#elif defined(BOOST_HAS_PTHREADS) - slots = static_cast( - pthread_getspecific(tss_data_native_key)); -#elif defined(BOOST_HAS_MPTASKS) - slots = static_cast( - MPGetTaskStorageValue(tss_data_native_key)); -#endif - - if (slots == 0 && alloc) - { - std::auto_ptr temp(new tss_slots); - -#if defined(BOOST_HAS_WINTHREADS) - if (at_thread_exit(&tss_thread_exit) == -1) - return 0; - if (!TlsSetValue(tss_data_native_key, temp.get())) - return 0; -#elif defined(BOOST_HAS_PTHREADS) - if (pthread_setspecific(tss_data_native_key, temp.get()) != 0) - return 0; -#elif defined(BOOST_HAS_MPTASKS) - if (MPSetTaskStorageValue(tss_data_native_key, temp.get()) != noErr) - return 0; -#endif - { - boost::mutex::scoped_lock lock(*tss_data_mutex); - tss_data_inc_use(lock); - } - slots = temp.release(); - } - - return slots; -} - -} // namespace - -namespace boost { - -namespace detail { -void tss::init(boost::function1* pcleanup) -{ - boost::call_once(&init_tss_data, tss_data_once); - if (tss_data_cleanup_handlers == 0) - throw thread_resource_error(); - boost::mutex::scoped_lock lock(*tss_data_mutex); - try - { - tss_data_cleanup_handlers->push_back(pcleanup); - m_slot = tss_data_cleanup_handlers->size() - 1; - tss_data_inc_use(lock); - } - catch (...) - { - throw thread_resource_error(); - } -} - -tss::~tss() -{ - boost::mutex::scoped_lock lock(*tss_data_mutex); - tss_data_dec_use(lock); -} - -void* tss::get() const -{ - tss_slots* slots = get_slots(false); - - if (!slots) - return 0; - - if (m_slot >= slots->size()) - return 0; - - return (*slots)[m_slot]; -} - -void tss::set(void* value) -{ - tss_slots* slots = get_slots(true); - - if (!slots) - throw boost::thread_resource_error(); - - if (m_slot >= slots->size()) - { - try - { - slots->resize(m_slot + 1); - } - catch (...) - { - throw boost::thread_resource_error(); - } - } - - (*slots)[m_slot] = value; -} - -void tss::cleanup(void* value) -{ - boost::mutex::scoped_lock lock(*tss_data_mutex); - (*(*tss_data_cleanup_handlers)[m_slot])(value); -} - -} // namespace detail -} // namespace boost - -#endif //BOOST_THREAD_NO_TSS_CLEANUP diff --git a/src/tss_hooks.cpp b/src/tss_hooks.cpp deleted file mode 100644 index be4bb097..00000000 --- a/src/tss_hooks.cpp +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright (C) 2004 Michael Glassford -// Copyright (C) 2006 Roland Schwarz -// Use, modification and distribution are subject to 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 - -#if defined(BOOST_HAS_WINTHREADS) - - #include - - #include -// #include - #include - - #include - - #define WIN32_LEAN_AND_MEAN - #include - - namespace - { - class CScopedCSLock - { - public: - CScopedCSLock(LPCRITICAL_SECTION cs) : cs(cs), lk(true) { - ::EnterCriticalSection(cs); - } - ~CScopedCSLock() { - if (lk) ::LeaveCriticalSection(cs); - } - void Unlock() { - lk = false; - ::LeaveCriticalSection(cs); - } - private: - bool lk; - LPCRITICAL_SECTION cs; - }; - - typedef std::list thread_exit_handlers; - - boost::once_flag once_init_threadmon_mutex = BOOST_ONCE_INIT; - //boost::mutex* threadmon_mutex; - // We don't use boost::mutex here, to avoid a memory leak report, - // because we cannot delete it again easily. - CRITICAL_SECTION threadmon_mutex; - void init_threadmon_mutex(void) - { - //threadmon_mutex = new boost::mutex; - //if (!threadmon_mutex) - // throw boost::thread_resource_error(); - ::InitializeCriticalSection(&threadmon_mutex); - } - - const DWORD invalid_tls_key = TLS_OUT_OF_INDEXES; - DWORD tls_key = invalid_tls_key; - - unsigned long attached_thread_count = 0; - } - - /* - Calls to DllMain() and tls_callback() are serialized by the OS; - however, calls to at_thread_exit are not, so it must be protected - by a mutex. Since we already need a mutex for at_thread_exit(), - and since there is no guarantee that on_process_enter(), - on_process_exit(), on_thread_enter(), and on_thread_exit() - will be called only from DllMain() or tls_callback(), it makes - sense to protect those, too. - */ - - extern "C" BOOST_THREAD_DECL int at_thread_exit( - thread_exit_handler exit_handler - ) - { - boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex); - //boost::mutex::scoped_lock lock(*threadmon_mutex); - CScopedCSLock lock(&threadmon_mutex); - - //Allocate a tls slot if necessary. - - if (tls_key == invalid_tls_key) - tls_key = TlsAlloc(); - - if (tls_key == invalid_tls_key) - return -1; - - //Get the exit handlers list for the current thread from tls. - - thread_exit_handlers* exit_handlers = - static_cast(TlsGetValue(tls_key)); - - if (!exit_handlers) - { - //No exit handlers list was created yet. - - try - { - //Attempt to create a new exit handlers list. - - exit_handlers = new thread_exit_handlers; - if (!exit_handlers) - return -1; - - //Attempt to store the list pointer in tls. - - if (TlsSetValue(tls_key, exit_handlers)) - ++attached_thread_count; - else - { - delete exit_handlers; - return -1; - } - } - catch (...) - { - return -1; - } - } - - //Like the C runtime library atexit() function, - //functions should be called in the reverse of - //the order they are added, so push them on the - //front of the list. - - try - { - exit_handlers->push_front(exit_handler); - } - catch (...) - { - return -1; - } - - //Like the atexit() function, a result of zero - //indicates success. - - return 0; - } - - extern "C" BOOST_THREAD_DECL void on_process_enter(void) - { - boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex); -// boost::mutex::scoped_lock lock(*threadmon_mutex); - CScopedCSLock lock(&threadmon_mutex); - - BOOST_ASSERT(attached_thread_count == 0); - } - - extern "C" BOOST_THREAD_DECL void on_process_exit(void) - { - boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex); -// boost::mutex::scoped_lock lock(*threadmon_mutex); - CScopedCSLock lock(&threadmon_mutex); - - BOOST_ASSERT(attached_thread_count == 0); - - //Free the tls slot if one was allocated. - - if (tls_key != invalid_tls_key) - { - TlsFree(tls_key); - tls_key = invalid_tls_key; - } - } - - extern "C" BOOST_THREAD_DECL void on_thread_enter(void) - { - //boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex); - //boost::mutex::scoped_lock lock(*threadmon_mutex); - } - - extern "C" BOOST_THREAD_DECL void on_thread_exit(void) - { - boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex); -// boost::mutex::scoped_lock lock(*threadmon_mutex); - CScopedCSLock lock(&threadmon_mutex); - - //Get the exit handlers list for the current thread from tls. - - if (tls_key == invalid_tls_key) - return; - - thread_exit_handlers* exit_handlers = - static_cast(TlsGetValue(tls_key)); - - //If a handlers list was found, use it. - - if (exit_handlers && TlsSetValue(tls_key, 0)) - { - BOOST_ASSERT(attached_thread_count > 0); - --attached_thread_count; - - //lock.unlock(); - lock.Unlock(); - - //Call each handler and remove it from the list - - while (!exit_handlers->empty()) - { - if (thread_exit_handler exit_handler = *exit_handlers->begin()) - (*exit_handler)(); - exit_handlers->pop_front(); - } - - delete exit_handlers; - exit_handlers = 0; - } - } - -#endif //defined(BOOST_HAS_WINTHREADS) diff --git a/src/tss_null.cpp b/src/tss_null.cpp index 07271782..3288c679 100644 --- a/src/tss_null.cpp +++ b/src/tss_null.cpp @@ -1,11 +1,12 @@ // (C) Copyright Michael Glassford 2004. +// (C) Copyright 2007 Anthony Williams // Use, modification and distribution are subject to 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 -#if defined(BOOST_HAS_WINTHREADS) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST)) && !defined(_MSC_VER) +#if defined(BOOST_HAS_WINTHREADS) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST)) && (!defined(_MSC_VER) || defined(UNDER_CE)) /* This file is a "null" implementation of tss cleanup; it's diff --git a/src/win32/exceptions.cpp b/src/win32/exceptions.cpp new file mode 100644 index 00000000..88813036 --- /dev/null +++ b/src/win32/exceptions.cpp @@ -0,0 +1,124 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// +// 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 + +namespace boost { + +thread_exception::thread_exception() + : m_sys_err(0) +{ +} + +thread_exception::thread_exception(int sys_err_code) + : m_sys_err(sys_err_code) +{ +} + +thread_exception::~thread_exception() throw() +{ +} + +int thread_exception::native_error() const +{ + return m_sys_err; +} + +lock_error::lock_error() +{ +} + +lock_error::lock_error(int sys_err_code) + : thread_exception(sys_err_code) +{ +} + +lock_error::~lock_error() throw() +{ +} + +const char* lock_error::what() const throw() +{ + return "boost::lock_error"; +} + +thread_resource_error::thread_resource_error() +{ +} + +thread_resource_error::thread_resource_error(int sys_err_code) + : thread_exception(sys_err_code) +{ +} + +thread_resource_error::~thread_resource_error() throw() +{ +} + +const char* thread_resource_error::what() const throw() +{ + return "boost::thread_resource_error"; +} + +unsupported_thread_option::unsupported_thread_option() +{ +} + +unsupported_thread_option::unsupported_thread_option(int sys_err_code) + : thread_exception(sys_err_code) +{ +} + +unsupported_thread_option::~unsupported_thread_option() throw() +{ +} + +const char* unsupported_thread_option::what() const throw() +{ + return "boost::unsupported_thread_option"; +} + +invalid_thread_argument::invalid_thread_argument() +{ +} + +invalid_thread_argument::invalid_thread_argument(int sys_err_code) + : thread_exception(sys_err_code) +{ +} + +invalid_thread_argument::~invalid_thread_argument() throw() +{ +} + +const char* invalid_thread_argument::what() const throw() +{ + return "boost::invalid_thread_argument"; +} + +thread_permission_error::thread_permission_error() +{ +} + +thread_permission_error::thread_permission_error(int sys_err_code) + : thread_exception(sys_err_code) +{ +} + +thread_permission_error::~thread_permission_error() throw() +{ +} + +const char* thread_permission_error::what() const throw() +{ + return "boost::thread_permission_error"; +} + +} // namespace boost diff --git a/src/win32/thread.cpp b/src/win32/thread.cpp new file mode 100644 index 00000000..fa83b7cf --- /dev/null +++ b/src/win32/thread.cpp @@ -0,0 +1,528 @@ +// 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 2007 Anthony Williams +// (C) Copyright 2007 David Deakins + +#include +#include +#include +#ifndef UNDER_CE +#include +#endif +#include +#include +#include +#include +#include + +namespace boost +{ + namespace + { + boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT; + DWORD current_thread_tls_key=0; + + void create_current_thread_tls_key() + { + current_thread_tls_key=TlsAlloc(); + BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES); + } + + detail::thread_data_base* get_current_thread_data() + { + boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key); + return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key); + } + + void set_current_thread_data(detail::thread_data_base* new_data) + { + boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key); + BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data)); + } + +#ifdef BOOST_NO_THREADEX +// Windows CE doesn't define _beginthreadex + + struct ThreadProxyData + { + typedef unsigned (__stdcall* func)(void*); + func start_address_; + void* arglist_; + ThreadProxyData(func start_address,void* arglist) : start_address_(start_address), arglist_(arglist) {} + }; + + DWORD WINAPI ThreadProxy(LPVOID args) + { + ThreadProxyData* data=reinterpret_cast(args); + DWORD ret=data->start_address_(data->arglist_); + delete data; + return ret; + } + + typedef void* uintptr_t; + + inline uintptr_t const _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*), + void* arglist, unsigned initflag, unsigned* thrdaddr) + { + DWORD threadID; + HANDLE hthread=CreateThread(static_cast(security),stack_size,ThreadProxy, + new ThreadProxyData(start_address,arglist),initflag,&threadID); + if (hthread!=0) + *thrdaddr=threadID; + return reinterpret_cast(hthread); + } + +#endif + + } + + void thread::yield() + { + this_thread::yield(); + } + + void thread::sleep(const system_time& target) + { + system_time const now(get_system_time()); + + if(target<=now) + { + this_thread::yield(); + } + else + { + this_thread::sleep(target-now); + } + } + + namespace detail + { + struct thread_exit_callback_node + { + boost::detail::thread_exit_function_base* func; + thread_exit_callback_node* next; + + thread_exit_callback_node(boost::detail::thread_exit_function_base* func_, + thread_exit_callback_node* next_): + func(func_),next(next_) + {} + }; + + struct tss_data_node + { + void const* key; + boost::shared_ptr func; + void* value; + tss_data_node* next; + + tss_data_node(void const* key_,boost::shared_ptr func_,void* value_, + tss_data_node* next_): + key(key_),func(func_),value(value_),next(next_) + {} + }; + + } + + namespace + { + void run_thread_exit_callbacks() + { + detail::thread_data_ptr current_thread_data(get_current_thread_data(),false); + if(current_thread_data) + { + while(current_thread_data->tss_data || current_thread_data->thread_exit_callbacks) + { + while(current_thread_data->thread_exit_callbacks) + { + detail::thread_exit_callback_node* const current_node=current_thread_data->thread_exit_callbacks; + current_thread_data->thread_exit_callbacks=current_node->next; + if(current_node->func) + { + (*current_node->func)(); + boost::detail::heap_delete(current_node->func); + } + boost::detail::heap_delete(current_node); + } + while(current_thread_data->tss_data) + { + detail::tss_data_node* const current_node=current_thread_data->tss_data; + current_thread_data->tss_data=current_node->next; + if(current_node->func) + { + (*current_node->func)(current_node->value); + } + boost::detail::heap_delete(current_node); + } + } + + } + set_current_thread_data(0); + } + + } + + + unsigned __stdcall thread::thread_start_function(void* param) + { + detail::thread_data_base* const thread_info(reinterpret_cast(param)); + set_current_thread_data(thread_info); + try + { + thread_info->run(); + } + catch(thread_interrupted const&) + { + } + catch(...) + { + std::terminate(); + } + run_thread_exit_callbacks(); + return 0; + } + + thread::thread() + {} + + void thread::start_thread() + { + uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id); + if(!new_thread) + { + throw thread_resource_error(); + } + intrusive_ptr_add_ref(thread_info.get()); + thread_info->thread_handle=(detail::win32::handle)(new_thread); + ResumeThread(thread_info->thread_handle); + } + + thread::thread(detail::thread_data_ptr data): + thread_info(data) + {} + + namespace + { + struct externally_launched_thread: + detail::thread_data_base + { + externally_launched_thread() + { + ++count; + interruption_enabled=false; + } + + void run() + {} + }; + + void make_external_thread_data() + { + externally_launched_thread* me=detail::heap_new(); + set_current_thread_data(me); + } + + detail::thread_data_base* get_or_make_current_thread_data() + { + detail::thread_data_base* current_thread_data(get_current_thread_data()); + if(!current_thread_data) + { + make_external_thread_data(); + current_thread_data=get_current_thread_data(); + } + return current_thread_data; + } + + } + + thread::~thread() + { + detach(); + } + + thread::thread(boost::move_t x) + { + { + boost::mutex::scoped_lock l(x->thread_info_mutex); + thread_info=x->thread_info; + } + x->release_handle(); + } + + thread& thread::operator=(boost::move_t x) + { + thread new_thread(x); + swap(new_thread); + return *this; + } + + thread::operator boost::move_t() + { + return move(); + } + + boost::move_t thread::move() + { + boost::move_t x(*this); + return x; + } + + void thread::swap(thread& x) + { + thread_info.swap(x.thread_info); + } + + thread::id thread::get_id() const + { + return thread::id(get_thread_info()); + } + + bool thread::joinable() const + { + return get_thread_info(); + } + + void thread::join() + { + detail::thread_data_ptr local_thread_info=get_thread_info(); + if(local_thread_info) + { + this_thread::interruptible_wait(local_thread_info->thread_handle,detail::win32::infinite); + release_handle(); + } + } + + bool thread::timed_join(boost::system_time const& wait_until) + { + detail::thread_data_ptr local_thread_info=get_thread_info(); + if(local_thread_info) + { + if(!this_thread::interruptible_wait(local_thread_info->thread_handle,get_milliseconds_until(wait_until))) + { + return false; + } + release_handle(); + } + return true; + } + + void thread::detach() + { + release_handle(); + } + + void thread::release_handle() + { + boost::mutex::scoped_lock l1(thread_info_mutex); + thread_info=0; + } + + void thread::interrupt() + { + detail::thread_data_ptr local_thread_info=get_thread_info(); + if(local_thread_info) + { + local_thread_info->interrupt(); + } + } + + bool thread::interruption_requested() const + { + detail::thread_data_ptr local_thread_info=get_thread_info(); + return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0); + } + + unsigned thread::hardware_concurrency() + { + SYSTEM_INFO info={0}; + GetSystemInfo(&info); + return info.dwNumberOfProcessors; + } + + thread::native_handle_type thread::native_handle() + { + detail::thread_data_ptr local_thread_info=get_thread_info(); + return local_thread_info?(detail::win32::handle)local_thread_info->thread_handle:detail::win32::invalid_handle_value; + } + + detail::thread_data_ptr thread::get_thread_info() const + { + boost::mutex::scoped_lock l(thread_info_mutex); + return thread_info; + } + + namespace this_thread + { + bool interruptible_wait(detail::win32::handle handle_to_wait_for,unsigned long milliseconds) + { + detail::win32::handle handles[2]={0}; + unsigned handle_count=0; + unsigned interruption_index=~0U; + if(handle_to_wait_for!=detail::win32::invalid_handle_value) + { + handles[handle_count++]=handle_to_wait_for; + } + if(get_current_thread_data() && get_current_thread_data()->interruption_enabled) + { + interruption_index=handle_count; + handles[handle_count++]=get_current_thread_data()->interruption_handle; + } + + if(handle_count) + { + unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,milliseconds); + if((handle_to_wait_for!=detail::win32::invalid_handle_value) && !notified_index) + { + return true; + } + else if(notified_index==interruption_index) + { + detail::win32::ResetEvent(get_current_thread_data()->interruption_handle); + throw thread_interrupted(); + } + } + else + { + detail::win32::Sleep(milliseconds); + } + return false; + } + + thread::id get_id() + { + return thread::id(get_or_make_current_thread_data()); + } + + void interruption_point() + { + if(interruption_enabled() && interruption_requested()) + { + detail::win32::ResetEvent(get_current_thread_data()->interruption_handle); + throw thread_interrupted(); + } + } + + bool interruption_enabled() + { + return get_current_thread_data() && get_current_thread_data()->interruption_enabled; + } + + bool interruption_requested() + { + return get_current_thread_data() && (detail::win32::WaitForSingleObject(get_current_thread_data()->interruption_handle,0)==0); + } + + void yield() + { + detail::win32::Sleep(0); + } + + disable_interruption::disable_interruption(): + interruption_was_enabled(interruption_enabled()) + { + if(interruption_was_enabled) + { + get_current_thread_data()->interruption_enabled=false; + } + } + + disable_interruption::~disable_interruption() + { + if(get_current_thread_data()) + { + get_current_thread_data()->interruption_enabled=interruption_was_enabled; + } + } + + restore_interruption::restore_interruption(disable_interruption& d) + { + if(d.interruption_was_enabled) + { + get_current_thread_data()->interruption_enabled=true; + } + } + + restore_interruption::~restore_interruption() + { + if(get_current_thread_data()) + { + get_current_thread_data()->interruption_enabled=false; + } + } + } + + namespace detail + { + void add_thread_exit_function(thread_exit_function_base* func) + { + detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); + thread_exit_callback_node* const new_node= + heap_new(func, + current_thread_data->thread_exit_callbacks); + current_thread_data->thread_exit_callbacks=new_node; + } + + tss_data_node* find_tss_data(void const* key) + { + detail::thread_data_base* const current_thread_data(get_current_thread_data()); + if(current_thread_data) + { + detail::tss_data_node* current_node=current_thread_data->tss_data; + while(current_node) + { + if(current_node->key==key) + { + return current_node; + } + current_node=current_node->next; + } + } + return NULL; + } + + void* get_tss_data(void const* key) + { + if(tss_data_node* const current_node=find_tss_data(key)) + { + return current_node->value; + } + return NULL; + } + + void set_tss_data(void const* key,boost::shared_ptr func,void* tss_data,bool cleanup_existing) + { + tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in + if(tss_data_node* const current_node=find_tss_data(key)) + { + if(cleanup_existing && current_node->func) + { + (*current_node->func)(current_node->value); + } + current_node->func=func; + current_node->value=tss_data; + } + else + { + detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); + tss_data_node* const new_node=heap_new(key,func,tss_data,current_thread_data->tss_data); + current_thread_data->tss_data=new_node; + } + } + } +} + + +extern "C" BOOST_THREAD_DECL void on_process_enter() +{} + +extern "C" BOOST_THREAD_DECL void on_thread_enter() +{} + +extern "C" BOOST_THREAD_DECL void on_process_exit() +{} + +extern "C" BOOST_THREAD_DECL void on_thread_exit() +{ + boost::run_thread_exit_callbacks(); +} + diff --git a/src/win32/timeconv.inl b/src/win32/timeconv.inl new file mode 100644 index 00000000..5ec3b179 --- /dev/null +++ b/src/win32/timeconv.inl @@ -0,0 +1,130 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// +// 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) + +// boostinspect:nounnamed + +namespace { +const int MILLISECONDS_PER_SECOND = 1000; +const int NANOSECONDS_PER_SECOND = 1000000000; +const int NANOSECONDS_PER_MILLISECOND = 1000000; + +const int MICROSECONDS_PER_SECOND = 1000000; +const int NANOSECONDS_PER_MICROSECOND = 1000; + +inline void to_time(int milliseconds, boost::xtime& xt) +{ + int res = 0; + res = boost::xtime_get(&xt, boost::TIME_UTC); + assert(res == boost::TIME_UTC); + + xt.sec += (milliseconds / MILLISECONDS_PER_SECOND); + xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) * + NANOSECONDS_PER_MILLISECOND); + + if (xt.nsec >= NANOSECONDS_PER_SECOND) + { + ++xt.sec; + xt.nsec -= NANOSECONDS_PER_SECOND; + } +} + +#if defined(BOOST_HAS_PTHREADS) +inline void to_timespec(const boost::xtime& xt, timespec& ts) +{ + ts.tv_sec = static_cast(xt.sec); + ts.tv_nsec = static_cast(xt.nsec); + if(ts.tv_nsec >= NANOSECONDS_PER_SECOND) + { + ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND; + ts.tv_nsec %= NANOSECONDS_PER_SECOND; + } +} + +inline void to_time(int milliseconds, timespec& ts) +{ + boost::xtime xt; + to_time(milliseconds, xt); + to_timespec(xt, ts); +} + +inline void to_timespec_duration(const boost::xtime& xt, timespec& ts) +{ + boost::xtime cur; + int res = 0; + res = boost::xtime_get(&cur, boost::TIME_UTC); + assert(res == boost::TIME_UTC); + + if (boost::xtime_cmp(xt, cur) <= 0) + { + ts.tv_sec = 0; + ts.tv_nsec = 0; + } + else + { + ts.tv_sec = xt.sec - cur.sec; + ts.tv_nsec = xt.nsec - cur.nsec; + + if( ts.tv_nsec < 0 ) + { + ts.tv_sec -= 1; + ts.tv_nsec += NANOSECONDS_PER_SECOND; + } + if(ts.tv_nsec >= NANOSECONDS_PER_SECOND) + { + ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND; + ts.tv_nsec %= NANOSECONDS_PER_SECOND; + } + } +} +#endif + +inline void to_duration(boost::xtime xt, int& milliseconds) +{ + boost::xtime cur; + int res = 0; + res = boost::xtime_get(&cur, boost::TIME_UTC); + assert(res == boost::TIME_UTC); + + if (boost::xtime_cmp(xt, cur) <= 0) + milliseconds = 0; + else + { + if (cur.nsec > xt.nsec) + { + xt.nsec += NANOSECONDS_PER_SECOND; + --xt.sec; + } + milliseconds = (int)((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) + + (((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) / + NANOSECONDS_PER_MILLISECOND); + } +} + +inline void to_microduration(boost::xtime xt, int& microseconds) +{ + boost::xtime cur; + int res = 0; + res = boost::xtime_get(&cur, boost::TIME_UTC); + assert(res == boost::TIME_UTC); + + if (boost::xtime_cmp(xt, cur) <= 0) + microseconds = 0; + else + { + if (cur.nsec > xt.nsec) + { + xt.nsec += NANOSECONDS_PER_SECOND; + --xt.sec; + } + microseconds = (int)((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) + + (((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) / + NANOSECONDS_PER_MICROSECOND); + } +} +} + +// Change Log: +// 1 Jun 01 Initial creation. diff --git a/src/tss_dll.cpp b/src/win32/tss_dll.cpp similarity index 100% rename from src/tss_dll.cpp rename to src/win32/tss_dll.cpp diff --git a/src/tss_pe.cpp b/src/win32/tss_pe.cpp similarity index 69% rename from src/tss_pe.cpp rename to src/win32/tss_pe.cpp index 0e250092..4528b90f 100644 --- a/src/tss_pe.cpp +++ b/src/win32/tss_pe.cpp @@ -1,11 +1,83 @@ +// $Id$ // (C) Copyright Aaron W. LaFramboise, Roland Schwarz, Michael Glassford 2004. +// (C) Copyright 2007 Roland Schwarz +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007 David Deakins // Use, modification and distribution are subject to 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 -#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) && defined(_MSC_VER) +#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) + +#if defined(__MINGW32__) && !defined(_WIN64) + +#include + +#include + +#include + +extern "C" void tss_cleanup_implemented(void) {} + +namespace { + void NTAPI on_tls_callback(void* h, DWORD dwReason, PVOID pv) + { + switch (dwReason) + { + case DLL_THREAD_DETACH: + { + on_thread_exit(); + break; + } + } + } + + void on_after_ctors(void) + { + on_process_enter(); + } + + void on_before_dtors(void) + { + on_thread_exit(); + } + + void on_after_dtors(void) + { + on_process_exit(); + } +} + +extern "C" { + + void (* after_ctors )(void) __attribute__((section(".ctors"))) = on_after_ctors; + void (* before_dtors)(void) __attribute__((section(".dtors"))) = on_before_dtors; + void (* after_dtors )(void) __attribute__((section(".dtors.zzz"))) = on_after_dtors; + + ULONG __tls_index__ = 0; + char __tls_end__ __attribute__((section(".tls$zzz"))) = 0; + char __tls_start__ __attribute__((section(".tls"))) = 0; + + + PIMAGE_TLS_CALLBACK __crt_xl_start__ __attribute__ ((section(".CRT$XLA"))) = 0; + PIMAGE_TLS_CALLBACK __crt_xl_tls_callback__ __attribute__ ((section(".CRT$XLB"))) = on_tls_callback; + PIMAGE_TLS_CALLBACK __crt_xl_end__ __attribute__ ((section(".CRT$XLZ"))) = 0; +} + +extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata$T"))) = +{ + (DWORD) &__tls_start__, + (DWORD) &__tls_end__, + (DWORD) &__tls_index__, + (DWORD) (&__crt_xl_start__+1), + (DWORD) 0, + (DWORD) 0 +}; + + +#elif defined(_MSC_VER) && !defined(UNDER_CE) #include @@ -48,6 +120,16 @@ //The .CRT$Xxx information is taken from Codeguru: //http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/ +#if (_MSC_VER >= 1400) +#pragma section(".CRT$XIU",long,read) +#pragma section(".CRT$XCU",long,read) +#pragma section(".CRT$XTU",long,read) +#pragma section(".CRT$XLC",long,read) + static __declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback; + static __declspec(allocate(".CRT$XIU"))_PVFV p_tls_prepare = on_tls_prepare; + static __declspec(allocate(".CRT$XCU"))_PVFV p_process_init = on_process_init; + static __declspec(allocate(".CRT$XTU"))_PVFV p_process_term = on_process_term; +#else #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 # pragma data_seg(push, old_seg) #endif @@ -72,7 +154,6 @@ #pragma data_seg(".CRT$XLB") _TLSCB p_thread_callback = on_tls_callback; #pragma data_seg() - //Callback for termination. #pragma data_seg(".CRT$XTU") @@ -81,6 +162,7 @@ #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 # pragma data_seg(pop, old_seg) #endif +#endif PVAPI on_tls_prepare(void) { @@ -148,10 +230,13 @@ void NTAPI on_tls_callback(HINSTANCE h, DWORD dwReason, PVOID pv) { + OutputDebugString("on_tls_callback\n"); + switch (dwReason) { case DLL_THREAD_DETACH: { + OutputDebugString("on_tls_callback: thread_exit\n"); on_thread_exit(); break; } @@ -175,5 +260,6 @@ longer needed and can be removed. */ } +#endif //defined(_MSC_VER) && !defined(UNDER_CE) #endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) diff --git a/src/xtime.cpp b/src/xtime.cpp deleted file mode 100644 index 0ae854ff..00000000 --- a/src/xtime.cpp +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (C) 2001-2003 -// William E. Kempf -// -// 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 - -#if defined(BOOST_HAS_FTIME) -# define __STDC_CONSTANT_MACROS -#endif - -#include - -#if defined(BOOST_HAS_FTIME) -# include -# include -#elif defined(BOOST_HAS_GETTIMEOFDAY) -# include -#elif defined(BOOST_HAS_MPTASKS) -# include -# include -#endif - -#include - -namespace boost { - -#ifdef BOOST_HAS_MPTASKS - -namespace detail -{ - -using thread::force_cast; - -struct startup_time_info -{ - startup_time_info() - { - // 1970 Jan 1 at 00:00:00 - static const DateTimeRec k_sUNIXBase = {1970, 1, 1, 0, 0, 0, 0}; - static unsigned long s_ulUNIXBaseSeconds = 0UL; - - if(s_ulUNIXBaseSeconds == 0UL) - { - // calculate the number of seconds between the Mac OS base and the - // UNIX base the first time we enter this constructor. - DateToSeconds(&k_sUNIXBase, &s_ulUNIXBaseSeconds); - } - - unsigned long ulSeconds; - - // get the time in UpTime units twice, with the time in seconds in the - // middle. - uint64_t ullFirstUpTime = force_cast(UpTime()); - GetDateTime(&ulSeconds); - uint64_t ullSecondUpTime = force_cast(UpTime()); - - // calculate the midpoint of the two UpTimes, and save that. - uint64_t ullAverageUpTime = (ullFirstUpTime + ullSecondUpTime) / 2ULL; - m_sStartupAbsoluteTime = force_cast(ullAverageUpTime); - - // save the number of seconds, recentered at the UNIX base. - m_ulStartupSeconds = ulSeconds - s_ulUNIXBaseSeconds; - } - - AbsoluteTime m_sStartupAbsoluteTime; - UInt32 m_ulStartupSeconds; -}; - -static startup_time_info g_sStartupTimeInfo; - -} // namespace detail - -#endif - - -int xtime_get(struct xtime* xtp, int clock_type) -{ - if (clock_type == TIME_UTC) - { -#if defined(BOOST_HAS_FTIME) - FILETIME ft; -# if defined(BOOST_NO_GETSYSTEMTIMEASFILETIME) - { - SYSTEMTIME st; - GetSystemTime(&st); - SystemTimeToFileTime(&st,&ft); - } -# else - GetSystemTimeAsFileTime(&ft); -# endif - static const boost::uint64_t TIMESPEC_TO_FILETIME_OFFSET = - UINT64_C(116444736000000000); - - const boost::uint64_t ft64 = - (static_cast(ft.dwHighDateTime) << 32) - + ft.dwLowDateTime; - - xtp->sec = static_cast( - (ft64 - TIMESPEC_TO_FILETIME_OFFSET) / 10000000 - ); - - xtp->nsec = static_cast( - ((ft64 - TIMESPEC_TO_FILETIME_OFFSET) % 10000000) * 100 - ); - - return clock_type; -#elif defined(BOOST_HAS_GETTIMEOFDAY) - struct timeval tv; -# ifndef NDEBUG - int res = -#endif - gettimeofday(&tv, 0); - assert(0 == res); - assert(tv.tv_sec >= 0); - assert(tv.tv_usec >= 0); - xtp->sec = tv.tv_sec; - xtp->nsec = tv.tv_usec * 1000; - return clock_type; -#elif defined(BOOST_HAS_CLOCK_GETTIME) - timespec ts; -# ifndef NDEBUG - int res = -# endif - clock_gettime(CLOCK_REALTIME, &ts); - assert(0 == res); - xtp->sec = ts.tv_sec; - xtp->nsec = ts.tv_nsec; - return clock_type; -#elif defined(BOOST_HAS_MPTASKS) - using detail::thread::force_cast; - // the Mac OS does not have an MP-safe way of getting the date/time, - // so we use a delta from the startup time. We _could_ defer this - // and use something that is interrupt-safe, but this would be _SLOW_, - // and we need speed here. - const uint64_t k_ullNanosecondsPerSecond(1000ULL * 1000ULL * 1000ULL); - AbsoluteTime sUpTime(UpTime()); - uint64_t ullNanoseconds( - force_cast( - AbsoluteDeltaToNanoseconds(sUpTime, - detail::g_sStartupTimeInfo.m_sStartupAbsoluteTime))); - uint64_t ullSeconds = (ullNanoseconds / k_ullNanosecondsPerSecond); - ullNanoseconds -= (ullSeconds * k_ullNanosecondsPerSecond); - xtp->sec = detail::g_sStartupTimeInfo.m_ulStartupSeconds + ullSeconds; - xtp->nsec = ullNanoseconds; - return clock_type; -#else -# error "xtime_get implementation undefined" -#endif - } - return 0; -} - -} // namespace boost - -// Change Log: -// 8 Feb 01 WEKEMPF Initial version. diff --git a/test/.cvsignore b/test/.cvsignore deleted file mode 100644 index cdbfc82a..00000000 --- a/test/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -bin -*.pdb diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index f3605d5b..209e6b07 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -40,6 +40,7 @@ rule thread-run ( sources ) [ thread-run test_once.cpp ] [ thread-run test_xtime.cpp ] [ thread-run test_barrier.cpp ] -# [ thread-run test_read_write_mutex.cpp ] + [ thread-run test_shared_mutex.cpp ] + [ thread-run test_lock_concept.cpp ] ; } diff --git a/test/test_barrier.cpp b/test/test_barrier.cpp index b6982966..bccd346f 100644 --- a/test/test_barrier.cpp +++ b/test/test_barrier.cpp @@ -10,6 +10,7 @@ #include #include +#include namespace { @@ -38,11 +39,19 @@ void test_barrier() boost::thread_group g; global_parameter = 0; - for (int i = 0; i < N_THREADS; ++i) - g.create_thread(&barrier_thread); - - g.join_all(); - + try + { + for (int i = 0; i < N_THREADS; ++i) + g.create_thread(&barrier_thread); + g.join_all(); + } + catch(...) + { + g.interrupt_all(); + g.join_all(); + throw; + } + BOOST_CHECK(global_parameter == 5); } diff --git a/test/test_condition.cpp b/test/test_condition.cpp index 4570f06e..2dbe32d0 100644 --- a/test/test_condition.cpp +++ b/test/test_condition.cpp @@ -103,7 +103,7 @@ void do_test_condition_notify_one() void test_condition_notify_one() { - timed_test(&do_test_condition_notify_one, 2, execution_monitor::use_mutex); + timed_test(&do_test_condition_notify_one, 100, execution_monitor::use_mutex); } void do_test_condition_notify_all() @@ -112,17 +112,27 @@ void do_test_condition_notify_all() boost::thread_group threads; condition_test_data data; - for (int i = 0; i < NUMTHREADS; ++i) - threads.create_thread(bind(&condition_test_thread, &data)); - + try { - boost::mutex::scoped_lock lock(data.mutex); - BOOST_CHECK(lock ? true : false); - data.notified++; - data.condition.notify_all(); + for (int i = 0; i < NUMTHREADS; ++i) + threads.create_thread(bind(&condition_test_thread, &data)); + + { + boost::mutex::scoped_lock lock(data.mutex); + BOOST_CHECK(lock ? true : false); + data.notified++; + data.condition.notify_all(); + } + + threads.join_all(); + } + catch(...) + { + threads.interrupt_all(); + threads.join_all(); + throw; } - threads.join_all(); BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS); } @@ -131,7 +141,7 @@ void test_condition_notify_all() // We should have already tested notify_one here, so // a timed test with the default execution_monitor::use_condition // should be OK, and gives the fastest performance - timed_test(&do_test_condition_notify_all, 3); + timed_test(&do_test_condition_notify_all, 100); } void do_test_condition_waits() @@ -189,6 +199,24 @@ void test_condition_waits() timed_test(&do_test_condition_waits, 12); } +void do_test_condition_wait_is_a_interruption_point() +{ + condition_test_data data; + + boost::thread thread(bind(&condition_test_thread, &data)); + + thread.interrupt(); + thread.join(); + BOOST_CHECK_EQUAL(data.awoken,0); +} + + +void test_condition_wait_is_a_interruption_point() +{ + timed_test(&do_test_condition_wait_is_a_interruption_point, 1); +} + + boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { boost::unit_test_framework::test_suite* test = @@ -197,6 +225,7 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) test->add(BOOST_TEST_CASE(&test_condition_notify_one)); test->add(BOOST_TEST_CASE(&test_condition_notify_all)); test->add(BOOST_TEST_CASE(&test_condition_waits)); + test->add(BOOST_TEST_CASE(&test_condition_wait_is_a_interruption_point)); return test; } diff --git a/test/test_lock_concept.cpp b/test/test_lock_concept.cpp new file mode 100644 index 00000000..b0f5dc72 --- /dev/null +++ b/test/test_lock_concept.cpp @@ -0,0 +1,173 @@ +// (C) Copyright 2006-7 Anthony Williams +// 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 +#include + +template +struct test_initially_locked +{ + void operator()() const + { + Mutex m; + Lock lock(m); + + BOOST_CHECK(lock); + BOOST_CHECK(lock.owns_lock()); + } +}; + +template +struct test_initially_unlocked_with_defer_lock_parameter +{ + void operator()() const + { + Mutex m; + Lock lock(m,boost::defer_lock); + + BOOST_CHECK(!lock); + BOOST_CHECK(!lock.owns_lock()); + } +}; + +template +struct test_initially_locked_with_adopt_lock_parameter +{ + void operator()() const + { + Mutex m; + m.lock(); + Lock lock(m,boost::adopt_lock); + + BOOST_CHECK(lock); + BOOST_CHECK(lock.owns_lock()); + } +}; + + +template +struct test_unlocked_after_unlock_called +{ + void operator()() const + { + Mutex m; + Lock lock(m); + lock.unlock(); + BOOST_CHECK(!lock); + BOOST_CHECK(!lock.owns_lock()); + } +}; + +template +struct test_locked_after_lock_called +{ + void operator()() const + { + Mutex m; + Lock lock(m,boost::defer_lock); + lock.lock(); + BOOST_CHECK(lock); + BOOST_CHECK(lock.owns_lock()); + } +}; + +template +struct test_locked_after_try_lock_called +{ + void operator()() const + { + Mutex m; + Lock lock(m,boost::defer_lock); + lock.try_lock(); + BOOST_CHECK(lock); + BOOST_CHECK(lock.owns_lock()); + } +}; + +template +struct test_throws_if_lock_called_when_already_locked +{ + void operator()() const + { + Mutex m; + Lock lock(m); + + BOOST_CHECK_THROW( lock.lock(), boost::lock_error ); + } +}; + +template +struct test_throws_if_try_lock_called_when_already_locked +{ + void operator()() const + { + Mutex m; + Lock lock(m); + + BOOST_CHECK_THROW( lock.try_lock(), boost::lock_error ); + } +}; + +template +struct test_throws_if_unlock_called_when_already_unlocked +{ + void operator()() const + { + Mutex m; + Lock lock(m); + lock.unlock(); + + BOOST_CHECK_THROW( lock.unlock(), boost::lock_error ); + } +}; + +BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex) +{ + typedef typename Mutex::scoped_lock Lock; + + test_initially_locked()(); + test_initially_unlocked_with_defer_lock_parameter()(); + test_initially_locked_with_adopt_lock_parameter()(); + test_unlocked_after_unlock_called()(); + test_locked_after_lock_called()(); + test_throws_if_lock_called_when_already_locked()(); + test_throws_if_unlock_called_when_already_unlocked()(); +} + +BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex) +{ + typedef typename Mutex::scoped_try_lock Lock; + + test_initially_locked()(); + test_initially_unlocked_with_defer_lock_parameter()(); + test_initially_locked_with_adopt_lock_parameter()(); + test_unlocked_after_unlock_called()(); + test_locked_after_lock_called()(); + test_locked_after_try_lock_called()(); + test_throws_if_lock_called_when_already_locked()(); + test_throws_if_try_lock_called_when_already_locked()(); + test_throws_if_unlock_called_when_already_unlocked()(); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: lock concept test suite"); + + typedef boost::mpl::vector mutex_types; + + test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_lock_concept,mutex_types)); + + typedef boost::mpl::vector try_mutex_types; + + test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,try_mutex_types)); + + return test; +} diff --git a/test/test_mutex.cpp b/test/test_mutex.cpp index 831e6bba..08170fd2 100644 --- a/test/test_mutex.cpp +++ b/test/test_mutex.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include @@ -29,7 +29,7 @@ struct test_lock // Test the lock's constructors. { - lock_type lock(mutex, false); + lock_type lock(mutex, boost::defer_lock); BOOST_CHECK(!lock); } lock_type lock(mutex); @@ -69,10 +69,10 @@ struct test_trylock BOOST_CHECK(lock ? true : false); } { - try_lock_type lock(mutex, false); + try_lock_type lock(mutex, boost::defer_lock); BOOST_CHECK(!lock); } - try_lock_type lock(mutex, true); + try_lock_type lock(mutex); BOOST_CHECK(lock ? true : false); // Construct and initialize an xtime for a fast time out. @@ -110,16 +110,16 @@ struct test_timedlock // Test the lock's constructors. { // Construct and initialize an xtime for a fast time out. - boost::xtime xt = delay(0, 100); + boost::system_time xt = boost::get_system_time()+boost::posix_time::milliseconds(100); timed_lock_type lock(mutex, xt); BOOST_CHECK(lock ? true : false); } { - timed_lock_type lock(mutex, false); + timed_lock_type lock(mutex, boost::defer_lock); BOOST_CHECK(!lock); } - timed_lock_type lock(mutex, true); + timed_lock_type lock(mutex); BOOST_CHECK(lock ? true : false); // Construct and initialize an xtime for a fast time out. @@ -139,8 +139,8 @@ struct test_timedlock BOOST_CHECK(lock ? true : false); lock.unlock(); BOOST_CHECK(!lock); - xt = delay(0, 100); - BOOST_CHECK(lock.timed_lock(xt)); + boost::system_time target = boost::get_system_time()+boost::posix_time::milliseconds(100); + BOOST_CHECK(lock.timed_lock(target)); BOOST_CHECK(lock ? true : false); } }; diff --git a/test/test_once.cpp b/test/test_once.cpp index d5c6eb9a..634b4fd7 100644 --- a/test/test_once.cpp +++ b/test/test_once.cpp @@ -1,52 +1,190 @@ -// Copyright (C) 2001-2003 -// William E. Kempf -// -// 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 +// (C) Copyright 2006-7 Anthony Williams +// 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 -#include +boost::once_flag flag=BOOST_ONCE_INIT; +int var_to_init=0; +boost::mutex m; -int once_value = 0; -boost::once_flag once = BOOST_ONCE_INIT; - -void init_once_value() +void initialize_variable() { - once_value++; + // ensure that if multiple threads get in here, they are serialized, so we can see the effect + boost::mutex::scoped_lock lock(m); + ++var_to_init; } -void test_once_thread() +void call_once_thread() { - boost::call_once(init_once_value, once); + unsigned const loop_count=100; + int my_once_value=0; + for(unsigned i=0;iadd(BOOST_TEST_CASE(test_once)); + test->add(BOOST_TEST_CASE(test_call_once)); + test->add(BOOST_TEST_CASE(test_call_once_arbitrary_functor)); + test->add(BOOST_TEST_CASE(test_call_once_retried_on_exception)); return test; } diff --git a/test/test_shared_mutex.cpp b/test/test_shared_mutex.cpp new file mode 100644 index 00000000..b43a186e --- /dev/null +++ b/test/test_shared_mutex.cpp @@ -0,0 +1,593 @@ +// (C) Copyright 2006-7 Anthony Williams +// 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 +#include +#include +#include "util.inl" +#include +#include + +#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \ + { \ + boost::mutex::scoped_lock lock(mutex_name); \ + BOOST_CHECK_EQUAL(value,expected_value); \ + } + + +namespace +{ + template + class locking_thread + { + boost::shared_mutex& rw_mutex; + unsigned& unblocked_count; + unsigned& simultaneous_running_count; + unsigned& max_simultaneous_running; + boost::mutex& unblocked_count_mutex; + boost::condition_variable& unblocked_condition; + boost::mutex& finish_mutex; + public: + locking_thread(boost::shared_mutex& rw_mutex_, + unsigned& unblocked_count_, + boost::mutex& unblocked_count_mutex_, + boost::condition_variable& unblocked_condition_, + boost::mutex& finish_mutex_, + unsigned& simultaneous_running_count_, + unsigned& max_simultaneous_running_): + rw_mutex(rw_mutex_), + unblocked_count(unblocked_count_), + unblocked_condition(unblocked_condition_), + simultaneous_running_count(simultaneous_running_count_), + max_simultaneous_running(max_simultaneous_running_), + unblocked_count_mutex(unblocked_count_mutex_), + finish_mutex(finish_mutex_) + {} + + void operator()() + { + // acquire lock + lock_type lock(rw_mutex); + + // increment count to show we're unblocked + { + boost::mutex::scoped_lock ublock(unblocked_count_mutex); + ++unblocked_count; + unblocked_condition.notify_one(); + ++simultaneous_running_count; + if(simultaneous_running_count>max_simultaneous_running) + { + max_simultaneous_running=simultaneous_running_count; + } + } + + // wait to finish + boost::mutex::scoped_lock finish_lock(finish_mutex); + { + boost::mutex::scoped_lock ublock(unblocked_count_mutex); + --simultaneous_running_count; + } + } + }; + +} + + +void test_multiple_readers() +{ + unsigned const number_of_threads=100; + + boost::thread_group pool; + + boost::shared_mutex rw_mutex; + unsigned unblocked_count=0; + unsigned simultaneous_running_count=0; + unsigned max_simultaneous_running=0; + boost::mutex unblocked_count_mutex; + boost::condition_variable unblocked_condition; + boost::mutex finish_mutex; + boost::mutex::scoped_lock finish_lock(finish_mutex); + + try + { + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + + { + boost::mutex::scoped_lock lk(unblocked_count_mutex); + while(unblocked_count >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + + boost::thread::sleep(delay(2)); + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); + + finish_lock.unlock(); + + pool.join_all(); + } + catch(...) + { + pool.interrupt_all(); + pool.join_all(); + throw; + } + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u); +} + +void test_reader_blocks_writer() +{ + boost::thread_group pool; + + boost::shared_mutex rw_mutex; + unsigned unblocked_count=0; + unsigned simultaneous_running_count=0; + unsigned max_simultaneous_running=0; + boost::mutex unblocked_count_mutex; + boost::condition_variable unblocked_condition; + boost::mutex finish_mutex; + boost::mutex::scoped_lock finish_lock(finish_mutex); + + try + { + + pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + { + boost::mutex::scoped_lock lk(unblocked_count_mutex); + while(unblocked_count<1) + { + unblocked_condition.wait(lk); + } + } + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); + pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); + + finish_lock.unlock(); + + pool.join_all(); + } + catch(...) + { + pool.interrupt_all(); + pool.join_all(); + throw; + } + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,2U); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u); +} + +void test_unlocking_writer_unblocks_all_readers() +{ + boost::thread_group pool; + + boost::shared_mutex rw_mutex; + boost::unique_lock write_lock(rw_mutex); + unsigned unblocked_count=0; + unsigned simultaneous_running_count=0; + unsigned max_simultaneous_running=0; + boost::mutex unblocked_count_mutex; + boost::condition_variable unblocked_condition; + boost::mutex finish_mutex; + boost::mutex::scoped_lock finish_lock(finish_mutex); + + unsigned const reader_count=100; + + try + { + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,0U); + + write_lock.unlock(); + + { + boost::mutex::scoped_lock lk(unblocked_count_mutex); + while(unblocked_count >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_reading_mutex,simultaneous_running_readers,max_simultaneous_readers)); + } + boost::thread::sleep(delay(1)); + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_writing_mutex,simultaneous_running_writers,max_simultaneous_writers)); + } + { + boost::mutex::scoped_lock lk(unblocked_count_mutex); + while(unblocked_count >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + + boost::thread::sleep(delay(1)); + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); + + finish_lock.unlock(); + + pool.join_all(); + } + catch(...) + { + pool.interrupt_all(); + pool.join_all(); + throw; + } + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u); +} + +void test_can_lock_upgrade_if_currently_locked_shared() +{ + boost::thread_group pool; + + boost::shared_mutex rw_mutex; + unsigned unblocked_count=0; + unsigned simultaneous_running_count=0; + unsigned max_simultaneous_running=0; + boost::mutex unblocked_count_mutex; + boost::condition_variable unblocked_condition; + boost::mutex finish_mutex; + boost::mutex::scoped_lock finish_lock(finish_mutex); + + unsigned const reader_count=100; + + try + { + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + boost::thread::sleep(delay(1)); + pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + { + boost::mutex::scoped_lock lk(unblocked_count_mutex); + while(unblocked_count<(reader_count+1)) + { + unblocked_condition.wait(lk); + } + } + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1); + + finish_lock.unlock(); + pool.join_all(); + } + catch(...) + { + pool.interrupt_all(); + pool.join_all(); + throw; + } + + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count+1); +} + +namespace +{ + class simple_writing_thread + { + boost::shared_mutex& rwm; + boost::mutex& finish_mutex; + boost::mutex& unblocked_mutex; + unsigned& unblocked_count; + + public: + simple_writing_thread(boost::shared_mutex& rwm_, + boost::mutex& finish_mutex_, + boost::mutex& unblocked_mutex_, + unsigned& unblocked_count_): + rwm(rwm_),finish_mutex(finish_mutex_), + unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_) + {} + + void operator()() + { + boost::unique_lock lk(rwm); + + { + boost::mutex::scoped_lock ulk(unblocked_mutex); + ++unblocked_count; + } + + boost::mutex::scoped_lock flk(finish_mutex); + } + }; +} + +void test_if_other_thread_has_write_lock_try_lock_shared_returns_false() +{ + + boost::shared_mutex rw_mutex; + boost::mutex finish_mutex; + boost::mutex unblocked_mutex; + unsigned unblocked_count=0; + boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); + + bool const try_succeeded=rw_mutex.try_lock_shared(); + BOOST_CHECK(!try_succeeded); + if(try_succeeded) + { + rw_mutex.unlock_shared(); + } + + finish_lock.unlock(); + writer.join(); +} + +void test_if_no_thread_has_lock_try_lock_shared_returns_true() +{ + boost::shared_mutex rw_mutex; + bool const try_succeeded=rw_mutex.try_lock_shared(); + BOOST_CHECK(try_succeeded); + if(try_succeeded) + { + rw_mutex.unlock_shared(); + } +} + +namespace +{ + class simple_reading_thread + { + boost::shared_mutex& rwm; + boost::mutex& finish_mutex; + boost::mutex& unblocked_mutex; + unsigned& unblocked_count; + + public: + simple_reading_thread(boost::shared_mutex& rwm_, + boost::mutex& finish_mutex_, + boost::mutex& unblocked_mutex_, + unsigned& unblocked_count_): + rwm(rwm_),finish_mutex(finish_mutex_), + unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_) + {} + + void operator()() + { + boost::shared_lock lk(rwm); + + { + boost::mutex::scoped_lock ulk(unblocked_mutex); + ++unblocked_count; + } + + boost::mutex::scoped_lock flk(finish_mutex); + } + }; +} + +void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true() +{ + + boost::shared_mutex rw_mutex; + boost::mutex finish_mutex; + boost::mutex unblocked_mutex; + unsigned unblocked_count=0; + boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); + + bool const try_succeeded=rw_mutex.try_lock_shared(); + BOOST_CHECK(try_succeeded); + if(try_succeeded) + { + rw_mutex.unlock_shared(); + } + + finish_lock.unlock(); + writer.join(); +} + +void test_timed_lock_shared_times_out_if_write_lock_held() +{ + boost::shared_mutex rw_mutex; + boost::mutex finish_mutex; + boost::mutex unblocked_mutex; + unsigned unblocked_count=0; + boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); + + boost::system_time const start=boost::get_system_time(); + boost::system_time const timeout=start+boost::posix_time::milliseconds(2000); + bool const timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout); + BOOST_CHECK(in_range(boost::get_xtime(timeout),1)); + BOOST_CHECK(!timed_lock_succeeded); + if(timed_lock_succeeded) + { + rw_mutex.unlock_shared(); + } + + finish_lock.unlock(); + writer.join(); +} + + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite"); + + test->add(BOOST_TEST_CASE(&test_multiple_readers)); + test->add(BOOST_TEST_CASE(&test_only_one_writer_permitted)); + test->add(BOOST_TEST_CASE(&test_reader_blocks_writer)); + test->add(BOOST_TEST_CASE(&test_unlocking_writer_unblocks_all_readers)); + test->add(BOOST_TEST_CASE(&test_unlocking_last_reader_only_unblocks_one_writer)); + test->add(BOOST_TEST_CASE(&test_only_one_upgrade_lock_permitted)); + test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_if_currently_locked_shared)); + test->add(BOOST_TEST_CASE(&test_if_other_thread_has_write_lock_try_lock_shared_returns_false)); + test->add(BOOST_TEST_CASE(&test_if_no_thread_has_lock_try_lock_shared_returns_true)); + test->add(BOOST_TEST_CASE(&test_if_other_thread_has_shared_lock_try_lock_shared_returns_true)); + test->add(BOOST_TEST_CASE(&test_timed_lock_shared_times_out_if_write_lock_held)); + + return test; +} diff --git a/test/test_thread.cpp b/test/test_thread.cpp index bca085cf..5535deb0 100644 --- a/test/test_thread.cpp +++ b/test/test_thread.cpp @@ -8,6 +8,9 @@ #include #include +#include +#include +#include #include @@ -21,12 +24,16 @@ void simple_thread() test_value = 999; } -void comparison_thread(boost::thread* parent) +void comparison_thread(boost::thread::id parent) { - boost::thread thrd; - BOOST_CHECK(thrd != *parent); - boost::thread thrd2; - BOOST_CHECK(thrd == thrd2); + boost::thread::id const my_id=boost::this_thread::get_id(); + + BOOST_CHECK(my_id != parent); + boost::thread::id const my_id2=boost::this_thread::get_id(); + BOOST_CHECK(my_id == my_id2); + + boost::thread::id const no_thread_id=boost::thread::id(); + BOOST_CHECK(my_id != no_thread_id); } void test_sleep() @@ -52,18 +59,146 @@ void test_creation() timed_test(&do_test_creation, 1); } -void do_test_comparison() +void do_test_id_comparison() { - boost::thread self; - boost::thread thrd(bind(&comparison_thread, &self)); + boost::thread::id const self=boost::this_thread::get_id(); + boost::thread thrd(boost::bind(&comparison_thread, self)); thrd.join(); } -void test_comparison() +void test_id_comparison() { - timed_test(&do_test_comparison, 1); + timed_test(&do_test_id_comparison, 1); } +void interruption_point_thread(boost::mutex* m,bool* failed) +{ + boost::mutex::scoped_lock lk(*m); + boost::this_thread::interruption_point(); + *failed=true; +} + +void do_test_thread_interrupts_at_interruption_point() +{ + boost::mutex m; + bool failed=false; + boost::mutex::scoped_lock lk(m); + boost::thread thrd(boost::bind(&interruption_point_thread,&m,&failed)); + thrd.interrupt(); + lk.unlock(); + thrd.join(); + BOOST_CHECK(!failed); +} + +void test_thread_interrupts_at_interruption_point() +{ + timed_test(&do_test_thread_interrupts_at_interruption_point, 1); +} + +void disabled_interruption_point_thread(boost::mutex* m,bool* failed) +{ + boost::mutex::scoped_lock lk(*m); + boost::this_thread::disable_interruption dc; + boost::this_thread::interruption_point(); + *failed=false; +} + +void do_test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point() +{ + boost::mutex m; + bool failed=true; + boost::mutex::scoped_lock lk(m); + boost::thread thrd(boost::bind(&disabled_interruption_point_thread,&m,&failed)); + thrd.interrupt(); + lk.unlock(); + thrd.join(); + BOOST_CHECK(!failed); +} + +void test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point() +{ + timed_test(&do_test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point, 1); +} + +struct non_copyable_functor: + boost::noncopyable +{ + unsigned value; + + non_copyable_functor(): + value(0) + {} + + void operator()() + { + value=999; + } +}; + +void do_test_creation_through_reference_wrapper() +{ + non_copyable_functor f; + + boost::thread thrd(boost::ref(f)); + thrd.join(); + BOOST_CHECK_EQUAL(f.value, 999u); +} + +void test_creation_through_reference_wrapper() +{ + timed_test(&do_test_creation_through_reference_wrapper, 1); +} + +struct long_running_thread +{ + boost::condition_variable cond; + boost::mutex mut; + bool done; + + long_running_thread(): + done(false) + {} + + void operator()() + { + boost::mutex::scoped_lock lk(mut); + while(!done) + { + cond.wait(lk); + } + } +}; + +void do_test_timed_join() +{ + long_running_thread f; + boost::thread thrd(boost::ref(f)); + BOOST_CHECK(thrd.joinable()); + boost::system_time xt=delay(3); + bool const joined=thrd.timed_join(xt); + BOOST_CHECK(in_range(boost::get_xtime(xt), 2)); + BOOST_CHECK(!joined); + BOOST_CHECK(thrd.joinable()); + { + boost::mutex::scoped_lock lk(f.mut); + f.done=true; + f.cond.notify_one(); + } + + xt=delay(3); + bool const joined2=thrd.timed_join(xt); + boost::system_time const now=boost::get_system_time(); + BOOST_CHECK(xt>now); + BOOST_CHECK(joined2); + BOOST_CHECK(!thrd.joinable()); +} + +void test_timed_join() +{ + timed_test(&do_test_timed_join, 10); +} + + boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { boost::unit_test_framework::test_suite* test = @@ -71,7 +206,11 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) test->add(BOOST_TEST_CASE(test_sleep)); test->add(BOOST_TEST_CASE(test_creation)); - test->add(BOOST_TEST_CASE(test_comparison)); + test->add(BOOST_TEST_CASE(test_id_comparison)); + test->add(BOOST_TEST_CASE(test_thread_interrupts_at_interruption_point)); + test->add(BOOST_TEST_CASE(test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point)); + test->add(BOOST_TEST_CASE(test_creation_through_reference_wrapper)); + test->add(BOOST_TEST_CASE(test_timed_join)); return test; } diff --git a/test/test_tss.cpp b/test/test_tss.cpp index 6ed570f1..d53c1d34 100644 --- a/test/test_tss.cpp +++ b/test/test_tss.cpp @@ -62,7 +62,7 @@ void test_tss_thread() } } -#if defined(BOOST_HAS_WINTHREADS) +#if defined(BOOST_THREAD_PLATFORM_WIN32) typedef HANDLE native_thread_t; DWORD WINAPI test_tss_thread_native(LPVOID lpParameter) @@ -91,6 +91,33 @@ void test_tss_thread() res = CloseHandle(thread); BOOST_CHECK(SUCCEEDED(res)); } +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) + typedef pthread_t native_thread_t; + +extern "C" +{ + void* test_tss_thread_native(void* lpParameter) + { + test_tss_thread(); + return 0; + } +} + + native_thread_t create_native_thread() + { + native_thread_t thread_handle; + + int const res = pthread_create(&thread_handle, 0, &test_tss_thread_native, 0); + BOOST_CHECK(!res); + return thread_handle; + } + + void join_native_thread(native_thread_t thread) + { + void* result=0; + int const res=pthread_join(thread,&result); + BOOST_CHECK(!res); + } #endif void do_test_tss() @@ -100,9 +127,19 @@ void do_test_tss() const int NUMTHREADS=5; boost::thread_group threads; - for (int i=0; i