• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org/libs/interprocess for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10 
11 //Thread launching functions are adapted from boost/detail/lightweight_thread.hpp
12 //
13 //  boost/detail/lightweight_thread.hpp
14 //
15 //  Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
16 //  Copyright (c) 2008 Peter Dimov
17 //
18 //  Distributed under the Boost Software License, Version 1.0.
19 //  See accompanying file LICENSE_1_0.txt or copy at
20 //  http://www.boost.org/LICENSE_1_0.txt
21 
22 #ifndef BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP
23 #define BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP
24 
25 #ifndef BOOST_CONFIG_HPP
26 #  include <boost/config.hpp>
27 #endif
28 #
29 #if defined(BOOST_HAS_PRAGMA_ONCE)
30 #  pragma once
31 #endif
32 
33 #include <boost/interprocess/detail/config_begin.hpp>
34 #include <boost/interprocess/detail/workaround.hpp>
35 #include <boost/interprocess/streams/bufferstream.hpp>
36 #include <boost/interprocess/detail/posix_time_types_wrk.hpp>
37 #include <cstddef>
38 #include <ostream>
39 
40 #if defined(BOOST_INTERPROCESS_WINDOWS)
41 #  include <boost/interprocess/detail/win32_api.hpp>
42 #  include <process.h>
43 #else
44 #  include <pthread.h>
45 #  include <unistd.h>
46 #  include <sched.h>
47 #  include <time.h>
48 #  ifdef BOOST_INTERPROCESS_BSD_DERIVATIVE
49       //Some *BSD systems (OpenBSD & NetBSD) need sys/param.h before sys/sysctl.h, whereas
50       //others (FreeBSD & Darwin) need sys/types.h
51 #     include <sys/types.h>
52 #     include <sys/param.h>
53 #     include <sys/sysctl.h>
54 #  endif
55 #if defined(__VXWORKS__)
56 #include <vxCpuLib.h>
57 #endif
58 //According to the article "C/C++ tip: How to measure elapsed real time for benchmarking"
59 //Check MacOs first as macOS 10.12 SDK defines both CLOCK_MONOTONIC and
60 //CLOCK_MONOTONIC_RAW and no clock_gettime.
61 #  if (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
62 #     include <mach/mach_time.h>  // mach_absolute_time, mach_timebase_info_data_t
63 #     define BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME
64 #  elif defined(CLOCK_MONOTONIC_PRECISE)   //BSD
65 #     define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC_PRECISE
66 #  elif defined(CLOCK_MONOTONIC_RAW)     //Linux
67 #     define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC_RAW
68 #  elif defined(CLOCK_HIGHRES)           //Solaris
69 #     define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_HIGHRES
70 #  elif defined(CLOCK_MONOTONIC)         //POSIX (AIX, BSD, Linux, Solaris)
71 #     define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC
72 #  else
73 #     error "No high resolution steady clock in your system, please provide a patch"
74 #  endif
75 #endif
76 
77 namespace boost {
78 namespace interprocess {
79 namespace ipcdetail{
80 
81 #if defined (BOOST_INTERPROCESS_WINDOWS)
82 
83 typedef unsigned long OS_process_id_t;
84 typedef unsigned long OS_thread_id_t;
85 struct OS_thread_t
86 {
OS_thread_tboost::interprocess::ipcdetail::OS_thread_t87    OS_thread_t()
88       : m_handle()
89    {}
90 
91 
handleboost::interprocess::ipcdetail::OS_thread_t92    void* handle() const
93    {  return m_handle;  }
94 
95    void* m_handle;
96 };
97 
98 typedef OS_thread_id_t OS_systemwide_thread_id_t;
99 
100 //process
get_current_process_id()101 inline OS_process_id_t get_current_process_id()
102 {  return winapi::get_current_process_id();  }
103 
get_invalid_process_id()104 inline OS_process_id_t get_invalid_process_id()
105 {  return OS_process_id_t(0);  }
106 
107 //thread
get_current_thread_id()108 inline OS_thread_id_t get_current_thread_id()
109 {  return winapi::get_current_thread_id();  }
110 
get_invalid_thread_id()111 inline OS_thread_id_t get_invalid_thread_id()
112 {  return OS_thread_id_t(0xffffffff);  }
113 
equal_thread_id(OS_thread_id_t id1,OS_thread_id_t id2)114 inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2)
115 {  return id1 == id2;  }
116 
117 //return the system tick in ns
get_system_tick_ns()118 inline unsigned long get_system_tick_ns()
119 {
120    unsigned long curres, ignore1, ignore2;
121    winapi::query_timer_resolution(&ignore1, &ignore2, &curres);
122    //Windows API returns the value in hundreds of ns
123    return (curres - 1ul)*100ul;
124 }
125 
126 //return the system tick in us
get_system_tick_us()127 inline unsigned long get_system_tick_us()
128 {
129    unsigned long curres, ignore1, ignore2;
130    winapi::query_timer_resolution(&ignore1, &ignore2, &curres);
131    //Windows API returns the value in hundreds of ns
132    return (curres - 1ul)/10ul + 1ul;
133 }
134 
135 typedef unsigned __int64 OS_highres_count_t;
136 
get_system_tick_in_highres_counts()137 inline unsigned long get_system_tick_in_highres_counts()
138 {
139    __int64 freq;
140    unsigned long curres, ignore1, ignore2;
141    winapi::query_timer_resolution(&ignore1, &ignore2, &curres);
142    //Frequency in counts per second
143    if(!winapi::query_performance_frequency(&freq)){
144       //Tick resolution in ms
145       return (curres-1ul)/10000ul + 1ul;
146    }
147    else{
148       //In femtoseconds
149       __int64 count_fs    = (1000000000000000LL - 1LL)/freq + 1LL;
150       __int64 tick_counts = (static_cast<__int64>(curres)*100000000LL - 1LL)/count_fs + 1LL;
151       return static_cast<unsigned long>(tick_counts);
152    }
153 }
154 
get_current_system_highres_count()155 inline OS_highres_count_t get_current_system_highres_count()
156 {
157    __int64 count;
158    if(!winapi::query_performance_counter(&count)){
159       count = winapi::get_tick_count();
160    }
161    return count;
162 }
163 
zero_highres_count(OS_highres_count_t & count)164 inline void zero_highres_count(OS_highres_count_t &count)
165 {  count = 0;  }
166 
is_highres_count_zero(const OS_highres_count_t & count)167 inline bool is_highres_count_zero(const OS_highres_count_t &count)
168 {  return count == 0;  }
169 
170 template <class Ostream>
ostream_highres_count(Ostream & ostream,const OS_highres_count_t & count)171 inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count)
172 {
173    ostream << count;
174    return ostream;
175 }
176 
system_highres_count_subtract(const OS_highres_count_t & l,const OS_highres_count_t & r)177 inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r)
178 {  return l - r;  }
179 
system_highres_count_less(const OS_highres_count_t & l,const OS_highres_count_t & r)180 inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r)
181 {  return l < r;  }
182 
system_highres_count_less_ul(const OS_highres_count_t & l,unsigned long r)183 inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r)
184 {  return l < static_cast<OS_highres_count_t>(r);  }
185 
thread_sleep_tick()186 inline void thread_sleep_tick()
187 {  winapi::sleep_tick();   }
188 
thread_yield()189 inline void thread_yield()
190 {  winapi::sched_yield();  }
191 
thread_sleep(unsigned int ms)192 inline void thread_sleep(unsigned int ms)
193 {  winapi::sleep(ms);  }
194 
195 //systemwide thread
get_current_systemwide_thread_id()196 inline OS_systemwide_thread_id_t get_current_systemwide_thread_id()
197 {
198    return get_current_thread_id();
199 }
200 
systemwide_thread_id_copy(const volatile OS_systemwide_thread_id_t & from,volatile OS_systemwide_thread_id_t & to)201 inline void systemwide_thread_id_copy
202    (const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to)
203 {
204    to = from;
205 }
206 
equal_systemwide_thread_id(const OS_systemwide_thread_id_t & id1,const OS_systemwide_thread_id_t & id2)207 inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2)
208 {
209    return equal_thread_id(id1, id2);
210 }
211 
get_invalid_systemwide_thread_id()212 inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id()
213 {
214    return get_invalid_thread_id();
215 }
216 
get_current_process_creation_time()217 inline long double get_current_process_creation_time()
218 {
219    winapi::interprocess_filetime CreationTime, ExitTime, KernelTime, UserTime;
220 
221    winapi::get_process_times
222       ( winapi::get_current_process(), &CreationTime, &ExitTime, &KernelTime, &UserTime);
223 
224    typedef long double ldouble_t;
225    const ldouble_t resolution = (100.0l/1000000000.0l);
226    return CreationTime.dwHighDateTime*(ldouble_t(1u<<31u)*2.0l*resolution) +
227               CreationTime.dwLowDateTime*resolution;
228 }
229 
get_num_cores()230 inline unsigned int get_num_cores()
231 {
232    winapi::interprocess_system_info sysinfo;
233    winapi::get_system_info( &sysinfo );
234    //in Windows dw is long which is equal in bits to int
235    return static_cast<unsigned>(sysinfo.dwNumberOfProcessors);
236 }
237 
238 #else    //#if defined (BOOST_INTERPROCESS_WINDOWS)
239 
240 typedef pthread_t OS_thread_t;
241 typedef pthread_t OS_thread_id_t;
242 typedef pid_t     OS_process_id_t;
243 
244 struct OS_systemwide_thread_id_t
245 {
246    OS_systemwide_thread_id_t()
247       :  pid(), tid()
248    {}
249 
250    OS_systemwide_thread_id_t(pid_t p, pthread_t t)
251       :  pid(p), tid(t)
252    {}
253 
254    OS_systemwide_thread_id_t(const OS_systemwide_thread_id_t &x)
255       :  pid(x.pid), tid(x.tid)
256    {}
257 
258    OS_systemwide_thread_id_t(const volatile OS_systemwide_thread_id_t &x)
259       :  pid(x.pid), tid(x.tid)
260    {}
261 
262    OS_systemwide_thread_id_t & operator=(const OS_systemwide_thread_id_t &x)
263    {  pid = x.pid;   tid = x.tid;   return *this;   }
264 
265    OS_systemwide_thread_id_t & operator=(const volatile OS_systemwide_thread_id_t &x)
266    {  pid = x.pid;   tid = x.tid;   return *this;  }
267 
268    void operator=(const OS_systemwide_thread_id_t &x) volatile
269    {  pid = x.pid;   tid = x.tid;   }
270 
271    pid_t       pid;
272    pthread_t   tid;
273 };
274 
275 inline void systemwide_thread_id_copy
276    (const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to)
277 {
278    to.pid = from.pid;
279    to.tid = from.tid;
280 }
281 
282 //process
283 inline OS_process_id_t get_current_process_id()
284 {  return ::getpid();  }
285 
286 inline OS_process_id_t get_invalid_process_id()
287 {  return pid_t(0);  }
288 
289 //thread
290 inline OS_thread_id_t get_current_thread_id()
291 {  return ::pthread_self();  }
292 
293 inline OS_thread_id_t get_invalid_thread_id()
294 {
295    static pthread_t invalid_id;
296    return invalid_id;
297 }
298 
299 inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2)
300 {  return 0 != pthread_equal(id1, id2);  }
301 
302 inline void thread_yield()
303 {  ::sched_yield();  }
304 
305 #ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME
306 typedef struct timespec OS_highres_count_t;
307 #else
308 typedef unsigned long long OS_highres_count_t;
309 #endif
310 
311 inline unsigned long get_system_tick_ns()
312 {
313    #ifdef _SC_CLK_TCK
314    long ticks_per_second =::sysconf(_SC_CLK_TCK); // ticks per sec
315    if(ticks_per_second <= 0){   //Try a typical value on error
316       ticks_per_second = 100;
317    }
318    return 999999999ul/static_cast<unsigned long>(ticks_per_second)+1ul;
319    #else
320       #error "Can't obtain system tick value for your system, please provide a patch"
321    #endif
322 }
323 
324 inline unsigned long get_system_tick_in_highres_counts()
325 {
326    #ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME
327    return get_system_tick_ns();
328    #else
329    mach_timebase_info_data_t info;
330    mach_timebase_info(&info);
331             //ns
332    return static_cast<unsigned long>
333    (
334       static_cast<double>(get_system_tick_ns())
335          / (static_cast<double>(info.numer) / info.denom)
336    );
337    #endif
338 }
339 
340 //return system ticks in us
341 inline unsigned long get_system_tick_us()
342 {
343    return (get_system_tick_ns()-1)/1000ul + 1ul;
344 }
345 
346 inline OS_highres_count_t get_current_system_highres_count()
347 {
348    #if defined(BOOST_INTERPROCESS_CLOCK_MONOTONIC)
349       struct timespec count;
350       ::clock_gettime(BOOST_INTERPROCESS_CLOCK_MONOTONIC, &count);
351       return count;
352    #elif defined(BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME)
353       return ::mach_absolute_time();
354    #endif
355 }
356 
357 #ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME
358 
359 inline void zero_highres_count(OS_highres_count_t &count)
360 {  count.tv_sec = 0; count.tv_nsec = 0;  }
361 
362 inline bool is_highres_count_zero(const OS_highres_count_t &count)
363 {  return count.tv_sec == 0 && count.tv_nsec == 0;  }
364 
365 template <class Ostream>
366 inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count)
367 {
368    ostream << count.tv_sec << "s:" << count.tv_nsec << "ns";
369    return ostream;
370 }
371 
372 inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r)
373 {
374    OS_highres_count_t res;
375 
376    if (l.tv_nsec < r.tv_nsec){
377       res.tv_nsec = 1000000000 + l.tv_nsec - r.tv_nsec;
378       res.tv_sec  = l.tv_sec - 1 - r.tv_sec;
379    }
380    else{
381       res.tv_nsec = l.tv_nsec - r.tv_nsec;
382       res.tv_sec  = l.tv_sec - r.tv_sec;
383    }
384 
385    return res;
386 }
387 
388 inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r)
389 {  return l.tv_sec < r.tv_sec || (l.tv_sec == r.tv_sec && l.tv_nsec < r.tv_nsec);  }
390 
391 inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r)
392 {  return !l.tv_sec && (static_cast<unsigned long>(l.tv_nsec) < r);  }
393 
394 #else
395 
396 inline void zero_highres_count(OS_highres_count_t &count)
397 {  count = 0;  }
398 
399 inline bool is_highres_count_zero(const OS_highres_count_t &count)
400 {  return count == 0;  }
401 
402 template <class Ostream>
403 inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count)
404 {
405    ostream << count ;
406    return ostream;
407 }
408 
409 inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r)
410 {  return l - r;  }
411 
412 inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r)
413 {  return l < r;  }
414 
415 inline bool system_highres_count_less_ul(const OS_highres_count_t &l, unsigned long r)
416 {  return l < static_cast<OS_highres_count_t>(r);  }
417 
418 #endif
419 
420 inline void thread_sleep_tick()
421 {
422    struct timespec rqt;
423    //Sleep for the half of the tick time
424    rqt.tv_sec  = 0;
425    rqt.tv_nsec = get_system_tick_ns()/2;
426    ::nanosleep(&rqt, 0);
427 }
428 
429 inline void thread_sleep(unsigned int ms)
430 {
431    struct timespec rqt;
432    rqt.tv_sec = ms/1000u;
433    rqt.tv_nsec = (ms%1000u)*1000000u;
434    ::nanosleep(&rqt, 0);
435 }
436 
437 //systemwide thread
438 inline OS_systemwide_thread_id_t get_current_systemwide_thread_id()
439 {
440    return OS_systemwide_thread_id_t(::getpid(), ::pthread_self());
441 }
442 
443 inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2)
444 {
445    return (0 != pthread_equal(id1.tid, id2.tid)) && (id1.pid == id2.pid);
446 }
447 
448 inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id()
449 {
450    return OS_systemwide_thread_id_t(get_invalid_process_id(), get_invalid_thread_id());
451 }
452 
453 inline long double get_current_process_creation_time()
454 { return 0.0L; }
455 
456 inline unsigned int get_num_cores()
457 {
458    #ifdef _SC_NPROCESSORS_ONLN
459       long cores = ::sysconf(_SC_NPROCESSORS_ONLN);
460       // sysconf returns -1 if the name is invalid, the option does not exist or
461       // does not have a definite limit.
462       // if sysconf returns some other negative number, we have no idea
463       // what is going on. Default to something safe.
464       if(cores <= 0){
465          return 1;
466       }
467       //Check for overflow (unlikely)
468       else if(static_cast<unsigned long>(cores) >=
469               static_cast<unsigned long>(static_cast<unsigned int>(-1))){
470          return static_cast<unsigned int>(-1);
471       }
472       else{
473          return static_cast<unsigned int>(cores);
474       }
475    #elif defined(BOOST_INTERPROCESS_BSD_DERIVATIVE) && defined(HW_NCPU)
476       int request[2] = { CTL_HW, HW_NCPU };
477       int num_cores;
478       std::size_t result_len = sizeof(num_cores);
479       if ( (::sysctl (request, 2, &num_cores, &result_len, 0, 0) < 0) || (num_cores <= 0) ){
480          //Return a safe value
481          return 1;
482       }
483       else{
484          return static_cast<unsigned int>(num_cores);
485       }
486    #elif defined(__VXWORKS__)
487       cpuset_t set =  ::vxCpuEnabledGet();
488     #ifdef __DCC__
489       int i;
490       for( i = 0; set; ++i)
491           {
492                set &= set -1;
493           }
494       return(i);
495     #else
496       return (__builtin_popcount(set) );
497     #endif
498    #endif
499 }
500 
501 inline int thread_create(OS_thread_t * thread, void *(*start_routine)(void*), void* arg)
502 {  return pthread_create(thread, 0, start_routine, arg); }
503 
504 inline void thread_join(OS_thread_t thread)
505 {  (void)pthread_join(thread, 0);  }
506 
507 #endif   //#if defined (BOOST_INTERPROCESS_WINDOWS)
508 
509 typedef char pid_str_t[sizeof(OS_process_id_t)*3+1];
510 
get_pid_str(pid_str_t & pid_str,OS_process_id_t pid)511 inline void get_pid_str(pid_str_t &pid_str, OS_process_id_t pid)
512 {
513    bufferstream bstream(pid_str, sizeof(pid_str));
514    bstream << pid << std::ends;
515 }
516 
get_pid_str(pid_str_t & pid_str)517 inline void get_pid_str(pid_str_t &pid_str)
518 {  get_pid_str(pid_str, get_current_process_id());  }
519 
520 #if defined(BOOST_INTERPROCESS_WINDOWS)
521 
thread_create(OS_thread_t * thread,unsigned (__stdcall * start_routine)(void *),void * arg)522 inline int thread_create( OS_thread_t * thread, unsigned (__stdcall * start_routine) (void*), void* arg )
523 {
524    void* h = (void*)_beginthreadex( 0, 0, start_routine, arg, 0, 0 );
525 
526    if( h != 0 ){
527       thread->m_handle = h;
528       return 0;
529    }
530    else{
531       return 1;
532    }
533 
534    thread->m_handle = (void*)_beginthreadex( 0, 0, start_routine, arg, 0, 0 );
535    return thread->m_handle != 0;
536 }
537 
thread_join(OS_thread_t thread)538 inline void thread_join( OS_thread_t thread)
539 {
540    winapi::wait_for_single_object( thread.handle(), winapi::infinite_time );
541    winapi::close_handle( thread.handle() );
542 }
543 
544 #endif
545 
546 class abstract_thread
547 {
548    public:
~abstract_thread()549    virtual ~abstract_thread() {}
550    virtual void run() = 0;
551 };
552 
553 template<class T>
554 class os_thread_func_ptr_deleter
555 {
556    public:
os_thread_func_ptr_deleter(T * p)557    explicit os_thread_func_ptr_deleter(T* p)
558       : m_p(p)
559    {}
560 
release()561    T *release()
562    {  T *p = m_p; m_p = 0; return p;  }
563 
get() const564    T *get() const
565    {  return m_p;  }
566 
operator ->() const567    T *operator ->() const
568    {  return m_p;  }
569 
~os_thread_func_ptr_deleter()570    ~os_thread_func_ptr_deleter()
571    {  delete m_p; }
572 
573    private:
574    T *m_p;
575 };
576 
577 #if defined(BOOST_INTERPROCESS_WINDOWS)
578 
launch_thread_routine(void * pv)579 inline unsigned __stdcall launch_thread_routine( void * pv )
580 {
581    os_thread_func_ptr_deleter<abstract_thread> pt( static_cast<abstract_thread *>( pv ) );
582    pt->run();
583    return 0;
584 }
585 
586 #else
587 
588 extern "C" void * launch_thread_routine( void * pv );
589 
launch_thread_routine(void * pv)590 inline void * launch_thread_routine( void * pv )
591 {
592    os_thread_func_ptr_deleter<abstract_thread> pt( static_cast<abstract_thread *>( pv ) );
593    pt->run();
594    return 0;
595 }
596 
597 #endif
598 
599 template<class F>
600 class launch_thread_impl
601    : public abstract_thread
602 {
603    public:
launch_thread_impl(F f)604    explicit launch_thread_impl( F f )
605       : f_( f )
606    {}
607 
run()608    void run()
609    {  f_();  }
610 
611    private:
612    F f_;
613 };
614 
615 template<class F>
thread_launch(OS_thread_t & pt,F f)616 inline int thread_launch( OS_thread_t & pt, F f )
617 {
618    os_thread_func_ptr_deleter<abstract_thread> p( new launch_thread_impl<F>( f ) );
619 
620    int r = thread_create(&pt, launch_thread_routine, p.get());
621    if( r == 0 ){
622       p.release();
623    }
624 
625    return r;
626 }
627 
628 }  //namespace ipcdetail{
629 }  //namespace interprocess {
630 }  //namespace boost {
631 
632 #include <boost/interprocess/detail/config_end.hpp>
633 
634 #endif   //BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP
635