Updated license from GPL version 2 or later to GPL version 3 or later.
[debian/gnuradio] / mblock / src / lib / qa_timeouts.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2007 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
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)
10  * any later version.
11  * 
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.
16  * 
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.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <qa_timeouts.h>
26 #include <cppunit/TestAssert.h>
27 #include <mb_mblock.h>
28 #include <mb_runtime.h>
29 #include <mb_protocol_class.h>
30 #include <mb_message.h>
31 #include <mb_msg_accepter.h>
32 #include <mb_class_registry.h>
33 #include <mb_timer_queue.h>
34 #include <string.h>
35 #include <iostream>
36
37
38 static pmt_t s_timeout = pmt_intern("%timeout");
39 static pmt_t s_done = pmt_intern("done");
40
41
42 // ------------------------------------------------------------------------
43 //    Exercise the priority queue used to implement timeouts.
44 // ------------------------------------------------------------------------
45 void
46 qa_timeouts::test_timer_queue()
47 {
48   mb_timer_queue        tq;
49   mb_msg_accepter_sptr  accepter;
50
51   mb_timeout_sptr       t1000_000 =
52     mb_timeout_sptr(new mb_timeout(mb_time(1000,0), PMT_F, accepter));
53
54   mb_timeout_sptr       t2000_000 =
55     mb_timeout_sptr(new mb_timeout(mb_time(2000,0), PMT_F, accepter));
56                                                                     
57   mb_timeout_sptr       t3000_000 =
58     mb_timeout_sptr(new mb_timeout(mb_time(3000,0), PMT_F, accepter));
59                                                                     
60   mb_timeout_sptr       t3000_125 =
61     mb_timeout_sptr(new mb_timeout(mb_time(3000,125), PMT_F, accepter));
62                                                                     
63   mb_timeout_sptr       t3000_250 =
64     mb_timeout_sptr(new mb_timeout(mb_time(3000,250), PMT_F, accepter));
65                                                                     
66   mb_timeout_sptr       t4000_000 =
67     mb_timeout_sptr(new mb_timeout(mb_time(4000,0), PMT_F, accepter));
68                                                                     
69   // insert in pseudo-random order
70
71   tq.push(t3000_125);
72   tq.push(t1000_000);
73   tq.push(t4000_000);
74   tq.push(t3000_250);
75   tq.push(t2000_000);
76   tq.push(t3000_000);
77
78   CPPUNIT_ASSERT_EQUAL(t1000_000, tq.top());
79   tq.pop();
80   
81   CPPUNIT_ASSERT_EQUAL(t2000_000, tq.top());
82   tq.pop();
83   
84   CPPUNIT_ASSERT_EQUAL(t3000_000, tq.top());
85   tq.pop();
86   
87   CPPUNIT_ASSERT_EQUAL(t3000_125, tq.top());
88   tq.pop();
89   
90   CPPUNIT_ASSERT_EQUAL(t3000_250, tq.top());
91   tq.pop();
92   
93   CPPUNIT_ASSERT_EQUAL(t4000_000, tq.top());
94   tq.pop();
95
96   CPPUNIT_ASSERT(tq.empty());
97
98   // insert in pseudo-random order
99
100   tq.push(t3000_000);
101   tq.push(t4000_000);
102   tq.push(t3000_125);
103   tq.push(t1000_000);
104   tq.push(t2000_000);
105   tq.push(t3000_250);
106
107   tq.cancel(t1000_000->handle());
108
109   CPPUNIT_ASSERT_EQUAL(t2000_000, tq.top());
110   tq.pop();
111   
112   CPPUNIT_ASSERT_EQUAL(t3000_000, tq.top());
113   tq.pop();
114   
115   tq.cancel(t3000_250->handle());
116
117   CPPUNIT_ASSERT_EQUAL(t3000_125, tq.top());
118   tq.pop();
119   
120   CPPUNIT_ASSERT_EQUAL(t4000_000, tq.top());
121   tq.pop();
122   
123   CPPUNIT_ASSERT(tq.empty());
124 }
125
126 // ------------------------------------------------------------------------
127 //   Test one-shot timeouts
128 // ------------------------------------------------------------------------
129
130 // FWIW, on SuSE 10.1 for x86-64, clock_getres returns 0.004 seconds.
131
132 #define TIMING_MARGIN 0.010     // seconds
133
134 class qa_timeouts_1_top : public mb_mblock
135 {
136   int           d_nleft;
137   int           d_nerrors;
138   mb_time       d_t0;
139   
140 public:
141   qa_timeouts_1_top(mb_runtime *runtime,
142                     const std::string &instance_name, pmt_t user_arg);
143
144   void initial_transition();
145   void handle_message(mb_message_sptr msg);
146 };
147
148 qa_timeouts_1_top::qa_timeouts_1_top(mb_runtime *runtime,
149                                      const std::string &instance_name,
150                                      pmt_t user_arg)
151   : mb_mblock(runtime, instance_name, user_arg),
152     d_nleft(0), d_nerrors(0)
153 {
154 }
155
156 void
157 qa_timeouts_1_top::initial_transition()
158 {
159   d_t0 = mb_time::time();       // now
160
161   schedule_one_shot_timeout(d_t0 + 0.200, pmt_from_double(0.200));
162   schedule_one_shot_timeout(d_t0 + 0.125, pmt_from_double(0.125));
163   schedule_one_shot_timeout(d_t0 + 0.075, pmt_from_double(0.075));
164   schedule_one_shot_timeout(d_t0 + 0.175, pmt_from_double(0.175));
165
166   d_nleft = 4;
167 }
168
169 void
170 qa_timeouts_1_top::handle_message(mb_message_sptr msg)
171 {
172   if (pmt_eq(msg->signal(), s_timeout)){
173     mb_time t_now = mb_time::time();
174     double expected_delta_t = pmt_to_double(msg->data());
175     double actual_delta_t = (t_now - d_t0).double_time();
176     double delta = expected_delta_t - actual_delta_t;
177
178     if (fabs(delta) > TIMING_MARGIN){
179       std::cerr << "qa_timeouts_1_top: expected_delta_t = " << expected_delta_t
180                 << " actual_delta_t = " << actual_delta_t << std::endl;
181       d_nerrors++;
182     }
183
184     if (--d_nleft <= 0)
185       shutdown_all(d_nerrors == 0 ? PMT_T : PMT_F);
186   }
187 }
188
189 REGISTER_MBLOCK_CLASS(qa_timeouts_1_top);
190
191 void
192 qa_timeouts::test_timeouts_1()
193 {
194   mb_runtime_sptr rt = mb_make_runtime();
195   pmt_t result = PMT_NIL;
196
197   rt->run("top", "qa_timeouts_1_top", PMT_F, &result);
198
199   CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
200 }
201
202 // ------------------------------------------------------------------------
203 //   Test periodic timeouts
204 // ------------------------------------------------------------------------
205
206 class qa_timeouts_2_top : public mb_mblock
207 {
208   int           d_nhandled;
209   int           d_nerrors;
210   double        d_delta_t;
211   mb_time       d_t0;
212   
213 public:
214   qa_timeouts_2_top(mb_runtime *runtime,
215                     const std::string &instance_name, pmt_t user_arg);
216
217   void initial_transition();
218   void handle_message(mb_message_sptr msg);
219 };
220
221 qa_timeouts_2_top::qa_timeouts_2_top(mb_runtime *runtime,
222                                      const std::string &instance_name,
223                                      pmt_t user_arg)
224   : mb_mblock(runtime, instance_name, user_arg),
225     d_nhandled(0), d_nerrors(0), d_delta_t(0.075)
226 {
227 }
228
229 void
230 qa_timeouts_2_top::initial_transition()
231 {
232   d_t0 = mb_time::time();       // now
233
234   schedule_periodic_timeout(d_t0 + d_delta_t, mb_time(d_delta_t), PMT_T);
235 }
236
237 void
238 qa_timeouts_2_top::handle_message(mb_message_sptr msg)
239 {
240   static const int NMSGS_TO_HANDLE = 5;
241
242   if (pmt_eq(msg->signal(), s_timeout)
243       && !pmt_eq(msg->data(), s_done)){
244
245     mb_time t_now = mb_time::time();
246
247     d_nhandled++;
248
249     double expected_delta_t = d_delta_t * d_nhandled;
250     double actual_delta_t = (t_now - d_t0).double_time();
251     double delta = expected_delta_t - actual_delta_t;
252
253     if (fabs(delta) > TIMING_MARGIN){
254       std::cerr << "qa_timeouts_2_top: expected_delta_t = " << expected_delta_t
255                 << " actual_delta_t = " << actual_delta_t << std::endl;
256       d_nerrors++;
257     }
258
259     if (d_nhandled == NMSGS_TO_HANDLE){
260       cancel_timeout(msg->metadata());  // test cancel_timeout...
261       schedule_one_shot_timeout(d_t0 + (d_delta_t * (d_nhandled + 2)), s_done);
262     }
263   }
264
265   if (pmt_eq(msg->signal(), s_timeout)
266       && pmt_eq(msg->data(), s_done)){
267     if (d_nhandled != NMSGS_TO_HANDLE){
268       std::cerr << "qa_timeouts_2_top: d_nhandled = " << d_nhandled
269                 << " expected d_nhandled = " << NMSGS_TO_HANDLE
270                 << " (cancel_timeout didn't work)\n";
271       d_nerrors++;
272     }
273     shutdown_all(d_nerrors == 0 ? PMT_T : PMT_F);
274   }
275 }
276
277 REGISTER_MBLOCK_CLASS(qa_timeouts_2_top);
278
279 void
280 qa_timeouts::test_timeouts_2()
281 {
282   mb_runtime_sptr rt = mb_make_runtime();
283   pmt_t result = PMT_NIL;
284
285   rt->run("top", "qa_timeouts_2_top", PMT_F, &result);
286
287   CPPUNIT_ASSERT(pmt_equal(PMT_T, result));
288 }