view libinterp/corefcn/sighandlers.cc @ 20939:b17fda023ca6

maint: Use new C++ archetype in more files. Place input validation first in files. Move declaration of retval down in function to be closer to point of usage. Eliminate else clause after if () error. Use "return ovl()" where it makes sense. * find.cc, gammainc.cc, gcd.cc, getgrent.cc, getpwent.cc, givens.cc, graphics.cc, help.cc, hess.cc, hex2num.cc, input.cc, kron.cc, load-path.cc, load-save.cc, lookup.cc, mappers.cc, matrix_type.cc, mgorth.cc, nproc.cc, ordschur.cc, pager.cc, pinv.cc, pr-output.cc, profiler.cc, psi.cc, quad.cc, rcond.cc, regexp.cc, schur.cc, sighandlers.cc, sparse.cc, str2double.cc, strfind.cc, strfns.cc, sub2ind.cc, svd.cc, sylvester.cc, symtab.cc, syscalls.cc, sysdep.cc, time.cc, toplev.cc, tril.cc, tsearch.cc, typecast.cc, urlwrite.cc, utils.cc, variables.cc, __delaunayn__.cc, __eigs__.cc, __glpk__.cc, __magick_read__.cc, __osmesa_print__.cc, __voronoi__.cc, amd.cc, audiodevinfo.cc, audioread.cc, chol.cc, colamd.cc, dmperm.cc, fftw.cc, qr.cc, symbfact.cc, symrcm.cc, ov-bool-mat.cc, ov-cell.cc, ov-class.cc, ov-classdef.cc, ov-fcn-handle.cc, ov-fcn-inline.cc, ov-flt-re-mat.cc, ov-java.cc, ov-null-mat.cc, ov-oncleanup.cc, ov-re-mat.cc, ov-struct.cc, ov-typeinfo.cc, ov-usr-fcn.cc, ov.cc, octave.cc: Use new C++ archetype in more files.
author Rik <rik@octave.org>
date Fri, 18 Dec 2015 15:37:22 -0800
parents 1142cf6abc0d
children 9d9270e2f98f
line wrap: on
line source

