xref: /oneTBB/test/tbb/test_queue_node.cpp (revision 51c0b2f7)
1*51c0b2f7Stbbdev /*
2*51c0b2f7Stbbdev     Copyright (c) 2005-2020 Intel Corporation
3*51c0b2f7Stbbdev 
4*51c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
5*51c0b2f7Stbbdev     you may not use this file except in compliance with the License.
6*51c0b2f7Stbbdev     You may obtain a copy of the License at
7*51c0b2f7Stbbdev 
8*51c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
9*51c0b2f7Stbbdev 
10*51c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
11*51c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
12*51c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*51c0b2f7Stbbdev     See the License for the specific language governing permissions and
14*51c0b2f7Stbbdev     limitations under the License.
15*51c0b2f7Stbbdev */
16*51c0b2f7Stbbdev 
17*51c0b2f7Stbbdev // TODO: Add overlapping put / receive tests
18*51c0b2f7Stbbdev 
19*51c0b2f7Stbbdev #include "common/config.h"
20*51c0b2f7Stbbdev 
21*51c0b2f7Stbbdev // TODO revamp: move parts dependent on __TBB_EXTRA_DEBUG into separate test(s) since having these
22*51c0b2f7Stbbdev // parts in all of tests might make testing of the product, which is different from what is actually
23*51c0b2f7Stbbdev // released.
24*51c0b2f7Stbbdev #define __TBB_EXTRA_DEBUG 1
25*51c0b2f7Stbbdev #include "tbb/flow_graph.h"
26*51c0b2f7Stbbdev 
27*51c0b2f7Stbbdev #include "common/test.h"
28*51c0b2f7Stbbdev #include "common/utils.h"
29*51c0b2f7Stbbdev #include "common/utils_assert.h"
30*51c0b2f7Stbbdev #include "common/checktype.h"
31*51c0b2f7Stbbdev #include "common/graph_utils.h"
32*51c0b2f7Stbbdev #include "common/test_follows_and_precedes_api.h"
33*51c0b2f7Stbbdev 
34*51c0b2f7Stbbdev #include <cstdio>
35*51c0b2f7Stbbdev 
36*51c0b2f7Stbbdev 
37*51c0b2f7Stbbdev //! \file test_queue_node.cpp
38*51c0b2f7Stbbdev //! \brief Test for [flow_graph.queue_node] specification
39*51c0b2f7Stbbdev 
40*51c0b2f7Stbbdev 
41*51c0b2f7Stbbdev #define N 1000
42*51c0b2f7Stbbdev #define C 10
43*51c0b2f7Stbbdev 
44*51c0b2f7Stbbdev template< typename T >
45*51c0b2f7Stbbdev void spin_try_get( tbb::flow::queue_node<T> &q, T &value ) {
46*51c0b2f7Stbbdev     while ( q.try_get(value) != true ) ;
47*51c0b2f7Stbbdev }
48*51c0b2f7Stbbdev 
49*51c0b2f7Stbbdev template< typename T >
50*51c0b2f7Stbbdev void check_item( T* next_value, T &value ) {
51*51c0b2f7Stbbdev     int tid = value / N;
52*51c0b2f7Stbbdev     int offset = value % N;
53*51c0b2f7Stbbdev     CHECK_MESSAGE( next_value[tid] == T(offset), "" );
54*51c0b2f7Stbbdev     ++next_value[tid];
55*51c0b2f7Stbbdev }
56*51c0b2f7Stbbdev 
57*51c0b2f7Stbbdev template< typename T >
58*51c0b2f7Stbbdev struct parallel_puts : utils::NoAssign {
59*51c0b2f7Stbbdev 
60*51c0b2f7Stbbdev     tbb::flow::queue_node<T> &my_q;
61*51c0b2f7Stbbdev 
62*51c0b2f7Stbbdev     parallel_puts( tbb::flow::queue_node<T> &q ) : my_q(q) {}
63*51c0b2f7Stbbdev 
64*51c0b2f7Stbbdev     void operator()(int i) const {
65*51c0b2f7Stbbdev         for (int j = 0; j < N; ++j) {
66*51c0b2f7Stbbdev             bool msg = my_q.try_put( T(N*i + j) );
67*51c0b2f7Stbbdev             CHECK_MESSAGE( msg == true, "" );
68*51c0b2f7Stbbdev         }
69*51c0b2f7Stbbdev     }
70*51c0b2f7Stbbdev 
71*51c0b2f7Stbbdev };
72*51c0b2f7Stbbdev 
73*51c0b2f7Stbbdev 
74*51c0b2f7Stbbdev 
75*51c0b2f7Stbbdev template< typename T >
76*51c0b2f7Stbbdev struct touches {
77*51c0b2f7Stbbdev 
78*51c0b2f7Stbbdev     bool **my_touches;
79*51c0b2f7Stbbdev     T **my_last_touch;
80*51c0b2f7Stbbdev     int my_num_threads;
81*51c0b2f7Stbbdev 
82*51c0b2f7Stbbdev     touches( int num_threads ) : my_num_threads(num_threads) {
83*51c0b2f7Stbbdev         my_last_touch = new T* [my_num_threads];
84*51c0b2f7Stbbdev         my_touches = new bool* [my_num_threads];
85*51c0b2f7Stbbdev         for ( int p = 0; p < my_num_threads; ++p) {
86*51c0b2f7Stbbdev             my_last_touch[p] = new T[my_num_threads];
87*51c0b2f7Stbbdev             for ( int p2 = 0; p2 < my_num_threads; ++p2)
88*51c0b2f7Stbbdev                 my_last_touch[p][p2] = -1;
89*51c0b2f7Stbbdev 
90*51c0b2f7Stbbdev             my_touches[p] = new bool[N*my_num_threads];
91*51c0b2f7Stbbdev             for ( int n = 0; n < N*my_num_threads; ++n)
92*51c0b2f7Stbbdev                 my_touches[p][n] = false;
93*51c0b2f7Stbbdev         }
94*51c0b2f7Stbbdev     }
95*51c0b2f7Stbbdev 
96*51c0b2f7Stbbdev     ~touches() {
97*51c0b2f7Stbbdev         for ( int p = 0; p < my_num_threads; ++p) {
98*51c0b2f7Stbbdev             delete [] my_touches[p];
99*51c0b2f7Stbbdev             delete [] my_last_touch[p];
100*51c0b2f7Stbbdev         }
101*51c0b2f7Stbbdev         delete [] my_touches;
102*51c0b2f7Stbbdev         delete [] my_last_touch;
103*51c0b2f7Stbbdev     }
104*51c0b2f7Stbbdev 
105*51c0b2f7Stbbdev     bool check( int tid, T v ) {
106*51c0b2f7Stbbdev         int v_tid = v / N;
107*51c0b2f7Stbbdev         if ( my_touches[tid][v] != false ) {
108*51c0b2f7Stbbdev             printf("Error: value seen twice by local thread\n");
109*51c0b2f7Stbbdev             return false;
110*51c0b2f7Stbbdev         }
111*51c0b2f7Stbbdev         if ( v <= my_last_touch[tid][v_tid] ) {
112*51c0b2f7Stbbdev             printf("Error: value seen in wrong order by local thread\n");
113*51c0b2f7Stbbdev             return false;
114*51c0b2f7Stbbdev         }
115*51c0b2f7Stbbdev         my_last_touch[tid][v_tid] = v;
116*51c0b2f7Stbbdev         my_touches[tid][v] = true;
117*51c0b2f7Stbbdev         return true;
118*51c0b2f7Stbbdev     }
119*51c0b2f7Stbbdev 
120*51c0b2f7Stbbdev     bool validate_touches() {
121*51c0b2f7Stbbdev         bool *all_touches = new bool[N*my_num_threads];
122*51c0b2f7Stbbdev         for ( int n = 0; n < N*my_num_threads; ++n)
123*51c0b2f7Stbbdev             all_touches[n] = false;
124*51c0b2f7Stbbdev 
125*51c0b2f7Stbbdev         for ( int p = 0; p < my_num_threads; ++p) {
126*51c0b2f7Stbbdev             for ( int n = 0; n < N*my_num_threads; ++n) {
127*51c0b2f7Stbbdev                 if ( my_touches[p][n] == true ) {
128*51c0b2f7Stbbdev                     CHECK_MESSAGE( ( all_touches[n] == false), "value see by more than one thread\n" );
129*51c0b2f7Stbbdev                     all_touches[n] = true;
130*51c0b2f7Stbbdev                 }
131*51c0b2f7Stbbdev             }
132*51c0b2f7Stbbdev         }
133*51c0b2f7Stbbdev         for ( int n = 0; n < N*my_num_threads; ++n) {
134*51c0b2f7Stbbdev             if ( !all_touches[n] )
135*51c0b2f7Stbbdev                 printf("No touch at %d, my_num_threads = %d\n", n, my_num_threads);
136*51c0b2f7Stbbdev             //CHECK_MESSAGE( ( all_touches[n] == true), "value not seen by any thread\n" );
137*51c0b2f7Stbbdev         }
138*51c0b2f7Stbbdev         delete [] all_touches;
139*51c0b2f7Stbbdev         return true;
140*51c0b2f7Stbbdev     }
141*51c0b2f7Stbbdev 
142*51c0b2f7Stbbdev };
143*51c0b2f7Stbbdev 
144*51c0b2f7Stbbdev template< typename T >
145*51c0b2f7Stbbdev struct parallel_gets : utils::NoAssign {
146*51c0b2f7Stbbdev 
147*51c0b2f7Stbbdev     tbb::flow::queue_node<T> &my_q;
148*51c0b2f7Stbbdev     touches<T> &my_touches;
149*51c0b2f7Stbbdev 
150*51c0b2f7Stbbdev     parallel_gets( tbb::flow::queue_node<T> &q, touches<T> &t) : my_q(q), my_touches(t) {}
151*51c0b2f7Stbbdev 
152*51c0b2f7Stbbdev     void operator()(int tid) const {
153*51c0b2f7Stbbdev         for (int j = 0; j < N; ++j) {
154*51c0b2f7Stbbdev             T v;
155*51c0b2f7Stbbdev             spin_try_get( my_q, v );
156*51c0b2f7Stbbdev             my_touches.check( tid, v );
157*51c0b2f7Stbbdev         }
158*51c0b2f7Stbbdev     }
159*51c0b2f7Stbbdev 
160*51c0b2f7Stbbdev };
161*51c0b2f7Stbbdev 
162*51c0b2f7Stbbdev template< typename T >
163*51c0b2f7Stbbdev struct parallel_put_get : utils::NoAssign {
164*51c0b2f7Stbbdev 
165*51c0b2f7Stbbdev     tbb::flow::queue_node<T> &my_q;
166*51c0b2f7Stbbdev     touches<T> &my_touches;
167*51c0b2f7Stbbdev 
168*51c0b2f7Stbbdev     parallel_put_get( tbb::flow::queue_node<T> &q, touches<T> &t ) : my_q(q), my_touches(t) {}
169*51c0b2f7Stbbdev 
170*51c0b2f7Stbbdev     void operator()(int tid) const {
171*51c0b2f7Stbbdev 
172*51c0b2f7Stbbdev         for ( int i = 0; i < N; i+=C ) {
173*51c0b2f7Stbbdev             int j_end = ( N < i + C ) ? N : i + C;
174*51c0b2f7Stbbdev             // dump about C values into the Q
175*51c0b2f7Stbbdev             for ( int j = i; j < j_end; ++j ) {
176*51c0b2f7Stbbdev                 CHECK_MESSAGE( my_q.try_put( T (N*tid + j ) ) == true, "" );
177*51c0b2f7Stbbdev             }
178*51c0b2f7Stbbdev             // receiver about C values from the Q
179*51c0b2f7Stbbdev             for ( int j = i; j < j_end; ++j ) {
180*51c0b2f7Stbbdev                 T v;
181*51c0b2f7Stbbdev                 spin_try_get( my_q, v );
182*51c0b2f7Stbbdev                 my_touches.check( tid, v );
183*51c0b2f7Stbbdev             }
184*51c0b2f7Stbbdev         }
185*51c0b2f7Stbbdev     }
186*51c0b2f7Stbbdev 
187*51c0b2f7Stbbdev };
188*51c0b2f7Stbbdev 
189*51c0b2f7Stbbdev //
190*51c0b2f7Stbbdev // Tests
191*51c0b2f7Stbbdev //
192*51c0b2f7Stbbdev // Item can be reserved, released, consumed ( single serial receiver )
193*51c0b2f7Stbbdev //
194*51c0b2f7Stbbdev template< typename T >
195*51c0b2f7Stbbdev int test_reservation() {
196*51c0b2f7Stbbdev     tbb::flow::graph g;
197*51c0b2f7Stbbdev     T bogus_value(-1);
198*51c0b2f7Stbbdev 
199*51c0b2f7Stbbdev     // Simple tests
200*51c0b2f7Stbbdev     tbb::flow::queue_node<T> q(g);
201*51c0b2f7Stbbdev 
202*51c0b2f7Stbbdev     q.try_put(T(1));
203*51c0b2f7Stbbdev     q.try_put(T(2));
204*51c0b2f7Stbbdev     q.try_put(T(3));
205*51c0b2f7Stbbdev 
206*51c0b2f7Stbbdev     T v;
207*51c0b2f7Stbbdev     CHECK_MESSAGE( q.reserve_item(v) == true, "" );
208*51c0b2f7Stbbdev     CHECK_MESSAGE( v == T(1), "" );
209*51c0b2f7Stbbdev     CHECK_MESSAGE( q.release_reservation() == true, "" );
210*51c0b2f7Stbbdev     v = bogus_value;
211*51c0b2f7Stbbdev     g.wait_for_all();
212*51c0b2f7Stbbdev     CHECK_MESSAGE( q.reserve_item(v) == true, "" );
213*51c0b2f7Stbbdev     CHECK_MESSAGE( v == T(1), "" );
214*51c0b2f7Stbbdev     CHECK_MESSAGE( q.consume_reservation() == true, "" );
215*51c0b2f7Stbbdev     v = bogus_value;
216*51c0b2f7Stbbdev     g.wait_for_all();
217*51c0b2f7Stbbdev 
218*51c0b2f7Stbbdev     CHECK_MESSAGE( q.try_get(v) == true, "" );
219*51c0b2f7Stbbdev     CHECK_MESSAGE( v == T(2), "" );
220*51c0b2f7Stbbdev     v = bogus_value;
221*51c0b2f7Stbbdev     g.wait_for_all();
222*51c0b2f7Stbbdev 
223*51c0b2f7Stbbdev     CHECK_MESSAGE( q.reserve_item(v) == true, "" );
224*51c0b2f7Stbbdev     CHECK_MESSAGE( v == T(3), "" );
225*51c0b2f7Stbbdev     CHECK_MESSAGE( q.release_reservation() == true, "" );
226*51c0b2f7Stbbdev     v = bogus_value;
227*51c0b2f7Stbbdev     g.wait_for_all();
228*51c0b2f7Stbbdev     CHECK_MESSAGE( q.reserve_item(v) == true, "" );
229*51c0b2f7Stbbdev     CHECK_MESSAGE( v == T(3), "" );
230*51c0b2f7Stbbdev     CHECK_MESSAGE( q.consume_reservation() == true, "" );
231*51c0b2f7Stbbdev     v = bogus_value;
232*51c0b2f7Stbbdev     g.wait_for_all();
233*51c0b2f7Stbbdev 
234*51c0b2f7Stbbdev     return 0;
235*51c0b2f7Stbbdev }
236*51c0b2f7Stbbdev 
237*51c0b2f7Stbbdev //
238*51c0b2f7Stbbdev // Tests
239*51c0b2f7Stbbdev //
240*51c0b2f7Stbbdev // multiple parallel senders, items in FIFO (relatively to sender) order
241*51c0b2f7Stbbdev // multiple parallel senders, multiple parallel receivers, items in FIFO order (relative to sender/receiver) and all items received
242*51c0b2f7Stbbdev //   * overlapped puts / gets
243*51c0b2f7Stbbdev //   * all puts finished before any getS
244*51c0b2f7Stbbdev //
245*51c0b2f7Stbbdev template< typename T >
246*51c0b2f7Stbbdev int test_parallel(int num_threads) {
247*51c0b2f7Stbbdev     tbb::flow::graph g;
248*51c0b2f7Stbbdev     tbb::flow::queue_node<T> q(g);
249*51c0b2f7Stbbdev     tbb::flow::queue_node<T> q2(g);
250*51c0b2f7Stbbdev     tbb::flow::queue_node<T> q3(g);
251*51c0b2f7Stbbdev     {
252*51c0b2f7Stbbdev         Checker< T > my_check;
253*51c0b2f7Stbbdev         T bogus_value(-1);
254*51c0b2f7Stbbdev         T j = bogus_value;
255*51c0b2f7Stbbdev         utils::NativeParallelFor( num_threads, parallel_puts<T>(q) );
256*51c0b2f7Stbbdev 
257*51c0b2f7Stbbdev         T *next_value = new T[num_threads];
258*51c0b2f7Stbbdev         for (int tid = 0; tid < num_threads; ++tid) next_value[tid] = T(0);
259*51c0b2f7Stbbdev 
260*51c0b2f7Stbbdev         for (int i = 0; i < num_threads * N; ++i ) {
261*51c0b2f7Stbbdev             spin_try_get( q, j );
262*51c0b2f7Stbbdev             check_item( next_value, j );
263*51c0b2f7Stbbdev             j = bogus_value;
264*51c0b2f7Stbbdev         }
265*51c0b2f7Stbbdev         for (int tid = 0; tid < num_threads; ++tid)  {
266*51c0b2f7Stbbdev             CHECK_MESSAGE( next_value[tid] == T(N), "" );
267*51c0b2f7Stbbdev         }
268*51c0b2f7Stbbdev         delete[] next_value;
269*51c0b2f7Stbbdev 
270*51c0b2f7Stbbdev         j = bogus_value;
271*51c0b2f7Stbbdev         g.wait_for_all();
272*51c0b2f7Stbbdev         CHECK_MESSAGE( q.try_get( j ) == false, "" );
273*51c0b2f7Stbbdev         CHECK_MESSAGE( j == bogus_value, "" );
274*51c0b2f7Stbbdev 
275*51c0b2f7Stbbdev         utils::NativeParallelFor( num_threads, parallel_puts<T>(q) );
276*51c0b2f7Stbbdev 
277*51c0b2f7Stbbdev         {
278*51c0b2f7Stbbdev             touches< T > t( num_threads );
279*51c0b2f7Stbbdev             utils::NativeParallelFor( num_threads, parallel_gets<T>(q, t) );
280*51c0b2f7Stbbdev             g.wait_for_all();
281*51c0b2f7Stbbdev             CHECK_MESSAGE( t.validate_touches(), "" );
282*51c0b2f7Stbbdev         }
283*51c0b2f7Stbbdev         j = bogus_value;
284*51c0b2f7Stbbdev         CHECK_MESSAGE( q.try_get( j ) == false, "" );
285*51c0b2f7Stbbdev         CHECK_MESSAGE( j == bogus_value, "" );
286*51c0b2f7Stbbdev 
287*51c0b2f7Stbbdev         g.wait_for_all();
288*51c0b2f7Stbbdev         {
289*51c0b2f7Stbbdev             touches< T > t2( num_threads );
290*51c0b2f7Stbbdev             utils::NativeParallelFor( num_threads, parallel_put_get<T>(q, t2) );
291*51c0b2f7Stbbdev             g.wait_for_all();
292*51c0b2f7Stbbdev             CHECK_MESSAGE( t2.validate_touches(), "" );
293*51c0b2f7Stbbdev         }
294*51c0b2f7Stbbdev         j = bogus_value;
295*51c0b2f7Stbbdev         CHECK_MESSAGE( q.try_get( j ) == false, "" );
296*51c0b2f7Stbbdev         CHECK_MESSAGE( j == bogus_value, "" );
297*51c0b2f7Stbbdev 
298*51c0b2f7Stbbdev         tbb::flow::make_edge( q, q2 );
299*51c0b2f7Stbbdev         tbb::flow::make_edge( q2, q3 );
300*51c0b2f7Stbbdev 
301*51c0b2f7Stbbdev         utils::NativeParallelFor( num_threads, parallel_puts<T>(q) );
302*51c0b2f7Stbbdev         {
303*51c0b2f7Stbbdev             touches< T > t3( num_threads );
304*51c0b2f7Stbbdev             utils::NativeParallelFor( num_threads, parallel_gets<T>(q3, t3) );
305*51c0b2f7Stbbdev             g.wait_for_all();
306*51c0b2f7Stbbdev             CHECK_MESSAGE( t3.validate_touches(), "" );
307*51c0b2f7Stbbdev         }
308*51c0b2f7Stbbdev         j = bogus_value;
309*51c0b2f7Stbbdev         g.wait_for_all();
310*51c0b2f7Stbbdev         CHECK_MESSAGE( q.try_get( j ) == false, "" );
311*51c0b2f7Stbbdev         g.wait_for_all();
312*51c0b2f7Stbbdev         CHECK_MESSAGE( q2.try_get( j ) == false, "" );
313*51c0b2f7Stbbdev         g.wait_for_all();
314*51c0b2f7Stbbdev         CHECK_MESSAGE( q3.try_get( j ) == false, "" );
315*51c0b2f7Stbbdev         CHECK_MESSAGE( j == bogus_value, "" );
316*51c0b2f7Stbbdev 
317*51c0b2f7Stbbdev         // test copy constructor
318*51c0b2f7Stbbdev         CHECK_MESSAGE( remove_successor( q, q2 ), "" );
319*51c0b2f7Stbbdev         utils::NativeParallelFor( num_threads, parallel_puts<T>(q) );
320*51c0b2f7Stbbdev         tbb::flow::queue_node<T> q_copy(q);
321*51c0b2f7Stbbdev         j = bogus_value;
322*51c0b2f7Stbbdev         g.wait_for_all();
323*51c0b2f7Stbbdev         CHECK_MESSAGE( q_copy.try_get( j ) == false, "" );
324*51c0b2f7Stbbdev         CHECK_MESSAGE( register_successor( q, q_copy ) == true, "" );
325*51c0b2f7Stbbdev         {
326*51c0b2f7Stbbdev             touches< T > t( num_threads );
327*51c0b2f7Stbbdev             utils::NativeParallelFor( num_threads, parallel_gets<T>(q_copy, t) );
328*51c0b2f7Stbbdev             g.wait_for_all();
329*51c0b2f7Stbbdev             CHECK_MESSAGE( t.validate_touches(), "" );
330*51c0b2f7Stbbdev         }
331*51c0b2f7Stbbdev         j = bogus_value;
332*51c0b2f7Stbbdev         CHECK_MESSAGE( q.try_get( j ) == false, "" );
333*51c0b2f7Stbbdev         CHECK_MESSAGE( j == bogus_value, "" );
334*51c0b2f7Stbbdev         CHECK_MESSAGE( q_copy.try_get( j ) == false, "" );
335*51c0b2f7Stbbdev         CHECK_MESSAGE( j == bogus_value, "" );
336*51c0b2f7Stbbdev     }
337*51c0b2f7Stbbdev 
338*51c0b2f7Stbbdev     return 0;
339*51c0b2f7Stbbdev }
340*51c0b2f7Stbbdev 
341*51c0b2f7Stbbdev //
342*51c0b2f7Stbbdev // Tests
343*51c0b2f7Stbbdev //
344*51c0b2f7Stbbdev // Predecessors cannot be registered
345*51c0b2f7Stbbdev // Empty Q rejects item requests
346*51c0b2f7Stbbdev // Single serial sender, items in FIFO order
347*51c0b2f7Stbbdev // Chained Qs ( 2 & 3 ), single sender, items at last Q in FIFO order
348*51c0b2f7Stbbdev //
349*51c0b2f7Stbbdev 
350*51c0b2f7Stbbdev template< typename T >
351*51c0b2f7Stbbdev int test_serial() {
352*51c0b2f7Stbbdev     tbb::flow::graph g;
353*51c0b2f7Stbbdev     tbb::flow::queue_node<T> q(g);
354*51c0b2f7Stbbdev     tbb::flow::queue_node<T> q2(g);
355*51c0b2f7Stbbdev     {   // destroy the graph after manipulating it, and see if all the items in the buffers
356*51c0b2f7Stbbdev         // have been destroyed before the graph
357*51c0b2f7Stbbdev         Checker<T> my_check;  // if CheckType< U > count constructions and destructions
358*51c0b2f7Stbbdev         T bogus_value(-1);
359*51c0b2f7Stbbdev         T j = bogus_value;
360*51c0b2f7Stbbdev 
361*51c0b2f7Stbbdev         //
362*51c0b2f7Stbbdev         // Rejects attempts to add / remove predecessor
363*51c0b2f7Stbbdev         // Rejects request from empty Q
364*51c0b2f7Stbbdev         //
365*51c0b2f7Stbbdev         CHECK_MESSAGE( register_predecessor( q, q2 ) == false, "" );
366*51c0b2f7Stbbdev         CHECK_MESSAGE( remove_predecessor( q, q2 ) == false, "" );
367*51c0b2f7Stbbdev         CHECK_MESSAGE( q.try_get( j ) == false, "" );
368*51c0b2f7Stbbdev         CHECK_MESSAGE( j == bogus_value, "" );
369*51c0b2f7Stbbdev 
370*51c0b2f7Stbbdev         //
371*51c0b2f7Stbbdev         // Simple puts and gets
372*51c0b2f7Stbbdev         //
373*51c0b2f7Stbbdev 
374*51c0b2f7Stbbdev         for (int i = 0; i < N; ++i) {
375*51c0b2f7Stbbdev             bool msg = q.try_put( T(i) );
376*51c0b2f7Stbbdev             CHECK_MESSAGE( msg == true, "" );
377*51c0b2f7Stbbdev         }
378*51c0b2f7Stbbdev 
379*51c0b2f7Stbbdev 
380*51c0b2f7Stbbdev         for (int i = 0; i < N; ++i) {
381*51c0b2f7Stbbdev             j = bogus_value;
382*51c0b2f7Stbbdev             spin_try_get( q, j );
383*51c0b2f7Stbbdev             CHECK_MESSAGE( i == j, "" );
384*51c0b2f7Stbbdev         }
385*51c0b2f7Stbbdev         j = bogus_value;
386*51c0b2f7Stbbdev         g.wait_for_all();
387*51c0b2f7Stbbdev         CHECK_MESSAGE( q.try_get( j ) == false, "" );
388*51c0b2f7Stbbdev         CHECK_MESSAGE( j == bogus_value, "" );
389*51c0b2f7Stbbdev 
390*51c0b2f7Stbbdev         tbb::flow::make_edge( q, q2 );
391*51c0b2f7Stbbdev 
392*51c0b2f7Stbbdev         for (int i = 0; i < N; ++i) {
393*51c0b2f7Stbbdev             bool msg = q.try_put( T(i) );
394*51c0b2f7Stbbdev             CHECK_MESSAGE( msg == true, "" );
395*51c0b2f7Stbbdev         }
396*51c0b2f7Stbbdev 
397*51c0b2f7Stbbdev 
398*51c0b2f7Stbbdev         for (int i = 0; i < N; ++i) {
399*51c0b2f7Stbbdev             j = bogus_value;
400*51c0b2f7Stbbdev             spin_try_get( q2, j );
401*51c0b2f7Stbbdev             CHECK_MESSAGE( i == j, "" );
402*51c0b2f7Stbbdev         }
403*51c0b2f7Stbbdev         j = bogus_value;
404*51c0b2f7Stbbdev         g.wait_for_all();
405*51c0b2f7Stbbdev         CHECK_MESSAGE( q.try_get( j ) == false, "" );
406*51c0b2f7Stbbdev         g.wait_for_all();
407*51c0b2f7Stbbdev         CHECK_MESSAGE( q2.try_get( j ) == false, "" );
408*51c0b2f7Stbbdev         CHECK_MESSAGE( j == bogus_value, "" );
409*51c0b2f7Stbbdev 
410*51c0b2f7Stbbdev         tbb::flow::remove_edge( q, q2 );
411*51c0b2f7Stbbdev         CHECK_MESSAGE( q.try_put( 1 ) == true, "" );
412*51c0b2f7Stbbdev         g.wait_for_all();
413*51c0b2f7Stbbdev         CHECK_MESSAGE( q2.try_get( j ) == false, "" );
414*51c0b2f7Stbbdev         CHECK_MESSAGE( j == bogus_value, "" );
415*51c0b2f7Stbbdev         g.wait_for_all();
416*51c0b2f7Stbbdev         CHECK_MESSAGE( q.try_get( j ) == true, "" );
417*51c0b2f7Stbbdev         CHECK_MESSAGE( j == 1, "" );
418*51c0b2f7Stbbdev 
419*51c0b2f7Stbbdev         tbb::flow::queue_node<T> q3(g);
420*51c0b2f7Stbbdev         tbb::flow::make_edge( q, q2 );
421*51c0b2f7Stbbdev         tbb::flow::make_edge( q2, q3 );
422*51c0b2f7Stbbdev 
423*51c0b2f7Stbbdev         for (int i = 0; i < N; ++i) {
424*51c0b2f7Stbbdev             bool msg = q.try_put( T(i) );
425*51c0b2f7Stbbdev             CHECK_MESSAGE( msg == true, "" );
426*51c0b2f7Stbbdev         }
427*51c0b2f7Stbbdev 
428*51c0b2f7Stbbdev         for (int i = 0; i < N; ++i) {
429*51c0b2f7Stbbdev             j = bogus_value;
430*51c0b2f7Stbbdev             spin_try_get( q3, j );
431*51c0b2f7Stbbdev             CHECK_MESSAGE( i == j, "" );
432*51c0b2f7Stbbdev         }
433*51c0b2f7Stbbdev         j = bogus_value;
434*51c0b2f7Stbbdev         g.wait_for_all();
435*51c0b2f7Stbbdev         CHECK_MESSAGE( q.try_get( j ) == false, "" );
436*51c0b2f7Stbbdev         g.wait_for_all();
437*51c0b2f7Stbbdev         CHECK_MESSAGE( q2.try_get( j ) == false, "" );
438*51c0b2f7Stbbdev         g.wait_for_all();
439*51c0b2f7Stbbdev         CHECK_MESSAGE( q3.try_get( j ) == false, "" );
440*51c0b2f7Stbbdev         CHECK_MESSAGE( j == bogus_value, "" );
441*51c0b2f7Stbbdev 
442*51c0b2f7Stbbdev         tbb::flow::remove_edge( q,  q2 );
443*51c0b2f7Stbbdev         CHECK_MESSAGE( q.try_put( 1 ) == true, "" );
444*51c0b2f7Stbbdev         g.wait_for_all();
445*51c0b2f7Stbbdev         CHECK_MESSAGE( q2.try_get( j ) == false, "" );
446*51c0b2f7Stbbdev         CHECK_MESSAGE( j == bogus_value, "" );
447*51c0b2f7Stbbdev         g.wait_for_all();
448*51c0b2f7Stbbdev         CHECK_MESSAGE( q3.try_get( j ) == false, "" );
449*51c0b2f7Stbbdev         CHECK_MESSAGE( j == bogus_value, "" );
450*51c0b2f7Stbbdev         g.wait_for_all();
451*51c0b2f7Stbbdev         CHECK_MESSAGE( q.try_get( j ) == true, "" );
452*51c0b2f7Stbbdev         CHECK_MESSAGE( j == 1, "" );
453*51c0b2f7Stbbdev     }
454*51c0b2f7Stbbdev 
455*51c0b2f7Stbbdev     return 0;
456*51c0b2f7Stbbdev }
457*51c0b2f7Stbbdev 
458*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
459*51c0b2f7Stbbdev #include <array>
460*51c0b2f7Stbbdev #include <vector>
461*51c0b2f7Stbbdev void test_follows_and_precedes_api() {
462*51c0b2f7Stbbdev     std::array<int, 3> messages_for_follows = { {0, 1, 2} };
463*51c0b2f7Stbbdev     std::vector<int> messages_for_precedes = {0, 1, 2};
464*51c0b2f7Stbbdev 
465*51c0b2f7Stbbdev     follows_and_precedes_testing::test_follows <int, tbb::flow::queue_node<int>>(messages_for_follows);
466*51c0b2f7Stbbdev     follows_and_precedes_testing::test_precedes <int, tbb::flow::queue_node<int>>(messages_for_precedes);
467*51c0b2f7Stbbdev }
468*51c0b2f7Stbbdev #endif
469*51c0b2f7Stbbdev 
470*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
471*51c0b2f7Stbbdev void test_deduction_guides() {
472*51c0b2f7Stbbdev     using namespace tbb::flow;
473*51c0b2f7Stbbdev     graph g;
474*51c0b2f7Stbbdev     broadcast_node<int> br(g);
475*51c0b2f7Stbbdev     queue_node<int> q0(g);
476*51c0b2f7Stbbdev 
477*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
478*51c0b2f7Stbbdev     queue_node q1(follows(br));
479*51c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(q1), queue_node<int>>);
480*51c0b2f7Stbbdev 
481*51c0b2f7Stbbdev     queue_node q2(precedes(br));
482*51c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(q2), queue_node<int>>);
483*51c0b2f7Stbbdev #endif
484*51c0b2f7Stbbdev 
485*51c0b2f7Stbbdev     queue_node q3(q0);
486*51c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(q3), queue_node<int>>);
487*51c0b2f7Stbbdev     g.wait_for_all();
488*51c0b2f7Stbbdev }
489*51c0b2f7Stbbdev #endif
490*51c0b2f7Stbbdev 
491*51c0b2f7Stbbdev //! Test serial, parallel behavior and reservation under parallelism
492*51c0b2f7Stbbdev //! \brief \ref requirement \ref error_guessing
493*51c0b2f7Stbbdev TEST_CASE("Parallel, serial test"){
494*51c0b2f7Stbbdev     for (int p = 2; p <= 4; ++p) {
495*51c0b2f7Stbbdev         tbb::task_arena arena(p);
496*51c0b2f7Stbbdev         arena.execute(
497*51c0b2f7Stbbdev             [&]() {
498*51c0b2f7Stbbdev 
499*51c0b2f7Stbbdev                 test_serial<int>();
500*51c0b2f7Stbbdev                 test_serial<CheckType<int> >();
501*51c0b2f7Stbbdev                 test_parallel<int>(p);
502*51c0b2f7Stbbdev                 test_parallel<CheckType<int> >(p);
503*51c0b2f7Stbbdev 
504*51c0b2f7Stbbdev             }
505*51c0b2f7Stbbdev         );
506*51c0b2f7Stbbdev 	}
507*51c0b2f7Stbbdev }
508*51c0b2f7Stbbdev 
509*51c0b2f7Stbbdev //! Test reset and cancellation
510*51c0b2f7Stbbdev //! \brief \ref error_guessing
511*51c0b2f7Stbbdev TEST_CASE("Resets test"){
512*51c0b2f7Stbbdev     INFO("Testing resets\n");
513*51c0b2f7Stbbdev     test_resets<int, tbb::flow::queue_node<int> >();
514*51c0b2f7Stbbdev     test_resets<float, tbb::flow::queue_node<float> >();
515*51c0b2f7Stbbdev }
516*51c0b2f7Stbbdev 
517*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
518*51c0b2f7Stbbdev //! Test follows and precedes API
519*51c0b2f7Stbbdev //! \brief \ref error_guessing
520*51c0b2f7Stbbdev TEST_CASE("Test follows and precedes API"){
521*51c0b2f7Stbbdev     test_follows_and_precedes_api();
522*51c0b2f7Stbbdev }
523*51c0b2f7Stbbdev #endif
524*51c0b2f7Stbbdev 
525*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
526*51c0b2f7Stbbdev //! Test decution guides
527*51c0b2f7Stbbdev //! \brief \ref requirement
528*51c0b2f7Stbbdev TEST_CASE("Deduction guides"){
529*51c0b2f7Stbbdev     test_deduction_guides();
530*51c0b2f7Stbbdev }
531*51c0b2f7Stbbdev #endif
532*51c0b2f7Stbbdev 
533*51c0b2f7Stbbdev //! Test operations on a reserved queue_node
534*51c0b2f7Stbbdev //! \brief \ref error_guessing
535*51c0b2f7Stbbdev TEST_CASE("queue_node with reservation"){
536*51c0b2f7Stbbdev     tbb::flow::graph g;
537*51c0b2f7Stbbdev 
538*51c0b2f7Stbbdev     tbb::flow::queue_node<int> q(g);
539*51c0b2f7Stbbdev 
540*51c0b2f7Stbbdev     bool res = q.try_put(42);
541*51c0b2f7Stbbdev     CHECK_MESSAGE( res, "queue_node must accept input." );
542*51c0b2f7Stbbdev 
543*51c0b2f7Stbbdev     int val = 1;
544*51c0b2f7Stbbdev     res = q.try_reserve(val);
545*51c0b2f7Stbbdev     CHECK_MESSAGE( res, "queue_node must reserve as it has an item." );
546*51c0b2f7Stbbdev     CHECK_MESSAGE( (val == 42), "queue_node must reserve once passed item." );
547*51c0b2f7Stbbdev 
548*51c0b2f7Stbbdev     int out_arg = -1;
549*51c0b2f7Stbbdev     CHECK_MESSAGE((q.try_reserve(out_arg) == false), "Reserving a reserved node should fail.");
550*51c0b2f7Stbbdev     CHECK_MESSAGE((out_arg == -1), "Reserving a reserved node should not update its argument.");
551*51c0b2f7Stbbdev 
552*51c0b2f7Stbbdev     out_arg = -1;
553*51c0b2f7Stbbdev     CHECK_MESSAGE((q.try_get(out_arg) == false), "Getting from reserved node should fail.");
554*51c0b2f7Stbbdev     CHECK_MESSAGE((out_arg == -1), "Getting from reserved node should not update its argument.");
555*51c0b2f7Stbbdev     g.wait_for_all();
556*51c0b2f7Stbbdev 
557*51c0b2f7Stbbdev }
558