1 | /* |
2 | Copyright (c) 2005-2019 Intel Corporation |
3 | |
4 | Licensed under the Apache License, Version 2.0 (the "License"); |
5 | you may not use this file except in compliance with the License. |
6 | You may obtain a copy of the License at |
7 | |
8 | http://www.apache.org/licenses/LICENSE-2.0 |
9 | |
10 | Unless required by applicable law or agreed to in writing, software |
11 | distributed under the License is distributed on an "AS IS" BASIS, |
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | See the License for the specific language governing permissions and |
14 | limitations under the License. |
15 | */ |
16 | |
17 | #include "tbb/atomic.h" |
18 | #if __TBB_CPP11_RVALUE_REF_PRESENT |
19 | #include <utility> // std::move |
20 | #endif |
21 | |
22 | #define HARNESS_NO_PARSE_COMMAND_LINE 1 |
23 | #include "harness_report.h" |
24 | #include "harness_assert.h" |
25 | |
26 | bool CheckSignatures() { |
27 | // Checks that thread ids can be compared, in the way users would do it |
28 | THREAD::id id1, id2; |
29 | bool result = id1 == id2; |
30 | result |= id1 != id2; |
31 | result |= id1 < id2; |
32 | result |= id1 > id2; |
33 | result |= id1 <= id2; |
34 | result |= id1 >= id2; |
35 | tbb::tbb_hash<THREAD::id> hash; |
36 | return result |= hash(id1)==hash(id2); |
37 | } |
38 | |
39 | static const int THRDS = 3; |
40 | static const int THRDS_DETACH = 2; |
41 | static tbb::atomic<int> sum; |
42 | static tbb::atomic<int> BaseCount; |
43 | static THREAD::id real_ids[THRDS+THRDS_DETACH]; |
44 | |
45 | class Base { |
46 | mutable int copy_throws; |
47 | friend void RunTests(); |
48 | friend void CheckExceptionSafety(); |
49 | void operator=( const Base& ); // Deny access |
50 | protected: |
51 | Base() : copy_throws(100) {++BaseCount;} |
52 | Base( const Base& c ) : copy_throws(c.copy_throws) { |
53 | if( --copy_throws<=0 ) |
54 | __TBB_THROW(0); |
55 | ++BaseCount; |
56 | } |
57 | ~Base() {--BaseCount;} |
58 | }; |
59 | |
60 | template<int N> |
61 | class Data: Base { |
62 | Data(); // Deny access |
63 | explicit Data(int v) : value(v) {} |
64 | |
65 | friend void RunTests(); |
66 | friend void CheckExceptionSafety(); |
67 | public: |
68 | int value; |
69 | }; |
70 | |
71 | #include "harness_barrier.h" |
72 | |
73 | class ThreadFunc: Base { |
74 | ThreadFunc() {} |
75 | |
76 | static Harness::SpinBarrier init_barrier; |
77 | |
78 | friend void RunTests(); |
79 | public: |
80 | void operator()(){ |
81 | real_ids[0] = THIS_THREAD::get_id(); |
82 | init_barrier.wait(); |
83 | |
84 | sum.fetch_and_add(1); |
85 | } |
86 | void operator()(int num){ |
87 | real_ids[num] = THIS_THREAD::get_id(); |
88 | init_barrier.wait(); |
89 | |
90 | sum.fetch_and_add(num); |
91 | } |
92 | void operator()(int num, Data<0> dx) { |
93 | real_ids[num] = THIS_THREAD::get_id(); |
94 | |
95 | const double WAIT = .1; |
96 | #if _WIN32 || _WIN64 |
97 | const double LONG_TOLERANCE = 0.120; // maximal scheduling quantum for Windows Server |
98 | #else |
99 | const double LONG_TOLERANCE = 0.200; // reasonable upper bound |
100 | #endif |
101 | tbb::tick_count::interval_t test_interval(WAIT); |
102 | tbb::tick_count t0 = tbb::tick_count::now(); |
103 | THIS_THREAD_SLEEP ( test_interval ); |
104 | tbb::tick_count t1 = tbb::tick_count::now(); |
105 | double delta = ((t1-t0)-test_interval).seconds(); |
106 | if(delta < 0.0) |
107 | REPORT("ERROR: Sleep interval too short (%g < %g)\n" , |
108 | (t1-t0).seconds(), test_interval.seconds() ); |
109 | if(delta > LONG_TOLERANCE) |
110 | REPORT("Warning: Sleep interval too long (%g outside long tolerance(%g))\n" , |
111 | (t1-t0).seconds(), test_interval.seconds() + LONG_TOLERANCE); |
112 | init_barrier.wait(); |
113 | |
114 | sum.fetch_and_add(num); |
115 | sum.fetch_and_add(dx.value); |
116 | } |
117 | void operator()(Data<0> d) { |
118 | THIS_THREAD_SLEEP ( tbb::tick_count::interval_t(d.value*1.) ); |
119 | } |
120 | }; |
121 | |
122 | Harness::SpinBarrier ThreadFunc::init_barrier(THRDS); |
123 | |
124 | void CheckRelations( const THREAD::id ids[], int n, bool duplicates_allowed ) { |
125 | for( int i=0; i<n; ++i ) { |
126 | const THREAD::id x = ids[i]; |
127 | for( int j=0; j<n; ++j ) { |
128 | const THREAD::id y = ids[j]; |
129 | ASSERT( (x==y)==!(x!=y), NULL ); |
130 | ASSERT( (x<y)==!(x>=y), NULL ); |
131 | ASSERT( (x>y)==!(x<=y), NULL ); |
132 | ASSERT( (x<y)+(x==y)+(x>y)==1, NULL ); |
133 | ASSERT( x!=y || i==j || duplicates_allowed, NULL ); |
134 | for( int k=0; k<n; ++k ) { |
135 | const THREAD::id z = ids[j]; |
136 | ASSERT( !(x<y && y<z) || x<z, "< is not transitive" ); |
137 | } |
138 | } |
139 | } |
140 | } |
141 | |
142 | class AnotherThreadFunc: Base { |
143 | public: |
144 | void operator()() {} |
145 | void operator()(const Data<1>&) {} |
146 | void operator()(const Data<1>&, const Data<2>&) {} |
147 | friend void CheckExceptionSafety(); |
148 | }; |
149 | |
150 | #if TBB_USE_EXCEPTIONS |
151 | void CheckExceptionSafety() { |
152 | int original_count = BaseCount; |
153 | // d loops over number of copies before throw occurs |
154 | for( int d=1; d<=3; ++d ) { |
155 | // Try all combinations of throw/nothrow for f, x, and y's copy constructor. |
156 | for( int i=0; i<8; ++i ) { |
157 | { |
158 | const AnotherThreadFunc f = AnotherThreadFunc(); |
159 | if( i&1 ) f.copy_throws = d; |
160 | const Data<1> x(0); |
161 | if( i&2 ) x.copy_throws = d; |
162 | const Data<2> y(0); |
163 | if( i&4 ) y.copy_throws = d; |
164 | bool exception_caught = false; |
165 | for( int j=0; j<3; ++j ) { |
166 | try { |
167 | switch(j) { |
168 | case 0: {THREAD t(f); t.join();} break; |
169 | case 1: {THREAD t(f,x); t.join();} break; |
170 | case 2: {THREAD t(f,x,y); t.join();} break; |
171 | } |
172 | } catch(...) { |
173 | exception_caught = true; |
174 | } |
175 | ASSERT( !exception_caught||(i&((1<<(j+1))-1))!=0, NULL ); |
176 | } |
177 | } |
178 | ASSERT( BaseCount==original_count, "object leak detected" ); |
179 | } |
180 | } |
181 | } |
182 | #endif /* TBB_USE_EXCEPTIONS */ |
183 | |
184 | #include <cstdio> |
185 | |
186 | #if __TBB_CPP11_RVALUE_REF_PRESENT |
187 | THREAD returnThread() { |
188 | return THREAD(); |
189 | } |
190 | #endif |
191 | |
192 | void RunTests() { |
193 | |
194 | ThreadFunc t; |
195 | Data<0> d100(100), d1(1), d0(0); |
196 | const THREAD::id id_zero; |
197 | THREAD::id id0, uniq_ids[THRDS]; |
198 | |
199 | THREAD thrs[THRDS]; |
200 | THREAD thr; |
201 | THREAD thr0(t); |
202 | THREAD thr1(t, 2); |
203 | THREAD thr2(t, 1, d100); |
204 | |
205 | ASSERT( thr0.get_id() != id_zero, NULL ); |
206 | id0 = thr0.get_id(); |
207 | tbb::move(thrs[0], thr0); |
208 | ASSERT( thr0.get_id() == id_zero, NULL ); |
209 | ASSERT( thrs[0].get_id() == id0, NULL ); |
210 | |
211 | THREAD::native_handle_type h1 = thr1.native_handle(); |
212 | THREAD::native_handle_type h2 = thr2.native_handle(); |
213 | THREAD::id id1 = thr1.get_id(); |
214 | THREAD::id id2 = thr2.get_id(); |
215 | tbb::swap(thr1, thr2); |
216 | ASSERT( thr1.native_handle() == h2, NULL ); |
217 | ASSERT( thr2.native_handle() == h1, NULL ); |
218 | ASSERT( thr1.get_id() == id2, NULL ); |
219 | ASSERT( thr2.get_id() == id1, NULL ); |
220 | #if __TBB_CPP11_RVALUE_REF_PRESENT |
221 | { |
222 | THREAD tmp_thr(std::move(thr1)); |
223 | ASSERT( tmp_thr.native_handle() == h2 && tmp_thr.get_id() == id2, NULL ); |
224 | thr1 = std::move(tmp_thr); |
225 | ASSERT( thr1.native_handle() == h2 && thr1.get_id() == id2, NULL ); |
226 | } |
227 | #endif |
228 | |
229 | thr1.swap(thr2); |
230 | ASSERT( thr1.native_handle() == h1, NULL ); |
231 | ASSERT( thr2.native_handle() == h2, NULL ); |
232 | ASSERT( thr1.get_id() == id1, NULL ); |
233 | ASSERT( thr2.get_id() == id2, NULL ); |
234 | thr1.swap(thr2); |
235 | |
236 | tbb::move(thrs[1], thr1); |
237 | ASSERT( thr1.get_id() == id_zero, NULL ); |
238 | |
239 | #if __TBB_CPP11_RVALUE_REF_PRESENT |
240 | thrs[2] = returnThread(); |
241 | ASSERT( thrs[2].get_id() == id_zero, NULL ); |
242 | #endif |
243 | tbb::move(thrs[2], thr2); |
244 | ASSERT( thr2.get_id() == id_zero, NULL ); |
245 | |
246 | for (int i=0; i<THRDS; i++) |
247 | uniq_ids[i] = thrs[i].get_id(); |
248 | |
249 | ASSERT( thrs[2].joinable(), NULL ); |
250 | |
251 | for (int i=0; i<THRDS; i++) |
252 | thrs[i].join(); |
253 | |
254 | #if !__TBB_WIN8UI_SUPPORT |
255 | // TODO: to find out the way to find thread_id without GetThreadId and other |
256 | // desktop functions. |
257 | // Now tbb_thread does have its own thread_id that stores std::thread object |
258 | // Test will fail in case it is run in desktop mode against New Windows*8 UI library |
259 | for (int i=0; i<THRDS; i++) |
260 | ASSERT( real_ids[i] == uniq_ids[i], NULL ); |
261 | #endif |
262 | |
263 | int current_sum = sum; |
264 | ASSERT( current_sum == 104, NULL ); |
265 | ASSERT( ! thrs[2].joinable(), NULL ); |
266 | ASSERT( BaseCount==4, "object leak detected" ); |
267 | |
268 | #if TBB_USE_EXCEPTIONS |
269 | CheckExceptionSafety(); |
270 | #endif |
271 | |
272 | // Note: all tests involving BaseCount should be put before the tests |
273 | // involing detached threads, because there is no way of knowing when |
274 | // a detached thread destroys its arguments. |
275 | |
276 | THREAD thr_detach_0(t, d0); |
277 | real_ids[THRDS] = thr_detach_0.get_id(); |
278 | thr_detach_0.detach(); |
279 | ASSERT( thr_detach_0.get_id() == id_zero, NULL ); |
280 | |
281 | THREAD thr_detach_1(t, d1); |
282 | real_ids[THRDS+1] = thr_detach_1.get_id(); |
283 | thr_detach_1.detach(); |
284 | ASSERT( thr_detach_1.get_id() == id_zero, NULL ); |
285 | |
286 | CheckRelations(real_ids, THRDS+THRDS_DETACH, true); |
287 | |
288 | CheckRelations(uniq_ids, THRDS, false); |
289 | |
290 | for (int i=0; i<2; i++) { |
291 | AnotherThreadFunc empty_func; |
292 | THREAD thr_to(empty_func), thr_from(empty_func); |
293 | THREAD::id from_id = thr_from.get_id(); |
294 | if (i) thr_to.join(); |
295 | #if __TBB_CPP11_RVALUE_REF_PRESENT |
296 | thr_to = std::move(thr_from); |
297 | #else |
298 | thr_to = thr_from; |
299 | #endif |
300 | ASSERT( thr_from.get_id() == THREAD::id(), NULL ); |
301 | ASSERT( thr_to.get_id() == from_id, NULL ); |
302 | } |
303 | |
304 | ASSERT( THREAD::hardware_concurrency() > 0, NULL); |
305 | } |
306 | |