/*

Copyright (C) 1993-2015 John W. Eaton

This file is part of Octave.

Octave is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.

Octave is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with Octave; see the file COPYING.  If not, see
<http://www.gnu.org/licenses/>.

*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <cstdlib>

#include <iostream>
#include <new>

#include <sys/types.h>
#include <unistd.h>

#include "cmd-edit.h"
#include "oct-syscalls.h"
#include "quit.h"
#include "singleton-cleanup.h"

#include "debug.h"
#include "defun.h"
#include "error.h"
#include "input.h"
#include "load-save.h"
#include "oct-map.h"
#include "pager.h"
#include "pt-bp.h"
#include "pt-eval.h"
#include "sighandlers.h"
#include "sysdep.h"
#include "syswait.h"
#include "toplev.h"
#include "utils.h"
#include "variables.h"

// Nonzero means we have already printed a message for this series of
// SIGPIPES.  We assume that the writer will eventually give up.
int pipe_handler_error_count = 0;

// TRUE means we can be interrupted.
bool can_interrupt = false;

// TRUE means we should try to enter the debugger on SIGINT.
bool Vdebug_on_interrupt = false;

// Allow users to avoid writing octave-workspace for SIGHUP (sent by
// closing gnome-terminal, for example).  Note that this variable has
// no effect if Vcrash_dumps_octave_core is FALSE.
static bool Vsighup_dumps_octave_core = true;

// Similar to Vsighup_dumps_octave_core, but for SIGTERM signal.
static bool Vsigterm_dumps_octave_core = true;

// List of signals we have caught since last call to octave_signal_handler.
static bool octave_signals_caught[NSIG];

// Forward declaration.
static void user_abort (const char *sig_name, int sig_number);

#if defined (__WIN32__) && ! defined (__CYGWIN__)

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

class
w32_interrupt_manager
{
public:
  ~w32_interrupt_manager (void)
  {
    if (thread)
      CloseHandle (thread);
  }

  static bool init (void) { return instance_ok (); }

  static void octave_jump_to_enclosing_context (void)
  {
    if (instance_ok ())
      instance->do_octave_jump_to_enclosing_context ();
  }

  static void user_abort (const char *sig_name, int sig_number)
  {
    if (instance_ok ())
      instance->do_user_abort (sig_name, sig_number);
  }

  static void raise_sigint (void)
  {
    if (instance_ok ())
      instance->do_raise_sigint ();
  }

private:
  w32_interrupt_manager (void)
    : thread (0), thread_id (0)
  {
    thread_id = GetCurrentThreadId ();

    DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
                     GetCurrentProcess (), &thread, 0, FALSE,
                     DUPLICATE_SAME_ACCESS);
  }

  static void octave_jump_to_enclosing_context_sync (void)
  {
#ifdef _MSC_VER
    _fpreset ();
#endif
    ::octave_jump_to_enclosing_context ();
  }

  void do_octave_jump_to_enclosing_context (void)
  {
    bool is_interrupt_thread = (GetCurrentThreadId () == thread_id);

    if (is_interrupt_thread)
      octave_jump_to_enclosing_context_sync ();
    else
      {
        // 64-bit Windows does not appear to have threadContext.Eip.
        // Something else must be done here to allow interrupts to
        // properly work across threads.

#if ! (defined (__MINGW64__) || defined (_WIN64))

        CONTEXT threadContext;

        SuspendThread (thread);
        threadContext.ContextFlags = CONTEXT_CONTROL;
        GetThreadContext (thread, &threadContext);
        threadContext.Eip = (DWORD) octave_jump_to_enclosing_context_sync;
        SetThreadContext (thread, &threadContext);
        ResumeThread (thread);
#endif
      }
  }

  void do_user_abort (const char *sig_name, int sig_number)
  {
    bool is_interrupt_thread = (GetCurrentThreadId () == thread_id);

    if (is_interrupt_thread)
      ::user_abort (sig_name, sig_number);
    else
      {
        SuspendThread (thread);
        ::user_abort (sig_name, sig_number);
        ResumeThread (thread);
      }
  }

  void do_raise_sigint (void)
  {
    bool is_interrupt_thread = (GetCurrentThreadId () == thread_id);

    if (is_interrupt_thread)
      ::raise (SIGINT);
    else
      {
        SuspendThread (thread);
        ::raise (SIGINT);
        ResumeThread (thread);
      }
  }

  static bool instance_ok (void)
  {
    bool retval = true;

    if (! instance)
      {
        instance = new w32_interrupt_manager ();

        if (instance)
          singleton_cleanup_list::add (cleanup_instance);
      }

    if (! instance)
      {
        error ("unable to create w32_interrupt_manager");

        retval = false;
      }

    return retval;
  }

  static void cleanup_instance (void) { delete instance; instance = 0; }

private:
  // A handle to the thread that is running the octave interpreter.
  HANDLE thread;

  // The ID of the thread that is running the octave interpreter.
  DWORD thread_id;

  static w32_interrupt_manager* instance;
};

w32_interrupt_manager* w32_interrupt_manager::instance = 0;

void w32_raise_sigint (void)
{
  w32_interrupt_manager::raise_sigint ();
}

#endif

// Signal handler return type.
#ifndef BADSIG
#define BADSIG (void (*)(int))-1
#endif

// The following is a workaround for an apparent bug in GCC 4.1.2 and
// possibly earlier versions.  See Octave bug report #30685 for details.
#if defined (__GNUC__)
# if ! (__GNUC__ > 4 \
        || (__GNUC__ == 4 && (__GNUC_MINOR__ > 1 \
                              || (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ > 2))))
#  undef GNULIB_NAMESPACE
#  define GNULIB_NAMESPACE
#  warning "disabling GNULIB_NAMESPACE for signal functions -- consider upgrading to a current version of GCC"
# endif
#endif

#define BLOCK_SIGNAL(sig, nvar, ovar) \
  do \
    { \
      GNULIB_NAMESPACE::sigemptyset (&nvar); \
      GNULIB_NAMESPACE::sigaddset (&nvar, sig); \
      GNULIB_NAMESPACE::sigemptyset (&ovar); \
      GNULIB_NAMESPACE::sigprocmask (SIG_BLOCK, &nvar, &ovar); \
    } \
  while (0)

#if ! defined (SIGCHLD) && defined (SIGCLD)
#define SIGCHLD SIGCLD
#endif

#define BLOCK_CHILD(nvar, ovar) BLOCK_SIGNAL (SIGCHLD, nvar, ovar)
#define UNBLOCK_CHILD(ovar) GNULIB_NAMESPACE::sigprocmask (SIG_SETMASK, &ovar, 0)

// Called from octave_quit () to actually do something about the signals
// we have caught.

void
octave_signal_handler (void)
{
  // The list of signals is relatively short, so we will just go
  // linearly through the list.

  for (int i = 0; i < NSIG; i++)
    {
      if (octave_signals_caught[i])
        {
          octave_signals_caught[i] = false;

          switch (i)
            {
#ifdef SIGCHLD
            case SIGCHLD:
              {
                volatile octave_interrupt_handler saved_interrupt_handler
                  = octave_ignore_interrupts ();

                sigset_t set, oset;

                BLOCK_CHILD (set, oset);

                octave_child_list::wait ();

                octave_set_interrupt_handler (saved_interrupt_handler);

                UNBLOCK_CHILD (oset);

                octave_child_list::reap ();
              }
              break;
#endif

            case SIGFPE:
              std::cerr << "warning: floating point exception" << std::endl;
              break;

#ifdef SIGPIPE
            case SIGPIPE:
              std::cerr << "warning: broken pipe" << std::endl;
              break;
#endif
            }
        }
    }
}

static void
my_friendly_exit (const char *sig_name, int sig_number,
                  bool save_vars = true)
{
  static bool been_there_done_that = false;

  if (been_there_done_that)
    {
#if defined (SIGABRT)
      octave_set_signal_handler (SIGABRT, SIG_DFL);
#endif

      std::cerr << "panic: attempted clean up apparently failed -- aborting...\n";

      MINGW_SIGNAL_CLEANUP ();

      abort ();
    }
  else
    {
      been_there_done_that = true;

      std::cerr << "panic: " << sig_name << " -- stopping myself...\n";

      if (save_vars)
        dump_octave_core ();

      if (sig_number < 0)
        {
          MINGW_SIGNAL_CLEANUP ();

          exit (1);
        }
      else
        {
          octave_set_signal_handler (sig_number, SIG_DFL);

          GNULIB_NAMESPACE::raise (sig_number);
        }
    }
}

sig_handler *
octave_set_signal_handler (int sig, sig_handler *handler,
                           bool restart_syscalls)
{
  struct sigaction act, oact;

  act.sa_handler = handler;
  act.sa_flags = 0;

#if defined (SIGALRM)
  if (sig == SIGALRM)
    {
#if defined (SA_INTERRUPT)
      act.sa_flags |= SA_INTERRUPT;
#endif
    }
#endif
#if defined (SA_RESTART)
#if defined (SIGALRM)
  else
#endif
  // FIXME: Do we also need to explicitly disable SA_RESTART?
  if (restart_syscalls)
    act.sa_flags |= SA_RESTART;
#endif

  GNULIB_NAMESPACE::sigemptyset (&act.sa_mask);
  GNULIB_NAMESPACE::sigemptyset (&oact.sa_mask);

  GNULIB_NAMESPACE::sigaction (sig, &act, &oact);

  return oact.sa_handler;
}

static void
generic_sig_handler (int sig)
{
  my_friendly_exit (strsignal (sig), sig);
}

// Handle SIGCHLD.

#ifdef SIGCHLD
static void
sigchld_handler (int /* sig */)
{
  octave_signal_caught = 1;

  octave_signals_caught[SIGCHLD] = true;
}
#endif /* defined (SIGCHLD) */

