• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
30 boost::mutex check_mutex;
31 boost::mutex tss_mutex;
32 int tss_instances = 0;
33 int tss_total = 0;
34 
35 struct tss_value_t
36 {
tss_value_ttss_value_t37     tss_value_t()
38     {
39         boost::unique_lock<boost::mutex> lock(tss_mutex);
40         ++tss_instances;
41         ++tss_total;
42         value = 0;
43     }
~tss_value_ttss_value_t44     ~tss_value_t()
45     {
46         boost::unique_lock<boost::mutex> lock(tss_mutex);
47         --tss_instances;
48     }
49     int value;
50 };
51 
52 boost::thread_specific_ptr<tss_value_t> tss_value;
53 
test_tss_thread()54 void test_tss_thread()
55 {
56     tss_value.reset(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 
BOOST_AUTO_TEST_CASE(test_tss_thread_native)77     BOOST_AUTO_TEST_CASE(test_tss_thread_native)
78     {
79         test_tss_thread();
80     }
81 
create_native_thread()82     native_thread_t create_native_thread()
83     {
84         return std::make_shared<std::thread>(test_tss_thread_native);
85     }
86 
join_native_thread(native_thread_t thread)87     void join_native_thread(native_thread_t thread)
88     {
89         thread->join();
90     }
91 
92 #else
93     typedef HANDLE native_thread_t;
94 
test_tss_thread_native(LPVOID)95     DWORD WINAPI test_tss_thread_native(LPVOID /*lpParameter*/)
96     {
97         test_tss_thread();
98         return 0;
99     }
100 
create_native_thread(void)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 
join_native_thread(native_thread_t thread)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 
127 extern "C"
128 {
test_tss_thread_native(void *)129     void* test_tss_thread_native(void* )
130     {
131         test_tss_thread();
132         return 0;
133     }
134 }
135 
create_native_thread()136     native_thread_t create_native_thread()
137     {
138         native_thread_t thread_handle;
139 
140         int const res = pthread_create(&thread_handle, 0, &test_tss_thread_native, 0);
141         BOOST_CHECK(!res);
142         return thread_handle;
143     }
144 
join_native_thread(native_thread_t thread)145     void join_native_thread(native_thread_t thread)
146     {
147         void* result=0;
148         int const res=pthread_join(thread,&result);
149         BOOST_CHECK(!res);
150     }
151 #endif
152 
do_test_tss()153 void 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(&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(thread5);
193     join_native_thread(thread4);
194     join_native_thread(thread3);
195     join_native_thread(thread2);
196     join_native_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 
BOOST_AUTO_TEST_CASE(test_tss)215 BOOST_AUTO_TEST_CASE(test_tss)
216 {
217     timed_test(&do_test_tss, 2);
218 }
219 
220 
221 bool tss_void_cleanup_called=false;
222 
tss_void_custom_cleanup(void * d)223 void 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 
230 boost::thread_specific_ptr<void> tss_void(tss_void_custom_cleanup);
231 
test_tss_void_thread()232 void test_tss_void_thread()
233 {
234     tss_void.reset(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 }
do_test_tss_void()249 void 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(&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 
314 boost::thread_specific_ptr<void> tss_void_with_cleanup(tss_void_custom_cleanup);
315 
tss_void_thread_with_custom_cleanup()316 void tss_void_thread_with_custom_cleanup()
317 {
318     tss_void_with_cleanup.reset(new tss_value_t);
319 }
320 
do_test_tss_void_with_custom_cleanup()321 void 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 
BOOST_AUTO_TEST_CASE(test_tss_void_with_custom_cleanup)339 BOOST_AUTO_TEST_CASE(test_tss_void_with_custom_cleanup)
340 {
341     timed_test(&do_test_tss_void_with_custom_cleanup, 2);
342 }
343 
344 
345 bool tss_cleanup_called=false;
346 
347 struct Dummy
348 {};
349 
tss_custom_cleanup(Dummy * d)350 void tss_custom_cleanup(Dummy* d)
351 {
352     delete d;
353     tss_cleanup_called=true;
354 }
355 
356 boost::thread_specific_ptr<Dummy> tss_with_cleanup(tss_custom_cleanup);
357 
tss_thread_with_custom_cleanup()358 void tss_thread_with_custom_cleanup()
359 {
360     tss_with_cleanup.reset(new Dummy);
361 }
362 
do_test_tss_with_custom_cleanup()363 void 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 
BOOST_AUTO_TEST_CASE(test_tss_with_custom_cleanup)381 BOOST_AUTO_TEST_CASE(test_tss_with_custom_cleanup)
382 {
383     timed_test(&do_test_tss_with_custom_cleanup, 2);
384 }
385 
386 Dummy* tss_object=new Dummy;
387 
tss_thread_with_custom_cleanup_and_release()388 void tss_thread_with_custom_cleanup_and_release()
389 {
390     tss_with_cleanup.reset(tss_object);
391     tss_with_cleanup.release();
392 }
393 
do_test_tss_does_no_cleanup_after_release()394 void 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 
416 struct dummy_class_tracks_deletions
417 {
418     static unsigned deletions;
419 
~dummy_class_tracks_deletionsdummy_class_tracks_deletions420     ~dummy_class_tracks_deletions()
421     {
422         ++deletions;
423     }
424 
425 };
426 
427 unsigned dummy_class_tracks_deletions::deletions=0;
428 
429 boost::thread_specific_ptr<dummy_class_tracks_deletions> tss_with_null_cleanup(NULL);
430 
tss_thread_with_null_cleanup(dummy_class_tracks_deletions * delete_tracker)431 void tss_thread_with_null_cleanup(dummy_class_tracks_deletions* delete_tracker)
432 {
433     tss_with_null_cleanup.reset(delete_tracker);
434 }
435 
do_test_tss_does_no_cleanup_with_null_cleanup_function()436 void 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 
BOOST_AUTO_TEST_CASE(test_tss_does_no_cleanup_after_release)458 BOOST_AUTO_TEST_CASE(test_tss_does_no_cleanup_after_release)
459 {
460     timed_test(&do_test_tss_does_no_cleanup_after_release, 2);
461 }
462 
BOOST_AUTO_TEST_CASE(test_tss_does_no_cleanup_with_null_cleanup_function)463 BOOST_AUTO_TEST_CASE(test_tss_does_no_cleanup_with_null_cleanup_function)
464 {
465     timed_test(&do_test_tss_does_no_cleanup_with_null_cleanup_function, 2);
466 }
467 
thread_with_local_tss_ptr()468 void thread_with_local_tss_ptr()
469 {
470     {
471         boost::thread_specific_ptr<Dummy> local_tss(tss_custom_cleanup);
472 
473         local_tss.reset(new Dummy);
474     }
475     BOOST_CHECK(tss_cleanup_called);
476     tss_cleanup_called=false;
477 }
478 
479 
BOOST_AUTO_TEST_CASE(test_tss_does_not_call_cleanup_after_ptr_destroyed)480 BOOST_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 
BOOST_AUTO_TEST_CASE(test_tss_cleanup_not_called_for_null_pointer)487 BOOST_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 Dummy);
491     tss_cleanup_called=false;
492     local_tss.reset(0);
493     BOOST_CHECK(tss_cleanup_called);
494     tss_cleanup_called=false;
495     local_tss.reset(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