// sequencer_node behaves like a queueing node, but requires a different constructor. void TestSequencerNode() { tbb::flow::graph g; tbb::flow::sequencer_node<int> bnode(g, seq_body()); REMARK("Testing sequencer_node:"); tbb::flow::function_node<int> fnode(g, tbb::flow::serial, serial_fn_body<int>(serial_fn_state0)); REMARK("Testing sequencer_node:"); serial_fn_state0 = 0; // reset to waiting state. REMARK(" make_edge"); tbb::flow::make_edge(bnode, fnode); ASSERT(!bnode.my_successors.empty(), "buffering node has no successor after make_edge"); REMARK(" try_put"); bnode.try_put(0); // will forward to the fnode BACKOFF_WAIT( serial_fn_state0 == 0, "timeout waiting for function_node"); // wait for the function_node to fire up ASSERT(!bnode.my_successors.empty(), "buffering node has no successor after forwarding message"); serial_fn_state0 = 0; g.wait_for_all(); REMARK(" remove_edge"); tbb::flow::remove_edge(bnode, fnode); ASSERT(bnode.my_successors.empty(), "buffering node has a successor after remove_edge"); tbb::flow::join_node<tbb::flow::tuple<int,int>,tbb::flow::reserving> jnode(g); tbb::flow::make_edge(bnode, tbb::flow::input_port<0>(jnode)); // will spawn a task g.wait_for_all(); ASSERT(!bnode.my_successors.empty(), "buffering node has no successor after attaching to join"); REMARK(" reverse"); bnode.try_put(3); // the edge should reverse g.wait_for_all(); ASSERT(bnode.my_successors.empty(), "buffering node has a successor after reserving"); REMARK(" reset()"); g.wait_for_all(); g.reset(); // should be in forward direction again ASSERT(!bnode.my_successors.empty(), "buffering node has no successor after reset()"); #if TBB_PREVIEW_FLOW_GRAPH_FEATURES REMARK(" remove_edge"); g.reset(tbb::flow::rf_extract); // should be in forward direction again ASSERT(bnode.my_successors.empty(), "buffering node has a successor after reset(rf_extract)"); ASSERT(fnode.my_predecessors.empty(), "buffering node reversed after reset(rf_extract)"); #endif REMARK(" done\n"); g.wait_for_all(); }
void TestBufferingNode(const char * name) { tbb::flow::graph g; B bnode(g); tbb::flow::function_node<int,int,tbb::flow::rejecting> fnode(g, tbb::flow::serial, serial_fn_body<int>(serial_fn_state0)); REMARK("Testing %s:", name); for(int icnt = 0; icnt < 2; icnt++) { bool reverse_edge = (icnt & 0x2) != 0; serial_fn_state0 = 0; // reset to waiting state. REMARK(" make_edge"); tbb::flow::make_edge(bnode, fnode); ASSERT(!bnode.my_successors.empty(), "buffering node has no successor after make_edge"); REMARK(" try_put"); bnode.try_put(1); // will forward to the fnode BACKOFF_WAIT(serial_fn_state0 == 0, "Timed out waiting for first put"); if(reverse_edge) { REMARK(" try_put2"); bnode.try_put(2); // will reverse the edge // cannot do a wait_for_all here; the function_node is still executing BACKOFF_WAIT(!bnode.my_successors.empty(), "Timed out waiting after 2nd put"); // at this point the only task running is the one for the function_node. ASSERT(bnode.my_successors.empty(), "successor not removed"); } else { ASSERT(!bnode.my_successors.empty(), "buffering node has no successor after forwarding message"); } serial_fn_state0 = 0; // release the function_node. if(reverse_edge) { // have to do a second release because the function_node will get the 2nd item BACKOFF_WAIT( serial_fn_state0 == 0, "Timed out waiting after 2nd put"); serial_fn_state0 = 0; // release the function_node. } g.wait_for_all(); REMARK(" remove_edge"); tbb::flow::remove_edge(bnode, fnode); ASSERT(bnode.my_successors.empty(), "buffering node has a successor after remove_edge"); } tbb::flow::join_node<tbb::flow::tuple<int,int>,tbb::flow::reserving> jnode(g); tbb::flow::make_edge(bnode, tbb::flow::input_port<0>(jnode)); // will spawn a task g.wait_for_all(); ASSERT(!bnode.my_successors.empty(), "buffering node has no successor after attaching to join"); REMARK(" reverse"); bnode.try_put(1); // the edge should reverse g.wait_for_all(); ASSERT(bnode.my_successors.empty(), "buffering node has a successor after reserving"); REMARK(" reset()"); g.wait_for_all(); g.reset(); // should be in forward direction again ASSERT(!bnode.my_successors.empty(), "buffering node has no successor after reset()"); REMARK(" remove_edge"); g.reset(tbb::flow::rf_clear_edges); ASSERT(bnode.my_successors.empty(), "buffering node has a successor after reset(rf_clear_edges)"); tbb::flow::make_edge(bnode, tbb::flow::input_port<0>(jnode)); // add edge again // reverse edge by adding to buffer. bnode.try_put(1); // the edge should reverse g.wait_for_all(); ASSERT(bnode.my_successors.empty(), "buffering node has a successor after reserving"); REMARK(" remove_edge(reversed)"); g.reset(tbb::flow::rf_clear_edges); ASSERT(bnode.my_successors.empty(), "buffering node has no successor after reset()"); ASSERT(tbb::flow::input_port<0>(jnode).my_predecessors.empty(), "predecessor not reset"); REMARK(" done\n"); g.wait_for_all(); }