From: bangerth Date: Wed, 14 Jan 2009 14:29:46 +0000 (+0000) Subject: Use boost threads instead of doing everything ourselves by hand calling POSIX and... X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a951705019fa35737c7fd7649ef70d6172dec4dc;p=dealii-svn.git Use boost threads instead of doing everything ourselves by hand calling POSIX and what not. Makes our code a lot simpler as well :-) git-svn-id: https://svn.dealii.org/trunk@18218 0785d39b-7218-0410-832d-ea1e28bc413d --- diff --git a/deal.II/base/include/base/std_cxx0x/thread.h b/deal.II/base/include/base/std_cxx0x/thread.h new file mode 100644 index 0000000000..48328e8687 --- /dev/null +++ b/deal.II/base/include/base/std_cxx0x/thread.h @@ -0,0 +1,36 @@ +//--------------------------------------------------------------------------- +// $Id: std_cxx0x_tuple.h 16094 2008-05-14 19:18:25Z bangerth $ +// Version: $Name$ +// +// Copyright (C) 2009 by the deal.II authors +// +// This file is subject to QPL and may not be distributed +// without copyright and license information. Please refer +// to the file deal.II/doc/license.html for the text and +// further information on this license. +// +//--------------------------------------------------------------------------- +#ifndef __deal2__std_cxx0x_thread_h +#define __deal2__std_cxx0x_thread_h + + +#include + +#ifdef DEAL_II_CAN_USE_CXX0X + +# include + +#else + +# include + +DEAL_II_NAMESPACE_OPEN +namespace std_cxx0x +{ + using boost::thread; +} +DEAL_II_NAMESPACE_CLOSE + +#endif + +#endif diff --git a/deal.II/base/include/base/thread_management.h b/deal.II/base/include/base/thread_management.h index 0a912d50e1..2c0ddb3249 100644 --- a/deal.II/base/include/base/thread_management.h +++ b/deal.II/base/include/base/thread_management.h @@ -21,6 +21,10 @@ #include #include +#if (DEAL_II_USE_MT == 1) +# include +#endif + #include #include #include @@ -1187,143 +1191,111 @@ namespace Threads namespace internal { #if (DEAL_II_USE_MT == 1) -# if defined(DEAL_II_USE_MT_POSIX) - /** - * @internal - * Base class describing a - * thread. This is the basic - * class abstracting the - * operating system's POSIX - * implementation into a C++ - * class. It provides a mechanism - * to start a new thread, as well - * as for joining it. - * - * @author Wolfgang Bangerth, 2003 - */ - struct thread_description_base + /** + * A class that represents threads. For + * each thread, we create exactly one of + * these objects -- exactly one because + * it carries the returned value of the + * function called on the thread. + * + * While we have only one of these + * objects per thread, several + * Threads::Thread objects may refer to + * this descriptor. + */ + template + struct ThreadDescriptor { - private: - /** - * Variable holding the data - * the operating system needs - * to work with a thread. - */ - pthread_t thread; - - /** - * Store whether the - * join() member function - * as already been called. If - * true, then join - * will return immediately, - * otherwise it needs to go - * through a call to the - * operating system. - * - * This class is generated - * exactly once per thread, - * but is kept in the - * background: user's should - * not directly access this - * class. Access to it is - * performed through counted - * pointers, both from - * Thread<> objects as - * well as from the thread - * entry point function on - * the new thread. It is only - * deleted when all users - * have freed it, which means - * that also the new thread - * has ended. - */ - mutable volatile bool was_joined; - - /** - * Mutex used to synchronise - * calls to the join() - * function. - */ - mutable ThreadMutex join_mutex; - - public: + /** + * An object that represents the + * thread started. + */ + std_cxx0x::thread thread; - /** - * Constructor. - */ - thread_description_base (); - - /** - * Destructor. - */ - virtual ~thread_description_base (); - - /** - * Create a new thread with - * the given thread entry - * point and arguments. Store - * the result of the - * operation in the - * thread member variable - * for further use. - */ - void create (void * (*p) (void *), void *d); - - /** - * Join a thread, i.e. wait - * for it to finish. This - * function can safely be - * called from different - * threads at the same time, - * and can also be called - * more than once. - */ - void join () const; + /** + * An object that will hold the value + * returned by the function called on + * the thread. + */ + return_value ret_val; /** - * Exception + * Constructor. Start the thread and + * let it put its return value into + * the ret_val object. */ - DeclException1 (ExcThreadCreationError, - int, - << "pthread_create return code is " << arg1); - }; + ThreadDescriptor (const std_cxx0x::function &function) + : + thread (thread_entry_point, function, &ret_val) + {} -# else // some other threading model -# error Not Implemented -# endif // defined(DEAL_II_USE_MT_POSIX) -#else // no threading enabled + /** + * Wait for the thread to end. + */ + void join () + { + thread.join (); + } + + private: - struct thread_description_base - { - static void join () {} + /** + * The function that runs on the + * thread. + */ + static + void thread_entry_point (const std_cxx0x::function function, + return_value *ret_val) + { + call (function, *ret_val); + } }; - -#endif - /** - * @internal - * Class derived from - * thread_description_base() - * that also provides the - * possibility to store a return - * value. - * - * @author Wolfgang Bangerth, 2003 - */ +#else + /** + * A class that represents threads. For + * each thread, we create exactly one of + * these objects -- exactly one because + * it carries the returned value of the + * function called on the thread. + * + * While we have only one of these + * objects per thread, several + * Threads::Thread objects may refer to + * this descriptor. + */ template - struct thread_description : public thread_description_base + struct ThreadDescriptor { + /** + * An object that will hold the value + * returned by the function called on + * the thread. + */ return_value ret_val; - }; - - // forward declare another class - template struct ThreadStarter; - } + /** + * Constructor. Start the thread and + * let it put its return value into + * the ret_val object. + */ + ThreadDescriptor (const std_cxx0x::function &function) + { + call (function, ret_val); + } + /** + * Wait for the thread to end. + */ + void join () + {} + }; + +#endif + } + /** * User visible class describing a @@ -1342,39 +1314,22 @@ namespace Threads * return value, you can omit the * template argument. * - * @author Wolfgang Bangerth, 2003 + * @author Wolfgang Bangerth, 2003, 2009 + * @ingroup threads */ template class Thread { + public: /** * Construct a thread object - * with a pointer to an - * internal thread object. This - * is the constructor used to - * the spawn family of - * functions. - * - * We would like to make this - * constructor private and only - * grant the - * fun_wrapper::fire_up - * function friendship, but - * granting friendship to - * functions in other - * namespaces doesn't work with - * some compilers, so only do - * so if the configure script - * decided that this is safe. + * with a function object. */ -#if defined(DEAL_II_NAMESP_TEMPL_FRIEND_BUG2) || defined(DEAL_II_NAMESP_TEMPL_FRIEND_BUG) - public: -#endif - Thread (const std_cxx0x::shared_ptr > &td) - : thread_descriptor (td) {} + Thread (const std_cxx0x::function &function) + : + thread_descriptor (new internal::ThreadDescriptor(function)) + {} - public: - /** * Default constructor. You * can't do much with a thread @@ -1382,7 +1337,7 @@ namespace Threads * except for assigning it a * thread object that holds * data created by the - * spawn functions. + * new_thread functions. */ Thread () {} @@ -1451,210 +1406,10 @@ namespace Threads * as long as there is at least * one subscriber to it. */ - std_cxx0x::shared_ptr > thread_descriptor; - -#if !defined(DEAL_II_NAMESP_TEMPL_FRIEND_BUG2) && !defined(DEAL_II_NAMESP_TEMPL_FRIEND_BUG) - template friend struct internal::ThreadStarter; -#endif + std_cxx0x::shared_ptr > thread_descriptor; }; - - - namespace internal - { - /** - * @internal - * Wrap the arguments to a - * non-member or static member - * function and provide an entry - * point for a new thread that - * unwraps this data and calls - * the function with them. - * - * @author Wolfgang Bangerth, 2003 - */ - template - struct ThreadStarter - { - public: - /** - * Start a new thread, wait - * until it has copied the - * data out of this object, - * and return the thread - * descriptor. - * - * In the non-multithreaded case, - * simply call the function. - */ - static - Thread start_thread (const std_cxx0x::function &function) - { - ThreadStarter wrapper (function); - wrapper.thread_descriptor = - std_cxx0x::shared_ptr > - (new internal::thread_description()); - -#if (DEAL_II_USE_MT == 1) - ThreadMutex::ScopedLock lock (wrapper.mutex); - wrapper.thread_descriptor->create (&ThreadStarter::entry_point, - (void *)&wrapper); - - // wait for the newly created - // thread to indicate that it has - // copied the function - // descriptor. note that the - // POSIX description of - // pthread_cond_wait says that - // the function can return - // spuriously and may have to be - // called again; we guard against - // this using the - // data_has_been_copied variable - // that indicates whether the - // condition has actually been - // met - do - { - wrapper.condition.wait (wrapper.mutex); - } - while (wrapper.data_has_been_copied == false); -#else - call (function, wrapper.thread_descriptor->ret_val); -#endif - return wrapper.thread_descriptor; - } - - private: - /** - * Constructor. Store the - * necessary information - * about the function to be - * called and with which - * arguments. - * - * Pass down the address of - * this class's thread entry - * point function. This way, - * we can ensure that object - * and thread entry point - * function always are in - * synch with respect to - * their knowledge of the - * types involved. - */ - ThreadStarter (const std_cxx0x::function &function) - : - function (function), - data_has_been_copied (false) - {} - - /** - * Shared pointer to the - * unique object describing a - * thread on the OS level. - */ - std_cxx0x::shared_ptr > - thread_descriptor; - - /** - * Mutex and condition - * variable used to - * synchronise calling and - * called thread. - */ - mutable ThreadMutex mutex; - mutable ThreadCondition condition; - - /** - * Pointer to the function to - * be called on the new - * thread. - * - * Note that it is enough to store a - * reference to the function object - * because of the way the creation of - * threads is staged. - */ - const std_cxx0x::function &function; - - /** - * A variable that indicates whether - * the called thread has copied the - * function descriptor to its own - * stack. - */ - mutable bool data_has_been_copied; - - /** - * Entry point for the new - * thread. - */ - static void * entry_point (void *arg) - { - const ThreadStarter *wrapper - = reinterpret_cast*> (arg); - - // copy information from - // the stack of the - // calling thread - std_cxx0x::function function = wrapper->function; - - std_cxx0x::shared_ptr > - thread_descriptor = wrapper->thread_descriptor; - - // signal the fact that - // we have copied all the - // information that is - // needed - // - // note that we indicate success - // of the operation not only - // through the condition variable - // but also through - // data_has_been_copied because - // pthread_cond_wait can return - // spuriously and we need to - // check there whether the return - // is spurious or not - { - wrapper->data_has_been_copied = true; - ThreadMutex::ScopedLock lock (wrapper->mutex); - wrapper->condition.signal (); - } - - // call the - // function. since an - // exception that is - // thrown from one of the - // called functions will - // not propagate to the - // main thread, it will - // kill the program if - // not treated here - // before we return to - // the operating system's - // thread library - internal::register_thread (); - try - { - internal::call (function, thread_descriptor->ret_val); - } - catch (const std::exception &exc) - { - internal::handle_std_exception (exc); - } - catch (...) - { - internal::handle_unknown_exception (); - } - internal::deregister_thread (); - - return 0; - } - }; - } - + namespace internal { /** @@ -1751,7 +1506,7 @@ namespace Threads Thread operator() () { - return ThreadStarter::start_thread (function); + return Thread (function); } private: @@ -1780,7 +1535,7 @@ namespace Threads operator() (typename std_cxx0x::tuple_element<0,ArgList>::type arg1) { return - ThreadStarter::start_thread + Thread (std_cxx0x::bind (function, internal::maybe_make_ref::type>::act(arg1))); } @@ -1812,7 +1567,7 @@ namespace Threads typename std_cxx0x::tuple_element<1,ArgList>::type arg2) { return - ThreadStarter::start_thread + Thread (std_cxx0x::bind (function, internal::maybe_make_ref::type>::act(arg1), internal::maybe_make_ref::type>::act(arg2))); @@ -1846,7 +1601,7 @@ namespace Threads typename std_cxx0x::tuple_element<2,ArgList>::type arg3) { return - ThreadStarter::start_thread + Thread (std_cxx0x::bind (function, internal::maybe_make_ref::type>::act(arg1), internal::maybe_make_ref::type>::act(arg2), @@ -1882,7 +1637,7 @@ namespace Threads typename std_cxx0x::tuple_element<3,ArgList>::type arg4) { return - ThreadStarter::start_thread + Thread (std_cxx0x::bind (function, internal::maybe_make_ref::type>::act(arg1), internal::maybe_make_ref::type>::act(arg2), @@ -1920,7 +1675,7 @@ namespace Threads typename std_cxx0x::tuple_element<4,ArgList>::type arg5) { return - ThreadStarter::start_thread + Thread (std_cxx0x::bind (function, internal::maybe_make_ref::type>::act(arg1), internal::maybe_make_ref::type>::act(arg2), @@ -1960,7 +1715,7 @@ namespace Threads typename std_cxx0x::tuple_element<5,ArgList>::type arg6) { return - ThreadStarter::start_thread + Thread (std_cxx0x::bind (function, internal::maybe_make_ref::type>::act(arg1), internal::maybe_make_ref::type>::act(arg2), @@ -2002,7 +1757,7 @@ namespace Threads typename std_cxx0x::tuple_element<6,ArgList>::type arg7) { return - ThreadStarter::start_thread + Thread (std_cxx0x::bind (function, internal::maybe_make_ref::type>::act(arg1), internal::maybe_make_ref::type>::act(arg2), @@ -2046,7 +1801,7 @@ namespace Threads typename std_cxx0x::tuple_element<7,ArgList>::type arg8) { return - ThreadStarter::start_thread + Thread (std_cxx0x::bind (function, internal::maybe_make_ref::type>::act(arg1), internal::maybe_make_ref::type>::act(arg2), @@ -2092,7 +1847,7 @@ namespace Threads typename std_cxx0x::tuple_element<8,ArgList>::type arg9) { return - ThreadStarter::start_thread + Thread (std_cxx0x::bind (function, internal::maybe_make_ref::type>::act(arg1), internal::maybe_make_ref::type>::act(arg2), diff --git a/deal.II/base/source/boost_threads.cc b/deal.II/base/source/boost_threads.cc new file mode 100644 index 0000000000..6632f20cae --- /dev/null +++ b/deal.II/base/source/boost_threads.cc @@ -0,0 +1,24 @@ +//--------------------------------------------------------------------------- +// $Id: thread_management.cc 18205 2009-01-13 13:53:08Z bangerth $ +// Version: $Name$ +// +// Copyright (C) 2009 by the deal.II authors +// +// This file is subject to QPL and may not be distributed +// without copyright and license information. Please refer +// to the file deal.II/doc/license.html for the text and +// further information on this license. +// +//--------------------------------------------------------------------------- + + +// include all the files that form BOOST's thread implementation so that we +// don't have to build BOOST itself only to get at this small part of it. it +// also ensures that we use the correct compiler and flags + +#define BOOST_THREAD_POSIX +#define BOOST_THREAD_BUILD_LIB 1 + +#include <../libs/thread/src/pthread/once.cpp> +#include <../libs/thread/src/pthread/exceptions.cpp> +#include <../libs/thread/src/pthread/thread.cpp> diff --git a/deal.II/base/source/thread_management.cc b/deal.II/base/source/thread_management.cc index ae6af3c6dc..8166a37d66 100644 --- a/deal.II/base/source/thread_management.cc +++ b/deal.II/base/source/thread_management.cc @@ -275,169 +275,7 @@ namespace Threads return_values[i].second = end; }; return return_values; - } - - -#if (DEAL_II_USE_MT == 1) && defined(DEAL_II_USE_MT_POSIX) - - namespace internal - { - thread_description_base::thread_description_base () - : - was_joined (false) - {} - - - - thread_description_base::~thread_description_base () - { - // if we are here, then the - // last listener is just about - // to cease to exists. there - // are two possibilities (since - // there are two types of - // possible listeners, and - // exactly one listener is - // around): - // - // 1. there are no Thread<> - // objects around any more, but - // we are at the end of the - // entry_point function of the - // new thread; the thread is - // still running, though, and - // we are called from this new - // thread. - // - // if this is the case, - // apparently none of the - // orginal listeners has called - // join(), otherwise the thread - // would not be running any - // more. since there are no - // listeners any more, nobody - // will ever call join() on - // this thread any - // more. however, to avoid a - // resource leak, somebody has - // to do something like that -- - // on the other hand, we can't - // since calling pthread_join() - // on ourself will create a - // deadlock, of course. so - // detach the thread. - // - // note that in this case, - // since nobody has ever called - // join(), was_joined must be - // false - // - // 2. the thread has already - // ended. in this case, the - // last Thread<> object - // refering to it just went out - // of scope. If this is the - // case, to prevent a memory - // leak, we have to call join - // on the thread, if this has - // not yet happened, i.e. if - // was_joined is false. - // - // if we are in case 2, then - // the destructor is called - // from another than the - // presently running thread - // - // - // now: how do we find out - // which case we're in? we - // could either call - // pthread_join and see whether - // we get an error back, or if - // we get back an error on - // pthread_detach. from the man - // pages, the second way seems - // a little bit safer, so go it: - if (was_joined == false) - { - // assume case 1: - int error = pthread_detach (thread); - if (error == 0) - return; - - // ouch, could not - // detach. see if thread - // could not be found any - // more: - if (error == ESRCH) - // ok, this is the - // case. then we are in - // branch 2, and need to - // join the thread - join (); - else - // something went - // terribly wrong - AssertThrow (false, ExcInternalError()); - } - } - - - void - thread_description_base::create (void * (*p) (void *), void *d) - { - // start new thread. retry until - // we either succeed or get an - // error other than EAGAIN - int error = 0; - do - { - error = pthread_create (&thread, 0, p, d); - } - while (error == EAGAIN); - - AssertThrow (error == 0, - ExcThreadCreationError(error)); - } - - - - void - thread_description_base::join () const - { - // use Schmidt's double - // checking pattern: if thread - // was already joined, then - // return immediately - if (was_joined) - return; - - // otherwise make sure that - // only one thread can enter - // the following section at a - // time - ThreadMutex::ScopedLock lock(join_mutex); - // while getting the lock, - // another thread may have set - // was_joined to true, so check - // again (this is the double - // checking pattern) and only - // if we are really sure that - // this has not happened, call - // pthread_join - if (!was_joined) - { - const int error = pthread_join (thread, 0); - AssertThrow (error == 0, ExcInternalError()); - } - - // set the flag - was_joined = true; - } - - } // end namespace internal - -#endif // (DEAL_II_USE_MT == 1) && defined(DEAL_II_USE_MT_POSIX) + } } // end namespace Thread diff --git a/deal.II/contrib/boost/include/boost/thread/barrier.hpp b/deal.II/contrib/boost/include/boost/thread/barrier.hpp new file mode 100644 index 0000000000..546f5e9779 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/barrier.hpp @@ -0,0 +1,63 @@ +// Copyright (C) 2002-2003 +// David Moore, William E. Kempf +// Copyright (C) 2007-8 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_BARRIER_JDM030602_HPP +#define BOOST_BARRIER_JDM030602_HPP + +#include + +#include +#include +#include +#include + +#include + +namespace boost +{ + + class barrier + { + public: + barrier(unsigned int count) + : m_threshold(count), m_count(count), m_generation(0) + { + if (count == 0) + throw std::invalid_argument("count cannot be zero."); + } + + bool wait() + { + boost::mutex::scoped_lock lock(m_mutex); + unsigned int gen = m_generation; + + if (--m_count == 0) + { + m_generation++; + m_count = m_threshold; + m_cond.notify_all(); + return true; + } + + while (gen == m_generation) + m_cond.wait(lock); + return false; + } + + private: + mutex m_mutex; + condition_variable m_cond; + unsigned int m_threshold; + unsigned int m_count; + unsigned int m_generation; + }; + +} // namespace boost + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/condition.hpp b/deal.II/contrib/boost/include/boost/thread/condition.hpp new file mode 100644 index 0000000000..35b879fe03 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/condition.hpp @@ -0,0 +1,16 @@ +#ifndef BOOST_THREAD_CONDITION_HPP +#define BOOST_THREAD_CONDITION_HPP +// (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) + +#include + +namespace boost +{ + typedef condition_variable_any condition; +} + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/condition_variable.hpp b/deal.II/contrib/boost/include/boost/thread/condition_variable.hpp new file mode 100644 index 0000000000..8f8e9f2ed6 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/condition_variable.hpp @@ -0,0 +1,21 @@ +#ifndef BOOST_THREAD_CONDITION_VARIABLE_HPP +#define BOOST_THREAD_CONDITION_VARIABLE_HPP + +// condition_variable.hpp +// +// (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) + +#include +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include +#else +#error "Boost threads unavailable on this platform" +#endif + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/detail/config.hpp b/deal.II/contrib/boost/include/boost/thread/detail/config.hpp new file mode 100644 index 0000000000..7661507f8d --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/detail/config.hpp @@ -0,0 +1,94 @@ +// 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) + +#ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP +#define BOOST_THREAD_CONFIG_WEK01032003_HPP + +#include +#include + +#if BOOST_WORKAROUND(__BORLANDC__, < 0x600) +# pragma warn -8008 // Condition always true/false +# pragma warn -8080 // Identifier declared but never used +# pragma warn -8057 // Parameter never used +# pragma warn -8066 // Unreachable code +#endif + +#include "platform.hpp" + +// compatibility with the rest of Boost's auto-linking code: +#if defined(BOOST_THREAD_DYN_DLL) || defined(BOOST_ALL_DYN_LINK) +# undef BOOST_THREAD_USE_LIB +# define BOOST_THREAD_USE_DLL +#endif + +#if defined(BOOST_THREAD_BUILD_DLL) //Build dll +#elif defined(BOOST_THREAD_BUILD_LIB) //Build lib +#elif defined(BOOST_THREAD_USE_DLL) //Use dll +#elif defined(BOOST_THREAD_USE_LIB) //Use lib +#else //Use default +# if defined(BOOST_THREAD_PLATFORM_WIN32) +# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN) + //For compilers supporting auto-tss cleanup + //with Boost.Threads lib, use Boost.Threads lib +# define BOOST_THREAD_USE_LIB +# else + //For compilers not yet supporting auto-tss cleanup + //with Boost.Threads lib, use Boost.Threads dll +# define BOOST_THREAD_USE_DLL +# endif +# else +# define BOOST_THREAD_USE_LIB +# endif +#endif + +#if defined(BOOST_HAS_DECLSPEC) +# if defined(BOOST_THREAD_BUILD_DLL) //Build dll +# define BOOST_THREAD_DECL __declspec(dllexport) +# elif defined(BOOST_THREAD_USE_DLL) //Use dll +# define BOOST_THREAD_DECL __declspec(dllimport) +# else +# define BOOST_THREAD_DECL +# endif +#else +# define BOOST_THREAD_DECL +#endif // BOOST_HAS_DECLSPEC + +// +// Automatically link to the correct build variant where possible. +// +#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_THREAD_NO_LIB) && !defined(BOOST_THREAD_BUILD_DLL) && !defined(BOOST_THREAD_BUILD_LIB) +// +// Tell the autolink to link dynamically, this will get undef'ed by auto_link.hpp +// once it's done with it: +// +#if defined(BOOST_THREAD_USE_DLL) +# define BOOST_DYN_LINK +#endif +// +// Set the name of our library, this will get undef'ed by auto_link.hpp +// once it's done with it: +// +#if defined(BOOST_THREAD_LIB_NAME) +# define BOOST_LIB_NAME BOOST_THREAD_LIB_NAME +#else +# define BOOST_LIB_NAME boost_thread +#endif +// +// If we're importing code from a dll, then tell auto_link.hpp about it: +// +// And include the header that does the work: +// +#include +#endif // auto-linking disabled + +#endif // BOOST_THREAD_CONFIG_WEK1032003_HPP + +// Change Log: +// 22 Jan 05 Roland Schwarz (speedsnail) +// Usage of BOOST_HAS_DECLSPEC macro. +// Default again is static lib usage. +// BOOST_DYN_LINK only defined when autolink included. diff --git a/deal.II/contrib/boost/include/boost/thread/detail/force_cast.hpp b/deal.II/contrib/boost/include/boost/thread/detail/force_cast.hpp new file mode 100644 index 0000000000..d5d15adc1a --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/detail/force_cast.hpp @@ -0,0 +1,39 @@ +// Copyright (C) 2001-2003 +// Mac Murrett +// +// 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) +// +// See http://www.boost.org for most recent version including documentation. + +#ifndef BOOST_FORCE_CAST_MJM012402_HPP +#define BOOST_FORCE_CAST_MJM012402_HPP + +#include + +namespace boost { +namespace detail { +namespace thread { + +// force_cast will convert anything to anything. + +// general case +template +inline Return_Type &force_cast(Argument_Type &rSrc) +{ + return(*reinterpret_cast(&rSrc)); +} + +// specialization for const +template +inline const Return_Type &force_cast(const Argument_Type &rSrc) +{ + return(*reinterpret_cast(&rSrc)); +} + +} // namespace thread +} // namespace detail +} // namespace boost + +#endif // BOOST_FORCE_CAST_MJM012402_HPP diff --git a/deal.II/contrib/boost/include/boost/thread/detail/move.hpp b/deal.II/contrib/boost/include/boost/thread/detail/move.hpp new file mode 100644 index 0000000000..044ecda6c7 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/detail/move.hpp @@ -0,0 +1,60 @@ +// 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-8 Anthony Williams + +#ifndef BOOST_THREAD_MOVE_HPP +#define BOOST_THREAD_MOVE_HPP + +#ifndef BOOST_NO_SFINAE +#include +#include +#endif + +#include + +namespace boost +{ + namespace detail + { + template + struct thread_move_t + { + T& t; + explicit thread_move_t(T& t_): + t(t_) + {} + + T& operator*() const + { + return t; + } + + T* operator->() const + { + return &t; + } + private: + void operator=(thread_move_t&); + }; + } + +#ifndef BOOST_NO_SFINAE + template + typename enable_if >, T >::type move(T& t) + { + return T(detail::thread_move_t(t)); + } +#endif + + template + detail::thread_move_t move(detail::thread_move_t t) + { + return t; + } + +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/detail/platform.hpp b/deal.II/contrib/boost/include/boost/thread/detail/platform.hpp new file mode 100644 index 0000000000..4a37cf389b --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/detail/platform.hpp @@ -0,0 +1,71 @@ +// Copyright 2006 Roland Schwarz. +// (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) +// +// This work is a reimplementation along the design and ideas +// of William E. Kempf. + +#ifndef BOOST_THREAD_RS06040501_HPP +#define BOOST_THREAD_RS06040501_HPP + +// fetch compiler and platform configuration +#include + +// insist on threading support being available: +#include + +// choose platform +#if defined(linux) || defined(__linux) || defined(__linux__) +# define BOOST_THREAD_LINUX +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +# define BOOST_THREAD_BSD +#elif defined(sun) || defined(__sun) +# define BOOST_THREAD_SOLARIS +#elif defined(__sgi) +# define BOOST_THREAD_IRIX +#elif defined(__hpux) +# define BOOST_THREAD_HPUX +#elif defined(__CYGWIN__) +# define BOOST_THREAD_CYGWIN +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +# define BOOST_THREAD_WIN32 +#elif defined(__BEOS__) +# define BOOST_THREAD_BEOS +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) +# define BOOST_THREAD_MACOS +#elif defined(__IBMCPP__) || defined(_AIX) +# define BOOST_THREAD_AIX +#elif defined(__amigaos__) +# define BOOST_THREAD_AMIGAOS +#elif defined(__QNXNTO__) +# define BOOST_THREAD_QNXNTO +#elif defined(unix) || defined(__unix) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE) +# if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_THREAD_POSIX) +# define BOOST_THREAD_POSIX +# endif +#endif + +// For every supported platform add a new entry into the dispatch table below. +// BOOST_THREAD_POSIX is tested first, so on platforms where posix and native +// threading is available, the user may choose, by defining BOOST_THREAD_POSIX +// in her source. If a platform is known to support pthreads and no native +// port of boost_thread is available just specify "pthread" in the +// dispatcher table. If there is no entry for a platform but pthreads is +// available on the platform, pthread is choosen as default. If nothing is +// available the preprocessor will fail with a diagnostic message. + +#if defined(BOOST_THREAD_POSIX) +# define BOOST_THREAD_PLATFORM_PTHREAD +#else +# if defined(BOOST_THREAD_WIN32) +# define BOOST_THREAD_PLATFORM_WIN32 +# elif defined(BOOST_HAS_PTHREADS) +# define BOOST_THREAD_PLATFORM_PTHREAD +# else +# error "Sorry, no boost threads are available for this platform." +# endif +#endif + +#endif // BOOST_THREAD_RS06040501_HPP diff --git a/deal.II/contrib/boost/include/boost/thread/detail/singleton.hpp b/deal.II/contrib/boost/include/boost/thread/detail/singleton.hpp new file mode 100644 index 0000000000..a20a42908d --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/detail/singleton.hpp @@ -0,0 +1,59 @@ +// Copyright (C) 2001-2003 +// Mac Murrett +// +// 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) +// +// See http://www.boost.org for most recent version including documentation. + +#ifndef BOOST_SINGLETON_MJM012402_HPP +#define BOOST_SINGLETON_MJM012402_HPP + +#include + +namespace boost { +namespace detail { +namespace thread { + +// class singleton has the same goal as all singletons: create one instance of +// a class on demand, then dish it out as requested. + +template +class singleton : private T +{ +private: + singleton(); + ~singleton(); + +public: + static T &instance(); +}; + + +template +inline singleton::singleton() +{ + /* no-op */ +} + +template +inline singleton::~singleton() +{ + /* no-op */ +} + +template +/*static*/ T &singleton::instance() +{ + // function-local static to force this to work correctly at static + // initialization time. + static singleton s_oT; + return(s_oT); +} + +} // namespace thread +} // namespace detail +} // namespace boost + +#endif // BOOST_SINGLETON_MJM012402_HPP diff --git a/deal.II/contrib/boost/include/boost/thread/detail/thread.hpp b/deal.II/contrib/boost/include/boost/thread/detail/thread.hpp new file mode 100644 index 0000000000..fbb895d170 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/detail/thread.hpp @@ -0,0 +1,575 @@ +#ifndef BOOST_THREAD_THREAD_COMMON_HPP +#define BOOST_THREAD_THREAD_COMMON_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-8 Anthony Williams + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4251) +#endif + +namespace boost +{ + namespace detail + { + template + class thread_data: + public detail::thread_data_base + { + public: +#ifdef BOOST_HAS_RVALUE_REFS + thread_data(F&& f_): + f(static_cast(f_)) + {} +#else + thread_data(F f_): + f(f_) + {} + thread_data(detail::thread_move_t f_): + f(f_) + {} +#endif + void run() + { + f(); + } + private: + F f; + + void operator=(thread_data&); + thread_data(thread_data&); + }; + + template + class thread_data >: + public detail::thread_data_base + { + private: + F& f; + + void operator=(thread_data&); + thread_data(thread_data&); + public: + thread_data(boost::reference_wrapper f_): + f(f_) + {} + + void run() + { + f(); + } + }; + + template + class thread_data >: + public detail::thread_data_base + { + private: + F& f; + void operator=(thread_data&); + thread_data(thread_data&); + public: + thread_data(const boost::reference_wrapper f_): + f(f_) + {} + + void run() + { + f(); + } + }; + } + + class BOOST_THREAD_DECL thread + { + private: + thread(thread&); + thread& operator=(thread&); + + void release_handle(); + + mutable boost::mutex thread_info_mutex; + detail::thread_data_ptr thread_info; + + void start_thread(); + + explicit thread(detail::thread_data_ptr data); + + detail::thread_data_ptr get_thread_info() const; + +#ifdef BOOST_HAS_RVALUE_REFS + template + static inline detail::thread_data_ptr make_thread_info(F&& f) + { + return detail::thread_data_ptr(detail::heap_new::type> >(static_cast(f))); + } + static inline detail::thread_data_ptr make_thread_info(void (*f)()) + { + return detail::thread_data_ptr(detail::heap_new >(f)); + } +#else + template + static inline detail::thread_data_ptr make_thread_info(F f) + { + return detail::thread_data_ptr(detail::heap_new >(f)); + } + template + static inline detail::thread_data_ptr make_thread_info(boost::detail::thread_move_t f) + { + return detail::thread_data_ptr(detail::heap_new >(f)); + } + + struct dummy; +#endif + public: + thread(); + ~thread(); + +#ifdef BOOST_HAS_RVALUE_REFS + template + thread(F&& f): + thread_info(make_thread_info(static_cast(f))) + { + start_thread(); + } + + thread(thread&& other) + { + thread_info.swap(other.thread_info); + } + + thread& operator=(thread&& other) + { + thread_info=other.thread_info; + other.thread_info.reset(); + return *this; + } + + thread&& move() + { + return static_cast(*this); + } + +#else +#ifdef BOOST_NO_SFINAE + template + explicit thread(F f): + thread_info(make_thread_info(f)) + { + start_thread(); + } +#else + template + explicit thread(F f,typename disable_if >, dummy* >::type=0): + thread_info(make_thread_info(f)) + { + start_thread(); + } +#endif + + template + explicit thread(detail::thread_move_t f): + thread_info(make_thread_info(f)) + { + start_thread(); + } + + thread(detail::thread_move_t x) + { + thread_info=x->thread_info; + x->thread_info.reset(); + } + + thread& operator=(detail::thread_move_t x) + { + thread new_thread(x); + swap(new_thread); + return *this; + } + + operator detail::thread_move_t() + { + return move(); + } + + detail::thread_move_t move() + { + detail::thread_move_t x(*this); + return x; + } + +#endif + + template + thread(F f,A1 a1): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1))) + { + start_thread(); + } + template + thread(F f,A1 a1,A2 a2): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5,a6))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5,a6,a7))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5,a6,a7,a8))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5,a6,a7,a8,a9))) + { + start_thread(); + } + + void swap(thread& x) + { + thread_info.swap(x.thread_info); + } + + class id; + id get_id() const; + + + bool joinable() const; + void join(); + bool timed_join(const system_time& wait_until); + + template + inline bool timed_join(TimeDuration const& rel_time) + { + return timed_join(get_system_time()+rel_time); + } + void detach(); + + static unsigned hardware_concurrency(); + + typedef detail::thread_data_base::native_handle_type native_handle_type; + native_handle_type native_handle(); + + // backwards compatibility + bool operator==(const thread& other) const; + bool operator!=(const thread& other) const; + + static inline void yield() + { + this_thread::yield(); + } + + static inline void sleep(const system_time& xt) + { + this_thread::sleep(xt); + } + + // extensions + void interrupt(); + bool interruption_requested() const; + }; + + inline void swap(thread& lhs,thread& rhs) + { + return lhs.swap(rhs); + } + +#ifdef BOOST_HAS_RVALUE_REFS + inline thread&& move(thread&& t) + { + return t; + } +#else + inline thread move(detail::thread_move_t t) + { + return thread(t); + } +#endif + + namespace this_thread + { + class BOOST_THREAD_DECL disable_interruption + { + disable_interruption(const disable_interruption&); + disable_interruption& operator=(const disable_interruption&); + + bool interruption_was_enabled; + friend class restore_interruption; + public: + disable_interruption(); + ~disable_interruption(); + }; + + class BOOST_THREAD_DECL restore_interruption + { + restore_interruption(const restore_interruption&); + restore_interruption& operator=(const restore_interruption&); + public: + explicit restore_interruption(disable_interruption& d); + ~restore_interruption(); + }; + + thread::id BOOST_THREAD_DECL get_id(); + + void BOOST_THREAD_DECL interruption_point(); + bool BOOST_THREAD_DECL interruption_enabled(); + bool BOOST_THREAD_DECL interruption_requested(); + + inline void sleep(xtime const& abs_time) + { + sleep(system_time(abs_time)); + } + } + + class thread::id + { + private: + detail::thread_data_ptr thread_data; + + id(detail::thread_data_ptr thread_data_): + thread_data(thread_data_) + {} + friend class thread; + friend id this_thread::get_id(); + public: + id(): + thread_data() + {} + + bool operator==(const id& y) const + { + return thread_data==y.thread_data; + } + + bool operator!=(const id& y) const + { + return thread_data!=y.thread_data; + } + + bool operator<(const id& y) const + { + return thread_data(const id& y) const + { + return y.thread_data=(const id& y) const + { + return !(thread_data + friend std::basic_ostream& + operator<<(std::basic_ostream& os, const id& x) + { + if(x.thread_data) + { + 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); + std::auto_ptr new_thread(new thread(threadfunc)); + threads.push_back(new_thread.get()); + return new_thread.release(); + } + + 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(); + } + } + + void interrupt_all() + { + boost::lock_guard guard(m); + + for(std::list::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + (*it)->interrupt(); + } + } + + size_t size() const + { + boost::lock_guard guard(m); + return threads.size(); + } + + private: + std::list threads; + mutable mutex m; + }; +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/detail/thread_heap_alloc.hpp b/deal.II/contrib/boost/include/boost/thread/detail/thread_heap_alloc.hpp new file mode 100644 index 0000000000..2f9bfd5c0b --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/detail/thread_heap_alloc.hpp @@ -0,0 +1,23 @@ +#ifndef BOOST_THREAD_THREAD_HEAP_ALLOC_HPP +#define BOOST_THREAD_THREAD_HEAP_ALLOC_HPP + +// thread_heap_alloc.hpp +// +// (C) Copyright 2008 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include +#else +#error "Boost threads unavailable on this platform" +#endif + + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/detail/tss_hooks.hpp b/deal.II/contrib/boost/include/boost/thread/detail/tss_hooks.hpp new file mode 100644 index 0000000000..c496844279 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/detail/tss_hooks.hpp @@ -0,0 +1,82 @@ +// (C) Copyright Michael Glassford 2004. +// 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) + +#if !defined(BOOST_TLS_HOOKS_HPP) +#define BOOST_TLS_HOOKS_HPP + +#include + +#include + +#if defined(BOOST_HAS_WINTHREADS) + + typedef void (__cdecl *thread_exit_handler)(void); + + extern "C" BOOST_THREAD_DECL int at_thread_exit( + thread_exit_handler exit_handler + ); + //Add a function to the list of functions that will + //be called when a thread is about to exit. + //Currently only implemented for Win32, but should + //later be implemented for all platforms. + //Used by Win32 implementation of Boost.Threads + //tss to perform cleanup. + //Like the C runtime library atexit() function, + //which it mimics, at_thread_exit() returns + //zero if successful and a nonzero + //value if an error occurs. + +#endif //defined(BOOST_HAS_WINTHREADS) + +#if defined(BOOST_HAS_WINTHREADS) + + extern "C" BOOST_THREAD_DECL void on_process_enter(void); + //Function to be called when the exe or dll + //that uses Boost.Threads first starts + //or is first loaded. + //Should be called only before the first call to + //on_thread_enter(). + //Called automatically by Boost.Threads when + //a method for doing so has been discovered. + //May be omitted; may be called multiple times. + + extern "C" BOOST_THREAD_DECL void on_process_exit(void); + //Function to be called when the exe or dll + //that uses Boost.Threads first starts + //or is first loaded. + //Should be called only after the last call to + //on_exit_thread(). + //Called automatically by Boost.Threads when + //a method for doing so has been discovered. + //Must not be omitted; may be called multiple times. + + extern "C" BOOST_THREAD_DECL void on_thread_enter(void); + //Function to be called just after a thread starts + //in an exe or dll that uses Boost.Threads. + //Must be called in the context of the thread + //that is starting. + //Called automatically by Boost.Threads when + //a method for doing so has been discovered. + //May be omitted; may be called multiple times. + + extern "C" BOOST_THREAD_DECL void __cdecl on_thread_exit(void); + //Function to be called just be fore a thread ends + //in an exe or dll that uses Boost.Threads. + //Must be called in the context of the thread + //that is ending. + //Called automatically by Boost.Threads when + //a method for doing so has been discovered. + //Must not be omitted; may be called multiple times. + + extern "C" void tss_cleanup_implemented(void); + //Dummy function used both to detect whether tss cleanup + //cleanup has been implemented and to force + //it to be linked into the Boost.Threads library. + +#endif //defined(BOOST_HAS_WINTHREADS) + +#include + +#endif //!defined(BOOST_TLS_HOOKS_HPP) diff --git a/deal.II/contrib/boost/include/boost/thread/exceptions.hpp b/deal.II/contrib/boost/include/boost/thread/exceptions.hpp new file mode 100644 index 0000000000..49e244fef4 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/exceptions.hpp @@ -0,0 +1,114 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// Copyright (C) 2007-8 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_EXCEPTIONS_PDM070801_H +#define BOOST_THREAD_EXCEPTIONS_PDM070801_H + +#include + +// pdm: Sorry, but this class is used all over the place & I end up +// with recursive headers if I don't separate it +// wek: Not sure why recursive headers would cause compilation problems +// given the include guards, but regardless it makes sense to +// seperate this out any way. + +#include +#include + +#include + +namespace boost +{ + + class BOOST_THREAD_DECL thread_interrupted + {}; + +class BOOST_THREAD_DECL thread_exception : public std::exception +{ +protected: + thread_exception(); + thread_exception(int sys_err_code); + +public: + ~thread_exception() throw(); + + int native_error() const; + +private: + int m_sys_err; +}; + + class condition_error: + public std::exception + { + public: + const char* what() const throw() + { + return "Condition error"; + } + }; + + +class BOOST_THREAD_DECL lock_error : public thread_exception +{ +public: + lock_error(); + lock_error(int sys_err_code); + ~lock_error() throw(); + + virtual const char* what() const throw(); +}; + +class BOOST_THREAD_DECL thread_resource_error : public thread_exception +{ +public: + thread_resource_error(); + thread_resource_error(int sys_err_code); + ~thread_resource_error() throw(); + + virtual const char* what() const throw(); +}; + +class BOOST_THREAD_DECL unsupported_thread_option : public thread_exception +{ +public: + unsupported_thread_option(); + unsupported_thread_option(int sys_err_code); + ~unsupported_thread_option() throw(); + + virtual const char* what() const throw(); +}; + +class BOOST_THREAD_DECL invalid_thread_argument : public thread_exception +{ +public: + invalid_thread_argument(); + invalid_thread_argument(int sys_err_code); + ~invalid_thread_argument() throw(); + + virtual const char* what() const throw(); +}; + +class BOOST_THREAD_DECL thread_permission_error : public thread_exception +{ +public: + thread_permission_error(); + thread_permission_error(int sys_err_code); + ~thread_permission_error() throw(); + + virtual const char* what() const throw(); +}; + +} // namespace boost + +#include + +#endif // BOOST_THREAD_CONFIG_PDM070801_H + +// Change log: +// 3 Jan 03 WEKEMPF Modified for DLL implementation. + diff --git a/deal.II/contrib/boost/include/boost/thread/locks.hpp b/deal.II/contrib/boost/include/boost/thread/locks.hpp new file mode 100644 index 0000000000..abbfd75b4e --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/locks.hpp @@ -0,0 +1,1430 @@ +// 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 BOOST_THREAD_LOCKS_HPP +#define BOOST_THREAD_LOCKS_HPP +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost +{ + struct xtime; + +#if defined(BOOST_NO_SFINAE) || \ + BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) || \ + BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) +#define BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES +#endif + +#ifndef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + namespace detail + { + template + struct has_member_lock + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template + static true_type has_member(U*,void (U::*dummy)()=&U::lock); + static false_type has_member(void*); + + BOOST_STATIC_CONSTANT(bool, value=sizeof(has_member_lock::has_member((T*)NULL))==sizeof(true_type)); + }; + + template + struct has_member_unlock + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template + static true_type has_member(U*,void (U::*dummy)()=&U::unlock); + static false_type has_member(void*); + + BOOST_STATIC_CONSTANT(bool, value=sizeof(has_member_unlock::has_member((T*)NULL))==sizeof(true_type)); + }; + + template + struct has_member_try_lock + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template + static true_type has_member(U*,bool (U::*dummy)()=&U::try_lock); + static false_type has_member(void*); + + BOOST_STATIC_CONSTANT(bool, value=sizeof(has_member_try_lock::has_member((T*)NULL))==sizeof(true_type)); + }; + + } + + + template + struct is_mutex_type + { + BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock::value && + detail::has_member_unlock::value && + detail::has_member_try_lock::value); + + }; +#else + template + struct is_mutex_type + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; +#endif + + struct defer_lock_t + {}; + struct try_to_lock_t + {}; + struct adopt_lock_t + {}; + + const defer_lock_t defer_lock={}; + const try_to_lock_t try_to_lock={}; + const adopt_lock_t adopt_lock={}; + + template + class shared_lock; + + template + class upgrade_lock; + + template + class unique_lock; + + namespace detail + { + template + class try_lock_wrapper; + } + +#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + template + struct is_mutex_type > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template + struct is_mutex_type > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template + struct is_mutex_type > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template + struct is_mutex_type > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + class mutex; + class timed_mutex; + class recursive_mutex; + class recursive_timed_mutex; + class shared_mutex; + + template<> + struct is_mutex_type + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_mutex_type + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_mutex_type + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_mutex_type + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_mutex_type + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + +#endif + + template + class lock_guard + { + private: + Mutex& m; + + explicit lock_guard(lock_guard&); + lock_guard& operator=(lock_guard&); + public: + explicit lock_guard(Mutex& m_): + m(m_) + { + m.lock(); + } + lock_guard(Mutex& m_,adopt_lock_t): + m(m_) + {} + ~lock_guard() + { + m.unlock(); + } + }; + + + template + class unique_lock + { + private: + Mutex* m; + bool is_locked; + unique_lock(unique_lock&); + explicit unique_lock(upgrade_lock&); + unique_lock& operator=(unique_lock&); + unique_lock& operator=(upgrade_lock& other); + public: + unique_lock(): + m(0),is_locked(false) + {} + + explicit unique_lock(Mutex& m_): + m(&m_),is_locked(false) + { + lock(); + } + unique_lock(Mutex& m_,adopt_lock_t): + m(&m_),is_locked(true) + {} + unique_lock(Mutex& m_,defer_lock_t): + m(&m_),is_locked(false) + {} + unique_lock(Mutex& m_,try_to_lock_t): + m(&m_),is_locked(false) + { + try_lock(); + } + template + unique_lock(Mutex& m_,TimeDuration const& target_time): + m(&m_),is_locked(false) + { + timed_lock(target_time); + } + unique_lock(Mutex& m_,system_time const& target_time): + m(&m_),is_locked(false) + { + timed_lock(target_time); + } +#ifdef BOOST_HAS_RVALUE_REFS + unique_lock(unique_lock&& other): + m(other.m),is_locked(other.is_locked) + { + other.is_locked=false; + other.m=0; + } + explicit unique_lock(upgrade_lock&& other); + + unique_lock&& move() + { + return static_cast&&>(*this); + } + + + unique_lock& operator=(unique_lock&& other) + { + unique_lock temp(other); + swap(temp); + return *this; + } + + unique_lock& operator=(upgrade_lock&& other) + { + unique_lock temp(other); + swap(temp); + return *this; + } + void swap(unique_lock&& other) + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } +#else + unique_lock(detail::thread_move_t > other): + m(other->m),is_locked(other->is_locked) + { + other->is_locked=false; + other->m=0; + } + unique_lock(detail::thread_move_t > other); + + operator detail::thread_move_t >() + { + return move(); + } + + detail::thread_move_t > move() + { + return detail::thread_move_t >(*this); + } + + unique_lock& operator=(detail::thread_move_t > other) + { + unique_lock temp(other); + swap(temp); + return *this; + } + + unique_lock& operator=(detail::thread_move_t > other) + { + unique_lock temp(other); + swap(temp); + return *this; + } + void swap(unique_lock& other) + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } + void swap(detail::thread_move_t > other) + { + std::swap(m,other->m); + std::swap(is_locked,other->is_locked); + } +#endif + + ~unique_lock() + { + if(owns_lock()) + { + m->unlock(); + } + } + void lock() + { + if(owns_lock()) + { + throw boost::lock_error(); + } + m->lock(); + is_locked=true; + } + bool try_lock() + { + if(owns_lock()) + { + throw boost::lock_error(); + } + is_locked=m->try_lock(); + return is_locked; + } + template + bool timed_lock(TimeDuration const& relative_time) + { + is_locked=m->timed_lock(relative_time); + return is_locked; + } + + bool timed_lock(::boost::system_time const& absolute_time) + { + is_locked=m->timed_lock(absolute_time); + return is_locked; + } + bool timed_lock(::boost::xtime const& absolute_time) + { + is_locked=m->timed_lock(absolute_time); + return is_locked; + } + void unlock() + { + if(!owns_lock()) + { + throw boost::lock_error(); + } + m->unlock(); + is_locked=false; + } + + typedef void (unique_lock::*bool_type)(); + operator bool_type() const + { + return is_locked?&unique_lock::lock:0; + } + bool operator!() const + { + return !owns_lock(); + } + bool owns_lock() const + { + return is_locked; + } + + Mutex* mutex() const + { + return m; + } + + Mutex* release() + { + Mutex* const res=m; + m=0; + is_locked=false; + return res; + } + + friend class shared_lock; + friend class upgrade_lock; + }; + +#ifdef BOOST_HAS_RVALUE_REFS + template + void swap(unique_lock&& lhs,unique_lock&& rhs) + { + lhs.swap(rhs); + } +#else + template + void swap(unique_lock& lhs,unique_lock& rhs) + { + lhs.swap(rhs); + } +#endif + +#ifdef BOOST_HAS_RVALUE_REFS + template + inline unique_lock&& move(unique_lock&& ul) + { + return ul; + } +#endif + + template + class shared_lock + { + protected: + Mutex* m; + bool is_locked; + private: + explicit shared_lock(shared_lock&); + shared_lock& operator=(shared_lock&); + public: + shared_lock(): + m(0),is_locked(false) + {} + + explicit shared_lock(Mutex& m_): + m(&m_),is_locked(false) + { + lock(); + } + shared_lock(Mutex& m_,adopt_lock_t): + m(&m_),is_locked(true) + {} + shared_lock(Mutex& m_,defer_lock_t): + m(&m_),is_locked(false) + {} + shared_lock(Mutex& m_,try_to_lock_t): + m(&m_),is_locked(false) + { + try_lock(); + } + shared_lock(Mutex& m_,system_time const& target_time): + m(&m_),is_locked(false) + { + timed_lock(target_time); + } + + shared_lock(detail::thread_move_t > other): + m(other->m),is_locked(other->is_locked) + { + other->is_locked=false; + other->m=0; + } + + shared_lock(detail::thread_move_t > other): + m(other->m),is_locked(other->is_locked) + { + if(is_locked) + { + m->unlock_and_lock_shared(); + } + other->is_locked=false; + other->m=0; + } + + shared_lock(detail::thread_move_t > other): + m(other->m),is_locked(other->is_locked) + { + if(is_locked) + { + m->unlock_upgrade_and_lock_shared(); + } + other->is_locked=false; + other->m=0; + } + + operator detail::thread_move_t >() + { + return move(); + } + + detail::thread_move_t > move() + { + return detail::thread_move_t >(*this); + } + + + shared_lock& operator=(detail::thread_move_t > other) + { + shared_lock temp(other); + swap(temp); + return *this; + } + + shared_lock& operator=(detail::thread_move_t > other) + { + shared_lock temp(other); + swap(temp); + return *this; + } + + shared_lock& operator=(detail::thread_move_t > other) + { + shared_lock temp(other); + swap(temp); + return *this; + } + +#ifdef BOOST_HAS_RVALUE_REFS + void swap(shared_lock&& other) + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } +#else + void swap(shared_lock& other) + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } + void swap(boost::detail::thread_move_t > other) + { + std::swap(m,other->m); + std::swap(is_locked,other->is_locked); + } +#endif + + Mutex* mutex() const + { + return m; + } + + ~shared_lock() + { + if(owns_lock()) + { + m->unlock_shared(); + } + } + void lock() + { + if(owns_lock()) + { + throw boost::lock_error(); + } + m->lock_shared(); + is_locked=true; + } + bool try_lock() + { + if(owns_lock()) + { + throw boost::lock_error(); + } + is_locked=m->try_lock_shared(); + return is_locked; + } + bool timed_lock(boost::system_time const& target_time) + { + if(owns_lock()) + { + throw boost::lock_error(); + } + is_locked=m->timed_lock_shared(target_time); + return is_locked; + } + template + bool timed_lock(Duration const& target_time) + { + if(owns_lock()) + { + throw boost::lock_error(); + } + is_locked=m->timed_lock_shared(target_time); + return is_locked; + } + void unlock() + { + if(!owns_lock()) + { + throw boost::lock_error(); + } + m->unlock_shared(); + is_locked=false; + } + + typedef void (shared_lock::*bool_type)(); + operator bool_type() const + { + return is_locked?&shared_lock::lock:0; + } + bool operator!() const + { + return !owns_lock(); + } + bool owns_lock() const + { + return is_locked; + } + + }; + +#ifdef BOOST_HAS_RVALUE_REFS + template + void swap(shared_lock&& lhs,shared_lock&& rhs) + { + lhs.swap(rhs); + } +#else + template + void swap(shared_lock& lhs,shared_lock& rhs) + { + lhs.swap(rhs); + } +#endif + + template + class upgrade_lock + { + protected: + Mutex* m; + bool is_locked; + private: + explicit upgrade_lock(upgrade_lock&); + upgrade_lock& operator=(upgrade_lock&); + public: + upgrade_lock(): + m(0),is_locked(false) + {} + + explicit upgrade_lock(Mutex& m_): + m(&m_),is_locked(false) + { + lock(); + } + upgrade_lock(Mutex& m_,adopt_lock_t): + m(&m_),is_locked(true) + {} + upgrade_lock(Mutex& m_,defer_lock_t): + m(&m_),is_locked(false) + {} + upgrade_lock(Mutex& m_,try_to_lock_t): + m(&m_),is_locked(false) + { + try_lock(); + } + upgrade_lock(detail::thread_move_t > other): + m(other->m),is_locked(other->is_locked) + { + other->is_locked=false; + other->m=0; + } + + upgrade_lock(detail::thread_move_t > other): + m(other->m),is_locked(other->is_locked) + { + if(is_locked) + { + m->unlock_and_lock_upgrade(); + } + other->is_locked=false; + other->m=0; + } + + operator detail::thread_move_t >() + { + return move(); + } + + detail::thread_move_t > move() + { + return detail::thread_move_t >(*this); + } + + + upgrade_lock& operator=(detail::thread_move_t > other) + { + upgrade_lock temp(other); + swap(temp); + return *this; + } + + upgrade_lock& operator=(detail::thread_move_t > other) + { + upgrade_lock temp(other); + swap(temp); + return *this; + } + + void swap(upgrade_lock& other) + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } + + ~upgrade_lock() + { + if(owns_lock()) + { + m->unlock_upgrade(); + } + } + void lock() + { + if(owns_lock()) + { + throw boost::lock_error(); + } + m->lock_upgrade(); + is_locked=true; + } + bool try_lock() + { + if(owns_lock()) + { + throw boost::lock_error(); + } + is_locked=m->try_lock_upgrade(); + return is_locked; + } + void unlock() + { + if(!owns_lock()) + { + throw boost::lock_error(); + } + m->unlock_upgrade(); + is_locked=false; + } + + typedef void (upgrade_lock::*bool_type)(); + operator bool_type() const + { + return is_locked?&upgrade_lock::lock:0; + } + bool operator!() const + { + return !owns_lock(); + } + bool owns_lock() const + { + return is_locked; + } + friend class shared_lock; + friend class unique_lock; + }; + + +#ifdef BOOST_HAS_RVALUE_REFS + template + unique_lock::unique_lock(upgrade_lock&& other): + m(other.m),is_locked(other.is_locked) + { + other.is_locked=false; + if(is_locked) + { + m.unlock_upgrade_and_lock(); + } + } +#else + template + unique_lock::unique_lock(detail::thread_move_t > other): + m(other->m),is_locked(other->is_locked) + { + other->is_locked=false; + if(is_locked) + { + m->unlock_upgrade_and_lock(); + } + } +#endif + template + class upgrade_to_unique_lock + { + private: + upgrade_lock* source; + unique_lock exclusive; + + explicit upgrade_to_unique_lock(upgrade_to_unique_lock&); + upgrade_to_unique_lock& operator=(upgrade_to_unique_lock&); + public: + explicit upgrade_to_unique_lock(upgrade_lock& m_): + source(&m_),exclusive(move(*source)) + {} + ~upgrade_to_unique_lock() + { + if(source) + { + *source=move(exclusive); + } + } + + upgrade_to_unique_lock(detail::thread_move_t > other): + source(other->source),exclusive(move(other->exclusive)) + { + other->source=0; + } + + upgrade_to_unique_lock& operator=(detail::thread_move_t > other) + { + upgrade_to_unique_lock temp(other); + swap(temp); + return *this; + } + void swap(upgrade_to_unique_lock& other) + { + std::swap(source,other.source); + exclusive.swap(other.exclusive); + } + typedef void (upgrade_to_unique_lock::*bool_type)(upgrade_to_unique_lock&); + operator bool_type() const + { + return exclusive.owns_lock()?&upgrade_to_unique_lock::swap:0; + } + bool operator!() const + { + return !owns_lock(); + } + bool owns_lock() const + { + return exclusive.owns_lock(); + } + }; + + namespace detail + { + template + class try_lock_wrapper: + private unique_lock + { + typedef unique_lock base; + public: + try_lock_wrapper() + {} + + explicit try_lock_wrapper(Mutex& m): + base(m,try_to_lock) + {} + + try_lock_wrapper(Mutex& m_,adopt_lock_t): + base(m_,adopt_lock) + {} + try_lock_wrapper(Mutex& m_,defer_lock_t): + base(m_,defer_lock) + {} + try_lock_wrapper(Mutex& m_,try_to_lock_t): + base(m_,try_to_lock) + {} + try_lock_wrapper(detail::thread_move_t > other): + base(detail::thread_move_t(*other)) + {} + + operator detail::thread_move_t >() + { + return move(); + } + + detail::thread_move_t > move() + { + return detail::thread_move_t >(*this); + } + + try_lock_wrapper& operator=(detail::thread_move_t > other) + { + try_lock_wrapper temp(other); + swap(temp); + return *this; + } + +#ifdef BOOST_HAS_RVALUE_REFS + void swap(try_lock_wrapper&& other) + { + base::swap(other); + } +#else + void swap(try_lock_wrapper& other) + { + base::swap(other); + } + void swap(detail::thread_move_t > other) + { + base::swap(*other); + } +#endif + + void lock() + { + base::lock(); + } + bool try_lock() + { + return base::try_lock(); + } + void unlock() + { + base::unlock(); + } + bool owns_lock() const + { + return base::owns_lock(); + } + Mutex* mutex() const + { + return base::mutex(); + } + Mutex* release() + { + return base::release(); + } + bool operator!() const + { + return !this->owns_lock(); + } + + typedef typename base::bool_type bool_type; + operator bool_type() const + { + return base::operator bool_type(); + } + }; + +#ifdef BOOST_HAS_RVALUE_REFS + template + void swap(try_lock_wrapper&& lhs,try_lock_wrapper&& rhs) + { + lhs.swap(rhs); + } +#else + template + void swap(try_lock_wrapper& lhs,try_lock_wrapper& rhs) + { + lhs.swap(rhs); + } +#endif + + template + unsigned try_lock_internal(MutexType1& m1,MutexType2& m2) + { + boost::unique_lock l1(m1,boost::try_to_lock); + if(!l1) + { + return 1; + } + if(!m2.try_lock()) + { + return 2; + } + l1.release(); + return 0; + } + + template + unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3) + { + boost::unique_lock l1(m1,boost::try_to_lock); + if(!l1) + { + return 1; + } + if(unsigned const failed_lock=try_lock_internal(m2,m3)) + { + return failed_lock+1; + } + l1.release(); + return 0; + } + + + template + unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4) + { + boost::unique_lock l1(m1,boost::try_to_lock); + if(!l1) + { + return 1; + } + if(unsigned const failed_lock=try_lock_internal(m2,m3,m4)) + { + return failed_lock+1; + } + l1.release(); + return 0; + } + + template + unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4,MutexType5& m5) + { + boost::unique_lock l1(m1,boost::try_to_lock); + if(!l1) + { + return 1; + } + if(unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) + { + return failed_lock+1; + } + l1.release(); + return 0; + } + + + template + unsigned lock_helper(MutexType1& m1,MutexType2& m2) + { + boost::unique_lock l1(m1); + if(!m2.try_lock()) + { + return 1; + } + l1.release(); + return 0; + } + + template + unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3) + { + boost::unique_lock l1(m1); + if(unsigned const failed_lock=try_lock_internal(m2,m3)) + { + return failed_lock; + } + l1.release(); + return 0; + } + + template + unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4) + { + boost::unique_lock l1(m1); + if(unsigned const failed_lock=try_lock_internal(m2,m3,m4)) + { + return failed_lock; + } + l1.release(); + return 0; + } + + template + unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4,MutexType5& m5) + { + boost::unique_lock l1(m1); + if(unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) + { + return failed_lock; + } + l1.release(); + return 0; + } + } + + namespace detail + { + template + struct is_mutex_type_wrapper + {}; + + template + void lock_impl(MutexType1& m1,MutexType2& m2,is_mutex_type_wrapper) + { + unsigned const lock_count=2; + unsigned lock_first=0; + while(true) + { + switch(lock_first) + { + case 0: + lock_first=detail::lock_helper(m1,m2); + if(!lock_first) + return; + break; + case 1: + lock_first=detail::lock_helper(m2,m1); + if(!lock_first) + return; + lock_first=(lock_first+1)%lock_count; + break; + } + } + } + + template + void lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper); + } + + + template + void lock(MutexType1& m1,MutexType2& m2) + { + detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper::value>()); + } + + template + void lock(const MutexType1& m1,MutexType2& m2) + { + detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper::value>()); + } + + template + void lock(MutexType1& m1,const MutexType2& m2) + { + detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper::value>()); + } + + template + void lock(const MutexType1& m1,const MutexType2& m2) + { + detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper::value>()); + } + + template + void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3) + { + unsigned const lock_count=3; + unsigned lock_first=0; + while(true) + { + switch(lock_first) + { + case 0: + lock_first=detail::lock_helper(m1,m2,m3); + if(!lock_first) + return; + break; + case 1: + lock_first=detail::lock_helper(m2,m3,m1); + if(!lock_first) + return; + lock_first=(lock_first+1)%lock_count; + break; + case 2: + lock_first=detail::lock_helper(m3,m1,m2); + if(!lock_first) + return; + lock_first=(lock_first+2)%lock_count; + break; + } + } + } + + template + void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4) + { + unsigned const lock_count=4; + unsigned lock_first=0; + while(true) + { + switch(lock_first) + { + case 0: + lock_first=detail::lock_helper(m1,m2,m3,m4); + if(!lock_first) + return; + break; + case 1: + lock_first=detail::lock_helper(m2,m3,m4,m1); + if(!lock_first) + return; + lock_first=(lock_first+1)%lock_count; + break; + case 2: + lock_first=detail::lock_helper(m3,m4,m1,m2); + if(!lock_first) + return; + lock_first=(lock_first+2)%lock_count; + break; + case 3: + lock_first=detail::lock_helper(m4,m1,m2,m3); + if(!lock_first) + return; + lock_first=(lock_first+3)%lock_count; + break; + } + } + } + + template + void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4,MutexType5& m5) + { + unsigned const lock_count=5; + unsigned lock_first=0; + while(true) + { + switch(lock_first) + { + case 0: + lock_first=detail::lock_helper(m1,m2,m3,m4,m5); + if(!lock_first) + return; + break; + case 1: + lock_first=detail::lock_helper(m2,m3,m4,m5,m1); + if(!lock_first) + return; + lock_first=(lock_first+1)%lock_count; + break; + case 2: + lock_first=detail::lock_helper(m3,m4,m5,m1,m2); + if(!lock_first) + return; + lock_first=(lock_first+2)%lock_count; + break; + case 3: + lock_first=detail::lock_helper(m4,m5,m1,m2,m3); + if(!lock_first) + return; + lock_first=(lock_first+3)%lock_count; + break; + case 4: + lock_first=detail::lock_helper(m5,m1,m2,m3,m4); + if(!lock_first) + return; + lock_first=(lock_first+4)%lock_count; + break; + } + } + } + + namespace detail + { + template::value> + struct try_lock_impl_return + { + typedef int type; + }; + + template + struct try_lock_impl_return + { + typedef Iterator type; + }; + + template + int try_lock_impl(MutexType1& m1,MutexType2& m2,is_mutex_type_wrapper) + { + return ((int)detail::try_lock_internal(m1,m2))-1; + } + + template + Iterator try_lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper); + } + + template + typename detail::try_lock_impl_return::type try_lock(MutexType1& m1,MutexType2& m2) + { + return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper::value>()); + } + + template + typename detail::try_lock_impl_return::type try_lock(const MutexType1& m1,MutexType2& m2) + { + return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper::value>()); + } + + template + typename detail::try_lock_impl_return::type try_lock(MutexType1& m1,const MutexType2& m2) + { + return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper::value>()); + } + + template + typename detail::try_lock_impl_return::type try_lock(const MutexType1& m1,const MutexType2& m2) + { + return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper::value>()); + } + + template + int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3) + { + return ((int)detail::try_lock_internal(m1,m2,m3))-1; + } + + template + int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3,MutexType4& m4) + { + return ((int)detail::try_lock_internal(m1,m2,m3,m4))-1; + } + + template + int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3,MutexType4& m4,MutexType5& m5) + { + return ((int)detail::try_lock_internal(m1,m2,m3,m4,m5))-1; + } + + + namespace detail + { + template + struct range_lock_guard + { + Iterator begin; + Iterator end; + + range_lock_guard(Iterator begin_,Iterator end_): + begin(begin_),end(end_) + { + lock(begin,end); + } + + void release() + { + begin=end; + } + + ~range_lock_guard() + { + for(;begin!=end;++begin) + { + begin->unlock(); + } + } + }; + + template + Iterator try_lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper) + + { + if(begin==end) + { + return end; + } + typedef typename std::iterator_traits::value_type lock_type; + unique_lock guard(*begin,try_to_lock); + + if(!guard.owns_lock()) + { + return begin; + } + Iterator const failed=try_lock(++begin,end); + if(failed==end) + { + guard.release(); + } + + return failed; + } + } + + + namespace detail + { + template + void lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper) + { + typedef typename std::iterator_traits::value_type lock_type; + + if(begin==end) + { + return; + } + bool start_with_begin=true; + Iterator second=begin; + ++second; + Iterator next=second; + + for(;;) + { + unique_lock begin_lock(*begin,defer_lock); + if(start_with_begin) + { + begin_lock.lock(); + Iterator const failed_lock=try_lock(next,end); + if(failed_lock==end) + { + begin_lock.release(); + return; + } + start_with_begin=false; + next=failed_lock; + } + else + { + detail::range_lock_guard guard(next,end); + if(begin_lock.try_lock()) + { + Iterator const failed_lock=try_lock(second,next); + if(failed_lock==next) + { + begin_lock.release(); + guard.release(); + return; + } + start_with_begin=false; + next=failed_lock; + } + else + { + start_with_begin=true; + next=second; + } + } + } + } + + } + +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/mutex.hpp b/deal.II/contrib/boost/include/boost/thread/mutex.hpp new file mode 100644 index 0000000000..4669886c7f --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/mutex.hpp @@ -0,0 +1,21 @@ +#ifndef BOOST_THREAD_MUTEX_HPP +#define BOOST_THREAD_MUTEX_HPP + +// mutex.hpp +// +// (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) + +#include +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include +#else +#error "Boost threads unavailable on this platform" +#endif + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/once.hpp b/deal.II/contrib/boost/include/boost/thread/once.hpp new file mode 100644 index 0000000000..975304e147 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/once.hpp @@ -0,0 +1,33 @@ +#ifndef BOOST_THREAD_ONCE_HPP +#define BOOST_THREAD_ONCE_HPP + +// once.hpp +// +// (C) Copyright 2006-7 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include +#else +#error "Boost threads unavailable on this platform" +#endif + +#include + +namespace boost +{ + inline void call_once(void (*func)(),once_flag& flag) + { + call_once(flag,func); + } +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/pthread/condition_variable.hpp b/deal.II/contrib/boost/include/boost/thread/pthread/condition_variable.hpp new file mode 100644 index 0000000000..8ec6ae7fcf --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/pthread/condition_variable.hpp @@ -0,0 +1,176 @@ +#ifndef BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP +#define BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_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-8 Anthony Williams + +#include "timespec.hpp" +#include "pthread_mutex_scoped_lock.hpp" +#include "thread_data.hpp" +#include "condition_variable_fwd.hpp" + +#include + +namespace boost +{ + inline void condition_variable::wait(unique_lock& m) + { + detail::interruption_checker check_for_interruption(&cond); + BOOST_VERIFY(!pthread_cond_wait(&cond,m.mutex()->native_handle())); + } + + inline bool condition_variable::timed_wait(unique_lock& m,boost::system_time const& wait_until) + { + detail::interruption_checker check_for_interruption(&cond); + struct timespec const timeout=detail::get_timespec(wait_until); + int const cond_res=pthread_cond_timedwait(&cond,m.mutex()->native_handle(),&timeout); + if(cond_res==ETIMEDOUT) + { + return false; + } + BOOST_ASSERT(!cond_res); + return true; + } + + inline void condition_variable::notify_one() + { + BOOST_VERIFY(!pthread_cond_signal(&cond)); + } + + inline void condition_variable::notify_all() + { + BOOST_VERIFY(!pthread_cond_broadcast(&cond)); + } + + class condition_variable_any + { + pthread_mutex_t internal_mutex; + pthread_cond_t cond; + + condition_variable_any(condition_variable&); + condition_variable_any& operator=(condition_variable&); + + public: + condition_variable_any() + { + int const res=pthread_mutex_init(&internal_mutex,NULL); + if(res) + { + throw thread_resource_error(); + } + int const res2=pthread_cond_init(&cond,NULL); + if(res2) + { + BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex)); + throw thread_resource_error(); + } + } + ~condition_variable_any() + { + BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex)); + BOOST_VERIFY(!pthread_cond_destroy(&cond)); + } + + template + void wait(lock_type& m) + { + int res=0; + { + detail::interruption_checker check_for_interruption(&cond); + { + boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); + m.unlock(); + res=pthread_cond_wait(&cond,&internal_mutex); + } + m.lock(); + } + if(res) + { + throw condition_error(); + } + } + + template + void wait(lock_type& m,predicate_type pred) + { + while(!pred()) wait(m); + } + + template + bool timed_wait(lock_type& m,boost::system_time const& wait_until) + { + struct timespec const timeout=detail::get_timespec(wait_until); + int res=0; + { + detail::interruption_checker check_for_interruption(&cond); + { + boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); + m.unlock(); + res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout); + } + m.lock(); + } + if(res==ETIMEDOUT) + { + return false; + } + if(res) + { + throw condition_error(); + } + return true; + } + template + bool timed_wait(lock_type& m,xtime const& wait_until) + { + return timed_wait(m,system_time(wait_until)); + } + + template + bool timed_wait(lock_type& m,duration_type const& wait_duration) + { + return timed_wait(m,get_system_time()+wait_duration); + } + + template + bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred) + { + while (!pred()) + { + if(!timed_wait(m, wait_until)) + return pred(); + } + return true; + } + + template + bool timed_wait(lock_type& m,xtime const& wait_until,predicate_type pred) + { + return timed_wait(m,system_time(wait_until),pred); + } + + template + bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred) + { + return timed_wait(m,get_system_time()+wait_duration,pred); + } + + void notify_one() + { + boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); + BOOST_VERIFY(!pthread_cond_signal(&cond)); + } + + void notify_all() + { + boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); + BOOST_VERIFY(!pthread_cond_broadcast(&cond)); + } + }; + +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/pthread/condition_variable_fwd.hpp b/deal.II/contrib/boost/include/boost/thread/pthread/condition_variable_fwd.hpp new file mode 100644 index 0000000000..4048cdfb2d --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/pthread/condition_variable_fwd.hpp @@ -0,0 +1,97 @@ +#ifndef BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP +#define BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_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-8 Anthony Williams + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost +{ + class condition_variable + { + private: + pthread_cond_t cond; + + condition_variable(condition_variable&); + condition_variable& operator=(condition_variable&); + + public: + condition_variable() + { + int const res=pthread_cond_init(&cond,NULL); + if(res) + { + throw thread_resource_error(); + } + } + ~condition_variable() + { + BOOST_VERIFY(!pthread_cond_destroy(&cond)); + } + + void wait(unique_lock& m); + + template + void wait(unique_lock& m,predicate_type pred) + { + while(!pred()) wait(m); + } + + bool timed_wait(unique_lock& m,boost::system_time const& wait_until); + bool timed_wait(unique_lock& m,xtime const& wait_until) + { + return timed_wait(m,system_time(wait_until)); + } + + template + bool timed_wait(unique_lock& m,duration_type const& wait_duration) + { + return timed_wait(m,get_system_time()+wait_duration); + } + + template + bool timed_wait(unique_lock& m,boost::system_time const& wait_until,predicate_type pred) + { + while (!pred()) + { + if(!timed_wait(m, wait_until)) + return pred(); + } + return true; + } + + template + bool timed_wait(unique_lock& m,xtime const& wait_until,predicate_type pred) + { + return timed_wait(m,system_time(wait_until),pred); + } + + template + bool timed_wait(unique_lock& m,duration_type const& wait_duration,predicate_type pred) + { + return timed_wait(m,get_system_time()+wait_duration,pred); + } + + typedef pthread_cond_t* native_handle_type; + native_handle_type native_handle() + { + return &cond; + } + + void notify_one(); + void notify_all(); + }; +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/pthread/mutex.hpp b/deal.II/contrib/boost/include/boost/thread/pthread/mutex.hpp new file mode 100644 index 0000000000..51d62ae546 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/pthread/mutex.hpp @@ -0,0 +1,210 @@ +#ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP +#define BOOST_THREAD_PTHREAD_MUTEX_HPP +// (C) Copyright 2007-8 Anthony Williams +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include +#include +#include +#include "timespec.hpp" +#include "pthread_mutex_scoped_lock.hpp" + +#ifdef _POSIX_TIMEOUTS +#if _POSIX_TIMEOUTS >= 0 +#define BOOST_PTHREAD_HAS_TIMEDLOCK +#endif +#endif + +#include + +namespace boost +{ + class mutex: + boost::noncopyable + { + private: + pthread_mutex_t m; + public: + mutex() + { + int const res=pthread_mutex_init(&m,NULL); + if(res) + { + throw thread_resource_error(); + } + } + ~mutex() + { + BOOST_VERIFY(!pthread_mutex_destroy(&m)); + } + + void lock() + { + BOOST_VERIFY(!pthread_mutex_lock(&m)); + } + + void unlock() + { + BOOST_VERIFY(!pthread_mutex_unlock(&m)); + } + + bool try_lock() + { + int const res=pthread_mutex_trylock(&m); + BOOST_ASSERT(!res || res==EBUSY); + return !res; + } + + typedef pthread_mutex_t* native_handle_type; + native_handle_type native_handle() + { + return &m; + } + + typedef unique_lock scoped_lock; + typedef detail::try_lock_wrapper scoped_try_lock; + }; + + typedef mutex try_mutex; + + class timed_mutex: + boost::noncopyable + { + private: + pthread_mutex_t m; +#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK + pthread_cond_t cond; + bool is_locked; +#endif + public: + timed_mutex() + { + int const res=pthread_mutex_init(&m,NULL); + if(res) + { + throw thread_resource_error(); + } +#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK + int const res2=pthread_cond_init(&cond,NULL); + if(res2) + { + BOOST_VERIFY(!pthread_mutex_destroy(&m)); + throw thread_resource_error(); + } + is_locked=false; +#endif + } + ~timed_mutex() + { + BOOST_VERIFY(!pthread_mutex_destroy(&m)); +#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK + BOOST_VERIFY(!pthread_cond_destroy(&cond)); +#endif + } + + template + bool timed_lock(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } + bool timed_lock(boost::xtime const & absolute_time) + { + return timed_lock(system_time(absolute_time)); + } + +#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK + void lock() + { + BOOST_VERIFY(!pthread_mutex_lock(&m)); + } + + void unlock() + { + BOOST_VERIFY(!pthread_mutex_unlock(&m)); + } + + bool try_lock() + { + int const res=pthread_mutex_trylock(&m); + BOOST_ASSERT(!res || res==EBUSY); + return !res; + } + bool timed_lock(system_time const & abs_time) + { + struct timespec const timeout=detail::get_timespec(abs_time); + int const res=pthread_mutex_timedlock(&m,&timeout); + BOOST_ASSERT(!res || res==ETIMEDOUT); + return !res; + } + + typedef pthread_mutex_t* native_handle_type; + native_handle_type native_handle() + { + return &m; + } + +#else + void lock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + while(is_locked) + { + BOOST_VERIFY(!pthread_cond_wait(&cond,&m)); + } + is_locked=true; + } + + void unlock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + is_locked=false; + BOOST_VERIFY(!pthread_cond_signal(&cond)); + } + + bool try_lock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(is_locked) + { + return false; + } + is_locked=true; + return true; + } + + bool timed_lock(system_time const & abs_time) + { + struct timespec const timeout=detail::get_timespec(abs_time); + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + while(is_locked) + { + int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout); + if(cond_res==ETIMEDOUT) + { + return false; + } + BOOST_ASSERT(!cond_res); + } + is_locked=true; + return true; + } +#endif + + typedef unique_lock scoped_timed_lock; + typedef detail::try_lock_wrapper scoped_try_lock; + typedef scoped_timed_lock scoped_lock; + }; + +} + +#include + + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/pthread/once.hpp b/deal.II/contrib/boost/include/boost/thread/pthread/once.hpp new file mode 100644 index 0000000000..f278a578f4 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/pthread/once.hpp @@ -0,0 +1,90 @@ +#ifndef BOOST_THREAD_PTHREAD_ONCE_HPP +#define BOOST_THREAD_PTHREAD_ONCE_HPP + +// once.hpp +// +// (C) Copyright 2007-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#include +#include "pthread_mutex_scoped_lock.hpp" +#include +#include + +#include + +namespace boost +{ + + struct once_flag + { + boost::uintmax_t epoch; + }; + + namespace detail + { + BOOST_THREAD_DECL boost::uintmax_t& get_once_per_thread_epoch(); + BOOST_THREAD_DECL extern boost::uintmax_t once_global_epoch; + BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex; + BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv; + } + +#define BOOST_ONCE_INITIAL_FLAG_VALUE 0 +#define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE} + + + // Based on Mike Burrows fast_pthread_once algorithm as described in + // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html + template + void call_once(once_flag& flag,Function f) + { + static boost::uintmax_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static boost::uintmax_t const being_initialized=uninitialized_flag+1; + boost::uintmax_t const epoch=flag.epoch; + boost::uintmax_t& this_thread_epoch=detail::get_once_per_thread_epoch(); + + if(epoch + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp b/deal.II/contrib/boost/include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp new file mode 100644 index 0000000000..2407f915a3 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp @@ -0,0 +1,54 @@ +#ifndef BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP +#define BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP +// (C) Copyright 2007-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +#include + +namespace boost +{ + namespace pthread + { + class pthread_mutex_scoped_lock + { + pthread_mutex_t* m; + public: + explicit pthread_mutex_scoped_lock(pthread_mutex_t* m_): + m(m_) + { + BOOST_VERIFY(!pthread_mutex_lock(m)); + } + ~pthread_mutex_scoped_lock() + { + BOOST_VERIFY(!pthread_mutex_unlock(m)); + } + + }; + + class pthread_mutex_scoped_unlock + { + pthread_mutex_t* m; + public: + explicit pthread_mutex_scoped_unlock(pthread_mutex_t* m_): + m(m_) + { + BOOST_VERIFY(!pthread_mutex_unlock(m)); + } + ~pthread_mutex_scoped_unlock() + { + BOOST_VERIFY(!pthread_mutex_lock(m)); + } + + }; + } +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/pthread/recursive_mutex.hpp b/deal.II/contrib/boost/include/boost/thread/pthread/recursive_mutex.hpp new file mode 100644 index 0000000000..f3f7bf1dda --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/pthread/recursive_mutex.hpp @@ -0,0 +1,266 @@ +#ifndef BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP +#define BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP +// (C) Copyright 2007-8 Anthony Williams +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include +#ifndef _WIN32 +#include +#endif +#include +#include +#include "timespec.hpp" +#include "pthread_mutex_scoped_lock.hpp" + +#ifdef _POSIX_TIMEOUTS +#if _POSIX_TIMEOUTS >= 0 +#define BOOST_PTHREAD_HAS_TIMEDLOCK +#endif +#endif + +#include + +namespace boost +{ + class recursive_mutex: + boost::noncopyable + { + private: + pthread_mutex_t m; + public: + recursive_mutex() + { + pthread_mutexattr_t attr; + + int const init_attr_res=pthread_mutexattr_init(&attr); + if(init_attr_res) + { + throw thread_resource_error(); + } + int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); + if(set_attr_res) + { + throw thread_resource_error(); + } + + int const res=pthread_mutex_init(&m,&attr); + if(res) + { + throw thread_resource_error(); + } + BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); + } + ~recursive_mutex() + { + BOOST_VERIFY(!pthread_mutex_destroy(&m)); + } + + void lock() + { + BOOST_VERIFY(!pthread_mutex_lock(&m)); + } + + void unlock() + { + BOOST_VERIFY(!pthread_mutex_unlock(&m)); + } + + bool try_lock() + { + int const res=pthread_mutex_trylock(&m); + BOOST_ASSERT(!res || res==EBUSY); + return !res; + } + + typedef pthread_mutex_t* native_handle_type; + native_handle_type native_handle() + { + return &m; + } + + typedef unique_lock scoped_lock; + typedef detail::try_lock_wrapper scoped_try_lock; + }; + + typedef recursive_mutex recursive_try_mutex; + + class recursive_timed_mutex: + boost::noncopyable + { + private: + pthread_mutex_t m; +#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK + pthread_cond_t cond; + bool is_locked; + pthread_t owner; + unsigned count; +#endif + public: + recursive_timed_mutex() + { +#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK + pthread_mutexattr_t attr; + + int const init_attr_res=pthread_mutexattr_init(&attr); + if(init_attr_res) + { + throw thread_resource_error(); + } + int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); + if(set_attr_res) + { + throw thread_resource_error(); + } + + int const res=pthread_mutex_init(&m,&attr); + if(res) + { + BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); + throw thread_resource_error(); + } + BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); +#else + int const res=pthread_mutex_init(&m,NULL); + if(res) + { + throw thread_resource_error(); + } + int const res2=pthread_cond_init(&cond,NULL); + if(res2) + { + BOOST_VERIFY(!pthread_mutex_destroy(&m)); + throw thread_resource_error(); + } + is_locked=false; + count=0; +#endif + } + ~recursive_timed_mutex() + { + BOOST_VERIFY(!pthread_mutex_destroy(&m)); +#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK + BOOST_VERIFY(!pthread_cond_destroy(&cond)); +#endif + } + + template + bool timed_lock(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } + +#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK + void lock() + { + BOOST_VERIFY(!pthread_mutex_lock(&m)); + } + + void unlock() + { + BOOST_VERIFY(!pthread_mutex_unlock(&m)); + } + + bool try_lock() + { + int const res=pthread_mutex_trylock(&m); + BOOST_ASSERT(!res || res==EBUSY); + return !res; + } + bool timed_lock(system_time const & abs_time) + { + struct timespec const timeout=detail::get_timespec(abs_time); + int const res=pthread_mutex_timedlock(&m,&timeout); + BOOST_ASSERT(!res || res==ETIMEDOUT); + return !res; + } + + typedef pthread_mutex_t* native_handle_type; + native_handle_type native_handle() + { + return &m; + } + +#else + void lock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(is_locked && pthread_equal(owner,pthread_self())) + { + ++count; + return; + } + + while(is_locked) + { + BOOST_VERIFY(!pthread_cond_wait(&cond,&m)); + } + is_locked=true; + ++count; + owner=pthread_self(); + } + + void unlock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(!--count) + { + is_locked=false; + } + BOOST_VERIFY(!pthread_cond_signal(&cond)); + } + + bool try_lock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(is_locked && !pthread_equal(owner,pthread_self())) + { + return false; + } + is_locked=true; + ++count; + owner=pthread_self(); + return true; + } + + bool timed_lock(system_time const & abs_time) + { + struct timespec const timeout=detail::get_timespec(abs_time); + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(is_locked && pthread_equal(owner,pthread_self())) + { + ++count; + return true; + } + while(is_locked) + { + int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout); + if(cond_res==ETIMEDOUT) + { + return false; + } + BOOST_ASSERT(!cond_res); + } + is_locked=true; + ++count; + owner=pthread_self(); + return true; + } +#endif + + typedef unique_lock scoped_timed_lock; + typedef detail::try_lock_wrapper scoped_try_lock; + typedef scoped_timed_lock scoped_lock; + }; + +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/pthread/shared_mutex.hpp b/deal.II/contrib/boost/include/boost/thread/pthread/shared_mutex.hpp new file mode 100644 index 0000000000..3ce4e23364 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/pthread/shared_mutex.hpp @@ -0,0 +1,303 @@ +#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP +#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP + +// (C) Copyright 2006-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include + +#include + +namespace boost +{ + class shared_mutex + { + private: + struct state_data + { + unsigned shared_count; + bool exclusive; + bool upgrade; + bool exclusive_waiting_blocked; + }; + + + + state_data state; + boost::mutex state_change; + boost::condition_variable shared_cond; + boost::condition_variable exclusive_cond; + boost::condition_variable upgrade_cond; + + void release_waiters() + { + exclusive_cond.notify_one(); + shared_cond.notify_all(); + } + + + public: + shared_mutex() + { + state_data state_={0,0,0,0}; + state=state_; + } + + ~shared_mutex() + { + } + + void lock_shared() + { + boost::this_thread::disable_interruption do_not_disturb; + boost::mutex::scoped_lock lk(state_change); + + while(state.exclusive || state.exclusive_waiting_blocked) + { + shared_cond.wait(lk); + } + ++state.shared_count; + } + + bool try_lock_shared() + { + boost::mutex::scoped_lock lk(state_change); + + if(state.exclusive || state.exclusive_waiting_blocked) + { + return false; + } + else + { + ++state.shared_count; + return true; + } + } + + bool timed_lock_shared(system_time const& timeout) + { + boost::this_thread::disable_interruption do_not_disturb; + boost::mutex::scoped_lock lk(state_change); + + while(state.exclusive || state.exclusive_waiting_blocked) + { + if(!shared_cond.timed_wait(lk,timeout)) + { + return false; + } + } + ++state.shared_count; + return true; + } + + template + bool timed_lock_shared(TimeDuration const & relative_time) + { + return timed_lock_shared(get_system_time()+relative_time); + } + + void unlock_shared() + { + boost::mutex::scoped_lock lk(state_change); + bool const last_reader=!--state.shared_count; + + if(last_reader) + { + if(state.upgrade) + { + state.upgrade=false; + state.exclusive=true; + upgrade_cond.notify_one(); + } + else + { + state.exclusive_waiting_blocked=false; + } + release_waiters(); + } + } + + void lock() + { + boost::this_thread::disable_interruption do_not_disturb; + boost::mutex::scoped_lock lk(state_change); + + while(state.shared_count || state.exclusive) + { + state.exclusive_waiting_blocked=true; + exclusive_cond.wait(lk); + } + state.exclusive=true; + } + + bool timed_lock(system_time const& timeout) + { + boost::this_thread::disable_interruption do_not_disturb; + boost::mutex::scoped_lock lk(state_change); + + while(state.shared_count || state.exclusive) + { + state.exclusive_waiting_blocked=true; + if(!exclusive_cond.timed_wait(lk,timeout)) + { + if(state.shared_count || state.exclusive) + { + state.exclusive_waiting_blocked=false; + exclusive_cond.notify_one(); + return false; + } + break; + } + } + state.exclusive=true; + return true; + } + + template + bool timed_lock(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } + + bool try_lock() + { + boost::mutex::scoped_lock lk(state_change); + + if(state.shared_count || state.exclusive) + { + return false; + } + else + { + state.exclusive=true; + return true; + } + + } + + void unlock() + { + boost::mutex::scoped_lock lk(state_change); + state.exclusive=false; + state.exclusive_waiting_blocked=false; + release_waiters(); + } + + void lock_upgrade() + { + boost::this_thread::disable_interruption do_not_disturb; + boost::mutex::scoped_lock lk(state_change); + while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + { + shared_cond.wait(lk); + } + ++state.shared_count; + state.upgrade=true; + } + + bool timed_lock_upgrade(system_time const& timeout) + { + boost::this_thread::disable_interruption do_not_disturb; + boost::mutex::scoped_lock lk(state_change); + while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + { + if(!shared_cond.timed_wait(lk,timeout)) + { + if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + { + return false; + } + break; + } + } + ++state.shared_count; + state.upgrade=true; + return true; + } + + template + bool timed_lock_upgrade(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } + + bool try_lock_upgrade() + { + boost::mutex::scoped_lock lk(state_change); + if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + { + return false; + } + else + { + ++state.shared_count; + state.upgrade=true; + return true; + } + } + + void unlock_upgrade() + { + boost::mutex::scoped_lock lk(state_change); + state.upgrade=false; + bool const last_reader=!--state.shared_count; + + if(last_reader) + { + state.exclusive_waiting_blocked=false; + release_waiters(); + } + } + + void unlock_upgrade_and_lock() + { + boost::this_thread::disable_interruption do_not_disturb; + boost::mutex::scoped_lock lk(state_change); + --state.shared_count; + while(state.shared_count) + { + upgrade_cond.wait(lk); + } + state.upgrade=false; + state.exclusive=true; + } + + void unlock_and_lock_upgrade() + { + boost::mutex::scoped_lock lk(state_change); + state.exclusive=false; + state.upgrade=true; + ++state.shared_count; + state.exclusive_waiting_blocked=false; + release_waiters(); + } + + void unlock_and_lock_shared() + { + boost::mutex::scoped_lock lk(state_change); + state.exclusive=false; + ++state.shared_count; + state.exclusive_waiting_blocked=false; + release_waiters(); + } + + void unlock_upgrade_and_lock_shared() + { + boost::mutex::scoped_lock lk(state_change); + state.upgrade=false; + state.exclusive_waiting_blocked=false; + release_waiters(); + } + }; +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/pthread/thread_data.hpp b/deal.II/contrib/boost/include/boost/thread/pthread/thread_data.hpp new file mode 100644 index 0000000000..244035b4ae --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/pthread/thread_data.hpp @@ -0,0 +1,118 @@ +#ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP +#define BOOST_THREAD_PTHREAD_THREAD_DATA_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 "condition_variable_fwd.hpp" + +#include + +namespace boost +{ + class thread; + + namespace detail + { + struct thread_exit_callback_node; + struct tss_data_node; + + struct thread_data_base; + typedef boost::shared_ptr thread_data_ptr; + + struct BOOST_THREAD_DECL thread_data_base: + enable_shared_from_this + { + thread_data_ptr self; + pthread_t thread_handle; + boost::mutex data_mutex; + boost::condition_variable done_condition; + boost::mutex sleep_mutex; + boost::condition_variable sleep_condition; + bool done; + bool join_started; + bool joined; + boost::detail::thread_exit_callback_node* thread_exit_callbacks; + boost::detail::tss_data_node* tss_data; + bool interrupt_enabled; + bool interrupt_requested; + pthread_cond_t* current_cond; + + thread_data_base(): + done(false),join_started(false),joined(false), + thread_exit_callbacks(0),tss_data(0), + interrupt_enabled(true), + interrupt_requested(false), + current_cond(0) + {} + virtual ~thread_data_base(); + + typedef pthread_t native_handle_type; + + virtual void run()=0; + }; + + BOOST_THREAD_DECL thread_data_base* get_current_thread_data(); + + class interruption_checker + { + thread_data_base* const thread_info; + + void check_for_interruption() + { + if(thread_info->interrupt_requested) + { + thread_info->interrupt_requested=false; + throw thread_interrupted(); + } + } + + void operator=(interruption_checker&); + public: + explicit interruption_checker(pthread_cond_t* cond): + thread_info(detail::get_current_thread_data()) + { + if(thread_info && thread_info->interrupt_enabled) + { + lock_guard guard(thread_info->data_mutex); + check_for_interruption(); + thread_info->current_cond=cond; + } + } + ~interruption_checker() + { + if(thread_info && thread_info->interrupt_enabled) + { + lock_guard guard(thread_info->data_mutex); + thread_info->current_cond=NULL; + check_for_interruption(); + } + } + }; + } + + namespace this_thread + { + void BOOST_THREAD_DECL yield(); + + void BOOST_THREAD_DECL sleep(system_time const& abs_time); + + template + inline void sleep(TimeDuration const& rel_time) + { + this_thread::sleep(get_system_time()+rel_time); + } + } +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/pthread/thread_heap_alloc.hpp b/deal.II/contrib/boost/include/boost/thread/pthread/thread_heap_alloc.hpp new file mode 100644 index 0000000000..7cc0aa0476 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/pthread/thread_heap_alloc.hpp @@ -0,0 +1,242 @@ +// 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 2008 Anthony Williams +#ifndef THREAD_HEAP_ALLOC_PTHREAD_HPP +#define THREAD_HEAP_ALLOC_PTHREAD_HPP + +#include + +namespace boost +{ + namespace detail + { + template + inline T* heap_new() + { + return new T(); + } + +#ifdef BOOST_HAS_RVALUE_REFS + template + inline T* heap_new(A1&& a1) + { + return new T(static_cast(a1)); + } + template + inline T* heap_new(A1&& a1,A2&& a2) + { + return new T(static_cast(a1),static_cast(a2)); + } + template + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3) + { + return new T(static_cast(a1),static_cast(a2), + static_cast(a3)); + } + template + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4) + { + return new T(static_cast(a1),static_cast(a2), + static_cast(a3),static_cast(a4)); + } +#else + template + inline T* heap_new_impl(A1 a1) + { + return new T(a1); + } + template + inline T* heap_new_impl(A1 a1,A2 a2) + { + return new T(a1,a2); + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3) + { + return new T(a1,a2,a3); + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4) + { + return new T(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1) + { + return heap_new_impl(a1); + } + template + inline T* heap_new(A1& a1) + { + return heap_new_impl(a1); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1& a1,A2 const& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1 const& a1,A2& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1& a1,A2& a2) + { + return heap_new_impl(a1,a2); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + +#endif + template + inline void heap_delete(T* data) + { + delete data; + } + + template + struct do_heap_delete + { + void operator()(T* data) const + { + detail::heap_delete(data); + } + }; + } +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/pthread/timespec.hpp b/deal.II/contrib/boost/include/boost/thread/pthread/timespec.hpp new file mode 100644 index 0000000000..d7465c1ac3 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/pthread/timespec.hpp @@ -0,0 +1,36 @@ +#ifndef BOOST_THREAD_PTHREAD_TIMESPEC_HPP +#define BOOST_THREAD_PTHREAD_TIMESPEC_HPP +// (C) Copyright 2007-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#ifndef _WIN32 +#include +#endif + +#include + +namespace boost +{ + namespace detail + { + inline struct timespec get_timespec(boost::system_time const& abs_time) + { + struct timespec timeout={0,0}; + boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0); + + timeout.tv_sec=time_since_epoch.total_seconds(); + timeout.tv_nsec=(long)(time_since_epoch.fractional_seconds()*(1000000000l/time_since_epoch.ticks_per_second())); + return timeout; + } + } +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/recursive_mutex.hpp b/deal.II/contrib/boost/include/boost/thread/recursive_mutex.hpp new file mode 100644 index 0000000000..d5f6116e72 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/recursive_mutex.hpp @@ -0,0 +1,21 @@ +#ifndef BOOST_THREAD_RECURSIVE_MUTEX_HPP +#define BOOST_THREAD_RECURSIVE_MUTEX_HPP + +// recursive_mutex.hpp +// +// (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) + +#include +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include +#else +#error "Boost threads unavailable on this platform" +#endif + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/shared_mutex.hpp b/deal.II/contrib/boost/include/boost/thread/shared_mutex.hpp new file mode 100644 index 0000000000..51eda0de0b --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/shared_mutex.hpp @@ -0,0 +1,21 @@ +#ifndef BOOST_THREAD_SHARED_MUTEX_HPP +#define BOOST_THREAD_SHARED_MUTEX_HPP + +// shared_mutex.hpp +// +// (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) + +#include +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include +#else +#error "Boost threads unavailable on this platform" +#endif + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/thread.hpp b/deal.II/contrib/boost/include/boost/thread/thread.hpp new file mode 100644 index 0000000000..6146132b77 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/thread.hpp @@ -0,0 +1,25 @@ +#ifndef BOOST_THREAD_THREAD_HPP +#define BOOST_THREAD_THREAD_HPP + +// thread.hpp +// +// (C) Copyright 2007-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include +#else +#error "Boost threads unavailable on this platform" +#endif + +#include + + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/thread_time.hpp b/deal.II/contrib/boost/include/boost/thread/thread_time.hpp new file mode 100644 index 0000000000..8b557d5c38 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/thread_time.hpp @@ -0,0 +1,50 @@ +#ifndef BOOST_THREAD_TIME_HPP +#define BOOST_THREAD_TIME_HPP +// (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) + +#include +#include + +#include + +namespace boost +{ + typedef boost::posix_time::ptime system_time; + + inline system_time get_system_time() + { + return boost::date_time::microsec_clock::universal_time(); + } + + namespace detail + { + inline system_time get_system_time_sentinel() + { + return system_time(boost::posix_time::pos_infin); + } + + inline unsigned long get_milliseconds_until(system_time const& target_time) + { + if(target_time.is_pos_infinity()) + { + return ~(unsigned long)0; + } + system_time const now=get_system_time(); + if(target_time<=now) + { + return 0; + } + return static_cast((target_time-now).total_milliseconds()+1); + } + + } + +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/tss.hpp b/deal.II/contrib/boost/include/boost/thread/tss.hpp new file mode 100644 index 0000000000..76380aa66b --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/tss.hpp @@ -0,0 +1,111 @@ +#ifndef BOOST_THREAD_TSS_HPP +#define BOOST_THREAD_TSS_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-8 Anthony Williams + +#include +#include +#include + +#include + +namespace boost +{ + namespace detail + { + struct tss_cleanup_function + { + virtual ~tss_cleanup_function() + {} + + virtual void operator()(void* data)=0; + }; + + BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr func,void* tss_data,bool cleanup_existing); + BOOST_THREAD_DECL void* get_tss_data(void const* key); + } + + template + class thread_specific_ptr + { + private: + thread_specific_ptr(thread_specific_ptr&); + thread_specific_ptr& operator=(thread_specific_ptr&); + + struct delete_data: + detail::tss_cleanup_function + { + void operator()(void* data) + { + delete static_cast(data); + } + }; + + struct run_custom_cleanup_function: + detail::tss_cleanup_function + { + void (*cleanup_function)(T*); + + explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)): + cleanup_function(cleanup_function_) + {} + + void operator()(void* data) + { + cleanup_function(static_cast(data)); + } + }; + + + boost::shared_ptr cleanup; + + public: + thread_specific_ptr(): + cleanup(detail::heap_new(),detail::do_heap_delete()) + {} + explicit thread_specific_ptr(void (*func_)(T*)) + { + if(func_) + { + cleanup.reset(detail::heap_new(func_),detail::do_heap_delete()); + } + } + ~thread_specific_ptr() + { + reset(); + } + + T* get() const + { + return static_cast(detail::get_tss_data(this)); + } + T* operator->() const + { + return get(); + } + T& operator*() const + { + return *get(); + } + T* release() + { + T* const temp=get(); + detail::set_tss_data(this,boost::shared_ptr(),0,false); + return temp; + } + void reset(T* new_value=0) + { + T* const current_value=get(); + if(current_value!=new_value) + { + detail::set_tss_data(this,cleanup,new_value,true); + } + } + }; +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/win32/basic_recursive_mutex.hpp b/deal.II/contrib/boost/include/boost/thread/win32/basic_recursive_mutex.hpp new file mode 100644 index 0000000000..05eb8d7630 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/win32/basic_recursive_mutex.hpp @@ -0,0 +1,120 @@ +#ifndef BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP +#define BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP + +// basic_recursive_mutex.hpp +// +// (C) Copyright 2006-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "thread_primitives.hpp" +#include "basic_timed_mutex.hpp" + +#include + +namespace boost +{ + namespace detail + { + template + struct basic_recursive_mutex_impl + { + long recursion_count; + long locking_thread_id; + underlying_mutex_type mutex; + + void initialize() + { + recursion_count=0; + locking_thread_id=0; + mutex.initialize(); + } + + void destroy() + { + mutex.destroy(); + } + + bool try_lock() + { + long const current_thread_id=win32::GetCurrentThreadId(); + return try_recursive_lock(current_thread_id) || try_basic_lock(current_thread_id); + } + + void lock() + { + long const current_thread_id=win32::GetCurrentThreadId(); + if(!try_recursive_lock(current_thread_id)) + { + mutex.lock(); + BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id); + recursion_count=1; + } + } + bool timed_lock(::boost::system_time const& target) + { + long const current_thread_id=win32::GetCurrentThreadId(); + return try_recursive_lock(current_thread_id) || try_timed_lock(current_thread_id,target); + } + template + bool timed_lock(Duration const& timeout) + { + return timed_lock(get_system_time()+timeout); + } + + void unlock() + { + if(!--recursion_count) + { + BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,0); + mutex.unlock(); + } + } + + private: + bool try_recursive_lock(long current_thread_id) + { + if(::boost::detail::interlocked_read_acquire(&locking_thread_id)==current_thread_id) + { + ++recursion_count; + return true; + } + return false; + } + + bool try_basic_lock(long current_thread_id) + { + if(mutex.try_lock()) + { + BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id); + recursion_count=1; + return true; + } + return false; + } + + bool try_timed_lock(long current_thread_id,::boost::system_time const& target) + { + if(mutex.timed_lock(target)) + { + BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id); + recursion_count=1; + return true; + } + return false; + } + + }; + + typedef basic_recursive_mutex_impl basic_recursive_mutex; + typedef basic_recursive_mutex_impl basic_recursive_timed_mutex; + } +} + +#define BOOST_BASIC_RECURSIVE_MUTEX_INITIALIZER {0} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/win32/basic_timed_mutex.hpp b/deal.II/contrib/boost/include/boost/thread/win32/basic_timed_mutex.hpp new file mode 100644 index 0000000000..751bdbdacc --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/win32/basic_timed_mutex.hpp @@ -0,0 +1,178 @@ +#ifndef BOOST_BASIC_TIMED_MUTEX_WIN32_HPP +#define BOOST_BASIC_TIMED_MUTEX_WIN32_HPP + +// basic_timed_mutex_win32.hpp +// +// (C) Copyright 2006-8 Anthony Williams +// +// 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 "thread_primitives.hpp" +#include "interlocked_read.hpp" +#include +#include +#include + +#include + +namespace boost +{ + namespace detail + { + struct basic_timed_mutex + { + BOOST_STATIC_CONSTANT(unsigned char,lock_flag_bit=31); + BOOST_STATIC_CONSTANT(unsigned char,event_set_flag_bit=30); + BOOST_STATIC_CONSTANT(long,lock_flag_value=1< + bool timed_lock(Duration const& timeout) + { + return timed_lock(get_system_time()+timeout); + } + + bool timed_lock(boost::xtime const& timeout) + { + return timed_lock(system_time(timeout)); + } + + void unlock() + { + long const offset=lock_flag_value; + long const old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,lock_flag_value); + if(!(old_count&event_set_flag_value) && (old_count>offset)) + { + if(!win32::interlocked_bit_test_and_set(&active_count,event_set_flag_bit)) + { + win32::SetEvent(get_event()); + } + } + } + + private: + void* get_event() + { + void* current_event=::boost::detail::interlocked_read_acquire(&event); + + if(!current_event) + { + void* const new_event=win32::create_anonymous_event(win32::auto_reset_event,win32::event_initially_reset); +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4311) +#pragma warning(disable:4312) +#endif + void* const old_event=BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&event,new_event,0); +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + if(old_event!=0) + { + win32::CloseHandle(new_event); + return old_event; + } + else + { + return new_event; + } + } + return current_event; + } + + }; + + } +} + +#define BOOST_BASIC_TIMED_MUTEX_INITIALIZER {0} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/win32/condition_variable.hpp b/deal.II/contrib/boost/include/boost/thread/win32/condition_variable.hpp new file mode 100644 index 0000000000..6e676b49ae --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/win32/condition_variable.hpp @@ -0,0 +1,418 @@ +#ifndef BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP +#define BOOST_THREAD_CONDITION_VARIABLE_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-8 Anthony Williams + +#include +#include "thread_primitives.hpp" +#include +#include +#include +#include +#include +#include "interlocked_read.hpp" +#include +#include +#include + +#include + +namespace boost +{ + namespace detail + { + class basic_cv_list_entry; + void intrusive_ptr_add_ref(basic_cv_list_entry * p); + void intrusive_ptr_release(basic_cv_list_entry * p); + + class basic_cv_list_entry + { + private: + detail::win32::handle_manager semaphore; + detail::win32::handle_manager wake_sem; + long waiters; + bool notified; + long references; + + basic_cv_list_entry(basic_cv_list_entry&); + void operator=(basic_cv_list_entry&); + + public: + explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_): + semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)), + wake_sem(wake_sem_.duplicate()), + waiters(1),notified(false),references(0) + {} + + static bool no_waiters(boost::intrusive_ptr const& entry) + { + return !detail::interlocked_read_acquire(&entry->waiters); + } + + void add_waiter() + { + BOOST_INTERLOCKED_INCREMENT(&waiters); + } + + void remove_waiter() + { + BOOST_INTERLOCKED_DECREMENT(&waiters); + } + + void release(unsigned count_to_release) + { + notified=true; + detail::win32::ReleaseSemaphore(semaphore,count_to_release,0); + } + + void release_waiters() + { + release(detail::interlocked_read_acquire(&waiters)); + } + + bool is_notified() const + { + return notified; + } + + bool wait(timeout wait_until) + { + return this_thread::interruptible_wait(semaphore,wait_until); + } + + bool woken() + { + unsigned long const woken_result=detail::win32::WaitForSingleObject(wake_sem,0); + BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0)); + return woken_result==0; + } + + friend void intrusive_ptr_add_ref(basic_cv_list_entry * p); + friend void intrusive_ptr_release(basic_cv_list_entry * p); + }; + + inline void intrusive_ptr_add_ref(basic_cv_list_entry * p) + { + BOOST_INTERLOCKED_INCREMENT(&p->references); + } + + inline void intrusive_ptr_release(basic_cv_list_entry * p) + { + if(!BOOST_INTERLOCKED_DECREMENT(&p->references)) + { + delete p; + } + } + + class basic_condition_variable + { + boost::mutex internal_mutex; + long total_count; + unsigned active_generation_count; + + typedef basic_cv_list_entry list_entry; + + typedef boost::intrusive_ptr entry_ptr; + typedef std::vector generation_list; + + generation_list generations; + detail::win32::handle_manager wake_sem; + + void wake_waiters(long count_to_wake) + { + detail::interlocked_write_release(&total_count,total_count-count_to_wake); + detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0); + } + + template + struct relocker + { + lock_type& lock; + bool unlocked; + + relocker(lock_type& lock_): + lock(lock_),unlocked(false) + {} + void unlock() + { + lock.unlock(); + unlocked=true; + } + ~relocker() + { + if(unlocked) + { + lock.lock(); + } + + } + private: + relocker(relocker&); + void operator=(relocker&); + }; + + + entry_ptr get_wait_entry() + { + boost::lock_guard internal_lock(internal_mutex); + + if(!wake_sem) + { + wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); + BOOST_ASSERT(wake_sem); + } + + detail::interlocked_write_release(&total_count,total_count+1); + if(generations.empty() || generations.back()->is_notified()) + { + entry_ptr new_entry(new list_entry(wake_sem)); + generations.push_back(new_entry); + return new_entry; + } + else + { + generations.back()->add_waiter(); + return generations.back(); + } + } + + struct entry_manager + { + entry_ptr const entry; + + entry_manager(entry_ptr const& entry_): + entry(entry_) + {} + + ~entry_manager() + { + entry->remove_waiter(); + } + + list_entry* operator->() + { + return entry.get(); + } + + private: + void operator=(entry_manager&); + entry_manager(entry_manager&); + }; + + + protected: + template + bool do_wait(lock_type& lock,timeout wait_until) + { + relocker locker(lock); + + entry_manager entry(get_wait_entry()); + + locker.unlock(); + + bool woken=false; + while(!woken) + { + if(!entry->wait(wait_until)) + { + return false; + } + + woken=entry->woken(); + } + return woken; + } + + template + bool do_wait(lock_type& m,timeout const& wait_until,predicate_type pred) + { + while (!pred()) + { + if(!do_wait(m, wait_until)) + return pred(); + } + return true; + } + + basic_condition_variable(const basic_condition_variable& other); + basic_condition_variable& operator=(const basic_condition_variable& other); + + public: + basic_condition_variable(): + total_count(0),active_generation_count(0),wake_sem(0) + {} + + ~basic_condition_variable() + {} + + void notify_one() + { + if(detail::interlocked_read_acquire(&total_count)) + { + boost::lock_guard internal_lock(internal_mutex); + if(!total_count) + { + return; + } + wake_waiters(1); + + for(generation_list::iterator it=generations.begin(), + end=generations.end(); + it!=end;++it) + { + (*it)->release(1); + } + generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end()); + } + } + + void notify_all() + { + if(detail::interlocked_read_acquire(&total_count)) + { + boost::lock_guard internal_lock(internal_mutex); + if(!total_count) + { + return; + } + wake_waiters(total_count); + for(generation_list::iterator it=generations.begin(), + end=generations.end(); + it!=end;++it) + { + (*it)->release_waiters(); + } + generations.clear(); + wake_sem=detail::win32::handle(0); + } + } + + }; + } + + class condition_variable: + private detail::basic_condition_variable + { + private: + condition_variable(condition_variable&); + void operator=(condition_variable&); + public: + condition_variable() + {} + + using detail::basic_condition_variable::notify_one; + using detail::basic_condition_variable::notify_all; + + void wait(unique_lock& m) + { + do_wait(m,detail::timeout::sentinel()); + } + + template + void wait(unique_lock& m,predicate_type pred) + { + while(!pred()) wait(m); + } + + + bool timed_wait(unique_lock& m,boost::system_time const& wait_until) + { + return do_wait(m,wait_until); + } + + bool timed_wait(unique_lock& m,boost::xtime const& wait_until) + { + return do_wait(m,system_time(wait_until)); + } + template + bool timed_wait(unique_lock& m,duration_type const& wait_duration) + { + return do_wait(m,wait_duration.total_milliseconds()); + } + + template + bool timed_wait(unique_lock& m,boost::system_time const& wait_until,predicate_type pred) + { + return do_wait(m,wait_until,pred); + } + template + bool timed_wait(unique_lock& m,boost::xtime const& wait_until,predicate_type pred) + { + return do_wait(m,system_time(wait_until),pred); + } + template + bool timed_wait(unique_lock& m,duration_type const& wait_duration,predicate_type pred) + { + return do_wait(m,wait_duration.total_milliseconds(),pred); + } + }; + + class condition_variable_any: + private detail::basic_condition_variable + { + private: + condition_variable_any(condition_variable_any&); + void operator=(condition_variable_any&); + public: + condition_variable_any() + {} + + using detail::basic_condition_variable::notify_one; + using detail::basic_condition_variable::notify_all; + + template + void wait(lock_type& m) + { + do_wait(m,detail::timeout::sentinel()); + } + + template + void wait(lock_type& m,predicate_type pred) + { + while(!pred()) wait(m); + } + + template + bool timed_wait(lock_type& m,boost::system_time const& wait_until) + { + return do_wait(m,wait_until); + } + + template + bool timed_wait(lock_type& m,boost::xtime const& wait_until) + { + return do_wait(m,system_time(wait_until)); + } + + template + bool timed_wait(lock_type& m,duration_type const& wait_duration) + { + return do_wait(m,wait_duration.total_milliseconds()); + } + + template + bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred) + { + return do_wait(m,wait_until,pred); + } + + template + bool timed_wait(lock_type& m,boost::xtime const& wait_until,predicate_type pred) + { + return do_wait(m,system_time(wait_until),pred); + } + + template + bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred) + { + return do_wait(m,wait_duration.total_milliseconds(),pred); + } + }; + +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/win32/interlocked_read.hpp b/deal.II/contrib/boost/include/boost/thread/win32/interlocked_read.hpp new file mode 100644 index 0000000000..133fb6f975 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/win32/interlocked_read.hpp @@ -0,0 +1,80 @@ +#ifndef BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP +#define BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP + +// interlocked_read_win32.hpp +// +// (C) Copyright 2005-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include + +#ifdef BOOST_MSVC + +extern "C" void _ReadWriteBarrier(void); +#pragma intrinsic(_ReadWriteBarrier) + +namespace boost +{ + namespace detail + { + inline long interlocked_read_acquire(long volatile* x) + { + long const res=*x; + _ReadWriteBarrier(); + return res; + } + inline void* interlocked_read_acquire(void* volatile* x) + { + void* const res=*x; + _ReadWriteBarrier(); + return res; + } + + inline void interlocked_write_release(long volatile* x,long value) + { + _ReadWriteBarrier(); + *x=value; + } + inline void interlocked_write_release(void* volatile* x,void* value) + { + _ReadWriteBarrier(); + *x=value; + } + } +} + +#else + +namespace boost +{ + namespace detail + { + inline long interlocked_read_acquire(long volatile* x) + { + return BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,0,0); + } + inline void* interlocked_read_acquire(void* volatile* x) + { + return BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(x,0,0); + } + inline void interlocked_write_release(long volatile* x,long value) + { + BOOST_INTERLOCKED_EXCHANGE(x,value); + } + inline void interlocked_write_release(void* volatile* x,void* value) + { + BOOST_INTERLOCKED_EXCHANGE_POINTER(x,value); + } + } +} + +#endif + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/win32/mutex.hpp b/deal.II/contrib/boost/include/boost/thread/win32/mutex.hpp new file mode 100644 index 0000000000..efe6241d40 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/win32/mutex.hpp @@ -0,0 +1,65 @@ +#ifndef BOOST_THREAD_WIN32_MUTEX_HPP +#define BOOST_THREAD_WIN32_MUTEX_HPP +// (C) Copyright 2005-7 Anthony Williams +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "basic_timed_mutex.hpp" +#include +#include +#include + +#include + +namespace boost +{ + namespace detail + { + typedef ::boost::detail::basic_timed_mutex underlying_mutex; + } + + class mutex: + boost::noncopyable, + public ::boost::detail::underlying_mutex + { + public: + mutex() + { + initialize(); + } + ~mutex() + { + destroy(); + } + + typedef unique_lock scoped_lock; + typedef detail::try_lock_wrapper scoped_try_lock; + }; + + typedef mutex try_mutex; + + class timed_mutex: + boost::noncopyable, + public ::boost::detail::basic_timed_mutex + { + public: + timed_mutex() + { + initialize(); + } + + ~timed_mutex() + { + destroy(); + } + + typedef unique_lock scoped_timed_lock; + typedef detail::try_lock_wrapper scoped_try_lock; + typedef scoped_timed_lock scoped_lock; + }; +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/win32/once.hpp b/deal.II/contrib/boost/include/boost/thread/win32/once.hpp new file mode 100644 index 0000000000..a6fcc94dc8 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/win32/once.hpp @@ -0,0 +1,136 @@ +#ifndef BOOST_THREAD_WIN32_ONCE_HPP +#define BOOST_THREAD_WIN32_ONCE_HPP + +// once.hpp +// +// (C) Copyright 2005-7 Anthony Williams +// (C) Copyright 2005 John Maddock +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std +{ + using ::memcpy; + using ::ptrdiff_t; +} +#endif + +namespace boost +{ + typedef long once_flag; + +#define BOOST_ONCE_INIT 0 + + namespace detail + { + struct win32_mutex_scoped_lock + { + void* const mutex_handle; + explicit win32_mutex_scoped_lock(void* mutex_handle_): + mutex_handle(mutex_handle_) + { + BOOST_VERIFY(!win32::WaitForSingleObject(mutex_handle,win32::infinite)); + } + ~win32_mutex_scoped_lock() + { + BOOST_VERIFY(win32::ReleaseMutex(mutex_handle)!=0); + } + private: + void operator=(win32_mutex_scoped_lock&); + }; + +#ifdef BOOST_NO_ANSI_APIS + template + void int_to_string(I p, wchar_t* buf) + { + for(unsigned i=0; i < sizeof(I)*2; ++i,++buf) + { + *buf = L'A' + static_cast((p >> (i*4)) & 0x0f); + } + *buf = 0; + } +#else + template + void int_to_string(I p, char* buf) + { + for(unsigned i=0; i < sizeof(I)*2; ++i,++buf) + { + *buf = 'A' + static_cast((p >> (i*4)) & 0x0f); + } + *buf = 0; + } +#endif + + // create a named mutex. It doesn't really matter what this name is + // as long as it is unique both to this process, and to the address of "flag": + inline void* create_once_mutex(void* flag_address) + { + +#ifdef BOOST_NO_ANSI_APIS + typedef wchar_t char_type; + static const char_type fixed_mutex_name[]=L"{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag"; +#else + typedef char char_type; + static const char_type fixed_mutex_name[]="{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag"; +#endif + unsigned const once_mutex_name_fixed_buffer_size=sizeof(fixed_mutex_name)/sizeof(char_type); + unsigned const once_mutex_name_fixed_length=once_mutex_name_fixed_buffer_size-1; + unsigned const once_mutex_name_length=once_mutex_name_fixed_buffer_size+sizeof(void*)*2+sizeof(unsigned long)*2; + char_type mutex_name[once_mutex_name_length]; + + std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name)); + + BOOST_STATIC_ASSERT(sizeof(void*) == sizeof(std::ptrdiff_t)); + detail::int_to_string(reinterpret_cast(flag_address), mutex_name + once_mutex_name_fixed_length); + detail::int_to_string(win32::GetCurrentProcessId(), mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2); + +#ifdef BOOST_NO_ANSI_APIS + return win32::CreateMutexW(0, 0, mutex_name); +#else + return win32::CreateMutexA(0, 0, mutex_name); +#endif + } + + + } + + + template + void call_once(once_flag& flag,Function f) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + long const function_complete_flag_value=0xc15730e2; + + if(::boost::detail::interlocked_read_acquire(&flag)!=function_complete_flag_value) + { + void* const mutex_handle(::boost::detail::create_once_mutex(&flag)); + BOOST_ASSERT(mutex_handle); + detail::win32::handle_manager const closer(mutex_handle); + detail::win32_mutex_scoped_lock const lock(mutex_handle); + + if(flag!=function_complete_flag_value) + { + f(); + BOOST_INTERLOCKED_EXCHANGE(&flag,function_complete_flag_value); + } + } + } +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/win32/recursive_mutex.hpp b/deal.II/contrib/boost/include/boost/thread/win32/recursive_mutex.hpp new file mode 100644 index 0000000000..2360a92ba4 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/win32/recursive_mutex.hpp @@ -0,0 +1,64 @@ +#ifndef BOOST_RECURSIVE_MUTEX_WIN32_HPP +#define BOOST_RECURSIVE_MUTEX_WIN32_HPP + +// recursive_mutex.hpp +// +// (C) Copyright 2006-7 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#include +#include "basic_recursive_mutex.hpp" +#include +#include + +#include + +namespace boost +{ + class recursive_mutex: + boost::noncopyable, + public ::boost::detail::basic_recursive_mutex + { + public: + recursive_mutex() + { + ::boost::detail::basic_recursive_mutex::initialize(); + } + ~recursive_mutex() + { + ::boost::detail::basic_recursive_mutex::destroy(); + } + + typedef unique_lock scoped_lock; + typedef detail::try_lock_wrapper scoped_try_lock; + }; + + typedef recursive_mutex recursive_try_mutex; + + class recursive_timed_mutex: + boost::noncopyable, + public ::boost::detail::basic_recursive_timed_mutex + { + public: + recursive_timed_mutex() + { + ::boost::detail::basic_recursive_timed_mutex::initialize(); + } + ~recursive_timed_mutex() + { + ::boost::detail::basic_recursive_timed_mutex::destroy(); + } + + typedef unique_lock scoped_timed_lock; + typedef detail::try_lock_wrapper scoped_try_lock; + typedef scoped_timed_lock scoped_lock; + }; +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/win32/shared_mutex.hpp b/deal.II/contrib/boost/include/boost/thread/win32/shared_mutex.hpp new file mode 100644 index 0000000000..58e8093a8b --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/win32/shared_mutex.hpp @@ -0,0 +1,566 @@ +#ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP +#define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP + +// (C) Copyright 2006-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost +{ + class shared_mutex: + private boost::noncopyable + { + private: + struct state_data + { + unsigned shared_count:11, + shared_waiting:11, + exclusive:1, + upgrade:1, + exclusive_waiting:7, + exclusive_waiting_blocked:1; + + friend bool operator==(state_data const& lhs,state_data const& rhs) + { + return *reinterpret_cast(&lhs)==*reinterpret_cast(&rhs); + } + }; + + + template + T interlocked_compare_exchange(T* target,T new_value,T comparand) + { + BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long)); + long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast(target), + *reinterpret_cast(&new_value), + *reinterpret_cast(&comparand)); + return *reinterpret_cast(&res); + } + + state_data state; + detail::win32::handle semaphores[2]; + detail::win32::handle &unlock_sem; + detail::win32::handle &exclusive_sem; + detail::win32::handle upgrade_sem; + + void release_waiters(state_data old_state) + { + if(old_state.exclusive_waiting) + { + BOOST_VERIFY(detail::win32::ReleaseSemaphore(exclusive_sem,1,0)!=0); + } + + if(old_state.shared_waiting || old_state.exclusive_waiting) + { + BOOST_VERIFY(detail::win32::ReleaseSemaphore(unlock_sem,old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0); + } + } + + + public: + shared_mutex(): + unlock_sem(semaphores[0]), + exclusive_sem(semaphores[1]) + { + unlock_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); + exclusive_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); + upgrade_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); + state_data state_={0}; + state=state_; + } + + ~shared_mutex() + { + detail::win32::CloseHandle(upgrade_sem); + detail::win32::CloseHandle(unlock_sem); + detail::win32::CloseHandle(exclusive_sem); + } + + bool try_lock_shared() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(!new_state.exclusive && !new_state.exclusive_waiting_blocked) + { + ++new_state.shared_count; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + return !(old_state.exclusive| old_state.exclusive_waiting_blocked); + } + + void lock_shared() + { + BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel())); + } + + template + bool timed_lock_shared(TimeDuration const & relative_time) + { + return timed_lock_shared(get_system_time()+relative_time); + } + + bool timed_lock_shared(boost::system_time const& wait_until) + { + for(;;) + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(new_state.exclusive || new_state.exclusive_waiting_blocked) + { + ++new_state.shared_waiting; + } + else + { + ++new_state.shared_count; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + + if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) + { + return true; + } + + unsigned long const res=detail::win32::WaitForSingleObject(unlock_sem,::boost::detail::get_milliseconds_until(wait_until)); + if(res==detail::win32::timeout) + { + for(;;) + { + state_data new_state=old_state; + if(new_state.exclusive || new_state.exclusive_waiting_blocked) + { + if(new_state.shared_waiting) + { + --new_state.shared_waiting; + } + } + else + { + ++new_state.shared_count; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + + if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) + { + return true; + } + return false; + } + + BOOST_ASSERT(res==0); + } + } + + void unlock_shared() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + bool const last_reader=!--new_state.shared_count; + + if(last_reader) + { + if(new_state.upgrade) + { + new_state.upgrade=false; + new_state.exclusive=true; + } + else + { + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + } + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + if(last_reader) + { + if(old_state.upgrade) + { + BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,0)!=0); + } + else + { + release_waiters(old_state); + } + } + break; + } + old_state=current_state; + } + } + + void lock() + { + BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel())); + } + + template + bool timed_lock(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } + + bool try_lock() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(new_state.shared_count || new_state.exclusive) + { + return false; + } + else + { + new_state.exclusive=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + return true; + } + + + bool timed_lock(boost::system_time const& wait_until) + { + for(;;) + { + state_data old_state=state; + + for(;;) + { + state_data new_state=old_state; + if(new_state.shared_count || new_state.exclusive) + { + ++new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=true; + } + else + { + new_state.exclusive=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + + if(!old_state.shared_count && !old_state.exclusive) + { + return true; + } + unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,true,::boost::detail::get_milliseconds_until(wait_until)); + if(wait_res==detail::win32::timeout) + { + for(;;) + { + state_data new_state=old_state; + if(new_state.shared_count || new_state.exclusive) + { + if(new_state.exclusive_waiting) + { + if(!--new_state.exclusive_waiting) + { + new_state.exclusive_waiting_blocked=false; + } + } + } + else + { + new_state.exclusive=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + if(!old_state.shared_count && !old_state.exclusive) + { + return true; + } + return false; + } + BOOST_ASSERT(wait_res<2); + } + } + + void unlock() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + new_state.exclusive=false; + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + release_waiters(old_state); + } + + void lock_upgrade() + { + for(;;) + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade) + { + ++new_state.shared_waiting; + } + else + { + ++new_state.shared_count; + new_state.upgrade=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + + if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade)) + { + return; + } + + BOOST_VERIFY(!detail::win32::WaitForSingleObject(unlock_sem,detail::win32::infinite)); + } + } + + bool try_lock_upgrade() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade) + { + return false; + } + else + { + ++new_state.shared_count; + new_state.upgrade=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + return true; + } + + void unlock_upgrade() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + new_state.upgrade=false; + bool const last_reader=!--new_state.shared_count; + + if(last_reader) + { + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + if(last_reader) + { + release_waiters(old_state); + } + break; + } + old_state=current_state; + } + } + + void unlock_upgrade_and_lock() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + bool const last_reader=!--new_state.shared_count; + + if(last_reader) + { + new_state.upgrade=false; + new_state.exclusive=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + if(!last_reader) + { + BOOST_VERIFY(!detail::win32::WaitForSingleObject(upgrade_sem,detail::win32::infinite)); + } + break; + } + old_state=current_state; + } + } + + void unlock_and_lock_upgrade() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + new_state.exclusive=false; + new_state.upgrade=true; + ++new_state.shared_count; + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + release_waiters(old_state); + } + + void unlock_and_lock_shared() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + new_state.exclusive=false; + ++new_state.shared_count; + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + release_waiters(old_state); + } + + void unlock_upgrade_and_lock_shared() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + new_state.upgrade=false; + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + release_waiters(old_state); + } + + }; +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/win32/thread_data.hpp b/deal.II/contrib/boost/include/boost/thread/win32/thread_data.hpp new file mode 100644 index 0000000000..1a6a1e0391 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/win32/thread_data.hpp @@ -0,0 +1,178 @@ +#ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP +#define BOOST_THREAD_PTHREAD_THREAD_DATA_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 2008 Anthony Williams + +#include +#include +#include +#include "thread_primitives.hpp" +#include "thread_heap_alloc.hpp" + +#include + +namespace boost +{ + namespace detail + { + struct thread_exit_callback_node; + struct tss_data_node; + + struct thread_data_base; + void intrusive_ptr_add_ref(thread_data_base * p); + void intrusive_ptr_release(thread_data_base * p); + + struct thread_data_base + { + long count; + detail::win32::handle_manager thread_handle; + detail::win32::handle_manager interruption_handle; + boost::detail::thread_exit_callback_node* thread_exit_callbacks; + boost::detail::tss_data_node* tss_data; + bool interruption_enabled; + unsigned id; + + thread_data_base(): + count(0),thread_handle(detail::win32::invalid_handle_value), + interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)), + thread_exit_callbacks(0),tss_data(0), + interruption_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); + } + } + + void interrupt() + { + BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0); + } + + typedef detail::win32::handle native_handle_type; + + virtual void run()=0; + }; + + typedef boost::intrusive_ptr thread_data_ptr; + + struct timeout + { + unsigned long start; + uintmax_t milliseconds; + bool relative; + boost::system_time abs_time; + + static unsigned long const max_non_infinite_wait=0xfffffffe; + + timeout(uintmax_t milliseconds_): + start(win32::GetTickCount()), + milliseconds(milliseconds_), + relative(true), + abs_time(boost::get_system_time()) + {} + + timeout(boost::system_time const& abs_time_): + start(win32::GetTickCount()), + milliseconds(0), + relative(false), + abs_time(abs_time_) + {} + + struct remaining_time + { + bool more; + unsigned long milliseconds; + + remaining_time(uintmax_t remaining): + more(remaining>max_non_infinite_wait), + milliseconds(more?max_non_infinite_wait:(unsigned long)remaining) + {} + }; + + remaining_time remaining_milliseconds() const + { + if(is_sentinel()) + { + return remaining_time(win32::infinite); + } + else if(relative) + { + unsigned long const now=win32::GetTickCount(); + unsigned long const elapsed=now-start; + return remaining_time((elapsed + inline void sleep(TimeDuration const& rel_time) + { + interruptible_wait(static_cast(rel_time.total_milliseconds())); + } + inline void sleep(system_time const& abs_time) + { + interruptible_wait(abs_time); + } + } + +} + +#include + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/win32/thread_heap_alloc.hpp b/deal.II/contrib/boost/include/boost/thread/win32/thread_heap_alloc.hpp new file mode 100644 index 0000000000..9f8186f55c --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/win32/thread_heap_alloc.hpp @@ -0,0 +1,397 @@ +// 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" +#include +#include + +#if defined( BOOST_USE_WINDOWS_H ) +# include + +namespace boost +{ + namespace detail + { + namespace win32 + { + using ::GetProcessHeap; + using ::HeapAlloc; + using ::HeapFree; + } + } +} + +#else + +# ifdef HeapAlloc +# undef HeapAlloc +# endif + +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 + +#include + +namespace boost +{ + namespace detail + { + inline BOOST_THREAD_DECL void* allocate_raw_heap_memory(unsigned size) + { + void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,size); + if(!heap_memory) + { + throw std::bad_alloc(); + } + return heap_memory; + } + + inline BOOST_THREAD_DECL void free_raw_heap_memory(void* heap_memory) + { + BOOST_VERIFY(detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,heap_memory)!=0); + } + + template + inline T* heap_new() + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + +#ifdef BOOST_HAS_RVALUE_REFS + template + inline T* heap_new(A1&& a1) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(static_cast(a1)); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + template + inline T* heap_new(A1&& a1,A2&& a2) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(static_cast(a1),static_cast(a2)); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + template + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(static_cast(a1),static_cast(a2), + static_cast(a3)); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + template + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(static_cast(a1),static_cast(a2), + static_cast(a3),static_cast(a4)); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } +#else + template + inline T* heap_new_impl(A1 a1) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(a1); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + + template + inline T* heap_new_impl(A1 a1,A2 a2) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(a1,a2); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(a1,a2,a3); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(a1,a2,a3,a4); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + + + template + inline T* heap_new(A1 const& a1) + { + return heap_new_impl(a1); + } + template + inline T* heap_new(A1& a1) + { + return heap_new_impl(a1); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1& a1,A2 const& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1 const& a1,A2& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1& a1,A2& a2) + { + return heap_new_impl(a1,a2); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + +#endif + template + inline void heap_delete(T* data) + { + data->~T(); + free_raw_heap_memory(data); + } + + template + struct do_heap_delete + { + void operator()(T* data) const + { + detail::heap_delete(data); + } + }; + } +} + +#include + + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/win32/thread_primitives.hpp b/deal.II/contrib/boost/include/boost/thread/win32/thread_primitives.hpp new file mode 100644 index 0000000000..67a1bc3cb2 --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/win32/thread_primitives.hpp @@ -0,0 +1,398 @@ +#ifndef BOOST_WIN32_THREAD_PRIMITIVES_HPP +#define BOOST_WIN32_THREAD_PRIMITIVES_HPP + +// win32_thread_primitives.hpp +// +// (C) Copyright 2005-7 Anthony Williams +// (C) Copyright 2007 David Deakins +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include + +#if defined( BOOST_USE_WINDOWS_H ) +# include + +namespace boost +{ + namespace detail + { + namespace win32 + { + typedef ULONG_PTR ulong_ptr; + typedef HANDLE handle; + unsigned const infinite=INFINITE; + unsigned const timeout=WAIT_TIMEOUT; + handle const invalid_handle_value=INVALID_HANDLE_VALUE; + +# ifdef BOOST_NO_ANSI_APIS + using ::CreateMutexW; + using ::CreateEventW; + using ::CreateSemaphoreW; +# else + using ::CreateMutexA; + using ::CreateEventA; + using ::CreateSemaphoreA; +# endif + using ::CloseHandle; + using ::ReleaseMutex; + using ::ReleaseSemaphore; + using ::SetEvent; + using ::ResetEvent; + using ::WaitForMultipleObjects; + using ::WaitForSingleObject; + using ::GetCurrentProcessId; + using ::GetCurrentThreadId; + using ::GetCurrentThread; + using ::GetCurrentProcess; + using ::DuplicateHandle; + using ::SleepEx; + using ::Sleep; + using ::QueueUserAPC; + using ::GetTickCount; + } + } +} +#elif defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ ) + +# ifdef UNDER_CE +# ifndef WINAPI +# ifndef _WIN32_WCE_EMULATION +# define WINAPI __cdecl // Note this doesn't match the desktop definition +# else +# define WINAPI __stdcall +# endif +# endif + +# ifdef __cplusplus +extern "C" { +# endif +typedef int BOOL; +typedef unsigned long DWORD; +typedef void* HANDLE; + +# include +# ifdef __cplusplus +} +# endif +# endif + +namespace boost +{ + namespace detail + { + namespace win32 + { + +# ifdef _WIN64 + typedef unsigned __int64 ulong_ptr; +# else + typedef unsigned long ulong_ptr; +# endif + typedef void* handle; + unsigned const infinite=~0U; + unsigned const timeout=258U; + handle const invalid_handle_value=(handle)(-1); + + extern "C" + { + struct _SECURITY_ATTRIBUTES; +# ifdef BOOST_NO_ANSI_APIS + __declspec(dllimport) void* __stdcall CreateMutexW(_SECURITY_ATTRIBUTES*,int,wchar_t const*); + __declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES*,long,long,wchar_t const*); + __declspec(dllimport) void* __stdcall CreateEventW(_SECURITY_ATTRIBUTES*,int,int,wchar_t const*); +# else + __declspec(dllimport) void* __stdcall CreateMutexA(_SECURITY_ATTRIBUTES*,int,char const*); + __declspec(dllimport) void* __stdcall CreateSemaphoreA(_SECURITY_ATTRIBUTES*,long,long,char const*); + __declspec(dllimport) void* __stdcall CreateEventA(_SECURITY_ATTRIBUTES*,int,int,char const*); +# endif + __declspec(dllimport) int __stdcall CloseHandle(void*); + __declspec(dllimport) int __stdcall ReleaseMutex(void*); + __declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void*,unsigned long); + __declspec(dllimport) unsigned long __stdcall WaitForMultipleObjects(unsigned long nCount,void* const * lpHandles,int bWaitAll,unsigned long dwMilliseconds); + __declspec(dllimport) int __stdcall ReleaseSemaphore(void*,long,long*); + __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) unsigned long __stdcall GetTickCount(); + +# ifndef UNDER_CE + __declspec(dllimport) unsigned long __stdcall GetCurrentProcessId(); + __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(); + __declspec(dllimport) void* __stdcall GetCurrentThread(); + __declspec(dllimport) void* __stdcall GetCurrentProcess(); + __declspec(dllimport) int __stdcall SetEvent(void*); + __declspec(dllimport) int __stdcall ResetEvent(void*); +# else + using ::GetCurrentProcessId; + using ::GetCurrentThreadId; + using ::GetCurrentThread; + using ::GetCurrentProcess; + using ::SetEvent; + using ::ResetEvent; +# endif + } + } + } +} +#else +# error "Win32 functions not available" +#endif + +#include + +namespace boost +{ + namespace detail + { + namespace win32 + { + enum event_type + { + auto_reset_event=false, + manual_reset_event=true + }; + + enum initial_event_state + { + event_initially_reset=false, + event_initially_set=true + }; + + inline handle create_anonymous_event(event_type type,initial_event_state state) + { +#if !defined(BOOST_NO_ANSI_APIS) + handle const res=win32::CreateEventA(0,type,state,0); +#else + handle const res=win32::CreateEventW(0,type,state,0); +#endif + if(!res) + { + throw thread_resource_error(); + } + return res; + } + + inline handle create_anonymous_semaphore(long initial_count,long max_count) + { +#if !defined(BOOST_NO_ANSI_APIS) + handle const res=CreateSemaphoreA(0,initial_count,max_count,0); +#else + handle const res=CreateSemaphoreW(0,initial_count,max_count,0); +#endif + if(!res) + { + throw thread_resource_error(); + } + return res; + } + + inline handle duplicate_handle(handle source) + { + handle const current_process=GetCurrentProcess(); + long const same_access_flag=2; + handle new_handle=0; + bool const success=DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0; + if(!success) + { + throw thread_resource_error(); + } + return new_handle; + } + + inline void release_semaphore(handle semaphore,long count) + { + BOOST_VERIFY(ReleaseSemaphore(semaphore,count,0)!=0); + } + + class handle_manager + { + private: + handle handle_to_manage; + handle_manager(handle_manager&); + handle_manager& operator=(handle_manager&); + + void cleanup() + { + if(handle_to_manage && handle_to_manage!=invalid_handle_value) + { + BOOST_VERIFY(CloseHandle(handle_to_manage)); + } + } + + public: + explicit handle_manager(handle handle_to_manage_): + handle_to_manage(handle_to_manage_) + {} + handle_manager(): + handle_to_manage(0) + {} + + handle_manager& operator=(handle new_handle) + { + cleanup(); + handle_to_manage=new_handle; + return *this; + } + + operator handle() const + { + 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; + handle_to_manage=0; + return res; + } + + bool operator!() const + { + return !handle_to_manage; + } + + ~handle_manager() + { + cleanup(); + } + }; + + } + } +} + +#if defined(BOOST_MSVC) && (_MSC_VER>=1400) && !defined(UNDER_CE) + +namespace boost +{ + namespace detail + { + namespace win32 + { +#if _MSC_VER==1400 + extern "C" unsigned char _interlockedbittestandset(long *a,long b); + extern "C" unsigned char _interlockedbittestandreset(long *a,long b); +#else + extern "C" unsigned char _interlockedbittestandset(volatile long *a,long b); + extern "C" unsigned char _interlockedbittestandreset(volatile long *a,long b); +#endif + +#pragma intrinsic(_interlockedbittestandset) +#pragma intrinsic(_interlockedbittestandreset) + + inline bool interlocked_bit_test_and_set(long* x,long bit) + { + return _interlockedbittestandset(x,bit)!=0; + } + + inline bool interlocked_bit_test_and_reset(long* x,long bit) + { + return _interlockedbittestandreset(x,bit)!=0; + } + + } + } +} +#define BOOST_THREAD_BTS_DEFINED +#elif (defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)) && defined(_M_IX86) +namespace boost +{ + namespace detail + { + namespace win32 + { + inline bool interlocked_bit_test_and_set(long* x,long bit) + { + __asm { + mov eax,bit; + mov edx,x; + lock bts [edx],eax; + setc al; + }; + } + + inline bool interlocked_bit_test_and_reset(long* x,long bit) + { + __asm { + mov eax,bit; + mov edx,x; + lock btr [edx],eax; + setc al; + }; + } + + } + } +} +#define BOOST_THREAD_BTS_DEFINED +#endif + +#ifndef BOOST_THREAD_BTS_DEFINED + +namespace boost +{ + namespace detail + { + namespace win32 + { + inline bool interlocked_bit_test_and_set(long* x,long bit) + { + long const value=1< + +#endif diff --git a/deal.II/contrib/boost/include/boost/thread/xtime.hpp b/deal.II/contrib/boost/include/boost/thread/xtime.hpp new file mode 100644 index 0000000000..7cc6272d6a --- /dev/null +++ b/deal.II/contrib/boost/include/boost/thread/xtime.hpp @@ -0,0 +1,92 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// Copyright (C) 2007-8 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_XTIME_WEK070601_HPP +#define BOOST_XTIME_WEK070601_HPP + +#include + +#include +#include +#include + +#include + +namespace boost { + +enum xtime_clock_types +{ + TIME_UTC=1 +// TIME_TAI, +// TIME_MONOTONIC, +// TIME_PROCESS, +// TIME_THREAD, +// TIME_LOCAL, +// TIME_SYNC, +// TIME_RESOLUTION +}; + +struct xtime +{ +#if defined(BOOST_NO_INT64_T) + typedef int_fast32_t xtime_sec_t; //INT_FAST32_MIN <= sec <= INT_FAST32_MAX +#else + typedef int_fast64_t xtime_sec_t; //INT_FAST64_MIN <= sec <= INT_FAST64_MAX +#endif + + typedef int_fast32_t xtime_nsec_t; //0 <= xtime.nsec < NANOSECONDS_PER_SECOND + + xtime_sec_t sec; + xtime_nsec_t nsec; + + operator system_time() const + { + return boost::posix_time::from_time_t(0)+ + boost::posix_time::seconds(static_cast(sec))+ +#ifdef BOOST_DATE_TIME_HAS_NANOSECONDS + boost::posix_time::nanoseconds(nsec); +#else + boost::posix_time::microseconds((nsec+500)/1000); +#endif + } + +}; + +inline xtime get_xtime(boost::system_time const& abs_time) +{ + xtime res; + boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0); + + res.sec=static_cast(time_since_epoch.total_seconds()); + res.nsec=static_cast(time_since_epoch.fractional_seconds()*(1000000000/time_since_epoch.ticks_per_second())); + return res; +} + +inline int xtime_get(struct xtime* xtp, int clock_type) +{ + if (clock_type == TIME_UTC) + { + *xtp=get_xtime(get_system_time()); + return clock_type; + } + return 0; +} + + +inline int xtime_cmp(const xtime& xt1, const xtime& xt2) +{ + if (xt1.sec == xt2.sec) + return (int)(xt1.nsec - xt2.nsec); + else + return (xt1.sec > xt2.sec) ? 1 : -1; +} + +} // namespace boost + +#include + +#endif //BOOST_XTIME_WEK070601_HPP diff --git a/deal.II/contrib/boost/libs/thread/build/Jamfile.v2 b/deal.II/contrib/boost/libs/thread/build/Jamfile.v2 new file mode 100644 index 0000000000..e69ff9019f --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/build/Jamfile.v2 @@ -0,0 +1,208 @@ +# $Id: Jamfile.v2 42230 2007-12-21 11:51:05Z anthonyw $ +# Copyright 2006-2007 Roland Schwarz. +# Copyright 2007 Anthony Williams +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +######################################################################### +# The boost threading library can be built on top of different API's +# Currently this is the win32 API and the pthreads API. +# Pthread is native on unix variants. +# To get pthread on windows you need the pthread win32 library +# http://sourceware.org/pthreads-win32 which is available under LGPL. +# +# You need to provide the include path and lib path in the variables +# PTW32_INCLUDE and PTW32_LIB respectively. You can specify these +# paths in site-config.jam, user-config.jam or in the environment. +# A new feature is provided to request a specific API: +# win32 and multi + static:BOOST_THREAD_BUILD_LIB=1 + shared:BOOST_THREAD_BUILD_DLL=1 + -@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag + @$(__name__).tag + : default-build multi + ; + +local rule default_threadapi ( ) +{ + local api = pthread ; + if [ os.name ] = "NT" { api = win32 ; } + return $(api) ; +} + +feature.feature threadapi : pthread win32 : propagated ; +feature.set-default threadapi : [ default_threadapi ] ; + +rule tag ( name : type ? : property-set ) +{ + local result = $(name) ; + + if $(type) in STATIC_LIB SHARED_LIB IMPORT_LIB + { + local api = [ $(property-set).get ] ; + + # non native api gets additional tag + if $(api) != [ default_threadapi ] { + result = $(result)_$(api) ; + } + } + + # forward to the boost tagging rule + return [ indirect.call $(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag + $(result) : $(type) : $(property-set) ] ; +} + +rule win32_pthread_paths ( properties * ) +{ + local result ; + local PTW32_INCLUDE ; + local PTW32_LIB ; + PTW32_INCLUDE = [ modules.peek : PTW32_INCLUDE ] ; + PTW32_LIB = [ modules.peek : PTW32_LIB ] ; + PTW32_INCLUDE ?= [ modules.peek user-config : PTW32_INCLUDE ] ; + PTW32_LIB ?= [ modules.peek user-config : PTW32_LIB ] ; + PTW32_INCLUDE ?= [ modules.peek site-config : PTW32_INCLUDE ] ; + PTW32_LIB ?= [ modules.peek site-config : PTW32_LIB ] ; + + if ! ( $(PTW32_INCLUDE) && $(PTW32_LIB) ) + { + if ! $(.notified) + { + echo "************************************************************" ; + echo "Trying to build Boost.Thread with pthread support." ; + echo "If you need pthread you should specify the paths." ; + echo "You can specify them in site-config.jam, user-config.jam" ; + echo "or in the environment." ; + echo "For example:" ; + echo "PTW32_INCLUDE=C:\\Program Files\\ptw32\\Pre-built2\\include" ; + echo "PTW32_LIB=C:\\Program Files\\ptw32\\Pre-built2\\lib" ; + echo "************************************************************" ; + .notified = true ; + } + } + else + { + local include_path = [ path.make $(PTW32_INCLUDE) ] ; + local lib_path = [ path.make $(PTW32_LIB) ] ; + local libname = pthread ; + if msvc in $(properties) + { + libname = $(libname)VC2.lib ; + } + if gcc in $(properties) + { + libname = lib$(libname)GC2.a ; + } + lib_path = [ path.glob $(lib_path) : $(libname) ] ; + if ! $(lib_path) + { + if ! $(.notified) + { + echo "************************************************************" ; + echo "Trying to build Boost.Thread with pthread support." ; + echo "But the library" $(libname) "could not be found in path" ; + echo $(PTW32_LIB) ; + echo "************************************************************" ; + .notified = true ; + } + } + else + { + result += $(include_path) ; + result += $(lib_path) ; + } + } + return $(result) ; +} + +rule usage-requirements ( properties * ) +{ + local result ; + if pthread in $(properties) + { + result += BOOST_THREAD_POSIX ; + if windows in $(properties) + { + result += [ win32_pthread_paths $(properties) ] ; + # TODO: What is for static linking? Is the also needed + # in that case? + } + } + return $(result) ; +} + +rule requirements ( properties * ) +{ + local result ; + + if pthread in $(properties) + { + result += BOOST_THREAD_POSIX ; + if windows in $(properties) + { + local paths = [ win32_pthread_paths $(properties) ] ; + if $(paths) + { + result += $(paths) ; + } + else + { + result = no ; + } + } + } + return $(result) ; +} + +alias thread_sources + : ## win32 sources ## + win32/thread.cpp + win32/exceptions.cpp + win32/tss_dll.cpp + win32/tss_pe.cpp + : ## requirements ## + win32 + ; + +alias thread_sources + : ## pthread sources ## + pthread/thread.cpp + pthread/exceptions.cpp + pthread/once.cpp + : ## requirements ## + pthread + ; + +explicit thread_sources ; + +lib boost_thread + : thread_sources + : @requirements + : + : shared:BOOST_THREAD_USE_DLL=1 + static:BOOST_THREAD_USE_LIB=1 + @usage-requirements + ; diff --git a/deal.II/contrib/boost/libs/thread/doc/Jamfile.v2 b/deal.II/contrib/boost/libs/thread/doc/Jamfile.v2 new file mode 100644 index 0000000000..dc68fc392e --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/doc/Jamfile.v2 @@ -0,0 +1,55 @@ +# (C) Copyright 2008 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) + +path-constant boost-images : ../../../doc/src/images ; + +xml thread : thread.qbk ; + +boostbook standalone + : + thread + : + # HTML options first: + # Use graphics not text for navigation: + navig.graphics=1 + # How far down we chunk nested sections, basically all of them: + chunk.section.depth=3 + # Don't put the first section on the same page as the TOC: + chunk.first.sections=1 + # How far down sections get TOC's + toc.section.depth=10 + # Max depth in each TOC: + toc.max.depth=3 + # How far down we go with TOC's + generate.section.toc.level=10 + # Path for links to Boost: + boost.root=../../../.. + # Path for libraries index: + boost.libraries=../../../../libs/libraries.htm + # Use the main Boost stylesheet: + html.stylesheet=../../../../doc/html/boostbook.css + + # PDF Options: + # TOC Generation: this is needed for FOP-0.9 and later: + #fop1.extensions=1 + # Or enable this if you're using XEP: + xep.extensions=1 + # TOC generation: this is needed for FOP 0.2, but must not be set to zero for FOP-0.9! + fop.extensions=0 + # No indent on body text: + body.start.indent=0pt + # Margin size: + page.margin.inner=0.5in + # Margin size: + page.margin.outer=0.5in + # Yes, we want graphics for admonishments: + admon.graphics=1 + # Set this one for PDF generation *only*: + # default pnd graphics are awful in PDF form, + # better use SVG's instead: + pdf:admon.graphics.extension=".svg" + pdf:admon.graphics.path=$(boost-images)/ + ; + diff --git a/deal.II/contrib/boost/libs/thread/doc/acknowledgements.qbk b/deal.II/contrib/boost/libs/thread/doc/acknowledgements.qbk new file mode 100644 index 0000000000..1f21921fa4 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/doc/acknowledgements.qbk @@ -0,0 +1,23 @@ +[/ + (C) Copyright 2007-8 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). +] + +[section:acknowledgements Acknowledgments] + +The original implementation of __boost_thread__ was written by William Kempf, with contributions from numerous others. This new +version initially grew out of an attempt to rewrite __boost_thread__ to William Kempf's design with fresh code that could be +released under the Boost Software License. However, as the C++ Standards committee have been actively discussing standardizing a +thread library for C++, this library has evolved to reflect the proposals, whilst retaining as much backwards-compatibility as +possible. + +Particular thanks must be given to Roland Schwarz, who contributed a lot of time and code to the original __boost_thread__ library, +and who has been actively involved with the rewrite. The scheme for dividing the platform-specific implementations into separate +directories was devised by Roland, and his input has contributed greatly to improving the quality of the current implementation. + +Thanks also must go to Peter Dimov, Howard Hinnant, Alexander Terekhov, Chris Thomasson and others for their comments on the +implementation details of the code. + +[endsect] diff --git a/deal.II/contrib/boost/libs/thread/doc/barrier.qbk b/deal.II/contrib/boost/libs/thread/doc/barrier.qbk new file mode 100644 index 0000000000..7e7c3e122b --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/doc/barrier.qbk @@ -0,0 +1,72 @@ +[/ + (C) Copyright 2007-8 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). +] + +[section:barriers Barriers] + +A barrier is a simple concept. Also known as a ['rendezvous], it is a synchronization point between multiple threads. The barrier is +configured for a particular number of threads (`n`), and as threads reach the barrier they must wait until all `n` threads have +arrived. Once the `n`-th thread has reached the barrier, all the waiting threads can proceed, and the barrier is reset. + +[section:barrier Class `barrier`] + + #include + + class barrier + { + public: + barrier(unsigned int count); + ~barrier(); + + bool wait(); + }; + +Instances of __barrier__ are not copyable or movable. + +[heading Constructor] + + barrier(unsigned int count); + +[variablelist + +[[Effects:] [Construct a barrier for `count` threads.]] + +[[Throws:] [__thread_resource_error__ if an error occurs.]] + +] + +[heading Destructor] + + ~barrier(); + +[variablelist + +[[Precondition:] [No threads are waiting on `*this`.]] + +[[Effects:] [Destroys `*this`.]] + +[[Throws:] [Nothing.]] + +] + +[heading Member function `wait`] + + bool wait(); + +[variablelist + +[[Effects:] [Block until `count` threads have called `wait` on `*this`. When the `count`-th thread calls `wait`, all waiting threads +are unblocked, and the barrier is reset. ]] + +[[Returns:] [`true` for exactly one thread from each batch of waiting threads, `false` otherwise.]] + +[[Throws:] [__thread_resource_error__ if an error occurs.]] + +] + +[endsect] + +[endsect] diff --git a/deal.II/contrib/boost/libs/thread/doc/changes.qbk b/deal.II/contrib/boost/libs/thread/doc/changes.qbk new file mode 100644 index 0000000000..25ae1472f2 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/doc/changes.qbk @@ -0,0 +1,83 @@ +[/ + (C) Copyright 2007-8 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). +] + +[section:changes Changes since boost 1.35] + +The 1.36.0 release of Boost includes a few new features in the thread library: + +* New generic __lock_multiple_ref__ and __try_lock_multiple_ref__ functions for locking multiple mutexes at once. + +* Rvalue reference support for move semantics where the compilers supports it. + +* A few bugs fixed and missing functions added (including the serious win32 condition variable bug). + +* `scoped_try_lock` types are now backwards-compatible with Boost 1.34.0 and previous releases. + +* Support for passing function arguments to the thread function by supplying additional arguments to the __thread__ constructor. + +* Backwards-compatibility overloads added for `timed_lock` and `timed_wait` functions to allow use of `xtime` for timeouts. + +[heading Changes since boost 1.34] + +Almost every line of code in __boost_thread__ has been changed since the 1.34 release of boost. However, most of the interface +changes have been extensions, so the new code is largely backwards-compatible with the old code. The new features and breaking +changes are described below. + +[heading New Features] + +* Instances of __thread__ and of the various lock types are now movable. + +* Threads can be interrupted at __interruption_points__. + +* Condition variables can now be used with any type that implements the __lockable_concept__, through the use of +`boost::condition_variable_any` (`boost::condition` is a `typedef` to `boost::condition_variable_any`, provided for backwards +compatibility). `boost::condition_variable` is provided as an optimization, and will only work with +`boost::unique_lock` (`boost::mutex::scoped_lock`). + +* Thread IDs are separated from __thread__, so a thread can obtain it's own ID (using `boost::this_thread::get_id()`), and IDs can +be used as keys in associative containers, as they have the full set of comparison operators. + +* Timeouts are now implemented using the Boost DateTime library, through a typedef `boost::system_time` for absolute timeouts, and +with support for relative timeouts in many cases. `boost::xtime` is supported for backwards compatibility only. + +* Locks are implemented as publicly accessible templates `boost::lock_guard`, `boost::unique_lock`, `boost::shared_lock`, and +`boost::upgrade_lock`, which are templated on the type of the mutex. The __lockable_concept__ has been extended to include publicly +available __lock_ref__ and __unlock_ref__ member functions, which are used by the lock types. + +[heading Breaking Changes] + +The list below should cover all changes to the public interface which break backwards compatibility. + +* __try_mutex__ has been removed, and the functionality subsumed into __mutex__. __try_mutex__ is left as a `typedef`, +but is no longer a separate class. + +* __recursive_try_mutex__ has been removed, and the functionality subsumed into +__recursive_mutex__. __recursive_try_mutex__ is left as a `typedef`, but is no longer a separate class. + +* `boost::detail::thread::lock_ops` has been removed. Code that relies on the `lock_ops` implementation detail will no longer work, +as this has been removed, as it is no longer necessary now that mutex types now have public __lock_ref__ and __unlock_ref__ member +functions. + +* `scoped_lock` constructors with a second parameter of type `bool` are no longer provided. With previous boost releases, +``boost::mutex::scoped_lock some_lock(some_mutex,false);`` could be used to create a lock object that was associated with a mutex, +but did not lock it on construction. This facility has now been replaced with the constructor that takes a +`boost::defer_lock_type` as the second parameter: ``boost::mutex::scoped_lock some_lock(some_mutex,boost::defer_lock);`` + +* The `locked()` member function of the `scoped_lock` types has been renamed to __owns_lock_ref__. + +* You can no longer obtain a __thread__ instance representing the current thread: a default-constructed __thread__ object is not +associated with any thread. The only use for such a thread object was to support the comparison operators: this functionality has +been moved to __thread_id__. + +* The broken `boost::read_write_mutex` has been replaced with __shared_mutex__. + +* __mutex__ is now never recursive. For Boost releases prior to 1.35 __mutex__ was recursive on Windows and not on POSIX platforms. + +* When using a __recursive_mutex__ with a call to [cond_any_wait_link `boost::condition_variable_any::wait()`], the mutex is only + unlocked one level, and not completely. This prior behaviour was not guaranteed and did not feature in the tests. + +[endsect] diff --git a/deal.II/contrib/boost/libs/thread/doc/condition_variables.qbk b/deal.II/contrib/boost/libs/thread/doc/condition_variables.qbk new file mode 100644 index 0000000000..e54dd34cc0 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/doc/condition_variables.qbk @@ -0,0 +1,513 @@ +[/ + (C) Copyright 2007-8 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). +] + +[section:condvar_ref Condition Variables] + +[heading Synopsis] + +The classes `condition_variable` and `condition_variable_any` provide a +mechanism for one thread to wait for notification from another thread that a +particular condition has become true. The general usage pattern is that one +thread locks a mutex and then calls `wait` on an instance of +`condition_variable` or `condition_variable_any`. When the thread is woken from +the wait, then it checks to see if the appropriate condition is now true, and +continues if so. If the condition is not true, then the thread then calls `wait` +again to resume waiting. In the simplest case, this condition is just a boolean +variable: + + boost::condition_variable cond; + boost::mutex mut; + bool data_ready; + + void process_data(); + + void wait_for_data_to_process() + { + boost::unique_lock lock(mut); + while(!data_ready) + { + cond.wait(lock); + } + process_data(); + } + +Notice that the `lock` is passed to `wait`: `wait` will atomically add the +thread to the set of threads waiting on the condition variable, and unlock the +mutex. When the thread is woken, the mutex will be locked again before the call +to `wait` returns. This allows other threads to acquire the mutex in order to +update the shared data, and ensures that the data associated with the condition +is correctly synchronized. + +In the mean time, another thread sets the condition to `true`, and then calls +either `notify_one` or `notify_all` on the condition variable to wake one +waiting thread or all the waiting threads respectively. + + void retrieve_data(); + void prepare_data(); + + void prepare_data_for_processing() + { + retrieve_data(); + prepare_data(); + { + boost::lock_guard lock(mut); + data_ready=true; + } + cond.notify_one(); + } + +Note that the same mutex is locked before the shared data is updated, but that +the mutex does not have to be locked across the call to `notify_one`. + +This example uses an object of type `condition_variable`, but would work just as +well with an object of type `condition_variable_any`: `condition_variable_any` +is more general, and will work with any kind of lock or mutex, whereas +`condition_variable` requires that the lock passed to `wait` is an instance of +`boost::unique_lock`. This enables `condition_variable` to make +optimizations in some cases, based on the knowledge of the mutex type; +`condition_variable_any` typically has a more complex implementation than +`condition_variable`. + +[section:condition_variable Class `condition_variable`] + + #include + + namespace boost + { + class condition_variable + { + public: + condition_variable(); + ~condition_variable(); + + void notify_one(); + void notify_all(); + + void wait(boost::unique_lock& lock); + + template + void wait(boost::unique_lock& lock,predicate_type predicate); + + bool timed_wait(boost::unique_lock& lock,boost::system_time const& abs_time); + + template + bool timed_wait(boost::unique_lock& lock,duration_type const& rel_time); + + template + bool timed_wait(boost::unique_lock& lock,boost::system_time const& abs_time,predicate_type predicate); + + template + bool timed_wait(boost::unique_lock& lock,duration_type const& rel_time,predicate_type predicate); + + // backwards compatibility + + bool timed_wait(boost::unique_lock& lock,boost::xtime const& abs_time); + + template + bool timed_wait(boost::unique_lock& lock,boost::xtime const& abs_time,predicate_type predicate); + }; + } + +[section:constructor `condition_variable()`] + +[variablelist + +[[Effects:] [Constructs an object of class `condition_variable`.]] + +[[Throws:] [__thread_resource_error__ if an error occurs.]] + +] + +[endsect] + +[section:destructor `~condition_variable()`] + +[variablelist + +[[Precondition:] [All threads waiting on `*this` have been notified by a call to +`notify_one` or `notify_all` (though the respective calls to `wait` or +`timed_wait` need not have returned).]] + +[[Effects:] [Destroys the object.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:notify_one `void notify_one()`] + +[variablelist + +[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call +to `wait` or `timed_wait`, unblocks one of those threads.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:notify_all `void notify_all()`] + +[variablelist + +[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call +to `wait` or `timed_wait`, unblocks all of those threads.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:wait `void wait(boost::unique_lock& lock)`] + +[variablelist + +[[Precondition:] [`lock` is locked by the current thread, and either no other +thread is currently waiting on `*this`, or the execution of the `mutex()` member +function on the `lock` objects supplied in the calls to `wait` or `timed_wait` +in all the threads currently waiting on `*this` would return the same value as +`lock->mutex()` for this call to `wait`.]] + +[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The +thread will unblock when notified by a call to `this->notify_one()` or +`this->notify_all()`, or spuriously. When the thread is unblocked (for whatever +reason), the lock is reacquired by invoking `lock.lock()` before the call to +`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the +function exits with an exception.]] + +[[Postcondition:] [`lock` is locked by the current thread.]] + +[[Throws:] [__thread_resource_error__ if an error +occurs. __thread_interrupted__ if the wait was interrupted by a call to +__interrupt__ on the __thread__ object associated with the current thread of execution.]] + +] + +[endsect] + +[section:wait_predicate `template void wait(boost::unique_lock& lock, predicate_type pred)`] + +[variablelist + +[[Effects:] [As-if `` +while(!pred()) +{ + wait(lock); +} +``]] + +] + +[endsect] + +[section:timed_wait `bool timed_wait(boost::unique_lock& lock,boost::system_time const& abs_time)`] + +[variablelist + +[[Precondition:] [`lock` is locked by the current thread, and either no other +thread is currently waiting on `*this`, or the execution of the `mutex()` member +function on the `lock` objects supplied in the calls to `wait` or `timed_wait` +in all the threads currently waiting on `*this` would return the same value as +`lock->mutex()` for this call to `wait`.]] + +[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The +thread will unblock when notified by a call to `this->notify_one()` or +`this->notify_all()`, when the time as reported by `boost::get_system_time()` +would be equal to or later than the specified `abs_time`, or spuriously. When +the thread is unblocked (for whatever reason), the lock is reacquired by +invoking `lock.lock()` before the call to `wait` returns. The lock is also +reacquired by invoking `lock.lock()` if the function exits with an exception.]] + +[[Returns:] [`false` if the call is returning because the time specified by +`abs_time` was reached, `true` otherwise.]] + +[[Postcondition:] [`lock` is locked by the current thread.]] + +[[Throws:] [__thread_resource_error__ if an error +occurs. __thread_interrupted__ if the wait was interrupted by a call to +__interrupt__ on the __thread__ object associated with the current thread of execution.]] + +] + +[endsect] + +[section:timed_wait_rel `template bool timed_wait(boost::unique_lock& lock,duration_type const& rel_time)`] + +[variablelist + +[[Precondition:] [`lock` is locked by the current thread, and either no other +thread is currently waiting on `*this`, or the execution of the `mutex()` member +function on the `lock` objects supplied in the calls to `wait` or `timed_wait` +in all the threads currently waiting on `*this` would return the same value as +`lock->mutex()` for this call to `wait`.]] + +[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The +thread will unblock when notified by a call to `this->notify_one()` or +`this->notify_all()`, after the period of time indicated by the `rel_time` +argument has elapsed, or spuriously. When the thread is unblocked (for whatever +reason), the lock is reacquired by invoking `lock.lock()` before the call to +`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the +function exits with an exception.]] + +[[Returns:] [`false` if the call is returning because the time period specified +by `rel_time` has elapsed, `true` otherwise.]] + +[[Postcondition:] [`lock` is locked by the current thread.]] + +[[Throws:] [__thread_resource_error__ if an error +occurs. __thread_interrupted__ if the wait was interrupted by a call to +__interrupt__ on the __thread__ object associated with the current thread of execution.]] + +] + +[note The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.] + +[endsect] + +[section:timed_wait_predicate `template bool timed_wait(boost::unique_lock& lock, boost::system_time const& abs_time, predicate_type pred)`] + +[variablelist + +[[Effects:] [As-if `` +while(!pred()) +{ + if(!timed_wait(lock,abs_time)) + { + return pred(); + } +} +return true; +``]] + +] + +[endsect] + + +[endsect] + +[section:condition_variable_any Class `condition_variable_any`] + + #include + + namespace boost + { + class condition_variable_any + { + public: + condition_variable_any(); + ~condition_variable_any(); + + void notify_one(); + void notify_all(); + + template + void wait(lock_type& lock); + + template + void wait(lock_type& lock,predicate_type predicate); + + template + bool timed_wait(lock_type& lock,boost::system_time const& abs_time); + + template + bool timed_wait(lock_type& lock,duration_type const& rel_time); + + template + bool timed_wait(lock_type& lock,boost::system_time const& abs_time,predicate_type predicate); + + template + bool timed_wait(lock_type& lock,duration_type const& rel_time,predicate_type predicate); + + // backwards compatibility + + template + bool timed_wait(lock_type>& lock,boost::xtime const& abs_time); + + template + bool timed_wait(lock_type& lock,boost::xtime const& abs_time,predicate_type predicate); + }; + } + +[section:constructor `condition_variable_any()`] + +[variablelist + +[[Effects:] [Constructs an object of class `condition_variable_any`.]] + +[[Throws:] [__thread_resource_error__ if an error occurs.]] + +] + +[endsect] + +[section:destructor `~condition_variable_any()`] + +[variablelist + +[[Precondition:] [All threads waiting on `*this` have been notified by a call to +`notify_one` or `notify_all` (though the respective calls to `wait` or +`timed_wait` need not have returned).]] + +[[Effects:] [Destroys the object.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:notify_one `void notify_one()`] + +[variablelist + +[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call +to `wait` or `timed_wait`, unblocks one of those threads.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:notify_all `void notify_all()`] + +[variablelist + +[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call +to `wait` or `timed_wait`, unblocks all of those threads.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:wait `template void wait(lock_type& lock)`] + +[variablelist + +[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The +thread will unblock when notified by a call to `this->notify_one()` or +`this->notify_all()`, or spuriously. When the thread is unblocked (for whatever +reason), the lock is reacquired by invoking `lock.lock()` before the call to +`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the +function exits with an exception.]] + +[[Postcondition:] [`lock` is locked by the current thread.]] + +[[Throws:] [__thread_resource_error__ if an error +occurs. __thread_interrupted__ if the wait was interrupted by a call to +__interrupt__ on the __thread__ object associated with the current thread of execution.]] + +] + +[endsect] + +[section:wait_predicate `template void wait(lock_type& lock, predicate_type pred)`] + +[variablelist + +[[Effects:] [As-if `` +while(!pred()) +{ + wait(lock); +} +``]] + +] + +[endsect] + +[section:timed_wait `template bool timed_wait(lock_type& lock,boost::system_time const& abs_time)`] + +[variablelist + +[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The +thread will unblock when notified by a call to `this->notify_one()` or +`this->notify_all()`, when the time as reported by `boost::get_system_time()` +would be equal to or later than the specified `abs_time`, or spuriously. When +the thread is unblocked (for whatever reason), the lock is reacquired by +invoking `lock.lock()` before the call to `wait` returns. The lock is also +reacquired by invoking `lock.lock()` if the function exits with an exception.]] + +[[Returns:] [`false` if the call is returning because the time specified by +`abs_time` was reached, `true` otherwise.]] + +[[Postcondition:] [`lock` is locked by the current thread.]] + +[[Throws:] [__thread_resource_error__ if an error +occurs. __thread_interrupted__ if the wait was interrupted by a call to +__interrupt__ on the __thread__ object associated with the current thread of execution.]] + +] + +[endsect] + +[section:timed_wait_rel `template bool timed_wait(lock_type& lock,duration_type const& rel_time)`] + +[variablelist + +[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The +thread will unblock when notified by a call to `this->notify_one()` or +`this->notify_all()`, after the period of time indicated by the `rel_time` +argument has elapsed, or spuriously. When the thread is unblocked (for whatever +reason), the lock is reacquired by invoking `lock.lock()` before the call to +`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the +function exits with an exception.]] + +[[Returns:] [`false` if the call is returning because the time period specified +by `rel_time` has elapsed, `true` otherwise.]] + +[[Postcondition:] [`lock` is locked by the current thread.]] + +[[Throws:] [__thread_resource_error__ if an error +occurs. __thread_interrupted__ if the wait was interrupted by a call to +__interrupt__ on the __thread__ object associated with the current thread of execution.]] + +] + +[note The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.] + +[endsect] + +[section:timed_wait_predicate `template bool timed_wait(lock_type& lock, boost::system_time const& abs_time, predicate_type pred)`] + +[variablelist + +[[Effects:] [As-if `` +while(!pred()) +{ + if(!timed_wait(lock,abs_time)) + { + return pred(); + } +} +return true; +``]] + +] + +[endsect] + +[endsect] + +[section:condition Typedef `condition`] + + #include + + typedef condition_variable_any condition; + +The typedef `condition` is provided for backwards compatibility with previous boost releases. + +[endsect] + +[endsect] diff --git a/deal.II/contrib/boost/libs/thread/doc/index.html b/deal.II/contrib/boost/libs/thread/doc/index.html new file mode 100644 index 0000000000..4d1b5db3b2 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/doc/index.html @@ -0,0 +1,12 @@ + + + + + + +Automatic redirection failed, please go to ../../../doc/html/thread.html + + diff --git a/deal.II/contrib/boost/libs/thread/doc/mutex_concepts.qbk b/deal.II/contrib/boost/libs/thread/doc/mutex_concepts.qbk new file mode 100644 index 0000000000..1affa78cb4 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/doc/mutex_concepts.qbk @@ -0,0 +1,1119 @@ +[/ + (C) Copyright 2007-8 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). +] + +[section:mutex_concepts Mutex Concepts] + +A mutex object facilitates protection against data races and allows thread-safe synchronization of data between threads. A thread +obtains ownership of a mutex object by calling one of the lock functions and relinquishes ownership by calling the corresponding +unlock function. Mutexes may be either recursive or non-recursive, and may grant simultaneous ownership to one or many +threads. __boost_thread__ supplies recursive and non-recursive mutexes with exclusive ownership semantics, along with a shared +ownership (multiple-reader / single-writer) mutex. + +__boost_thread__ supports four basic concepts for lockable objects: __lockable_concept_type__, __timed_lockable_concept_type__, +__shared_lockable_concept_type__ and __upgrade_lockable_concept_type__. Each mutex type implements one or more of these concepts, as +do the various lock types. + +[section:lockable `Lockable` Concept] + +The __lockable_concept__ models exclusive ownership. A type that implements the __lockable_concept__ shall provide the following +member functions: + +* [lock_ref_link `void lock();`] +* [try_lock_ref_link `bool try_lock();`] +* [unlock_ref_link `void unlock();`] + +Lock ownership acquired through a call to __lock_ref__ or __try_lock_ref__ must be released through a call to __unlock_ref__. + +[section:lock `void lock()`] + +[variablelist + +[[Effects:] [The current thread blocks until ownership can be obtained for the current thread.]] + +[[Postcondition:] [The current thread owns `*this`.]] + +[[Throws:] [__thread_resource_error__ if an error occurs.]] + +] +[endsect] + +[section:try_lock `bool try_lock()`] + +[variablelist + +[[Effects:] [Attempt to obtain ownership for the current thread without blocking.]] + +[[Returns:] [`true` if ownership was obtained for the current thread, `false` otherwise.]] + +[[Postcondition:] [If the call returns `true`, the current thread owns the `*this`.]] + +[[Throws:] [__thread_resource_error__ if an error occurs.]] + +] +[endsect] + +[section:unlock `void unlock()`] + +[variablelist + +[[Precondition:] [The current thread owns `*this`.]] + +[[Effects:] [Releases ownership by the current thread.]] + +[[Postcondition:] [The current thread no longer owns `*this`.]] + +[[Throws:] [Nothing]] +] +[endsect] +[endsect] + +[section:timed_lockable `TimedLockable` Concept] + +The __timed_lockable_concept__ refines the __lockable_concept__ to add support for +timeouts when trying to acquire the lock. + +A type that implements the __timed_lockable_concept__ shall meet the requirements +of the __lockable_concept__. In addition, the following member functions must be +provided: + +* [timed_lock_ref_link `bool timed_lock(boost::system_time const& abs_time);`] +* [timed_lock_duration_ref_link `template bool timed_lock(DurationType const& rel_time);`] + +Lock ownership acquired through a call to __timed_lock_ref__ must be released through a call to __unlock_ref__. + +[section:timed_lock `bool timed_lock(boost::system_time const& abs_time)`] + +[variablelist + +[[Effects:] [Attempt to obtain ownership for the current thread. Blocks until ownership can be obtained, or the specified time is +reached. If the specified time has already passed, behaves as __try_lock_ref__.]] + +[[Returns:] [`true` if ownership was obtained for the current thread, `false` otherwise.]] + +[[Postcondition:] [If the call returns `true`, the current thread owns `*this`.]] + +[[Throws:] [__thread_resource_error__ if an error occurs.]] +] +[endsect] + +[section:timed_lock_duration `template bool +timed_lock(DurationType const& rel_time)`] + +[variablelist + +[[Effects:] [As-if [timed_lock_ref_link +`timed_lock(boost::get_system_time()+rel_time)`].]] + +] +[endsect] + +[endsect] + +[section:shared_lockable `SharedLockable` Concept] + +The __shared_lockable_concept__ is a refinement of the __timed_lockable_concept__ that +allows for ['shared ownership] as well as ['exclusive ownership]. This is the +standard multiple-reader / single-write model: at most one thread can have +exclusive ownership, and if any thread does have exclusive ownership, no other threads +can have shared or exclusive ownership. Alternatively, many threads may have +shared ownership. + +For a type to implement the __shared_lockable_concept__, as well as meeting the +requirements of the __timed_lockable_concept__, it must also provide the following +member functions: + +* [lock_shared_ref_link `void lock_shared();`] +* [try_lock_shared_ref_link `bool try_lock_shared();`] +* [unlock_shared_ref_link `bool unlock_shared();`] +* [timed_lock_shared_ref_link `bool timed_lock_shared(boost::system_time const& abs_time);`] + +Lock ownership acquired through a call to __lock_shared_ref__, __try_lock_shared_ref__ or __timed_lock_shared_ref__ must be released +through a call to __unlock_shared_ref__. + +[section:lock_shared `void lock_shared()`] + +[variablelist + +[[Effects:] [The current thread blocks until shared ownership can be obtained for the current thread.]] + +[[Postcondition:] [The current thread has shared ownership of `*this`.]] + +[[Throws:] [__thread_resource_error__ if an error occurs.]] + +] +[endsect] + +[section:try_lock_shared `bool try_lock_shared()`] + +[variablelist + +[[Effects:] [Attempt to obtain shared ownership for the current thread without blocking.]] + +[[Returns:] [`true` if shared ownership was obtained for the current thread, `false` otherwise.]] + +[[Postcondition:] [If the call returns `true`, the current thread has shared ownership of `*this`.]] + +[[Throws:] [__thread_resource_error__ if an error occurs.]] + +] +[endsect] + +[section:timed_lock_shared `bool timed_lock_shared(boost::system_time const& abs_time)`] + +[variablelist + +[[Effects:] [Attempt to obtain shared ownership for the current thread. Blocks until shared ownership can be obtained, or the +specified time is reached. If the specified time has already passed, behaves as __try_lock_shared_ref__.]] + +[[Returns:] [`true` if shared ownership was acquired for the current thread, `false` otherwise.]] + +[[Postcondition:] [If the call returns `true`, the current thread has shared +ownership of `*this`.]] + +[[Throws:] [__thread_resource_error__ if an error occurs.]] + +] +[endsect] + +[section:unlock_shared `void unlock_shared()`] + +[variablelist + +[[Precondition:] [The current thread has shared ownership of `*this`.]] + +[[Effects:] [Releases shared ownership of `*this` by the current thread.]] + +[[Postcondition:] [The current thread no longer has shared ownership of `*this`.]] + +[[Throws:] [Nothing]] + +] +[endsect] + + +[endsect] + +[section:upgrade_lockable `UpgradeLockable` Concept] + +The __upgrade_lockable_concept__ is a refinement of the __shared_lockable_concept__ that allows for ['upgradable ownership] as well +as ['shared ownership] and ['exclusive ownership]. This is an extension to the multiple-reader / single-write model provided by the +__shared_lockable_concept__: a single thread may have ['upgradable ownership] at the same time as others have ['shared +ownership]. The thread with ['upgradable ownership] may at any time attempt to upgrade that ownership to ['exclusive ownership]. If +no other threads have shared ownership, the upgrade is completed immediately, and the thread now has ['exclusive ownership], which +must be relinquished by a call to __unlock_ref__, just as if it had been acquired by a call to __lock_ref__. + +If a thread with ['upgradable ownership] tries to upgrade whilst other threads have ['shared ownership], the attempt will fail and +the thread will block until ['exclusive ownership] can be acquired. + +Ownership can also be ['downgraded] as well as ['upgraded]: exclusive ownership of an implementation of the +__upgrade_lockable_concept__ can be downgraded to upgradable ownership or shared ownership, and upgradable ownership can be +downgraded to plain shared ownership. + +For a type to implement the __upgrade_lockable_concept__, as well as meeting the +requirements of the __shared_lockable_concept__, it must also provide the following +member functions: + +* [lock_upgrade_ref_link `void lock_upgrade();`] +* [unlock_upgrade_ref_link `bool unlock_upgrade();`] +* [unlock_upgrade_and_lock_ref_link `void unlock_upgrade_and_lock();`] +* [unlock_and_lock_upgrade_ref_link `void unlock_and_lock_upgrade();`] +* [unlock_upgrade_and_lock_shared_ref_link `void unlock_upgrade_and_lock_shared();`] + +Lock ownership acquired through a call to __lock_upgrade_ref__ must be released through a call to __unlock_upgrade_ref__. If the +ownership type is changed through a call to one of the `unlock_xxx_and_lock_yyy()` functions, ownership must be released through a +call to the unlock function corresponding to the new level of ownership. + + +[section:lock_upgrade `void lock_upgrade()`] + +[variablelist + +[[Effects:] [The current thread blocks until upgrade ownership can be obtained for the current thread.]] + +[[Postcondition:] [The current thread has upgrade ownership of `*this`.]] + +[[Throws:] [__thread_resource_error__ if an error occurs.]] + +] +[endsect] + +[section:unlock_upgrade `void unlock_upgrade()`] + +[variablelist + +[[Precondition:] [The current thread has upgrade ownership of `*this`.]] + +[[Effects:] [Releases upgrade ownership of `*this` by the current thread.]] + +[[Postcondition:] [The current thread no longer has upgrade ownership of `*this`.]] + +[[Throws:] [Nothing]] + +] +[endsect] + +[section:unlock_upgrade_and_lock `void unlock_upgrade_and_lock()`] + +[variablelist + +[[Precondition:] [The current thread has upgrade ownership of `*this`.]] + +[[Effects:] [Atomically releases upgrade ownership of `*this` by the current thread and acquires exclusive ownership of `*this`. If +any other threads have shared ownership, blocks until exclusive ownership can be acquired.]] + +[[Postcondition:] [The current thread has exclusive ownership of `*this`.]] + +[[Throws:] [Nothing]] + +] +[endsect] + +[section:unlock_upgrade_and_lock_shared `void unlock_upgrade_and_lock_shared()`] + +[variablelist + +[[Precondition:] [The current thread has upgrade ownership of `*this`.]] + +[[Effects:] [Atomically releases upgrade ownership of `*this` by the current thread and acquires shared ownership of `*this` without +blocking.]] + +[[Postcondition:] [The current thread has shared ownership of `*this`.]] + +[[Throws:] [Nothing]] + +] +[endsect] + +[section:unlock_and_lock_upgrade `void unlock_and_lock_upgrade()`] + +[variablelist + +[[Precondition:] [The current thread has exclusive ownership of `*this`.]] + +[[Effects:] [Atomically releases exclusive ownership of `*this` by the current thread and acquires upgrade ownership of `*this` +without blocking.]] + +[[Postcondition:] [The current thread has upgrade ownership of `*this`.]] + +[[Throws:] [Nothing]] + +] +[endsect] + +[endsect] + +[endsect] + +[section:locks Lock Types] + +[section:lock_guard Class template `lock_guard`] + + #include + + template + class lock_guard + { + public: + explicit lock_guard(Lockable& m_); + lock_guard(Lockable& m_,boost::adopt_lock_t); + + ~lock_guard(); + }; + +__lock_guard__ is very simple: on construction it +acquires ownership of the implementation of the __lockable_concept__ supplied as +the constructor parameter. On destruction, the ownership is released. This +provides simple RAII-style locking of a __lockable_concept_type__ object, to facilitate exception-safe +locking and unlocking. In addition, the [link +thread.synchronization.locks.lock_guard.constructor_adopt `lock_guard(Lockable & +m,boost::adopt_lock_t)` constructor] allows the __lock_guard__ object to +take ownership of a lock already held by the current thread. + +[section:constructor `lock_guard(Lockable & m)`] + +[variablelist + +[[Effects:] [Stores a reference to `m`. Invokes [lock_ref_link `m.lock()`].]] + +[[Throws:] [Any exception thrown by the call to [lock_ref_link `m.lock()`].]] + +] + +[endsect] + +[section:constructor_adopt `lock_guard(Lockable & m,boost::adopt_lock_t)`] + +[variablelist + +[[Precondition:] [The current thread owns a lock on `m` equivalent to one +obtained by a call to [lock_ref_link `m.lock()`].]] + +[[Effects:] [Stores a reference to `m`. Takes ownership of the lock state of +`m`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:destructor `~lock_guard()`] + +[variablelist + +[[Effects:] [Invokes [unlock_ref_link `m.unlock()`] on the __lockable_concept_type__ +object passed to the constructor.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[endsect] + +[section:unique_lock Class template `unique_lock`] + + #include + + template + class unique_lock + { + public: + unique_lock(); + explicit unique_lock(Lockable& m_); + unique_lock(Lockable& m_,adopt_lock_t); + unique_lock(Lockable& m_,defer_lock_t); + unique_lock(Lockable& m_,try_to_lock_t); + unique_lock(Lockable& m_,system_time const& target_time); + + ~unique_lock(); + + unique_lock(detail::thread_move_t > other); + unique_lock(detail::thread_move_t > other); + + operator detail::thread_move_t >(); + detail::thread_move_t > move(); + unique_lock& operator=(detail::thread_move_t > other); + unique_lock& operator=(detail::thread_move_t > other); + + void swap(unique_lock& other); + void swap(detail::thread_move_t > other); + + void lock(); + bool try_lock(); + + template + bool timed_lock(TimeDuration const& relative_time); + bool timed_lock(::boost::system_time const& absolute_time); + + void unlock(); + + bool owns_lock() const; + operator ``['unspecified-bool-type]``() const; + bool operator!() const; + + Lockable* mutex() const; + Lockable* release(); + }; + +__unique_lock__ is more complex than __lock_guard__: not only does it provide for RAII-style locking, it also allows for deferring +acquiring the lock until the __lock_ref__ member function is called explicitly, or trying to acquire the lock in a non-blocking +fashion, or with a timeout. Consequently, __unlock_ref__ is only called in the destructor if the lock object has locked the +__lockable_concept_type__ object, or otherwise adopted a lock on the __lockable_concept_type__ object. + +Specializations of __unique_lock__ model the __timed_lockable_concept__ if the supplied __lockable_concept_type__ type itself models +__timed_lockable_concept__ (e.g. `boost::unique_lock`), or the __lockable_concept__ otherwise +(e.g. `boost::unique_lock`). + +An instance of __unique_lock__ is said to ['own] the lock state of a __lockable_concept_type__ `m` if __mutex_func_ref__ returns a +pointer to `m` and __owns_lock_ref__ returns `true`. If an object that ['owns] the lock state of a __lockable_concept_type__ object +is destroyed, then the destructor will invoke [unlock_ref_link `mutex()->unlock()`]. + +The member functions of __unique_lock__ are not thread-safe. In particular, __unique_lock__ is intended to model the ownership of a +__lockable_concept_type__ object by a particular thread, and the member functions that release ownership of the lock state +(including the destructor) must be called by the same thread that acquired ownership of the lock state. + +[section:defaultconstructor `unique_lock()`] + +[variablelist + +[[Effects:] [Creates a lock object with no associated mutex.]] + +[[Postcondition:] [__owns_lock_ref__ returns `false`. __mutex_func_ref__ returns `NULL`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:constructor `unique_lock(Lockable & m)`] + +[variablelist + +[[Effects:] [Stores a reference to `m`. Invokes [lock_ref_link `m.lock()`].]] + +[[Postcondition:] [__owns_lock_ref__ returns `true`. __mutex_func_ref__ returns `&m`.]] + +[[Throws:] [Any exception thrown by the call to [lock_ref_link `m.lock()`].]] + +] + +[endsect] + +[section:constructor_adopt `unique_lock(Lockable & m,boost::adopt_lock_t)`] + +[variablelist + +[[Precondition:] [The current thread owns an exclusive lock on `m`.]] + +[[Effects:] [Stores a reference to `m`. Takes ownership of the lock state of `m`.]] + +[[Postcondition:] [__owns_lock_ref__ returns `true`. __mutex_func_ref__ returns `&m`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:constructor_defer `unique_lock(Lockable & m,boost::defer_lock_t)`] + +[variablelist + +[[Effects:] [Stores a reference to `m`.]] + +[[Postcondition:] [__owns_lock_ref__ returns `false`. __mutex_func_ref__ returns `&m`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:constructor_try `unique_lock(Lockable & m,boost::try_to_lock_t)`] + +[variablelist + +[[Effects:] [Stores a reference to `m`. Invokes [try_lock_ref_link +`m.try_lock()`], and takes ownership of the lock state if the call returns +`true`.]] + +[[Postcondition:] [__mutex_func_ref__ returns `&m`. If the call to __try_lock_ref__ +returned `true`, then __owns_lock_ref__ returns `true`, otherwise __owns_lock_ref__ +returns `false`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:constructor_abs_time `unique_lock(Lockable & m,boost::system_time const& abs_time)`] + +[variablelist + +[[Effects:] [Stores a reference to `m`. Invokes [timed_lock_ref_link +`m.timed_lock(abs_time)`], and takes ownership of the lock state if the call +returns `true`.]] + +[[Postcondition:] [__mutex_func_ref__ returns `&m`. If the call to __timed_lock_ref__ +returned `true`, then __owns_lock_ref__ returns `true`, otherwise __owns_lock_ref__ +returns `false`.]] + +[[Throws:] [Any exceptions thrown by the call to [timed_lock_ref_link `m.timed_lock(abs_time)`].]] + +] + +[endsect] + +[section:destructor `~unique_lock()`] + +[variablelist + +[[Effects:] [Invokes __mutex_func_ref__`->`[unlock_ref_link `unlock()`] if +__owns_lock_ref__ returns `true`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:owns_lock `bool owns_lock() const`] + +[variablelist + +[[Returns:] [`true` if the `*this` owns the lock on the __lockable_concept_type__ +object associated with `*this`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:mutex `Lockable* mutex() const`] + +[variablelist + +[[Returns:] [A pointer to the __lockable_concept_type__ object associated with +`*this`, or `NULL` if there is no such object.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:bool_conversion `operator unspecified-bool-type() const`] + +[variablelist + +[[Returns:] [If __owns_lock_ref__ would return `true`, a value that evaluates to +`true` in boolean contexts, otherwise a value that evaluates to `false` in +boolean contexts.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:operator_not `bool operator!() const`] + +[variablelist + +[[Returns:] [`!` __owns_lock_ref__.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:release `Lockable* release()`] + +[variablelist + +[[Effects:] [The association between `*this` and the __lockable_concept_type__ object is removed, without affecting the lock state +of the __lockable_concept_type__ object. If __owns_lock_ref__ would have returned `true`, it is the responsibility of the calling +code to ensure that the __lockable_concept_type__ is correctly unlocked.]] + +[[Returns:] [A pointer to the __lockable_concept_type__ object associated with `*this` at the point of the call, or `NULL` if there +is no such object.]] + +[[Throws:] [Nothing.]] + +[[Postcondition:] [`*this` is no longer associated with any __lockable_concept_type__ object. __mutex_func_ref__ returns `NULL` and +__owns_lock_ref__ returns `false`.]] + +] + +[endsect] + +[endsect] + +[section:shared_lock Class template `shared_lock`] + + #include + + template + class shared_lock + { + public: + shared_lock(); + explicit shared_lock(Lockable& m_); + shared_lock(Lockable& m_,adopt_lock_t); + shared_lock(Lockable& m_,defer_lock_t); + shared_lock(Lockable& m_,try_to_lock_t); + shared_lock(Lockable& m_,system_time const& target_time); + shared_lock(detail::thread_move_t > other); + shared_lock(detail::thread_move_t > other); + shared_lock(detail::thread_move_t > other); + + ~shared_lock(); + + operator detail::thread_move_t >(); + detail::thread_move_t > move(); + + shared_lock& operator=(detail::thread_move_t > other); + shared_lock& operator=(detail::thread_move_t > other); + shared_lock& operator=(detail::thread_move_t > other); + void swap(shared_lock& other); + + void lock(); + bool try_lock(); + bool timed_lock(boost::system_time const& target_time); + void unlock(); + + operator ``['unspecified-bool-type]``() const; + bool operator!() const; + bool owns_lock() const; + }; + +Like __unique_lock__, __shared_lock__ models the __lockable_concept__, but rather than acquiring unique ownership of the supplied +__lockable_concept_type__ object, locking an instance of __shared_lock__ acquires shared ownership. + +Like __unique_lock__, not only does it provide for RAII-style locking, it also allows for deferring acquiring the lock until the +__lock_ref__ member function is called explicitly, or trying to acquire the lock in a non-blocking fashion, or with a +timeout. Consequently, __unlock_ref__ is only called in the destructor if the lock object has locked the __lockable_concept_type__ +object, or otherwise adopted a lock on the __lockable_concept_type__ object. + +An instance of __shared_lock__ is said to ['own] the lock state of a __lockable_concept_type__ `m` if __mutex_func_ref__ returns a +pointer to `m` and __owns_lock_ref__ returns `true`. If an object that ['owns] the lock state of a __lockable_concept_type__ object +is destroyed, then the destructor will invoke [unlock_shared_ref_link `mutex()->unlock_shared()`]. + +The member functions of __shared_lock__ are not thread-safe. In particular, __shared_lock__ is intended to model the shared +ownership of a __lockable_concept_type__ object by a particular thread, and the member functions that release ownership of the lock +state (including the destructor) must be called by the same thread that acquired ownership of the lock state. + +[section:defaultconstructor `shared_lock()`] + +[variablelist + +[[Effects:] [Creates a lock object with no associated mutex.]] + +[[Postcondition:] [__owns_lock_ref__ returns `false`. __mutex_func_ref__ returns `NULL`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:constructor `shared_lock(Lockable & m)`] + +[variablelist + +[[Effects:] [Stores a reference to `m`. Invokes [lock_shared_ref_link `m.lock_shared()`].]] + +[[Postcondition:] [__owns_lock_shared_ref__ returns `true`. __mutex_func_ref__ returns `&m`.]] + +[[Throws:] [Any exception thrown by the call to [lock_shared_ref_link `m.lock_shared()`].]] + +] + +[endsect] + +[section:constructor_adopt `shared_lock(Lockable & m,boost::adopt_lock_t)`] + +[variablelist + +[[Precondition:] [The current thread owns an exclusive lock on `m`.]] + +[[Effects:] [Stores a reference to `m`. Takes ownership of the lock state of `m`.]] + +[[Postcondition:] [__owns_lock_shared_ref__ returns `true`. __mutex_func_ref__ returns `&m`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:constructor_defer `shared_lock(Lockable & m,boost::defer_lock_t)`] + +[variablelist + +[[Effects:] [Stores a reference to `m`.]] + +[[Postcondition:] [__owns_lock_shared_ref__ returns `false`. __mutex_func_ref__ returns `&m`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:constructor_try `shared_lock(Lockable & m,boost::try_to_lock_t)`] + +[variablelist + +[[Effects:] [Stores a reference to `m`. Invokes [try_lock_shared_ref_link +`m.try_lock_shared()`], and takes ownership of the lock state if the call returns +`true`.]] + +[[Postcondition:] [__mutex_func_ref__ returns `&m`. If the call to __try_lock_shared_ref__ +returned `true`, then __owns_lock_shared_ref__ returns `true`, otherwise __owns_lock_shared_ref__ +returns `false`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:constructor_abs_time `shared_lock(Lockable & m,boost::system_time const& abs_time)`] + +[variablelist + +[[Effects:] [Stores a reference to `m`. Invokes [timed_lock_shared_ref_link +`m.timed_lock(abs_time)`], and takes ownership of the lock state if the call +returns `true`.]] + +[[Postcondition:] [__mutex_func_ref__ returns `&m`. If the call to __timed_lock_shared_ref__ +returned `true`, then __owns_lock_shared_ref__ returns `true`, otherwise __owns_lock_shared_ref__ +returns `false`.]] + +[[Throws:] [Any exceptions thrown by the call to [timed_lock_shared_ref_link `m.timed_lock(abs_time)`].]] + +] + +[endsect] + +[section:destructor `~shared_lock()`] + +[variablelist + +[[Effects:] [Invokes __mutex_func_ref__`->`[unlock_shared_ref_link `unlock_shared()`] if +__owns_lock_shared_ref__ returns `true`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:owns_lock `bool owns_lock() const`] + +[variablelist + +[[Returns:] [`true` if the `*this` owns the lock on the __lockable_concept_type__ +object associated with `*this`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:mutex `Lockable* mutex() const`] + +[variablelist + +[[Returns:] [A pointer to the __lockable_concept_type__ object associated with +`*this`, or `NULL` if there is no such object.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:bool_conversion `operator unspecified-bool-type() const`] + +[variablelist + +[[Returns:] [If __owns_lock_shared_ref__ would return `true`, a value that evaluates to +`true` in boolean contexts, otherwise a value that evaluates to `false` in +boolean contexts.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:operator_not `bool operator!() const`] + +[variablelist + +[[Returns:] [`!` __owns_lock_shared_ref__.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:release `Lockable* release()`] + +[variablelist + +[[Effects:] [The association between `*this` and the __lockable_concept_type__ object is removed, without affecting the lock state +of the __lockable_concept_type__ object. If __owns_lock_shared_ref__ would have returned `true`, it is the responsibility of the calling +code to ensure that the __lockable_concept_type__ is correctly unlocked.]] + +[[Returns:] [A pointer to the __lockable_concept_type__ object associated with `*this` at the point of the call, or `NULL` if there +is no such object.]] + +[[Throws:] [Nothing.]] + +[[Postcondition:] [`*this` is no longer associated with any __lockable_concept_type__ object. __mutex_func_ref__ returns `NULL` and +__owns_lock_shared_ref__ returns `false`.]] + +] + +[endsect] + +[endsect] + +[section:upgrade_lock Class template `upgrade_lock`] + + #include + + template + class upgrade_lock + { + public: + explicit upgrade_lock(Lockable& m_); + + upgrade_lock(detail::thread_move_t > other); + upgrade_lock(detail::thread_move_t > other); + + ~upgrade_lock(); + + operator detail::thread_move_t >(); + detail::thread_move_t > move(); + + upgrade_lock& operator=(detail::thread_move_t > other); + upgrade_lock& operator=(detail::thread_move_t > other); + + void swap(upgrade_lock& other); + + void lock(); + void unlock(); + + operator ``['unspecified-bool-type]``() const; + bool operator!() const; + bool owns_lock() const; + }; + +Like __unique_lock__, __upgrade_lock__ models the __lockable_concept__, but rather than acquiring unique ownership of the supplied +__lockable_concept_type__ object, locking an instance of __upgrade_lock__ acquires upgrade ownership. + +Like __unique_lock__, not only does it provide for RAII-style locking, it also allows for deferring acquiring the lock until the +__lock_ref__ member function is called explicitly, or trying to acquire the lock in a non-blocking fashion, or with a +timeout. Consequently, __unlock_ref__ is only called in the destructor if the lock object has locked the __lockable_concept_type__ +object, or otherwise adopted a lock on the __lockable_concept_type__ object. + +An instance of __upgrade_lock__ is said to ['own] the lock state of a __lockable_concept_type__ `m` if __mutex_func_ref__ returns a +pointer to `m` and __owns_lock_ref__ returns `true`. If an object that ['owns] the lock state of a __lockable_concept_type__ object +is destroyed, then the destructor will invoke [unlock_upgrade_ref_link `mutex()->unlock_upgrade()`]. + +The member functions of __upgrade_lock__ are not thread-safe. In particular, __upgrade_lock__ is intended to model the upgrade +ownership of a __lockable_concept_type__ object by a particular thread, and the member functions that release ownership of the lock +state (including the destructor) must be called by the same thread that acquired ownership of the lock state. + +[endsect] + +[section:upgrade_to_unique_lock Class template `upgrade_to_unique_lock`] + + #include + + template + class upgrade_to_unique_lock + { + public: + explicit upgrade_to_unique_lock(upgrade_lock& m_); + + ~upgrade_to_unique_lock(); + + upgrade_to_unique_lock(detail::thread_move_t > other); + upgrade_to_unique_lock& operator=(detail::thread_move_t > other); + void swap(upgrade_to_unique_lock& other); + + operator ``['unspecified-bool-type]``() const; + bool operator!() const; + bool owns_lock() const; + }; + +__upgrade_to_unique_lock__ allows for a temporary upgrade of an __upgrade_lock__ to exclusive ownership. When constructed with a +reference to an instance of __upgrade_lock__, if that instance has upgrade ownership on some __lockable_concept_type__ object, that +ownership is upgraded to exclusive ownership. When the __upgrade_to_unique_lock__ instance is destroyed, the ownership of the +__lockable_concept_type__ is downgraded back to ['upgrade ownership]. + +[endsect] + +[section:scoped_try_lock Mutex-specific class `scoped_try_lock`] + + class MutexType::scoped_try_lock + { + private: + MutexType::scoped_try_lock(MutexType::scoped_try_lock& other); + MutexType::scoped_try_lock& operator=(MutexType::scoped_try_lock& other); + public: + MutexType::scoped_try_lock(); + explicit MutexType::scoped_try_lock(MutexType& m); + MutexType::scoped_try_lock(MutexType& m_,adopt_lock_t); + MutexType::scoped_try_lock(MutexType& m_,defer_lock_t); + MutexType::scoped_try_lock(MutexType& m_,try_to_lock_t); + + MutexType::scoped_try_lock(MutexType::scoped_try_lock&& other); + MutexType::scoped_try_lock& operator=(MutexType::scoped_try_lock&& other); + + void swap(MutexType::scoped_try_lock&& other); + + void lock(); + bool try_lock(); + void unlock(); + bool owns_lock() const; + + MutexType* mutex() const; + MutexType* release(); + bool operator!() const; + + typedef ``['unspecified-bool-type]`` bool_type; + operator bool_type() const; + }; + +The member typedef `scoped_try_lock` is provided for each distinct +`MutexType` as a typedef to a class with the preceding definition. The +semantics of each constructor and member function are identical to +those of [unique_lock_link `boost::unique_lock`] for the same `MutexType`, except +that the constructor that takes a single reference to a mutex will +call [try_lock_ref_link `m.try_lock()`] rather than `m.lock()`. + + +[endsect] + +[endsect] + +[section:lock_functions Lock functions] + +[section:lock_multiple Non-member function `lock(Lockable1,Lockable2,...)`] + + template + void lock(Lockable1& l1,Lockable2& l2); + + template + void lock(Lockable1& l1,Lockable2& l2,Lockable3& l3); + + template + void lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4); + + template + void lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4,Lockable5& l5); + +[variablelist + +[[Effects:] [Locks the __lockable_concept_type__ objects supplied as +arguments in an unspecified and indeterminate order in a way that +avoids deadlock. It is safe to call this function concurrently from +multiple threads with the same mutexes (or other lockable objects) in +different orders without risk of deadlock. If any of the __lock_ref__ +or __try_lock_ref__ operations on the supplied +__lockable_concept_type__ objects throws an exception any locks +acquired by the function will be released before the function exits.]] + +[[Throws:] [Any exceptions thrown by calling __lock_ref__ or +__try_lock_ref__ on the supplied __lockable_concept_type__ objects.]] + +[[Postcondition:] [All the supplied __lockable_concept_type__ objects +are locked by the calling thread.]] + +] + +[endsect] + +[section:lock_range Non-member function `lock(begin,end)`] + + template + void lock(ForwardIterator begin,ForwardIterator end); + +[variablelist + +[[Preconditions:] [The `value_type` of `ForwardIterator` must implement the __lockable_concept__]] + +[[Effects:] [Locks all the __lockable_concept_type__ objects in the +supplied range in an unspecified and indeterminate order in a way that +avoids deadlock. It is safe to call this function concurrently from +multiple threads with the same mutexes (or other lockable objects) in +different orders without risk of deadlock. If any of the __lock_ref__ +or __try_lock_ref__ operations on the __lockable_concept_type__ +objects in the supplied range throws an exception any locks acquired +by the function will be released before the function exits.]] + +[[Throws:] [Any exceptions thrown by calling __lock_ref__ or +__try_lock_ref__ on the supplied __lockable_concept_type__ objects.]] + +[[Postcondition:] [All the __lockable_concept_type__ objects in the +supplied range are locked by the calling thread.]] + +] + +[endsect] + +[section:try_lock_multiple Non-member function `try_lock(Lockable1,Lockable2,...)`] + + template + int try_lock(Lockable1& l1,Lockable2& l2); + + template + int try_lock(Lockable1& l1,Lockable2& l2,Lockable3& l3); + + template + int try_lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4); + + template + int try_lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4,Lockable5& l5); + +[variablelist + +[[Effects:] [Calls __try_lock_ref__ on each of the +__lockable_concept_type__ objects supplied as arguments. If any of the +calls to __try_lock_ref__ returns `false` then all locks acquired are +released and the zero-based index of the failed lock is returned. + +If any of the __try_lock_ref__ operations on the supplied +__lockable_concept_type__ objects throws an exception any locks +acquired by the function will be released before the function exits.]] + +[[Returns:] [`-1` if all the supplied __lockable_concept_type__ objects +are now locked by the calling thread, the zero-based index of the +object which could not be locked otherwise.]] + +[[Throws:] [Any exceptions thrown by calling __try_lock_ref__ on the +supplied __lockable_concept_type__ objects.]] + +[[Postcondition:] [If the function returns `-1`, all the supplied +__lockable_concept_type__ objects are locked by the calling +thread. Otherwise any locks acquired by this function will have been +released.]] + +] + +[endsect] + +[section:try_lock_range Non-member function `try_lock(begin,end)`] + + template + ForwardIterator try_lock(ForwardIterator begin,ForwardIterator end); + +[variablelist + +[[Preconditions:] [The `value_type` of `ForwardIterator` must implement the __lockable_concept__]] + +[[Effects:] [Calls __try_lock_ref__ on each of the +__lockable_concept_type__ objects in the supplied range. If any of the +calls to __try_lock_ref__ returns `false` then all locks acquired are +released and an iterator referencing the failed lock is returned. + +If any of the __try_lock_ref__ operations on the supplied +__lockable_concept_type__ objects throws an exception any locks +acquired by the function will be released before the function exits.]] + +[[Returns:] [`end` if all the supplied __lockable_concept_type__ +objects are now locked by the calling thread, an iterator referencing +the object which could not be locked otherwise.]] + +[[Throws:] [Any exceptions thrown by calling __try_lock_ref__ on the +supplied __lockable_concept_type__ objects.]] + +[[Postcondition:] [If the function returns `end` then all the +__lockable_concept_type__ objects in the supplied range are locked by +the calling thread, otherwise all locks acquired by the function have +been released.]] + +] + +[endsect] + + +[endsect] diff --git a/deal.II/contrib/boost/libs/thread/doc/mutexes.qbk b/deal.II/contrib/boost/libs/thread/doc/mutexes.qbk new file mode 100644 index 0000000000..ddea86a4bb --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/doc/mutexes.qbk @@ -0,0 +1,224 @@ +[/ + (C) Copyright 2007-8 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). +] + +[section:mutex_types Mutex Types] + +[section:mutex Class `mutex`] + + #include + + class mutex: + boost::noncopyable + { + public: + mutex(); + ~mutex(); + + void lock(); + bool try_lock(); + void unlock(); + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); + + typedef unique_lock scoped_lock; + typedef unspecified-type scoped_try_lock; + }; + +__mutex__ implements the __lockable_concept__ to provide an exclusive-ownership mutex. At most one thread can own the lock on a given +instance of __mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__ and __unlock_ref__ shall be permitted. + +[section:nativehandle Member function `native_handle()`] + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); + +[variablelist + +[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying +implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + + +[endsect] + +[section:try_mutex Typedef `try_mutex`] + + #include + + typedef mutex try_mutex; + +__try_mutex__ is a `typedef` to __mutex__, provided for backwards compatibility with previous releases of boost. + +[endsect] + +[section:timed_mutex Class `timed_mutex`] + + #include + + class timed_mutex: + boost::noncopyable + { + public: + timed_mutex(); + ~timed_mutex(); + + void lock(); + void unlock(); + bool try_lock(); + bool timed_lock(system_time const & abs_time); + + template + bool timed_lock(TimeDuration const & relative_time); + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); + + typedef unique_lock scoped_timed_lock; + typedef unspecified-type scoped_try_lock; + typedef scoped_timed_lock scoped_lock; + }; + +__timed_mutex__ implements the __timed_lockable_concept__ to provide an exclusive-ownership mutex. At most one thread can own the +lock on a given instance of __timed_mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__, +__timed_lock_ref__, __timed_lock_duration_ref__ and __unlock_ref__ shall be permitted. + +[section:nativehandle Member function `native_handle()`] + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); + +[variablelist + +[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying +implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[endsect] + +[section:recursive_mutex Class `recursive_mutex`] + + #include + + class recursive_mutex: + boost::noncopyable + { + public: + recursive_mutex(); + ~recursive_mutex(); + + void lock(); + bool try_lock(); + void unlock(); + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); + + typedef unique_lock scoped_lock; + typedef unspecified-type scoped_try_lock; + }; + +__recursive_mutex__ implements the __lockable_concept__ to provide an exclusive-ownership recursive mutex. At most one thread can +own the lock on a given instance of __recursive_mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__ and +__unlock_ref__ shall be permitted. A thread that already has exclusive ownership of a given __recursive_mutex__ instance can call +__lock_ref__ or __try_lock_ref__ to acquire an additional level of ownership of the mutex. __unlock_ref__ must be called once for +each level of ownership acquired by a single thread before ownership can be acquired by another thread. + +[section:nativehandle Member function `native_handle()`] + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); + +[variablelist + +[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying +implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[endsect] + +[section:recursive_try_mutex Typedef `recursive_try_mutex`] + + #include + + typedef recursive_mutex recursive_try_mutex; + +__recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for backwards compatibility with previous releases of boost. + +[endsect] + +[section:recursive_timed_mutex Class `recursive_timed_mutex`] + + #include + + class recursive_timed_mutex: + boost::noncopyable + { + public: + recursive_timed_mutex(); + ~recursive_timed_mutex(); + + void lock(); + bool try_lock(); + void unlock(); + + bool timed_lock(system_time const & abs_time); + + template + bool timed_lock(TimeDuration const & relative_time); + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); + + typedef unique_lock scoped_lock; + typedef unspecified-type scoped_try_lock; + typedef scoped_lock scoped_timed_lock; + }; + +__recursive_timed_mutex__ implements the __timed_lockable_concept__ to provide an exclusive-ownership recursive mutex. At most one +thread can own the lock on a given instance of __recursive_timed_mutex__ at any time. Multiple concurrent calls to __lock_ref__, +__try_lock_ref__, __timed_lock_ref__, __timed_lock_duration_ref__ and __unlock_ref__ shall be permitted. A thread that already has +exclusive ownership of a given __recursive_timed_mutex__ instance can call __lock_ref__, __timed_lock_ref__, +__timed_lock_duration_ref__ or __try_lock_ref__ to acquire an additional level of ownership of the mutex. __unlock_ref__ must be +called once for each level of ownership acquired by a single thread before ownership can be acquired by another thread. + +[section:nativehandle Member function `native_handle()`] + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); + +[variablelist + +[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying +implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[endsect] + +[include shared_mutex_ref.qbk] + +[endsect] diff --git a/deal.II/contrib/boost/libs/thread/doc/once.qbk b/deal.II/contrib/boost/libs/thread/doc/once.qbk new file mode 100644 index 0000000000..fd53e7dee1 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/doc/once.qbk @@ -0,0 +1,56 @@ +[/ + (C) Copyright 2007-8 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). +] + +[section:once One-time Initialization] + +`boost::call_once` provides a mechanism for ensuring that an initialization routine is run exactly once without data races or deadlocks. + +[section:once_flag Typedef `once_flag`] + + #include + + typedef platform-specific-type once_flag; + #define BOOST_ONCE_INIT platform-specific-initializer + +Objects of type `boost::once_flag` shall be initialized with `BOOST_ONCE_INIT`: + + boost::once_flag f=BOOST_ONCE_INIT; + +[endsect] + +[section:call_once Non-member function `call_once`] + + #include + + template + void call_once(once_flag& flag,Callable func); + +[variablelist + +[[Requires:] [`Callable` is `CopyConstructible`. Copying `func` shall have no side effects, and the effect of calling the copy shall +be equivalent to calling the original. ]] + +[[Effects:] [Calls to `call_once` on the same `once_flag` object are serialized. If there has been no prior effective `call_once` on +the same `once_flag` object, the argument `func` (or a copy thereof) is called as-if by invoking `func()`, and the invocation of +`call_once` is effective if and only if `func()` returns without exception. If an exception is thrown, the exception is +propagated to the caller. If there has been a prior effective `call_once` on the same `once_flag` object, the `call_once` returns +without invoking `func`. ]] + +[[Synchronization:] [The completion of an effective `call_once` invocation on a `once_flag` object, synchronizes with +all subsequent `call_once` invocations on the same `once_flag` object. ]] + +[[Throws:] [`thread_resource_error` when the effects cannot be achieved. or any exception propagated from `func`.]] + +] + + void call_once(void (*func)(),once_flag& flag); + +This second overload is provided for backwards compatibility. The effects of `call_once(func,flag)` shall be the same as those of +`call_once(flag,func)`. + +[endsect] +[endsect] diff --git a/deal.II/contrib/boost/libs/thread/doc/overview.qbk b/deal.II/contrib/boost/libs/thread/doc/overview.qbk new file mode 100644 index 0000000000..c647a6d219 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/doc/overview.qbk @@ -0,0 +1,30 @@ +[/ + (C) Copyright 2007-8 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). +] + +[section:overview Overview] + +__boost_thread__ enables the use of multiple threads of execution with shared data in portable C++ code. It provides classes and +functions for managing the threads themselves, along with others for synchronizing data between the threads or providing separate +copies of data specific to individual threads. + +The __boost_thread__ library was originally written and designed by William E. Kempf. This version is a major rewrite designed to +closely follow the proposals presented to the C++ Standards Committee, in particular +[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2497.html N2497], +[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2320.html N2320], +[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2184.html N2184], +[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2139.html N2139], and +[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2094.html N2094] + +In order to use the classes and functions described here, you can +either include the specific headers specified by the descriptions of +each class or function, or include the master thread library header: + + #include + +which includes all the other headers in turn. + +[endsect] diff --git a/deal.II/contrib/boost/libs/thread/doc/shared_mutex_ref.qbk b/deal.II/contrib/boost/libs/thread/doc/shared_mutex_ref.qbk new file mode 100644 index 0000000000..49cd16737a --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/doc/shared_mutex_ref.qbk @@ -0,0 +1,44 @@ +[/ + (C) Copyright 2007-8 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). +] + +[section:shared_mutex Class `shared_mutex`] + + #include + + class shared_mutex + { + public: + shared_mutex(); + ~shared_mutex(); + + void lock_shared(); + bool try_lock_shared(); + bool timed_lock_shared(system_time const& timeout); + void unlock_shared(); + + void lock(); + bool try_lock(); + bool timed_lock(system_time const& timeout); + void unlock(); + + void lock_upgrade(); + void unlock_upgrade(); + + void unlock_upgrade_and_lock(); + void unlock_and_lock_upgrade(); + void unlock_and_lock_shared(); + void unlock_upgrade_and_lock_shared(); + }; + +The class `boost::shared_mutex` provides an implementation of a multiple-reader / single-writer mutex. It implements the +__upgrade_lockable_concept__. + +Multiple concurrent calls to __lock_ref__, __try_lock_ref__, __timed_lock_ref__, __lock_shared_ref__, __try_lock_shared_ref__ and +__timed_lock_shared_ref__ shall be permitted. + + +[endsect] diff --git a/deal.II/contrib/boost/libs/thread/doc/thread.qbk b/deal.II/contrib/boost/libs/thread/doc/thread.qbk new file mode 100644 index 0000000000..e6346db6ec --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/doc/thread.qbk @@ -0,0 +1,167 @@ +[/ + (C) Copyright 2007-8 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). +] + +[article Thread + [quickbook 1.4] + [authors [Williams, Anthony]] + [copyright 2007-8 Anthony Williams] + [purpose C++ Library for launching threads and synchronizing data between them] + [category text] + [license + 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]) + ] +] + +[template lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.lockable [link_text]]] +[def __lockable_concept__ [lockable_concept_link `Lockable` concept]] +[def __lockable_concept_type__ [lockable_concept_link `Lockable`]] + +[template timed_lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable [link_text]]] +[def __timed_lockable_concept__ [timed_lockable_concept_link `TimedLockable` concept]] +[def __timed_lockable_concept_type__ [timed_lockable_concept_link `TimedLockable`]] + +[template shared_lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable [link_text]]] +[def __shared_lockable_concept__ [shared_lockable_concept_link `SharedLockable` concept]] +[def __shared_lockable_concept_type__ [shared_lockable_concept_link `SharedLockable`]] + +[template upgrade_lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable [link_text]]] +[def __upgrade_lockable_concept__ [upgrade_lockable_concept_link `UpgradeLockable` concept]] +[def __upgrade_lockable_concept_type__ [upgrade_lockable_concept_link `UpgradeLockable`]] + + +[template lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.lock [link_text]]] +[def __lock_ref__ [lock_ref_link `lock()`]] + +[template lock_multiple_ref_link[link_text] [link thread.synchronization.lock_functions.lock_multiple [link_text]]] +[def __lock_multiple_ref__ [lock_multiple_ref_link `lock()`]] + +[template try_lock_multiple_ref_link[link_text] [link thread.synchronization.lock_functions.try_lock_multiple [link_text]]] +[def __try_lock_multiple_ref__ [try_lock_multiple_ref_link `try_lock()`]] + +[template unlock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.unlock [link_text]]] +[def __unlock_ref__ [unlock_ref_link `unlock()`]] + +[template try_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.try_lock [link_text]]] +[def __try_lock_ref__ [try_lock_ref_link `try_lock()`]] + +[template timed_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable.timed_lock [link_text]]] +[def __timed_lock_ref__ [timed_lock_ref_link `timed_lock()`]] + +[template timed_lock_duration_ref_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable.timed_lock_duration [link_text]]] +[def __timed_lock_duration_ref__ [timed_lock_duration_ref_link `timed_lock()`]] + +[template lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.lock_shared [link_text]]] +[def __lock_shared_ref__ [lock_shared_ref_link `lock_shared()`]] + +[template unlock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.unlock_shared [link_text]]] +[def __unlock_shared_ref__ [unlock_shared_ref_link `unlock_shared()`]] + +[template try_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.try_lock_shared [link_text]]] +[def __try_lock_shared_ref__ [try_lock_shared_ref_link `try_lock_shared()`]] + +[template timed_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.timed_lock_shared [link_text]]] +[def __timed_lock_shared_ref__ [timed_lock_shared_ref_link `timed_lock_shared()`]] + +[template timed_lock_shared_duration_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.timed_lock_shared_duration [link_text]]] +[def __timed_lock_shared_duration_ref__ [timed_lock_shared_duration_ref_link `timed_lock_shared()`]] + +[template lock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.lock_upgrade [link_text]]] +[def __lock_upgrade_ref__ [lock_upgrade_ref_link `lock_upgrade()`]] + +[template unlock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade [link_text]]] +[def __unlock_upgrade_ref__ [unlock_upgrade_ref_link `unlock_upgrade()`]] + +[template unlock_upgrade_and_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade_and_lock [link_text]]] +[def __unlock_upgrade_and_lock_ref__ [unlock_upgrade_and_lock_ref_link `unlock_upgrade_and_lock()`]] + +[template unlock_and_lock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_and_lock_upgrade [link_text]]] +[def __unlock_and_lock_upgrade_ref__ [unlock_and_lock_upgrade_ref_link `unlock_and_lock_upgrade()`]] + +[template unlock_upgrade_and_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade_and_lock_shared [link_text]]] +[def __unlock_upgrade_and_lock_shared_ref__ [unlock_upgrade_and_lock_shared_ref_link `unlock_upgrade_and_lock_shared()`]] + +[template owns_lock_ref_link[link_text] [link thread.synchronization.locks.unique_lock.owns_lock [link_text]]] +[def __owns_lock_ref__ [owns_lock_ref_link `owns_lock()`]] + +[template owns_lock_shared_ref_link[link_text] [link thread.synchronization.locks.shared_lock.owns_lock [link_text]]] +[def __owns_lock_shared_ref__ [owns_lock_shared_ref_link `owns_lock()`]] + +[template mutex_func_ref_link[link_text] [link thread.synchronization.locks.unique_lock.mutex [link_text]]] +[def __mutex_func_ref__ [mutex_func_ref_link `mutex()`]] + +[def __boost_thread__ [*Boost.Thread]] +[def __not_a_thread__ ['Not-a-Thread]] +[def __interruption_points__ [link interruption_points ['interruption points]]] + +[def __mutex__ [link thread.synchronization.mutex_types.mutex `boost::mutex`]] +[def __try_mutex__ [link thread.synchronization.mutex_types.try_mutex `boost::try_mutex`]] +[def __timed_mutex__ [link thread.synchronization.mutex_types.timed_mutex `boost::timed_mutex`]] +[def __recursive_mutex__ [link thread.synchronization.mutex_types.recursive_mutex `boost::recursive_mutex`]] +[def __recursive_try_mutex__ [link thread.synchronization.mutex_types.recursive_try_mutex `boost::recursive_try_mutex`]] +[def __recursive_timed_mutex__ [link thread.synchronization.mutex_types.recursive_timed_mutex `boost::recursive_timed_mutex`]] +[def __shared_mutex__ [link thread.synchronization.mutex_types.shared_mutex `boost::shared_mutex`]] + +[template unique_lock_link[link_text] [link thread.synchronization.locks.unique_lock [link_text]]] + +[def __lock_guard__ [link thread.synchronization.locks.lock_guard `boost::lock_guard`]] +[def __unique_lock__ [unique_lock_link `boost::unique_lock`]] +[def __shared_lock__ [link thread.synchronization.locks.shared_lock `boost::shared_lock`]] +[def __upgrade_lock__ [link thread.synchronization.locks.upgrade_lock `boost::upgrade_lock`]] +[def __upgrade_to_unique_lock__ [link thread.synchronization.locks.upgrade_to_unique_lock `boost::upgrade_to_unique_lock`]] + + +[def __thread__ [link thread.thread_management.thread `boost::thread`]] +[def __thread_id__ [link thread.thread_management.thread.id `boost::thread::id`]] +[template join_link[link_text] [link thread.thread_management.thread.join [link_text]]] +[def __join__ [join_link `join()`]] +[template timed_join_link[link_text] [link thread.thread_management.thread.timed_join [link_text]]] +[def __timed_join__ [timed_join_link `timed_join()`]] +[def __detach__ [link thread.thread_management.thread.detach `detach()`]] +[def __interrupt__ [link thread.thread_management.thread.interrupt `interrupt()`]] +[def __sleep__ [link thread.thread_management.this_thread.sleep `boost::this_thread::sleep()`]] + +[def __interruption_enabled__ [link thread.thread_management.this_thread.interruption_enabled `boost::this_thread::interruption_enabled()`]] +[def __interruption_requested__ [link thread.thread_management.this_thread.interruption_requested `boost::this_thread::interruption_requested()`]] +[def __interruption_point__ [link thread.thread_management.this_thread.interruption_point `boost::this_thread::interruption_point()`]] +[def __disable_interruption__ [link thread.thread_management.this_thread.disable_interruption `boost::this_thread::disable_interruption`]] +[def __restore_interruption__ [link thread.thread_management.this_thread.restore_interruption `boost::this_thread::restore_interruption`]] + +[def __thread_resource_error__ `boost::thread_resource_error`] +[def __thread_interrupted__ `boost::thread_interrupted`] +[def __barrier__ [link thread.synchronization.barriers.barrier `boost::barrier`]] + +[template cond_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable.wait [link_text]]] +[def __cond_wait__ [cond_wait_link `wait()`]] +[template cond_timed_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable.timed_wait [link_text]]] +[def __cond_timed_wait__ [cond_timed_wait_link `timed_wait()`]] +[template cond_any_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable_any.wait [link_text]]] +[def __cond_any_wait__ [cond_any_wait_link `wait()`]] +[template cond_any_timed_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable_any.timed_wait [link_text]]] +[def __cond_any_timed_wait__ [cond_any_timed_wait_link `timed_wait()`]] + +[def __blocked__ ['blocked]] + +[include overview.qbk] +[include changes.qbk] + +[include thread_ref.qbk] + +[section:synchronization Synchronization] +[include mutex_concepts.qbk] +[include mutexes.qbk] +[include condition_variables.qbk] +[include once.qbk] +[include barrier.qbk] +[endsect] + +[include tss.qbk] + +[include time.qbk] + +[include acknowledgements.qbk] diff --git a/deal.II/contrib/boost/libs/thread/doc/thread_ref.qbk b/deal.II/contrib/boost/libs/thread/doc/thread_ref.qbk new file mode 100644 index 0000000000..43e62ea13f --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/doc/thread_ref.qbk @@ -0,0 +1,1064 @@ +[/ + (C) Copyright 2007-8 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). +] + +[section:thread_management Thread Management] + +[heading Synopsis] + +The __thread__ class is responsible for launching and managing threads. Each __thread__ object represents a single thread of execution, +or __not_a_thread__, and at most one __thread__ object represents a given thread of execution: objects of type __thread__ are not +copyable. + +Objects of type __thread__ are movable, however, so they can be stored in move-aware containers, and returned from functions. This +allows the details of thread creation to be wrapped in a function. + + boost::thread make_thread(); + + void f() + { + boost::thread some_thread=make_thread(); + some_thread.join(); + } + +[Note: On compilers that support rvalue references, __thread__ provides a proper move constructor and move-assignment operator, and +therefore meets the C++0x ['MoveConstructible] and ['MoveAssignable] concepts. With such compilers, __thread__ can therefore be used +with containers that support those concepts. + +For other compilers, move support is provided with a move emulation layer, so containers must explicitly detect that move emulation +layer. See for details.] + +[heading Launching threads] + +A new thread is launched by passing an object of a callable type that can be invoked with no parameters to the constructor. The +object is then copied into internal storage, and invoked on the newly-created thread of execution. If the object must not (or +cannot) be copied, then `boost::ref` can be used to pass in a reference to the function object. In this case, the user of +__boost_thread__ must ensure that the referred-to object outlives the newly-created thread of execution. + + struct callable + { + void operator()(); + }; + + boost::thread copies_are_safe() + { + callable x; + return boost::thread(x); + } // x is destroyed, but the newly-created thread has a copy, so this is OK + + boost::thread oops() + { + callable x; + return boost::thread(boost::ref(x)); + } // x is destroyed, but the newly-created thread still has a reference + // this leads to undefined behaviour + +If you wish to construct an instance of __thread__ with a function or callable object that requires arguments to be supplied, +this can be done by passing additional arguments to the __thread__ constructor: + + void find_the_question(int the_answer); + + boost::thread deep_thought_2(find_the_question,42); + +The arguments are ['copied] into the internal thread structure: if a reference is required, use `boost::ref`, just as for references +to callable functions. + +There is an unspecified limit on the number of additional arguments that can be passed. + +[heading Exceptions in thread functions] + +If the function or callable object passed to the __thread__ constructor propagates an exception when invoked that is not of type +__thread_interrupted__, `std::terminate()` is called. + +[heading Joining and detaching] + +When the __thread__ object that represents a thread of execution is destroyed the thread becomes ['detached]. Once a thread is +detached, it will continue executing until the invocation of the function or callable object supplied on construction has completed, +or the program is terminated. A thread can also be detached by explicitly invoking the __detach__ member function on the __thread__ +object. In this case, the __thread__ object ceases to represent the now-detached thread, and instead represents __not_a_thread__. + +In order to wait for a thread of execution to finish, the __join__ or __timed_join__ member functions of the __thread__ object must be +used. __join__ will block the calling thread until the thread represented by the __thread__ object has completed. If the thread of +execution represented by the __thread__ object has already completed, or the __thread__ object represents __not_a_thread__, then __join__ +returns immediately. __timed_join__ is similar, except that a call to __timed_join__ will also return if the thread being waited for +does not complete when the specified time has elapsed. + +[heading Interruption] + +A running thread can be ['interrupted] by invoking the __interrupt__ member function of the corresponding __thread__ object. When the +interrupted thread next executes one of the specified __interruption_points__ (or if it is currently __blocked__ whilst executing one) +with interruption enabled, then a __thread_interrupted__ exception will be thrown in the interrupted thread. If not caught, +this will cause the execution of the interrupted thread to terminate. As with any other exception, the stack will be unwound, and +destructors for objects of automatic storage duration will be executed. + +If a thread wishes to avoid being interrupted, it can create an instance of __disable_interruption__. Objects of this class disable +interruption for the thread that created them on construction, and restore the interruption state to whatever it was before on +destruction: + + void f() + { + // interruption enabled here + { + boost::this_thread::disable_interruption di; + // interruption disabled + { + boost::this_thread::disable_interruption di2; + // interruption still disabled + } // di2 destroyed, interruption state restored + // interruption still disabled + } // di destroyed, interruption state restored + // interruption now enabled + } + +The effects of an instance of __disable_interruption__ can be temporarily reversed by constructing an instance of +__restore_interruption__, passing in the __disable_interruption__ object in question. This will +restore the interruption state to what it was when the __disable_interruption__ object was constructed, and then +disable interruption again when the __restore_interruption__ object is destroyed. + + void g() + { + // interruption enabled here + { + boost::this_thread::disable_interruption di; + // interruption disabled + { + boost::this_thread::restore_interruption ri(di); + // interruption now enabled + } // ri destroyed, interruption disable again + } // di destroyed, interruption state restored + // interruption now enabled + } + +At any point, the interruption state for the current thread can be queried by calling __interruption_enabled__. + +[#interruption_points] + +[heading Predefined Interruption Points] + +The following functions are ['interruption points], which will throw __thread_interrupted__ if interruption is enabled for the +current thread, and interruption is requested for the current thread: + +* [join_link `boost::thread::join()`] +* [timed_join_link `boost::thread::timed_join()`] +* [cond_wait_link `boost::condition_variable::wait()`] +* [cond_timed_wait_link `boost::condition_variable::timed_wait()`] +* [cond_any_wait_link `boost::condition_variable_any::wait()`] +* [cond_any_timed_wait_link `boost::condition_variable_any::timed_wait()`] +* [link thread.thread_management.thread.sleep `boost::thread::sleep()`] +* __sleep__ +* __interruption_point__ + +[heading Thread IDs] + +Objects of class __thread_id__ can be used to identify threads. Each running thread of execution has a unique ID obtainable +from the corresponding __thread__ by calling the `get_id()` member function, or by calling `boost::this_thread::get_id()` from +within the thread. Objects of class __thread_id__ can be copied, and used as keys in associative containers: the full range of +comparison operators is provided. Thread IDs can also be written to an output stream using the stream insertion operator, though the +output format is unspecified. + +Each instance of __thread_id__ either refers to some thread, or __not_a_thread__. Instances that refer to __not_a_thread__ +compare equal to each other, but not equal to any instances that refer to an actual thread of execution. The comparison operators on +__thread_id__ yield a total order for every non-equal thread ID. + +[section:thread Class `thread`] + + #include + + class thread + { + public: + thread(); + ~thread(); + + template + explicit thread(F f); + + template + thread(F f,A1 a1,A2 a2,...); + + template + thread(detail::thread_move_t f); + + // move support + thread(detail::thread_move_t x); + thread& operator=(detail::thread_move_t x); + operator detail::thread_move_t(); + detail::thread_move_t move(); + + void swap(thread& x); + + class id; + id get_id() const; + + bool joinable() const; + void join(); + bool timed_join(const system_time& wait_until); + + template + bool timed_join(TimeDuration const& rel_time); + + void detach(); + + static unsigned hardware_concurrency(); + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); + + void interrupt(); + bool interruption_requested() const; + + // backwards compatibility + bool operator==(const thread& other) const; + bool operator!=(const thread& other) const; + + static void yield(); + static void sleep(const system_time& xt); + }; + + void swap(thread& lhs,thread& rhs); + +[section:default_constructor Default Constructor] + + thread(); + +[variablelist + +[[Effects:] [Constructs a __thread__ instance that refers to __not_a_thread__.]] + +[[Throws:] [Nothing]] + +] + +[endsect] + +[section:callable_constructor Thread Constructor] + + template + thread(Callable func); + +[variablelist + +[[Preconditions:] [`Callable` must by copyable.]] + +[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created +thread of execution. If this invocation results in an exception being propagated into the internals of the thread library that is +not of type __thread_interrupted__, then `std::terminate()` will be called.]] + +[[Postconditions:] [`*this` refers to the newly created thread of execution.]] + +[[Throws:] [__thread_resource_error__ if an error occurs.]] + +] + +[endsect] + +[section:multiple_argument_constructor Thread Constructor with arguments] + + template + thread(F f,A1 a1,A2 a2,...); + +[variablelist + +[[Preconditions:] [`F` and each `A`n must by copyable or movable.]] + +[[Effects:] [As if [link +thread.thread_management.thread.callable_constructor +`thread(boost::bind(f,a1,a2,...))`. Consequently, `f` and each `a`n +are copied into internal storage for access by the new thread.]]] + +[[Postconditions:] [`*this` refers to the newly created thread of execution.]] + +[[Throws:] [__thread_resource_error__ if an error occurs.]] + +[[Note:] [Currently up to nine additional arguments `a1` to `a9` can be specified in addition to the function `f`.]] + +] + +[endsect] + +[section:destructor Thread Destructor] + + ~thread(); + +[variablelist + +[[Effects:] [If `*this` has an associated thread of execution, calls __detach__. Destroys `*this`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:joinable Member function `joinable()`] + + bool joinable() const; + +[variablelist + +[[Returns:] [`true` if `*this` refers to a thread of execution, `false` otherwise.]] + +[[Throws:] [Nothing]] + +] + + +[endsect] + +[section:join Member function `join()`] + + void join(); + +[variablelist + +[[Preconditions:] [`this->get_id()!=boost::this_thread::get_id()`]] + +[[Effects:] [If `*this` refers to a thread of execution, waits for that thread of execution to complete.]] + +[[Postconditions:] [If `*this` refers to a thread of execution on entry, that thread of execution has completed. `*this` no longer refers to any thread of execution.]] + +[[Throws:] [__thread_interrupted__ if the current thread of execution is interrupted.]] + +[[Notes:] [`join()` is one of the predefined __interruption_points__.]] + +] + +[endsect] + +[section:timed_join Member function `timed_join()`] + + bool timed_join(const system_time& wait_until); + + template + bool timed_join(TimeDuration const& rel_time); + +[variablelist + +[[Preconditions:] [`this->get_id()!=boost::this_thread::get_id()`]] + +[[Effects:] [If `*this` refers to a thread of execution, waits for that thread of execution to complete, the time `wait_until` has +been reach or the specified duration `rel_time` has elapsed. If `*this` doesn't refer to a thread of execution, returns immediately.]] + +[[Returns:] [`true` if `*this` refers to a thread of execution on entry, and that thread of execution has completed before the call +times out, `false` otherwise.]] + +[[Postconditions:] [If `*this` refers to a thread of execution on entry, and `timed_join` returns `true`, that thread of execution +has completed, and `*this` no longer refers to any thread of execution. If this call to `timed_join` returns `false`, `*this` is +unchanged.]] + +[[Throws:] [__thread_interrupted__ if the current thread of execution is interrupted.]] + +[[Notes:] [`timed_join()` is one of the predefined __interruption_points__.]] + +] + +[endsect] + +[section:detach Member function `detach()`] + + void detach(); + +[variablelist + +[[Effects:] [If `*this` refers to a thread of execution, that thread of execution becomes detached, and no longer has an associated __thread__ object.]] + +[[Postconditions:] [`*this` no longer refers to any thread of execution.]] + +[[Throws:] [Nothing]] + +] + +[endsect] + + +[section:get_id Member function `get_id()`] + + thread::id get_id() const; + +[variablelist + +[[Returns:] [If `*this` refers to a thread of execution, an instance of __thread_id__ that represents that thread. Otherwise returns +a default-constructed __thread_id__.]] + +[[Throws:] [Nothing]] + +] + +[endsect] + +[section:interrupt Member function `interrupt()`] + + void interrupt(); + +[variablelist + +[[Effects:] [If `*this` refers to a thread of execution, request that the thread will be interrupted the next time it enters one of +the predefined __interruption_points__ with interruption enabled, or if it is currently __blocked__ in a call to one of the +predefined __interruption_points__ with interruption enabled .]] + +[[Throws:] [Nothing]] + +] + + +[endsect] + +[section:hardware_concurrency Static member function `hardware_concurrency()`] + + unsigned hardware_concurrency(); + +[variablelist + +[[Returns:] [The number of hardware threads available on the current system (e.g. number of CPUs or cores or hyperthreading units), +or 0 if this information is not available.]] + +[[Throws:] [Nothing]] + +] + +[endsect] + +[section:nativehandle Member function `native_handle()`] + + typedef platform-specific-type native_handle_type; + native_handle_type native_handle(); + +[variablelist + +[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying +implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:equals `operator==`] + + bool operator==(const thread& other) const; + +[variablelist + +[[Returns:] [`get_id()==other.get_id()`]] + +] + +[endsect] + +[section:not_equals `operator!=`] + + bool operator!=(const thread& other) const; + +[variablelist + +[[Returns:] [`get_id()!=other.get_id()`]] + +] + +[endsect] + +[section:sleep Static member function `sleep()`] + + void sleep(system_time const& abs_time); + +[variablelist + +[[Effects:] [Suspends the current thread until the specified time has been reached.]] + +[[Throws:] [__thread_interrupted__ if the current thread of execution is interrupted.]] + +[[Notes:] [`sleep()` is one of the predefined __interruption_points__.]] + +] + +[endsect] + +[section:yield Static member function `yield()`] + + void yield(); + +[variablelist + +[[Effects:] [See [link thread.thread_management.this_thread.yield `boost::this_thread::yield()`].]] + +] + +[endsect] + +[section:swap Member function `swap()`] + + void swap(thread& other); + +[variablelist + +[[Effects:] [Exchanges the threads of execution associated with `*this` and `other`, so `*this` is associated with the thread of +execution associated with `other` prior to the call, and vice-versa.]] + +[[Postconditions:] [`this->get_id()` returns the same value as `other.get_id()` prior to the call. `other.get_id()` returns the same +value as `this->get_id()` prior to the call.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:non_member_swap Non-member function `swap()`] + + #include + + void swap(thread& lhs,thread& rhs); + +[variablelist + +[[Effects:] [[link thread.thread_management.thread.swap `lhs.swap(rhs)`].]] + +] + +[endsect] + + +[section:id Class `boost::thread::id`] + + #include + + class thread::id + { + public: + id(); + + bool operator==(const id& y) const; + bool operator!=(const id& y) const; + bool operator<(const id& y) const; + bool operator>(const id& y) const; + bool operator<=(const id& y) const; + bool operator>=(const id& y) const; + + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, const id& x); + }; + +[section:constructor Default constructor] + + id(); + +[variablelist + +[[Effects:] [Constructs a __thread_id__ instance that represents __not_a_thread__.]] + +[[Throws:] [Nothing]] + +] + +[endsect] + +[section:is_equal `operator==`] + + bool operator==(const id& y) const; + +[variablelist + +[[Returns:] [`true` if `*this` and `y` both represent the same thread of execution, or both represent __not_a_thread__, `false` +otherwise.]] + +[[Throws:] [Nothing]] + +] + +[endsect] + +[section:not_equal `operator!=`] + + bool operator!=(const id& y) const; + +[variablelist + +[[Returns:] [`true` if `*this` and `y` represent different threads of execution, or one represents a thread of execution, and +the other represent __not_a_thread__, `false` otherwise.]] + +[[Throws:] [Nothing]] + +] + +[endsect] + +[section:less_than `operator<`] + + bool operator<(const id& y) const; + +[variablelist + +[[Returns:] [`true` if `*this!=y` is `true` and the implementation-defined total order of __thread_id__ values places `*this` before +`y`, `false` otherwise.]] + +[[Throws:] [Nothing]] + +[[Note:] [A __thread_id__ instance representing __not_a_thread__ will always compare less than an instance representing a thread of +execution.]] + +] + +[endsect] + + +[section:greater_than `operator>`] + + bool operator>(const id& y) const; + +[variablelist + +[[Returns:] [`y<*this`]] + +[[Throws:] [Nothing]] + +] + +[endsect] + +[section:less_than_or_equal `operator>=`] + + bool operator<=(const id& y) const; + +[variablelist + +[[Returns:] [`!(y<*this)`]] + +[[Throws:] [Nothing]] + +] + +[endsect] + +[section:greater_than_or_equal `operator>=`] + + bool operator>=(const id& y) const; + +[variablelist + +[[Returns:] [`!(*this + friend std::basic_ostream& + operator<<(std::basic_ostream& os, const id& x); + +[variablelist + +[[Effects:] [Writes a representation of the __thread_id__ instance `x` to the stream `os`, such that the representation of two +instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `a!=b`.]] + +[[Returns:] [`os`]] + +] + +[endsect] + + +[endsect] + +[endsect] + +[section:this_thread Namespace `this_thread`] + +[section:get_id Non-member function `get_id()`] + + #include + + namespace this_thread + { + thread::id get_id(); + } + +[variablelist + +[[Returns:] [An instance of __thread_id__ that represents that currently executing thread.]] + +[[Throws:] [__thread_resource_error__ if an error occurs.]] + +] + +[endsect] + +[section:interruption_point Non-member function `interruption_point()`] + + #include + + namespace this_thread + { + void interruption_point(); + } + +[variablelist + +[[Effects:] [Check to see if the current thread has been interrupted.]] + +[[Throws:] [__thread_interrupted__ if __interruption_enabled__ and __interruption_requested__ both return `true`.]] + +] + +[endsect] + +[section:interruption_requested Non-member function `interruption_requested()`] + + #include + + namespace this_thread + { + bool interruption_requested(); + } + +[variablelist + +[[Returns:] [`true` if interruption has been requested for the current thread, `false` otherwise.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:interruption_enabled Non-member function `interruption_enabled()`] + + #include + + namespace this_thread + { + bool interruption_enabled(); + } + +[variablelist + +[[Returns:] [`true` if interruption has been enabled for the current thread, `false` otherwise.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:sleep Non-member function `sleep()`] + + #include + + namespace this_thread + { + template + void sleep(TimeDuration const& rel_time); + } + +[variablelist + +[[Effects:] [Suspends the current thread until the specified time has elapsed.]] + +[[Throws:] [__thread_interrupted__ if the current thread of execution is interrupted.]] + +[[Notes:] [`sleep()` is one of the predefined __interruption_points__.]] + +] + +[endsect] + +[section:yield Non-member function `yield()`] + + #include + + namespace this_thread + { + void yield(); + } + +[variablelist + +[[Effects:] [Gives up the remainder of the current thread's time slice, to allow other threads to run.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:disable_interruption Class `disable_interruption`] + + #include + + namespace this_thread + { + class disable_interruption + { + public: + disable_interruption(); + ~disable_interruption(); + }; + } + +`boost::this_thread::disable_interruption` disables interruption for the current thread on construction, and restores the prior +interruption state on destruction. Instances of `disable_interruption` cannot be copied or moved. + +[section:constructor Constructor] + + disable_interruption(); + +[variablelist + +[[Effects:] [Stores the current state of __interruption_enabled__ and disables interruption for the current thread.]] + +[[Postconditions:] [__interruption_enabled__ returns `false` for the current thread.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:destructor Destructor] + + ~disable_interruption(); + +[variablelist + +[[Preconditions:] [Must be called from the same thread from which `*this` was constructed.]] + +[[Effects:] [Restores the current state of __interruption_enabled__ for the current thread to that prior to the construction of `*this`.]] + +[[Postconditions:] [__interruption_enabled__ for the current thread returns the value stored in the constructor of `*this`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[endsect] + +[section:restore_interruption Class `restore_interruption`] + + #include + + namespace this_thread + { + class restore_interruption + { + public: + explicit restore_interruption(disable_interruption& disabler); + ~restore_interruption(); + }; + } + +On construction of an instance of `boost::this_thread::restore_interruption`, the interruption state for the current thread is +restored to the interruption state stored by the constructor of the supplied instance of __disable_interruption__. When the instance +is destroyed, interruption is again disabled. Instances of `restore_interruption` cannot be copied or moved. + +[section:constructor Constructor] + + explicit restore_interruption(disable_interruption& disabler); + +[variablelist + +[[Preconditions:] [Must be called from the same thread from which `disabler` was constructed.]] + +[[Effects:] [Restores the current state of __interruption_enabled__ for the current thread to that prior to the construction of `disabler`.]] + +[[Postconditions:] [__interruption_enabled__ for the current thread returns the value stored in the constructor of `disabler`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:destructor Destructor] + + ~restore_interruption(); + +[variablelist + +[[Preconditions:] [Must be called from the same thread from which `*this` was constructed.]] + +[[Effects:] [Disables interruption for the current thread.]] + +[[Postconditions:] [__interruption_enabled__ for the current thread returns `false`.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[endsect] + +[section:atthreadexit Non-member function template `at_thread_exit()`] + + #include + + template + void at_thread_exit(Callable func); + +[variablelist + +[[Effects:] [A copy of `func` is placed in +thread-specific storage. This copy is invoked when the current thread +exits (even if the thread has been interrupted).]] + +[[Postconditions:] [A copy of `func` has been saved for invocation on thread exit.]] + +[[Throws:] [`std::bad_alloc` if memory cannot be allocated for the copy of the function, __thread_resource_error__ if any other +error occurs within the thread library. Any exception thrown whilst copying `func` into internal storage.]] + +] + +[endsect] + +[endsect] + +[section:threadgroup Class `thread_group`] + + #include + + class thread_group: + private noncopyable + { + public: + thread_group(); + ~thread_group(); + + template + thread* create_thread(F threadfunc); + void add_thread(thread* thrd); + void remove_thread(thread* thrd); + void join_all(); + void interrupt_all(); + int size() const; + }; + +`thread_group` provides for a collection of threads that are related in some fashion. New threads can be added to the group with +`add_thread` and `create_thread` member functions. `thread_group` is not copyable or movable. + +[section:constructor Constructor] + + thread_group(); + +[variablelist + +[[Effects:] [Create a new thread group with no threads.]] + +] + +[endsect] + +[section:destructor Destructor] + + ~thread_group(); + +[variablelist + +[[Effects:] [Destroy `*this` and `delete` all __thread__ objects in the group.]] + +] + +[endsect] + +[section:create_thread Member function `create_thread()`] + + template + thread* create_thread(F threadfunc); + +[variablelist + +[[Effects:] [Create a new __thread__ object as-if by `new thread(threadfunc)` and add it to the group.]] + +[[Postcondition:] [`this->size()` is increased by one, the new thread is running.]] + +[[Returns:] [A pointer to the new __thread__ object.]] + +] + +[endsect] + +[section:add_thread Member function `add_thread()`] + + void add_thread(thread* thrd); + +[variablelist + +[[Precondition:] [The expression `delete thrd` is well-formed and will not result in undefined behaviour.]] + +[[Effects:] [Take ownership of the __thread__ object pointed to by `thrd` and add it to the group.]] + +[[Postcondition:] [`this->size()` is increased by one.]] + +] + +[endsect] + +[section:remove_thread Member function `remove_thread()`] + + void remove_thread(thread* thrd); + +[variablelist + +[[Effects:] [If `thrd` is a member of the group, remove it without calling `delete`.]] + +[[Postcondition:] [If `thrd` was a member of the group, `this->size()` is decreased by one.]] + +] + +[endsect] + +[section:join_all Member function `join_all()`] + + void join_all(); + +[variablelist + +[[Effects:] [Call `join()` on each __thread__ object in the group.]] + +[[Postcondition:] [Every thread in the group has terminated.]] + +[[Note:] [Since __join__ is one of the predefined __interruption_points__, `join_all()` is also an interruption point.]] + +] + +[endsect] + +[section:interrupt_all Member function `interrupt_all()`] + + void interrupt_all(); + +[variablelist + +[[Effects:] [Call `interrupt()` on each __thread__ object in the group.]] + +] + +[endsect] + +[section:size Member function `size()`] + + int size(); + +[variablelist + +[[Returns:] [The number of threads in the group.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + + +[endsect] + +[endsect] diff --git a/deal.II/contrib/boost/libs/thread/doc/time.qbk b/deal.II/contrib/boost/libs/thread/doc/time.qbk new file mode 100644 index 0000000000..879854279a --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/doc/time.qbk @@ -0,0 +1,75 @@ +[/ + (C) Copyright 2007-8 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). +] + +[section:time Date and Time Requirements] + +As of Boost 1.35.0, the __boost_thread__ library uses the [link date_time Boost.Date_Time] library for all operations that require a +time out. These include (but are not limited to): + +* __sleep__ +* __timed_join__ +* __cond_timed_wait__ +* __timed_lock_ref__ + +For the overloads that accept an absolute time parameter, an object of type [link thread.time.system_time `boost::system_time`] is +required. Typically, this will be obtained by adding a duration to the current time, obtained with a call to [link +thread.time.get_system_time `boost::get_system_time()`]. e.g. + + boost::system_time const timeout=boost::get_system_time() + boost::posix_time::milliseconds(500); + + extern bool done; + extern boost::mutex m; + extern boost::condition_variable cond; + + boost::unique_lock lk(m); + while(!done) + { + if(!cond.timed_wait(lk,timeout)) + { + throw "timed out"; + } + } + +For the overloads that accept a ['TimeDuration] parameter, an object of any type that meets the [link +date_time.posix_time.time_duration Boost.Date_Time Time Duration requirements] can be used, e.g. + + boost::this_thread::sleep(boost::posix_time::milliseconds(25)); + + boost::mutex m; + if(m.timed_lock(boost::posix_time::nanoseconds(100))) + { + // ... + } + +[section:system_time Typedef `system_time`] + + #include + + typedef boost::posix_time::ptime system_time; + +See the documentation for [link date_time.posix_time.ptime_class `boost::posix_time::ptime`] in the Boost.Date_Time library. + +[endsect] + +[section:get_system_time Non-member function `get_system_time()`] + + #include + + system_time get_system_time(); + +[variablelist + +[[Returns:] [The current time.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + + +[endsect] \ No newline at end of file diff --git a/deal.II/contrib/boost/libs/thread/doc/tss.qbk b/deal.II/contrib/boost/libs/thread/doc/tss.qbk new file mode 100644 index 0000000000..6a9ffc44ae --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/doc/tss.qbk @@ -0,0 +1,184 @@ +[/ + (C) Copyright 2007-8 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). +] + +[section Thread Local Storage] + +[heading Synopsis] + +Thread local storage allows multi-threaded applications to have a separate instance of a given data item for each thread. Where a +single-threaded application would use static or global data, this could lead to contention, deadlock or data corruption in a +multi-threaded application. One example is the C `errno` variable, used for storing the error code related to functions from the +Standard C library. It is common practice (and required by POSIX) for compilers that support multi-threaded applications to provide +a separate instance of `errno` for each thread, in order to avoid different threads competing to read or update the value. + +Though compilers often provide this facility in the form of extensions to the declaration syntax (such as `__declspec(thread)` or +`__thread` annotations on `static` or namespace-scope variable declarations), such support is non-portable, and is often limited in +some way, such as only supporting POD types. + +[heading Portable thread-local storage with `boost::thread_specific_ptr`] + +`boost::thread_specific_ptr` provides a portable mechanism for thread-local storage that works on all compilers supported by +__boost_thread__. Each instance of `boost::thread_specific_ptr` represents a pointer to an object (such as `errno`) where each +thread must have a distinct value. The value for the current thread can be obtained using the `get()` member function, or by using +the `*` and `->` pointer deference operators. Initially the pointer has a value of `NULL` in each thread, but the value for the +current thread can be set using the `reset()` member function. + +If the value of the pointer for the current thread is changed using `reset()`, then the previous value is destroyed by calling the +cleanup routine. Alternatively, the stored value can be reset to `NULL` and the prior value returned by calling the `release()` +member function, allowing the application to take back responsibility for destroying the object. + +[heading Cleanup at thread exit] + +When a thread exits, the objects associated with each `boost::thread_specific_ptr` instance are destroyed. By default, the object +pointed to by a pointer `p` is destroyed by invoking `delete p`, but this can be overridden for a specific instance of +`boost::thread_specific_ptr` by providing a cleanup routine to the constructor. In this case, the object is destroyed by invoking +`func(p)` where `func` is the cleanup routine supplied to the constructor. The cleanup functions are called in an unspecified +order. If a cleanup routine sets the value of associated with an instance of `boost::thread_specific_ptr` that has already been +cleaned up, that value is added to the cleanup list. Cleanup finishes when there are no outstanding instances of +`boost::thread_specific_ptr` with values. + + +[section:thread_specific_ptr Class `thread_specific_ptr`] + + #include + + template + class thread_specific_ptr + { + public: + thread_specific_ptr(); + explicit thread_specific_ptr(void (*cleanup_function)(T*)); + ~thread_specific_ptr(); + + T* get() const; + T* operator->() const; + T& operator*() const; + + T* release(); + void reset(T* new_value=0); + }; + +[section:default_constructor `thread_specific_ptr();`] + +[variablelist + +[[Requires:] [`delete this->get()` is well-formed.]] + +[[Effects:] [Construct a `thread_specific_ptr` object for storing a pointer to an object of type `T` specific to each thread. The +default `delete`-based cleanup function will be used to destroy any thread-local objects when `reset()` is called, or the thread +exits.]] + +[[Throws:] [`boost::thread_resource_error` if an error occurs.]] + +] + +[endsect] + +[section:constructor_with_custom_cleanup `explicit thread_specific_ptr(void (*cleanup_function)(T*));`] + +[variablelist + +[[Requires:] [`cleanup_function(this->get())` does not throw any exceptions.]] + +[[Effects:] [Construct a `thread_specific_ptr` object for storing a pointer to an object of type `T` specific to each thread. The +supplied `cleanup_function` will be used to destroy any thread-local objects when `reset()` is called, or the thread exits.]] + +[[Throws:] [`boost::thread_resource_error` if an error occurs.]] + +] + +[endsect] + +[section:destructor `~thread_specific_ptr();`] + +[variablelist + +[[Effects:] [Calls `this->reset()` to clean up the associated value for the current thread, and destroys `*this`.]] + +[[Throws:] [Nothing.]] + +] + +[note Care needs to be taken to ensure that any threads still running after an instance of `boost::thread_specific_ptr` has been +destroyed do not call any member functions on that instance.] + +[endsect] + +[section:get `T* get() const;`] + +[variablelist + +[[Returns:] [The pointer associated with the current thread.]] + +[[Throws:] [Nothing.]] + +] + +[note The initial value associated with an instance of `boost::thread_specific_ptr` is `NULL` for each thread.] + +[endsect] + +[section:operator_arrow `T* operator->() const;`] + +[variablelist + +[[Returns:] [`this->get()`]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:operator_star `T& operator*() const;`] + +[variablelist + +[[Requires:] [`this->get` is not `NULL`.]] + +[[Returns:] [`*(this->get())`]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[section:reset `void reset(T* new_value=0);`] + +[variablelist + +[[Effects:] [If `this->get()!=new_value` and `this->get()` is non-`NULL`, invoke `delete this->get()` or +`cleanup_function(this->get())` as appropriate. Store `new_value` as the pointer associated with the current thread.]] + +[[Postcondition:] [`this->get()==new_value`]] + +[[Throws:] [`boost::thread_resource_error` if an error occurs.]] + +] + +[endsect] + +[section:release `T* release();`] + +[variablelist + +[[Effects:] [Return `this->get()` and store `NULL` as the pointer associated with the current thread without invoking the cleanup +function.]] + +[[Postcondition:] [`this->get()==0`]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + + +[endsect] + +[endsect] diff --git a/deal.II/contrib/boost/libs/thread/example/Jamfile.v2 b/deal.II/contrib/boost/libs/thread/example/Jamfile.v2 new file mode 100644 index 0000000000..bfc8a59b3c --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/example/Jamfile.v2 @@ -0,0 +1,23 @@ +# 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) + +project boost/thread/example + : requirements ../build//boost_thread multi + ; + + +exe monitor : monitor.cpp ; +exe starvephil : starvephil.cpp ; +exe tennis : tennis.cpp ; +exe condition : condition.cpp ; +exe mutex : mutex.cpp ; +exe once : once.cpp ; +exe recursive_mutex : recursive_mutex.cpp ; +exe thread : thread.cpp ; +exe thread_group : thread_group.cpp ; +exe tss : tss.cpp ; +exe xtime : xtime.cpp ; + diff --git a/deal.II/contrib/boost/libs/thread/example/condition.cpp b/deal.II/contrib/boost/libs/thread/example/condition.cpp new file mode 100644 index 0000000000..096c35d8af --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/example/condition.cpp @@ -0,0 +1,82 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include + +class bounded_buffer : private boost::noncopyable +{ +public: + typedef boost::mutex::scoped_lock lock; + + bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { } + + void send (int m) { + lock lk(monitor); + while (buffered == circular_buf.size()) + buffer_not_full.wait(lk); + circular_buf[end] = m; + end = (end+1) % circular_buf.size(); + ++buffered; + buffer_not_empty.notify_one(); + } + int receive() { + lock lk(monitor); + while (buffered == 0) + buffer_not_empty.wait(lk); + int i = circular_buf[begin]; + begin = (begin+1) % circular_buf.size(); + --buffered; + buffer_not_full.notify_one(); + return i; + } + +private: + int begin, end, buffered; + std::vector circular_buf; + boost::condition buffer_not_full, buffer_not_empty; + boost::mutex monitor; +}; + +bounded_buffer buf(2); + +boost::mutex io_mutex; + +void sender() { + int n = 0; + while (n < 100) { + buf.send(n); + { + boost::mutex::scoped_lock io_lock(io_mutex); + std::cout << "sent: " << n << std::endl; + } + ++n; + } + buf.send(-1); +} + +void receiver() { + int n; + do { + n = buf.receive(); + { + boost::mutex::scoped_lock io_lock(io_mutex); + std::cout << "received: " << n << std::endl; + } + } while (n != -1); // -1 indicates end of buffer +} + +int main(int, char*[]) +{ + boost::thread thrd1(&sender); + boost::thread thrd2(&receiver); + thrd1.join(); + thrd2.join(); + return 0; +} diff --git a/deal.II/contrib/boost/libs/thread/example/monitor.cpp b/deal.II/contrib/boost/libs/thread/example/monitor.cpp new file mode 100644 index 0000000000..0a7383fb47 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/example/monitor.cpp @@ -0,0 +1,112 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include + +namespace { +const int ITERS = 100; +boost::mutex io_mutex; +} // namespace + +template +class buffer_t +{ +public: + typedef typename M::scoped_lock scoped_lock; + + buffer_t(int n) + : p(0), c(0), full(0), buf(n) + { + } + + void send(int m) + { + scoped_lock lk(mutex); + while (full == buf.size()) + cond.wait(lk); + buf[p] = m; + p = (p+1) % buf.size(); + ++full; + cond.notify_one(); + } + int receive() + { + scoped_lock lk(mutex); + while (full == 0) + cond.wait(lk); + int i = buf[c]; + c = (c+1) % buf.size(); + --full; + cond.notify_one(); + return i; + } + + static buffer_t& get_buffer() + { + static buffer_t buf(2); + return buf; + } + + static void do_sender_thread() + { + for (int n = 0; n < ITERS; ++n) + { + { + boost::mutex::scoped_lock lock(io_mutex); + std::cout << "sending: " << n << std::endl; + } + get_buffer().send(n); + } + } + + static void do_receiver_thread() + { + for (int x=0; x < (ITERS/2); ++x) + { + int n = get_buffer().receive(); + { + boost::mutex::scoped_lock lock(io_mutex); + std::cout << "received: " << n << std::endl; + } + } + } + +private: + M mutex; + boost::condition cond; + unsigned int p, c, full; + std::vector buf; +}; + +template +void do_test(M* dummy=0) +{ + typedef buffer_t buffer_type; + buffer_type::get_buffer(); + boost::thread thrd1(&buffer_type::do_receiver_thread); + boost::thread thrd2(&buffer_type::do_receiver_thread); + boost::thread thrd3(&buffer_type::do_sender_thread); + thrd1.join(); + thrd2.join(); + thrd3.join(); +} + +void test_buffer() +{ + do_test(); + do_test(); +} + +int main() +{ + test_buffer(); + return 0; +} diff --git a/deal.II/contrib/boost/libs/thread/example/mutex.cpp b/deal.II/contrib/boost/libs/thread/example/mutex.cpp new file mode 100644 index 0000000000..b276d54909 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/example/mutex.cpp @@ -0,0 +1,47 @@ +// 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 + +boost::mutex io_mutex; // The iostreams are not guaranteed to be thread-safe! + +class counter +{ +public: + counter() : count(0) { } + + int increment() { + boost::mutex::scoped_lock scoped_lock(mutex); + return ++count; + } + +private: + boost::mutex mutex; + int count; +}; + +counter c; + +void change_count() +{ + int i = c.increment(); + boost::mutex::scoped_lock scoped_lock(io_mutex); + std::cout << "count == " << i << std::endl; +} + +int main(int, char*[]) +{ + const int num_threads = 4; + boost::thread_group thrds; + for (int i=0; i < num_threads; ++i) + thrds.create_thread(&change_count); + + thrds.join_all(); + + return 0; +} diff --git a/deal.II/contrib/boost/libs/thread/example/once.cpp b/deal.II/contrib/boost/libs/thread/example/once.cpp new file mode 100644 index 0000000000..5a5b6f5589 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/example/once.cpp @@ -0,0 +1,31 @@ +// 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 + +int value=0; +boost::once_flag once = BOOST_ONCE_INIT; + +void init() +{ + ++value; +} + +void thread_proc() +{ + boost::call_once(&init, once); +} + +int main(int argc, char* argv[]) +{ + boost::thread_group threads; + for (int i=0; i<5; ++i) + threads.create_thread(&thread_proc); + threads.join_all(); + assert(value == 1); +} diff --git a/deal.II/contrib/boost/libs/thread/example/recursive_mutex.cpp b/deal.II/contrib/boost/libs/thread/example/recursive_mutex.cpp new file mode 100644 index 0000000000..c5199545de --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/example/recursive_mutex.cpp @@ -0,0 +1,49 @@ +// 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 + +class counter +{ +public: + counter() : count(0) { } + + int add(int val) { + boost::recursive_mutex::scoped_lock scoped_lock(mutex); + count += val; + return count; + } + int increment() { + boost::recursive_mutex::scoped_lock scoped_lock(mutex); + return add(1); + } + +private: + boost::recursive_mutex mutex; + int count; +}; + +counter c; + +void change_count() +{ + std::cout << "count == " << c.increment() << std::endl; +} + +int main(int, char*[]) +{ + const int num_threads=4; + + boost::thread_group threads; + for (int i=0; i < num_threads; ++i) + threads.create_thread(&change_count); + + threads.join_all(); + + return 0; +} diff --git a/deal.II/contrib/boost/libs/thread/example/starvephil.cpp b/deal.II/contrib/boost/libs/thread/example/starvephil.cpp new file mode 100644 index 0000000000..0ef2e0d32d --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/example/starvephil.cpp @@ -0,0 +1,185 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include + +namespace +{ +boost::mutex iomx; +} // namespace + +class canteen +{ +public: + canteen() : m_chickens(0) { } + + void get(int id) + { + boost::mutex::scoped_lock lock(m_mutex); + while (m_chickens == 0) + { + { + boost::mutex::scoped_lock lock(iomx); + std::cout << "(" << clock() << ") Phil" << id << + ": wot, no chickens? I'll WAIT ..." << std::endl; + } + m_condition.wait(lock); + } + { + boost::mutex::scoped_lock lock(iomx); + std::cout << "(" << clock() << ") Phil" << id << + ": those chickens look good ... one please ..." << std::endl; + } + m_chickens--; + } + void put(int value) + { + boost::mutex::scoped_lock lock(m_mutex); + { + boost::mutex::scoped_lock lock(iomx); + std::cout << "(" << clock() + << ") Chef: ouch ... make room ... this dish is " + << "very hot ..." << std::endl; + } + boost::xtime xt; + boost::xtime_get(&xt, boost::TIME_UTC); + xt.sec += 3; + boost::thread::sleep(xt); + m_chickens += value; + { + boost::mutex::scoped_lock lock(iomx); + std::cout << "(" << clock() << + ") Chef: more chickens ... " << m_chickens << + " now available ... NOTIFYING ..." << std::endl; + } + m_condition.notify_all(); + } + +private: + boost::mutex m_mutex; + boost::condition m_condition; + int m_chickens; +}; + +canteen g_canteen; + +void chef() +{ + const int chickens = 4; + { + boost::mutex::scoped_lock lock(iomx); + std::cout << "(" << clock() << ") Chef: starting ..." << std::endl; + } + for (;;) + { + { + boost::mutex::scoped_lock lock(iomx); + std::cout << "(" << clock() << ") Chef: cooking ..." << std::endl; + } + boost::xtime xt; + boost::xtime_get(&xt, boost::TIME_UTC); + xt.sec += 2; + boost::thread::sleep(xt); + { + boost::mutex::scoped_lock lock(iomx); + std::cout << "(" << clock() << ") Chef: " << chickens + << " chickens, ready-to-go ..." << std::endl; + } + g_canteen.put(chickens); + } +} + +struct phil +{ + phil(int id) : m_id(id) { } + void run() { + { + boost::mutex::scoped_lock lock(iomx); + std::cout << "(" << clock() << ") Phil" << m_id + << ": starting ..." << std::endl; + } + for (;;) + { + if (m_id > 0) + { + boost::xtime xt; + boost::xtime_get(&xt, boost::TIME_UTC); + xt.sec += 3; + boost::thread::sleep(xt); + } + { + boost::mutex::scoped_lock lock(iomx); + std::cout << "(" << clock() << ") Phil" << m_id + << ": gotta eat ..." << std::endl; + } + g_canteen.get(m_id); + { + boost::mutex::scoped_lock lock(iomx); + std::cout << "(" << clock() << ") Phil" << m_id + << ": mmm ... that's good ..." << std::endl; + } + } + } + static void do_thread(void* param) { + static_cast(param)->run(); + } + + int m_id; +}; + +struct thread_adapt +{ + thread_adapt(void (*func)(void*), void* param) + : _func(func), _param(param) + { + } + int operator()() const + { + _func(_param); + return 0; + } + + void (*_func)(void*); + void* _param; +}; + +class thread_adapter +{ +public: + thread_adapter(void (*func)(void*), void* param) + : _func(func), _param(param) + { + } + void operator()() const { _func(_param); } +private: + void (*_func)(void*); + void* _param; +}; + +int main(int argc, char* argv[]) +{ + boost::thread thrd_chef(&chef); + phil p[] = { phil(0), phil(1), phil(2), phil(3), phil(4) }; + boost::thread thrd_phil0(thread_adapter(&phil::do_thread, &p[0])); + boost::thread thrd_phil1(thread_adapter(&phil::do_thread, &p[1])); + boost::thread thrd_phil2(thread_adapter(&phil::do_thread, &p[2])); + boost::thread thrd_phil3(thread_adapter(&phil::do_thread, &p[3])); + boost::thread thrd_phil4(thread_adapter(&phil::do_thread, &p[4])); + + thrd_chef.join(); + thrd_phil0.join(); + thrd_phil1.join(); + thrd_phil2.join(); + thrd_phil3.join(); + thrd_phil4.join(); + + return 0; +} diff --git a/deal.II/contrib/boost/libs/thread/example/tennis.cpp b/deal.II/contrib/boost/libs/thread/example/tennis.cpp new file mode 100644 index 0000000000..e222871719 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/example/tennis.cpp @@ -0,0 +1,135 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include + +#if defined(BOOST_HAS_WINTHREADS) +# include +# include +#endif + +enum game_state +{ + START, + PLAYER_A, + PLAYER_B, + GAME_OVER, + ONE_PLAYER_GONE, + BOTH_PLAYERS_GONE +}; + +int state; +boost::mutex mutex; +boost::condition cond; + +char* player_name(int state) +{ + if (state == PLAYER_A) + return "PLAYER-A"; + if (state == PLAYER_B) + return "PLAYER-B"; + throw "bad player"; + return 0; +} + +void player(void* param) +{ + boost::mutex::scoped_lock lock(mutex); + + int active = (int)param; + int other = active == PLAYER_A ? PLAYER_B : PLAYER_A; + + while (state < GAME_OVER) + { + std::cout << player_name(active) << ": Play." << std::endl; + state = other; + cond.notify_all(); + do + { + cond.wait(lock); + if (state == other) + { + std::cout << "---" << player_name(active) + << ": Spurious wakeup!" << std::endl; + } + } while (state == other); + } + + ++state; + std::cout << player_name(active) << ": Gone." << std::endl; + cond.notify_all(); +} + +struct thread_adapt +{ + thread_adapt(void (*func)(void*), void* param) + : _func(func), _param(param) + { + } + int operator()() const + { + _func(_param); + return 0; + } + + void (*_func)(void*); + void* _param; +}; + +class thread_adapter +{ +public: + thread_adapter(void (*func)(void*), void* param) + : _func(func), _param(param) + { + } + void operator()() const { _func(_param); } +private: + void (*_func)(void*); + void* _param; +}; + +int main(int argc, char* argv[]) +{ + state = START; + + boost::thread thrda(thread_adapter(&player, (void*)PLAYER_A)); + boost::thread thrdb(thread_adapter(&player, (void*)PLAYER_B)); + + boost::xtime xt; + boost::xtime_get(&xt, boost::TIME_UTC); + xt.sec += 1; + boost::thread::sleep(xt); + { + boost::mutex::scoped_lock lock(mutex); + std::cout << "---Noise ON..." << std::endl; + } + + for (int i = 0; i < 1000000; ++i) + cond.notify_all(); + + { + boost::mutex::scoped_lock lock(mutex); + std::cout << "---Noise OFF..." << std::endl; + state = GAME_OVER; + cond.notify_all(); + do + { + cond.wait(lock); + } while (state != BOTH_PLAYERS_GONE); + } + + std::cout << "GAME OVER" << std::endl; + + thrda.join(); + thrdb.join(); + + return 0; +} diff --git a/deal.II/contrib/boost/libs/thread/example/thread.cpp b/deal.II/contrib/boost/libs/thread/example/thread.cpp new file mode 100644 index 0000000000..c21a3b5ea8 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/example/thread.cpp @@ -0,0 +1,35 @@ +// 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 + +struct thread_alarm +{ + thread_alarm(int secs) : m_secs(secs) { } + void operator()() + { + boost::xtime xt; + boost::xtime_get(&xt, boost::TIME_UTC); + xt.sec += m_secs; + + boost::thread::sleep(xt); + + std::cout << "alarm sounded..." << std::endl; + } + + int m_secs; +}; + +int main(int argc, char* argv[]) +{ + int secs = 5; + std::cout << "setting alarm for 5 seconds..." << std::endl; + thread_alarm alarm(secs); + boost::thread thrd(alarm); + thrd.join(); +} diff --git a/deal.II/contrib/boost/libs/thread/example/thread_group.cpp b/deal.II/contrib/boost/libs/thread/example/thread_group.cpp new file mode 100644 index 0000000000..232776dc62 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/example/thread_group.cpp @@ -0,0 +1,25 @@ +// 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 + +int count = 0; +boost::mutex mutex; + +void increment_count() +{ + boost::mutex::scoped_lock lock(mutex); + std::cout << "count = " << ++count << std::endl; +} + +int main(int argc, char* argv[]) +{ + boost::thread_group threads; + for (int i = 0; i < 10; ++i) + threads.create_thread(&increment_count); + threads.join_all(); +} diff --git a/deal.II/contrib/boost/libs/thread/example/tss.cpp b/deal.II/contrib/boost/libs/thread/example/tss.cpp new file mode 100644 index 0000000000..f867a9180a --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/example/tss.cpp @@ -0,0 +1,36 @@ +// 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 + +boost::thread_specific_ptr value; + +void increment() +{ + int* p = value.get(); + ++*p; +} + +void thread_proc() +{ + value.reset(new int(0)); // initialize the thread's storage + for (int i=0; i<10; ++i) + { + increment(); + int* p = value.get(); + assert(*p == i+1); + } +} + +int main(int argc, char* argv[]) +{ + boost::thread_group threads; + for (int i=0; i<5; ++i) + threads.create_thread(&thread_proc); + threads.join_all(); +} diff --git a/deal.II/contrib/boost/libs/thread/example/xtime.cpp b/deal.II/contrib/boost/libs/thread/example/xtime.cpp new file mode 100644 index 0000000000..a9b1933908 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/example/xtime.cpp @@ -0,0 +1,16 @@ +// 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 + +int main(int argc, char* argv[]) +{ + boost::xtime xt; + boost::xtime_get(&xt, boost::TIME_UTC); + xt.sec += 1; + boost::thread::sleep(xt); // Sleep for 1 second +} diff --git a/deal.II/contrib/boost/libs/thread/index.html b/deal.II/contrib/boost/libs/thread/index.html new file mode 100644 index 0000000000..f54e21e2fb --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/index.html @@ -0,0 +1,13 @@ + + + + + + + +Automatic redirection failed, please go to doc/index.html + + diff --git a/deal.II/contrib/boost/libs/thread/src/pthread/exceptions.cpp b/deal.II/contrib/boost/libs/thread/src/pthread/exceptions.cpp new file mode 100644 index 0000000000..8881303607 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/src/pthread/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/deal.II/contrib/boost/libs/thread/src/pthread/once.cpp b/deal.II/contrib/boost/libs/thread/src/pthread/once.cpp new file mode 100644 index 0000000000..6e3722a8e3 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/src/pthread/once.cpp @@ -0,0 +1,51 @@ +// Copyright (C) 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#define __STDC_CONSTANT_MACROS +#include +#include +#include +#include + +namespace boost +{ + namespace detail + { + BOOST_THREAD_DECL boost::uintmax_t once_global_epoch=UINTMAX_C(~0); + BOOST_THREAD_DECL pthread_mutex_t once_epoch_mutex=PTHREAD_MUTEX_INITIALIZER; + BOOST_THREAD_DECL pthread_cond_t once_epoch_cv = PTHREAD_COND_INITIALIZER; + + namespace + { + pthread_key_t epoch_tss_key; + pthread_once_t epoch_tss_key_flag=PTHREAD_ONCE_INIT; + + extern "C" void delete_epoch_tss_data(void* data) + { + free(data); + } + + extern "C" void create_epoch_tss_key() + { + BOOST_VERIFY(!pthread_key_create(&epoch_tss_key,delete_epoch_tss_data)); + } + + } + + boost::uintmax_t& get_once_per_thread_epoch() + { + BOOST_VERIFY(!pthread_once(&epoch_tss_key_flag,create_epoch_tss_key)); + void* data=pthread_getspecific(epoch_tss_key); + if(!data) + { + data=malloc(sizeof(boost::uintmax_t)); + BOOST_VERIFY(!pthread_setspecific(epoch_tss_key,data)); + *static_cast(data)=UINTMAX_C(~0); + } + return *static_cast(data); + } + } + +} diff --git a/deal.II/contrib/boost/libs/thread/src/pthread/thread.cpp b/deal.II/contrib/boost/libs/thread/src/pthread/thread.cpp new file mode 100644 index 0000000000..83f053e607 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/src/pthread/thread.cpp @@ -0,0 +1,677 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// Copyright (C) 2007-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#include +#include +#include +#include +#include +#ifdef __linux__ +#include +#elif defined(__APPLE__) || defined(__FreeBSD__) +#include +#include +#elif defined BOOST_HAS_UNISTD_H +#include +#endif + +#include "timeconv.inl" + +namespace boost +{ + namespace detail + { + thread_data_base::~thread_data_base() + {} + + struct thread_exit_callback_node + { + boost::detail::thread_exit_function_base* func; + thread_exit_callback_node* next; + + thread_exit_callback_node(boost::detail::thread_exit_function_base* func_, + thread_exit_callback_node* next_): + func(func_),next(next_) + {} + }; + + struct tss_data_node + { + void const* key; + boost::shared_ptr func; + void* value; + tss_data_node* next; + + tss_data_node(void const* key_,boost::shared_ptr func_,void* value_, + tss_data_node* next_): + key(key_),func(func_),value(value_),next(next_) + {} + }; + + namespace + { + boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT; + pthread_key_t current_thread_tls_key; + + extern "C" + { + void tls_destructor(void* data) + { + boost::detail::thread_data_base* thread_info=static_cast(data); + if(thread_info) + { + while(thread_info->tss_data || thread_info->thread_exit_callbacks) + { + while(thread_info->thread_exit_callbacks) + { + detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks; + thread_info->thread_exit_callbacks=current_node->next; + if(current_node->func) + { + (*current_node->func)(); + delete current_node->func; + } + delete current_node; + } + while(thread_info->tss_data) + { + detail::tss_data_node* const current_node=thread_info->tss_data; + thread_info->tss_data=current_node->next; + if(current_node->func) + { + (*current_node->func)(current_node->value); + } + delete current_node; + } + } + thread_info->self.reset(); + } + } + } + + + void create_current_thread_tls_key() + { + BOOST_VERIFY(!pthread_key_create(¤t_thread_tls_key,&tls_destructor)); + } + } + + boost::detail::thread_data_base* get_current_thread_data() + { + boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key); + return (boost::detail::thread_data_base*)pthread_getspecific(current_thread_tls_key); + } + + void set_current_thread_data(detail::thread_data_base* new_data) + { + boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key); + BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data)); + } + } + + namespace + { + extern "C" + { + void* thread_proxy(void* param) + { + boost::detail::thread_data_ptr thread_info = static_cast(param)->self; + thread_info->self.reset(); + detail::set_current_thread_data(thread_info.get()); + try + { + thread_info->run(); + } + catch(thread_interrupted const&) + { + } + catch(...) + { + std::terminate(); + } + + detail::tls_destructor(thread_info.get()); + detail::set_current_thread_data(0); + boost::lock_guard lock(thread_info->data_mutex); + thread_info->done=true; + thread_info->done_condition.notify_all(); + return 0; + } + } + + struct externally_launched_thread: + detail::thread_data_base + { + externally_launched_thread() + { + interrupt_enabled=false; + } + + void run() + {} + + private: + externally_launched_thread(externally_launched_thread&); + void operator=(externally_launched_thread&); + }; + + detail::thread_data_base* make_external_thread_data() + { + detail::thread_data_base* const me(new externally_launched_thread()); + me->self.reset(me); + set_current_thread_data(me); + return me; + } + + + detail::thread_data_base* get_or_make_current_thread_data() + { + detail::thread_data_base* current_thread_data(detail::get_current_thread_data()); + if(!current_thread_data) + { + current_thread_data=make_external_thread_data(); + } + return current_thread_data; + } + + } + + + thread::thread() + {} + + void thread::start_thread() + { + thread_info->self=thread_info; + int const res = pthread_create(&thread_info->thread_handle, 0, &thread_proxy, thread_info.get()); + if (res != 0) + { + thread_info->self.reset(); + throw thread_resource_error(); + } + } + + thread::~thread() + { + detach(); + } + + detail::thread_data_ptr thread::get_thread_info() const + { + lock_guard l(thread_info_mutex); + return thread_info; + } + + void thread::join() + { + detail::thread_data_ptr const local_thread_info=get_thread_info(); + if(local_thread_info) + { + bool do_join=false; + + { + unique_lock lock(local_thread_info->data_mutex); + while(!local_thread_info->done) + { + local_thread_info->done_condition.wait(lock); + } + do_join=!local_thread_info->join_started; + + if(do_join) + { + local_thread_info->join_started=true; + } + else + { + while(!local_thread_info->joined) + { + local_thread_info->done_condition.wait(lock); + } + } + } + if(do_join) + { + void* result=0; + BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result)); + lock_guard lock(local_thread_info->data_mutex); + local_thread_info->joined=true; + local_thread_info->done_condition.notify_all(); + } + + lock_guard l1(thread_info_mutex); + if(thread_info==local_thread_info) + { + thread_info.reset(); + } + } + } + + bool thread::timed_join(system_time const& wait_until) + { + detail::thread_data_ptr const local_thread_info=get_thread_info(); + if(local_thread_info) + { + bool do_join=false; + + { + unique_lock lock(local_thread_info->data_mutex); + while(!local_thread_info->done) + { + if(!local_thread_info->done_condition.timed_wait(lock,wait_until)) + { + return false; + } + } + do_join=!local_thread_info->join_started; + + if(do_join) + { + local_thread_info->join_started=true; + } + else + { + while(!local_thread_info->joined) + { + local_thread_info->done_condition.wait(lock); + } + } + } + if(do_join) + { + void* result=0; + BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result)); + lock_guard lock(local_thread_info->data_mutex); + local_thread_info->joined=true; + local_thread_info->done_condition.notify_all(); + } + + lock_guard l1(thread_info_mutex); + if(thread_info==local_thread_info) + { + thread_info.reset(); + } + } + return true; + } + + bool thread::joinable() const + { + return get_thread_info(); + } + + + void thread::detach() + { + detail::thread_data_ptr local_thread_info; + { + lock_guard l1(thread_info_mutex); + thread_info.swap(local_thread_info); + } + + if(local_thread_info) + { + lock_guard lock(local_thread_info->data_mutex); + if(!local_thread_info->join_started) + { + BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle)); + local_thread_info->join_started=true; + local_thread_info->joined=true; + } + } + } + + namespace this_thread + { + + void sleep(const system_time& st) + { + detail::thread_data_base* const thread_info=detail::get_current_thread_data(); + + if(thread_info) + { + unique_lock lk(thread_info->sleep_mutex); + while(thread_info->sleep_condition.timed_wait(lk,st)) + ; + } + else + { + xtime const xt=get_xtime(st); + + for (int foo=0; foo < 5; ++foo) + { +# if defined(BOOST_HAS_PTHREAD_DELAY_NP) + timespec ts; + to_timespec_duration(xt, ts); + BOOST_VERIFY(!pthread_delay_np(&ts)); +# elif defined(BOOST_HAS_NANOSLEEP) + timespec ts; + to_timespec_duration(xt, ts); + + // nanosleep takes a timespec that is an offset, not + // an absolute time. + nanosleep(&ts, 0); +# else + mutex mx; + mutex::scoped_lock lock(mx); + condition cond; + cond.timed_wait(lock, xt); +# endif + xtime cur; + xtime_get(&cur, TIME_UTC); + if (xtime_cmp(xt, cur) <= 0) + return; + } + } + } + + void yield() + { +# if defined(BOOST_HAS_SCHED_YIELD) + BOOST_VERIFY(!sched_yield()); +# elif defined(BOOST_HAS_PTHREAD_YIELD) + BOOST_VERIFY(!pthread_yield()); +# else + xtime xt; + xtime_get(&xt, TIME_UTC); + sleep(xt); +# endif + } + } + + unsigned thread::hardware_concurrency() + { +#if defined(PTW32_VERSION) || defined(__hpux) + return pthread_num_processors_np(); +#elif defined(__linux__) + return get_nprocs(); +#elif defined(__APPLE__) || defined(__FreeBSD__) + int count; + size_t size=sizeof(count); + return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count; +#elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN) + int const count=sysconf(_SC_NPROCESSORS_ONLN); + return (count>0)?count:0; +#else + return 0; +#endif + } + + thread::id thread::get_id() const + { + detail::thread_data_ptr const local_thread_info=get_thread_info(); + if(local_thread_info) + { + return id(local_thread_info); + } + else + { + return id(); + } + } + + void thread::interrupt() + { + detail::thread_data_ptr const local_thread_info=get_thread_info(); + if(local_thread_info) + { + lock_guard lk(local_thread_info->data_mutex); + local_thread_info->interrupt_requested=true; + if(local_thread_info->current_cond) + { + BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info->current_cond)); + } + } + } + + bool thread::interruption_requested() const + { + detail::thread_data_ptr const local_thread_info=get_thread_info(); + if(local_thread_info) + { + lock_guard lk(local_thread_info->data_mutex); + return local_thread_info->interrupt_requested; + } + else + { + return false; + } + } + + thread::native_handle_type thread::native_handle() + { + detail::thread_data_ptr const local_thread_info=get_thread_info(); + if(local_thread_info) + { + lock_guard lk(local_thread_info->data_mutex); + return local_thread_info->thread_handle; + } + else + { + return pthread_t(); + } + } + + + + namespace this_thread + { + thread::id get_id() + { + boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data(); + return thread::id(thread_info?thread_info->shared_from_this():detail::thread_data_ptr()); + } + + void interruption_point() + { + boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data(); + if(thread_info && thread_info->interrupt_enabled) + { + lock_guard lg(thread_info->data_mutex); + if(thread_info->interrupt_requested) + { + thread_info->interrupt_requested=false; + throw thread_interrupted(); + } + } + } + + bool interruption_enabled() + { + boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data(); + return thread_info && thread_info->interrupt_enabled; + } + + bool interruption_requested() + { + boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data(); + if(!thread_info) + { + return false; + } + else + { + lock_guard lg(thread_info->data_mutex); + return thread_info->interrupt_requested; + } + } + + disable_interruption::disable_interruption(): + interruption_was_enabled(interruption_enabled()) + { + if(interruption_was_enabled) + { + detail::get_current_thread_data()->interrupt_enabled=false; + } + } + + disable_interruption::~disable_interruption() + { + if(detail::get_current_thread_data()) + { + detail::get_current_thread_data()->interrupt_enabled=interruption_was_enabled; + } + } + + restore_interruption::restore_interruption(disable_interruption& d) + { + if(d.interruption_was_enabled) + { + detail::get_current_thread_data()->interrupt_enabled=true; + } + } + + restore_interruption::~restore_interruption() + { + if(detail::get_current_thread_data()) + { + detail::get_current_thread_data()->interrupt_enabled=false; + } + } + } + + namespace detail + { + void add_thread_exit_function(thread_exit_function_base* func) + { + detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); + thread_exit_callback_node* const new_node= + new thread_exit_callback_node(func,current_thread_data->thread_exit_callbacks); + current_thread_data->thread_exit_callbacks=new_node; + } + + tss_data_node* find_tss_data(void const* key) + { + detail::thread_data_base* const current_thread_data(get_current_thread_data()); + if(current_thread_data) + { + detail::tss_data_node* current_node=current_thread_data->tss_data; + while(current_node) + { + if(current_node->key==key) + { + return current_node; + } + current_node=current_node->next; + } + } + return NULL; + } + + void* get_tss_data(void const* key) + { + if(tss_data_node* const current_node=find_tss_data(key)) + { + return current_node->value; + } + return NULL; + } + + void set_tss_data(void const* key,boost::shared_ptr func,void* tss_data,bool cleanup_existing) + { + if(tss_data_node* const current_node=find_tss_data(key)) + { + if(cleanup_existing && current_node->func) + { + (*current_node->func)(current_node->value); + } + current_node->func=func; + current_node->value=tss_data; + } + else + { + detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); + tss_data_node* const new_node=new tss_data_node(key,func,tss_data,current_thread_data->tss_data); + current_thread_data->tss_data=new_node; + } + } + } + +// thread_group::thread_group() +// { +// } + +// thread_group::~thread_group() +// { +// // We shouldn't have to scoped_lock here, since referencing this object +// // from another thread while we're deleting it in the current thread is +// // going to lead to undefined behavior any way. +// for (std::list::iterator it = m_threads.begin(); +// it != m_threads.end(); ++it) +// { +// delete (*it); +// } +// } + +// thread* thread_group::create_thread(const function0& threadfunc) +// { +// // No scoped_lock required here since the only "shared data" that's +// // modified here occurs inside add_thread which does scoped_lock. +// std::auto_ptr thrd(new thread(threadfunc)); +// add_thread(thrd.get()); +// return thrd.release(); +// } + +// void thread_group::add_thread(thread* thrd) +// { +// mutex::scoped_lock scoped_lock(m_mutex); + +// // For now we'll simply ignore requests to add a thread object multiple +// // times. Should we consider this an error and either throw or return an +// // error value? +// std::list::iterator it = std::find(m_threads.begin(), +// m_threads.end(), thrd); +// BOOST_ASSERT(it == m_threads.end()); +// if (it == m_threads.end()) +// m_threads.push_back(thrd); +// } + +// void thread_group::remove_thread(thread* thrd) +// { +// mutex::scoped_lock scoped_lock(m_mutex); + +// // For now we'll simply ignore requests to remove a thread object that's +// // not in the group. Should we consider this an error and either throw or +// // return an error value? +// std::list::iterator it = std::find(m_threads.begin(), +// m_threads.end(), thrd); +// BOOST_ASSERT(it != m_threads.end()); +// if (it != m_threads.end()) +// m_threads.erase(it); +// } + +// void thread_group::join_all() +// { +// mutex::scoped_lock scoped_lock(m_mutex); +// for (std::list::iterator it = m_threads.begin(); +// it != m_threads.end(); ++it) +// { +// (*it)->join(); +// } +// } + +// void thread_group::interrupt_all() +// { +// boost::lock_guard guard(m_mutex); + +// for(std::list::iterator it=m_threads.begin(),end=m_threads.end(); +// it!=end; +// ++it) +// { +// (*it)->interrupt(); +// } +// } + + +// size_t thread_group::size() const +// { +// return m_threads.size(); +// } + +} diff --git a/deal.II/contrib/boost/libs/thread/src/pthread/timeconv.inl b/deal.II/contrib/boost/libs/thread/src/pthread/timeconv.inl new file mode 100644 index 0000000000..5ec3b1798a --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/src/pthread/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/deal.II/contrib/boost/libs/thread/src/tss_null.cpp b/deal.II/contrib/boost/libs/thread/src/tss_null.cpp new file mode 100644 index 0000000000..ff13b30f66 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/src/tss_null.cpp @@ -0,0 +1,34 @@ +// (C) Copyright Michael Glassford 2004. +// (C) Copyright 2007 Anthony Williams +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#if defined(BOOST_HAS_WINTHREADS) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST) || defined(UNDER_CE)) && (!defined(_MSC_VER) || defined(UNDER_CE)) + + /* + This file is a "null" implementation of tss cleanup; it's + purpose is to to eliminate link errors in cases + where it is known that tss cleanup is not needed. + */ + + extern "C" void tss_cleanup_implemented(void) + { + /* + This function's sole purpose is to cause a link error in cases where + automatic tss cleanup is not implemented by Boost.Threads as a + reminder that user code is responsible for calling the necessary + functions at the appropriate times (and for implementing an a + tss_cleanup_implemented() function to eliminate the linker's + missing symbol error). + + If Boost.Threads later implements automatic tss cleanup in cases + where it currently doesn't (which is the plan), the duplicate + symbol error will warn the user that their custom solution is no + longer needed and can be removed. + */ + } + +#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) && !defined(_MSC_VER) diff --git a/deal.II/contrib/boost/libs/thread/src/win32/exceptions.cpp b/deal.II/contrib/boost/libs/thread/src/win32/exceptions.cpp new file mode 100644 index 0000000000..8881303607 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/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/deal.II/contrib/boost/libs/thread/src/win32/thread.cpp b/deal.II/contrib/boost/libs/thread/src/win32/thread.cpp new file mode 100644 index 0000000000..9c4f82b011 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/src/win32/thread.cpp @@ -0,0 +1,595 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007 David Deakins + +#define _WIN32_WINNT 0x400 +#define WINVER 0x400 + +#include +#include +#include +#ifndef UNDER_CE +#include +#endif +#include +#include +#include +#include +#include +#include + +namespace boost +{ + namespace + { + boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT; + DWORD current_thread_tls_key=0; + + void create_current_thread_tls_key() + { + tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in + current_thread_tls_key=TlsAlloc(); + BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES); + } + + void cleanup_tls_key() + { + if(current_thread_tls_key) + { + TlsFree(current_thread_tls_key); + current_thread_tls_key=0; + } + } + + detail::thread_data_base* get_current_thread_data() + { + if(!current_thread_tls_key) + { + return 0; + } + return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key); + } + + void set_current_thread_data(detail::thread_data_base* new_data) + { + boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key); + BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data)); + } + +#ifdef BOOST_NO_THREADEX +// Windows CE doesn't define _beginthreadex + + struct ThreadProxyData + { + typedef unsigned (__stdcall* func)(void*); + func start_address_; + void* arglist_; + ThreadProxyData(func start_address,void* arglist) : start_address_(start_address), arglist_(arglist) {} + }; + + DWORD WINAPI ThreadProxy(LPVOID args) + { + ThreadProxyData* data=reinterpret_cast(args); + DWORD ret=data->start_address_(data->arglist_); + delete data; + return ret; + } + + typedef void* uintptr_t; + + inline uintptr_t const _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*), + void* arglist, unsigned initflag, unsigned* thrdaddr) + { + DWORD threadID; + HANDLE hthread=CreateThread(static_cast(security),stack_size,ThreadProxy, + new ThreadProxyData(start_address,arglist),initflag,&threadID); + if (hthread!=0) + *thrdaddr=threadID; + return reinterpret_cast(hthread); + } + +#endif + + } + + namespace detail + { + struct thread_exit_callback_node + { + boost::detail::thread_exit_function_base* func; + thread_exit_callback_node* next; + + thread_exit_callback_node(boost::detail::thread_exit_function_base* func_, + thread_exit_callback_node* next_): + func(func_),next(next_) + {} + }; + + struct tss_data_node + { + void const* key; + boost::shared_ptr func; + void* value; + tss_data_node* next; + + tss_data_node(void const* key_,boost::shared_ptr func_,void* value_, + tss_data_node* next_): + key(key_),func(func_),value(value_),next(next_) + {} + }; + + } + + namespace + { + void run_thread_exit_callbacks() + { + detail::thread_data_ptr current_thread_data(get_current_thread_data(),false); + if(current_thread_data) + { + while(current_thread_data->tss_data || current_thread_data->thread_exit_callbacks) + { + while(current_thread_data->thread_exit_callbacks) + { + detail::thread_exit_callback_node* const current_node=current_thread_data->thread_exit_callbacks; + current_thread_data->thread_exit_callbacks=current_node->next; + if(current_node->func) + { + (*current_node->func)(); + boost::detail::heap_delete(current_node->func); + } + boost::detail::heap_delete(current_node); + } + while(current_thread_data->tss_data) + { + detail::tss_data_node* const current_node=current_thread_data->tss_data; + current_thread_data->tss_data=current_node->next; + if(current_node->func) + { + (*current_node->func)(current_node->value); + } + boost::detail::heap_delete(current_node); + } + } + + set_current_thread_data(0); + } + } + + unsigned __stdcall thread_start_function(void* param) + { + detail::thread_data_base* const thread_info(reinterpret_cast(param)); + set_current_thread_data(thread_info); + try + { + thread_info->run(); + } + catch(thread_interrupted const&) + { + } + catch(...) + { + std::terminate(); + } + run_thread_exit_callbacks(); + return 0; + } + } + + thread::thread() + {} + + void thread::start_thread() + { + uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id); + if(!new_thread) + { + throw thread_resource_error(); + } + intrusive_ptr_add_ref(thread_info.get()); + thread_info->thread_handle=(detail::win32::handle)(new_thread); + ResumeThread(thread_info->thread_handle); + } + + thread::thread(detail::thread_data_ptr data): + thread_info(data) + {} + + namespace + { + struct externally_launched_thread: + detail::thread_data_base + { + externally_launched_thread() + { + ++count; + interruption_enabled=false; + } + + void run() + {} + private: + externally_launched_thread(externally_launched_thread&); + void operator=(externally_launched_thread&); + }; + + void make_external_thread_data() + { + externally_launched_thread* me=detail::heap_new(); + set_current_thread_data(me); + } + + detail::thread_data_base* get_or_make_current_thread_data() + { + detail::thread_data_base* current_thread_data(get_current_thread_data()); + if(!current_thread_data) + { + make_external_thread_data(); + current_thread_data=get_current_thread_data(); + } + return current_thread_data; + } + + } + + thread::~thread() + { + detach(); + } + + thread::id thread::get_id() const + { + return thread::id(get_thread_info()); + } + + bool thread::joinable() const + { + return get_thread_info(); + } + + void thread::join() + { + detail::thread_data_ptr local_thread_info=get_thread_info(); + if(local_thread_info) + { + this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel()); + release_handle(); + } + } + + bool thread::timed_join(boost::system_time const& wait_until) + { + detail::thread_data_ptr local_thread_info=get_thread_info(); + if(local_thread_info) + { + if(!this_thread::interruptible_wait(local_thread_info->thread_handle,get_milliseconds_until(wait_until))) + { + return false; + } + release_handle(); + } + return true; + } + + void thread::detach() + { + release_handle(); + } + + void thread::release_handle() + { + lock_guard l1(thread_info_mutex); + thread_info=0; + } + + void thread::interrupt() + { + detail::thread_data_ptr local_thread_info=get_thread_info(); + if(local_thread_info) + { + local_thread_info->interrupt(); + } + } + + bool thread::interruption_requested() const + { + detail::thread_data_ptr local_thread_info=get_thread_info(); + return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0); + } + + unsigned thread::hardware_concurrency() + { + SYSTEM_INFO info={0}; + GetSystemInfo(&info); + return info.dwNumberOfProcessors; + } + + thread::native_handle_type thread::native_handle() + { + detail::thread_data_ptr local_thread_info=get_thread_info(); + return local_thread_info?(detail::win32::handle)local_thread_info->thread_handle:detail::win32::invalid_handle_value; + } + + detail::thread_data_ptr thread::get_thread_info() const + { + boost::mutex::scoped_lock l(thread_info_mutex); + return thread_info; + } + + namespace this_thread + { + namespace + { + LARGE_INTEGER get_due_time(detail::timeout const& target_time) + { + LARGE_INTEGER due_time={0}; + if(target_time.relative) + { + unsigned long const elapsed_milliseconds=GetTickCount()-target_time.start; + LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds); + LONGLONG const hundred_nanoseconds_in_one_millisecond=10000; + + if(remaining_milliseconds>0) + { + due_time.QuadPart=-(remaining_milliseconds*hundred_nanoseconds_in_one_millisecond); + } + } + else + { + SYSTEMTIME target_system_time={0}; + target_system_time.wYear=target_time.abs_time.date().year(); + target_system_time.wMonth=target_time.abs_time.date().month(); + target_system_time.wDay=target_time.abs_time.date().day(); + target_system_time.wHour=(WORD)target_time.abs_time.time_of_day().hours(); + target_system_time.wMinute=(WORD)target_time.abs_time.time_of_day().minutes(); + target_system_time.wSecond=(WORD)target_time.abs_time.time_of_day().seconds(); + + if(!SystemTimeToFileTime(&target_system_time,((FILETIME*)&due_time))) + { + due_time.QuadPart=0; + } + else + { + long const hundred_nanoseconds_in_one_second=10000000; + due_time.QuadPart+=target_time.abs_time.time_of_day().fractional_seconds()*(hundred_nanoseconds_in_one_second/target_time.abs_time.time_of_day().ticks_per_second()); + } + } + return due_time; + } + } + + + bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time) + { + detail::win32::handle handles[3]={0}; + unsigned handle_count=0; + unsigned wait_handle_index=~0U; + unsigned interruption_index=~0U; + unsigned timeout_index=~0U; + if(handle_to_wait_for!=detail::win32::invalid_handle_value) + { + wait_handle_index=handle_count; + handles[handle_count++]=handle_to_wait_for; + } + if(get_current_thread_data() && get_current_thread_data()->interruption_enabled) + { + interruption_index=handle_count; + handles[handle_count++]=get_current_thread_data()->interruption_handle; + } + + detail::win32::handle_manager timer_handle; + +#ifndef UNDER_CE + unsigned const min_timer_wait_period=20; + + if(!target_time.is_sentinel()) + { + detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds(); + if(time_left.milliseconds > min_timer_wait_period) + { + // for a long-enough timeout, use a waitable timer (which tracks clock changes) + timer_handle=CreateWaitableTimer(NULL,false,NULL); + if(timer_handle!=0) + { + LARGE_INTEGER due_time=get_due_time(target_time); + + bool const set_time_succeeded=SetWaitableTimer(timer_handle,&due_time,0,0,0,false)!=0; + if(set_time_succeeded) + { + timeout_index=handle_count; + handles[handle_count++]=timer_handle; + } + } + } + else if(!target_time.relative) + { + // convert short absolute-time timeouts into relative ones, so we don't race against clock changes + target_time=detail::timeout(time_left.milliseconds); + } + } +#endif + + bool const using_timer=timeout_index!=~0u; + detail::timeout::remaining_time time_left(0); + + do + { + if(!using_timer) + { + time_left=target_time.remaining_milliseconds(); + } + + if(handle_count) + { + unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds); + if(notified_indexinterruption_handle); + throw thread_interrupted(); + } + else if(notified_index==timeout_index) + { + return false; + } + } + } + else + { + detail::win32::Sleep(time_left.milliseconds); + } + if(target_time.relative) + { + target_time.milliseconds-=detail::timeout::max_non_infinite_wait; + } + } + while(time_left.more); + return false; + } + + thread::id get_id() + { + return thread::id(get_or_make_current_thread_data()); + } + + void interruption_point() + { + if(interruption_enabled() && interruption_requested()) + { + detail::win32::ResetEvent(get_current_thread_data()->interruption_handle); + throw thread_interrupted(); + } + } + + bool interruption_enabled() + { + return get_current_thread_data() && get_current_thread_data()->interruption_enabled; + } + + bool interruption_requested() + { + return get_current_thread_data() && (detail::win32::WaitForSingleObject(get_current_thread_data()->interruption_handle,0)==0); + } + + void yield() + { + detail::win32::Sleep(0); + } + + disable_interruption::disable_interruption(): + interruption_was_enabled(interruption_enabled()) + { + if(interruption_was_enabled) + { + get_current_thread_data()->interruption_enabled=false; + } + } + + disable_interruption::~disable_interruption() + { + if(get_current_thread_data()) + { + get_current_thread_data()->interruption_enabled=interruption_was_enabled; + } + } + + restore_interruption::restore_interruption(disable_interruption& d) + { + if(d.interruption_was_enabled) + { + get_current_thread_data()->interruption_enabled=true; + } + } + + restore_interruption::~restore_interruption() + { + if(get_current_thread_data()) + { + get_current_thread_data()->interruption_enabled=false; + } + } + } + + namespace detail + { + void add_thread_exit_function(thread_exit_function_base* func) + { + detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); + thread_exit_callback_node* const new_node= + heap_new(func, + current_thread_data->thread_exit_callbacks); + current_thread_data->thread_exit_callbacks=new_node; + } + + tss_data_node* find_tss_data(void const* key) + { + detail::thread_data_base* const current_thread_data(get_current_thread_data()); + if(current_thread_data) + { + detail::tss_data_node* current_node=current_thread_data->tss_data; + while(current_node) + { + if(current_node->key==key) + { + return current_node; + } + current_node=current_node->next; + } + } + return NULL; + } + + void* get_tss_data(void const* key) + { + if(tss_data_node* const current_node=find_tss_data(key)) + { + return current_node->value; + } + return NULL; + } + + void set_tss_data(void const* key,boost::shared_ptr func,void* tss_data,bool cleanup_existing) + { + if(tss_data_node* const current_node=find_tss_data(key)) + { + if(cleanup_existing && current_node->func.get()) + { + (*current_node->func)(current_node->value); + } + current_node->func=func; + current_node->value=tss_data; + } + else + { + detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); + tss_data_node* const new_node=heap_new(key,func,tss_data,current_thread_data->tss_data); + current_thread_data->tss_data=new_node; + } + } + } +} + + +extern "C" BOOST_THREAD_DECL void on_process_enter() +{} + +extern "C" BOOST_THREAD_DECL void on_thread_enter() +{} + +extern "C" BOOST_THREAD_DECL void on_process_exit() +{ + boost::cleanup_tls_key(); +} + +extern "C" BOOST_THREAD_DECL void on_thread_exit() +{ + boost::run_thread_exit_callbacks(); +} + diff --git a/deal.II/contrib/boost/libs/thread/src/win32/timeconv.inl b/deal.II/contrib/boost/libs/thread/src/win32/timeconv.inl new file mode 100644 index 0000000000..5ec3b1798a --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/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/deal.II/contrib/boost/libs/thread/src/win32/tss_dll.cpp b/deal.II/contrib/boost/libs/thread/src/win32/tss_dll.cpp new file mode 100644 index 0000000000..0522a12360 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/src/win32/tss_dll.cpp @@ -0,0 +1,72 @@ +// (C) Copyright Michael Glassford 2004. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL) + + #include + + #define WIN32_LEAN_AND_MEAN + #include + + #if defined(__BORLANDC__) + extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/) + #elif defined(_WIN32_WCE) + extern "C" BOOL WINAPI DllMain(HANDLE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/) + #else + extern "C" BOOL WINAPI DllMain(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/) + #endif + { + switch(dwReason) + { + case DLL_PROCESS_ATTACH: + { + on_process_enter(); + on_thread_enter(); + break; + } + + case DLL_THREAD_ATTACH: + { + on_thread_enter(); + break; + } + + case DLL_THREAD_DETACH: + { + on_thread_exit(); + break; + } + + case DLL_PROCESS_DETACH: + { + on_thread_exit(); + on_process_exit(); + break; + } + } + + return TRUE; + } + + extern "C" void tss_cleanup_implemented(void) + { + /* + This function's sole purpose is to cause a link error in cases where + automatic tss cleanup is not implemented by Boost.Threads as a + reminder that user code is responsible for calling the necessary + functions at the appropriate times (and for implementing an a + tss_cleanup_implemented() function to eliminate the linker's + missing symbol error). + + If Boost.Threads later implements automatic tss cleanup in cases + where it currently doesn't (which is the plan), the duplicate + symbol error will warn the user that their custom solution is no + longer needed and can be removed. + */ + } + +#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL) diff --git a/deal.II/contrib/boost/libs/thread/src/win32/tss_pe.cpp b/deal.II/contrib/boost/libs/thread/src/win32/tss_pe.cpp new file mode 100644 index 0000000000..ae89bc41b2 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/src/win32/tss_pe.cpp @@ -0,0 +1,287 @@ +// $Id: tss_pe.cpp 49324 2008-10-13 20:30:13Z anthonyw $ +// (C) Copyright Aaron W. LaFramboise, Roland Schwarz, Michael Glassford 2004. +// (C) Copyright 2007 Roland Schwarz +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007 David Deakins +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) + +#if defined(__MINGW32__) && !defined(_WIN64) + +#include + +#include + +#include + +extern "C" void tss_cleanup_implemented(void) {} + +namespace { + void NTAPI on_tls_callback(void* h, DWORD dwReason, PVOID pv) + { + switch (dwReason) + { + case DLL_THREAD_DETACH: + { + on_thread_exit(); + break; + } + } + } + + void on_after_ctors(void) + { + on_process_enter(); + } + + void on_before_dtors(void) + { + on_thread_exit(); + } + + void on_after_dtors(void) + { + on_process_exit(); + } +} + +extern "C" { + + void (* after_ctors )(void) __attribute__((section(".ctors"))) = on_after_ctors; + void (* before_dtors)(void) __attribute__((section(".dtors"))) = on_before_dtors; + void (* after_dtors )(void) __attribute__((section(".dtors.zzz"))) = on_after_dtors; + + ULONG __tls_index__ = 0; + char __tls_end__ __attribute__((section(".tls$zzz"))) = 0; + char __tls_start__ __attribute__((section(".tls"))) = 0; + + + PIMAGE_TLS_CALLBACK __crt_xl_start__ __attribute__ ((section(".CRT$XLA"))) = 0; + PIMAGE_TLS_CALLBACK __crt_xl_tls_callback__ __attribute__ ((section(".CRT$XLB"))) = on_tls_callback; + PIMAGE_TLS_CALLBACK __crt_xl_end__ __attribute__ ((section(".CRT$XLZ"))) = 0; +} + +extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata$T"))) = +{ + (DWORD) &__tls_start__, + (DWORD) &__tls_end__, + (DWORD) &__tls_index__, + (DWORD) (&__crt_xl_start__+1), + (DWORD) 0, + (DWORD) 0 +}; + + +#elif defined(_MSC_VER) && !defined(UNDER_CE) + + #include + + #include + + #define WIN32_LEAN_AND_MEAN + #include + + //Definitions required by implementation + + #if (_MSC_VER < 1300) // 1300 == VC++ 7.0 + typedef void (__cdecl *_PVFV)(void); + #define INIRETSUCCESS + #define PVAPI void + #else + typedef int (__cdecl *_PVFV)(void); + #define INIRETSUCCESS 0 + #define PVAPI int + #endif + + typedef void (NTAPI* _TLSCB)(HINSTANCE, DWORD, PVOID); + + //Symbols for connection to the runtime environment + + extern "C" + { + extern DWORD _tls_used; //the tls directory (located in .rdata segment) + extern _TLSCB __xl_a[], __xl_z[]; //tls initializers */ + } + + namespace + { + //Forward declarations + + static PVAPI on_tls_prepare(void); + static PVAPI on_process_init(void); + static PVAPI on_process_term(void); + static void NTAPI on_tls_callback(HINSTANCE, DWORD, PVOID); + + //The .CRT$Xxx information is taken from Codeguru: + //http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/ + +#if (_MSC_VER >= 1400) +#pragma section(".CRT$XIU",long,read) +#pragma section(".CRT$XCU",long,read) +#pragma section(".CRT$XTU",long,read) +#pragma section(".CRT$XLC",long,read) + __declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback; + __declspec(allocate(".CRT$XIU"))_PVFV p_tls_prepare = on_tls_prepare; + __declspec(allocate(".CRT$XCU"))_PVFV p_process_init = on_process_init; + __declspec(allocate(".CRT$XTU"))_PVFV p_process_term = on_process_term; +#else + #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 + # pragma data_seg(push, old_seg) + #endif + //Callback to run tls glue code first. + //I don't think it is necessary to run it + //at .CRT$XIB level, since we are only + //interested in thread detachement. But + //this could be changed easily if required. + + #pragma data_seg(".CRT$XIU") + static _PVFV p_tls_prepare = on_tls_prepare; + #pragma data_seg() + + //Callback after all global ctors. + + #pragma data_seg(".CRT$XCU") + static _PVFV p_process_init = on_process_init; + #pragma data_seg() + + //Callback for tls notifications. + + #pragma data_seg(".CRT$XLB") + _TLSCB p_thread_callback = on_tls_callback; + #pragma data_seg() + //Callback for termination. + + #pragma data_seg(".CRT$XTU") + static _PVFV p_process_term = on_process_term; + #pragma data_seg() + #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 + # pragma data_seg(pop, old_seg) + #endif +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4189) +#endif + + PVAPI on_tls_prepare(void) + { + //The following line has an important side effect: + //if the TLS directory is not already there, it will + //be created by the linker. In other words, it forces a tls + //directory to be generated by the linker even when static tls + //(i.e. __declspec(thread)) is not used. + //The volatile should prevent the optimizer + //from removing the reference. + + DWORD volatile dw = _tls_used; + + #if (_MSC_VER < 1300) // 1300 == VC++ 7.0 + _TLSCB* pfbegin = __xl_a; + _TLSCB* pfend = __xl_z; + _TLSCB* pfdst = pfbegin; + //pfdst = (_TLSCB*)_tls_used.AddressOfCallBacks; + + //The following loop will merge the address pointers + //into a contiguous area, since the tlssup code seems + //to require this (at least on MSVC 6) + + while (pfbegin < pfend) + { + if (*pfbegin != 0) + { + *pfdst = *pfbegin; + ++pfdst; + } + ++pfbegin; + } + + *pfdst = 0; + #endif + + return INIRETSUCCESS; + } +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + + PVAPI on_process_init(void) + { + //Schedule on_thread_exit() to be called for the main + //thread before destructors of global objects have been + //called. + + //It will not be run when 'quick' exiting the + //library; however, this is the standard behaviour + //for destructors of global objects, so that + //shouldn't be a problem. + + atexit(on_thread_exit); + + //Call Boost process entry callback here + + on_process_enter(); + + return INIRETSUCCESS; + } + + PVAPI on_process_term(void) + { + on_process_exit(); + return INIRETSUCCESS; + } + + void NTAPI on_tls_callback(HINSTANCE /*h*/, DWORD dwReason, PVOID /*pv*/) + { + switch (dwReason) + { + case DLL_THREAD_DETACH: + on_thread_exit(); + break; + } + } + + BOOL WINAPI dll_callback(HANDLE, DWORD dwReason, LPVOID) + { + switch (dwReason) + { + case DLL_THREAD_DETACH: + on_thread_exit(); + break; + case DLL_PROCESS_DETACH: + on_process_exit(); + break; + } + return true; + } + } //namespace + +extern "C" +{ + extern BOOL (WINAPI * const _pRawDllMain)(HANDLE, DWORD, LPVOID)=&dll_callback; +} + + extern "C" void tss_cleanup_implemented(void) + { + /* + This function's sole purpose is to cause a link error in cases where + automatic tss cleanup is not implemented by Boost.Threads as a + reminder that user code is responsible for calling the necessary + functions at the appropriate times (and for implementing an a + tss_cleanup_implemented() function to eliminate the linker's + missing symbol error). + + If Boost.Threads later implements automatic tss cleanup in cases + where it currently doesn't (which is the plan), the duplicate + symbol error will warn the user that their custom solution is no + longer needed and can be removed. + */ + } +#endif //defined(_MSC_VER) && !defined(UNDER_CE) + +#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) diff --git a/deal.II/contrib/boost/libs/thread/test/Carbon.r b/deal.II/contrib/boost/libs/thread/test/Carbon.r new file mode 100644 index 0000000000..e0ac5b449e --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/Carbon.r @@ -0,0 +1,18 @@ +/* + * Permit this Carbon application to launch on OS X + * + * © 1997-2000 Metrowerks Corp. + * + * Questions and comments to: + * + * + */ + + +/*----------------------------carb Â¥ Carbon on OS X launch information --------------------------*/ +type 'carb' { +}; + + +resource 'carb'(0) { +}; diff --git a/deal.II/contrib/boost/libs/thread/test/Jamfile.v2 b/deal.II/contrib/boost/libs/thread/test/Jamfile.v2 new file mode 100644 index 0000000000..a6a769cb43 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/Jamfile.v2 @@ -0,0 +1,61 @@ +# (C) Copyright William E. Kempf 2001. +# (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) +# +# Boost.Threads test Jamfile +# +# Additional configuration variables used: +# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32 +# library should be used instead of "native" threads. This feature is +# mostly used for testing and it's generally recommended you use the +# native threading libraries instead. PTW32 should be set to be a list +# of two strings, the first specifying the installation path of the +# pthreads-win32 library and the second specifying which library +# variant to link against (see the pthreads-win32 documentation). +# Example: jam -sPTW32="c:\pthreads-win32 pthreadVCE.lib" + +# bring in rules for testing +import testing ; + +project + : requirements /boost/test//boost_unit_test_framework/static + multi + ; + +rule thread-run ( sources ) +{ + return + [ run $(sources) ../build//boost_thread ] + [ run $(sources) ../src/tss_null.cpp ../build//boost_thread/static + : : : : $(sources[1]:B)_lib ] + ; +} + +{ + test-suite "threads" + : [ thread-run test_thread.cpp ] + [ thread-run test_thread_id.cpp ] + [ thread-run test_hardware_concurrency.cpp ] + [ thread-run test_thread_move.cpp ] + [ thread-run test_thread_launching.cpp ] + [ thread-run test_thread_mf.cpp ] + [ thread-run test_move_function.cpp ] + [ thread-run test_mutex.cpp ] + [ thread-run test_condition_notify_one.cpp ] + [ thread-run test_condition_timed_wait_times_out.cpp ] + [ thread-run test_condition_notify_all.cpp ] + [ thread-run test_condition.cpp ] + [ thread-run test_tss.cpp ] + [ thread-run test_once.cpp ] + [ thread-run test_xtime.cpp ] + [ thread-run test_barrier.cpp ] + [ thread-run test_shared_mutex.cpp ] + [ thread-run test_shared_mutex_part_2.cpp ] + [ thread-run test_shared_mutex_timed_locks.cpp ] + [ thread-run test_lock_concept.cpp ] + [ thread-run test_generic_locks.cpp ] + [ compile-fail no_implicit_move_from_lvalue_thread.cpp ] + [ compile-fail no_implicit_assign_from_lvalue_thread.cpp ] + ; +} diff --git a/deal.II/contrib/boost/libs/thread/test/condition_test_common.hpp b/deal.II/contrib/boost/libs/thread/test/condition_test_common.hpp new file mode 100644 index 0000000000..38f7790989 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/condition_test_common.hpp @@ -0,0 +1,97 @@ +#ifndef CONDITION_TEST_COMMON_HPP +#define CONDITION_TEST_COMMON_HPP +// Copyright (C) 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +unsigned const timeout_seconds=5; + +struct wait_for_flag +{ + boost::mutex mutex; + boost::condition_variable cond_var; + bool flag; + unsigned woken; + + wait_for_flag(): + flag(false),woken(0) + {} + + struct check_flag + { + bool const& flag; + + check_flag(bool const& flag_): + flag(flag_) + {} + + bool operator()() const + { + return flag; + } + private: + void operator=(check_flag&); + }; + + + void wait_without_predicate() + { + boost::mutex::scoped_lock lock(mutex); + while(!flag) + { + cond_var.wait(lock); + } + ++woken; + } + + void wait_with_predicate() + { + boost::mutex::scoped_lock lock(mutex); + cond_var.wait(lock,check_flag(flag)); + if(flag) + { + ++woken; + } + } + + void timed_wait_without_predicate() + { + boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds); + + boost::mutex::scoped_lock lock(mutex); + while(!flag) + { + if(!cond_var.timed_wait(lock,timeout)) + { + return; + } + } + ++woken; + } + + void timed_wait_with_predicate() + { + boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds); + boost::mutex::scoped_lock lock(mutex); + if(cond_var.timed_wait(lock,timeout,check_flag(flag)) && flag) + { + ++woken; + } + } + void relative_timed_wait_with_predicate() + { + boost::mutex::scoped_lock lock(mutex); + if(cond_var.timed_wait(lock,boost::posix_time::seconds(timeout_seconds),check_flag(flag)) && flag) + { + ++woken; + } + } +}; + + +#endif diff --git a/deal.II/contrib/boost/libs/thread/test/no_implicit_assign_from_lvalue_thread.cpp b/deal.II/contrib/boost/libs/thread/test/no_implicit_assign_from_lvalue_thread.cpp new file mode 100644 index 0000000000..02b6893edd --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/no_implicit_assign_from_lvalue_thread.cpp @@ -0,0 +1,15 @@ +// Copyright (C) 2008 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include + +void do_nothing() +{} + +void test() +{ + boost::thread t1(do_nothing); + boost::thread t2; + t2=t1; +} diff --git a/deal.II/contrib/boost/libs/thread/test/no_implicit_move_from_lvalue_thread.cpp b/deal.II/contrib/boost/libs/thread/test/no_implicit_move_from_lvalue_thread.cpp new file mode 100644 index 0000000000..5c4600ec26 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/no_implicit_move_from_lvalue_thread.cpp @@ -0,0 +1,14 @@ +// Copyright (C) 2008 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include + +void do_nothing() +{} + +void test() +{ + boost::thread t1(do_nothing); + boost::thread t2(t1); +} diff --git a/deal.II/contrib/boost/libs/thread/test/shared_mutex_locking_thread.hpp b/deal.II/contrib/boost/libs/thread/test/shared_mutex_locking_thread.hpp new file mode 100644 index 0000000000..98a415b121 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/shared_mutex_locking_thread.hpp @@ -0,0 +1,132 @@ +#ifndef SHARED_MUTEX_LOCKING_THREAD_HPP +#define SHARED_MUTEX_LOCKING_THREAD_HPP + +// (C) Copyright 2008 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +template +class locking_thread +{ + boost::shared_mutex& rw_mutex; + unsigned& unblocked_count; + boost::condition_variable& unblocked_condition; + unsigned& simultaneous_running_count; + unsigned& max_simultaneous_running; + boost::mutex& unblocked_count_mutex; + boost::mutex& finish_mutex; +public: + locking_thread(boost::shared_mutex& rw_mutex_, + unsigned& unblocked_count_, + boost::mutex& unblocked_count_mutex_, + boost::condition_variable& unblocked_condition_, + boost::mutex& finish_mutex_, + unsigned& simultaneous_running_count_, + unsigned& max_simultaneous_running_): + rw_mutex(rw_mutex_), + unblocked_count(unblocked_count_), + unblocked_condition(unblocked_condition_), + simultaneous_running_count(simultaneous_running_count_), + max_simultaneous_running(max_simultaneous_running_), + unblocked_count_mutex(unblocked_count_mutex_), + finish_mutex(finish_mutex_) + {} + + void operator()() + { + // acquire lock + lock_type lock(rw_mutex); + + // increment count to show we're unblocked + { + boost::mutex::scoped_lock ublock(unblocked_count_mutex); + ++unblocked_count; + unblocked_condition.notify_one(); + ++simultaneous_running_count; + if(simultaneous_running_count>max_simultaneous_running) + { + max_simultaneous_running=simultaneous_running_count; + } + } + + // wait to finish + boost::mutex::scoped_lock finish_lock(finish_mutex); + { + boost::mutex::scoped_lock ublock(unblocked_count_mutex); + --simultaneous_running_count; + } + } +private: + void operator=(locking_thread&); +}; + +class simple_writing_thread +{ + boost::shared_mutex& rwm; + boost::mutex& finish_mutex; + boost::mutex& unblocked_mutex; + unsigned& unblocked_count; + + void operator=(simple_writing_thread&); + +public: + simple_writing_thread(boost::shared_mutex& rwm_, + boost::mutex& finish_mutex_, + boost::mutex& unblocked_mutex_, + unsigned& unblocked_count_): + rwm(rwm_),finish_mutex(finish_mutex_), + unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_) + {} + + void operator()() + { + boost::unique_lock lk(rwm); + + { + boost::mutex::scoped_lock ulk(unblocked_mutex); + ++unblocked_count; + } + + boost::mutex::scoped_lock flk(finish_mutex); + } +}; + +class simple_reading_thread +{ + boost::shared_mutex& rwm; + boost::mutex& finish_mutex; + boost::mutex& unblocked_mutex; + unsigned& unblocked_count; + + void operator=(simple_reading_thread&); + +public: + simple_reading_thread(boost::shared_mutex& rwm_, + boost::mutex& finish_mutex_, + boost::mutex& unblocked_mutex_, + unsigned& unblocked_count_): + rwm(rwm_),finish_mutex(finish_mutex_), + unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_) + {} + + void operator()() + { + boost::shared_lock lk(rwm); + + { + boost::mutex::scoped_lock ulk(unblocked_mutex); + ++unblocked_count; + } + + boost::mutex::scoped_lock flk(finish_mutex); + } +}; + + +#endif diff --git a/deal.II/contrib/boost/libs/thread/test/test.mcp b/deal.II/contrib/boost/libs/thread/test/test.mcp new file mode 100644 index 0000000000..f27f0b97b8 Binary files /dev/null and b/deal.II/contrib/boost/libs/thread/test/test.mcp differ diff --git a/deal.II/contrib/boost/libs/thread/test/test_barrier.cpp b/deal.II/contrib/boost/libs/thread/test/test_barrier.cpp new file mode 100644 index 0000000000..e487970421 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_barrier.cpp @@ -0,0 +1,66 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#include + +#include +#include + +namespace { + +// Shared variables for generation barrier test +const int N_THREADS=10; +boost::barrier gen_barrier(N_THREADS); +boost::mutex mutex; +long global_parameter; + +void barrier_thread() +{ + for (int i = 0; i < 5; ++i) + { + if (gen_barrier.wait()) + { + boost::mutex::scoped_lock lock(mutex); + global_parameter++; + } + } +} + +} // namespace + +void test_barrier() +{ + boost::thread_group g; + global_parameter = 0; + + try + { + for (int i = 0; i < N_THREADS; ++i) + g.create_thread(&barrier_thread); + g.join_all(); + } + catch(...) + { + g.interrupt_all(); + g.join_all(); + throw; + } + + BOOST_CHECK_EQUAL(global_parameter,5); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: barrier test suite"); + + test->add(BOOST_TEST_CASE(&test_barrier)); + + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_condition.cpp b/deal.II/contrib/boost/libs/thread/test/test_condition.cpp new file mode 100644 index 0000000000..ea008bfe1b --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_condition.cpp @@ -0,0 +1,190 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// Copyright (C) 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#include +#include + +#include + +#include + +struct condition_test_data +{ + condition_test_data() : notified(0), awoken(0) { } + + boost::mutex mutex; + boost::condition_variable condition; + int notified; + int awoken; +}; + +void condition_test_thread(condition_test_data* data) +{ + boost::mutex::scoped_lock lock(data->mutex); + BOOST_CHECK(lock ? true : false); + while (!(data->notified > 0)) + data->condition.wait(lock); + BOOST_CHECK(lock ? true : false); + data->awoken++; +} + +struct cond_predicate +{ + cond_predicate(int& var, int val) : _var(var), _val(val) { } + + bool operator()() { return _var == _val; } + + int& _var; + int _val; +private: + void operator=(cond_predicate&); + +}; + +void condition_test_waits(condition_test_data* data) +{ + boost::mutex::scoped_lock lock(data->mutex); + BOOST_CHECK(lock ? true : false); + + // Test wait. + while (data->notified != 1) + data->condition.wait(lock); + BOOST_CHECK(lock ? true : false); + BOOST_CHECK_EQUAL(data->notified, 1); + data->awoken++; + data->condition.notify_one(); + + // Test predicate wait. + data->condition.wait(lock, cond_predicate(data->notified, 2)); + BOOST_CHECK(lock ? true : false); + BOOST_CHECK_EQUAL(data->notified, 2); + data->awoken++; + data->condition.notify_one(); + + // Test timed_wait. + boost::xtime xt = delay(10); + while (data->notified != 3) + data->condition.timed_wait(lock, xt); + BOOST_CHECK(lock ? true : false); + BOOST_CHECK_EQUAL(data->notified, 3); + data->awoken++; + data->condition.notify_one(); + + // Test predicate timed_wait. + xt = delay(10); + cond_predicate pred(data->notified, 4); + BOOST_CHECK(data->condition.timed_wait(lock, xt, pred)); + BOOST_CHECK(lock ? true : false); + BOOST_CHECK(pred()); + BOOST_CHECK_EQUAL(data->notified, 4); + data->awoken++; + data->condition.notify_one(); + + // Test predicate timed_wait with relative timeout + cond_predicate pred_rel(data->notified, 5); + BOOST_CHECK(data->condition.timed_wait(lock, boost::posix_time::seconds(10), pred_rel)); + BOOST_CHECK(lock ? true : false); + BOOST_CHECK(pred_rel()); + BOOST_CHECK_EQUAL(data->notified, 5); + data->awoken++; + data->condition.notify_one(); +} + +void do_test_condition_waits() +{ + condition_test_data data; + + boost::thread thread(bind(&condition_test_waits, &data)); + + { + boost::mutex::scoped_lock lock(data.mutex); + BOOST_CHECK(lock ? true : false); + + boost::thread::sleep(delay(1)); + data.notified++; + data.condition.notify_one(); + while (data.awoken != 1) + data.condition.wait(lock); + BOOST_CHECK(lock ? true : false); + BOOST_CHECK_EQUAL(data.awoken, 1); + + boost::thread::sleep(delay(1)); + data.notified++; + data.condition.notify_one(); + while (data.awoken != 2) + data.condition.wait(lock); + BOOST_CHECK(lock ? true : false); + BOOST_CHECK_EQUAL(data.awoken, 2); + + boost::thread::sleep(delay(1)); + data.notified++; + data.condition.notify_one(); + while (data.awoken != 3) + data.condition.wait(lock); + BOOST_CHECK(lock ? true : false); + BOOST_CHECK_EQUAL(data.awoken, 3); + + boost::thread::sleep(delay(1)); + data.notified++; + data.condition.notify_one(); + while (data.awoken != 4) + data.condition.wait(lock); + BOOST_CHECK(lock ? true : false); + BOOST_CHECK_EQUAL(data.awoken, 4); + + + boost::thread::sleep(delay(1)); + data.notified++; + data.condition.notify_one(); + while (data.awoken != 5) + data.condition.wait(lock); + BOOST_CHECK(lock ? true : false); + BOOST_CHECK_EQUAL(data.awoken, 5); + } + + thread.join(); + BOOST_CHECK_EQUAL(data.awoken, 5); +} + +void test_condition_waits() +{ + // We should have already tested notify_one here, so + // a timed test with the default execution_monitor::use_condition + // should be OK, and gives the fastest performance + timed_test(&do_test_condition_waits, 12); +} + +void do_test_condition_wait_is_a_interruption_point() +{ + condition_test_data data; + + boost::thread thread(bind(&condition_test_thread, &data)); + + thread.interrupt(); + thread.join(); + BOOST_CHECK_EQUAL(data.awoken,0); +} + + +void test_condition_wait_is_a_interruption_point() +{ + timed_test(&do_test_condition_wait_is_a_interruption_point, 1); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: condition test suite"); + + test->add(BOOST_TEST_CASE(&test_condition_waits)); + test->add(BOOST_TEST_CASE(&test_condition_wait_is_a_interruption_point)); + + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_condition_notify_all.cpp b/deal.II/contrib/boost/libs/thread/test/test_condition_notify_all.cpp new file mode 100644 index 0000000000..11a983ebf4 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_condition_notify_all.cpp @@ -0,0 +1,222 @@ +// Copyright (C) 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include + +#include + +#include +#include "condition_test_common.hpp" + +unsigned const number_of_test_threads=5; + +void do_test_condition_notify_all_wakes_from_wait() +{ + wait_for_flag data; + + boost::thread_group group; + + try + { + for(unsigned i=0;iadd(BOOST_TEST_CASE(&test_condition_notify_all)); + + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_condition_notify_one.cpp b/deal.II/contrib/boost/libs/thread/test/test_condition_notify_one.cpp new file mode 100644 index 0000000000..a5d82becfc --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_condition_notify_one.cpp @@ -0,0 +1,155 @@ +// Copyright (C) 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include + +#include + +#include +#include "condition_test_common.hpp" + +void do_test_condition_notify_one_wakes_from_wait() +{ + wait_for_flag data; + + boost::thread thread(bind(&wait_for_flag::wait_without_predicate, data)); + + { + boost::mutex::scoped_lock lock(data.mutex); + data.flag=true; + data.cond_var.notify_one(); + } + + thread.join(); + BOOST_CHECK(data.woken); +} + +void do_test_condition_notify_one_wakes_from_wait_with_predicate() +{ + wait_for_flag data; + + boost::thread thread(bind(&wait_for_flag::wait_with_predicate, data)); + + { + boost::mutex::scoped_lock lock(data.mutex); + data.flag=true; + data.cond_var.notify_one(); + } + + thread.join(); + BOOST_CHECK(data.woken); +} + +void do_test_condition_notify_one_wakes_from_timed_wait() +{ + wait_for_flag data; + + boost::thread thread(bind(&wait_for_flag::timed_wait_without_predicate, data)); + + { + boost::mutex::scoped_lock lock(data.mutex); + data.flag=true; + data.cond_var.notify_one(); + } + + thread.join(); + BOOST_CHECK(data.woken); +} + +void do_test_condition_notify_one_wakes_from_timed_wait_with_predicate() +{ + wait_for_flag data; + + boost::thread thread(bind(&wait_for_flag::timed_wait_with_predicate, data)); + + { + boost::mutex::scoped_lock lock(data.mutex); + data.flag=true; + data.cond_var.notify_one(); + } + + thread.join(); + BOOST_CHECK(data.woken); +} + +void do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate() +{ + wait_for_flag data; + + boost::thread thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data)); + + { + boost::mutex::scoped_lock lock(data.mutex); + data.flag=true; + data.cond_var.notify_one(); + } + + thread.join(); + BOOST_CHECK(data.woken); +} + +namespace +{ + boost::mutex multiple_wake_mutex; + boost::condition_variable multiple_wake_cond; + unsigned multiple_wake_count=0; + + void wait_for_condvar_and_increase_count() + { + boost::mutex::scoped_lock lk(multiple_wake_mutex); + multiple_wake_cond.wait(lk); + ++multiple_wake_count; + } + +} + + +void do_test_multiple_notify_one_calls_wakes_multiple_threads() +{ + boost::thread thread1(wait_for_condvar_and_increase_count); + boost::thread thread2(wait_for_condvar_and_increase_count); + + boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + multiple_wake_cond.notify_one(); + + boost::thread thread3(wait_for_condvar_and_increase_count); + + boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + multiple_wake_cond.notify_one(); + multiple_wake_cond.notify_one(); + boost::this_thread::sleep(boost::posix_time::milliseconds(200)); + + { + boost::mutex::scoped_lock lk(multiple_wake_mutex); + BOOST_CHECK(multiple_wake_count==3); + } + + thread1.join(); + thread2.join(); + thread3.join(); +} + +void test_condition_notify_one() +{ + timed_test(&do_test_condition_notify_one_wakes_from_wait, timeout_seconds, execution_monitor::use_mutex); + timed_test(&do_test_condition_notify_one_wakes_from_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex); + timed_test(&do_test_condition_notify_one_wakes_from_timed_wait, timeout_seconds, execution_monitor::use_mutex); + timed_test(&do_test_condition_notify_one_wakes_from_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex); + timed_test(&do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex); + timed_test(&do_test_multiple_notify_one_calls_wakes_multiple_threads, timeout_seconds, execution_monitor::use_mutex); +} + + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: condition test suite"); + + test->add(BOOST_TEST_CASE(&test_condition_notify_one)); + + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_condition_timed_wait_times_out.cpp b/deal.II/contrib/boost/libs/thread/test/test_condition_timed_wait_times_out.cpp new file mode 100644 index 0000000000..9e17003f78 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_condition_timed_wait_times_out.cpp @@ -0,0 +1,173 @@ +// Copyright (C) 2007-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#include + +#include +#include "util.inl" + +bool fake_predicate() +{ + return false; +} + +unsigned const timeout_seconds=2; +unsigned const timeout_grace=1; +boost::posix_time::milliseconds const timeout_resolution(100); + + +void do_test_timed_wait_times_out() +{ + boost::condition_variable cond; + boost::mutex m; + + boost::posix_time::seconds const delay(timeout_seconds); + boost::mutex::scoped_lock lock(m); + boost::system_time const start=boost::get_system_time(); + boost::system_time const timeout=start+delay; + + while(cond.timed_wait(lock,timeout)); + + boost::system_time const end=boost::get_system_time(); + BOOST_CHECK((delay-timeout_resolution)<=(end-start)); +} + +void do_test_timed_wait_with_predicate_times_out() +{ + boost::condition_variable cond; + boost::mutex m; + + boost::posix_time::seconds const delay(timeout_seconds); + boost::mutex::scoped_lock lock(m); + boost::system_time const start=boost::get_system_time(); + boost::system_time const timeout=start+delay; + + bool const res=cond.timed_wait(lock,timeout,fake_predicate); + + boost::system_time const end=boost::get_system_time(); + BOOST_CHECK(!res); + BOOST_CHECK((delay-timeout_resolution)<=(end-start)); +} + +void do_test_relative_timed_wait_with_predicate_times_out() +{ + boost::condition_variable cond; + boost::mutex m; + + boost::posix_time::seconds const delay(timeout_seconds); + boost::mutex::scoped_lock lock(m); + boost::system_time const start=boost::get_system_time(); + + bool const res=cond.timed_wait(lock,delay,fake_predicate); + + boost::system_time const end=boost::get_system_time(); + BOOST_CHECK(!res); + BOOST_CHECK((delay-timeout_resolution)<=(end-start)); +} + +void do_test_timed_wait_relative_times_out() +{ + boost::condition_variable cond; + boost::mutex m; + + boost::posix_time::seconds const delay(timeout_seconds); + boost::mutex::scoped_lock lock(m); + boost::system_time const start=boost::get_system_time(); + + while(cond.timed_wait(lock,delay)); + + boost::system_time const end=boost::get_system_time(); + BOOST_CHECK((delay-timeout_resolution)<=(end-start)); +} + +void do_test_cv_any_timed_wait_times_out() +{ + boost::condition_variable_any cond; + boost::mutex m; + + boost::posix_time::seconds const delay(timeout_seconds); + boost::mutex::scoped_lock lock(m); + boost::system_time const start=boost::get_system_time(); + boost::system_time const timeout=start+delay; + + while(cond.timed_wait(lock,timeout)); + + boost::system_time const end=boost::get_system_time(); + BOOST_CHECK((delay-timeout_resolution)<=(end-start)); +} + +void do_test_cv_any_timed_wait_with_predicate_times_out() +{ + boost::condition_variable_any cond; + boost::mutex m; + + boost::posix_time::seconds const delay(timeout_seconds); + boost::mutex::scoped_lock lock(m); + boost::system_time const start=boost::get_system_time(); + boost::system_time const timeout=start+delay; + + bool const res=cond.timed_wait(lock,timeout,fake_predicate); + + boost::system_time const end=boost::get_system_time(); + BOOST_CHECK(!res); + BOOST_CHECK((delay-timeout_resolution)<=(end-start)); +} + +void do_test_cv_any_relative_timed_wait_with_predicate_times_out() +{ + boost::condition_variable_any cond; + boost::mutex m; + + boost::posix_time::seconds const delay(timeout_seconds); + boost::mutex::scoped_lock lock(m); + boost::system_time const start=boost::get_system_time(); + + bool const res=cond.timed_wait(lock,delay,fake_predicate); + + boost::system_time const end=boost::get_system_time(); + BOOST_CHECK(!res); + BOOST_CHECK((delay-timeout_resolution)<=(end-start)); +} + +void do_test_cv_any_timed_wait_relative_times_out() +{ + boost::condition_variable_any cond; + boost::mutex m; + + boost::posix_time::seconds const delay(timeout_seconds); + boost::mutex::scoped_lock lock(m); + boost::system_time const start=boost::get_system_time(); + + while(cond.timed_wait(lock,delay)); + + boost::system_time const end=boost::get_system_time(); + BOOST_CHECK((delay-timeout_resolution)<=(end-start)); +} + + +void test_timed_wait_times_out() +{ + timed_test(&do_test_timed_wait_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex); + timed_test(&do_test_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex); + timed_test(&do_test_relative_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex); + timed_test(&do_test_timed_wait_relative_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex); + timed_test(&do_test_cv_any_timed_wait_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex); + timed_test(&do_test_cv_any_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex); + timed_test(&do_test_cv_any_relative_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex); + timed_test(&do_test_cv_any_timed_wait_relative_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: condition test suite"); + + test->add(BOOST_TEST_CASE(&test_timed_wait_times_out)); + + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_generic_locks.cpp b/deal.II/contrib/boost/libs/thread/test/test_generic_locks.cpp new file mode 100644 index 0000000000..d3880d5c18 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_generic_locks.cpp @@ -0,0 +1,523 @@ +// (C) Copyright 2008 Anthony Williams +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include + +void test_lock_two_uncontended() +{ + boost::mutex m1,m2; + + boost::mutex::scoped_lock l1(m1,boost::defer_lock), + l2(m2,boost::defer_lock); + + BOOST_CHECK(!l1.owns_lock()); + BOOST_CHECK(!l2.owns_lock()); + + boost::lock(l1,l2); + + BOOST_CHECK(l1.owns_lock()); + BOOST_CHECK(l2.owns_lock()); +} + +struct wait_data +{ + boost::mutex m; + bool flag; + boost::condition_variable cond; + + wait_data(): + flag(false) + {} + + void wait() + { + boost::mutex::scoped_lock l(m); + while(!flag) + { + cond.wait(l); + } + } + + template + bool timed_wait(Duration d) + { + boost::system_time const target=boost::get_system_time()+d; + + boost::mutex::scoped_lock l(m); + while(!flag) + { + if(!cond.timed_wait(l,target)) + { + return flag; + } + } + return true; + } + + void signal() + { + boost::mutex::scoped_lock l(m); + flag=true; + cond.notify_all(); + } +}; + + +void lock_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,wait_data* locked,wait_data* quit) +{ + boost::lock_guard l1(*m1); + boost::this_thread::sleep(boost::posix_time::milliseconds(500)); + boost::lock_guard l2(*m2); + locked->signal(); + quit->wait(); +} + +void lock_pair(boost::mutex* m1,boost::mutex* m2) +{ + boost::lock(*m1,*m2); + boost::mutex::scoped_lock l1(*m1,boost::adopt_lock), + l2(*m2,boost::adopt_lock); +} + +void test_lock_two_other_thread_locks_in_order() +{ + boost::mutex m1,m2; + wait_data locked; + wait_data release; + + boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release); + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + + boost::thread t2(lock_pair,&m1,&m2); + BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1))); + + release.signal(); + + BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1))); + + t.join(); +} + +void test_lock_two_other_thread_locks_in_opposite_order() +{ + boost::mutex m1,m2; + wait_data locked; + wait_data release; + + boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release); + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + + boost::thread t2(lock_pair,&m2,&m1); + BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1))); + + release.signal(); + + BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1))); + + t.join(); +} + +void test_lock_five_uncontended() +{ + boost::mutex m1,m2,m3,m4,m5; + + boost::mutex::scoped_lock l1(m1,boost::defer_lock), + l2(m2,boost::defer_lock), + l3(m3,boost::defer_lock), + l4(m4,boost::defer_lock), + l5(m5,boost::defer_lock); + + BOOST_CHECK(!l1.owns_lock()); + BOOST_CHECK(!l2.owns_lock()); + BOOST_CHECK(!l3.owns_lock()); + BOOST_CHECK(!l4.owns_lock()); + BOOST_CHECK(!l5.owns_lock()); + + boost::lock(l1,l2,l3,l4,l5); + + BOOST_CHECK(l1.owns_lock()); + BOOST_CHECK(l2.owns_lock()); + BOOST_CHECK(l3.owns_lock()); + BOOST_CHECK(l4.owns_lock()); + BOOST_CHECK(l5.owns_lock()); +} + +void lock_five_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5, + wait_data* locked,wait_data* quit) +{ + boost::lock_guard l1(*m1); + boost::this_thread::sleep(boost::posix_time::milliseconds(500)); + boost::lock_guard l2(*m2); + boost::this_thread::sleep(boost::posix_time::milliseconds(500)); + boost::lock_guard l3(*m3); + boost::this_thread::sleep(boost::posix_time::milliseconds(500)); + boost::lock_guard l4(*m4); + boost::this_thread::sleep(boost::posix_time::milliseconds(500)); + boost::lock_guard l5(*m5); + locked->signal(); + quit->wait(); +} + +void lock_five(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5) +{ + boost::lock(*m1,*m2,*m3,*m4,*m5); + m1->unlock(); + m2->unlock(); + m3->unlock(); + m4->unlock(); + m5->unlock(); +} + +void test_lock_five_other_thread_locks_in_order() +{ + boost::mutex m1,m2,m3,m4,m5; + wait_data locked; + wait_data release; + + boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release); + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + + boost::thread t2(lock_five,&m1,&m2,&m3,&m4,&m5); + BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3))); + + release.signal(); + + BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3))); + + t.join(); +} + +void test_lock_five_other_thread_locks_in_different_order() +{ + boost::mutex m1,m2,m3,m4,m5; + wait_data locked; + wait_data release; + + boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release); + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + + boost::thread t2(lock_five,&m5,&m1,&m4,&m2,&m3); + BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3))); + + release.signal(); + + BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3))); + + t.join(); +} + +void lock_n(boost::mutex* mutexes,unsigned count) +{ + boost::lock(mutexes,mutexes+count); + for(unsigned i=0;i + struct is_mutex_type + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; +} + + + +void test_lock_five_in_range() +{ + unsigned const num_mutexes=5; + dummy_mutex mutexes[num_mutexes]; + + boost::lock(mutexes,mutexes+num_mutexes); + + for(unsigned i=0;i l1(m1,boost::defer_lock), + l2(m2,boost::defer_lock); + + int const res=boost::try_lock(l1,l2); + + BOOST_CHECK(res==0); + BOOST_CHECK(m1.is_locked); + BOOST_CHECK(!m2.is_locked); + BOOST_CHECK(!l1.owns_lock()); + BOOST_CHECK(!l2.owns_lock()); +} +void test_try_lock_two_second_locked() +{ + dummy_mutex m1,m2; + m2.lock(); + + boost::unique_lock l1(m1,boost::defer_lock), + l2(m2,boost::defer_lock); + + int const res=boost::try_lock(l1,l2); + + BOOST_CHECK(res==1); + BOOST_CHECK(!m1.is_locked); + BOOST_CHECK(m2.is_locked); + BOOST_CHECK(!l1.owns_lock()); + BOOST_CHECK(!l2.owns_lock()); +} + +void test_try_lock_three() +{ + int const num_mutexes=3; + + for(int i=-1;i=0) + { + mutexes[i].lock(); + } + boost::unique_lock l1(mutexes[0],boost::defer_lock), + l2(mutexes[1],boost::defer_lock), + l3(mutexes[2],boost::defer_lock); + + int const res=boost::try_lock(l1,l2,l3); + + BOOST_CHECK(res==i); + for(int j=0;j=0) + { + mutexes[i].lock(); + } + boost::unique_lock l1(mutexes[0],boost::defer_lock), + l2(mutexes[1],boost::defer_lock), + l3(mutexes[2],boost::defer_lock), + l4(mutexes[3],boost::defer_lock); + + int const res=boost::try_lock(l1,l2,l3,l4); + + BOOST_CHECK(res==i); + for(int j=0;j=0) + { + mutexes[i].lock(); + } + boost::unique_lock l1(mutexes[0],boost::defer_lock), + l2(mutexes[1],boost::defer_lock), + l3(mutexes[2],boost::defer_lock), + l4(mutexes[3],boost::defer_lock), + l5(mutexes[4],boost::defer_lock); + + int const res=boost::try_lock(l1,l2,l3,l4,l5); + + BOOST_CHECK(res==i); + for(int j=0;jadd(BOOST_TEST_CASE(&test_lock_two_uncontended)); + test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_order)); + test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_opposite_order)); + test->add(BOOST_TEST_CASE(&test_lock_five_uncontended)); + test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_order)); + test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_different_order)); + test->add(BOOST_TEST_CASE(&test_lock_five_in_range)); + test->add(BOOST_TEST_CASE(&test_lock_ten_in_range)); + test->add(BOOST_TEST_CASE(&test_lock_ten_other_thread_locks_in_different_order)); + test->add(BOOST_TEST_CASE(&test_try_lock_two_uncontended)); + test->add(BOOST_TEST_CASE(&test_try_lock_two_first_locked)); + test->add(BOOST_TEST_CASE(&test_try_lock_two_second_locked)); + test->add(BOOST_TEST_CASE(&test_try_lock_three)); + test->add(BOOST_TEST_CASE(&test_try_lock_four)); + test->add(BOOST_TEST_CASE(&test_try_lock_five)); + + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_hardware_concurrency.cpp b/deal.II/contrib/boost/libs/thread/test/test_hardware_concurrency.cpp new file mode 100644 index 0000000000..7c1c148b7b --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_hardware_concurrency.cpp @@ -0,0 +1,21 @@ +// Copyright (C) 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include +#include +#include + +void test_hardware_concurrency_is_non_zero() +{ + BOOST_CHECK(boost::thread::hardware_concurrency()!=0); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: hardware concurrency test suite"); + + test->add(BOOST_TEST_CASE(test_hardware_concurrency_is_non_zero)); + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_lock_concept.cpp b/deal.II/contrib/boost/libs/thread/test/test_lock_concept.cpp new file mode 100644 index 0000000000..06367d5b84 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_lock_concept.cpp @@ -0,0 +1,571 @@ +// (C) Copyright 2006-8 Anthony Williams +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include +#include +#include + +template +struct test_initially_locked +{ + void operator()() const + { + Mutex m; + Lock lock(m); + + BOOST_CHECK(lock); + BOOST_CHECK(lock.owns_lock()); + } +}; + +template +struct test_initially_unlocked_if_other_thread_has_lock +{ + Mutex m; + boost::mutex done_mutex; + bool done; + bool locked; + boost::condition_variable done_cond; + + test_initially_unlocked_if_other_thread_has_lock(): + done(false),locked(false) + {} + + void locking_thread() + { + Lock lock(m); + + boost::lock_guard lk(done_mutex); + locked=lock.owns_lock(); + done=true; + done_cond.notify_one(); + } + + bool is_done() const + { + return done; + } + + + void operator()() + { + Lock lock(m); + + typedef test_initially_unlocked_if_other_thread_has_lock this_type; + + boost::thread t(&this_type::locking_thread,this); + + try + { + { + boost::mutex::scoped_lock lk(done_mutex); + BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2), + boost::bind(&this_type::is_done,this))); + BOOST_CHECK(!locked); + } + + lock.unlock(); + t.join(); + } + catch(...) + { + lock.unlock(); + t.join(); + throw; + } + } +}; + +template +struct test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock +{ + Mutex m; + boost::mutex done_mutex; + bool done; + bool locked; + boost::condition_variable done_cond; + + test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock(): + done(false),locked(false) + {} + + void locking_thread() + { + Lock lock(m,boost::try_to_lock); + + boost::lock_guard lk(done_mutex); + locked=lock.owns_lock(); + done=true; + done_cond.notify_one(); + } + + bool is_done() const + { + return done; + } + + + void operator()() + { + boost::unique_lock lock(m); + + typedef test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock this_type; + + boost::thread t(&this_type::locking_thread,this); + + try + { + { + boost::mutex::scoped_lock lk(done_mutex); + BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2), + boost::bind(&this_type::is_done,this))); + BOOST_CHECK(!locked); + } + + lock.unlock(); + t.join(); + } + catch(...) + { + lock.unlock(); + t.join(); + throw; + } + } +}; + +template +struct test_initially_locked_if_other_thread_has_shared_lock +{ + Mutex m; + boost::mutex done_mutex; + bool done; + bool locked; + boost::condition_variable done_cond; + + test_initially_locked_if_other_thread_has_shared_lock(): + done(false),locked(false) + {} + + void locking_thread() + { + Lock lock(m); + + boost::lock_guard lk(done_mutex); + locked=lock.owns_lock(); + done=true; + done_cond.notify_one(); + } + + bool is_done() const + { + return done; + } + + + void operator()() + { + boost::shared_lock lock(m); + + typedef test_initially_locked_if_other_thread_has_shared_lock this_type; + + boost::thread t(&this_type::locking_thread,this); + + try + { + { + boost::mutex::scoped_lock lk(done_mutex); + BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2), + boost::bind(&this_type::is_done,this))); + BOOST_CHECK(locked); + } + + lock.unlock(); + t.join(); + } + catch(...) + { + lock.unlock(); + t.join(); + throw; + } + } +}; + +template +struct test_initially_unlocked_with_defer_lock_parameter +{ + void operator()() const + { + Mutex m; + Lock lock(m,boost::defer_lock); + + BOOST_CHECK(!lock); + BOOST_CHECK(!lock.owns_lock()); + } +}; + +template +struct test_initially_locked_with_adopt_lock_parameter +{ + void operator()() const + { + Mutex m; + m.lock(); + Lock lock(m,boost::adopt_lock); + + BOOST_CHECK(lock); + BOOST_CHECK(lock.owns_lock()); + } +}; + + +template +struct test_unlocked_after_unlock_called +{ + void operator()() const + { + Mutex m; + Lock lock(m); + lock.unlock(); + BOOST_CHECK(!lock); + BOOST_CHECK(!lock.owns_lock()); + } +}; + +template +struct test_locked_after_lock_called +{ + void operator()() const + { + Mutex m; + Lock lock(m,boost::defer_lock); + lock.lock(); + BOOST_CHECK(lock); + BOOST_CHECK(lock.owns_lock()); + } +}; + +template +struct test_locked_after_try_lock_called +{ + void operator()() const + { + Mutex m; + Lock lock(m,boost::defer_lock); + lock.try_lock(); + BOOST_CHECK(lock); + BOOST_CHECK(lock.owns_lock()); + } +}; + +template +struct test_unlocked_after_try_lock_if_other_thread_has_lock +{ + Mutex m; + boost::mutex done_mutex; + bool done; + bool locked; + boost::condition_variable done_cond; + + test_unlocked_after_try_lock_if_other_thread_has_lock(): + done(false),locked(false) + {} + + void locking_thread() + { + Lock lock(m,boost::defer_lock); + + boost::lock_guard lk(done_mutex); + locked=lock.owns_lock(); + done=true; + done_cond.notify_one(); + } + + bool is_done() const + { + return done; + } + + + void operator()() + { + Lock lock(m); + + typedef test_unlocked_after_try_lock_if_other_thread_has_lock this_type; + + boost::thread t(&this_type::locking_thread,this); + + try + { + { + boost::mutex::scoped_lock lk(done_mutex); + BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2), + boost::bind(&this_type::is_done,this))); + BOOST_CHECK(!locked); + } + + lock.unlock(); + t.join(); + } + catch(...) + { + lock.unlock(); + t.join(); + throw; + } + } +}; + +template +struct test_throws_if_lock_called_when_already_locked +{ + void operator()() const + { + Mutex m; + Lock lock(m); + + BOOST_CHECK_THROW( lock.lock(), boost::lock_error ); + } +}; + +template +struct test_throws_if_try_lock_called_when_already_locked +{ + void operator()() const + { + Mutex m; + Lock lock(m); + + BOOST_CHECK_THROW( lock.try_lock(), boost::lock_error ); + } +}; + +template +struct test_throws_if_unlock_called_when_already_unlocked +{ + void operator()() const + { + Mutex m; + Lock lock(m); + lock.unlock(); + + BOOST_CHECK_THROW( lock.unlock(), boost::lock_error ); + } +}; +template +struct test_default_constructed_has_no_mutex_and_unlocked +{ + void operator()() const + { + Lock l; + BOOST_CHECK(!l.mutex()); + BOOST_CHECK(!l.owns_lock()); + }; +}; + + +template +struct test_locks_can_be_swapped +{ + void operator()() const + { + Mutex m1; + Mutex m2; + Mutex m3; + + Lock l1(m1); + Lock l2(m2); + + BOOST_CHECK_EQUAL(l1.mutex(),&m1); + BOOST_CHECK_EQUAL(l2.mutex(),&m2); + + l1.swap(l2); + + BOOST_CHECK_EQUAL(l1.mutex(),&m2); + BOOST_CHECK_EQUAL(l2.mutex(),&m1); + + swap(l1,l2); + + BOOST_CHECK_EQUAL(l1.mutex(),&m1); + BOOST_CHECK_EQUAL(l2.mutex(),&m2); + + l1.swap(Lock(m3)); + + BOOST_CHECK_EQUAL(l1.mutex(),&m3); + } +}; + +template +void test_lock_is_scoped_lock_concept_for_mutex() +{ + test_default_constructed_has_no_mutex_and_unlocked()(); + test_initially_locked()(); + test_initially_unlocked_with_defer_lock_parameter()(); + test_initially_locked_with_adopt_lock_parameter()(); + test_unlocked_after_unlock_called()(); + test_locked_after_lock_called()(); + test_throws_if_lock_called_when_already_locked()(); + test_throws_if_unlock_called_when_already_unlocked()(); + test_locks_can_be_swapped()(); + test_locked_after_try_lock_called()(); + test_throws_if_try_lock_called_when_already_locked()(); + test_unlocked_after_try_lock_if_other_thread_has_lock()(); +} + + +BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex) +{ + typedef typename Mutex::scoped_lock Lock; + + test_lock_is_scoped_lock_concept_for_mutex(); +} + +BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_unique_lock_is_scoped_lock,Mutex) +{ + typedef boost::unique_lock Lock; + + test_lock_is_scoped_lock_concept_for_mutex(); +} + +BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex) +{ + typedef typename Mutex::scoped_try_lock Lock; + + test_default_constructed_has_no_mutex_and_unlocked()(); + test_initially_locked()(); + test_initially_unlocked_if_other_thread_has_lock()(); + test_initially_unlocked_with_defer_lock_parameter()(); + test_initially_locked_with_adopt_lock_parameter()(); + test_unlocked_after_unlock_called()(); + test_locked_after_lock_called()(); + test_locked_after_try_lock_called()(); + test_unlocked_after_try_lock_if_other_thread_has_lock()(); + test_throws_if_lock_called_when_already_locked()(); + test_throws_if_try_lock_called_when_already_locked()(); + test_throws_if_unlock_called_when_already_unlocked()(); + test_locks_can_be_swapped()(); +} + +struct dummy_shared_mutex +{ + bool locked; + bool shared_locked; + bool shared_unlocked; + bool shared_timed_locked_relative; + bool shared_timed_locked_absolute; + bool timed_locked_relative; + bool timed_locked_absolute; + + dummy_shared_mutex(): + locked(false),shared_locked(false),shared_unlocked(false), + shared_timed_locked_relative(false), + shared_timed_locked_absolute(false), + timed_locked_relative(false), + timed_locked_absolute(false) + {} + + void lock() + { + locked=true; + } + + void lock_shared() + { + shared_locked=true; + } + + void unlock() + {} + + void unlock_shared() + { + shared_unlocked=true; + } + + bool timed_lock_shared(boost::system_time) + { + shared_timed_locked_absolute=true; + return false; + } + template + bool timed_lock_shared(Duration) + { + shared_timed_locked_relative=true; + return false; + } + bool timed_lock(boost::system_time) + { + timed_locked_absolute=true; + return false; + } + template + bool timed_lock(Duration) + { + timed_locked_relative=true; + return false; + } + +}; + + +void test_shared_lock() +{ + typedef boost::shared_mutex Mutex; + typedef boost::shared_lock Lock; + + test_default_constructed_has_no_mutex_and_unlocked()(); + test_initially_locked()(); + test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock()(); + test_initially_locked_if_other_thread_has_shared_lock()(); + test_initially_unlocked_with_defer_lock_parameter()(); + test_initially_locked_with_adopt_lock_parameter()(); + test_unlocked_after_unlock_called()(); + test_locked_after_lock_called()(); + test_locked_after_try_lock_called()(); + test_throws_if_lock_called_when_already_locked()(); + test_throws_if_try_lock_called_when_already_locked()(); + test_throws_if_unlock_called_when_already_unlocked()(); + test_locks_can_be_swapped()(); + + dummy_shared_mutex dummy; + boost::shared_lock lk(dummy); + BOOST_CHECK(dummy.shared_locked); + lk.unlock(); + BOOST_CHECK(dummy.shared_unlocked); + lk.timed_lock(boost::posix_time::milliseconds(5)); + BOOST_CHECK(dummy.shared_timed_locked_relative); + lk.timed_lock(boost::get_system_time()); + BOOST_CHECK(dummy.shared_timed_locked_absolute); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: lock concept test suite"); + + typedef boost::mpl::vector mutex_types_with_scoped_lock; + + test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_lock_concept,mutex_types_with_scoped_lock)); + + typedef boost::mpl::vector mutex_types_with_scoped_try_lock; + + test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,mutex_types_with_scoped_try_lock)); + + typedef boost::mpl::vector all_mutex_types; + + test->add(BOOST_TEST_CASE_TEMPLATE(test_unique_lock_is_scoped_lock,all_mutex_types)); + test->add(BOOST_TEST_CASE(&test_shared_lock)); + + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_move_function.cpp b/deal.II/contrib/boost/libs/thread/test/test_move_function.cpp new file mode 100644 index 0000000000..6400ada85b --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_move_function.cpp @@ -0,0 +1,124 @@ +// Copyright (C) 2007-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include +#include +#include +#include + +void do_nothing() +{} + +void test_thread_move_from_lvalue_on_construction() +{ + boost::thread src(do_nothing); + boost::thread::id src_id=src.get_id(); + boost::thread dest(boost::move(src)); + boost::thread::id dest_id=dest.get_id(); + BOOST_CHECK(src_id==dest_id); + BOOST_CHECK(src.get_id()==boost::thread::id()); + dest.join(); +} + +void test_thread_move_from_lvalue_on_assignment() +{ + boost::thread src(do_nothing); + boost::thread::id src_id=src.get_id(); + boost::thread dest; + dest=boost::move(src); + boost::thread::id dest_id=dest.get_id(); + BOOST_CHECK(src_id==dest_id); + BOOST_CHECK(src.get_id()==boost::thread::id()); + dest.join(); +} + +boost::thread start_thread() +{ + return boost::thread(do_nothing); +} + +void test_thread_move_from_rvalue_on_construction() +{ + boost::thread x(start_thread()); + BOOST_CHECK(x.get_id()!=boost::thread::id()); + x.join(); +} + +void test_thread_move_from_rvalue_using_explicit_move() +{ + boost::thread x(boost::move(start_thread())); + BOOST_CHECK(x.get_id()!=boost::thread::id()); + x.join(); +} + +void test_unique_lock_move_from_lvalue_on_construction() +{ + boost::mutex m; + boost::unique_lock l(m); + BOOST_CHECK(l.owns_lock()); + BOOST_CHECK(l.mutex()==&m); + + boost::unique_lock l2(boost::move(l)); + BOOST_CHECK(!l.owns_lock()); + BOOST_CHECK(!l.mutex()); + BOOST_CHECK(l2.owns_lock()); + BOOST_CHECK(l2.mutex()==&m); +} + +boost::unique_lock get_lock(boost::mutex& m) +{ + return boost::unique_lock(m); +} + + +void test_unique_lock_move_from_rvalue_on_construction() +{ + boost::mutex m; + boost::unique_lock l(get_lock(m)); + BOOST_CHECK(l.owns_lock()); + BOOST_CHECK(l.mutex()==&m); +} + +namespace user_test_ns +{ + template + T move(T& t) + { + return t.move(); + } + + bool move_called=false; + + struct nc: + public boost::shared_ptr + { + nc move() + { + move_called=true; + return nc(); + } + }; +} + +void test_move_for_user_defined_type_unaffected() +{ + user_test_ns::nc src; + user_test_ns::nc dest=move(src); + BOOST_CHECK(user_test_ns::move_called); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: thread move test suite"); + + test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_construction)); + test->add(BOOST_TEST_CASE(test_thread_move_from_rvalue_on_construction)); + test->add(BOOST_TEST_CASE(test_thread_move_from_rvalue_using_explicit_move)); + test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_assignment)); + test->add(BOOST_TEST_CASE(test_unique_lock_move_from_lvalue_on_construction)); + test->add(BOOST_TEST_CASE(test_unique_lock_move_from_rvalue_on_construction)); + test->add(BOOST_TEST_CASE(test_move_for_user_defined_type_unaffected)); + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_mutex.cpp b/deal.II/contrib/boost/libs/thread/test/test_mutex.cpp new file mode 100644 index 0000000000..8725a8fda2 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_mutex.cpp @@ -0,0 +1,347 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#include +#include +#include +#include + +#include + +#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only +#include + +template +struct test_lock +{ + typedef M mutex_type; + typedef typename M::scoped_lock lock_type; + + void operator()() + { + mutex_type mutex; + boost::condition condition; + + // Test the lock's constructors. + { + lock_type lock(mutex, boost::defer_lock); + BOOST_CHECK(!lock); + } + lock_type lock(mutex); + BOOST_CHECK(lock ? true : false); + + // Construct and initialize an xtime for a fast time out. + boost::xtime xt = delay(0, 100); + + // Test the lock and the mutex with condition variables. + // No one is going to notify this condition variable. We expect to + // time out. + BOOST_CHECK(!condition.timed_wait(lock, xt)); + BOOST_CHECK(lock ? true : false); + + // Test the lock and unlock methods. + lock.unlock(); + BOOST_CHECK(!lock); + lock.lock(); + BOOST_CHECK(lock ? true : false); + } +}; + +template +struct test_trylock +{ + typedef M mutex_type; + typedef typename M::scoped_try_lock try_lock_type; + + void operator()() + { + mutex_type mutex; + boost::condition condition; + + // Test the lock's constructors. + { + try_lock_type lock(mutex); + BOOST_CHECK(lock ? true : false); + } + { + try_lock_type lock(mutex, boost::defer_lock); + BOOST_CHECK(!lock); + } + try_lock_type lock(mutex); + BOOST_CHECK(lock ? true : false); + + // Construct and initialize an xtime for a fast time out. + boost::xtime xt = delay(0, 100); + + // Test the lock and the mutex with condition variables. + // No one is going to notify this condition variable. We expect to + // time out. + BOOST_CHECK(!condition.timed_wait(lock, xt)); + BOOST_CHECK(lock ? true : false); + + // Test the lock, unlock and trylock methods. + lock.unlock(); + BOOST_CHECK(!lock); + lock.lock(); + BOOST_CHECK(lock ? true : false); + lock.unlock(); + BOOST_CHECK(!lock); + BOOST_CHECK(lock.try_lock()); + BOOST_CHECK(lock ? true : false); + } +}; + +template +struct test_lock_times_out_if_other_thread_has_lock +{ + typedef boost::unique_lock Lock; + + Mutex m; + boost::mutex done_mutex; + bool done; + bool locked; + boost::condition_variable done_cond; + + test_lock_times_out_if_other_thread_has_lock(): + done(false),locked(false) + {} + + void locking_thread() + { + Lock lock(m,boost::defer_lock); + lock.timed_lock(boost::posix_time::milliseconds(50)); + + boost::lock_guard lk(done_mutex); + locked=lock.owns_lock(); + done=true; + done_cond.notify_one(); + } + + void locking_thread_through_constructor() + { + Lock lock(m,boost::posix_time::milliseconds(50)); + + boost::lock_guard lk(done_mutex); + locked=lock.owns_lock(); + done=true; + done_cond.notify_one(); + } + + bool is_done() const + { + return done; + } + + typedef test_lock_times_out_if_other_thread_has_lock this_type; + + void do_test(void (this_type::*test_func)()) + { + Lock lock(m); + + locked=false; + done=false; + + boost::thread t(test_func,this); + + try + { + { + boost::mutex::scoped_lock lk(done_mutex); + BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2), + boost::bind(&this_type::is_done,this))); + BOOST_CHECK(!locked); + } + + lock.unlock(); + t.join(); + } + catch(...) + { + lock.unlock(); + t.join(); + throw; + } + } + + + void operator()() + { + do_test(&this_type::locking_thread); + do_test(&this_type::locking_thread_through_constructor); + } +}; + +template +struct test_timedlock +{ + typedef M mutex_type; + typedef typename M::scoped_timed_lock timed_lock_type; + + static bool fake_predicate() + { + return false; + } + + void operator()() + { + test_lock_times_out_if_other_thread_has_lock()(); + + mutex_type mutex; + boost::condition condition; + + // Test the lock's constructors. + { + // Construct and initialize an xtime for a fast time out. + boost::system_time xt = boost::get_system_time()+boost::posix_time::milliseconds(100); + + timed_lock_type lock(mutex, xt); + BOOST_CHECK(lock ? true : false); + } + { + timed_lock_type lock(mutex, boost::defer_lock); + BOOST_CHECK(!lock); + } + timed_lock_type lock(mutex); + BOOST_CHECK(lock ? true : false); + + // Construct and initialize an xtime for a fast time out. + boost::system_time timeout = boost::get_system_time()+boost::posix_time::milliseconds(100); + + // Test the lock and the mutex with condition variables. + // No one is going to notify this condition variable. We expect to + // time out. + BOOST_CHECK(!condition.timed_wait(lock, timeout, fake_predicate)); + BOOST_CHECK(lock ? true : false); + + boost::system_time now=boost::get_system_time(); + boost::posix_time::milliseconds const timeout_resolution(20); + BOOST_CHECK((timeout-timeout_resolution) +struct test_recursive_lock +{ + typedef M mutex_type; + typedef typename M::scoped_lock lock_type; + + void operator()() + { + mutex_type mx; + lock_type lock1(mx); + lock_type lock2(mx); + } +}; + + +void do_test_mutex() +{ + test_lock()(); +} + +void test_mutex() +{ + timed_test(&do_test_mutex, 3); +} + +void do_test_try_mutex() +{ + test_lock()(); + test_trylock()(); +} + +void test_try_mutex() +{ + timed_test(&do_test_try_mutex, 3); +} + +void do_test_timed_mutex() +{ + test_lock()(); + test_trylock()(); + test_timedlock()(); +} + +void test_timed_mutex() +{ + timed_test(&do_test_timed_mutex, 3); +} + +void do_test_recursive_mutex() +{ + test_lock()(); + test_recursive_lock()(); +} + +void test_recursive_mutex() +{ + timed_test(&do_test_recursive_mutex, 3); +} + +void do_test_recursive_try_mutex() +{ + test_lock()(); + test_trylock()(); + test_recursive_lock()(); +} + +void test_recursive_try_mutex() +{ + timed_test(&do_test_recursive_try_mutex, 3); +} + +void do_test_recursive_timed_mutex() +{ + test_lock()(); + test_trylock()(); + test_timedlock()(); + test_recursive_lock()(); +} + +void test_recursive_timed_mutex() +{ + timed_test(&do_test_recursive_timed_mutex, 3); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: mutex test suite"); + + test->add(BOOST_TEST_CASE(&test_mutex)); + test->add(BOOST_TEST_CASE(&test_try_mutex)); + test->add(BOOST_TEST_CASE(&test_timed_mutex)); + test->add(BOOST_TEST_CASE(&test_recursive_mutex)); + test->add(BOOST_TEST_CASE(&test_recursive_try_mutex)); + test->add(BOOST_TEST_CASE(&test_recursive_timed_mutex)); + + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_once.cpp b/deal.II/contrib/boost/libs/thread/test/test_once.cpp new file mode 100644 index 0000000000..f0e2c1e5dc --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_once.cpp @@ -0,0 +1,191 @@ +// (C) Copyright 2006-7 Anthony Williams +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include + +boost::once_flag flag=BOOST_ONCE_INIT; +int var_to_init=0; +boost::mutex m; + +void initialize_variable() +{ + // ensure that if multiple threads get in here, they are serialized, so we can see the effect + boost::mutex::scoped_lock lock(m); + ++var_to_init; +} + + +void call_once_thread() +{ + unsigned const loop_count=100; + int my_once_value=0; + for(unsigned i=0;iadd(BOOST_TEST_CASE(test_call_once)); + test->add(BOOST_TEST_CASE(test_call_once_arbitrary_functor)); + test->add(BOOST_TEST_CASE(test_call_once_retried_on_exception)); + + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_shared_mutex.cpp b/deal.II/contrib/boost/libs/thread/test/test_shared_mutex.cpp new file mode 100644 index 0000000000..2cd4502b88 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_shared_mutex.cpp @@ -0,0 +1,285 @@ +// (C) Copyright 2006-7 Anthony Williams +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include "util.inl" +#include "shared_mutex_locking_thread.hpp" + +#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \ + { \ + boost::mutex::scoped_lock lock(mutex_name); \ + BOOST_CHECK_EQUAL(value,expected_value); \ + } + +void test_multiple_readers() +{ + unsigned const number_of_threads=10; + + boost::thread_group pool; + + boost::shared_mutex rw_mutex; + unsigned unblocked_count=0; + unsigned simultaneous_running_count=0; + unsigned max_simultaneous_running=0; + boost::mutex unblocked_count_mutex; + boost::condition_variable unblocked_condition; + boost::mutex finish_mutex; + boost::mutex::scoped_lock finish_lock(finish_mutex); + + try + { + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + + { + boost::mutex::scoped_lock lk(unblocked_count_mutex); + while(unblocked_count >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + + boost::thread::sleep(delay(2)); + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); + + finish_lock.unlock(); + + pool.join_all(); + } + catch(...) + { + pool.interrupt_all(); + pool.join_all(); + throw; + } + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u); +} + +void test_reader_blocks_writer() +{ + boost::thread_group pool; + + boost::shared_mutex rw_mutex; + unsigned unblocked_count=0; + unsigned simultaneous_running_count=0; + unsigned max_simultaneous_running=0; + boost::mutex unblocked_count_mutex; + boost::condition_variable unblocked_condition; + boost::mutex finish_mutex; + boost::mutex::scoped_lock finish_lock(finish_mutex); + + try + { + + pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + { + boost::mutex::scoped_lock lk(unblocked_count_mutex); + while(unblocked_count<1) + { + unblocked_condition.wait(lk); + } + } + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); + pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); + + finish_lock.unlock(); + + pool.join_all(); + } + catch(...) + { + pool.interrupt_all(); + pool.join_all(); + throw; + } + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,2U); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u); +} + +void test_unlocking_writer_unblocks_all_readers() +{ + boost::thread_group pool; + + boost::shared_mutex rw_mutex; + boost::unique_lock write_lock(rw_mutex); + unsigned unblocked_count=0; + unsigned simultaneous_running_count=0; + unsigned max_simultaneous_running=0; + boost::mutex unblocked_count_mutex; + boost::condition_variable unblocked_condition; + boost::mutex finish_mutex; + boost::mutex::scoped_lock finish_lock(finish_mutex); + + unsigned const reader_count=10; + + try + { + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,0U); + + write_lock.unlock(); + + { + boost::mutex::scoped_lock lk(unblocked_count_mutex); + while(unblocked_count >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_reading_mutex,simultaneous_running_readers,max_simultaneous_readers)); + } + boost::thread::sleep(delay(1)); + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_writing_mutex,simultaneous_running_writers,max_simultaneous_writers)); + } + { + boost::mutex::scoped_lock lk(unblocked_count_mutex); + while(unblocked_countadd(BOOST_TEST_CASE(&test_multiple_readers)); + test->add(BOOST_TEST_CASE(&test_only_one_writer_permitted)); + test->add(BOOST_TEST_CASE(&test_reader_blocks_writer)); + test->add(BOOST_TEST_CASE(&test_unlocking_writer_unblocks_all_readers)); + test->add(BOOST_TEST_CASE(&test_unlocking_last_reader_only_unblocks_one_writer)); + + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_shared_mutex_part_2.cpp b/deal.II/contrib/boost/libs/thread/test/test_shared_mutex_part_2.cpp new file mode 100644 index 0000000000..ae38838bb9 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_shared_mutex_part_2.cpp @@ -0,0 +1,290 @@ +// (C) Copyright 2006-7 Anthony Williams +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include "util.inl" +#include "shared_mutex_locking_thread.hpp" + +#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \ + { \ + boost::mutex::scoped_lock lock(mutex_name); \ + BOOST_CHECK_EQUAL(value,expected_value); \ + } + +class simple_upgrade_thread +{ + boost::shared_mutex& rwm; + boost::mutex& finish_mutex; + boost::mutex& unblocked_mutex; + unsigned& unblocked_count; + + void operator=(simple_upgrade_thread&); + +public: + simple_upgrade_thread(boost::shared_mutex& rwm_, + boost::mutex& finish_mutex_, + boost::mutex& unblocked_mutex_, + unsigned& unblocked_count_): + rwm(rwm_),finish_mutex(finish_mutex_), + unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_) + {} + + void operator()() + { + boost::upgrade_lock lk(rwm); + + { + boost::mutex::scoped_lock ulk(unblocked_mutex); + ++unblocked_count; + } + + boost::mutex::scoped_lock flk(finish_mutex); + } +}; + + +void test_only_one_upgrade_lock_permitted() +{ + unsigned const number_of_threads=10; + + boost::thread_group pool; + + boost::shared_mutex rw_mutex; + unsigned unblocked_count=0; + unsigned simultaneous_running_count=0; + unsigned max_simultaneous_running=0; + boost::mutex unblocked_count_mutex; + boost::condition_variable unblocked_condition; + boost::mutex finish_mutex; + boost::mutex::scoped_lock finish_lock(finish_mutex); + + try + { + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + + boost::thread::sleep(delay(1)); + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); + + finish_lock.unlock(); + + pool.join_all(); + } + catch(...) + { + pool.interrupt_all(); + pool.join_all(); + throw; + } + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u); +} + +void test_can_lock_upgrade_if_currently_locked_shared() +{ + boost::thread_group pool; + + boost::shared_mutex rw_mutex; + unsigned unblocked_count=0; + unsigned simultaneous_running_count=0; + unsigned max_simultaneous_running=0; + boost::mutex unblocked_count_mutex; + boost::condition_variable unblocked_condition; + boost::mutex finish_mutex; + boost::mutex::scoped_lock finish_lock(finish_mutex); + + unsigned const reader_count=10; + + try + { + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + boost::thread::sleep(delay(1)); + pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + { + boost::mutex::scoped_lock lk(unblocked_count_mutex); + while(unblocked_count<(reader_count+1)) + { + unblocked_condition.wait(lk); + } + } + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1); + + finish_lock.unlock(); + pool.join_all(); + } + catch(...) + { + pool.interrupt_all(); + pool.join_all(); + throw; + } + + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count+1); +} + +void test_if_other_thread_has_write_lock_try_lock_shared_returns_false() +{ + + boost::shared_mutex rw_mutex; + boost::mutex finish_mutex; + boost::mutex unblocked_mutex; + unsigned unblocked_count=0; + boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); + boost::this_thread::sleep(boost::posix_time::seconds(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); + + bool const try_succeeded=rw_mutex.try_lock_shared(); + BOOST_CHECK(!try_succeeded); + if(try_succeeded) + { + rw_mutex.unlock_shared(); + } + + finish_lock.unlock(); + writer.join(); +} + +void test_if_other_thread_has_write_lock_try_lock_upgrade_returns_false() +{ + + boost::shared_mutex rw_mutex; + boost::mutex finish_mutex; + boost::mutex unblocked_mutex; + unsigned unblocked_count=0; + boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); + boost::this_thread::sleep(boost::posix_time::seconds(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); + + bool const try_succeeded=rw_mutex.try_lock_upgrade(); + BOOST_CHECK(!try_succeeded); + if(try_succeeded) + { + rw_mutex.unlock_upgrade(); + } + + finish_lock.unlock(); + writer.join(); +} + +void test_if_no_thread_has_lock_try_lock_shared_returns_true() +{ + boost::shared_mutex rw_mutex; + bool const try_succeeded=rw_mutex.try_lock_shared(); + BOOST_CHECK(try_succeeded); + if(try_succeeded) + { + rw_mutex.unlock_shared(); + } +} + +void test_if_no_thread_has_lock_try_lock_upgrade_returns_true() +{ + boost::shared_mutex rw_mutex; + bool const try_succeeded=rw_mutex.try_lock_upgrade(); + BOOST_CHECK(try_succeeded); + if(try_succeeded) + { + rw_mutex.unlock_upgrade(); + } +} + +void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true() +{ + + boost::shared_mutex rw_mutex; + boost::mutex finish_mutex; + boost::mutex unblocked_mutex; + unsigned unblocked_count=0; + boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); + + bool const try_succeeded=rw_mutex.try_lock_shared(); + BOOST_CHECK(try_succeeded); + if(try_succeeded) + { + rw_mutex.unlock_shared(); + } + + finish_lock.unlock(); + writer.join(); +} + +void test_if_other_thread_has_shared_lock_try_lock_upgrade_returns_true() +{ + + boost::shared_mutex rw_mutex; + boost::mutex finish_mutex; + boost::mutex unblocked_mutex; + unsigned unblocked_count=0; + boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); + + bool const try_succeeded=rw_mutex.try_lock_upgrade(); + BOOST_CHECK(try_succeeded); + if(try_succeeded) + { + rw_mutex.unlock_upgrade(); + } + + finish_lock.unlock(); + writer.join(); +} + +void test_if_other_thread_has_upgrade_lock_try_lock_upgrade_returns_false() +{ + + boost::shared_mutex rw_mutex; + boost::mutex finish_mutex; + boost::mutex unblocked_mutex; + unsigned unblocked_count=0; + boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::thread writer(simple_upgrade_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); + boost::this_thread::sleep(boost::posix_time::seconds(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); + + bool const try_succeeded=rw_mutex.try_lock_upgrade(); + BOOST_CHECK(!try_succeeded); + if(try_succeeded) + { + rw_mutex.unlock_upgrade(); + } + + finish_lock.unlock(); + writer.join(); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite"); + + test->add(BOOST_TEST_CASE(&test_only_one_upgrade_lock_permitted)); + test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_if_currently_locked_shared)); + test->add(BOOST_TEST_CASE(&test_if_other_thread_has_write_lock_try_lock_shared_returns_false)); + test->add(BOOST_TEST_CASE(&test_if_no_thread_has_lock_try_lock_shared_returns_true)); + test->add(BOOST_TEST_CASE(&test_if_other_thread_has_shared_lock_try_lock_shared_returns_true)); + + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_shared_mutex_timed_locks.cpp b/deal.II/contrib/boost/libs/thread/test/test_shared_mutex_timed_locks.cpp new file mode 100644 index 0000000000..04efbc9ba1 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_shared_mutex_timed_locks.cpp @@ -0,0 +1,268 @@ +// (C) Copyright 2006-7 Anthony Williams +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include "util.inl" +#include "shared_mutex_locking_thread.hpp" + +#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \ + { \ + boost::mutex::scoped_lock lock(mutex_name); \ + BOOST_CHECK_EQUAL(value,expected_value); \ + } + + +void test_timed_lock_shared_times_out_if_write_lock_held() +{ + boost::shared_mutex rw_mutex; + boost::mutex finish_mutex; + boost::mutex unblocked_mutex; + unsigned unblocked_count=0; + boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); + + boost::system_time const start=boost::get_system_time(); + boost::system_time const timeout=start+boost::posix_time::milliseconds(500); + boost::posix_time::milliseconds const timeout_resolution(50); + bool timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout); + BOOST_CHECK((timeout-timeout_resolution)add(BOOST_TEST_CASE(&test_timed_lock_shared_times_out_if_write_lock_held)); + test->add(BOOST_TEST_CASE(&test_timed_lock_shared_succeeds_if_no_lock_held)); + test->add(BOOST_TEST_CASE(&test_timed_lock_shared_succeeds_if_read_lock_held)); + test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_if_write_lock_held)); + test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_if_read_lock_held)); + test->add(BOOST_TEST_CASE(&test_timed_lock_succeeds_if_no_lock_held)); + test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_but_read_lock_succeeds_if_read_lock_held)); + + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_thread.cpp b/deal.II/contrib/boost/libs/thread/test/test_thread.cpp new file mode 100644 index 0000000000..480e258abb --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_thread.cpp @@ -0,0 +1,234 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// Copyright (C) 2008 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#include +#include +#include +#include + +#include + +#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only +#include + +int test_value; + +void simple_thread() +{ + test_value = 999; +} + +void comparison_thread(boost::thread::id parent) +{ + boost::thread::id const my_id=boost::this_thread::get_id(); + + BOOST_CHECK(my_id != parent); + boost::thread::id const my_id2=boost::this_thread::get_id(); + BOOST_CHECK(my_id == my_id2); + + boost::thread::id const no_thread_id=boost::thread::id(); + BOOST_CHECK(my_id != no_thread_id); +} + +void test_sleep() +{ + boost::xtime xt = delay(3); + boost::thread::sleep(xt); + + // Ensure it's in a range instead of checking actual equality due to time + // lapse + BOOST_CHECK(in_range(xt, 2)); +} + +void do_test_creation() +{ + test_value = 0; + boost::thread thrd(&simple_thread); + thrd.join(); + BOOST_CHECK_EQUAL(test_value, 999); +} + +void test_creation() +{ + timed_test(&do_test_creation, 1); +} + +void do_test_id_comparison() +{ + boost::thread::id const self=boost::this_thread::get_id(); + boost::thread thrd(boost::bind(&comparison_thread, self)); + thrd.join(); +} + +void test_id_comparison() +{ + timed_test(&do_test_id_comparison, 1); +} + +void interruption_point_thread(boost::mutex* m,bool* failed) +{ + boost::mutex::scoped_lock lk(*m); + boost::this_thread::interruption_point(); + *failed=true; +} + +void do_test_thread_interrupts_at_interruption_point() +{ + boost::mutex m; + bool failed=false; + boost::mutex::scoped_lock lk(m); + boost::thread thrd(boost::bind(&interruption_point_thread,&m,&failed)); + thrd.interrupt(); + lk.unlock(); + thrd.join(); + BOOST_CHECK(!failed); +} + +void test_thread_interrupts_at_interruption_point() +{ + timed_test(&do_test_thread_interrupts_at_interruption_point, 1); +} + +void disabled_interruption_point_thread(boost::mutex* m,bool* failed) +{ + boost::mutex::scoped_lock lk(*m); + boost::this_thread::disable_interruption dc; + boost::this_thread::interruption_point(); + *failed=false; +} + +void do_test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point() +{ + boost::mutex m; + bool failed=true; + boost::mutex::scoped_lock lk(m); + boost::thread thrd(boost::bind(&disabled_interruption_point_thread,&m,&failed)); + thrd.interrupt(); + lk.unlock(); + thrd.join(); + BOOST_CHECK(!failed); +} + +void test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point() +{ + timed_test(&do_test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point, 1); +} + +struct non_copyable_functor: + boost::noncopyable +{ + unsigned value; + + non_copyable_functor(): + value(0) + {} + + void operator()() + { + value=999; + } +}; + +void do_test_creation_through_reference_wrapper() +{ + non_copyable_functor f; + + boost::thread thrd(boost::ref(f)); + thrd.join(); + BOOST_CHECK_EQUAL(f.value, 999u); +} + +void test_creation_through_reference_wrapper() +{ + timed_test(&do_test_creation_through_reference_wrapper, 1); +} + +struct long_running_thread +{ + boost::condition_variable cond; + boost::mutex mut; + bool done; + + long_running_thread(): + done(false) + {} + + void operator()() + { + boost::mutex::scoped_lock lk(mut); + while(!done) + { + cond.wait(lk); + } + } +}; + +void do_test_timed_join() +{ + long_running_thread f; + boost::thread thrd(boost::ref(f)); + BOOST_CHECK(thrd.joinable()); + boost::system_time xt=delay(3); + bool const joined=thrd.timed_join(xt); + BOOST_CHECK(in_range(boost::get_xtime(xt), 2)); + BOOST_CHECK(!joined); + BOOST_CHECK(thrd.joinable()); + { + boost::mutex::scoped_lock lk(f.mut); + f.done=true; + f.cond.notify_one(); + } + + xt=delay(3); + bool const joined2=thrd.timed_join(xt); + boost::system_time const now=boost::get_system_time(); + BOOST_CHECK(xt>now); + BOOST_CHECK(joined2); + BOOST_CHECK(!thrd.joinable()); +} + +void test_timed_join() +{ + timed_test(&do_test_timed_join, 10); +} + +void test_swap() +{ + boost::thread t(simple_thread); + boost::thread t2(simple_thread); + boost::thread::id id1=t.get_id(); + boost::thread::id id2=t2.get_id(); + + t.swap(t2); + BOOST_CHECK(t.get_id()==id2); + BOOST_CHECK(t2.get_id()==id1); + + swap(t,t2); + BOOST_CHECK(t.get_id()==id1); + BOOST_CHECK(t2.get_id()==id2); +} + + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: thread test suite"); + + test->add(BOOST_TEST_CASE(test_sleep)); + test->add(BOOST_TEST_CASE(test_creation)); + test->add(BOOST_TEST_CASE(test_id_comparison)); + test->add(BOOST_TEST_CASE(test_thread_interrupts_at_interruption_point)); + test->add(BOOST_TEST_CASE(test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point)); + test->add(BOOST_TEST_CASE(test_creation_through_reference_wrapper)); + test->add(BOOST_TEST_CASE(test_timed_join)); + test->add(BOOST_TEST_CASE(test_swap)); + + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_thread_id.cpp b/deal.II/contrib/boost/libs/thread/test/test_thread_id.cpp new file mode 100644 index 0000000000..777bc718dd --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_thread_id.cpp @@ -0,0 +1,149 @@ +// Copyright (C) 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include +#include +#include + +void do_nothing() +{} + +void test_thread_id_for_default_constructed_thread_is_default_constructed_id() +{ + boost::thread t; + BOOST_CHECK(t.get_id()==boost::thread::id()); +} + +void test_thread_id_for_running_thread_is_not_default_constructed_id() +{ + boost::thread t(do_nothing); + BOOST_CHECK(t.get_id()!=boost::thread::id()); + t.join(); +} + +void test_different_threads_have_different_ids() +{ + boost::thread t(do_nothing); + boost::thread t2(do_nothing); + BOOST_CHECK(t.get_id()!=t2.get_id()); + t.join(); + t2.join(); +} + +void test_thread_ids_have_a_total_order() +{ + boost::thread t(do_nothing); + boost::thread t2(do_nothing); + boost::thread t3(do_nothing); + BOOST_CHECK(t.get_id()!=t2.get_id()); + BOOST_CHECK(t.get_id()!=t3.get_id()); + BOOST_CHECK(t2.get_id()!=t3.get_id()); + + BOOST_CHECK((t.get_id()t2.get_id()) != (t2.get_id()>t.get_id())); + BOOST_CHECK((t.get_id()>t3.get_id()) != (t3.get_id()>t.get_id())); + BOOST_CHECK((t2.get_id()>t3.get_id()) != (t3.get_id()>t2.get_id())); + + BOOST_CHECK((t.get_id()t.get_id())); + BOOST_CHECK((t2.get_id()t2.get_id())); + BOOST_CHECK((t.get_id()t.get_id())); + BOOST_CHECK((t3.get_id()t3.get_id())); + BOOST_CHECK((t2.get_id()t2.get_id())); + BOOST_CHECK((t3.get_id()t3.get_id())); + + BOOST_CHECK((t.get_id()=t.get_id())); + BOOST_CHECK((t2.get_id()=t2.get_id())); + BOOST_CHECK((t.get_id()=t.get_id())); + BOOST_CHECK((t3.get_id()=t3.get_id())); + BOOST_CHECK((t2.get_id()=t2.get_id())); + BOOST_CHECK((t3.get_id()=t3.get_id())); + + BOOST_CHECK((t.get_id()<=t2.get_id()) == (t2.get_id()>t.get_id())); + BOOST_CHECK((t2.get_id()<=t.get_id()) == (t.get_id()>t2.get_id())); + BOOST_CHECK((t.get_id()<=t3.get_id()) == (t3.get_id()>t.get_id())); + BOOST_CHECK((t3.get_id()<=t.get_id()) == (t.get_id()>t3.get_id())); + BOOST_CHECK((t2.get_id()<=t3.get_id()) == (t3.get_id()>t2.get_id())); + BOOST_CHECK((t3.get_id()<=t2.get_id()) == (t2.get_id()>t3.get_id())); + + if((t.get_id() t.get_id())); + BOOST_CHECK(!(default_id > t2.get_id())); + BOOST_CHECK(!(default_id > t3.get_id())); + + BOOST_CHECK(!(default_id >= t.get_id())); + BOOST_CHECK(!(default_id >= t2.get_id())); + BOOST_CHECK(!(default_id >= t3.get_id())); + + t.join(); + t2.join(); + t3.join(); +} + +void get_thread_id(boost::thread::id* id) +{ + *id=boost::this_thread::get_id(); +} + +void test_thread_id_of_running_thread_returned_by_this_thread_get_id() +{ + boost::thread::id id; + boost::thread t(boost::bind(get_thread_id,&id)); + boost::thread::id t_id=t.get_id(); + t.join(); + BOOST_CHECK(id==t_id); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: thread move test suite"); + + test->add(BOOST_TEST_CASE(test_thread_id_for_default_constructed_thread_is_default_constructed_id)); + test->add(BOOST_TEST_CASE(test_thread_id_for_running_thread_is_not_default_constructed_id)); + test->add(BOOST_TEST_CASE(test_different_threads_have_different_ids)); + test->add(BOOST_TEST_CASE(test_thread_ids_have_a_total_order)); + test->add(BOOST_TEST_CASE(test_thread_id_of_running_thread_returned_by_this_thread_get_id)); + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_thread_launching.cpp b/deal.II/contrib/boost/libs/thread/test/test_thread_launching.cpp new file mode 100644 index 0000000000..4582e657ea --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_thread_launching.cpp @@ -0,0 +1,226 @@ +// Copyright (C) 2007-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include +#include +#include +#include +#include +#include + +bool normal_function_called=false; + +void normal_function() +{ + normal_function_called=true; +} + +void test_thread_function_no_arguments() +{ + boost::thread function(normal_function); + function.join(); + BOOST_CHECK(normal_function_called); +} + +int nfoa_res=0; + +void normal_function_one_arg(int i) +{ + nfoa_res=i; +} + +void test_thread_function_one_argument() +{ + boost::thread function(normal_function_one_arg,42); + function.join(); + BOOST_CHECK_EQUAL(42,nfoa_res); +} + +struct callable_no_args +{ + static bool called; + + void operator()() const + { + called=true; + } +}; + +bool callable_no_args::called=false; + +void test_thread_callable_object_no_arguments() +{ + callable_no_args func; + boost::thread callable(func); + callable.join(); + BOOST_CHECK(callable_no_args::called); +} + +struct callable_noncopyable_no_args: + boost::noncopyable +{ + static bool called; + + void operator()() const + { + called=true; + } +}; + +bool callable_noncopyable_no_args::called=false; + +void test_thread_callable_object_ref_no_arguments() +{ + callable_noncopyable_no_args func; + + boost::thread callable(boost::ref(func)); + callable.join(); + BOOST_CHECK(callable_noncopyable_no_args::called); +} + +struct callable_one_arg +{ + static bool called; + static int called_arg; + + void operator()(int arg) const + { + called=true; + called_arg=arg; + } +}; + +bool callable_one_arg::called=false; +int callable_one_arg::called_arg=0; + +void test_thread_callable_object_one_argument() +{ + callable_one_arg func; + boost::thread callable(func,42); + callable.join(); + BOOST_CHECK(callable_one_arg::called); + BOOST_CHECK_EQUAL(callable_one_arg::called_arg,42); +} + +struct callable_multiple_arg +{ + static bool called_two; + static int called_two_arg1; + static double called_two_arg2; + static bool called_three; + static std::string called_three_arg1; + static std::vector called_three_arg2; + static int called_three_arg3; + + void operator()(int arg1,double arg2) const + { + called_two=true; + called_two_arg1=arg1; + called_two_arg2=arg2; + } + void operator()(std::string const& arg1,std::vector const& arg2,int arg3) const + { + called_three=true; + called_three_arg1=arg1; + called_three_arg2=arg2; + called_three_arg3=arg3; + } +}; + +bool callable_multiple_arg::called_two=false; +bool callable_multiple_arg::called_three=false; +int callable_multiple_arg::called_two_arg1; +double callable_multiple_arg::called_two_arg2; +std::string callable_multiple_arg::called_three_arg1; +std::vector callable_multiple_arg::called_three_arg2; +int callable_multiple_arg::called_three_arg3; + +void test_thread_callable_object_multiple_arguments() +{ + std::vector x; + for(unsigned i=0;i<7;++i) + { + x.push_back(i*i); + } + + callable_multiple_arg func; + + boost::thread callable3(func,"hello",x,1.2); + callable3.join(); + BOOST_CHECK(callable_multiple_arg::called_three); + BOOST_CHECK_EQUAL(callable_multiple_arg::called_three_arg1,"hello"); + BOOST_CHECK_EQUAL(callable_multiple_arg::called_three_arg2.size(),x.size()); + for(unsigned j=0;jadd(BOOST_TEST_CASE(test_thread_function_no_arguments)); + test->add(BOOST_TEST_CASE(test_thread_function_one_argument)); + test->add(BOOST_TEST_CASE(test_thread_callable_object_no_arguments)); + test->add(BOOST_TEST_CASE(test_thread_callable_object_ref_no_arguments)); + test->add(BOOST_TEST_CASE(test_thread_callable_object_one_argument)); + test->add(BOOST_TEST_CASE(test_thread_callable_object_multiple_arguments)); + test->add(BOOST_TEST_CASE(test_thread_member_function_no_arguments)); + test->add(BOOST_TEST_CASE(test_thread_member_function_one_argument)); + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_thread_mf.cpp b/deal.II/contrib/boost/libs/thread/test/test_thread_mf.cpp new file mode 100644 index 0000000000..aa5a5dc1e3 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_thread_mf.cpp @@ -0,0 +1,134 @@ +// +// Copyright (C) 2008 Peter Dimov +// +// 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 + +struct X +{ + mutable unsigned int hash; + + X(): hash(0) {} + + int f0() { f1(17); return 0; } + int g0() const { g1(17); return 0; } + + int f1(int a1) { hash = (hash * 17041 + a1) % 32768; return 0; } + int g1(int a1) const { hash = (hash * 17041 + a1 * 2) % 32768; return 0; } + + int f2(int a1, int a2) { f1(a1); f1(a2); return 0; } + int g2(int a1, int a2) const { g1(a1); g1(a2); return 0; } + + int f3(int a1, int a2, int a3) { f2(a1, a2); f1(a3); return 0; } + int g3(int a1, int a2, int a3) const { g2(a1, a2); g1(a3); return 0; } + + int f4(int a1, int a2, int a3, int a4) { f3(a1, a2, a3); f1(a4); return 0; } + int g4(int a1, int a2, int a3, int a4) const { g3(a1, a2, a3); g1(a4); return 0; } + + int f5(int a1, int a2, int a3, int a4, int a5) { f4(a1, a2, a3, a4); f1(a5); return 0; } + int g5(int a1, int a2, int a3, int a4, int a5) const { g4(a1, a2, a3, a4); g1(a5); return 0; } + + int f6(int a1, int a2, int a3, int a4, int a5, int a6) { f5(a1, a2, a3, a4, a5); f1(a6); return 0; } + int g6(int a1, int a2, int a3, int a4, int a5, int a6) const { g5(a1, a2, a3, a4, a5); g1(a6); return 0; } + + int f7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) { f6(a1, a2, a3, a4, a5, a6); f1(a7); return 0; } + int g7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) const { g6(a1, a2, a3, a4, a5, a6); g1(a7); return 0; } + + int f8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) { f7(a1, a2, a3, a4, a5, a6, a7); f1(a8); return 0; } + int g8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) const { g7(a1, a2, a3, a4, a5, a6, a7); g1(a8); return 0; } +}; + +int main() +{ + X x; + + // 0 + + boost::thread( &X::f0, &x ).join(); + boost::thread( &X::f0, boost::ref(x) ).join(); + + boost::thread( &X::g0, &x ).join(); + boost::thread( &X::g0, x ).join(); + boost::thread( &X::g0, boost::ref(x) ).join(); + + // 1 + + boost::thread( &X::f1, &x, 1 ).join(); + boost::thread( &X::f1, boost::ref(x), 1 ).join(); + + boost::thread( &X::g1, &x, 1 ).join(); + boost::thread( &X::g1, x, 1 ).join(); + boost::thread( &X::g1, boost::ref(x), 1 ).join(); + + // 2 + + boost::thread( &X::f2, &x, 1, 2 ).join(); + boost::thread( &X::f2, boost::ref(x), 1, 2 ).join(); + + boost::thread( &X::g2, &x, 1, 2 ).join(); + boost::thread( &X::g2, x, 1, 2 ).join(); + boost::thread( &X::g2, boost::ref(x), 1, 2 ).join(); + + // 3 + + boost::thread( &X::f3, &x, 1, 2, 3 ).join(); + boost::thread( &X::f3, boost::ref(x), 1, 2, 3 ).join(); + + boost::thread( &X::g3, &x, 1, 2, 3 ).join(); + boost::thread( &X::g3, x, 1, 2, 3 ).join(); + boost::thread( &X::g3, boost::ref(x), 1, 2, 3 ).join(); + + // 4 + + boost::thread( &X::f4, &x, 1, 2, 3, 4 ).join(); + boost::thread( &X::f4, boost::ref(x), 1, 2, 3, 4 ).join(); + + boost::thread( &X::g4, &x, 1, 2, 3, 4 ).join(); + boost::thread( &X::g4, x, 1, 2, 3, 4 ).join(); + boost::thread( &X::g4, boost::ref(x), 1, 2, 3, 4 ).join(); + + // 5 + + boost::thread( &X::f5, &x, 1, 2, 3, 4, 5 ).join(); + boost::thread( &X::f5, boost::ref(x), 1, 2, 3, 4, 5 ).join(); + + boost::thread( &X::g5, &x, 1, 2, 3, 4, 5 ).join(); + boost::thread( &X::g5, x, 1, 2, 3, 4, 5 ).join(); + boost::thread( &X::g5, boost::ref(x), 1, 2, 3, 4, 5 ).join(); + + // 6 + + boost::thread( &X::f6, &x, 1, 2, 3, 4, 5, 6 ).join(); + boost::thread( &X::f6, boost::ref(x), 1, 2, 3, 4, 5, 6 ).join(); + + boost::thread( &X::g6, &x, 1, 2, 3, 4, 5, 6 ).join(); + boost::thread( &X::g6, x, 1, 2, 3, 4, 5, 6 ).join(); + boost::thread( &X::g6, boost::ref(x), 1, 2, 3, 4, 5, 6 ).join(); + + // 7 + + boost::thread( &X::f7, &x, 1, 2, 3, 4, 5, 6, 7).join(); + boost::thread( &X::f7, boost::ref(x), 1, 2, 3, 4, 5, 6, 7).join(); + + boost::thread( &X::g7, &x, 1, 2, 3, 4, 5, 6, 7).join(); + boost::thread( &X::g7, x, 1, 2, 3, 4, 5, 6, 7).join(); + boost::thread( &X::g7, boost::ref(x), 1, 2, 3, 4, 5, 6, 7).join(); + + // 8 + + boost::thread( &X::f8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join(); + boost::thread( &X::f8, boost::ref(x), 1, 2, 3, 4, 5, 6, 7, 8 ).join(); + + boost::thread( &X::g8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join(); + boost::thread( &X::g8, x, 1, 2, 3, 4, 5, 6, 7, 8 ).join(); + boost::thread( &X::g8, boost::ref(x), 1, 2, 3, 4, 5, 6, 7, 8 ).join(); + + BOOST_TEST( x.hash == 23558 ); + + return boost::report_errors(); +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_thread_move.cpp b/deal.II/contrib/boost/libs/thread/test/test_thread_move.cpp new file mode 100644 index 0000000000..550b62dd94 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_thread_move.cpp @@ -0,0 +1,72 @@ +// Copyright (C) 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include +#include + +void do_nothing(boost::thread::id* my_id) +{ + *my_id=boost::this_thread::get_id(); +} + +void test_move_on_construction() +{ + boost::thread::id the_id; + boost::thread x=boost::thread(do_nothing,&the_id); + boost::thread::id x_id=x.get_id(); + x.join(); + BOOST_CHECK_EQUAL(the_id,x_id); +} + +boost::thread make_thread(boost::thread::id* the_id) +{ + return boost::thread(do_nothing,the_id); +} + +void test_move_from_function_return() +{ + boost::thread::id the_id; + boost::thread x=make_thread(&the_id); + boost::thread::id x_id=x.get_id(); + x.join(); + BOOST_CHECK_EQUAL(the_id,x_id); +} + +boost::thread make_thread_return_lvalue(boost::thread::id* the_id) +{ + boost::thread t(do_nothing,the_id); + return boost::move(t); +} + +void test_move_from_function_return_lvalue() +{ + boost::thread::id the_id; + boost::thread x=make_thread_return_lvalue(&the_id); + boost::thread::id x_id=x.get_id(); + x.join(); + BOOST_CHECK_EQUAL(the_id,x_id); +} + +void test_move_assign() +{ + boost::thread::id the_id; + boost::thread x(do_nothing,&the_id); + boost::thread y; + y=boost::move(x); + boost::thread::id y_id=y.get_id(); + y.join(); + BOOST_CHECK_EQUAL(the_id,y_id); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: thread move test suite"); + + test->add(BOOST_TEST_CASE(test_move_on_construction)); + test->add(BOOST_TEST_CASE(test_move_from_function_return)); + test->add(BOOST_TEST_CASE(test_move_from_function_return_lvalue)); + test->add(BOOST_TEST_CASE(test_move_assign)); + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_tss.cpp b/deal.II/contrib/boost/libs/thread/test/test_tss.cpp new file mode 100644 index 0000000000..8a6545ce78 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_tss.cpp @@ -0,0 +1,324 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// Copyright (C) 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#include +#include + +#include + +#include + +#include + +#if defined(BOOST_HAS_WINTHREADS) + #define WIN32_LEAN_AND_MEAN + #include +#endif + +boost::mutex check_mutex; +boost::mutex tss_mutex; +int tss_instances = 0; +int tss_total = 0; + +struct tss_value_t +{ + tss_value_t() + { + boost::mutex::scoped_lock lock(tss_mutex); + ++tss_instances; + ++tss_total; + value = 0; + } + ~tss_value_t() + { + boost::mutex::scoped_lock lock(tss_mutex); + --tss_instances; + } + int value; +}; + +boost::thread_specific_ptr tss_value; + +void test_tss_thread() +{ + tss_value.reset(new tss_value_t()); + for (int i=0; i<1000; ++i) + { + int& n = tss_value->value; + // Don't call BOOST_CHECK_EQUAL directly, as it doesn't appear to + // be thread safe. Must evaluate further. + if (n != i) + { + boost::mutex::scoped_lock lock(check_mutex); + BOOST_CHECK_EQUAL(n, i); + } + ++n; + } +} + +#if defined(BOOST_THREAD_PLATFORM_WIN32) + typedef HANDLE native_thread_t; + + DWORD WINAPI test_tss_thread_native(LPVOID /*lpParameter*/) + { + test_tss_thread(); + return 0; + } + + native_thread_t create_native_thread(void) + { + native_thread_t const res=CreateThread( + 0, //security attributes (0 = not inheritable) + 0, //stack size (0 = default) + &test_tss_thread_native, //function to execute + 0, //parameter to pass to function + 0, //creation flags (0 = run immediately) + 0 //thread id (0 = thread id not returned) + ); + BOOST_CHECK(res!=0); + return res; + } + + void join_native_thread(native_thread_t thread) + { + DWORD res = WaitForSingleObject(thread, INFINITE); + BOOST_CHECK(res == WAIT_OBJECT_0); + + res = CloseHandle(thread); + BOOST_CHECK(SUCCEEDED(res)); + } +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) + typedef pthread_t native_thread_t; + +extern "C" +{ + void* test_tss_thread_native(void* lpParameter) + { + test_tss_thread(); + return 0; + } +} + + native_thread_t create_native_thread() + { + native_thread_t thread_handle; + + int const res = pthread_create(&thread_handle, 0, &test_tss_thread_native, 0); + BOOST_CHECK(!res); + return thread_handle; + } + + void join_native_thread(native_thread_t thread) + { + void* result=0; + int const res=pthread_join(thread,&result); + BOOST_CHECK(!res); + } +#endif + +void do_test_tss() +{ + tss_instances = 0; + tss_total = 0; + + const int NUMTHREADS=5; + boost::thread_group threads; + try + { + for (int i=0; i tss_with_cleanup(tss_custom_cleanup); + +void tss_thread_with_custom_cleanup() +{ + tss_with_cleanup.reset(new Dummy); +} + +void do_test_tss_with_custom_cleanup() +{ + boost::thread t(tss_thread_with_custom_cleanup); + try + { + t.join(); + } + catch(...) + { + t.interrupt(); + t.join(); + throw; + } + + BOOST_CHECK(tss_cleanup_called); +} + + +void test_tss_with_custom_cleanup() +{ + timed_test(&do_test_tss_with_custom_cleanup, 2); +} + +Dummy* tss_object=new Dummy; + +void tss_thread_with_custom_cleanup_and_release() +{ + tss_with_cleanup.reset(tss_object); + tss_with_cleanup.release(); +} + +void do_test_tss_does_no_cleanup_after_release() +{ + tss_cleanup_called=false; + boost::thread t(tss_thread_with_custom_cleanup_and_release); + try + { + t.join(); + } + catch(...) + { + t.interrupt(); + t.join(); + throw; + } + + BOOST_CHECK(!tss_cleanup_called); + if(!tss_cleanup_called) + { + delete tss_object; + } +} + +struct dummy_class_tracks_deletions +{ + static unsigned deletions; + + ~dummy_class_tracks_deletions() + { + ++deletions; + } + +}; + +unsigned dummy_class_tracks_deletions::deletions=0; + +boost::thread_specific_ptr tss_with_null_cleanup(NULL); + +void tss_thread_with_null_cleanup(dummy_class_tracks_deletions* delete_tracker) +{ + tss_with_null_cleanup.reset(delete_tracker); +} + +void do_test_tss_does_no_cleanup_with_null_cleanup_function() +{ + dummy_class_tracks_deletions* delete_tracker=new dummy_class_tracks_deletions; + boost::thread t(tss_thread_with_null_cleanup,delete_tracker); + try + { + t.join(); + } + catch(...) + { + t.interrupt(); + t.join(); + throw; + } + + BOOST_CHECK(!dummy_class_tracks_deletions::deletions); + if(!dummy_class_tracks_deletions::deletions) + { + delete delete_tracker; + } +} + +void test_tss_does_no_cleanup_after_release() +{ + timed_test(&do_test_tss_does_no_cleanup_after_release, 2); +} + +void test_tss_does_no_cleanup_with_null_cleanup_function() +{ + timed_test(&do_test_tss_does_no_cleanup_with_null_cleanup_function, 2); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: tss test suite"); + + test->add(BOOST_TEST_CASE(test_tss)); + test->add(BOOST_TEST_CASE(test_tss_with_custom_cleanup)); + test->add(BOOST_TEST_CASE(test_tss_does_no_cleanup_after_release)); + test->add(BOOST_TEST_CASE(test_tss_does_no_cleanup_with_null_cleanup_function)); + + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/test_xtime.cpp b/deal.II/contrib/boost/libs/thread/test/test_xtime.cpp new file mode 100644 index 0000000000..efdfd3c778 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/test_xtime.cpp @@ -0,0 +1,109 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// Copyright (C) 2008 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include + +#include +#include +#include + +void test_xtime_cmp() +{ + boost::xtime xt1, xt2, cur; + BOOST_CHECK_EQUAL( + boost::xtime_get(&cur, boost::TIME_UTC), + static_cast(boost::TIME_UTC)); + + xt1 = xt2 = cur; + xt1.nsec -= 1; + xt2.nsec += 1; + + BOOST_CHECK(boost::xtime_cmp(xt1, cur) < 0); + BOOST_CHECK(boost::xtime_cmp(xt2, cur) > 0); + BOOST_CHECK(boost::xtime_cmp(cur, cur) == 0); + + xt1 = xt2 = cur; + xt1.sec -= 1; + xt2.sec += 1; + + BOOST_CHECK(boost::xtime_cmp(xt1, cur) < 0); + BOOST_CHECK(boost::xtime_cmp(xt2, cur) > 0); + BOOST_CHECK(boost::xtime_cmp(cur, cur) == 0); +} + +void test_xtime_get() +{ + boost::xtime orig, cur, old; + BOOST_CHECK_EQUAL( + boost::xtime_get(&orig, + boost::TIME_UTC), static_cast(boost::TIME_UTC)); + old = orig; + + for (int x=0; x < 100; ++x) + { + BOOST_CHECK_EQUAL( + boost::xtime_get(&cur, boost::TIME_UTC), + static_cast(boost::TIME_UTC)); + BOOST_CHECK(boost::xtime_cmp(cur, orig) >= 0); + BOOST_CHECK(boost::xtime_cmp(cur, old) >= 0); + old = cur; + } +} + +void test_xtime_mutex_backwards_compatibility() +{ + boost::timed_mutex m; + BOOST_CHECK(m.timed_lock(boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)))); + m.unlock(); + boost::timed_mutex::scoped_timed_lock lk(m,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10))); + BOOST_CHECK(lk.owns_lock()); + if(lk.owns_lock()) + { + lk.unlock(); + } + BOOST_CHECK(lk.timed_lock(boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)))); + if(lk.owns_lock()) + { + lk.unlock(); + } +} + +bool predicate() +{ + return false; +} + + +void test_xtime_condvar_backwards_compatibility() +{ + boost::condition_variable cond; + boost::condition_variable_any cond_any; + boost::mutex m; + + boost::mutex::scoped_lock lk(m); + cond.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10))); + cond.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)),predicate); + cond_any.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10))); + cond_any.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)),predicate); +} + + + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: xtime test suite"); + + test->add(BOOST_TEST_CASE(&test_xtime_cmp)); + test->add(BOOST_TEST_CASE(&test_xtime_get)); + test->add(BOOST_TEST_CASE(&test_xtime_mutex_backwards_compatibility)); + test->add(BOOST_TEST_CASE(&test_xtime_condvar_backwards_compatibility)); + + return test; +} diff --git a/deal.II/contrib/boost/libs/thread/test/util.inl b/deal.II/contrib/boost/libs/thread/test/util.inl new file mode 100644 index 0000000000..60f88e0544 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/test/util.inl @@ -0,0 +1,183 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// Copyright (C) 2007-8 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) + +#if !defined(UTIL_INL_WEK01242003) +#define UTIL_INL_WEK01242003 + +#include +#include +#include +#include + +#ifndef DEFAULT_EXECUTION_MONITOR_TYPE +# define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_condition +#endif + +// boostinspect:nounnamed + +namespace +{ +inline boost::xtime delay(int secs, int msecs=0, int nsecs=0) +{ + const int MILLISECONDS_PER_SECOND = 1000; + const int NANOSECONDS_PER_SECOND = 1000000000; + const int NANOSECONDS_PER_MILLISECOND = 1000000; + + boost::xtime xt; + if (boost::TIME_UTC != boost::xtime_get (&xt, boost::TIME_UTC)) + BOOST_ERROR ("boost::xtime_get != boost::TIME_UTC"); + + nsecs += xt.nsec; + msecs += nsecs / NANOSECONDS_PER_MILLISECOND; + secs += msecs / MILLISECONDS_PER_SECOND; + nsecs += (msecs % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND; + xt.nsec = nsecs % NANOSECONDS_PER_SECOND; + xt.sec += secs + (nsecs / NANOSECONDS_PER_SECOND); + + return xt; +} + +inline bool in_range(const boost::xtime& xt, int secs=1) +{ + boost::xtime min = delay(-secs); + boost::xtime max = delay(0); + return (boost::xtime_cmp(xt, min) >= 0) && + (boost::xtime_cmp(xt, max) <= 0); +} + +class execution_monitor +{ +public: + enum wait_type { use_sleep_only, use_mutex, use_condition }; + + execution_monitor(wait_type type, int secs) + : done(false), type(type), secs(secs) { } + void start() + { + if (type != use_sleep_only) { + boost::mutex::scoped_lock lock(mutex); done = false; + } else { + done = false; + } + } + void finish() + { + if (type != use_sleep_only) { + boost::mutex::scoped_lock lock(mutex); + done = true; + if (type == use_condition) + cond.notify_one(); + } else { + done = true; + } + } + bool wait() + { + boost::xtime xt = delay(secs); + if (type != use_condition) + boost::thread::sleep(xt); + if (type != use_sleep_only) { + boost::mutex::scoped_lock lock(mutex); + while (type == use_condition && !done) { + if (!cond.timed_wait(lock, xt)) + break; + } + return done; + } + return done; + } + +private: + boost::mutex mutex; + boost::condition cond; + bool done; + wait_type type; + int secs; +}; + +template +class indirect_adapter +{ +public: + indirect_adapter(F func, execution_monitor& monitor) + : func(func), monitor(monitor) { } + void operator()() const + { + try + { + boost::thread thrd(func); + thrd.join(); + } + catch (...) + { + monitor.finish(); + throw; + } + monitor.finish(); + } + +private: + F func; + execution_monitor& monitor; + void operator=(indirect_adapter&); +}; + +template +void timed_test(F func, int secs, + execution_monitor::wait_type type=DEFAULT_EXECUTION_MONITOR_TYPE) +{ + execution_monitor monitor(type, secs); + indirect_adapter ifunc(func, monitor); + monitor.start(); + boost::thread thrd(ifunc); + BOOST_REQUIRE_MESSAGE(monitor.wait(), + "Timed test didn't complete in time, possible deadlock."); +} + +template +class thread_binder +{ +public: + thread_binder(const F& func, const T& param) + : func(func), param(param) { } + void operator()() const { func(param); } + +private: + F func; + T param; +}; + +template +thread_binder bind(const F& func, const T& param) +{ + return thread_binder(func, param); +} + +template +class thread_member_binder +{ +public: + thread_member_binder(R (T::*func)(), T& param) + : func(func), param(param) { } + void operator()() const { (param.*func)(); } + +private: + void operator=(thread_member_binder&); + + R (T::*func)(); + T& param; +}; + + +template +thread_member_binder bind(R (T::*func)(), T& param) +{ + return thread_member_binder(func, param); +} +} // namespace + +#endif diff --git a/deal.II/contrib/boost/libs/thread/tutorial/bounded_buffer.cpp b/deal.II/contrib/boost/libs/thread/tutorial/bounded_buffer.cpp new file mode 100644 index 0000000000..276aaebf11 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/tutorial/bounded_buffer.cpp @@ -0,0 +1,69 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include + +class bounded_buffer : private boost::noncopyable +{ +public: + typedef boost::mutex::scoped_lock lock; + bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { } + void send (int m) { + lock lk(monitor); + while (buffered == circular_buf.size()) + buffer_not_full.wait(lk); + circular_buf[end] = m; + end = (end+1) % circular_buf.size(); + ++buffered; + buffer_not_empty.notify_one(); + } + int receive() { + lock lk(monitor); + while (buffered == 0) + buffer_not_empty.wait(lk); + int i = circular_buf[begin]; + begin = (begin+1) % circular_buf.size(); + --buffered; + buffer_not_full.notify_one(); + return i; + } +private: + int begin, end, buffered; + std::vector circular_buf; + boost::condition buffer_not_full, buffer_not_empty; + boost::mutex monitor; +}; +bounded_buffer buf(2); + +void sender() { + int n = 0; + while (n < 100) { + buf.send(n); + std::cout << "sent: " << n << std::endl; + ++n; + } + buf.send(-1); +} + +void receiver() { + int n; + do { + n = buf.receive(); + std::cout << "received: " << n << std::endl; + } while (n != -1); // -1 indicates end of buffer +} + +int main() +{ + boost::thread thrd1(&sender); + boost::thread thrd2(&receiver); + thrd1.join(); + thrd2.join(); +} diff --git a/deal.II/contrib/boost/libs/thread/tutorial/counter.cpp b/deal.II/contrib/boost/libs/thread/tutorial/counter.cpp new file mode 100644 index 0000000000..a5ca0b4d63 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/tutorial/counter.cpp @@ -0,0 +1,28 @@ +// 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 + +boost::mutex mutex; +int counter=0; + +void change_count() +{ + boost::mutex::scoped_lock lock(mutex); + int i = ++counter; + std::cout << "count == " << i << std::endl; +} + +int main() +{ + const int num_threads = 4; + boost::thread_group thrds; + for (int i=0; i < num_threads; ++i) + thrds.create_thread(&change_count); + thrds.join_all(); +} diff --git a/deal.II/contrib/boost/libs/thread/tutorial/factorial.cpp b/deal.II/contrib/boost/libs/thread/tutorial/factorial.cpp new file mode 100644 index 0000000000..9dd1001d9d --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/tutorial/factorial.cpp @@ -0,0 +1,32 @@ +// 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 + +class factorial +{ +public: + factorial(int x, int& res) : x(x), res(res) { } + void operator()() { res = calculate(x); } + int result() const { return res; } + +private: + int calculate(int x) { return x <= 1 ? 1 : x * calculate(x-1); } + +private: + int x; + int& res; +}; + +int main() +{ + int result; + factorial f(10, result); + boost::thread thrd(f); + thrd.join(); + std::cout << "10! = " << result << std::endl; +} diff --git a/deal.II/contrib/boost/libs/thread/tutorial/factorial2.cpp b/deal.II/contrib/boost/libs/thread/tutorial/factorial2.cpp new file mode 100644 index 0000000000..c30421bc53 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/tutorial/factorial2.cpp @@ -0,0 +1,32 @@ +// 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 + +class factorial +{ +public: + factorial(int x) : x(x), res(0) { } + void operator()() { res = calculate(x); } + int result() const { return res; } + +private: + int calculate(int x) { return x <= 1 ? 1 : x * calculate(x-1); } + +private: + int x; + int res; +}; + +int main() +{ + factorial f(10); + boost::thread thrd(boost::ref(f)); + thrd.join(); + std::cout << "10! = " << f.result() << std::endl; +} diff --git a/deal.II/contrib/boost/libs/thread/tutorial/factorial3.cpp b/deal.II/contrib/boost/libs/thread/tutorial/factorial3.cpp new file mode 100644 index 0000000000..2515bfeabf --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/tutorial/factorial3.cpp @@ -0,0 +1,36 @@ +// 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 + +const int NUM_CALCS=5; + +class factorial +{ +public: + factorial(int x, int& res) : x(x), res(res) { } + void operator()() { res = calculate(x); } + int result() const { return res; } + +private: + int calculate(int x) { return x <= 1 ? 1 : x * calculate(x-1); } + +private: + int x; + int& res; +}; + +int main() +{ + int results[NUM_CALCS]; + boost::thread_group thrds; + for (int i=0; i < NUM_CALCS; ++i) + thrds.create_thread(factorial(i*10, results[i])); + thrds.join_all(); + for (int j=0; j < NUM_CALCS; ++j) + std::cout << j*10 << "! = " << results[j] << std::endl; +} diff --git a/deal.II/contrib/boost/libs/thread/tutorial/helloworld.cpp b/deal.II/contrib/boost/libs/thread/tutorial/helloworld.cpp new file mode 100644 index 0000000000..5003108f49 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/tutorial/helloworld.cpp @@ -0,0 +1,19 @@ +// 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 + +void helloworld() +{ + std::cout << "Hello World!" << std::endl; +} + +int main() +{ + boost::thread thrd(&helloworld); + thrd.join(); +} diff --git a/deal.II/contrib/boost/libs/thread/tutorial/helloworld2.cpp b/deal.II/contrib/boost/libs/thread/tutorial/helloworld2.cpp new file mode 100644 index 0000000000..dc7a698a81 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/tutorial/helloworld2.cpp @@ -0,0 +1,24 @@ +// 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 + +struct helloworld +{ + helloworld(const char* who) : m_who(who) { } + void operator()() + { + std::cout << m_who << "says, \"Hello World.\"" << std::endl; + } + const char* m_who; +}; + +int main() +{ + boost::thread thrd(helloworld("Bob")); + thrd.join(); +} diff --git a/deal.II/contrib/boost/libs/thread/tutorial/helloworld3.cpp b/deal.II/contrib/boost/libs/thread/tutorial/helloworld3.cpp new file mode 100644 index 0000000000..cd43987f58 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/tutorial/helloworld3.cpp @@ -0,0 +1,20 @@ +// 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 + +void helloworld(const char* who) +{ + std::cout << who << "says, \"Hello World.\"" << std::endl; +} + +int main() +{ + boost::thread thrd(boost::bind(&helloworld, "Bob")); + thrd.join(); +} diff --git a/deal.II/contrib/boost/libs/thread/tutorial/helloworld4.cpp b/deal.II/contrib/boost/libs/thread/tutorial/helloworld4.cpp new file mode 100644 index 0000000000..cd43987f58 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/tutorial/helloworld4.cpp @@ -0,0 +1,20 @@ +// 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 + +void helloworld(const char* who) +{ + std::cout << who << "says, \"Hello World.\"" << std::endl; +} + +int main() +{ + boost::thread thrd(boost::bind(&helloworld, "Bob")); + thrd.join(); +} diff --git a/deal.II/contrib/boost/libs/thread/tutorial/once.cpp b/deal.II/contrib/boost/libs/thread/tutorial/once.cpp new file mode 100644 index 0000000000..5a5b6f5589 --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/tutorial/once.cpp @@ -0,0 +1,31 @@ +// 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 + +int value=0; +boost::once_flag once = BOOST_ONCE_INIT; + +void init() +{ + ++value; +} + +void thread_proc() +{ + boost::call_once(&init, once); +} + +int main(int argc, char* argv[]) +{ + boost::thread_group threads; + for (int i=0; i<5; ++i) + threads.create_thread(&thread_proc); + threads.join_all(); + assert(value == 1); +} diff --git a/deal.II/contrib/boost/libs/thread/tutorial/tss.cpp b/deal.II/contrib/boost/libs/thread/tutorial/tss.cpp new file mode 100644 index 0000000000..f867a9180a --- /dev/null +++ b/deal.II/contrib/boost/libs/thread/tutorial/tss.cpp @@ -0,0 +1,36 @@ +// 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 + +boost::thread_specific_ptr value; + +void increment() +{ + int* p = value.get(); + ++*p; +} + +void thread_proc() +{ + value.reset(new int(0)); // initialize the thread's storage + for (int i=0; i<10; ++i) + { + increment(); + int* p = value.get(); + assert(*p == i+1); + } +} + +int main(int argc, char* argv[]) +{ + boost::thread_group threads; + for (int i=0; i<5; ++i) + threads.create_thread(&thread_proc); + threads.join_all(); +}