#ifdef SIGFPE
#if defined (__alpha__)
static void
sigfpe_handler (int /* sig */)
{
  if (can_interrupt && octave_interrupt_state >= 0)
    {
      octave_signal_caught = 1;

      octave_signals_caught[SIGFPE] = true;

      octave_interrupt_state++;
    }
}
#endif /* defined (__alpha__) */
#endif /* defined (SIGFPE) */

#if defined (SIGHUP) || defined (SIGTERM)
static void
sig_hup_or_term_handler (int sig)
{
  switch (sig)
    {
#if defined (SIGHUP)
    case SIGHUP:
      {
        if (Vsighup_dumps_octave_core)
          dump_octave_core ();
      }
      break;
#endif

#if defined (SIGTERM)
    case SIGTERM:
      {
        if (Vsigterm_dumps_octave_core)
          dump_octave_core ();
      }
      break;
#endif

    default:
      break;
    }

  clean_up_and_exit (0);
}
#endif

#if 0
#if defined (SIGWINCH)
static void
sigwinch_handler (int /* sig */)
{
  command_editor::resize_terminal ();
}
#endif
#endif

// Handle SIGINT by restarting the parser (see octave.cc).
//
// This also has to work for SIGBREAK (on systems that have it), so we
// use the value of sig, instead of just assuming that it is called
// for SIGINT only.

