head	1.2;
access;
symbols
	netbsd-11-0-RC7:1.2
	netbsd-11-0-RC6:1.2
	netbsd-11-0-RC5:1.2
	netbsd-11-0-RC4:1.2
	netbsd-11-0-RC3:1.2
	netbsd-11-0-RC2:1.2
	netbsd-11-0-RC1:1.2
	perseant-exfatfs-base-20250801:1.2
	netbsd-11:1.2.0.10
	netbsd-11-base:1.2
	netbsd-10-1-RELEASE:1.2
	perseant-exfatfs-base-20240630:1.2
	perseant-exfatfs:1.2.0.8
	perseant-exfatfs-base:1.2
	netbsd-8-3-RELEASE:1.1.1.1
	netbsd-9-4-RELEASE:1.1.1.1
	netbsd-10-0-RELEASE:1.2
	netbsd-10-0-RC6:1.2
	netbsd-10-0-RC5:1.2
	netbsd-10-0-RC4:1.2
	netbsd-10-0-RC3:1.2
	netbsd-10-0-RC2:1.2
	netbsd-10-0-RC1:1.2
	netbsd-10:1.2.0.6
	netbsd-10-base:1.2
	netbsd-9-3-RELEASE:1.1.1.1
	cjep_sun2x-base1:1.2
	cjep_sun2x:1.2.0.4
	cjep_sun2x-base:1.2
	cjep_staticlib_x-base1:1.2
	netbsd-9-2-RELEASE:1.1.1.1
	cjep_staticlib_x:1.2.0.2
	cjep_staticlib_x-base:1.2
	netbsd-9-1-RELEASE:1.1.1.1
	phil-wifi-20200421:1.1.1.1
	phil-wifi-20200411:1.1.1.1
	is-mlppp:1.1.1.1.0.40
	is-mlppp-base:1.1.1.1
	phil-wifi-20200406:1.1.1.1
	netbsd-8-2-RELEASE:1.1.1.1
	netbsd-9-0-RELEASE:1.1.1.1
	netbsd-9-0-RC2:1.1.1.1
	netbsd-9-0-RC1:1.1.1.1
	phil-wifi-20191119:1.1.1.1
	netbsd-9:1.1.1.1.0.38
	netbsd-9-base:1.1.1.1
	phil-wifi-20190609:1.1.1.1
	netbsd-8-1-RELEASE:1.1.1.1
	netbsd-8-1-RC1:1.1.1.1
	pgoyette-compat-merge-20190127:1.1.1.1
	pgoyette-compat-20190127:1.1.1.1
	pgoyette-compat-20190118:1.1.1.1
	pgoyette-compat-1226:1.1.1.1
	pgoyette-compat-1126:1.1.1.1
	pgoyette-compat-1020:1.1.1.1
	pgoyette-compat-0930:1.1.1.1
	pgoyette-compat-0906:1.1.1.1
	netbsd-7-2-RELEASE:1.1.1.1
	pgoyette-compat-0728:1.1.1.1
	netbsd-8-0-RELEASE:1.1.1.1
	phil-wifi:1.1.1.1.0.36
	phil-wifi-base:1.1.1.1
	pgoyette-compat-0625:1.1.1.1
	netbsd-8-0-RC2:1.1.1.1
	pgoyette-compat-0521:1.1.1.1
	pgoyette-compat-0502:1.1.1.1
	pgoyette-compat-0422:1.1.1.1
	netbsd-8-0-RC1:1.1.1.1
	pgoyette-compat-0415:1.1.1.1
	pgoyette-compat-0407:1.1.1.1
	pgoyette-compat-0330:1.1.1.1
	pgoyette-compat-0322:1.1.1.1
	pgoyette-compat-0315:1.1.1.1
	netbsd-7-1-2-RELEASE:1.1.1.1
	pgoyette-compat:1.1.1.1.0.34
	pgoyette-compat-base:1.1.1.1
	netbsd-7-1-1-RELEASE:1.1.1.1
	matt-nb8-mediatek:1.1.1.1.0.32
	matt-nb8-mediatek-base:1.1.1.1
	perseant-stdc-iso10646:1.1.1.1.0.30
	perseant-stdc-iso10646-base:1.1.1.1
	netbsd-8:1.1.1.1.0.28
	netbsd-8-base:1.1.1.1
	prg-localcount2-base3:1.1.1.1
	prg-localcount2-base2:1.1.1.1
	prg-localcount2-base1:1.1.1.1
	prg-localcount2:1.1.1.1.0.26
	prg-localcount2-base:1.1.1.1
	pgoyette-localcount-20170426:1.1.1.1
	bouyer-socketcan-base1:1.1.1.1
	pgoyette-localcount-20170320:1.1.1.1
	netbsd-7-1:1.1.1.1.0.24
	netbsd-7-1-RELEASE:1.1.1.1
	netbsd-7-1-RC2:1.1.1.1
	netbsd-7-nhusb-base-20170116:1.1.1.1
	bouyer-socketcan:1.1.1.1.0.22
	bouyer-socketcan-base:1.1.1.1
	pgoyette-localcount-20170107:1.1.1.1
	netbsd-7-1-RC1:1.1.1.1
	pgoyette-localcount-20161104:1.1.1.1
	netbsd-7-0-2-RELEASE:1.1.1.1
	localcount-20160914:1.1.1.1
	netbsd-7-nhusb:1.1.1.1.0.20
	netbsd-7-nhusb-base:1.1.1.1
	pgoyette-localcount-20160806:1.1.1.1
	pgoyette-localcount-20160726:1.1.1.1
	pgoyette-localcount:1.1.1.1.0.18
	pgoyette-localcount-base:1.1.1.1
	netbsd-7-0-1-RELEASE:1.1.1.1
	netbsd-7-0:1.1.1.1.0.16
	netbsd-7-0-RELEASE:1.1.1.1
	netbsd-7-0-RC3:1.1.1.1
	netbsd-7-0-RC2:1.1.1.1
	netbsd-7-0-RC1:1.1.1.1
	netbsd-7:1.1.1.1.0.14
	netbsd-7-base:1.1.1.1
	yamt-pagecache:1.1.1.1.0.12
	yamt-pagecache-base9:1.1.1.1
	tls-earlyentropy:1.1.1.1.0.10
	tls-earlyentropy-base:1.1.1.1
	riastradh-xf86-video-intel-2-7-1-pre-2-21-15:1.1.1.1
	riastradh-drm2-base3:1.1.1.1
	kyua-cli-0-7:1.1.1.1
	riastradh-drm2-base2:1.1.1.1
	riastradh-drm2-base1:1.1.1.1
	riastradh-drm2:1.1.1.1.0.2
	riastradh-drm2-base:1.1.1.1
	khorben-n900:1.1.1.1.0.8
	agc-symver:1.1.1.1.0.6
	agc-symver-base:1.1.1.1
	tls-maxphys-base:1.1.1.1
	tls-maxphys:1.1.1.1.0.4
	kyua-cli-0-6:1.1.1.1
	GOOGLE-CODE:1.1.1;
