Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

thread/detail/thread.hpp

By: aj3423 on Oct 23rd, 2012  |  syntax: C++  |  size: 18.86 KB  |  views: 31  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. #ifndef BOOST_THREAD_THREAD_COMMON_HPP
  2. #define BOOST_THREAD_THREAD_COMMON_HPP
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. // (C) Copyright 2007-10 Anthony Williams
  7. // (C) Copyright 20011-12 Vicente J. Botet Escriba
  8.  
  9. #include <boost/thread/detail/config.hpp>
  10. #include <boost/thread/exceptions.hpp>
  11. #ifndef BOOST_NO_IOSTREAM
  12. #include <ostream>
  13. #endif
  14. #include <boost/thread/detail/move.hpp>
  15. #include <boost/thread/mutex.hpp>
  16. #include <boost/thread/xtime.hpp>
  17. #include <boost/thread/detail/thread_heap_alloc.hpp>
  18. #include <boost/assert.hpp>
  19. #include <list>
  20. #include <algorithm>
  21. #include <boost/ref.hpp>
  22. #include <boost/cstdint.hpp>
  23. #include <boost/bind.hpp>
  24. #include <stdlib.h>
  25. #include <memory>
  26. #include <boost/utility/enable_if.hpp>
  27. #include <boost/type_traits/remove_reference.hpp>
  28. #include <boost/io/ios_state.hpp>
  29. #include <boost/type_traits/is_same.hpp>
  30. #include <boost/type_traits/decay.hpp>
  31. #include <boost/functional/hash.hpp>
  32. #ifdef BOOST_THREAD_USES_CHRONO
  33. #include <boost/chrono/system_clocks.hpp>
  34. #include <boost/chrono/ceil.hpp>
  35. #endif
  36.  
  37. #include <boost/config/abi_prefix.hpp>
  38.  
  39. #ifdef BOOST_MSVC
  40. #pragma warning(push)
  41. #pragma warning(disable:4251)
  42. #endif
  43.  
  44. namespace boost
  45. {
  46.  
  47.     namespace detail
  48.     {
  49.         template<typename F>
  50.         class thread_data:
  51.             public detail::thread_data_base
  52.         {
  53.         public:
  54.             BOOST_THREAD_NO_COPYABLE(thread_data)
  55. #ifndef BOOST_NO_RVALUE_REFERENCES
  56.               thread_data(BOOST_THREAD_RV_REF(F) f_):
  57.                 f(boost::forward<F>(f_))
  58.               {}
  59. // This overloading must be removed if we want the packaged_task's tests to pass.
  60. //            thread_data(F& f_):
  61. //                f(f_)
  62. //            {}
  63. #else
  64.  
  65.             thread_data(BOOST_THREAD_RV_REF(F) f_):
  66.               f(f_)
  67.             {}
  68.             thread_data(F f_):
  69.                 f(f_)
  70.             {}
  71. #endif
  72.             void run()
  73.             {
  74.                 f();
  75.             }
  76.         private:
  77.             F f;
  78.         };
  79.  
  80.         template<typename F>
  81.         class thread_data<boost::reference_wrapper<F> >:
  82.             public detail::thread_data_base
  83.         {
  84.         private:
  85.             F& f;
  86.         public:
  87.             BOOST_THREAD_NO_COPYABLE(thread_data)
  88.             thread_data(boost::reference_wrapper<F> f_):
  89.                 f(f_)
  90.             {}
  91.             void run()
  92.             {
  93.                 f();
  94.             }
  95.         };
  96.  
  97.         template<typename F>
  98.         class thread_data<const boost::reference_wrapper<F> >:
  99.             public detail::thread_data_base
  100.         {
  101.         private:
  102.             F& f;
  103.         public:
  104.             BOOST_THREAD_NO_COPYABLE(thread_data)
  105.             thread_data(const boost::reference_wrapper<F> f_):
  106.                 f(f_)
  107.             {}
  108.             void run()
  109.             {
  110.                 f();
  111.             }
  112.         };
  113.     }
  114.  
  115.     class BOOST_THREAD_DECL thread
  116.     {
  117.     public:
  118.       typedef thread_attributes attributes;
  119.  
  120.       BOOST_THREAD_MOVABLE_ONLY(thread)
  121.     private:
  122.  
  123.         void release_handle();
  124.  
  125.         detail::thread_data_ptr thread_info;
  126.  
  127.         void start_thread();
  128.         void start_thread(const attributes& attr);
  129.  
  130.         explicit thread(detail::thread_data_ptr data);
  131.  
  132.         detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const;
  133.  
  134. #ifndef BOOST_NO_RVALUE_REFERENCES
  135.         template<typename F>
  136.         static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f)
  137.         {
  138.             return detail::thread_data_ptr(detail::heap_new<detail::thread_data<typename boost::remove_reference<F>::type> >(
  139.                 boost::forward<F>(f)));
  140.         }
  141.         static inline detail::thread_data_ptr make_thread_info(void (*f)())
  142.         {
  143.             return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >(
  144.                 boost::forward<void(*)()>(f)));
  145.         }
  146. #else
  147.         template<typename F>
  148.         static inline detail::thread_data_ptr make_thread_info(F f)
  149.         {
  150.             return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
  151.         }
  152.         template<typename F>
  153.         static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f)
  154.         {
  155.             return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
  156.         }
  157.  
  158. #endif
  159.         struct dummy;
  160.     public:
  161. #if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF.
  162. #if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
  163.         thread(const volatile thread&);
  164. #endif
  165. #endif
  166.         thread() BOOST_NOEXCEPT;
  167.         ~thread()
  168.         {
  169.     #if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
  170.           if (joinable()) {
  171.             std::terminate();
  172.           }
  173.     #else
  174.             detach();
  175.     #endif
  176.         }
  177. #ifndef BOOST_NO_RVALUE_REFERENCES
  178.         template <
  179.           class F
  180.         >
  181.         explicit thread(BOOST_THREAD_RV_REF(F) f
  182.         , typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0
  183.         ):
  184.           thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f))))
  185.         {
  186.             start_thread();
  187.         }
  188.         template <
  189.           class F
  190.         >
  191.         thread(attributes& attrs, BOOST_THREAD_RV_REF(F) f):
  192.           thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f))))
  193.         {
  194.             start_thread(attrs);
  195.         }
  196.  
  197. #else
  198. #ifdef BOOST_NO_SFINAE
  199.         template <class F>
  200.         explicit thread(F f):
  201.             thread_info(make_thread_info(f))
  202.         {
  203.             start_thread();
  204.         }
  205.         template <class F>
  206.         thread(attributes& attrs, F f):
  207.             thread_info(make_thread_info(f))
  208.         {
  209.             start_thread(attrs);
  210.         }
  211. #else
  212.         template <class F>
  213.         explicit thread(F f
  214.             // todo Disable also if Or is_same<typename decay<F>::type, thread>
  215.         , typename disable_if<boost::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0):
  216.             thread_info(make_thread_info(f))
  217.         {
  218.             start_thread();
  219.         }
  220.         template <class F>
  221.         thread(attributes& attrs, F f
  222.         , typename disable_if<boost::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0):
  223.             thread_info(make_thread_info(f))
  224.         {
  225.             start_thread(attrs);
  226.         }
  227. #endif
  228.         template <class F>
  229.         explicit thread(BOOST_THREAD_RV_REF(F) f
  230.         , typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0
  231.         ):
  232.             thread_info(make_thread_info(f))
  233.         {
  234.             start_thread();
  235.         }
  236.  
  237.         template <class F>
  238.         thread(attributes& attrs, BOOST_THREAD_RV_REF(F) f):
  239.             thread_info(make_thread_info(f))
  240.         {
  241.             start_thread(attrs);
  242.         }
  243. #endif
  244.         thread(BOOST_THREAD_RV_REF(thread) x)
  245.         {
  246.             thread_info=BOOST_THREAD_RV(x).thread_info;
  247.             BOOST_THREAD_RV(x).thread_info.reset();
  248.         }
  249. #if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF.
  250. #if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
  251.         thread& operator=(thread x)
  252.         {
  253.             swap(x);
  254.             return *this;
  255.         }
  256. #endif
  257. #endif
  258.  
  259.         thread& operator=(BOOST_THREAD_RV_REF(thread) other) BOOST_NOEXCEPT
  260.         {
  261.  
  262. #if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
  263.             if (joinable()) std::terminate();
  264. #endif
  265.             thread_info=BOOST_THREAD_RV(other).thread_info;
  266.             BOOST_THREAD_RV(other).thread_info.reset();
  267.             return *this;
  268.         }
  269.  
  270.         template <class F,class A1>
  271.         thread(F f,A1 a1,typename disable_if<boost::is_convertible<F&,thread_attributes >, dummy* >::type=0):
  272.             thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1)))
  273.         {
  274.             start_thread();
  275.         }
  276.         template <class F,class A1,class A2>
  277.         thread(F f,A1 a1,A2 a2):
  278.             thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2)))
  279.         {
  280.             start_thread();
  281.         }
  282.  
  283.         template <class F,class A1,class A2,class A3>
  284.         thread(F f,A1 a1,A2 a2,A3 a3):
  285.             thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3)))
  286.         {
  287.             start_thread();
  288.         }
  289.  
  290.         template <class F,class A1,class A2,class A3,class A4>
  291.         thread(F f,A1 a1,A2 a2,A3 a3,A4 a4):
  292.             thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4)))
  293.         {
  294.             start_thread();
  295.         }
  296.  
  297.         template <class F,class A1,class A2,class A3,class A4,class A5>
  298.         thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5):
  299.             thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5)))
  300.         {
  301.             start_thread();
  302.         }
  303.  
  304.         template <class F,class A1,class A2,class A3,class A4,class A5,class A6>
  305.         thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6):
  306.             thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6)))
  307.         {
  308.             start_thread();
  309.         }
  310.  
  311.         template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7>
  312.         thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7):
  313.             thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7)))
  314.         {
  315.             start_thread();
  316.         }
  317.  
  318.         template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8>
  319.         thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8):
  320.             thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8)))
  321.         {
  322.             start_thread();
  323.         }
  324.  
  325.         template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8,class A9>
  326.         thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9):
  327.             thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8,a9)))
  328.         {
  329.             start_thread();
  330.         }
  331.  
  332.         void swap(thread& x) BOOST_NOEXCEPT
  333.         {
  334.             thread_info.swap(x.thread_info);
  335.         }
  336.  
  337.         class BOOST_SYMBOL_VISIBLE id;
  338.         id get_id() const BOOST_NOEXCEPT;
  339.  
  340.  
  341.         bool joinable() const BOOST_NOEXCEPT;
  342.         void join();
  343. #ifdef BOOST_THREAD_USES_CHRONO
  344.         template <class Rep, class Period>
  345.         bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
  346.         {
  347.           return try_join_until(chrono::steady_clock::now() + rel_time);
  348.         }
  349.         template <class Clock, class Duration>
  350.         bool try_join_until(const chrono::time_point<Clock, Duration>& t)
  351.         {
  352.           using namespace chrono;
  353.           system_clock::time_point     s_now = system_clock::now();
  354.           typename Clock::time_point  c_now = Clock::now();
  355.           return try_join_until(s_now + ceil<nanoseconds>(t - c_now));
  356.         }
  357.         template <class Duration>
  358.         bool try_join_until(const chrono::time_point<chrono::system_clock, Duration>& t)
  359.         {
  360.           using namespace chrono;
  361.           typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
  362.           return try_join_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
  363.         }
  364. #endif
  365. #if defined(BOOST_THREAD_PLATFORM_WIN32)
  366.         bool timed_join(const system_time& abs_time);
  367.  
  368. #ifdef BOOST_THREAD_USES_CHRONO
  369.         bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp);
  370. #endif
  371.     public:
  372.  
  373. #else
  374.         bool timed_join(const system_time& abs_time)
  375.         {
  376.           struct timespec const ts=detail::get_timespec(abs_time);
  377.           return do_try_join_until(ts);
  378.         }
  379. #ifdef BOOST_THREAD_USES_CHRONO
  380.         bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
  381.         {
  382.           using namespace chrono;
  383.           nanoseconds d = tp.time_since_epoch();
  384.           timespec ts;
  385.           seconds s = duration_cast<seconds>(d);
  386.           ts.tv_sec = static_cast<long>(s.count());
  387.           ts.tv_nsec = static_cast<long>((d - s).count());
  388.           return do_try_join_until(ts);
  389.         }
  390. #endif
  391.       private:
  392.         bool do_try_join_until(struct timespec const &timeout);
  393.       public:
  394.  
  395. #endif
  396.  
  397.         template<typename TimeDuration>
  398.         inline bool timed_join(TimeDuration const& rel_time)
  399.         {
  400.             return timed_join(get_system_time()+rel_time);
  401.         }
  402.  
  403.         void detach() BOOST_NOEXCEPT;
  404.  
  405.         static unsigned hardware_concurrency() BOOST_NOEXCEPT;
  406.  
  407. #define BOOST_THREAD_DEFINES_THREAD_NATIVE_HANDLE
  408.         typedef detail::thread_data_base::native_handle_type native_handle_type;
  409.         native_handle_type native_handle();
  410.  
  411. #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
  412.         // Use thread::id when comparisions are needed
  413.         // backwards compatibility
  414.         bool operator==(const thread& other) const;
  415.         bool operator!=(const thread& other) const;
  416. #endif
  417.         static inline void yield() BOOST_NOEXCEPT
  418.         {
  419.             this_thread::yield();
  420.         }
  421.  
  422.         static inline void sleep(const system_time& xt)
  423.         {
  424.             this_thread::sleep(xt);
  425.         }
  426.  
  427.         // extensions
  428.         void interrupt();
  429.         bool interruption_requested() const BOOST_NOEXCEPT;
  430.     };
  431.  
  432.     inline void swap(thread& lhs,thread& rhs) BOOST_NOEXCEPT
  433.     {
  434.         return lhs.swap(rhs);
  435.     }
  436.  
  437. #ifndef BOOST_NO_RVALUE_REFERENCES
  438.     inline thread&& move(thread& t) BOOST_NOEXCEPT
  439.     {
  440.         return static_cast<thread&&>(t);
  441.     }
  442. #endif
  443.  
  444.     BOOST_THREAD_DCL_MOVABLE(thread)
  445.  
  446.     namespace this_thread
  447.     {
  448.         thread::id BOOST_THREAD_DECL get_id() BOOST_NOEXCEPT;
  449.  
  450.         void BOOST_THREAD_DECL interruption_point();
  451.         bool BOOST_THREAD_DECL interruption_enabled() BOOST_NOEXCEPT;
  452.         bool BOOST_THREAD_DECL interruption_requested() BOOST_NOEXCEPT;
  453.  
  454.         inline BOOST_SYMBOL_VISIBLE void sleep(xtime const& abs_time)
  455.         {
  456.             sleep(system_time(abs_time));
  457.         }
  458.     }
  459.  
  460.     class BOOST_SYMBOL_VISIBLE thread::id
  461.     {
  462.     private:
  463.         friend inline
  464.         std::size_t
  465.         hash_value(const thread::id &v)
  466.         {
  467. #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
  468.           return hash_value(v.thread_data);
  469. #else
  470.           return hash_value(v.thread_data.get());
  471. #endif
  472.         }
  473.  
  474. #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
  475. #if defined(BOOST_THREAD_PLATFORM_WIN32)
  476.         typedef unsigned int data;
  477. #else
  478.         typedef thread::native_handle_type data;
  479. #endif
  480. #else
  481.         typedef detail::thread_data_ptr data;
  482. #endif
  483.         data thread_data;
  484.  
  485.         id(data thread_data_):
  486.             thread_data(thread_data_)
  487.         {}
  488.         friend class thread;
  489.         friend id BOOST_THREAD_DECL this_thread::get_id() BOOST_NOEXCEPT;
  490.     public:
  491.         id() BOOST_NOEXCEPT:
  492. #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
  493. #if defined(BOOST_THREAD_PLATFORM_WIN32)
  494.         thread_data(0)
  495. #else
  496.         thread_data(0)
  497. #endif
  498. #else
  499.         thread_data()
  500. #endif
  501.         {}
  502.  
  503.         id(const id& other) BOOST_NOEXCEPT :
  504.             thread_data(other.thread_data)
  505.         {}
  506.  
  507.         bool operator==(const id& y) const BOOST_NOEXCEPT
  508.         {
  509.             return thread_data==y.thread_data;
  510.         }
  511.  
  512.         bool operator!=(const id& y) const BOOST_NOEXCEPT
  513.         {
  514.             return thread_data!=y.thread_data;
  515.         }
  516.  
  517.         bool operator<(const id& y) const BOOST_NOEXCEPT
  518.         {
  519.             return thread_data<y.thread_data;
  520.         }
  521.  
  522.         bool operator>(const id& y) const BOOST_NOEXCEPT
  523.         {
  524.             return y.thread_data<thread_data;
  525.         }
  526.  
  527.         bool operator<=(const id& y) const BOOST_NOEXCEPT
  528.         {
  529.             return !(y.thread_data<thread_data);
  530.         }
  531.  
  532.         bool operator>=(const id& y) const BOOST_NOEXCEPT
  533.         {
  534.             return !(thread_data<y.thread_data);
  535.         }
  536.  
  537. #ifndef BOOST_NO_IOSTREAM
  538. #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
  539.         template<class charT, class traits>
  540.         friend BOOST_SYMBOL_VISIBLE
  541.   std::basic_ostream<charT, traits>&
  542.         operator<<(std::basic_ostream<charT, traits>& os, const id& x)
  543.         {
  544.             if(x.thread_data)
  545.             {
  546.                 io::ios_flags_saver  ifs( os );
  547.                 return os<< std::hex << x.thread_data;
  548.             }
  549.             else
  550.             {
  551.                 return os<<"{Not-any-thread}";
  552.             }
  553.         }
  554. #else
  555.         template<class charT, class traits>
  556.         BOOST_SYMBOL_VISIBLE
  557.   std::basic_ostream<charT, traits>&
  558.         print(std::basic_ostream<charT, traits>& os) const
  559.         {
  560.             if(thread_data)
  561.             {
  562.               io::ios_flags_saver  ifs( os );
  563.               return os<< std::hex << thread_data;
  564.             }
  565.             else
  566.             {
  567.                 return os<<"{Not-any-thread}";
  568.             }
  569.         }
  570.  
  571. #endif
  572. #endif
  573.     };
  574.  
  575. #if !defined(BOOST_NO_IOSTREAM) && defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
  576.     template<class charT, class traits>
  577.     BOOST_SYMBOL_VISIBLE
  578.     std::basic_ostream<charT, traits>&
  579.     operator<<(std::basic_ostream<charT, traits>& os, const thread::id& x)
  580.     {
  581.         return x.print(os);
  582.     }
  583. #endif
  584.  
  585. #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
  586.     inline bool thread::operator==(const thread& other) const
  587.     {
  588.         return get_id()==other.get_id();
  589.     }
  590.  
  591.     inline bool thread::operator!=(const thread& other) const
  592.     {
  593.         return get_id()!=other.get_id();
  594.     }
  595. #endif
  596.  
  597.     namespace detail
  598.     {
  599.         struct thread_exit_function_base
  600.         {
  601.             virtual ~thread_exit_function_base()
  602.             {}
  603.             virtual void operator()()=0;
  604.         };
  605.  
  606.         template<typename F>
  607.         struct thread_exit_function:
  608.             thread_exit_function_base
  609.         {
  610.             F f;
  611.  
  612.             thread_exit_function(F f_):
  613.                 f(f_)
  614.             {}
  615.  
  616.             void operator()()
  617.             {
  618.                 f();
  619.             }
  620.         };
  621.  
  622.         void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*);
  623.     }
  624.  
  625.     namespace this_thread
  626.     {
  627.         template<typename F>
  628.         void at_thread_exit(F f)
  629.         {
  630.             detail::thread_exit_function_base* const thread_exit_func=detail::heap_new<detail::thread_exit_function<F> >(f);
  631.             detail::add_thread_exit_function(thread_exit_func);
  632.         }
  633.     }
  634. }
  635.  
  636. #ifdef BOOST_MSVC
  637. #pragma warning(pop)
  638. #endif
  639.  
  640. #include <boost/config/abi_suffix.hpp>
  641.  
  642. #endif