static void
user_abort (const char *sig_name, int sig_number)
{
  if (! octave_initialized)
    exit (1);

  if (can_interrupt)
    {
      if (Vdebug_on_interrupt)
        {
          if (! octave_debug_on_interrupt_state)
            {
              tree_evaluator::debug_mode = true;
              octave_debug_on_interrupt_state = true;

              return;
            }
          else
            {
              // Clear the flag and do normal interrupt stuff.

              tree_evaluator::debug_mode
                = bp_table::have_breakpoints () || Vdebugging;
              octave_debug_on_interrupt_state = false;
            }
        }

      if (octave_interrupt_immediately)
        {
          if (octave_interrupt_state == 0)
            octave_interrupt_state = 1;

#if defined (__WIN32__) && ! defined (__CYGWIN__)
          w32_interrupt_manager::octave_jump_to_enclosing_context ();
#else
          octave_jump_to_enclosing_context ();
#endif
        }
      else
        {
          // If we are already cleaning up from a previous interrupt,
          // take note of the fact that another interrupt signal has
          // arrived.

          if (octave_interrupt_state < 0)
            octave_interrupt_state = 0;

          octave_signal_caught = 1;
          octave_interrupt_state++;

          if (interactive && ! forced_interactive
              && octave_interrupt_state == 2)
            std::cerr << "Press Control-C again to abort." << std::endl;

          if (octave_interrupt_state >= 3)
            my_friendly_exit (sig_name, sig_number, true);
        }
    }

}

static void
sigint_handler (int sig)
{
#if defined (__WIN32__) && ! defined (__CYGWIN__)
  w32_interrupt_manager::user_abort (strsignal (sig), sig);
#else
  user_abort (strsignal (sig), sig);
#endif
}

#ifdef SIGPIPE
static void
sigpipe_handler (int /* sig */)
{
  octave_signal_caught = 1;

  octave_signals_caught[SIGPIPE] = true;

  // Don't loop forever on account of this.

  if (pipe_handler_error_count++ > 100 && octave_interrupt_state >= 0)
    octave_interrupt_state++;
}
#endif /* defined (SIGPIPE) */