locks; strict;
comment	@// @;


1.2
date	2020.07.02.14.04.01;	author lukem;	state Exp;
branches;
next	1.1;
commitid	YUoDcZ95aoStLveC;

1.1
date	2013.02.23.12.34.07;	author jmmv;	state Exp;
branches
	1.1.1.1;
next	;

1.1.1.1
date	2013.02.23.12.34.07;	author jmmv;	state Exp;
branches
	1.1.1.1.4.1
	1.1.1.1.12.1;
next	;

1.1.1.1.4.1
date	2013.02.23.12.34.07;	author tls;	state dead;
branches;
next	1.1.1.1.4.2;

1.1.1.1.4.2
date	2013.02.25.00.26.18;	author tls;	state Exp;
branches;
next	;

1.1.1.1.12.1
date	2013.02.23.12.34.07;	author yamt;	state dead;
branches;
next	1.1.1.1.12.2;
commitid	h3iiOYJJCkPr7yBx;

1.1.1.1.12.2
date	2014.05.22.15.45.30;	author yamt;	state Exp;
branches;
next	;
commitid	h3iiOYJJCkPr7yBx;


desc
@@


1.2
log
@kyua-cli: convert auto_ptr to unique_ptr

Update kyua-cli to C++11 and use unique_ptr instead of auto_ptr,
(with std::move() where appropriate), to avoid deprecated warning by g++ 8.

