From a646153615131fa58b15d1d8bb81d52534f57d86 Mon Sep 17 00:00:00 2001 From: Anthony Williams Date: Tue, 23 Oct 2007 08:57:17 +0000 Subject: [PATCH] platform split for pthread and win32 builds so can use pthread-win32 library on Windows with pthread feature; new C++0x-alike thread class interface on win32. [SVN r40348] --- build/Jamfile.v2 | 106 +++-- include/boost/thread/pthread/mutex.hpp | 2 + .../boost/thread/pthread/recursive_mutex.hpp | 2 + include/boost/thread/pthread/thread.hpp | 136 ++++++ include/boost/thread/thread.hpp | 95 +--- include/boost/thread/win32/thread.hpp | 413 ++++++++++++++++ .../boost/thread/win32/thread_heap_alloc.hpp | 105 +++++ .../boost/thread/win32/thread_primitives.hpp | 19 +- src/mac/debug_prefix.hpp | 8 - src/mac/delivery_man.cpp | 66 --- src/mac/delivery_man.hpp | 84 ---- src/mac/dt_scheduler.cpp | 93 ---- src/mac/dt_scheduler.hpp | 63 --- src/mac/execution_context.cpp | 60 --- src/mac/execution_context.hpp | 47 -- src/mac/init.cpp | 58 --- src/mac/init.hpp | 34 -- src/mac/msl_replacements/assert.cpp | 24 - src/mac/msl_replacements/console_io.cpp | 128 ----- src/mac/msl_replacements/malloc.cpp | 52 -- src/mac/msl_replacements/news_and_deletes.cpp | 99 ---- src/mac/msl_replacements/time.cpp | 150 ------ src/mac/os.cpp | 57 --- src/mac/os.hpp | 37 -- src/mac/ot_context.cpp | 46 -- src/mac/ot_context.hpp | 58 --- src/mac/package.hpp | 76 --- src/mac/periodical.hpp | 97 ---- src/mac/prefix.hpp | 9 - src/mac/remote_call_manager.cpp | 48 -- src/mac/remote_call_manager.hpp | 102 ---- src/mac/remote_calls.hpp | 157 ------- src/mac/safe.cpp | 210 --------- src/mac/safe.hpp | 41 -- src/mac/scoped_critical_region.cpp | 47 -- src/mac/scoped_critical_region.hpp | 63 --- src/mac/st_scheduler.cpp | 85 ---- src/mac/st_scheduler.hpp | 67 --- src/mac/thread_cleanup.cpp | 56 --- src/mac/thread_cleanup.hpp | 36 -- src/{ => pthread}/exceptions.cpp | 0 src/{ => pthread}/thread.cpp | 157 +------ src/{ => pthread}/timeconv.inl | 0 src/{ => pthread}/tss.cpp | 0 src/{ => pthread}/xtime.cpp | 0 src/win32/exceptions.cpp | 124 +++++ src/win32/thread.cpp | 443 ++++++++++++++++++ src/win32/timeconv.inl | 130 +++++ src/win32/tss.cpp | 251 ++++++++++ src/{ => win32}/tss_dll.cpp | 0 src/{ => win32}/tss_hooks.cpp | 0 src/{ => win32}/tss_pe.cpp | 0 src/win32/xtime.cpp | 158 +++++++ test/test_shared_mutex.cpp | 34 +- test/test_thread.cpp | 26 +- 55 files changed, 1911 insertions(+), 2548 deletions(-) create mode 100644 include/boost/thread/pthread/thread.hpp create mode 100644 include/boost/thread/win32/thread.hpp create mode 100644 include/boost/thread/win32/thread_heap_alloc.hpp delete mode 100644 src/mac/debug_prefix.hpp delete mode 100644 src/mac/delivery_man.cpp delete mode 100644 src/mac/delivery_man.hpp delete mode 100644 src/mac/dt_scheduler.cpp delete mode 100644 src/mac/dt_scheduler.hpp delete mode 100644 src/mac/execution_context.cpp delete mode 100644 src/mac/execution_context.hpp delete mode 100644 src/mac/init.cpp delete mode 100644 src/mac/init.hpp delete mode 100644 src/mac/msl_replacements/assert.cpp delete mode 100644 src/mac/msl_replacements/console_io.cpp delete mode 100644 src/mac/msl_replacements/malloc.cpp delete mode 100644 src/mac/msl_replacements/news_and_deletes.cpp delete mode 100644 src/mac/msl_replacements/time.cpp delete mode 100644 src/mac/os.cpp delete mode 100644 src/mac/os.hpp delete mode 100644 src/mac/ot_context.cpp delete mode 100644 src/mac/ot_context.hpp delete mode 100644 src/mac/package.hpp delete mode 100644 src/mac/periodical.hpp delete mode 100644 src/mac/prefix.hpp delete mode 100644 src/mac/remote_call_manager.cpp delete mode 100644 src/mac/remote_call_manager.hpp delete mode 100644 src/mac/remote_calls.hpp delete mode 100644 src/mac/safe.cpp delete mode 100644 src/mac/safe.hpp delete mode 100644 src/mac/scoped_critical_region.cpp delete mode 100644 src/mac/scoped_critical_region.hpp delete mode 100644 src/mac/st_scheduler.cpp delete mode 100644 src/mac/st_scheduler.hpp delete mode 100644 src/mac/thread_cleanup.cpp delete mode 100644 src/mac/thread_cleanup.hpp rename src/{ => pthread}/exceptions.cpp (100%) rename src/{ => pthread}/thread.cpp (52%) rename src/{ => pthread}/timeconv.inl (100%) rename src/{ => pthread}/tss.cpp (100%) rename src/{ => pthread}/xtime.cpp (100%) create mode 100644 src/win32/exceptions.cpp create mode 100644 src/win32/thread.cpp create mode 100644 src/win32/timeconv.inl create mode 100644 src/win32/tss.cpp rename src/{ => win32}/tss_dll.cpp (100%) rename src/{ => win32}/tss_hooks.cpp (100%) rename src/{ => win32}/tss_pe.cpp (100%) create mode 100644 src/win32/xtime.cpp diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 560161b5..b9a4f393 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -1,39 +1,83 @@ -# (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) +# Copyright 2006 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) import os ; - +import feature ; project boost/thread - : source-location ../src - : requirements shared:BOOST_THREAD_BUILD_DLL=1 multi - : default-build multi + : source-location ../src + : requirements multi + static:BOOST_THREAD_BUILD_LIB=1 + shared:BOOST_THREAD_BUILD_DLL=1 + : default-build multi ; -CPP_SOURCES = -# barrier -# condition - exceptions -# mutex -# once -# recursive_mutex -# read_write_mutex - thread - tss_hooks - tss_dll - tss_pe - tss - xtime - ; +BOOST_PTHREAD_OPTS = BOOST_THREAD_POSIX ; +if [ os.name ] = "NT" +{ + AVAILABLE_THREAD_APIS = win32 ; + + local PTW32_INCLUDE = [ modules.peek : PTW32_INCLUDE ] ; + local PTW32_LIB = [ modules.peek : PTW32_LIB ] ; + if $(PTW32_INCLUDE) && $(PTW32_LIB) + { + BOOST_PTHREAD_OPTS += + BOOST_HAS_PTHREADS + $(PTW32_INCLUDE) + $(PTW32_LIB) ; + + AVAILABLE_THREAD_APIS += pthread ; + } + else + { + echo "******************************************************" ; + echo "Building Boost.Thread without optional pthread support" ; + echo "If you need pthread you should specify the paths." ; + echo "For example:" ; + echo "PTW32_INCLUDE=C:\\Program Files\\ptw32\\Pre-built2\\include" ; + echo "PTW32_LIB=C:\\Program Files\\ptw32\\Pre-built2\\lib\\pthreadVC2.lib" ; + echo "******************************************************" ; + BOOST_PTHREAD_OPTS += no ; + } +} +else +{ + AVAILABLE_THREAD_APIS = pthread ; + if [ os.name ] = CYGWIN + { + AVAILABLE_THREAD_APIS += win32 ; + } +} + +feature.feature thrd-api : $(AVAILABLE_THREAD_APIS) : symmetric propagated composite ; +feature.compose pthread : $(BOOST_PTHREAD_OPTS) ; + +lib boost_thread + : ## sources ## + win32/thread.cpp + win32/exceptions.cpp + win32/xtime.cpp + win32/tss.cpp + win32/tss_hooks.cpp + win32/tss_dll.cpp + win32/tss_pe.cpp + : ## requirements ## + win32 + ; + +# build the pthread based variant 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 - ; + : ## sources ## + pthread/thread.cpp + pthread/exceptions.cpp + pthread/xtime.cpp + pthread/tss.cpp + : ## requirements ## + pthread + $(BOOST_PTHREAD_OPTS) + ; + diff --git a/include/boost/thread/pthread/mutex.hpp b/include/boost/thread/pthread/mutex.hpp index 4b9636df..7483686d 100644 --- a/include/boost/thread/pthread/mutex.hpp +++ b/include/boost/thread/pthread/mutex.hpp @@ -11,7 +11,9 @@ #include #include #include +#ifndef WIN32 #include +#endif #include #include "timespec.hpp" #include "pthread_mutex_scoped_lock.hpp" diff --git a/include/boost/thread/pthread/recursive_mutex.hpp b/include/boost/thread/pthread/recursive_mutex.hpp index 21395b4d..f7ea9300 100644 --- a/include/boost/thread/pthread/recursive_mutex.hpp +++ b/include/boost/thread/pthread/recursive_mutex.hpp @@ -11,7 +11,9 @@ #include #include #include +#ifndef WIN32 #include +#endif #include #include #include "timespec.hpp" diff --git a/include/boost/thread/pthread/thread.hpp b/include/boost/thread/pthread/thread.hpp new file mode 100644 index 00000000..622ef027 --- /dev/null +++ b/include/boost/thread/pthread/thread.hpp @@ -0,0 +1,136 @@ +// 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) + +#ifndef BOOST_THREAD_WEK070601_HPP +#define BOOST_THREAD_WEK070601_HPP + +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace boost { + + class thread; + + namespace detail + { + class thread_id; + } + + namespace this_thread + { + detail::thread_id get_id(); + } + + namespace detail + { + class thread_id + { + boost::optional id; + + friend class boost::thread; + + friend thread_id this_thread::get_id(); + + thread_id(pthread_t id_): + id(id_) + {} + + public: + thread_id() + {} + + bool operator==(const thread_id& y) const + { + return (id && y.id) && (pthread_equal(*id,*y.id)!=0); + } + + bool operator!=(const thread_id& y) const + { + return !(*this==y); + } + + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, const thread_id& x) + { + if(x.id) + { + return os<<*x.id; + } + else + { + return os<<"{Not-any-thread}"; + } + } + + }; + } + + struct xtime; + class BOOST_THREAD_DECL thread : private noncopyable + { + public: + thread(); + explicit thread(const function0& threadfunc); + ~thread(); + + bool operator==(const thread& other) const; + bool operator!=(const thread& other) const; + + void join(); + + static void sleep(const xtime& xt); + static void yield(); + + typedef detail::thread_id id; + + id get_id() const + { + return m_id; + } + + private: + id m_id; + bool m_joinable; + }; + + namespace this_thread + { + inline thread::id get_id() + { + return thread::id(pthread_self()); + } + } + + class BOOST_THREAD_DECL thread_group : private noncopyable + { + public: + thread_group(); + ~thread_group(); + + thread* create_thread(const function0& threadfunc); + void add_thread(thread* thrd); + void remove_thread(thread* thrd); + void join_all(); + int size() const; + + private: + std::list m_threads; + mutex m_mutex; + }; +} // namespace boost + + +#endif // BOOST_THREAD_WEK070601_HPP diff --git a/include/boost/thread/thread.hpp b/include/boost/thread/thread.hpp index 0f410eb9..da4323f0 100644 --- a/include/boost/thread/thread.hpp +++ b/include/boost/thread/thread.hpp @@ -1,88 +1,15 @@ -// Copyright (C) 2001-2003 -// William E. Kempf +#ifndef BOOST_THREAD_THREAD_HPP +#define BOOST_THREAD_THREAD_HPP + +// thread.hpp // -// 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 +// +// 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) -#ifndef BOOST_THREAD_WEK070601_HPP -#define BOOST_THREAD_WEK070601_HPP +#include +#include BOOST_THREAD_PLATFORM(thread.hpp) -#include - -#include -#include -#include -#include -#include - -#if defined(BOOST_HAS_PTHREADS) -# include -#elif defined(BOOST_HAS_MPTASKS) -# include #endif - -namespace boost { - -struct xtime; -// disable warnings about non dll import -// see: http://www.boost.org/more/separate_compilation.html#dlls -#ifdef BOOST_MSVC -# pragma warning(push) -# pragma warning(disable: 4251 4231 4660 4275) -#endif -class BOOST_THREAD_DECL thread : private noncopyable -{ -public: - thread(); - explicit thread(const function0& threadfunc); - ~thread(); - - bool operator==(const thread& other) const; - bool operator!=(const thread& other) const; - - void join(); - - static void sleep(const xtime& xt); - static void yield(); - -private: -#if defined(BOOST_HAS_WINTHREADS) - void* m_thread; - unsigned int m_id; -#elif defined(BOOST_HAS_PTHREADS) -private: - pthread_t m_thread; -#elif defined(BOOST_HAS_MPTASKS) - MPQueueID m_pJoinQueueID; - MPTaskID m_pTaskID; -#endif - bool m_joinable; -}; - -class BOOST_THREAD_DECL thread_group : private noncopyable -{ -public: - thread_group(); - ~thread_group(); - - thread* create_thread(const function0& threadfunc); - void add_thread(thread* thrd); - void remove_thread(thread* thrd); - void join_all(); - int size() const; - -private: - std::list m_threads; - mutex m_mutex; -}; -#ifdef BOOST_MSVC -# pragma warning(pop) -#endif -} // namespace boost - -// Change Log: -// 8 Feb 01 WEKEMPF Initial version. -// 1 Jun 01 WEKEMPF Added boost::thread initial implementation. -// 3 Jul 01 WEKEMPF Redesigned boost::thread to be noncopyable. - -#endif // BOOST_THREAD_WEK070601_HPP diff --git a/include/boost/thread/win32/thread.hpp b/include/boost/thread/win32/thread.hpp new file mode 100644 index 00000000..c5b99ced --- /dev/null +++ b/include/boost/thread/win32/thread.hpp @@ -0,0 +1,413 @@ +#ifndef BOOST_THREAD_THREAD_WIN32_HPP +#define BOOST_THREAD_THREAD_WIN32_HPP +// 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 + +#include +#include +#include +#include +#include +#include +#include +#include "thread_primitives.hpp" +#include "thread_heap_alloc.hpp" +#include +#include +#include + +namespace boost +{ + class thread_canceled + {}; + + namespace detail + { + struct thread_exit_callback_node; + + struct thread_data_base + { + long count; + detail::win32::handle_manager thread_handle; + detail::win32::handle_manager cancel_handle; + boost::detail::thread_exit_callback_node* thread_exit_callbacks; + bool cancel_enabled; + unsigned id; + + thread_data_base(): + count(0),thread_handle(detail::win32::invalid_handle_value), + cancel_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)), + thread_exit_callbacks(0), + cancel_enabled(true), + id(0) + {} + virtual ~thread_data_base() + {} + + friend void intrusive_ptr_add_ref(thread_data_base * p) + { + BOOST_INTERLOCKED_INCREMENT(&p->count); + } + + friend void intrusive_ptr_release(thread_data_base * p) + { + if(!BOOST_INTERLOCKED_DECREMENT(&p->count)) + { + detail::heap_delete(p); + } + } + + virtual void run()=0; + }; + } + + class BOOST_THREAD_DECL thread + { + private: + thread(thread&); + thread& operator=(thread&); + + void release_handle(); + + template + struct thread_data: + detail::thread_data_base + { + F f; + + thread_data(F f_): + f(f_) + {} + thread_data(boost::move_t f_): + f(f_) + {} + + void run() + { + f(); + } + }; + + mutable boost::mutex thread_info_mutex; + boost::intrusive_ptr thread_info; + + static unsigned __stdcall thread_start_function(void* param); + + void start_thread(); + + explicit thread(boost::intrusive_ptr data); + + boost::intrusive_ptr get_thread_info() const; + public: + thread(); + ~thread(); + + template + thread(F f): + thread_info(detail::heap_new >(f)) + { + start_thread(); + } + template + thread(boost::move_t f): + thread_info(detail::heap_new >(f)) + { + start_thread(); + } + + thread(boost::move_t x); + thread& operator=(boost::move_t x); + operator boost::move_t(); + boost::move_t move(); + + void swap(thread& x); + + class id; + id get_id() const; + + + bool joinable() const; + void join(); + void detach(); + + static unsigned hardware_concurrency(); + + typedef detail::win32::handle native_handle_type; + native_handle_type native_handle(); + + // backwards compatibility + bool operator==(const thread& other) const; + bool operator!=(const thread& other) const; + + static void yield(); + static void sleep(const system_time& xt); + + // extensions + class cancel_handle; + cancel_handle get_cancel_handle() const; + void cancel(); + bool cancellation_requested() const; + + static thread self(); + }; + + namespace this_thread + { + class disable_cancellation + { + disable_cancellation(const disable_cancellation&); + disable_cancellation& operator=(const disable_cancellation&); + + bool cancel_was_enabled; + friend class enable_cancellation; + public: + disable_cancellation(); + ~disable_cancellation(); + }; + + class enable_cancellation + { + enable_cancellation(const enable_cancellation&); + enable_cancellation& operator=(const enable_cancellation&); + public: + explicit enable_cancellation(disable_cancellation& d); + ~enable_cancellation(); + }; + + thread::id BOOST_THREAD_DECL get_id(); + + bool BOOST_THREAD_DECL cancellable_wait(detail::win32::handle handle_to_wait_for,unsigned long milliseconds); + + void BOOST_THREAD_DECL cancellation_point(); + bool BOOST_THREAD_DECL cancellation_enabled(); + bool BOOST_THREAD_DECL cancellation_requested(); + thread::cancel_handle BOOST_THREAD_DECL get_cancel_handle(); + + void BOOST_THREAD_DECL yield(); + template + void sleep(TimeDuration const& rel_time) + { + cancellable_wait(detail::win32::invalid_handle_value,static_cast(rel_time.total_milliseconds())); + } + } + + class thread::id + { + private: + unsigned thread_id; + + id(unsigned thread_id_): + thread_id(thread_id_) + {} + friend class thread; + friend id this_thread::get_id(); + public: + id(): + thread_id(0) + {} + + bool operator==(const id& y) const + { + return thread_id==y.thread_id; + } + + bool operator!=(const id& y) const + { + return thread_id!=y.thread_id; + } + + bool operator<(const id& y) const + { + return thread_id(const id& y) const + { + return thread_id>y.thread_id; + } + + bool operator<=(const id& y) const + { + return thread_id<=y.thread_id; + } + + bool operator>=(const id& y) const + { + return thread_id>=y.thread_id; + } + + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, const id& x) + { + return os< + struct thread_exit_function: + thread_exit_function_base + { + F f; + + thread_exit_function(F f_): + f(f_) + {} + + void operator()() const + { + f(); + } + }; + + void add_thread_exit_function(thread_exit_function_base*); + } + + namespace this_thread + { + template + void at_thread_exit(F f) + { + detail::thread_exit_function_base* const thread_exit_func=detail::heap_new >(f); + detail::add_thread_exit_function(thread_exit_func); + } + } + + class thread_group: + private noncopyable + { + public: + ~thread_group() + { + for(std::list::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + delete *it; + } + } + + template + thread* create_thread(F threadfunc) + { + boost::lock_guard guard(m); + thread* const new_thread=new thread(threadfunc); + threads.push_back(new_thread); + return new_thread; + } + + void add_thread(thread* thrd) + { + if(thrd) + { + boost::lock_guard guard(m); + threads.push_back(thrd); + } + } + + void remove_thread(thread* thrd) + { + boost::lock_guard guard(m); + std::list::iterator const it=std::find(threads.begin(),threads.end(),thrd); + if(it!=threads.end()) + { + threads.erase(it); + } + } + + void join_all() + { + boost::lock_guard guard(m); + + for(std::list::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + (*it)->join(); + } + } + + int size() const + { + boost::lock_guard guard(m); + return threads.size(); + } + + private: + std::list threads; + mutable mutex m; + }; +} + +#endif diff --git a/include/boost/thread/win32/thread_heap_alloc.hpp b/include/boost/thread/win32/thread_heap_alloc.hpp new file mode 100644 index 00000000..abf6e9ca --- /dev/null +++ b/include/boost/thread/win32/thread_heap_alloc.hpp @@ -0,0 +1,105 @@ +// 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 +#ifndef THREAD_HEAP_ALLOC_HPP +#define THREAD_HEAP_ALLOC_HPP +#include +#include "thread_primitives.hpp" + +#if defined( BOOST_USE_WINDOWS_H ) +# include + +namespace boost +{ + namespace detail + { + namespace win32 + { + using ::GetProcessHeap; + using ::HeapAlloc; + using ::HeapFree; + } + } +} + +#else + +namespace boost +{ + namespace detail + { + namespace win32 + { + extern "C" + { + __declspec(dllimport) handle __stdcall GetProcessHeap(); + __declspec(dllimport) void* __stdcall HeapAlloc(handle,unsigned long,ulong_ptr); + __declspec(dllimport) int __stdcall HeapFree(handle,unsigned long,void*); + } + } + } +} + +#endif + +namespace boost +{ + namespace detail + { + template + T* heap_new() + { + void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,sizeof(T)); + T* const data=new (heap_memory) T(); + return data; + } + + template + T* heap_new(A1 a1) + { + void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,sizeof(T)); + T* const data=new (heap_memory) T(a1); + return data; + } + + template + T* heap_new(A1 a1,A2 a2) + { + void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,sizeof(T)); + T* const data=new (heap_memory) T(a1,a2); + return data; + } + + template + void heap_delete(T* data) + { + data->~T(); + detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,data); + } + + template + struct do_delete + { + T* data; + + do_delete(T* data_): + data(data_) + {} + + void operator()() const + { + detail::heap_delete(data); + } + }; + + template + do_delete make_heap_deleter(T* data) + { + return do_delete(data); + } + } +} + + +#endif diff --git a/include/boost/thread/win32/thread_primitives.hpp b/include/boost/thread/win32/thread_primitives.hpp index 604263e1..f8d1854e 100644 --- a/include/boost/thread/win32/thread_primitives.hpp +++ b/include/boost/thread/win32/thread_primitives.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #if defined( BOOST_USE_WINDOWS_H ) # include @@ -25,6 +26,7 @@ namespace boost typedef HANDLE handle; unsigned const infinite=INFINITE; unsigned const timeout=WAIT_TIMEOUT; + handle const invalid_handle_value=INVALID_HANDLE_VALUE; using ::CreateMutexA; using ::CreateEventA; @@ -42,6 +44,7 @@ namespace boost using ::GetCurrentProcess; using ::DuplicateHandle; using ::SleepEx; + using ::Sleep; using ::QueueUserAPC; } } @@ -62,6 +65,7 @@ namespace boost typedef void* handle; unsigned const infinite=~0U; unsigned const timeout=258U; + handle const invalid_handle_value=(handle)(-1); extern "C" { @@ -79,6 +83,7 @@ namespace boost __declspec(dllimport) void* __stdcall GetCurrentProcess(); __declspec(dllimport) int __stdcall DuplicateHandle(void*,void*,void*,void**,unsigned long,int,unsigned long); __declspec(dllimport) unsigned long __stdcall SleepEx(unsigned long,int); + __declspec(dllimport) void __stdcall Sleep(unsigned long); typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr); __declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr); __declspec(dllimport) int __stdcall SetEvent(void*); @@ -158,9 +163,9 @@ namespace boost void cleanup() { - if(handle_to_manage) + if(handle_to_manage && handle_to_manage!=invalid_handle_value) { - unsigned long result=CloseHandle(handle_to_manage); + unsigned long const result=CloseHandle(handle_to_manage); BOOST_ASSERT(result); } } @@ -185,6 +190,16 @@ namespace boost return handle_to_manage; } + handle duplicate() const + { + return duplicate_handle(handle_to_manage); + } + + void swap(handle_manager& other) + { + std::swap(handle_to_manage,other.handle_to_manage); + } + handle release() { handle const res=handle_to_manage; 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/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/thread.cpp b/src/pthread/thread.cpp similarity index 52% rename from src/thread.cpp rename to src/pthread/thread.cpp index dc8ff078..c4757d29 100644 --- a/src/thread.cpp +++ b/src/pthread/thread.cpp @@ -13,58 +13,10 @@ #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: @@ -94,24 +46,12 @@ public: } // 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 { thread_param* p = static_cast(param); boost::function0 threadfunc = p->m_threadfunc; p->started(); threadfunc(); -#if defined(BOOST_HAS_WINTHREADS) - on_thread_exit(); -#endif -#if defined(BOOST_HAS_MPTASKS) - ::boost::detail::thread_cleanup(); -#endif return 0; } @@ -119,56 +59,20 @@ extern "C" { 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(): + m_joinable(false) +{} 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; + pthread_t m_thread; 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 + m_id=m_thread; param.wait(); } @@ -176,29 +80,13 @@ 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 + pthread_detach(*m_id.id); } } 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 + return m_id==other.m_id; } bool thread::operator!=(const thread& other) const @@ -210,19 +98,8 @@ 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); + res = pthread_join(*m_id.id, 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; @@ -232,11 +109,6 @@ 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); @@ -256,13 +128,6 @@ void thread::sleep(const xtime& xt) 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) @@ -272,9 +137,6 @@ void thread::sleep(const xtime& xt) 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(); @@ -288,9 +150,6 @@ void thread::yield() xtime_get(&xt, TIME_UTC); sleep(xt); # endif -#elif defined(BOOST_HAS_MPTASKS) - MPYield(); -#endif } thread_group::thread_group() 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/tss.cpp b/src/pthread/tss.cpp similarity index 100% rename from src/tss.cpp rename to src/pthread/tss.cpp diff --git a/src/xtime.cpp b/src/pthread/xtime.cpp similarity index 100% rename from src/xtime.cpp rename to src/pthread/xtime.cpp 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..1b3b7207 --- /dev/null +++ b/src/win32/thread.cpp @@ -0,0 +1,443 @@ +// 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 + +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ + namespace + { +#ifdef _MSC_VER + __declspec(thread) detail::thread_data_base* current_thread_data=0; + detail::thread_data_base* get_current_thread_data() + { + return current_thread_data; + } + void set_current_thread_data(detail::thread_data_base* new_data) + { + current_thread_data=new_data; + } +#elif defined(__BORLANDC__) + detail::thread_data_base* __thread current_thread_data=0; + detail::thread_data_base* get_current_thread_data() + { + return current_thread_data; + } + void set_current_thread_data(detail::thread_data_base* new_data) + { + current_thread_data=new_data; + } +#else + + 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); + BOOL const res=TlsSetValue(current_thread_tls_key,new_data); + BOOST_ASSERT(res); + } +#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); + } + } + + unsigned __stdcall thread::thread_start_function(void* param) + { + boost::intrusive_ptr thread_info(reinterpret_cast(param),false); + set_current_thread_data(thread_info.get()); + try + { + thread_info->run(); + } + catch(thread_canceled const&) + { + } + catch(...) + { + std::terminate(); + } + 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(boost::intrusive_ptr data): + thread_info(data) + {} + + namespace + { + struct externally_launched_thread: + detail::thread_data_base + { + externally_launched_thread() + { + ++count; + thread_handle=detail::win32::duplicate_handle(detail::win32::GetCurrentThread()); + } + + void run() + {} + }; + + struct externally_launched_thread_deleter + { + externally_launched_thread* thread_data; + + externally_launched_thread_deleter(externally_launched_thread* thread_data_): + thread_data(thread_data_) + {} + + void operator()() const + { + intrusive_ptr_release(thread_data); + } + }; + + } + + + thread thread::self() + { + if(!get_current_thread_data()) + { + externally_launched_thread* me=detail::heap_new(); + set_current_thread_data(me); + this_thread::at_thread_exit(externally_launched_thread_deleter(me)); + } + return thread(boost::intrusive_ptr(get_current_thread_data())); + } + + thread::~thread() + { + cancel(); + 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 boost::move_t(*this); + } + + boost::move_t thread::move() + { + return boost::move_t(*this); + } + + void thread::swap(thread& x) + { + thread_info.swap(x.thread_info); + } + + thread::id thread::get_id() const + { + boost::intrusive_ptr local_thread_info=get_thread_info(); + return local_thread_info?thread::id(local_thread_info->id):thread::id(); + } + + thread::cancel_handle thread::get_cancel_handle() const + { + boost::intrusive_ptr local_thread_info=get_thread_info(); + return local_thread_info?thread::cancel_handle(local_thread_info->cancel_handle.duplicate()):thread::cancel_handle(); + } + + bool thread::joinable() const + { + return get_thread_info(); + } + + void thread::join() + { + boost::intrusive_ptr local_thread_info=get_thread_info(); + if(local_thread_info) + { + this_thread::cancellable_wait(local_thread_info->thread_handle,detail::win32::infinite); + release_handle(); + } + } + + void thread::detach() + { + release_handle(); + } + + void thread::release_handle() + { + boost::mutex::scoped_lock l1(thread_info_mutex); + thread_info=0; + } + + void thread::cancel() + { + boost::intrusive_ptr local_thread_info=get_thread_info(); + if(local_thread_info) + { + detail::win32::SetEvent(local_thread_info->cancel_handle); + } + } + + bool thread::cancellation_requested() const + { + boost::intrusive_ptr local_thread_info=get_thread_info(); + return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->cancel_handle,0)==0); + } + + unsigned thread::hardware_concurrency() + { + SYSTEM_INFO info={0}; + GetSystemInfo(&info); + return info.dwNumberOfProcessors; + } + + thread::native_handle_type thread::native_handle() + { + boost::intrusive_ptr local_thread_info=get_thread_info(); + return local_thread_info?(detail::win32::handle)local_thread_info->thread_handle:detail::win32::invalid_handle_value; + } + + boost::intrusive_ptr thread::get_thread_info() const + { + boost::mutex::scoped_lock l(thread_info_mutex); + return thread_info; + } + + namespace this_thread + { + thread::cancel_handle get_cancel_handle() + { + return get_current_thread_data()?thread::cancel_handle(get_current_thread_data()->cancel_handle.duplicate()):thread::cancel_handle(); + } + + bool cancellable_wait(detail::win32::handle handle_to_wait_for,unsigned long milliseconds) + { + detail::win32::handle handles[2]={0}; + unsigned handle_count=0; + unsigned cancel_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()->cancel_enabled) + { + cancel_index=handle_count; + handles[handle_count++]=get_current_thread_data()->cancel_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==cancel_index) + { + detail::win32::ResetEvent(get_current_thread_data()->cancel_handle); + throw thread_canceled(); + } + } + else + { + detail::win32::Sleep(milliseconds); + } + return false; + } + + thread::id get_id() + { + return thread::id(detail::win32::GetCurrentThreadId()); + } + + void cancellation_point() + { + if(cancellation_enabled() && cancellation_requested()) + { + detail::win32::ResetEvent(get_current_thread_data()->cancel_handle); + throw thread_canceled(); + } + } + + bool cancellation_enabled() + { + return get_current_thread_data() && get_current_thread_data()->cancel_enabled; + } + + bool cancellation_requested() + { + return get_current_thread_data() && (detail::win32::WaitForSingleObject(get_current_thread_data()->cancel_handle,0)==0); + } + + void yield() + { + detail::win32::Sleep(0); + } + + disable_cancellation::disable_cancellation(): + cancel_was_enabled(cancellation_enabled()) + { + if(cancel_was_enabled) + { + get_current_thread_data()->cancel_enabled=false; + } + } + + disable_cancellation::~disable_cancellation() + { + if(get_current_thread_data()) + { + get_current_thread_data()->cancel_enabled=cancel_was_enabled; + } + } + + enable_cancellation::enable_cancellation(disable_cancellation& d) + { + if(d.cancel_was_enabled) + { + get_current_thread_data()->cancel_enabled=true; + } + } + + enable_cancellation::~enable_cancellation() + { + if(get_current_thread_data()) + { + get_current_thread_data()->cancel_enabled=false; + } + } + } + + namespace detail + { + struct thread_exit_callback_node + { + boost::detail::thread_exit_function_base* func; + thread_exit_callback_node* next; + }; + } + namespace + { + void NTAPI thread_exit_func_callback(HINSTANCE, DWORD, PVOID); + typedef void (NTAPI* tls_callback)(HINSTANCE, DWORD, PVOID); + +#ifdef _MSC_VER + extern "C" + { + extern DWORD _tls_used; //the tls directory (located in .rdata segment) + extern tls_callback __xl_a[], __xl_z[]; //tls initializers */ + } + +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +# pragma data_seg(push, old_seg) +#endif + +#pragma data_seg(".CRT$XLB") + tls_callback p_thread_callback = thread_exit_func_callback; +#pragma data_seg() + +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +# pragma data_seg(pop, old_seg) +#endif +#endif + + void NTAPI thread_exit_func_callback(HINSTANCE h, DWORD dwReason, PVOID pv) + { + if((dwReason==DLL_THREAD_DETACH) || (dwReason==DLL_PROCESS_DETACH)) + { + if(boost::detail::thread_data_base* const current_thread_data=get_current_thread_data()) + { + 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); + } + } + } + } + } + + namespace detail + { + void add_thread_exit_function(thread_exit_function_base* func) + { + thread_exit_callback_node* const new_node=heap_new(); + new_node->func=func; + new_node->next=get_current_thread_data()->thread_exit_callbacks; + get_current_thread_data()->thread_exit_callbacks=new_node; + } + } +} + 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/win32/tss.cpp b/src/win32/tss.cpp new file mode 100644 index 00000000..33f635b9 --- /dev/null +++ b/src/win32/tss.cpp @@ -0,0 +1,251 @@ +// 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(tss_data_once, &init_tss_data); + 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_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_hooks.cpp b/src/win32/tss_hooks.cpp similarity index 100% rename from src/tss_hooks.cpp rename to src/win32/tss_hooks.cpp diff --git a/src/tss_pe.cpp b/src/win32/tss_pe.cpp similarity index 100% rename from src/tss_pe.cpp rename to src/win32/tss_pe.cpp diff --git a/src/win32/xtime.cpp b/src/win32/xtime.cpp new file mode 100644 index 00000000..0ae854ff --- /dev/null +++ b/src/win32/xtime.cpp @@ -0,0 +1,158 @@ +// 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/test_shared_mutex.cpp b/test/test_shared_mutex.cpp index 763758d3..14058180 100644 --- a/test/test_shared_mutex.cpp +++ b/test/test_shared_mutex.cpp @@ -9,6 +9,8 @@ #include #include #include "util.inl" +#include +#include #define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \ { \ @@ -37,10 +39,10 @@ namespace unsigned& max_simultaneous_running_): rw_mutex(rw_mutex_), unblocked_count(unblocked_count_), - unblocked_count_mutex(unblocked_count_mutex_), - finish_mutex(finish_mutex_), simultaneous_running_count(simultaneous_running_count_), - max_simultaneous_running(max_simultaneous_running_) + max_simultaneous_running(max_simultaneous_running_), + unblocked_count_mutex(unblocked_count_mutex_), + finish_mutex(finish_mutex_) {} void operator()() @@ -129,7 +131,7 @@ void test_only_one_writer_permitted() pool.join_all(); CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads); - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u); } void test_reader_blocks_writer() @@ -156,7 +158,7 @@ void test_reader_blocks_writer() pool.join_all(); CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,2U); - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u); } void test_unlocking_writer_unblocks_all_readers() @@ -218,19 +220,19 @@ void test_unlocking_last_reader_only_unblocks_one_writer() { pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,finish_writing_mutex,simultaneous_running_writers,max_simultaneous_writers)); } - boost::thread::sleep(delay(1)); + boost::thread::sleep(delay(2)); CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count); finish_reading_lock.unlock(); - boost::thread::sleep(delay(1)); + boost::thread::sleep(delay(2)); CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1); finish_writing_lock.unlock(); pool.join_all(); CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+writer_count); CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_readers,reader_count); - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_writers,1); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_writers,1u); } void test_only_one_upgrade_lock_permitted() @@ -261,7 +263,7 @@ void test_only_one_upgrade_lock_permitted() pool.join_all(); CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads); - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u); } void test_can_lock_upgrade_if_currently_locked_shared() @@ -334,7 +336,7 @@ void test_if_other_thread_has_write_lock_try_lock_shared_returns_false() 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,1); + CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); bool const try_succeeded=rw_mutex.try_lock_shared(); BOOST_CHECK(!try_succeeded); @@ -400,7 +402,7 @@ void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true() 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,1); + CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); bool const try_succeeded=rw_mutex.try_lock_shared(); BOOST_CHECK(try_succeeded); @@ -422,12 +424,18 @@ void test_timed_lock_shared_times_out_if_write_lock_held() 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,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(100); bool const timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout); - BOOST_CHECK(timeout<=boost::get_system_time()); + boost::system_time const wakeup=boost::get_system_time(); + BOOST_CHECK(timeout<=(wakeup+boost::posix_time::milliseconds(1))); + if(timeout>wakeup) + { + std::cout<<"timeout="<