]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/thread/test/test_tss.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / thread / test / test_tss.cpp
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 {
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
52 boost::thread_specific_ptr<tss_value_t> tss_value;
53
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
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
127 extern "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(&thread_handle, 0, &test_tss_thread_native, 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(thread,&result);
149 BOOST_CHECK(!res);
150 }
151 #endif
152
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 BOOST_CHECK_MESSAGE(tss_instances == 0, "Support of automatic tss cleanup for native threading API not available");
209 BOOST_CHECK_EQUAL(tss_total, 5);
210 }
211
212 BOOST_AUTO_TEST_CASE(test_tss)
213 {
214 timed_test(&do_test_tss, 2);
215 }
216
217
218 bool tss_void_cleanup_called=false;
219
220 void tss_void_custom_cleanup(void* d)
221 {
222 std::cout << d << std::endl;
223 delete reinterpret_cast<tss_value_t*>(d);
224 tss_void_cleanup_called=true;
225 }
226
227 boost::thread_specific_ptr<void> tss_void(tss_void_custom_cleanup);
228
229 void test_tss_void_thread()
230 {
231 tss_void.reset(new tss_value_t());
232 for (int i=0; i<10; ++i)
233 {
234 int& n = static_cast<tss_value_t*>(tss_value.get())->value;
235 *tss_value;
236 // Don't call BOOST_CHECK_EQUAL directly, as it doesn't appear to
237 // be thread safe. Must evaluate further.
238 if (n != i)
239 {
240 boost::unique_lock<boost::mutex> lock(check_mutex);
241 BOOST_CHECK_EQUAL(n, i);
242 }
243 ++n;
244 }
245 }
246 void do_test_tss_void()
247 {
248 tss_instances = 0;
249 tss_total = 0;
250
251 const int NUMTHREADS=5;
252 boost::thread_group threads;
253 try
254 {
255 for (int i=0; i<NUMTHREADS; ++i)
256 threads.create_thread(&test_tss_void_thread);
257 threads.join_all();
258 }
259 catch(...)
260 {
261 threads.interrupt_all();
262 threads.join_all();
263 throw;
264 }
265
266
267 std::cout
268 << "tss_instances = " << tss_instances
269 << "; tss_total = " << tss_total
270 << "\n";
271 std::cout.flush();
272
273 BOOST_CHECK_EQUAL(tss_instances, 0);
274 BOOST_CHECK_EQUAL(tss_total, 5);
275
276 // tss_instances = 0;
277 // tss_total = 0;
278 //
279 // native_thread_t thread1 = create_native_thread();
280 // native_thread_t thread2 = create_native_thread();
281 // native_thread_t thread3 = create_native_thread();
282 // native_thread_t thread4 = create_native_thread();
283 // native_thread_t thread5 = create_native_thread();
284 //
285 // join_native_thread(thread5);
286 // join_native_thread(thread4);
287 // join_native_thread(thread3);
288 // join_native_thread(thread2);
289 // join_native_thread(thread1);
290 //
291 // std::cout
292 // << "tss_instances = " << tss_instances
293 // << "; tss_total = " << tss_total
294 // << "\n";
295 // std::cout.flush();
296 //
297 // // The following is not really an error. TSS cleanup support still is available for boost threads.
298 // // Also this usually will be triggered only when bound to the static version of thread lib.
299 // // 2006-10-02 Roland Schwarz
300 // //BOOST_CHECK_EQUAL(tss_instances, 0);
301 // BOOST_CHECK_MESSAGE(tss_instances == 0, "Support of automatic tss cleanup for native threading API not available");
302 // BOOST_CHECK_EQUAL(tss_total, 5);
303 }
304
305 //BOOST_AUTO_TEST_CASE(test_tss_void)
306 //{
307 // timed_test(&do_test_tss_void, 2);
308 //}
309
310
311 boost::thread_specific_ptr<void> tss_void_with_cleanup(tss_void_custom_cleanup);
312
313 void tss_void_thread_with_custom_cleanup()
314 {
315 tss_void_with_cleanup.reset(new tss_value_t);
316 }
317
318 void do_test_tss_void_with_custom_cleanup()
319 {
320 boost::thread t(tss_void_thread_with_custom_cleanup);
321 try
322 {
323 t.join();
324 }
325 catch(...)
326 {
327 t.interrupt();
328 t.join();
329 throw;
330 }
331
332 BOOST_CHECK(tss_void_cleanup_called);
333 }
334
335
336 BOOST_AUTO_TEST_CASE(test_tss_void_with_custom_cleanup)
337 {
338 timed_test(&do_test_tss_void_with_custom_cleanup, 2);
339 }
340
341
342 bool tss_cleanup_called=false;
343
344 struct Dummy
345 {};
346
347 void tss_custom_cleanup(Dummy* d)
348 {
349 delete d;
350 tss_cleanup_called=true;
351 }
352
353 boost::thread_specific_ptr<Dummy> tss_with_cleanup(tss_custom_cleanup);
354
355 void tss_thread_with_custom_cleanup()
356 {
357 tss_with_cleanup.reset(new Dummy);
358 }
359
360 void do_test_tss_with_custom_cleanup()
361 {
362 boost::thread t(tss_thread_with_custom_cleanup);
363 try
364 {
365 t.join();
366 }
367 catch(...)
368 {
369 t.interrupt();
370 t.join();
371 throw;
372 }
373
374 BOOST_CHECK(tss_cleanup_called);
375 }
376
377
378 BOOST_AUTO_TEST_CASE(test_tss_with_custom_cleanup)
379 {
380 timed_test(&do_test_tss_with_custom_cleanup, 2);
381 }
382
383 Dummy* tss_object=new Dummy;
384
385 void tss_thread_with_custom_cleanup_and_release()
386 {
387 tss_with_cleanup.reset(tss_object);
388 tss_with_cleanup.release();
389 }
390
391 void do_test_tss_does_no_cleanup_after_release()
392 {
393 tss_cleanup_called=false;
394 boost::thread t(tss_thread_with_custom_cleanup_and_release);
395 try
396 {
397 t.join();
398 }
399 catch(...)
400 {
401 t.interrupt();
402 t.join();
403 throw;
404 }
405
406 BOOST_CHECK(!tss_cleanup_called);
407 if(!tss_cleanup_called)
408 {
409 delete tss_object;
410 }
411 }
412
413 struct dummy_class_tracks_deletions
414 {
415 static unsigned deletions;
416
417 ~dummy_class_tracks_deletions()
418 {
419 ++deletions;
420 }
421
422 };
423
424 unsigned dummy_class_tracks_deletions::deletions=0;
425
426 boost::thread_specific_ptr<dummy_class_tracks_deletions> tss_with_null_cleanup(NULL);
427
428 void tss_thread_with_null_cleanup(dummy_class_tracks_deletions* delete_tracker)
429 {
430 tss_with_null_cleanup.reset(delete_tracker);
431 }
432
433 void do_test_tss_does_no_cleanup_with_null_cleanup_function()
434 {
435 dummy_class_tracks_deletions* delete_tracker=new dummy_class_tracks_deletions;
436 boost::thread t(tss_thread_with_null_cleanup,delete_tracker);
437 try
438 {
439 t.join();
440 }
441 catch(...)
442 {
443 t.interrupt();
444 t.join();
445 throw;
446 }
447
448 BOOST_CHECK(!dummy_class_tracks_deletions::deletions);
449 if(!dummy_class_tracks_deletions::deletions)
450 {
451 delete delete_tracker;
452 }
453 }
454
455 BOOST_AUTO_TEST_CASE(test_tss_does_no_cleanup_after_release)
456 {
457 timed_test(&do_test_tss_does_no_cleanup_after_release, 2);
458 }
459
460 BOOST_AUTO_TEST_CASE(test_tss_does_no_cleanup_with_null_cleanup_function)
461 {
462 timed_test(&do_test_tss_does_no_cleanup_with_null_cleanup_function, 2);
463 }
464
465 void thread_with_local_tss_ptr()
466 {
467 {
468 boost::thread_specific_ptr<Dummy> local_tss(tss_custom_cleanup);
469
470 local_tss.reset(new Dummy);
471 }
472 BOOST_CHECK(tss_cleanup_called);
473 tss_cleanup_called=false;
474 }
475
476
477 BOOST_AUTO_TEST_CASE(test_tss_does_not_call_cleanup_after_ptr_destroyed)
478 {
479 boost::thread t(thread_with_local_tss_ptr);
480 t.join();
481 BOOST_CHECK(!tss_cleanup_called);
482 }
483
484 BOOST_AUTO_TEST_CASE(test_tss_cleanup_not_called_for_null_pointer)
485 {
486 boost::thread_specific_ptr<Dummy> local_tss(tss_custom_cleanup);
487 local_tss.reset(new Dummy);
488 tss_cleanup_called=false;
489 local_tss.reset(0);
490 BOOST_CHECK(tss_cleanup_called);
491 tss_cleanup_called=false;
492 local_tss.reset(new Dummy);
493 BOOST_CHECK(!tss_cleanup_called);
494 }
495
496 //BOOST_AUTO_TEST_CASE(test_tss_at_the_same_adress)
497 //{
498 // for(int i=0; i<2; i++)
499 // {
500 // boost::thread_specific_ptr<Dummy> local_tss(tss_custom_cleanup);
501 // local_tss.reset(new Dummy);
502 // tss_cleanup_called=false;
503 // BOOST_CHECK(tss_cleanup_called);
504 // tss_cleanup_called=false;
505 // BOOST_CHECK(!tss_cleanup_called);
506 // }
507 //}
508