xref: /freebsd-src/contrib/kyua/utils/signals/timer_test.cpp (revision b0d29bc47dba79f6f38e67eabadfb4b32ffd9390)
1*b0d29bc4SBrooks Davis // Copyright 2010 The Kyua Authors.
2*b0d29bc4SBrooks Davis // All rights reserved.
3*b0d29bc4SBrooks Davis //
4*b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5*b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6*b0d29bc4SBrooks Davis // met:
7*b0d29bc4SBrooks Davis //
8*b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9*b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer.
10*b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11*b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer in the
12*b0d29bc4SBrooks Davis //   documentation and/or other materials provided with the distribution.
13*b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14*b0d29bc4SBrooks Davis //   may be used to endorse or promote products derived from this software
15*b0d29bc4SBrooks Davis //   without specific prior written permission.
16*b0d29bc4SBrooks Davis //
17*b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*b0d29bc4SBrooks Davis 
29*b0d29bc4SBrooks Davis #include "utils/signals/timer.hpp"
30*b0d29bc4SBrooks Davis 
31*b0d29bc4SBrooks Davis extern "C" {
32*b0d29bc4SBrooks Davis #include <signal.h>
33*b0d29bc4SBrooks Davis #include <unistd.h>
34*b0d29bc4SBrooks Davis }
35*b0d29bc4SBrooks Davis 
36*b0d29bc4SBrooks Davis #include <cstddef>
37*b0d29bc4SBrooks Davis #include <iostream>
38*b0d29bc4SBrooks Davis #include <vector>
39*b0d29bc4SBrooks Davis 
40*b0d29bc4SBrooks Davis #include <atf-c++.hpp>
41*b0d29bc4SBrooks Davis 
42*b0d29bc4SBrooks Davis #include "utils/datetime.hpp"
43*b0d29bc4SBrooks Davis #include "utils/defs.hpp"
44*b0d29bc4SBrooks Davis #include "utils/format/containers.ipp"
45*b0d29bc4SBrooks Davis #include "utils/format/macros.hpp"
46*b0d29bc4SBrooks Davis #include "utils/signals/interrupts.hpp"
47*b0d29bc4SBrooks Davis #include "utils/signals/programmer.hpp"
48*b0d29bc4SBrooks Davis 
49*b0d29bc4SBrooks Davis namespace datetime = utils::datetime;
50*b0d29bc4SBrooks Davis namespace signals = utils::signals;
51*b0d29bc4SBrooks Davis 
52*b0d29bc4SBrooks Davis 
53*b0d29bc4SBrooks Davis namespace {
54*b0d29bc4SBrooks Davis 
55*b0d29bc4SBrooks Davis 
56*b0d29bc4SBrooks Davis /// A timer that inserts an element into a vector on activation.
57*b0d29bc4SBrooks Davis class delayed_inserter : public signals::timer {
58*b0d29bc4SBrooks Davis     /// Vector into which to insert the element.
59*b0d29bc4SBrooks Davis     std::vector< int >& _destination;
60*b0d29bc4SBrooks Davis 
61*b0d29bc4SBrooks Davis     /// Element to insert into _destination on activation.
62*b0d29bc4SBrooks Davis     const int _item;
63*b0d29bc4SBrooks Davis 
64*b0d29bc4SBrooks Davis     /// Timer activation callback.
65*b0d29bc4SBrooks Davis     void
callback(void)66*b0d29bc4SBrooks Davis     callback(void)
67*b0d29bc4SBrooks Davis     {
68*b0d29bc4SBrooks Davis         signals::interrupts_inhibiter inhibiter;
69*b0d29bc4SBrooks Davis         _destination.push_back(_item);
70*b0d29bc4SBrooks Davis     }
71*b0d29bc4SBrooks Davis 
72*b0d29bc4SBrooks Davis public:
73*b0d29bc4SBrooks Davis     /// Constructor.
74*b0d29bc4SBrooks Davis     ///
75*b0d29bc4SBrooks Davis     /// \param delta Time to the timer activation.
76*b0d29bc4SBrooks Davis     /// \param destination Vector into which to insert the element.
77*b0d29bc4SBrooks Davis     /// \param item Element to insert into destination on activation.
delayed_inserter(const datetime::delta & delta,std::vector<int> & destination,const int item)78*b0d29bc4SBrooks Davis     delayed_inserter(const datetime::delta& delta,
79*b0d29bc4SBrooks Davis                      std::vector< int >& destination, const int item) :
80*b0d29bc4SBrooks Davis         signals::timer(delta), _destination(destination), _item(item)
81*b0d29bc4SBrooks Davis     {
82*b0d29bc4SBrooks Davis     }
83*b0d29bc4SBrooks Davis };
84*b0d29bc4SBrooks Davis 
85*b0d29bc4SBrooks Davis 
86*b0d29bc4SBrooks Davis /// Signal handler that does nothing.
87*b0d29bc4SBrooks Davis static void
null_handler(const int)88*b0d29bc4SBrooks Davis null_handler(const int /* signo */)
89*b0d29bc4SBrooks Davis {
90*b0d29bc4SBrooks Davis }
91*b0d29bc4SBrooks Davis 
92*b0d29bc4SBrooks Davis 
93*b0d29bc4SBrooks Davis /// Waits for the activation of all given timers.
94*b0d29bc4SBrooks Davis ///
95*b0d29bc4SBrooks Davis /// \param timers Pointers to all the timers to wait for.
96*b0d29bc4SBrooks Davis static void
wait_timers(const std::vector<signals::timer * > & timers)97*b0d29bc4SBrooks Davis wait_timers(const std::vector< signals::timer* >& timers)
98*b0d29bc4SBrooks Davis {
99*b0d29bc4SBrooks Davis     std::size_t n_fired, old_n_fired = 0;
100*b0d29bc4SBrooks Davis     do {
101*b0d29bc4SBrooks Davis         n_fired = 0;
102*b0d29bc4SBrooks Davis         for (std::vector< signals::timer* >::const_iterator
103*b0d29bc4SBrooks Davis                  iter = timers.begin(); iter != timers.end(); ++iter) {
104*b0d29bc4SBrooks Davis             const signals::timer* timer = *iter;
105*b0d29bc4SBrooks Davis             if (timer->fired())
106*b0d29bc4SBrooks Davis                 ++n_fired;
107*b0d29bc4SBrooks Davis         }
108*b0d29bc4SBrooks Davis         if (old_n_fired < n_fired) {
109*b0d29bc4SBrooks Davis             std::cout << "Waiting; " << n_fired << " timers fired so far\n";
110*b0d29bc4SBrooks Davis             old_n_fired = n_fired;
111*b0d29bc4SBrooks Davis         }
112*b0d29bc4SBrooks Davis         ::usleep(100);
113*b0d29bc4SBrooks Davis     } while (n_fired < timers.size());
114*b0d29bc4SBrooks Davis }
115*b0d29bc4SBrooks Davis 
116*b0d29bc4SBrooks Davis 
117*b0d29bc4SBrooks Davis }  // anonymous namespace
118*b0d29bc4SBrooks Davis 
119*b0d29bc4SBrooks Davis 
120*b0d29bc4SBrooks Davis ATF_TEST_CASE(program_seconds);
ATF_TEST_CASE_HEAD(program_seconds)121*b0d29bc4SBrooks Davis ATF_TEST_CASE_HEAD(program_seconds)
122*b0d29bc4SBrooks Davis {
123*b0d29bc4SBrooks Davis     set_md_var("timeout", "10");
124*b0d29bc4SBrooks Davis }
ATF_TEST_CASE_BODY(program_seconds)125*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(program_seconds)
126*b0d29bc4SBrooks Davis {
127*b0d29bc4SBrooks Davis     signals::timer timer(datetime::delta(1, 0));
128*b0d29bc4SBrooks Davis     ATF_REQUIRE(!timer.fired());
129*b0d29bc4SBrooks Davis     while (!timer.fired())
130*b0d29bc4SBrooks Davis         ::usleep(1000);
131*b0d29bc4SBrooks Davis }
132*b0d29bc4SBrooks Davis 
133*b0d29bc4SBrooks Davis 
134*b0d29bc4SBrooks Davis ATF_TEST_CASE(program_useconds);
ATF_TEST_CASE_HEAD(program_useconds)135*b0d29bc4SBrooks Davis ATF_TEST_CASE_HEAD(program_useconds)
136*b0d29bc4SBrooks Davis {
137*b0d29bc4SBrooks Davis     set_md_var("timeout", "10");
138*b0d29bc4SBrooks Davis }
ATF_TEST_CASE_BODY(program_useconds)139*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(program_useconds)
140*b0d29bc4SBrooks Davis {
141*b0d29bc4SBrooks Davis     signals::timer timer(datetime::delta(0, 500000));
142*b0d29bc4SBrooks Davis     ATF_REQUIRE(!timer.fired());
143*b0d29bc4SBrooks Davis     while (!timer.fired())
144*b0d29bc4SBrooks Davis         ::usleep(1000);
145*b0d29bc4SBrooks Davis }
146*b0d29bc4SBrooks Davis 
147*b0d29bc4SBrooks Davis 
148*b0d29bc4SBrooks Davis ATF_TEST_CASE(multiprogram_ordered);
ATF_TEST_CASE_HEAD(multiprogram_ordered)149*b0d29bc4SBrooks Davis ATF_TEST_CASE_HEAD(multiprogram_ordered)
150*b0d29bc4SBrooks Davis {
151*b0d29bc4SBrooks Davis     set_md_var("timeout", "20");
152*b0d29bc4SBrooks Davis }
ATF_TEST_CASE_BODY(multiprogram_ordered)153*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(multiprogram_ordered)
154*b0d29bc4SBrooks Davis {
155*b0d29bc4SBrooks Davis     static const std::size_t n_timers = 100;
156*b0d29bc4SBrooks Davis 
157*b0d29bc4SBrooks Davis     std::vector< signals::timer* > timers;
158*b0d29bc4SBrooks Davis     std::vector< int > items, exp_items;
159*b0d29bc4SBrooks Davis 
160*b0d29bc4SBrooks Davis     const int initial_delay_ms = 1000000;
161*b0d29bc4SBrooks Davis     for (std::size_t i = 0; i < n_timers; ++i) {
162*b0d29bc4SBrooks Davis         exp_items.push_back(i);
163*b0d29bc4SBrooks Davis 
164*b0d29bc4SBrooks Davis         timers.push_back(new delayed_inserter(
165*b0d29bc4SBrooks Davis             datetime::delta(0, initial_delay_ms + (i + 1) * 10000),
166*b0d29bc4SBrooks Davis             items, i));
167*b0d29bc4SBrooks Davis         ATF_REQUIRE(!timers[i]->fired());
168*b0d29bc4SBrooks Davis     }
169*b0d29bc4SBrooks Davis 
170*b0d29bc4SBrooks Davis     wait_timers(timers);
171*b0d29bc4SBrooks Davis 
172*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exp_items, items);
173*b0d29bc4SBrooks Davis }
174*b0d29bc4SBrooks Davis 
175*b0d29bc4SBrooks Davis 
176*b0d29bc4SBrooks Davis ATF_TEST_CASE(multiprogram_reorder_next_activations);
ATF_TEST_CASE_HEAD(multiprogram_reorder_next_activations)177*b0d29bc4SBrooks Davis ATF_TEST_CASE_HEAD(multiprogram_reorder_next_activations)
178*b0d29bc4SBrooks Davis {
179*b0d29bc4SBrooks Davis     set_md_var("timeout", "20");
180*b0d29bc4SBrooks Davis }
ATF_TEST_CASE_BODY(multiprogram_reorder_next_activations)181*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(multiprogram_reorder_next_activations)
182*b0d29bc4SBrooks Davis {
183*b0d29bc4SBrooks Davis     std::vector< signals::timer* > timers;
184*b0d29bc4SBrooks Davis     std::vector< int > items;
185*b0d29bc4SBrooks Davis 
186*b0d29bc4SBrooks Davis     // First timer with an activation in the future.
187*b0d29bc4SBrooks Davis     timers.push_back(new delayed_inserter(
188*b0d29bc4SBrooks Davis                          datetime::delta(0, 100000), items, 1));
189*b0d29bc4SBrooks Davis     ATF_REQUIRE(!timers[timers.size() - 1]->fired());
190*b0d29bc4SBrooks Davis 
191*b0d29bc4SBrooks Davis     // Timer with an activation earlier than the previous one.
192*b0d29bc4SBrooks Davis     timers.push_back(new delayed_inserter(
193*b0d29bc4SBrooks Davis                          datetime::delta(0, 50000), items, 2));
194*b0d29bc4SBrooks Davis     ATF_REQUIRE(!timers[timers.size() - 1]->fired());
195*b0d29bc4SBrooks Davis 
196*b0d29bc4SBrooks Davis     // Timer with an activation later than all others.
197*b0d29bc4SBrooks Davis     timers.push_back(new delayed_inserter(
198*b0d29bc4SBrooks Davis                          datetime::delta(0, 200000), items, 3));
199*b0d29bc4SBrooks Davis     ATF_REQUIRE(!timers[timers.size() - 1]->fired());
200*b0d29bc4SBrooks Davis 
201*b0d29bc4SBrooks Davis     // Timer with an activation in between.
202*b0d29bc4SBrooks Davis     timers.push_back(new delayed_inserter(
203*b0d29bc4SBrooks Davis                          datetime::delta(0, 150000), items, 4));
204*b0d29bc4SBrooks Davis     ATF_REQUIRE(!timers[timers.size() - 1]->fired());
205*b0d29bc4SBrooks Davis 
206*b0d29bc4SBrooks Davis     wait_timers(timers);
207*b0d29bc4SBrooks Davis 
208*b0d29bc4SBrooks Davis     std::vector< int > exp_items;
209*b0d29bc4SBrooks Davis     exp_items.push_back(2);
210*b0d29bc4SBrooks Davis     exp_items.push_back(1);
211*b0d29bc4SBrooks Davis     exp_items.push_back(4);
212*b0d29bc4SBrooks Davis     exp_items.push_back(3);
213*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exp_items, items);
214*b0d29bc4SBrooks Davis }
215*b0d29bc4SBrooks Davis 
216*b0d29bc4SBrooks Davis 
217*b0d29bc4SBrooks Davis ATF_TEST_CASE(multiprogram_and_cancel_some);
ATF_TEST_CASE_HEAD(multiprogram_and_cancel_some)218*b0d29bc4SBrooks Davis ATF_TEST_CASE_HEAD(multiprogram_and_cancel_some)
219*b0d29bc4SBrooks Davis {
220*b0d29bc4SBrooks Davis     set_md_var("timeout", "20");
221*b0d29bc4SBrooks Davis }
ATF_TEST_CASE_BODY(multiprogram_and_cancel_some)222*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(multiprogram_and_cancel_some)
223*b0d29bc4SBrooks Davis {
224*b0d29bc4SBrooks Davis     std::vector< signals::timer* > timers;
225*b0d29bc4SBrooks Davis     std::vector< int > items;
226*b0d29bc4SBrooks Davis 
227*b0d29bc4SBrooks Davis     // First timer with an activation in the future.
228*b0d29bc4SBrooks Davis     timers.push_back(new delayed_inserter(
229*b0d29bc4SBrooks Davis                          datetime::delta(0, 100000), items, 1));
230*b0d29bc4SBrooks Davis 
231*b0d29bc4SBrooks Davis     // Timer with an activation earlier than the previous one.
232*b0d29bc4SBrooks Davis     timers.push_back(new delayed_inserter(
233*b0d29bc4SBrooks Davis                          datetime::delta(0, 50000), items, 2));
234*b0d29bc4SBrooks Davis 
235*b0d29bc4SBrooks Davis     // Timer with an activation later than all others.
236*b0d29bc4SBrooks Davis     timers.push_back(new delayed_inserter(
237*b0d29bc4SBrooks Davis                          datetime::delta(0, 200000), items, 3));
238*b0d29bc4SBrooks Davis 
239*b0d29bc4SBrooks Davis     // Timer with an activation in between.
240*b0d29bc4SBrooks Davis     timers.push_back(new delayed_inserter(
241*b0d29bc4SBrooks Davis                          datetime::delta(0, 150000), items, 4));
242*b0d29bc4SBrooks Davis 
243*b0d29bc4SBrooks Davis     // Cancel the first timer to reprogram next activation.
244*b0d29bc4SBrooks Davis     timers[1]->unprogram(); delete timers[1]; timers.erase(timers.begin() + 1);
245*b0d29bc4SBrooks Davis 
246*b0d29bc4SBrooks Davis     // Cancel another timer without reprogramming next activation.
247*b0d29bc4SBrooks Davis     timers[2]->unprogram(); delete timers[2]; timers.erase(timers.begin() + 2);
248*b0d29bc4SBrooks Davis 
249*b0d29bc4SBrooks Davis     wait_timers(timers);
250*b0d29bc4SBrooks Davis 
251*b0d29bc4SBrooks Davis     std::vector< int > exp_items;
252*b0d29bc4SBrooks Davis     exp_items.push_back(1);
253*b0d29bc4SBrooks Davis     exp_items.push_back(3);
254*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exp_items, items);
255*b0d29bc4SBrooks Davis }
256*b0d29bc4SBrooks Davis 
257*b0d29bc4SBrooks Davis 
258*b0d29bc4SBrooks Davis ATF_TEST_CASE(multiprogram_and_expire_before_activations);
ATF_TEST_CASE_HEAD(multiprogram_and_expire_before_activations)259*b0d29bc4SBrooks Davis ATF_TEST_CASE_HEAD(multiprogram_and_expire_before_activations)
260*b0d29bc4SBrooks Davis {
261*b0d29bc4SBrooks Davis     set_md_var("timeout", "20");
262*b0d29bc4SBrooks Davis }
ATF_TEST_CASE_BODY(multiprogram_and_expire_before_activations)263*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(multiprogram_and_expire_before_activations)
264*b0d29bc4SBrooks Davis {
265*b0d29bc4SBrooks Davis     std::vector< signals::timer* > timers;
266*b0d29bc4SBrooks Davis     std::vector< int > items;
267*b0d29bc4SBrooks Davis 
268*b0d29bc4SBrooks Davis     {
269*b0d29bc4SBrooks Davis         signals::interrupts_inhibiter inhibiter;
270*b0d29bc4SBrooks Davis 
271*b0d29bc4SBrooks Davis         // First timer with an activation in the future.
272*b0d29bc4SBrooks Davis         timers.push_back(new delayed_inserter(
273*b0d29bc4SBrooks Davis                              datetime::delta(0, 100000), items, 1));
274*b0d29bc4SBrooks Davis         ATF_REQUIRE(!timers[timers.size() - 1]->fired());
275*b0d29bc4SBrooks Davis 
276*b0d29bc4SBrooks Davis         // Timer with an activation earlier than the previous one.
277*b0d29bc4SBrooks Davis         timers.push_back(new delayed_inserter(
278*b0d29bc4SBrooks Davis                              datetime::delta(0, 50000), items, 2));
279*b0d29bc4SBrooks Davis         ATF_REQUIRE(!timers[timers.size() - 1]->fired());
280*b0d29bc4SBrooks Davis 
281*b0d29bc4SBrooks Davis         ::sleep(1);
282*b0d29bc4SBrooks Davis 
283*b0d29bc4SBrooks Davis         // Timer with an activation later than all others.
284*b0d29bc4SBrooks Davis         timers.push_back(new delayed_inserter(
285*b0d29bc4SBrooks Davis                              datetime::delta(0, 200000), items, 3));
286*b0d29bc4SBrooks Davis 
287*b0d29bc4SBrooks Davis         ::sleep(1);
288*b0d29bc4SBrooks Davis     }
289*b0d29bc4SBrooks Davis 
290*b0d29bc4SBrooks Davis     wait_timers(timers);
291*b0d29bc4SBrooks Davis 
292*b0d29bc4SBrooks Davis     std::vector< int > exp_items;
293*b0d29bc4SBrooks Davis     exp_items.push_back(2);
294*b0d29bc4SBrooks Davis     exp_items.push_back(1);
295*b0d29bc4SBrooks Davis     exp_items.push_back(3);
296*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exp_items, items);
297*b0d29bc4SBrooks Davis }
298*b0d29bc4SBrooks Davis 
299*b0d29bc4SBrooks Davis 
300*b0d29bc4SBrooks Davis ATF_TEST_CASE(expire_before_firing);
ATF_TEST_CASE_HEAD(expire_before_firing)301*b0d29bc4SBrooks Davis ATF_TEST_CASE_HEAD(expire_before_firing)
302*b0d29bc4SBrooks Davis {
303*b0d29bc4SBrooks Davis     set_md_var("timeout", "20");
304*b0d29bc4SBrooks Davis }
ATF_TEST_CASE_BODY(expire_before_firing)305*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(expire_before_firing)
306*b0d29bc4SBrooks Davis {
307*b0d29bc4SBrooks Davis     std::vector< int > items;
308*b0d29bc4SBrooks Davis 
309*b0d29bc4SBrooks Davis     // The code below causes a signal to go pending.  Make sure we ignore it
310*b0d29bc4SBrooks Davis     // when we unblock signals.
311*b0d29bc4SBrooks Davis     signals::programmer sigalrm(SIGALRM, null_handler);
312*b0d29bc4SBrooks Davis 
313*b0d29bc4SBrooks Davis     {
314*b0d29bc4SBrooks Davis         signals::interrupts_inhibiter inhibiter;
315*b0d29bc4SBrooks Davis 
316*b0d29bc4SBrooks Davis         delayed_inserter* timer = new delayed_inserter(
317*b0d29bc4SBrooks Davis             datetime::delta(0, 1000), items, 1234);
318*b0d29bc4SBrooks Davis         ::sleep(1);
319*b0d29bc4SBrooks Davis         // Interrupts are inhibited so we never got a chance to execute the
320*b0d29bc4SBrooks Davis         // timer before it was destroyed.  However, the handler should run
321*b0d29bc4SBrooks Davis         // regardless at some point, possibly during deletion.
322*b0d29bc4SBrooks Davis         timer->unprogram();
323*b0d29bc4SBrooks Davis         delete timer;
324*b0d29bc4SBrooks Davis     }
325*b0d29bc4SBrooks Davis 
326*b0d29bc4SBrooks Davis     std::vector< int > exp_items;
327*b0d29bc4SBrooks Davis     exp_items.push_back(1234);
328*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exp_items, items);
329*b0d29bc4SBrooks Davis }
330*b0d29bc4SBrooks Davis 
331*b0d29bc4SBrooks Davis 
332*b0d29bc4SBrooks Davis ATF_TEST_CASE(reprogram_from_scratch);
ATF_TEST_CASE_HEAD(reprogram_from_scratch)333*b0d29bc4SBrooks Davis ATF_TEST_CASE_HEAD(reprogram_from_scratch)
334*b0d29bc4SBrooks Davis {
335*b0d29bc4SBrooks Davis     set_md_var("timeout", "20");
336*b0d29bc4SBrooks Davis }
ATF_TEST_CASE_BODY(reprogram_from_scratch)337*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(reprogram_from_scratch)
338*b0d29bc4SBrooks Davis {
339*b0d29bc4SBrooks Davis     std::vector< int > items;
340*b0d29bc4SBrooks Davis 
341*b0d29bc4SBrooks Davis     delayed_inserter* timer1 = new delayed_inserter(
342*b0d29bc4SBrooks Davis         datetime::delta(0, 100000), items, 1);
343*b0d29bc4SBrooks Davis     timer1->unprogram(); delete timer1;
344*b0d29bc4SBrooks Davis 
345*b0d29bc4SBrooks Davis     // All constructed timers are now dead, so the interval timer should have
346*b0d29bc4SBrooks Davis     // been reprogrammed.  Let's start over.
347*b0d29bc4SBrooks Davis 
348*b0d29bc4SBrooks Davis     delayed_inserter* timer2 = new delayed_inserter(
349*b0d29bc4SBrooks Davis         datetime::delta(0, 200000), items, 2);
350*b0d29bc4SBrooks Davis     while (!timer2->fired())
351*b0d29bc4SBrooks Davis         ::usleep(1000);
352*b0d29bc4SBrooks Davis     timer2->unprogram(); delete timer2;
353*b0d29bc4SBrooks Davis 
354*b0d29bc4SBrooks Davis     std::vector< int > exp_items;
355*b0d29bc4SBrooks Davis     exp_items.push_back(2);
356*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exp_items, items);
357*b0d29bc4SBrooks Davis }
358*b0d29bc4SBrooks Davis 
359*b0d29bc4SBrooks Davis 
360*b0d29bc4SBrooks Davis ATF_TEST_CASE(unprogram);
ATF_TEST_CASE_HEAD(unprogram)361*b0d29bc4SBrooks Davis ATF_TEST_CASE_HEAD(unprogram)
362*b0d29bc4SBrooks Davis {
363*b0d29bc4SBrooks Davis     set_md_var("timeout", "10");
364*b0d29bc4SBrooks Davis }
ATF_TEST_CASE_BODY(unprogram)365*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(unprogram)
366*b0d29bc4SBrooks Davis {
367*b0d29bc4SBrooks Davis     signals::timer timer(datetime::delta(0, 500000));
368*b0d29bc4SBrooks Davis     timer.unprogram();
369*b0d29bc4SBrooks Davis     usleep(500000);
370*b0d29bc4SBrooks Davis     ATF_REQUIRE(!timer.fired());
371*b0d29bc4SBrooks Davis }
372*b0d29bc4SBrooks Davis 
373*b0d29bc4SBrooks Davis 
374*b0d29bc4SBrooks Davis ATF_TEST_CASE(infinitesimal);
ATF_TEST_CASE_HEAD(infinitesimal)375*b0d29bc4SBrooks Davis ATF_TEST_CASE_HEAD(infinitesimal)
376*b0d29bc4SBrooks Davis {
377*b0d29bc4SBrooks Davis     set_md_var("descr", "Ensure that the ordering in which the signal, the "
378*b0d29bc4SBrooks Davis                "timer and the global state are programmed is correct; do so "
379*b0d29bc4SBrooks Davis                "by setting an extremely small delay for the timer hoping that "
380*b0d29bc4SBrooks Davis                "it can trigger such conditions");
381*b0d29bc4SBrooks Davis     set_md_var("timeout", "10");
382*b0d29bc4SBrooks Davis }
ATF_TEST_CASE_BODY(infinitesimal)383*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(infinitesimal)
384*b0d29bc4SBrooks Davis {
385*b0d29bc4SBrooks Davis     const std::size_t rounds = 100;
386*b0d29bc4SBrooks Davis     const std::size_t exp_good = 90;
387*b0d29bc4SBrooks Davis 
388*b0d29bc4SBrooks Davis     std::size_t good = 0;
389*b0d29bc4SBrooks Davis     for (std::size_t i = 0; i < rounds; i++) {
390*b0d29bc4SBrooks Davis         signals::timer timer(datetime::delta(0, 1));
391*b0d29bc4SBrooks Davis 
392*b0d29bc4SBrooks Davis         // From the setitimer(2) documentation:
393*b0d29bc4SBrooks Davis         //
394*b0d29bc4SBrooks Davis         //     Time values smaller than the resolution of the system clock are
395*b0d29bc4SBrooks Davis         //     rounded up to this resolution (typically 10 milliseconds).
396*b0d29bc4SBrooks Davis         //
397*b0d29bc4SBrooks Davis         // We don't know what this resolution is but we must wait for longer
398*b0d29bc4SBrooks Davis         // than we programmed; do a rough guess and hope it is good.  This may
399*b0d29bc4SBrooks Davis         // be obviously wrong and thus lead to mysterious test failures in some
400*b0d29bc4SBrooks Davis         // systems, hence why we only expect a percentage of successes below.
401*b0d29bc4SBrooks Davis         // Still, we can fail...
402*b0d29bc4SBrooks Davis         ::usleep(1000);
403*b0d29bc4SBrooks Davis 
404*b0d29bc4SBrooks Davis         if (timer.fired())
405*b0d29bc4SBrooks Davis             ++good;
406*b0d29bc4SBrooks Davis         timer.unprogram();
407*b0d29bc4SBrooks Davis     }
408*b0d29bc4SBrooks Davis     std::cout << F("Ran %s tests, %s passed; threshold is %s\n")
409*b0d29bc4SBrooks Davis         % rounds % good % exp_good;
410*b0d29bc4SBrooks Davis     ATF_REQUIRE(good >= exp_good);
411*b0d29bc4SBrooks Davis }
412*b0d29bc4SBrooks Davis 
413*b0d29bc4SBrooks Davis 
ATF_INIT_TEST_CASES(tcs)414*b0d29bc4SBrooks Davis ATF_INIT_TEST_CASES(tcs)
415*b0d29bc4SBrooks Davis {
416*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, program_seconds);
417*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, program_useconds);
418*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, multiprogram_ordered);
419*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, multiprogram_reorder_next_activations);
420*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, multiprogram_and_cancel_some);
421*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, multiprogram_and_expire_before_activations);
422*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, expire_before_firing);
423*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, reprogram_from_scratch);
424*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, unprogram);
425*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, infinitesimal);
426*b0d29bc4SBrooks Davis }
427