octave_interrupt_handler
octave_catch_interrupts (void)
{
  octave_interrupt_handler retval;

#if defined (__WIN32__) && ! defined (__CYGWIN__)
  w32_interrupt_manager::init ();
#endif

#ifdef SIGINT
  retval.int_handler = octave_set_signal_handler (SIGINT, sigint_handler);
#endif

#ifdef SIGBREAK
  retval.brk_handler = octave_set_signal_handler (SIGBREAK, sigint_handler);
#endif

  return retval;
}

octave_interrupt_handler
octave_ignore_interrupts (void)
{
  octave_interrupt_handler retval;

#if defined (__WIN32__) && ! defined (__CYGWIN__)
  w32_interrupt_manager::init ();
#endif

#ifdef SIGINT
  retval.int_handler = octave_set_signal_handler (SIGINT, SIG_IGN);
#endif

#ifdef SIGBREAK
  retval.brk_handler = octave_set_signal_handler (SIGBREAK, SIG_IGN);
#endif

  return retval;
}

octave_interrupt_handler
octave_set_interrupt_handler (const volatile octave_interrupt_handler& h,
                              bool restart_syscalls)
{
  octave_interrupt_handler retval;

#if defined (__WIN32__) && ! defined (__CYGWIN__)
  w32_interrupt_manager::init ();
#endif

#ifdef SIGINT
  retval.int_handler = octave_set_signal_handler (SIGINT, h.int_handler,
                                                  restart_syscalls);
#endif

#ifdef SIGBREAK
  retval.brk_handler = octave_set_signal_handler (SIGBREAK, h.brk_handler,
                                                  restart_syscalls);
#endif

  return retval;
}

// Install all the handlers for the signals we might care about.

void
install_signal_handlers (void)
{
  for (int i = 0; i < NSIG; i++)
    octave_signals_caught[i] = false;

  octave_catch_interrupts ();

#ifdef SIGABRT
  octave_set_signal_handler (SIGABRT, generic_sig_handler);
#endif

#ifdef SIGALRM
  octave_set_signal_handler (SIGALRM, generic_sig_handler);
#endif

#ifdef SIGBUS
  octave_set_signal_handler (SIGBUS, generic_sig_handler);
#endif

#ifdef SIGCHLD
  octave_set_signal_handler (SIGCHLD, sigchld_handler);
#endif

  // SIGCLD
  // SIGCONT

#ifdef SIGEMT
  octave_set_signal_handler (SIGEMT, generic_sig_handler);
#endif

#ifdef SIGFPE
#if defined (__alpha__)
  octave_set_signal_handler (SIGFPE, sigfpe_handler);
#else
  octave_set_signal_handler (SIGFPE, generic_sig_handler);
#endif
#endif

#ifdef SIGHUP
  octave_set_signal_handler (SIGHUP, sig_hup_or_term_handler);
#endif

#ifdef SIGILL
  octave_set_signal_handler (SIGILL, generic_sig_handler);
#endif

  // SIGINFO
  // SIGINT

#ifdef SIGIOT
  octave_set_signal_handler (SIGIOT, generic_sig_handler);
#endif

#ifdef SIGLOST
  octave_set_signal_handler (SIGLOST, generic_sig_handler);
#endif

#ifdef SIGPIPE
  octave_set_signal_handler (SIGPIPE, sigpipe_handler);
#endif

#ifdef SIGPOLL
  octave_set_signal_handler (SIGPOLL, SIG_IGN);
#endif

  // SIGPROF
  // SIGPWR

#ifdef SIGQUIT
  octave_set_signal_handler (SIGQUIT, generic_sig_handler);
#endif

#ifdef SIGSEGV
  octave_set_signal_handler (SIGSEGV, generic_sig_handler);
#endif

  // SIGSTOP

#ifdef SIGSYS
  octave_set_signal_handler (SIGSYS, generic_sig_handler);
#endif

#ifdef SIGTERM
  octave_set_signal_handler (SIGTERM, sig_hup_or_term_handler);
#endif

#ifdef SIGTRAP
  octave_set_signal_handler (SIGTRAP, generic_sig_handler);
#endif

  // SIGTSTP
  // SIGTTIN
  // SIGTTOU
  // SIGURG

#ifdef SIGUSR1
  octave_set_signal_handler (SIGUSR1, generic_sig_handler);
#endif

#ifdef SIGUSR2
  octave_set_signal_handler (SIGUSR2, generic_sig_handler);
#endif

#ifdef SIGVTALRM
  octave_set_signal_handler (SIGVTALRM, generic_sig_handler);
#endif

#ifdef SIGIO
  octave_set_signal_handler (SIGIO, SIG_IGN);
#endif

#if 0
#ifdef SIGWINCH
  octave_set_signal_handler (SIGWINCH, sigwinch_handler);
#endif
#endif

#ifdef SIGXCPU
  octave_set_signal_handler (SIGXCPU, generic_sig_handler);
#endif

#ifdef SIGXFSZ
  octave_set_signal_handler (SIGXFSZ, generic_sig_handler);
#endif

}