(I didn't change some of the code that could arguably be refactored
to use unique_ptr or shared_ptr instead of raw pointers
and therefore remove the special case destructor handling).
@
text
@// Copyright 2012 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
// * Neither the name of Google Inc. nor the names of its contributors
//   may be used to endorse or promote products derived from this software
//   without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "utils/signals/interrupts.hpp"

extern "C" {
#include <signal.h>
#include <unistd.h>
}

#include <cstdlib>
#include <cstring>
#include <set>

#include "utils/sanity.hpp"
#include "utils/signals/exceptions.hpp"
#include "utils/signals/programmer.hpp"

namespace signals = utils::signals;


namespace {


/// The interrupt signal that fired, or -1 if none.
static volatile int fired_signal = -1;


/// Collection of PIDs.
typedef std::set< pid_t > pids_set;


/// List of processes to kill upon reception of a signal.
static pids_set pids_to_kill;


/// Programmer status for the SIGHUP signal.
static std::unique_ptr< signals::programmer > sighup_handler;
/// Programmer status for the SIGINT signal.
static std::unique_ptr< signals::programmer > sigint_handler;
/// Programmer status for the SIGTERM signal.
static std::unique_ptr< signals::programmer > sigterm_handler;


/// Signal mask to restore after exiting a signal inhibited section.
static sigset_t old_sigmask;


/// Whether there is an interrupts_handler object in existence or not.
bool interrupts_handler_active = false;


/// Whether there is an interrupts_inhibiter object in existence or not.
bool interrupts_inhibiter_active = false;


/// Generic handler to capture interrupt signals.
///
/// From this handler, we record that an interrupt has happened so that
/// check_interrupt() can know whether there execution has to be stopped or not.
/// We also terminate any of our child processes (started by the
/// utils::process::children class) so that any ongoing wait(2) system calls
/// terminate.
///
/// \param signo The signal that caused this handler to be called.
static void
signal_handler(const int signo)
{
    static const char* message = "[-- Signal caught; please wait for "
        "cleanup --]\n";
    if (::write(STDERR_FILENO, message, std::strlen(message)) == -1) {
        // We are exiting: the message printed here is only for informational
        // purposes.  If we fail to print it (which probably means something
        // is really bad), there is not much we can do within the signal
        // handler, so just ignore this.
    }

    fired_signal = signo;

    for (pids_set::const_iterator iter = pids_to_kill.begin();
        iter != pids_to_kill.end(); ++iter) {
        // Redirecting the interrupt signal to our child processes does NOT
        // guarantee that they also terminate.  For that to happen, we'd need to
        // SIGKILL them.
        //
        // *However*, because we use this code to invoke the kyua-testers only,
        // and because we assume that such processes are well-behaved and
        // terminate according to our expectations, we do it this way, which
        // allows the testers to know which specific signal made them terminate.
        (void)::kill(*iter, signo);
    }
}


/// Installs signal handlers for potential interrupts.
///
/// \pre Must not have been called before.
/// \post The various sig*_handler global variables are atomically updated.
static void
setup_handlers(void)
{
    PRE(sighup_handler.get() == NULL);
    PRE(sigint_handler.get() == NULL);
    PRE(sigterm_handler.get() == NULL);

    // Create the handlers on the stack first so that, if any of them fails, the
    // stack unwinding cleans things up.
    std::unique_ptr< signals::programmer > tmp_sighup_handler(
        new signals::programmer(SIGHUP, signal_handler));
    std::unique_ptr< signals::programmer > tmp_sigint_handler(
        new signals::programmer(SIGINT, signal_handler));
    std::unique_ptr< signals::programmer > tmp_sigterm_handler(
        new signals::programmer(SIGTERM, signal_handler));

    // Now, update the global pointers, which is an operation that cannot fail.
    sighup_handler = std::move(tmp_sighup_handler);
    sigint_handler = std::move(tmp_sigint_handler);
    sigterm_handler = std::move(tmp_sigterm_handler);
}


/// Uninstalls the signal handlers installed by setup_handlers().
static void
cleanup_handlers(void)
{
    sighup_handler->unprogram(); sighup_handler.reset(NULL);
    sigint_handler->unprogram(); sigint_handler.reset(NULL);
    sigterm_handler->unprogram(); sigterm_handler.reset(NULL);
}



/// Masks the signals installed by setup_handlers().
static void
mask_signals(void)
{
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGHUP);
    sigaddset(&mask, SIGINT);
    sigaddset(&mask, SIGTERM);
    const int ret = ::sigprocmask(SIG_BLOCK, &mask, &old_sigmask);
    INV(ret != -1);
}


