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