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