/// Resets the signal masking put in place by mask_signals().
static void
unmask_signals(void)
{
    const int ret = ::sigprocmask(SIG_SETMASK, &old_sigmask, NULL);
    INV(ret != -1);
}


}  // anonymous namespace


/// Constructor that sets up the signal handlers.
signals::interrupts_handler::interrupts_handler(void)
{
    PRE(!interrupts_handler_active);
    setup_handlers();
    interrupts_handler_active = true;
}


/// Destructor that removes the signal handlers.
signals::interrupts_handler::~interrupts_handler(void)
{
    cleanup_handlers();
    interrupts_handler_active = false;
}


/// Constructor that sets up signal masking.
signals::interrupts_inhibiter::interrupts_inhibiter(void)
{
    PRE(!interrupts_inhibiter_active);
    mask_signals();
    interrupts_inhibiter_active = true;
}


/// Destructor that removes signal masking.
signals::interrupts_inhibiter::~interrupts_inhibiter(void)
{
    unmask_signals();
    interrupts_inhibiter_active = false;
}


/// Checks if an interrupt has fired.
///
/// Calls to this function should be sprinkled in strategic places through the
/// code protected by an interrupts_handler object.
///
/// \throw interrupted_error If there has been an interrupt.
void
signals::check_interrupt(void)
{
    if (fired_signal != -1)
        throw interrupted_error(fired_signal);
}


/// Registers a child process to be killed upon reception of an interrupt.
///
/// \pre Must be called with interrupts being inhibited.  The caller must ensure
/// that the call call to fork() and the addition of the PID happen atomically.
///
/// \param pid The PID of the child process.  Must not have been yet regsitered.
void
signals::add_pid_to_kill(const pid_t pid)
{
    PRE(interrupts_inhibiter_active);
    PRE(pids_to_kill.find(pid) == pids_to_kill.end());
    pids_to_kill.insert(pid);
}


/// Unregisters a child process previously registered via add_pid_to_kill().
///
/// \pre Must be called with interrupts being inhibited.  This is not necessary,
/// but pushing this to the caller simplifies our logic and provides consistency
/// with the add_pid_to_kill() call.
///
/// \param pid The PID of the child process.  Must have been registered
///     previously, and the process must have already been awaited for.
void
signals::remove_pid_to_kill(const pid_t pid)
{
    PRE(interrupts_inhibiter_active);
    PRE(pids_to_kill.find(pid) != pids_to_kill.end());
    pids_to_kill.erase(pid);
}
@


