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