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