Home | History | Annotate | Line # | Download | only in tools
      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