1.1
log
@Initial revision
@
text
@d63 1
a63 1
static std::auto_ptr< signals::programmer > sighup_handler;
d65 1
a65 1
static std::auto_ptr< signals::programmer > sigint_handler;
d67 1
a67 1
static std::auto_ptr< signals::programmer > sigterm_handler;
d133 1
a133 1
    std::auto_ptr< signals::programmer > tmp_sighup_handler(
d135 1
a135 1
    std::auto_ptr< signals::programmer > tmp_sigint_handler(
d137 1
a137 1
    std::auto_ptr< signals::programmer > tmp_sigterm_handler(
d141 3
a143 3
    sighup_handler = tmp_sighup_handler;
    sigint_handler = tmp_sigint_handler;
    sigterm_handler = tmp_sigterm_handler;
@


1.1.1.1
log
@Initial import of Kyua CLI, version 0.6:

This is the main component of Kyua and its build will be guarded by the
MKKYUA knob.  core@@ has approved this import.

Description:

Kyua (pronounced Q.A.) is a testing framework for both developers and
users.  Kyua is different from most other testing frameworks in that it
puts the end user experience before anything else.  There are multiple
reasons for users to run the tests themselves, and Kyua ensures that
they can do so in the most convenient way.

This module, kyua-cli, provides the command-line interface to the Kyua
runtime system.  The major purpose of this tool is to run test cases and
generate unified reports for their results.
@
text
@@


1.1.1.1.12.1
log
@file interrupts.cpp was added on branch yamt-pagecache on 2014-05-22 15:45:30 +0000
@
text
@d1 261
@


1.1.1.1.12.2
log
@sync with head.

for a reference, the tree before this commit was tagged
as yamt-pagecache-tag8.

this commit was splitted into small chunks to avoid
a limitation of cvs.  ("Protocol error: too many arguments")
@
text
@a0 261
// Copyright 2012 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
// * Neither the name of Google Inc. nor the names of its contributors
//   may be used to endorse or promote products derived from this software
//   without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "utils/signals/interrupts.hpp"

extern "C" {
#include <signal.h>
#include <unistd.h>
}

#include <cstdlib>
#include <cstring>
#include <set>

#include "utils/sanity.hpp"
#include "utils/signals/exceptions.hpp"
#include "utils/signals/programmer.hpp"

namespace signals = utils::signals;


namespace {


/// The interrupt signal that fired, or -1 if none.
static volatile int fired_signal = -1;


/// Collection of PIDs.
typedef std::set< pid_t > pids_set;


/// List of processes to kill upon reception of a signal.
static pids_set pids_to_kill;


/// Programmer status for the SIGHUP signal.
static std::auto_ptr< signals::programmer > sighup_handler;
/// Programmer status for the SIGINT signal.
static std::auto_ptr< signals::programmer > sigint_handler;
/// Programmer status for the SIGTERM signal.
static std::auto_ptr< signals::programmer > sigterm_handler;


/// Signal mask to restore after exiting a signal inhibited section.
static sigset_t old_sigmask;


/// Whether there is an interrupts_handler object in existence or not.
bool interrupts_handler_active = false;


/// Whether there is an interrupts_inhibiter object in existence or not.
bool interrupts_inhibiter_active = false;


/// Generic handler to capture interrupt signals.
///
/// From this handler, we record that an interrupt has happened so that
/// check_interrupt() can know whether there execution has to be stopped or not.
/// We also terminate any of our child processes (started by the
/// utils::process::children class) so that any ongoing wait(2) system calls
/// terminate.
///
/// \param signo The signal that caused this handler to be called.
static void
signal_handler(const int signo)
{
    static const char* message = "[-- Signal caught; please wait for "
        "cleanup --]\n";
    if (::write(STDERR_FILENO, message, std::strlen(message)) == -1) {
        // We are exiting: the message printed here is only for informational
        // purposes.  If we fail to print it (which probably means something
        // is really bad), there is not much we can do within the signal
        // handler, so just ignore this.
    }

    fired_signal = signo;

    for (pids_set::const_iterator iter = pids_to_kill.begin();
        iter != pids_to_kill.end(); ++iter) {
        // Redirecting the interrupt signal to our child processes does NOT
        // guarantee that they also terminate.  For that to happen, we'd need to
        // SIGKILL them.
        //
        // *However*, because we use this code to invoke the kyua-testers only,
        // and because we assume that such processes are well-behaved and
        // terminate according to our expectations, we do it this way, which
        // allows the testers to know which specific signal made them terminate.
        (void)::kill(*iter, signo);
    }
}


/// Installs signal handlers for potential interrupts.
///
/// \pre Must not have been called before.
/// \post The various sig*_handler global variables are atomically updated.
static void
setup_handlers(void)
{
    PRE(sighup_handler.get() == NULL);
    PRE(sigint_handler.get() == NULL);
    PRE(sigterm_handler.get() == NULL);

    // Create the handlers on the stack first so that, if any of them fails, the
    // stack unwinding cleans things up.
    std::auto_ptr< signals::programmer > tmp_sighup_handler(
        new signals::programmer(SIGHUP, signal_handler));
    std::auto_ptr< signals::programmer > tmp_sigint_handler(
        new signals::programmer(SIGINT, signal_handler));
    std::auto_ptr< signals::programmer > tmp_sigterm_handler(
        new signals::programmer(SIGTERM, signal_handler));

    // Now, update the global pointers, which is an operation that cannot fail.
    sighup_handler = tmp_sighup_handler;
    sigint_handler = tmp_sigint_handler;
    sigterm_handler = tmp_sigterm_handler;
}


/// Uninstalls the signal handlers installed by setup_handlers().
static void
cleanup_handlers(void)
{
    sighup_handler->unprogram(); sighup_handler.reset(NULL);
    sigint_handler->unprogram(); sigint_handler.reset(NULL);
    sigterm_handler->unprogram(); sigterm_handler.reset(NULL);
}



/// Masks the signals installed by setup_handlers().
static void
mask_signals(void)
{
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGHUP);
    sigaddset(&mask, SIGINT);
    sigaddset(&mask, SIGTERM);
    const int ret = ::sigprocmask(SIG_BLOCK, &mask, &old_sigmask);
    INV(ret != -1);
}


/// Resets the signal masking put in place by mask_signals().
static void
unmask_signals(void)
{
    const int ret = ::sigprocmask(SIG_SETMASK, &old_sigmask, NULL);
    INV(ret != -1);
}


}  // anonymous namespace


/// Constructor that sets up the signal handlers.
signals::interrupts_handler::interrupts_handler(void)
{
    PRE(!interrupts_handler_active);
    setup_handlers();
    interrupts_handler_active = true;
}


/// Destructor that removes the signal handlers.
signals::interrupts_handler::~interrupts_handler(void)
{
    cleanup_handlers();
    interrupts_handler_active = false;
}


/// Constructor that sets up signal masking.
signals::interrupts_inhibiter::interrupts_inhibiter(void)
{
    PRE(!interrupts_inhibiter_active);
    mask_signals();
    interrupts_inhibiter_active = true;
}


/// Destructor that removes signal masking.
signals::interrupts_inhibiter::~interrupts_inhibiter(void)
{
    unmask_signals();
    interrupts_inhibiter_active = false;
}


/// Checks if an interrupt has fired.
///
/// Calls to this function should be sprinkled in strategic places through the
/// code protected by an interrupts_handler object.
///
/// \throw interrupted_error If there has been an interrupt.
void
signals::check_interrupt(void)
{
    if (fired_signal != -1)
        throw interrupted_error(fired_signal);
}


/// Registers a child process to be killed upon reception of an interrupt.
///
/// \pre Must be called with interrupts being inhibited.  The caller must ensure
/// that the call call to fork() and the addition of the PID happen atomically.
///
/// \param pid The PID of the child process.  Must not have been yet regsitered.
void
signals::add_pid_to_kill(const pid_t pid)
{
    PRE(interrupts_inhibiter_active);
    PRE(pids_to_kill.find(pid) == pids_to_kill.end());
    pids_to_kill.insert(pid);
}


/// Unregisters a child process previously registered via add_pid_to_kill().
///
/// \pre Must be called with interrupts being inhibited.  This is not necessary,
/// but pushing this to the caller simplifies our logic and provides consistency
/// with the add_pid_to_kill() call.
///
/// \param pid The PID of the child process.  Must have been registered
///     previously, and the process must have already been awaited for.
void
signals::remove_pid_to_kill(const pid_t pid)
{
    PRE(interrupts_inhibiter_active);
    PRE(pids_to_kill.find(pid) != pids_to_kill.end());
    pids_to_kill.erase(pid);
}
@


1.1.1.1.4.1
log
@file interrupts.cpp was added on branch tls-maxphys on 2013-02-25 00:26:18 +0000
@
text
@d1 261
@


1.1.1.1.4.2
log
@resync with head
@
text
@a0 261
// Copyright 2012 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
// * Neither the name of Google Inc. nor the names of its contributors
//   may be used to endorse or promote products derived from this software
//   without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "utils/signals/interrupts.hpp"

extern "C" {
#include <signal.h>
#include <unistd.h>
}

#include <cstdlib>
#include <cstring>
#include <set>

#include "utils/sanity.hpp"
#include "utils/signals/exceptions.hpp"
#include "utils/signals/programmer.hpp"

namespace signals = utils::signals;


namespace {


/// The interrupt signal that fired, or -1 if none.
static volatile int fired_signal = -1;


/// Collection of PIDs.
typedef std::set< pid_t > pids_set;


/// List of processes to kill upon reception of a signal.
static pids_set pids_to_kill;


/// Programmer status for the SIGHUP signal.
static std::auto_ptr< signals::programmer > sighup_handler;
/// Programmer status for the SIGINT signal.
static std::auto_ptr< signals::programmer > sigint_handler;
/// Programmer status for the SIGTERM signal.
static std::auto_ptr< signals::programmer > sigterm_handler;


/// Signal mask to restore after exiting a signal inhibited section.
static sigset_t old_sigmask;


/// Whether there is an interrupts_handler object in existence or not.
bool interrupts_handler_active = false;


/// Whether there is an interrupts_inhibiter object in existence or not.
bool interrupts_inhibiter_active = false;


/// Generic handler to capture interrupt signals.
///
/// From this handler, we record that an interrupt has happened so that
/// check_interrupt() can know whether there execution has to be stopped or not.
/// We also terminate any of our child processes (started by the
/// utils::process::children class) so that any ongoing wait(2) system calls
/// terminate.
///
/// \param signo The signal that caused this handler to be called.
static void
signal_handler(const int signo)
{
    static const char* message = "[-- Signal caught; please wait for "
        "cleanup --]\n";
    if (::write(STDERR_FILENO, message, std::strlen(message)) == -1) {
        // We are exiting: the message printed here is only for informational
        // purposes.  If we fail to print it (which probably means something
        // is really bad), there is not much we can do within the signal
        // handler, so just ignore this.
    }

    fired_signal = signo;

    for (pids_set::const_iterator iter = pids_to_kill.begin();
        iter != pids_to_kill.end(); ++iter) {
        // Redirecting the interrupt signal to our child processes does NOT
        // guarantee that they also terminate.  For that to happen, we'd need to
        // SIGKILL them.
        //
        // *However*, because we use this code to invoke the kyua-testers only,
        // and because we assume that such processes are well-behaved and
        // terminate according to our expectations, we do it this way, which
        // allows the testers to know which specific signal made them terminate.
        (void)::kill(*iter, signo);
    }
}


/// Installs signal handlers for potential interrupts.
///
/// \pre Must not have been called before.
/// \post The various sig*_handler global variables are atomically updated.
static void
setup_handlers(void)
{
    PRE(sighup_handler.get() == NULL);
    PRE(sigint_handler.get() == NULL);
    PRE(sigterm_handler.get() == NULL);

    // Create the handlers on the stack first so that, if any of them fails, the
    // stack unwinding cleans things up.
    std::auto_ptr< signals::programmer > tmp_sighup_handler(
        new signals::programmer(SIGHUP, signal_handler));
    std::auto_ptr< signals::programmer > tmp_sigint_handler(
        new signals::programmer(SIGINT, signal_handler));
    std::auto_ptr< signals::programmer > tmp_sigterm_handler(
        new signals::programmer(SIGTERM, signal_handler));

    // Now, update the global pointers, which is an operation that cannot fail.
    sighup_handler = tmp_sighup_handler;
    sigint_handler = tmp_sigint_handler;
    sigterm_handler = tmp_sigterm_handler;
}


/// Uninstalls the signal handlers installed by setup_handlers().
static void
cleanup_handlers(void)
{
    sighup_handler->unprogram(); sighup_handler.reset(NULL);
    sigint_handler->unprogram(); sigint_handler.reset(NULL);
    sigterm_handler->unprogram(); sigterm_handler.reset(NULL);
}



/// Masks the signals installed by setup_handlers().
static void
mask_signals(void)
{
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGHUP);
    sigaddset(&mask, SIGINT);
    sigaddset(&mask, SIGTERM);
    const int ret = ::sigprocmask(SIG_BLOCK, &mask, &old_sigmask);
    INV(ret != -1);
}


/// Resets the signal masking put in place by mask_signals().
static void
unmask_signals(void)
{
    const int ret = ::sigprocmask(SIG_SETMASK, &old_sigmask, NULL);
    INV(ret != -1);
}


}  // anonymous namespace


/// Constructor that sets up the signal handlers.
signals::interrupts_handler::interrupts_handler(void)
{
    PRE(!interrupts_handler_active);
    setup_handlers();
    interrupts_handler_active = true;
}


/// Destructor that removes the signal handlers.
signals::interrupts_handler::~interrupts_handler(void)
{
    cleanup_handlers();
    interrupts_handler_active = false;
}


/// Constructor that sets up signal masking.
signals::interrupts_inhibiter::interrupts_inhibiter(void)
{
    PRE(!interrupts_inhibiter_active);
    mask_signals();
    interrupts_inhibiter_active = true;
}


/// Destructor that removes signal masking.
signals::interrupts_inhibiter::~interrupts_inhibiter(void)
{
    unmask_signals();
    interrupts_inhibiter_active = false;
}


/// Checks if an interrupt has fired.
///
/// Calls to this function should be sprinkled in strategic places through the
/// code protected by an interrupts_handler object.
///
/// \throw interrupted_error If there has been an interrupt.
void
signals::check_interrupt(void)
{
    if (fired_signal != -1)
        throw interrupted_error(fired_signal);
}


/// Registers a child process to be killed upon reception of an interrupt.
///
/// \pre Must be called with interrupts being inhibited.  The caller must ensure
/// that the call call to fork() and the addition of the PID happen atomically.
///
/// \param pid The PID of the child process.  Must not have been yet regsitered.
void
signals::add_pid_to_kill(const pid_t pid)
{
    PRE(interrupts_inhibiter_active);
    PRE(pids_to_kill.find(pid) == pids_to_kill.end());
    pids_to_kill.insert(pid);
}


/// Unregisters a child process previously registered via add_pid_to_kill().
///
/// \pre Must be called with interrupts being inhibited.  This is not necessary,
/// but pushing this to the caller simplifies our logic and provides consistency
/// with the add_pid_to_kill() call.
///
/// \param pid The PID of the child process.  Must have been registered
///     previously, and the process must have already been awaited for.
void
signals::remove_pid_to_kill(const pid_t pid)
{
    PRE(interrupts_inhibiter_active);
    PRE(pids_to_kill.find(pid) != pids_to_kill.end());
    pids_to_kill.erase(pid);
}
@