static octave_scalar_map
make_sig_struct (void)
{
  octave_scalar_map m;

#ifdef SIGABRT
  m.assign ("ABRT", SIGABRT);
#endif

#ifdef SIGALRM
  m.assign ("ALRM", SIGALRM);
#endif

#ifdef SIGBUS
  m.assign ("BUS", SIGBUS);
#endif

#ifdef SIGCHLD
  m.assign ("CHLD", SIGCHLD);
#endif

#ifdef SIGCLD
  m.assign ("CLD", SIGCLD);
#endif

#ifdef SIGCONT
  m.assign ("CONT", SIGCONT);
#endif

#ifdef SIGEMT
  m.assign ("EMT", SIGEMT);
#endif

#ifdef SIGFPE
  m.assign ("FPE", SIGFPE);
#endif

#ifdef SIGHUP
  m.assign ("HUP", SIGHUP);
#endif

#ifdef SIGILL
  m.assign ("ILL", SIGILL);
#endif

#ifdef SIGINFO
  m.assign ("INFO", SIGINFO);
#endif

#ifdef SIGINT
  m.assign ("INT", SIGINT);
#endif

#ifdef SIGIO
  m.assign ("IO", SIGIO);
#endif

#ifdef SIGIOT
  m.assign ("IOT", SIGIOT);
#endif

#ifdef SIGKILL
  m.assign ("KILL", SIGKILL);
#endif

#ifdef SIGLOST
  m.assign ("LOST", SIGLOST);
#endif

#ifdef SIGPIPE
  m.assign ("PIPE", SIGPIPE);
#endif

#ifdef SIGPOLL
  m.assign ("POLL", SIGPOLL);
#endif

#ifdef SIGPROF
  m.assign ("PROF", SIGPROF);
#endif

#ifdef SIGPWR
  m.assign ("PWR", SIGPWR);
#endif

#ifdef SIGQUIT
  m.assign ("QUIT", SIGQUIT);
#endif

#ifdef SIGSEGV
  m.assign ("SEGV", SIGSEGV);
#endif

#ifdef SIGSTKFLT
  m.assign ("STKFLT", SIGSTKFLT);
#endif

#ifdef SIGSTOP
  m.assign ("STOP", SIGSTOP);
#endif

#ifdef SIGSYS
  m.assign ("SYS", SIGSYS);
#endif

#ifdef SIGTERM
  m.assign ("TERM", SIGTERM);
#endif

#ifdef SIGTRAP
  m.assign ("TRAP", SIGTRAP);
#endif

#ifdef SIGTSTP
  m.assign ("TSTP", SIGTSTP);
#endif

#ifdef SIGTTIN
  m.assign ("TTIN", SIGTTIN);
#endif

#ifdef SIGTTOU
  m.assign ("TTOU", SIGTTOU);
#endif

#ifdef SIGUNUSED
  m.assign ("UNUSED", SIGUNUSED);
#endif

#ifdef SIGURG
  m.assign ("URG", SIGURG);
#endif

#ifdef SIGUSR1
  m.assign ("USR1", SIGUSR1);
#endif

#ifdef SIGUSR2
  m.assign ("USR2", SIGUSR2);
#endif

#ifdef SIGVTALRM
  m.assign ("VTALRM", SIGVTALRM);
#endif

#ifdef SIGWINCH
  m.assign ("WINCH", SIGWINCH);
#endif

#ifdef SIGXCPU
  m.assign ("XCPU", SIGXCPU);
#endif

#ifdef SIGXFSZ
  m.assign ("XFSZ", SIGXFSZ);
#endif

  return m;
}

