3 * Copyright 2007,2008 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include <qa_timeouts.h>
26 #include <cppunit/TestAssert.h>
27 #include <mblock/mblock.h>
28 #include <mblock/runtime.h>
29 #include <mblock/protocol_class.h>
30 #include <mblock/message.h>
31 #include <mblock/msg_accepter.h>
32 #include <mblock/class_registry.h>
33 #include <mb_timer_queue.h>
37 using namespace gruel;
39 static pmt_t s_timeout = pmt_intern("%timeout");
40 static pmt_t s_done = pmt_intern("done");
43 // ------------------------------------------------------------------------
44 // Exercise the priority queue used to implement timeouts.
45 // ------------------------------------------------------------------------
47 qa_timeouts::test_timer_queue()
50 mb_msg_accepter_sptr accepter;
52 mb_timeout_sptr t1000_000 =
53 mb_timeout_sptr(new mb_timeout(mb_time(1000,0), PMT_F, accepter));
55 mb_timeout_sptr t2000_000 =
56 mb_timeout_sptr(new mb_timeout(mb_time(2000,0), PMT_F, accepter));
58 mb_timeout_sptr t3000_000 =
59 mb_timeout_sptr(new mb_timeout(mb_time(3000,0), PMT_F, accepter));
61 mb_timeout_sptr t3000_125 =
62 mb_timeout_sptr(new mb_timeout(mb_time(3000,125), PMT_F, accepter));
64 mb_timeout_sptr t3000_250 =
65 mb_timeout_sptr(new mb_timeout(mb_time(3000,250), PMT_F, accepter));
67 mb_timeout_sptr t4000_000 =
68 mb_timeout_sptr(new mb_timeout(mb_time(4000,0), PMT_F, accepter));
70 // insert in pseudo-random order
79 CPPUNIT_ASSERT_EQUAL(t1000_000, tq.top());
82 CPPUNIT_ASSERT_EQUAL(t2000_000, tq.top());
85 CPPUNIT_ASSERT_EQUAL(t3000_000, tq.top());
88 CPPUNIT_ASSERT_EQUAL(t3000_125, tq.top());
91 CPPUNIT_ASSERT_EQUAL(t3000_250, tq.top());
94 CPPUNIT_ASSERT_EQUAL(t4000_000, tq.top());
97 CPPUNIT_ASSERT(tq.empty());
99 // insert in pseudo-random order
108 tq.cancel(t1000_000->handle());
110 CPPUNIT_ASSERT_EQUAL(t2000_000, tq.top());
113 CPPUNIT_ASSERT_EQUAL(t3000_000, tq.top());
116 tq.cancel(t3000_250->handle());
118 CPPUNIT_ASSERT_EQUAL(t3000_125, tq.top());
121 CPPUNIT_ASSERT_EQUAL(t4000_000, tq.top());
124 CPPUNIT_ASSERT(tq.empty());
127 // ------------------------------------------------------------------------
128 // Test one-shot timeouts
129 // ------------------------------------------------------------------------
131 // FWIW, on SuSE 10.1 for x86-64, clock_getres returns 0.004 seconds.
133 // #define TIMING_MARGIN 0.010 // seconds // was failing on some systems
134 #define TIMING_MARGIN 0.025 // seconds (really sloppy; consider enabling RT scheduler)
137 class qa_timeouts_1_top : public mb_mblock
144 qa_timeouts_1_top(mb_runtime *runtime,
145 const std::string &instance_name, pmt_t user_arg);
147 void initial_transition();
148 void handle_message(mb_message_sptr msg);
151 qa_timeouts_1_top::qa_timeouts_1_top(mb_runtime *runtime,
152 const std::string &instance_name,
154 : mb_mblock(runtime, instance_name, user_arg),
155 d_nleft(0), d_nerrors(0)
160 qa_timeouts_1_top::initial_transition()
162 d_t0 = mb_time::time(); // now
164 schedule_one_shot_timeout(d_t0 + 0.200, pmt_from_double(0.200));
165 schedule_one_shot_timeout(d_t0 + 0.125, pmt_from_double(0.125));
166 schedule_one_shot_timeout(d_t0 + 0.075, pmt_from_double(0.075));
167 schedule_one_shot_timeout(d_t0 + 0.175, pmt_from_double(0.175));
173 qa_timeouts_1_top::handle_message(mb_message_sptr msg)
175 if (pmt_eq(msg->signal(), s_timeout)){
176 mb_time t_now = mb_time::time();
177 double expected_delta_t = pmt_to_double(msg->data());
178 double actual_delta_t = (t_now - d_t0).double_time();
179 double delta = expected_delta_t - actual_delta_t;
181 if (fabs(delta) > TIMING_MARGIN){
182 std::cerr << "qa_timeouts_1_top: expected_delta_t = " << expected_delta_t
183 << " actual_delta_t = " << actual_delta_t << std::endl;
188 shutdown_all(d_nerrors == 0 ? PMT_T : PMT_F);
192 REGISTER_MBLOCK_CLASS(qa_timeouts_1_top);
195 qa_timeouts::test_timeouts_1()
197 mb_runtime_sptr rt = mb_make_runtime();
198 pmt_t result = PMT_NIL;
200 rt->run("top", "qa_timeouts_1_top", PMT_F, &result);
202 CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
205 // ------------------------------------------------------------------------
206 // Test periodic timeouts
207 // ------------------------------------------------------------------------
209 class qa_timeouts_2_top : public mb_mblock
217 qa_timeouts_2_top(mb_runtime *runtime,
218 const std::string &instance_name, pmt_t user_arg);
220 void initial_transition();
221 void handle_message(mb_message_sptr msg);
224 qa_timeouts_2_top::qa_timeouts_2_top(mb_runtime *runtime,
225 const std::string &instance_name,
227 : mb_mblock(runtime, instance_name, user_arg),
228 d_nhandled(0), d_nerrors(0), d_delta_t(0.075)
233 qa_timeouts_2_top::initial_transition()
235 d_t0 = mb_time::time(); // now
237 schedule_periodic_timeout(d_t0 + d_delta_t, mb_time(d_delta_t), PMT_T);
241 qa_timeouts_2_top::handle_message(mb_message_sptr msg)
243 static const int NMSGS_TO_HANDLE = 5;
245 if (pmt_eq(msg->signal(), s_timeout)
246 && !pmt_eq(msg->data(), s_done)){
248 mb_time t_now = mb_time::time();
252 double expected_delta_t = d_delta_t * d_nhandled;
253 double actual_delta_t = (t_now - d_t0).double_time();
254 double delta = expected_delta_t - actual_delta_t;
256 if (fabs(delta) > TIMING_MARGIN){
257 std::cerr << "qa_timeouts_2_top: expected_delta_t = " << expected_delta_t
258 << " actual_delta_t = " << actual_delta_t << std::endl;
262 if (d_nhandled == NMSGS_TO_HANDLE){
263 cancel_timeout(msg->metadata()); // test cancel_timeout...
264 schedule_one_shot_timeout(d_t0 + (d_delta_t * (d_nhandled + 2)), s_done);
268 if (pmt_eq(msg->signal(), s_timeout)
269 && pmt_eq(msg->data(), s_done)){
270 if (d_nhandled != NMSGS_TO_HANDLE){
271 std::cerr << "qa_timeouts_2_top: d_nhandled = " << d_nhandled
272 << " expected d_nhandled = " << NMSGS_TO_HANDLE
273 << " (cancel_timeout didn't work)\n";
276 shutdown_all(d_nerrors == 0 ? PMT_T : PMT_F);
280 REGISTER_MBLOCK_CLASS(qa_timeouts_2_top);
283 qa_timeouts::test_timeouts_2()
285 mb_runtime_sptr rt = mb_make_runtime();
286 pmt_t result = PMT_NIL;
288 rt->run("top", "qa_timeouts_2_top", PMT_F, &result);
290 CPPUNIT_ASSERT(pmt_equal(PMT_T, result));