1 1.1 jmmv // 2 1.1 jmmv // Automated Testing Framework (atf) 3 1.1 jmmv // 4 1.1 jmmv // Copyright (c) 2010 The NetBSD Foundation, Inc. 5 1.1 jmmv // All rights reserved. 6 1.1 jmmv // 7 1.1 jmmv // Redistribution and use in source and binary forms, with or without 8 1.1 jmmv // modification, are permitted provided that the following conditions 9 1.1 jmmv // are met: 10 1.1 jmmv // 1. Redistributions of source code must retain the above copyright 11 1.1 jmmv // notice, this list of conditions and the following disclaimer. 12 1.1 jmmv // 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jmmv // notice, this list of conditions and the following disclaimer in the 14 1.1 jmmv // documentation and/or other materials provided with the distribution. 15 1.1 jmmv // 16 1.1 jmmv // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17 1.1 jmmv // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 1.1 jmmv // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 1.1 jmmv // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 1.1 jmmv // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21 1.1 jmmv // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 1.1 jmmv // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23 1.1 jmmv // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 1.1 jmmv // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 1.1 jmmv // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 1.1 jmmv // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 1.1 jmmv // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 jmmv // 29 1.1 jmmv 30 1.1 jmmv extern "C" { 31 1.1 jmmv #include <sys/time.h> 32 1.1 jmmv } 33 1.1 jmmv 34 1.1 jmmv #include <cassert> 35 1.1 jmmv #include <cerrno> 36 1.1 jmmv #include <csignal> 37 1.1 jmmv #include <ctime> 38 1.1 jmmv 39 1.1 jmmv #include "exceptions.hpp" 40 1.1 jmmv #include "signals.hpp" 41 1.1 jmmv #include "timers.hpp" 42 1.1 jmmv 43 1.1 jmmv namespace impl = tools::timers; 44 1.1 jmmv #define IMPL_NAME "tools::timers" 45 1.1 jmmv 46 1.1 jmmv // ------------------------------------------------------------------------ 47 1.1 jmmv // Auxiliary functions. 48 1.1 jmmv // ------------------------------------------------------------------------ 49 1.1 jmmv 50 1.1 jmmv static 51 1.1 jmmv void 52 1.2 jmmv handler(const int signo __attribute__((__unused__)), siginfo_t* si, 53 1.2 jmmv void* uc __attribute__((__unused__))) 54 1.1 jmmv { 55 1.1 jmmv impl::timer* timer = static_cast< impl::timer* >(si->si_value.sival_ptr); 56 1.1 jmmv timer->set_fired(); 57 1.1 jmmv timer->timeout_callback(); 58 1.1 jmmv } 59 1.1 jmmv 60 1.1 jmmv // ------------------------------------------------------------------------ 61 1.1 jmmv // The "timer" class. 62 1.1 jmmv // ------------------------------------------------------------------------ 63 1.1 jmmv 64 1.1 jmmv struct impl::timer::impl { 65 1.1 jmmv ::timer_t m_timer; 66 1.1 jmmv ::itimerspec m_old_it; 67 1.1 jmmv 68 1.1 jmmv struct ::sigaction m_old_sa; 69 1.1 jmmv volatile bool m_fired; 70 1.1 jmmv 71 1.1 jmmv impl(void) : m_fired(false) 72 1.1 jmmv { 73 1.1 jmmv } 74 1.1 jmmv }; 75 1.1 jmmv 76 1.1 jmmv impl::timer::timer(const unsigned int seconds) : 77 1.1 jmmv m_pimpl(new impl()) 78 1.1 jmmv { 79 1.1 jmmv struct ::sigaction sa; 80 1.1 jmmv sigemptyset(&sa.sa_mask); 81 1.1 jmmv sa.sa_flags = SA_SIGINFO; 82 1.1 jmmv sa.sa_sigaction = ::handler; 83 1.1 jmmv if (::sigaction(SIGALRM, &sa, &m_pimpl->m_old_sa) == -1) 84 1.1 jmmv throw tools::system_error(IMPL_NAME "::timer::timer", 85 1.1 jmmv "Failed to set signal handler", errno); 86 1.1 jmmv 87 1.1 jmmv struct ::sigevent se; 88 1.1 jmmv se.sigev_notify = SIGEV_SIGNAL; 89 1.1 jmmv se.sigev_signo = SIGALRM; 90 1.1 jmmv se.sigev_value.sival_ptr = static_cast< void* >(this); 91 1.1 jmmv se.sigev_notify_function = NULL; 92 1.1 jmmv se.sigev_notify_attributes = NULL; 93 1.1 jmmv if (::timer_create(CLOCK_MONOTONIC, &se, &m_pimpl->m_timer) == -1) { 94 1.1 jmmv ::sigaction(SIGALRM, &m_pimpl->m_old_sa, NULL); 95 1.1 jmmv throw tools::system_error(IMPL_NAME "::timer::timer", 96 1.1 jmmv "Failed to create timer", errno); 97 1.1 jmmv } 98 1.1 jmmv 99 1.1 jmmv struct ::itimerspec it; 100 1.1 jmmv it.it_interval.tv_sec = 0; 101 1.1 jmmv it.it_interval.tv_nsec = 0; 102 1.1 jmmv it.it_value.tv_sec = seconds; 103 1.1 jmmv it.it_value.tv_nsec = 0; 104 1.1 jmmv if (::timer_settime(m_pimpl->m_timer, 0, &it, &m_pimpl->m_old_it) == -1) { 105 1.1 jmmv ::sigaction(SIGALRM, &m_pimpl->m_old_sa, NULL); 106 1.1 jmmv ::timer_delete(m_pimpl->m_timer); 107 1.1 jmmv throw tools::system_error(IMPL_NAME "::timer::timer", 108 1.1 jmmv "Failed to program timer", errno); 109 1.1 jmmv } 110 1.1 jmmv } 111 1.1 jmmv 112 1.1 jmmv impl::timer::~timer(void) 113 1.1 jmmv { 114 1.3 jmmv int ret; 115 1.3 jmmv 116 1.3 jmmv ret = ::timer_delete(m_pimpl->m_timer); 117 1.1 jmmv assert(ret != -1); 118 1.1 jmmv 119 1.3 jmmv ret = ::sigaction(SIGALRM, &m_pimpl->m_old_sa, NULL); 120 1.3 jmmv assert(ret != -1); 121 1.1 jmmv } 122 1.1 jmmv 123 1.1 jmmv bool 124 1.1 jmmv impl::timer::fired(void) 125 1.1 jmmv const 126 1.1 jmmv { 127 1.1 jmmv return m_pimpl->m_fired; 128 1.1 jmmv } 129 1.1 jmmv 130 1.1 jmmv void 131 1.1 jmmv impl::timer::set_fired(void) 132 1.1 jmmv { 133 1.1 jmmv m_pimpl->m_fired = true; 134 1.1 jmmv } 135 1.1 jmmv 136 1.1 jmmv // ------------------------------------------------------------------------ 137 1.1 jmmv // The "child_timer" class. 138 1.1 jmmv // ------------------------------------------------------------------------ 139 1.1 jmmv 140 1.1 jmmv impl::child_timer::child_timer(const unsigned int seconds, const pid_t pid, 141 1.1 jmmv volatile bool& terminate) : 142 1.1 jmmv timer(seconds), 143 1.1 jmmv m_pid(pid), 144 1.1 jmmv m_terminate(terminate) 145 1.1 jmmv { 146 1.1 jmmv } 147 1.1 jmmv 148 1.1 jmmv impl::child_timer::~child_timer(void) 149 1.1 jmmv { 150 1.1 jmmv } 151 1.1 jmmv 152 1.1 jmmv void 153 1.1 jmmv impl::child_timer::timeout_callback(void) 154 1.1 jmmv { 155 1.1 jmmv static const timespec ts = { 1, 0 }; 156 1.1 jmmv m_terminate = true; 157 1.1 jmmv ::kill(-m_pid, SIGTERM); 158 1.1 jmmv ::nanosleep(&ts, NULL); 159 1.1 jmmv if (::kill(-m_pid, 0) != -1) 160 1.1 jmmv ::kill(-m_pid, SIGKILL); 161 1.1 jmmv } 162