octave_child_list::octave_child_list_rep *octave_child_list::instance = 0;

bool
octave_child_list::instance_ok (void)
{
  bool retval = true;

  if (! instance)
    {
      instance = new octave_child_list_rep ();

      if (instance)
        singleton_cleanup_list::add (cleanup_instance);
    }

  if (! instance)
    {
      error ("unable to create child list object!");

      retval = false;
    }

  return retval;
}

void
octave_child_list::insert (pid_t pid, octave_child::child_event_handler f)
{
  if (instance_ok ())
    instance->insert (pid, f);
}

void
octave_child_list::reap (void)
{
  if (instance_ok ())
    instance->reap ();
}

bool
octave_child_list::wait (void)
{
  return (instance_ok ()) ? instance->wait () : false;
}

class pid_equal
{
public:

  pid_equal (pid_t v) : val (v) { }

  bool operator () (const octave_child& oc) const { return oc.pid == val; }

private:

  pid_t val;
};

void
octave_child_list::remove (pid_t pid)
{
  if (instance_ok ())
    instance->remove_if (pid_equal (pid));
}

#define OCL_REP octave_child_list::octave_child_list_rep

void
OCL_REP::insert (pid_t pid, octave_child::child_event_handler f)
{
  append (octave_child (pid, f));
}

void
OCL_REP::reap (void)
{
  // Mark the record for PID invalid.

  for (iterator p = begin (); p != end (); p++)
    {
      // The call to the octave_child::child_event_handler might
      // invalidate the iterator (for example, by calling
      // octave_child_list::remove), so we increment the iterator
      // here.

      octave_child& oc = *p;

      if (oc.have_status)
        {
          oc.have_status = 0;

          octave_child::child_event_handler f = oc.handler;

          if (f && f (oc.pid, oc.status))
            oc.pid = -1;
        }
    }

  remove_if (pid_equal (-1));
}

// Wait on our children and record any changes in their status.

bool
OCL_REP::wait (void)
{
  bool retval = false;

  for (iterator p = begin (); p != end (); p++)
    {
      octave_child& oc = *p;

      pid_t pid = oc.pid;

      if (pid > 0)
        {
          int status;

          if (octave_syscalls::waitpid (pid, &status, WNOHANG) > 0)
            {
              oc.have_status = 1;

              oc.status = status;

              retval = true;

              break;
            }
        }
    }

  return retval;
}

DEFUN (SIG, args, ,
       "-*- texinfo -*-\n\
@deftypefn {} {} SIG ()\n\
Return a structure containing Unix signal names and their defined values.\n\
@end deftypefn")
{
  if (args.length () != 0)
    print_usage ();

  static octave_scalar_map m = make_sig_struct ();

  return ovl (m);
}

/*
%!assert (isstruct (SIG ()))
%!assert (! isempty (SIG ()))

%!error SIG (1)
*/

