1// Copyright (C) 2001-2003
2// William E. Kempf
3// Copyright (C) 2007 Anthony Williams
4//
5// Distributed under the Boost Software License, Version 1.0. (See accompanying
6// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7
8#define BOOST_THREAD_VERSION 2
9#define BOOST_THREAD_PROVIDES_INTERRUPTIONS
10#define BOOST_TEST_MODULE Boost.Threads: tss test suite
11
12#include <boost/thread/detail/config.hpp>
13#include <boost/predef/platform.h>
14
15#include <boost/thread/tss.hpp>
16#include <boost/thread/mutex.hpp>
17#include <boost/thread/thread.hpp>
18
19#include <boost/test/unit_test.hpp>
20
21#include "./util.inl"
22
23#include <iostream>
24
25#if defined(BOOST_THREAD_PLATFORM_WIN32)
26 #define WIN32_LEAN_AND_MEAN
27 #include <windows.h>
28#endif
29
30boost::mutex check_mutex;
31boost::mutex tss_mutex;
32int tss_instances = 0;
33int tss_total = 0;
34
35struct tss_value_t
36{
37 tss_value_t()
38 {
39 boost::unique_lock<boost::mutex> lock(tss_mutex);
40 ++tss_instances;
41 ++tss_total;
42 value = 0;
43 }
44 ~tss_value_t()
45 {
46 boost::unique_lock<boost::mutex> lock(tss_mutex);
47 --tss_instances;
48 }
49 int value;
50};
51
52boost::thread_specific_ptr<tss_value_t> tss_value;
53
54void test_tss_thread()
55{
56 tss_value.reset(new_value: new tss_value_t());
57 for (int i=0; i<1000; ++i)
58 {
59 int& n = tss_value->value;
60 // Don't call BOOST_CHECK_EQUAL directly, as it doesn't appear to
61 // be thread safe. Must evaluate further.
62 if (n != i)
63 {
64 boost::unique_lock<boost::mutex> lock(check_mutex);
65 BOOST_CHECK_EQUAL(n, i);
66 }
67 ++n;
68 }
69}
70
71
72
73#if defined(BOOST_THREAD_PLATFORM_WIN32)
74#if BOOST_PLAT_WINDOWS_RUNTIME
75 typedef std::shared_ptr<std::thread> native_thread_t;
76
77 BOOST_AUTO_TEST_CASE(test_tss_thread_native)
78 {
79 test_tss_thread();
80 }
81
82 native_thread_t create_native_thread()
83 {
84 return std::make_shared<std::thread>(test_tss_thread_native);
85 }
86
87 void join_native_thread(native_thread_t thread)
88 {
89 thread->join();
90 }
91
92#else
93 typedef HANDLE native_thread_t;
94
95 DWORD WINAPI test_tss_thread_native(LPVOID /*lpParameter*/)
96 {
97 test_tss_thread();
98 return 0;
99 }
100
101 native_thread_t create_native_thread(void)
102 {
103 native_thread_t const res=CreateThread(
104 0, //security attributes (0 = not inheritable)
105 0, //stack size (0 = default)
106 &test_tss_thread_native, //function to execute
107 0, //parameter to pass to function
108 0, //creation flags (0 = run immediately)
109 0 //thread id (0 = thread id not returned)
110 );
111 BOOST_CHECK(res!=0);
112 return res;
113 }
114
115 void join_native_thread(native_thread_t thread)
116 {
117 DWORD res = WaitForSingleObject(thread, INFINITE);
118 BOOST_CHECK(res == WAIT_OBJECT_0);
119
120 res = CloseHandle(thread);
121 BOOST_CHECK(SUCCEEDED(res));
122 }
123#endif
124#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
125 typedef pthread_t native_thread_t;
126
127extern "C"
128{
129 void* test_tss_thread_native(void* )
130 {
131 test_tss_thread();
132 return 0;
133 }
134}
135
136 native_thread_t create_native_thread()
137 {
138 native_thread_t thread_handle;
139
140 int const res = pthread_create(newthread: &thread_handle, attr: 0, start_routine: &test_tss_thread_native, arg: 0);
141 BOOST_CHECK(!res);
142 return thread_handle;
143 }
144
145 void join_native_thread(native_thread_t thread)
146 {
147 void* result=0;
148 int const res=pthread_join(th: thread,thread_return: &result);
149 BOOST_CHECK(!res);
150 }
151#endif
152
153void do_test_tss()
154{
155 tss_instances = 0;
156 tss_total = 0;
157
158 const int NUMTHREADS=5;
159 boost::thread_group threads;
160 try
161 {
162 for (int i=0; i<NUMTHREADS; ++i)
163 threads.create_thread(threadfunc: &test_tss_thread);
164 threads.join_all();
165 }
166 catch(...)
167 {
168 threads.interrupt_all();
169 threads.join_all();
170 throw;
171 }
172
173
174 std::cout
175 << "tss_instances = " << tss_instances
176 << "; tss_total = " << tss_total
177 << "\n";
178 std::cout.flush();
179
180 BOOST_CHECK_EQUAL(tss_instances, 0);
181 BOOST_CHECK_EQUAL(tss_total, 5);
182
183 tss_instances = 0;
184 tss_total = 0;
185
186 native_thread_t thread1 = create_native_thread();
187 native_thread_t thread2 = create_native_thread();
188 native_thread_t thread3 = create_native_thread();
189 native_thread_t thread4 = create_native_thread();
190 native_thread_t thread5 = create_native_thread();
191
192 join_native_thread(thread: thread5);
193 join_native_thread(thread: thread4);
194 join_native_thread(thread: thread3);
195 join_native_thread(thread: thread2);
196 join_native_thread(thread: thread1);
197
198 std::cout
199 << "tss_instances = " << tss_instances
200 << "; tss_total = " << tss_total
201 << "\n";
202 std::cout.flush();
203
204 // The following is not really an error. TSS cleanup support still is available for boost threads.
205 // Also this usually will be triggered only when bound to the static version of thread lib.
206 // 2006-10-02 Roland Schwarz
207 //BOOST_CHECK_EQUAL(tss_instances, 0);
208#if !defined(__MINGW32__)
209 // This fails on MinGW, when using the static lib
210 BOOST_CHECK_MESSAGE(tss_instances == 0, "Support of automatic tss cleanup for native threading API not available");
211#endif
212 BOOST_CHECK_EQUAL(tss_total, 5);
213}
214
215BOOST_AUTO_TEST_CASE(test_tss)
216{
217 timed_test(func: &do_test_tss, secs: 2);
218}
219
220
221bool tss_void_cleanup_called=false;
222
223void tss_void_custom_cleanup(void* d)
224{
225 std::cout << d << std::endl;
226 delete reinterpret_cast<tss_value_t*>(d);
227 tss_void_cleanup_called=true;
228}
229
230boost::thread_specific_ptr<void> tss_void(tss_void_custom_cleanup);
231
232void test_tss_void_thread()
233{
234 tss_void.reset(new_value: new tss_value_t());
235 for (int i=0; i<10; ++i)
236 {
237 int& n = static_cast<tss_value_t*>(tss_value.get())->value;
238 *tss_value;
239 // Don't call BOOST_CHECK_EQUAL directly, as it doesn't appear to
240 // be thread safe. Must evaluate further.
241 if (n != i)
242 {
243 boost::unique_lock<boost::mutex> lock(check_mutex);
244 BOOST_CHECK_EQUAL(n, i);
245 }
246 ++n;
247 }
248}
249void do_test_tss_void()
250{
251 tss_instances = 0;
252 tss_total = 0;
253
254 const int NUMTHREADS=5;
255 boost::thread_group threads;
256 try
257 {
258 for (int i=0; i<NUMTHREADS; ++i)
259 threads.create_thread(threadfunc: &test_tss_void_thread);
260 threads.join_all();
261 }
262 catch(...)
263 {
264 threads.interrupt_all();
265 threads.join_all();
266 throw;
267 }
268
269
270 std::cout
271 << "tss_instances = " << tss_instances
272 << "; tss_total = " << tss_total
273 << "\n";
274 std::cout.flush();
275
276 BOOST_CHECK_EQUAL(tss_instances, 0);
277 BOOST_CHECK_EQUAL(tss_total, 5);
278
279// tss_instances = 0;
280// tss_total = 0;
281//
282// native_thread_t thread1 = create_native_thread();
283// native_thread_t thread2 = create_native_thread();
284// native_thread_t thread3 = create_native_thread();
285// native_thread_t thread4 = create_native_thread();
286// native_thread_t thread5 = create_native_thread();
287//
288// join_native_thread(thread5);
289// join_native_thread(thread4);
290// join_native_thread(thread3);
291// join_native_thread(thread2);
292// join_native_thread(thread1);
293//
294// std::cout
295// << "tss_instances = " << tss_instances
296// << "; tss_total = " << tss_total
297// << "\n";
298// std::cout.flush();
299//
300// // The following is not really an error. TSS cleanup support still is available for boost threads.
301// // Also this usually will be triggered only when bound to the static version of thread lib.
302// // 2006-10-02 Roland Schwarz
303// //BOOST_CHECK_EQUAL(tss_instances, 0);
304// BOOST_CHECK_MESSAGE(tss_instances == 0, "Support of automatic tss cleanup for native threading API not available");
305// BOOST_CHECK_EQUAL(tss_total, 5);
306}
307
308//BOOST_AUTO_TEST_CASE(test_tss_void)
309//{
310// timed_test(&do_test_tss_void, 2);
311//}
312
313
314boost::thread_specific_ptr<void> tss_void_with_cleanup(tss_void_custom_cleanup);
315
316void tss_void_thread_with_custom_cleanup()
317{
318 tss_void_with_cleanup.reset(new_value: new tss_value_t);
319}
320
321void do_test_tss_void_with_custom_cleanup()
322{
323 boost::thread t(tss_void_thread_with_custom_cleanup);
324 try
325 {
326 t.join();
327 }
328 catch(...)
329 {
330 t.interrupt();
331 t.join();
332 throw;
333 }
334
335 BOOST_CHECK(tss_void_cleanup_called);
336}
337
338
339BOOST_AUTO_TEST_CASE(test_tss_void_with_custom_cleanup)
340{
341 timed_test(func: &do_test_tss_void_with_custom_cleanup, secs: 2);
342}
343
344
345bool tss_cleanup_called=false;
346
347struct Dummy
348{};
349
350void tss_custom_cleanup(Dummy* d)
351{
352 delete d;
353 tss_cleanup_called=true;
354}
355
356boost::thread_specific_ptr<Dummy> tss_with_cleanup(tss_custom_cleanup);
357
358void tss_thread_with_custom_cleanup()
359{
360 tss_with_cleanup.reset(new_value: new Dummy);
361}
362
363void do_test_tss_with_custom_cleanup()
364{
365 boost::thread t(tss_thread_with_custom_cleanup);
366 try
367 {
368 t.join();
369 }
370 catch(...)
371 {
372 t.interrupt();
373 t.join();
374 throw;
375 }
376
377 BOOST_CHECK(tss_cleanup_called);
378}
379
380
381BOOST_AUTO_TEST_CASE(test_tss_with_custom_cleanup)
382{
383 timed_test(func: &do_test_tss_with_custom_cleanup, secs: 2);
384}
385
386Dummy* tss_object=new Dummy;
387
388void tss_thread_with_custom_cleanup_and_release()
389{
390 tss_with_cleanup.reset(new_value: tss_object);
391 tss_with_cleanup.release();
392}
393
394void do_test_tss_does_no_cleanup_after_release()
395{
396 tss_cleanup_called=false;
397 boost::thread t(tss_thread_with_custom_cleanup_and_release);
398 try
399 {
400 t.join();
401 }
402 catch(...)
403 {
404 t.interrupt();
405 t.join();
406 throw;
407 }
408
409 BOOST_CHECK(!tss_cleanup_called);
410 if(!tss_cleanup_called)
411 {
412 delete tss_object;
413 }
414}
415
416struct dummy_class_tracks_deletions
417{
418 static unsigned deletions;
419
420 ~dummy_class_tracks_deletions()
421 {
422 ++deletions;
423 }
424
425};
426
427unsigned dummy_class_tracks_deletions::deletions=0;
428
429boost::thread_specific_ptr<dummy_class_tracks_deletions> tss_with_null_cleanup(NULL);
430
431void tss_thread_with_null_cleanup(dummy_class_tracks_deletions* delete_tracker)
432{
433 tss_with_null_cleanup.reset(new_value: delete_tracker);
434}
435
436void do_test_tss_does_no_cleanup_with_null_cleanup_function()
437{
438 dummy_class_tracks_deletions* delete_tracker=new dummy_class_tracks_deletions;
439 boost::thread t(tss_thread_with_null_cleanup,delete_tracker);
440 try
441 {
442 t.join();
443 }
444 catch(...)
445 {
446 t.interrupt();
447 t.join();
448 throw;
449 }
450
451 BOOST_CHECK(!dummy_class_tracks_deletions::deletions);
452 if(!dummy_class_tracks_deletions::deletions)
453 {
454 delete delete_tracker;
455 }
456}
457
458BOOST_AUTO_TEST_CASE(test_tss_does_no_cleanup_after_release)
459{
460 timed_test(func: &do_test_tss_does_no_cleanup_after_release, secs: 2);
461}
462
463BOOST_AUTO_TEST_CASE(test_tss_does_no_cleanup_with_null_cleanup_function)
464{
465 timed_test(func: &do_test_tss_does_no_cleanup_with_null_cleanup_function, secs: 2);
466}
467
468void thread_with_local_tss_ptr()
469{
470 {
471 boost::thread_specific_ptr<Dummy> local_tss(tss_custom_cleanup);
472
473 local_tss.reset(new_value: new Dummy);
474 }
475 BOOST_CHECK(tss_cleanup_called);
476 tss_cleanup_called=false;
477}
478
479
480BOOST_AUTO_TEST_CASE(test_tss_does_not_call_cleanup_after_ptr_destroyed)
481{
482 boost::thread t(thread_with_local_tss_ptr);
483 t.join();
484 BOOST_CHECK(!tss_cleanup_called);
485}
486
487BOOST_AUTO_TEST_CASE(test_tss_cleanup_not_called_for_null_pointer)
488{
489 boost::thread_specific_ptr<Dummy> local_tss(tss_custom_cleanup);
490 local_tss.reset(new_value: new Dummy);
491 tss_cleanup_called=false;
492 local_tss.reset(new_value: 0);
493 BOOST_CHECK(tss_cleanup_called);
494 tss_cleanup_called=false;
495 local_tss.reset(new_value: new Dummy);
496 BOOST_CHECK(!tss_cleanup_called);
497}
498
499//BOOST_AUTO_TEST_CASE(test_tss_at_the_same_adress)
500//{
501// for(int i=0; i<2; i++)
502// {
503// boost::thread_specific_ptr<Dummy> local_tss(tss_custom_cleanup);
504// local_tss.reset(new Dummy);
505// tss_cleanup_called=false;
506// BOOST_CHECK(tss_cleanup_called);
507// tss_cleanup_called=false;
508// BOOST_CHECK(!tss_cleanup_called);
509// }
510//}
511
512

source code of boost/libs/thread/test/test_tss.cpp