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