DEFUN (debug_on_interrupt, args, nargout,
       "-*- texinfo -*-\n\
@deftypefn  {} {@var{val} =} debug_on_interrupt ()\n\
@deftypefnx {} {@var{old_val} =} debug_on_interrupt (@var{new_val})\n\
@deftypefnx {} {} debug_on_interrupt (@var{new_val}, \"local\")\n\
Query or set the internal variable that controls whether Octave will try\n\
to enter debugging mode when it receives an interrupt signal (typically\n\
generated with @kbd{C-c}).\n\
\n\
If a second interrupt signal is received before reaching the debugging mode,\n\
a normal interrupt will occur.\n\
\n\
When called from inside a function with the @qcode{\"local\"} option, the\n\
variable is changed locally for the function and any subroutines it calls.\n\
The original variable value is restored when exiting the function.\n\
@seealso{debug_on_error, debug_on_warning}\n\
@end deftypefn")
{
  return SET_INTERNAL_VARIABLE (debug_on_interrupt);
}

/*
%!test
%! orig_val = debug_on_interrupt ();
%! old_val = debug_on_interrupt (! orig_val);
%! assert (orig_val, old_val);
%! assert (debug_on_interrupt (), ! orig_val);
%! debug_on_interrupt (orig_val);
%! assert (debug_on_interrupt (), orig_val);

%!error (debug_on_interrupt (1, 2))
*/

DEFUN (sighup_dumps_octave_core, args, nargout,
       "-*- texinfo -*-\n\
@deftypefn  {} {@var{val} =} sighup_dumps_octave_core ()\n\
@deftypefnx {} {@var{old_val} =} sighup_dumps_octave_core (@var{new_val})\n\
@deftypefnx {} {} sighup_dumps_octave_core (@var{new_val}, \"local\")\n\
Query or set the internal variable that controls whether Octave tries\n\
to save all current variables to the file @file{octave-workspace} if it\n\
receives a hangup signal.\n\
\n\
When called from inside a function with the @qcode{\"local\"} option, the\n\
variable is changed locally for the function and any subroutines it calls.\n\
The original variable value is restored when exiting the function.\n\
@end deftypefn")
{
  return SET_INTERNAL_VARIABLE (sighup_dumps_octave_core);
}

/*
%!test
%! orig_val = sighup_dumps_octave_core ();
%! old_val = sighup_dumps_octave_core (! orig_val);
%! assert (orig_val, old_val);
%! assert (sighup_dumps_octave_core (), ! orig_val);
%! sighup_dumps_octave_core (orig_val);
%! assert (sighup_dumps_octave_core (), orig_val);

%!error (sighup_dumps_octave_core (1, 2))
*/

DEFUN (sigterm_dumps_octave_core, args, nargout,
       "-*- texinfo -*-\n\
@deftypefn  {} {@var{val} =} sigterm_dumps_octave_core ()\n\
@deftypefnx {} {@var{old_val} =} sigterm_dumps_octave_core (@var{new_val})\n\
@deftypefnx {} {} sigterm_dumps_octave_core (@var{new_val}, \"local\")\n\
Query or set the internal variable that controls whether Octave tries\n\
to save all current variables to the file @file{octave-workspace} if it\n\
receives a terminate signal.\n\
\n\
When called from inside a function with the @qcode{\"local\"} option, the\n\
variable is changed locally for the function and any subroutines it calls.\n\
The original variable value is restored when exiting the function.\n\
@end deftypefn")
{
  return SET_INTERNAL_VARIABLE (sigterm_dumps_octave_core);
}

/*
%!test
%! orig_val = sigterm_dumps_octave_core ();
%! old_val = sigterm_dumps_octave_core (! orig_val);
%! assert (orig_val, old_val);
%! assert (sigterm_dumps_octave_core (), ! orig_val);
%! sigterm_dumps_octave_core (orig_val);
%! assert (sigterm_dumps_octave_core (), orig_val);

%!error (sigterm_dumps_octave_core (1, 2))
*/