1//
2// Automated Testing Framework (atf)
3//
4// Copyright (c) 2007 The NetBSD Foundation, Inc.
5// All rights reserved.
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions
9// are met:
10// 1. Redistributions of source code must retain the above copyright
11//    notice, this list of conditions and the following disclaimer.
12// 2. Redistributions in binary form must reproduce the above copyright
13//    notice, this list of conditions and the following disclaimer in the
14//    documentation and/or other materials provided with the distribution.
15//
16// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28//
29
30#if defined(HAVE_CONFIG_H)
31#include "bconfig.h"
32#endif
33
34extern "C" {
35#include <signal.h>
36#include <unistd.h>
37}
38
39#include <cerrno>
40
41#include "atf-c++/detail/exceptions.hpp"
42#include "atf-c++/detail/sanity.hpp"
43
44#include "signals.hpp"
45
46namespace impl = atf::atf_run;
47#define IMPL_NAME "atf::atf_run"
48
49const int impl::last_signo = LAST_SIGNO;
50
51// ------------------------------------------------------------------------
52// The "signal_holder" class.
53// ------------------------------------------------------------------------
54
55namespace {
56
57static bool happened[LAST_SIGNO + 1];
58
59static
60void
61holder_handler(const int signo)
62{
63    happened[signo] = true;
64}
65
66} // anonymous namespace
67
68impl::signal_holder::signal_holder(const int signo) :
69    m_signo(signo),
70    m_sp(NULL)
71{
72    happened[signo] = false;
73    m_sp = new signal_programmer(m_signo, holder_handler);
74}
75
76impl::signal_holder::~signal_holder(void)
77{
78    if (m_sp != NULL)
79        delete m_sp;
80
81    if (happened[m_signo])
82        ::kill(::getpid(), m_signo);
83}
84
85void
86impl::signal_holder::process(void)
87{
88    if (happened[m_signo]) {
89        delete m_sp;
90        m_sp = NULL;
91        happened[m_signo] = false;
92        ::kill(::getpid(), m_signo);
93        m_sp = new signal_programmer(m_signo, holder_handler);
94    }
95}
96
97// ------------------------------------------------------------------------
98// The "signal_programmer" class.
99// ------------------------------------------------------------------------
100
101impl::signal_programmer::signal_programmer(const int signo, const handler h) :
102    m_signo(signo),
103    m_handler(h),
104    m_programmed(false)
105{
106    struct ::sigaction sa;
107
108    sa.sa_handler = m_handler;
109    sigemptyset(&sa.sa_mask);
110    sa.sa_flags = 0;
111
112    if (::sigaction(m_signo, &sa, &m_oldsa) == -1)
113        throw atf::system_error(IMPL_NAME, "Could not install handler for "
114                                "signal", errno);
115    m_programmed = true;
116}
117
118impl::signal_programmer::~signal_programmer(void)
119{
120    unprogram();
121}
122
123void
124impl::signal_programmer::unprogram(void)
125{
126    if (m_programmed) {
127        if (::sigaction(m_signo, &m_oldsa, NULL) == -1)
128            UNREACHABLE;
129        m_programmed = false;
130    }
131}
132
133// ------------------------------------------------------------------------
134// Free functions.
135// ------------------------------------------------------------------------
136
137void
138impl::reset(const int signo)
139{
140    struct ::sigaction sa;
141
142    sa.sa_handler = SIG_DFL;
143    sigemptyset(&sa.sa_mask);
144    sa.sa_flags = 0;
145
146    (void)::sigaction(signo, &sa, NULL);
147}
148