]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/thread/src/pthread/thread.cpp
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / boost / libs / thread / src / pthread / thread.cpp
CommitLineData
7c673cae
FG
1// Copyright (C) 2001-2003
2// William E. Kempf
3// Copyright (C) 2007-8 Anthony Williams
4// (C) Copyright 2011-2012 Vicente J. Botet Escriba
5//
6// Distributed under the Boost Software License, Version 1.0. (See accompanying
7// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8
9#include <boost/thread/detail/config.hpp>
10
11#include <boost/thread/thread_only.hpp>
12#if defined BOOST_THREAD_USES_DATETIME
13#include <boost/thread/xtime.hpp>
14#endif
15#include <boost/thread/condition_variable.hpp>
16#include <boost/thread/locks.hpp>
17#include <boost/thread/once.hpp>
18#include <boost/thread/tss.hpp>
19#include <boost/thread/future.hpp>
20
21#ifdef __GLIBC__
22#include <sys/sysinfo.h>
23#elif defined(__APPLE__) || defined(__FreeBSD__)
24#include <sys/types.h>
25#include <sys/sysctl.h>
26#elif defined BOOST_HAS_UNISTD_H
27#include <unistd.h>
28#endif
29
11fdf7f2
TL
30#if defined(__VXWORKS__)
31#include <vxCpuLib.h>
32#endif
33
7c673cae
FG
34#include <boost/algorithm/string/split.hpp>
35#include <boost/algorithm/string/trim.hpp>
36#include <boost/lexical_cast.hpp>
37
38#include <fstream>
39#include <string>
40#include <set>
41#include <vector>
42#include <string.h> // memcmp.
43
44namespace boost
45{
46 namespace detail
47 {
48 thread_data_base::~thread_data_base()
49 {
50 for (notify_list_t::iterator i = notify.begin(), e = notify.end();
51 i != e; ++i)
52 {
53 i->second->unlock();
54 i->first->notify_all();
55 }
56 for (async_states_t::iterator i = async_states_.begin(), e = async_states_.end();
57 i != e; ++i)
58 {
b32b8144 59 (*i)->notify_deferred();
7c673cae
FG
60 }
61 }
62
63 struct thread_exit_callback_node
64 {
65 boost::detail::thread_exit_function_base* func;
66 thread_exit_callback_node* next;
67
68 thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
69 thread_exit_callback_node* next_):
70 func(func_),next(next_)
71 {}
72 };
73
74 namespace
75 {
76#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
77 boost::once_flag current_thread_tls_init_flag;
78#else
79 boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
80#endif
81 pthread_key_t current_thread_tls_key;
82
83 extern "C"
84 {
85 static void tls_destructor(void* data)
86 {
87 //boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
88 boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(data)->shared_from_this();
89
90 if(thread_info)
91 {
92 while(!thread_info->tss_data.empty() || thread_info->thread_exit_callbacks)
93 {
94
95 while(thread_info->thread_exit_callbacks)
96 {
97 detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks;
98 thread_info->thread_exit_callbacks=current_node->next;
99 if(current_node->func)
100 {
101 (*current_node->func)();
102 delete current_node->func;
103 }
104 delete current_node;
105 }
106 while (!thread_info->tss_data.empty())
107 {
108 std::map<void const*,detail::tss_data_node>::iterator current
109 = thread_info->tss_data.begin();
110 if(current->second.func && (current->second.value!=0))
111 {
112 (*current->second.func)(current->second.value);
113 }
114 thread_info->tss_data.erase(current);
115 }
116 }
117 thread_info->self.reset();
118 }
119 }
120 }
121
122#if defined BOOST_THREAD_PATCH
123 struct delete_current_thread_tls_key_on_dlclose_t
124 {
125 delete_current_thread_tls_key_on_dlclose_t()
126 {
127 }
128 ~delete_current_thread_tls_key_on_dlclose_t()
129 {
130 const boost::once_flag uninitialized = BOOST_ONCE_INIT;
131 if (memcmp(&current_thread_tls_init_flag, &uninitialized, sizeof(boost::once_flag)))
132 {
133 void* data = pthread_getspecific(current_thread_tls_key);
134 if (data)
135 tls_destructor(data);
136 pthread_key_delete(current_thread_tls_key);
137 }
138 }
139 };
140 delete_current_thread_tls_key_on_dlclose_t delete_current_thread_tls_key_on_dlclose;
141#endif
142 void create_current_thread_tls_key()
143 {
144 BOOST_VERIFY(!pthread_key_create(&current_thread_tls_key,&tls_destructor));
145 }
146 }
147
148 boost::detail::thread_data_base* get_current_thread_data()
149 {
150 boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
151 return (boost::detail::thread_data_base*)pthread_getspecific(current_thread_tls_key);
152 }
153
154 void set_current_thread_data(detail::thread_data_base* new_data)
155 {
156 boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
157 BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data));
158 }
159 }
160
161 namespace
162 {
163 extern "C"
164 {
165 static void* thread_proxy(void* param)
166 {
167 //boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->self;
168 boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->shared_from_this();
169 thread_info->self.reset();
170 detail::set_current_thread_data(thread_info.get());
171#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
172 BOOST_TRY
173 {
174#endif
175 thread_info->run();
176#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
177
178 }
179 BOOST_CATCH (thread_interrupted const&)
180 {
181 }
182// Removed as it stops the debugger identifying the cause of the exception
183// Unhandled exceptions still cause the application to terminate
184// BOOST_CATCH(...)
185// {
186// throw;
187//
188// std::terminate();
189// }
190 BOOST_CATCH_END
191#endif
192 detail::tls_destructor(thread_info.get());
193 detail::set_current_thread_data(0);
194 boost::lock_guard<boost::mutex> lock(thread_info->data_mutex);
195 thread_info->done=true;
196 thread_info->done_condition.notify_all();
197
198 return 0;
199 }
200 }
201 }
202 namespace detail
203 {
204 struct externally_launched_thread:
205 detail::thread_data_base
206 {
207 externally_launched_thread()
208 {
209#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
210 interrupt_enabled=false;
211#endif
212 }
213 ~externally_launched_thread() {
214 BOOST_ASSERT(notify.empty());
215 notify.clear();
216 BOOST_ASSERT(async_states_.empty());
217 async_states_.clear();
218 }
219 void run()
220 {}
221 void notify_all_at_thread_exit(condition_variable*, mutex*)
222 {}
223
224 private:
225 externally_launched_thread(externally_launched_thread&);
226 void operator=(externally_launched_thread&);
227 };
228
229 thread_data_base* make_external_thread_data()
230 {
231 thread_data_base* const me(detail::heap_new<externally_launched_thread>());
232 me->self.reset(me);
233 set_current_thread_data(me);
234 return me;
235 }
236
237
238 thread_data_base* get_or_make_current_thread_data()
239 {
240 thread_data_base* current_thread_data(get_current_thread_data());
241 if(!current_thread_data)
242 {
243 current_thread_data=make_external_thread_data();
244 }
245 return current_thread_data;
246 }
247
248 }
249
250
251 thread::thread() BOOST_NOEXCEPT
252 {}
253
254 bool thread::start_thread_noexcept()
255 {
256 thread_info->self=thread_info;
257 int const res = pthread_create(&thread_info->thread_handle, 0, &thread_proxy, thread_info.get());
258 if (res != 0)
259 {
260 thread_info->self.reset();
261 return false;
262 }
263 return true;
264 }
265
266 bool thread::start_thread_noexcept(const attributes& attr)
267 {
268 thread_info->self=thread_info;
269 const attributes::native_handle_type* h = attr.native_handle();
270 int res = pthread_create(&thread_info->thread_handle, h, &thread_proxy, thread_info.get());
271 if (res != 0)
272 {
273 thread_info->self.reset();
274 return false;
275 }
276 int detached_state;
277 res = pthread_attr_getdetachstate(h, &detached_state);
278 if (res != 0)
279 {
280 thread_info->self.reset();
281 return false;
282 }
283 if (PTHREAD_CREATE_DETACHED==detached_state)
284 {
285 detail::thread_data_ptr local_thread_info;
286 thread_info.swap(local_thread_info);
287
288 if(local_thread_info)
289 {
290 //lock_guard<mutex> lock(local_thread_info->data_mutex);
291 if(!local_thread_info->join_started)
292 {
293 //BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
294 local_thread_info->join_started=true;
295 local_thread_info->joined=true;
296 }
297 }
298 }
299 return true;
300 }
301
302
303
304 detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
305 {
306 return thread_info;
307 }
308
309 bool thread::join_noexcept()
310 {
311 detail::thread_data_ptr const local_thread_info=(get_thread_info)();
312 if(local_thread_info)
313 {
314 bool do_join=false;
315
316 {
317 unique_lock<mutex> lock(local_thread_info->data_mutex);
318 while(!local_thread_info->done)
319 {
320 local_thread_info->done_condition.wait(lock);
321 }
322 do_join=!local_thread_info->join_started;
323
324 if(do_join)
325 {
326 local_thread_info->join_started=true;
327 }
328 else
329 {
330 while(!local_thread_info->joined)
331 {
332 local_thread_info->done_condition.wait(lock);
333 }
334 }
335 }
336 if(do_join)
337 {
338 void* result=0;
339 BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
340 lock_guard<mutex> lock(local_thread_info->data_mutex);
341 local_thread_info->joined=true;
342 local_thread_info->done_condition.notify_all();
343 }
344
345 if(thread_info==local_thread_info)
346 {
347 thread_info.reset();
348 }
349 return true;
350 }
351 else
352 {
353 return false;
354 }
355 }
356
11fdf7f2 357 bool thread::do_try_join_until_noexcept(detail::internal_platform_timepoint const &timeout, bool& res)
7c673cae
FG
358 {
359 detail::thread_data_ptr const local_thread_info=(get_thread_info)();
360 if(local_thread_info)
361 {
362 bool do_join=false;
363
364 {
365 unique_lock<mutex> lock(local_thread_info->data_mutex);
366 while(!local_thread_info->done)
367 {
11fdf7f2
TL
368 if(!local_thread_info->done_condition.do_wait_until(lock,timeout)) break; // timeout occurred
369 }
370 if(!local_thread_info->done)
371 {
372 res=false;
373 return true;
7c673cae
FG
374 }
375 do_join=!local_thread_info->join_started;
376
377 if(do_join)
378 {
379 local_thread_info->join_started=true;
380 }
381 else
382 {
383 while(!local_thread_info->joined)
384 {
385 local_thread_info->done_condition.wait(lock);
386 }
387 }
388 }
389 if(do_join)
390 {
391 void* result=0;
392 BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
393 lock_guard<mutex> lock(local_thread_info->data_mutex);
394 local_thread_info->joined=true;
395 local_thread_info->done_condition.notify_all();
396 }
397
398 if(thread_info==local_thread_info)
399 {
400 thread_info.reset();
401 }
402 res=true;
403 return true;
404 }
405 else
406 {
407 return false;
408 }
409 }
410
411 bool thread::joinable() const BOOST_NOEXCEPT
412 {
413 return (get_thread_info)()?true:false;
414 }
415
416
417 void thread::detach()
418 {
419 detail::thread_data_ptr local_thread_info;
420 thread_info.swap(local_thread_info);
421
422 if(local_thread_info)
423 {
424 lock_guard<mutex> lock(local_thread_info->data_mutex);
425 if(!local_thread_info->join_started)
426 {
427 BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
428 local_thread_info->join_started=true;
429 local_thread_info->joined=true;
430 }
431 }
432 }
433
434 namespace this_thread
435 {
436 namespace no_interruption_point
437 {
438 namespace hidden
439 {
11fdf7f2 440 void BOOST_THREAD_DECL sleep_for_internal(const detail::platform_duration& ts)
7c673cae 441 {
11fdf7f2 442 if (ts > detail::platform_duration::zero())
7c673cae 443 {
11fdf7f2
TL
444 // Use pthread_delay_np or nanosleep whenever possible here in the no_interruption_point
445 // namespace because they do not provide an interruption point.
7c673cae
FG
446 # if defined(BOOST_HAS_PTHREAD_DELAY_NP)
447 # if defined(__IBMCPP__) || defined(_AIX)
11fdf7f2 448 BOOST_VERIFY(!pthread_delay_np(const_cast<timespec*>(&ts.getTs())));
7c673cae 449 # else
11fdf7f2 450 BOOST_VERIFY(!pthread_delay_np(&ts.getTs()));
7c673cae
FG
451 # endif
452 # elif defined(BOOST_HAS_NANOSLEEP)
11fdf7f2 453 nanosleep(&ts.getTs(), 0);
7c673cae 454 # else
11fdf7f2 455 // This should never be reached due to BOOST_THREAD_SLEEP_FOR_IS_STEADY
7c673cae 456 # endif
7c673cae
FG
457 }
458 }
7c673cae
FG
459 }
460 }
7c673cae 461
7c673cae
FG
462 void yield() BOOST_NOEXCEPT
463 {
464# if defined(BOOST_HAS_SCHED_YIELD)
465 BOOST_VERIFY(!sched_yield());
466# elif defined(BOOST_HAS_PTHREAD_YIELD)
467 BOOST_VERIFY(!pthread_yield());
468//# elif defined BOOST_THREAD_USES_DATETIME
469// xtime xt;
470// xtime_get(&xt, TIME_UTC_);
471// sleep(xt);
472// sleep_for(chrono::milliseconds(0));
473# else
11fdf7f2
TL
474 mutex mx;
475 unique_lock<mutex> lock(mx);
476 condition_variable cond;
477 cond.do_wait_until(lock, detail::internal_platform_clock::now())
7c673cae
FG
478# endif
479 }
480 }
481 unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
482 {
483#if defined(PTW32_VERSION) || defined(__hpux)
484 return pthread_num_processors_np();
485#elif defined(__APPLE__) || defined(__FreeBSD__)
486 int count;
487 size_t size=sizeof(count);
488 return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count;
489#elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN)
490 int const count=sysconf(_SC_NPROCESSORS_ONLN);
491 return (count>0)?count:0;
11fdf7f2
TL
492#elif defined(__VXWORKS__)
493 cpuset_t set = ::vxCpuEnabledGet();
494 #ifdef __DCC__
495 int i;
496 for( i = 0; set; ++i)
497 {
498 set &= set -1;
499 }
500 return(i);
501 #else
502 return (__builtin_popcount(set) );
503 #endif
7c673cae
FG
504#elif defined(__GLIBC__)
505 return get_nprocs();
506#else
507 return 0;
508#endif
509 }
510
511 unsigned thread::physical_concurrency() BOOST_NOEXCEPT
512 {
513#ifdef __linux__
514 try {
515 using namespace std;
516
517 ifstream proc_cpuinfo ("/proc/cpuinfo");
518
519 const string physical_id("physical id"), core_id("core id");
520
521 typedef std::pair<unsigned, unsigned> core_entry; // [physical ID, core id]
522
523 std::set<core_entry> cores;
524
525 core_entry current_core_entry;
526
527 string line;
528 while ( getline(proc_cpuinfo, line) ) {
529 if (line.empty())
530 continue;
531
532 vector<string> key_val(2);
533 boost::split(key_val, line, boost::is_any_of(":"));
534
535 if (key_val.size() != 2)
536 return hardware_concurrency();
537
538 string key = key_val[0];
539 string value = key_val[1];
540 boost::trim(key);
541 boost::trim(value);
542
543 if (key == physical_id) {
544 current_core_entry.first = boost::lexical_cast<unsigned>(value);
545 continue;
546 }
547
548 if (key == core_id) {
549 current_core_entry.second = boost::lexical_cast<unsigned>(value);
550 cores.insert(current_core_entry);
551 continue;
552 }
553 }
554 // Fall back to hardware_concurrency() in case
555 // /proc/cpuinfo is formatted differently than we expect.
556 return cores.size() != 0 ? cores.size() : hardware_concurrency();
557 } catch(...) {
558 return hardware_concurrency();
559 }
560#elif defined(__APPLE__)
561 int count;
562 size_t size=sizeof(count);
563 return sysctlbyname("hw.physicalcpu",&count,&size,NULL,0)?0:count;
564#else
565 return hardware_concurrency();
566#endif
567 }
568
569#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
570 void thread::interrupt()
571 {
572 detail::thread_data_ptr const local_thread_info=(get_thread_info)();
573 if(local_thread_info)
574 {
575 lock_guard<mutex> lk(local_thread_info->data_mutex);
576 local_thread_info->interrupt_requested=true;
577 if(local_thread_info->current_cond)
578 {
579 boost::pthread::pthread_mutex_scoped_lock internal_lock(local_thread_info->cond_mutex);
580 BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info->current_cond));
581 }
582 }
583 }
584
585 bool thread::interruption_requested() const BOOST_NOEXCEPT
586 {
587 detail::thread_data_ptr const local_thread_info=(get_thread_info)();
588 if(local_thread_info)
589 {
590 lock_guard<mutex> lk(local_thread_info->data_mutex);
591 return local_thread_info->interrupt_requested;
592 }
593 else
594 {
595 return false;
596 }
597 }
598#endif
599
600 thread::native_handle_type thread::native_handle()
601 {
602 detail::thread_data_ptr const local_thread_info=(get_thread_info)();
603 if(local_thread_info)
604 {
605 lock_guard<mutex> lk(local_thread_info->data_mutex);
606 return local_thread_info->thread_handle;
607 }
608 else
609 {
610 return pthread_t();
611 }
612 }
613
614
615
616#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
617 namespace this_thread
618 {
619 void interruption_point()
620 {
621#ifndef BOOST_NO_EXCEPTIONS
622 boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
623 if(thread_info && thread_info->interrupt_enabled)
624 {
625 lock_guard<mutex> lg(thread_info->data_mutex);
626 if(thread_info->interrupt_requested)
627 {
628 thread_info->interrupt_requested=false;
629 throw thread_interrupted();
630 }
631 }
632#endif
633 }
634
635 bool interruption_enabled() BOOST_NOEXCEPT
636 {
637 boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
638 return thread_info && thread_info->interrupt_enabled;
639 }
640
641 bool interruption_requested() BOOST_NOEXCEPT
642 {
643 boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
644 if(!thread_info)
645 {
646 return false;
647 }
648 else
649 {
650 lock_guard<mutex> lg(thread_info->data_mutex);
651 return thread_info->interrupt_requested;
652 }
653 }
654
655 disable_interruption::disable_interruption() BOOST_NOEXCEPT:
656 interruption_was_enabled(interruption_enabled())
657 {
658 if(interruption_was_enabled)
659 {
660 detail::get_current_thread_data()->interrupt_enabled=false;
661 }
662 }
663
664 disable_interruption::~disable_interruption() BOOST_NOEXCEPT
665 {
666 if(detail::get_current_thread_data())
667 {
668 detail::get_current_thread_data()->interrupt_enabled=interruption_was_enabled;
669 }
670 }
671
672 restore_interruption::restore_interruption(disable_interruption& d) BOOST_NOEXCEPT
673 {
674 if(d.interruption_was_enabled)
675 {
676 detail::get_current_thread_data()->interrupt_enabled=true;
677 }
678 }
679
680 restore_interruption::~restore_interruption() BOOST_NOEXCEPT
681 {
682 if(detail::get_current_thread_data())
683 {
684 detail::get_current_thread_data()->interrupt_enabled=false;
685 }
686 }
687 }
688#endif
689
690 namespace detail
691 {
692 void add_thread_exit_function(thread_exit_function_base* func)
693 {
694 detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
695 thread_exit_callback_node* const new_node=
696 heap_new<thread_exit_callback_node>(func,current_thread_data->thread_exit_callbacks);
697 current_thread_data->thread_exit_callbacks=new_node;
698 }
699
700 tss_data_node* find_tss_data(void const* key)
701 {
702 detail::thread_data_base* const current_thread_data(get_current_thread_data());
703 if(current_thread_data)
704 {
705 std::map<void const*,tss_data_node>::iterator current_node=
706 current_thread_data->tss_data.find(key);
707 if(current_node!=current_thread_data->tss_data.end())
708 {
709 return &current_node->second;
710 }
711 }
712 return 0;
713 }
714
715 void* get_tss_data(void const* key)
716 {
717 if(tss_data_node* const current_node=find_tss_data(key))
718 {
719 return current_node->value;
720 }
721 return 0;
722 }
723
724 void add_new_tss_node(void const* key,
725 boost::shared_ptr<tss_cleanup_function> func,
726 void* tss_data)
727 {
728 detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
729 current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(func,tss_data)));
730 }
731
732 void erase_tss_node(void const* key)
733 {
734 detail::thread_data_base* const current_thread_data(get_current_thread_data());
735 if(current_thread_data)
736 {
737 current_thread_data->tss_data.erase(key);
738 }
739 }
740
741 void set_tss_data(void const* key,
742 boost::shared_ptr<tss_cleanup_function> func,
743 void* tss_data,bool cleanup_existing)
744 {
745 if(tss_data_node* const current_node=find_tss_data(key))
746 {
747 if(cleanup_existing && current_node->func && (current_node->value!=0))
748 {
749 (*current_node->func)(current_node->value);
750 }
751 if(func || (tss_data!=0))
752 {
753 current_node->func=func;
754 current_node->value=tss_data;
755 }
756 else
757 {
758 erase_tss_node(key);
759 }
760 }
761 else if(func || (tss_data!=0))
762 {
763 add_new_tss_node(key,func,tss_data);
764 }
765 }
766 }
767
768 BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk)
769 {
770 detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
771 if(current_thread_data)
772 {
773 current_thread_data->notify_all_at_thread_exit(&cond, lk.release());
774 }
775 }
776namespace detail {
777
778 void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
779 {
780 detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
781 if(current_thread_data)
782 {
783 current_thread_data->make_ready_at_thread_exit(as);
784 }
785 }
786}
787
788
789
790}