test_tss.cpp 12 KB

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