1 | // Copyright (C) 2001-2003 |
---|
2 | // William E. Kempf |
---|
3 | // |
---|
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
---|
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
---|
6 | |
---|
7 | #include <boost/thread/detail/config.hpp> |
---|
8 | |
---|
9 | #include <boost/thread/tss.hpp> |
---|
10 | #include <boost/thread/mutex.hpp> |
---|
11 | #include <boost/thread/thread.hpp> |
---|
12 | |
---|
13 | #include <boost/test/unit_test.hpp> |
---|
14 | |
---|
15 | #include <libs/thread/test/util.inl> |
---|
16 | |
---|
17 | #include <iostream> |
---|
18 | |
---|
19 | #if defined(BOOST_HAS_WINTHREADS) |
---|
20 | #define WIN32_LEAN_AND_MEAN |
---|
21 | #include <windows.h> |
---|
22 | #endif |
---|
23 | |
---|
24 | boost::mutex check_mutex; |
---|
25 | boost::mutex tss_mutex; |
---|
26 | int tss_instances = 0; |
---|
27 | int tss_total = 0; |
---|
28 | |
---|
29 | struct tss_value_t |
---|
30 | { |
---|
31 | tss_value_t() |
---|
32 | { |
---|
33 | boost::mutex::scoped_lock lock(tss_mutex); |
---|
34 | ++tss_instances; |
---|
35 | ++tss_total; |
---|
36 | value = 0; |
---|
37 | } |
---|
38 | ~tss_value_t() |
---|
39 | { |
---|
40 | boost::mutex::scoped_lock lock(tss_mutex); |
---|
41 | --tss_instances; |
---|
42 | } |
---|
43 | int value; |
---|
44 | }; |
---|
45 | |
---|
46 | boost::thread_specific_ptr<tss_value_t> tss_value; |
---|
47 | |
---|
48 | void test_tss_thread() |
---|
49 | { |
---|
50 | tss_value.reset(new tss_value_t()); |
---|
51 | for (int i=0; i<1000; ++i) |
---|
52 | { |
---|
53 | int& n = tss_value->value; |
---|
54 | // Don't call BOOST_CHECK_EQUAL directly, as it doesn't appear to |
---|
55 | // be thread safe. Must evaluate further. |
---|
56 | if (n != i) |
---|
57 | { |
---|
58 | boost::mutex::scoped_lock lock(check_mutex); |
---|
59 | BOOST_CHECK_EQUAL(n, i); |
---|
60 | } |
---|
61 | ++n; |
---|
62 | } |
---|
63 | } |
---|
64 | |
---|
65 | #if defined(BOOST_HAS_WINTHREADS) |
---|
66 | typedef HANDLE native_thread_t; |
---|
67 | |
---|
68 | DWORD WINAPI test_tss_thread_native(LPVOID lpParameter) |
---|
69 | { |
---|
70 | test_tss_thread(); |
---|
71 | return 0; |
---|
72 | } |
---|
73 | |
---|
74 | native_thread_t create_native_thread(void) |
---|
75 | { |
---|
76 | return CreateThread( |
---|
77 | 0, //security attributes (0 = not inheritable) |
---|
78 | 0, //stack size (0 = default) |
---|
79 | &test_tss_thread_native, //function to execute |
---|
80 | 0, //parameter to pass to function |
---|
81 | 0, //creation flags (0 = run immediately) |
---|
82 | 0 //thread id (0 = thread id not returned) |
---|
83 | ); |
---|
84 | } |
---|
85 | |
---|
86 | void join_native_thread(native_thread_t thread) |
---|
87 | { |
---|
88 | DWORD res = WaitForSingleObject(thread, INFINITE); |
---|
89 | BOOST_CHECK(res == WAIT_OBJECT_0); |
---|
90 | |
---|
91 | res = CloseHandle(thread); |
---|
92 | BOOST_CHECK(SUCCEEDED(res)); |
---|
93 | } |
---|
94 | #endif |
---|
95 | |
---|
96 | void do_test_tss() |
---|
97 | { |
---|
98 | tss_instances = 0; |
---|
99 | tss_total = 0; |
---|
100 | |
---|
101 | const int NUMTHREADS=5; |
---|
102 | boost::thread_group threads; |
---|
103 | for (int i=0; i<NUMTHREADS; ++i) |
---|
104 | threads.create_thread(&test_tss_thread); |
---|
105 | threads.join_all(); |
---|
106 | |
---|
107 | std::cout |
---|
108 | << "tss_instances = " << tss_instances |
---|
109 | << "; tss_total = " << tss_total |
---|
110 | << "\n"; |
---|
111 | std::cout.flush(); |
---|
112 | |
---|
113 | BOOST_CHECK_EQUAL(tss_instances, 0); |
---|
114 | BOOST_CHECK_EQUAL(tss_total, 5); |
---|
115 | |
---|
116 | #if defined(BOOST_HAS_WINTHREADS) |
---|
117 | tss_instances = 0; |
---|
118 | tss_total = 0; |
---|
119 | |
---|
120 | native_thread_t thread1 = create_native_thread(); |
---|
121 | BOOST_CHECK(thread1 != 0); |
---|
122 | |
---|
123 | native_thread_t thread2 = create_native_thread(); |
---|
124 | BOOST_CHECK(thread2 != 0); |
---|
125 | |
---|
126 | native_thread_t thread3 = create_native_thread(); |
---|
127 | BOOST_CHECK(thread3 != 0); |
---|
128 | |
---|
129 | native_thread_t thread4 = create_native_thread(); |
---|
130 | BOOST_CHECK(thread3 != 0); |
---|
131 | |
---|
132 | native_thread_t thread5 = create_native_thread(); |
---|
133 | BOOST_CHECK(thread3 != 0); |
---|
134 | |
---|
135 | join_native_thread(thread5); |
---|
136 | join_native_thread(thread4); |
---|
137 | join_native_thread(thread3); |
---|
138 | join_native_thread(thread2); |
---|
139 | join_native_thread(thread1); |
---|
140 | |
---|
141 | std::cout |
---|
142 | << "tss_instances = " << tss_instances |
---|
143 | << "; tss_total = " << tss_total |
---|
144 | << "\n"; |
---|
145 | std::cout.flush(); |
---|
146 | |
---|
147 | // The following is not really an error. TSS cleanup support still is available for boost threads. |
---|
148 | // Also this usually will be triggered only when bound to the static version of thread lib. |
---|
149 | // 2006-10-02 Roland Schwarz |
---|
150 | //BOOST_CHECK_EQUAL(tss_instances, 0); |
---|
151 | BOOST_CHECK_MESSAGE(tss_instances == 0, "Support of automatic tss cleanup for native threading API not available"); |
---|
152 | BOOST_CHECK_EQUAL(tss_total, 5); |
---|
153 | #endif |
---|
154 | } |
---|
155 | |
---|
156 | void test_tss() |
---|
157 | { |
---|
158 | timed_test(&do_test_tss, 2); |
---|
159 | } |
---|
160 | |
---|
161 | boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) |
---|
162 | { |
---|
163 | boost::unit_test_framework::test_suite* test = |
---|
164 | BOOST_TEST_SUITE("Boost.Threads: tss test suite"); |
---|
165 | |
---|
166 | test->add(BOOST_TEST_CASE(test_tss)); |
---|
167 | |
---|
168 | return test; |
---|
169 | } |
---|