changeset 5142:0f9108f298ab

[project @ 2005-02-12 02:29:34 by jwe]
author jwe
date Sat, 12 Feb 2005 02:29:35 +0000
parents f51d2e9681f4
children d6e99e773993
files libcruft/ChangeLog libcruft/misc/cquit.c libcruft/misc/quit.cc libcruft/misc/quit.h src/ChangeLog src/DLD-FUNCTIONS/gplot.l src/Makefile.in src/TEMPLATE-INST/Array-oc.cc src/base-list.h src/input.cc src/pager.cc src/sighandlers.cc src/sighandlers.h src/toplev.cc
diffstat 14 files changed, 342 insertions(+), 247 deletions(-) [+]
line wrap: on
line diff
--- a/libcruft/ChangeLog	Thu Feb 10 18:37:55 2005 +0000
+++ b/libcruft/ChangeLog	Sat Feb 12 02:29:35 2005 +0000
@@ -1,3 +1,13 @@
+2005-02-10  John W. Eaton  <jwe@octave.org>
+
+	* misc/cquit.c (octave_signal_caught): New global variable.
+	* misc/quit.cc (occtave_handle_signal): New function.
+	(octave_signal_hook): New global pointer.
+	* misc/quit.h: Provide decls.
+	(OCTAVE_QUIT): Check octave_signal_caught, not
+	octave_interrupt_state, and call octave_handle_signal, not
+	octave_throw_interrupt_exception.
+	
 2005-02-08  John W. Eaton  <jwe@octave.org>
 
 	* misc/quit.h: Use C-style comments.
--- a/libcruft/misc/cquit.c	Thu Feb 10 18:37:55 2005 +0000
+++ b/libcruft/misc/cquit.c	Sat Feb 12 02:29:35 2005 +0000
@@ -87,6 +87,8 @@
 
 sig_atomic_t octave_allocation_error = 0;
 
+sig_atomic_t octave_signal_caught = 0;
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/libcruft/misc/quit.cc	Thu Feb 10 18:37:55 2005 +0000
+++ b/libcruft/misc/quit.cc	Sat Feb 12 02:29:35 2005 +0000
@@ -26,14 +26,29 @@
 
 #include <cstring>
 
+#include <iostream>
 #include <new>
 
 #include "quit.h"
 
+void (*octave_signal_hook) (void) = 0;
 void (*octave_interrupt_hook) (void) = 0;
 void (*octave_bad_alloc_hook) (void) = 0;
 
 void
+octave_handle_signal (void)
+{
+  if (octave_signal_hook)
+    octave_signal_hook ();
+
+  if (octave_interrupt_state > 0)
+    {
+      octave_interrupt_state = -1;
+      octave_throw_interrupt_exception ();
+    }
+}
+
+void
 octave_throw_interrupt_exception (void)
 {
   if (octave_interrupt_hook)
--- a/libcruft/misc/quit.h	Thu Feb 10 18:37:55 2005 +0000
+++ b/libcruft/misc/quit.h	Sat Feb 12 02:29:35 2005 +0000
@@ -77,6 +77,10 @@
 
 extern sig_atomic_t octave_allocation_error;
 
+extern sig_atomic_t octave_signal_caught;
+
+extern void octave_handle_signal (void);
+
 extern void octave_throw_interrupt_exception (void) GCC_ATTR_NORETURN;
 
 extern void octave_throw_bad_alloc (void) GCC_ATTR_NORETURN;
@@ -84,10 +88,10 @@
 #define OCTAVE_QUIT \
   do \
     { \
-      if (octave_interrupt_state > 0) \
+      if (octave_signal_caught) \
         { \
-          octave_interrupt_state = -1; \
-          octave_throw_interrupt_exception (); \
+          octave_signal_caught = 0; \
+          octave_handle_signal (); \
         } \
     } \
   while (0)
@@ -169,6 +173,7 @@
 /* These should only be declared for C++ code, and should also be
    outside of any extern "C" block.  */
 
+extern void (*octave_signal_hook) (void);
 extern void (*octave_interrupt_hook) (void);
 extern void (*octave_bad_alloc_hook) (void);
 
--- a/src/ChangeLog	Thu Feb 10 18:37:55 2005 +0000
+++ b/src/ChangeLog	Sat Feb 12 02:29:35 2005 +0000
@@ -1,3 +1,60 @@
+2005-02-11  John W. Eaton  <jwe@octave.org>
+
+	* sighandlers.cc (sigpipe_handler): Don't try to take action.
+	Set octave_signal_caught and octave_signals_caught here.
+	(sigchld_handler): Call octave_child_list::wait here.
+	Set octave_signal_caught and octave_signals_caught here.
+	(octave_signals_caught): New static file-scope variable.
+	(sigint_handler): Also set octave_signal_caught.
+
+	* sighandlers.cc (sigpipe_handler): 
+
+	* DLD-FUNCTIONS/gplot.l (plot_stream_event_handler): Rename from
+	plot_stream_death_handler.  Return true if plotter has exited.
+	Call close_plot_stream with false arg.
+	(plot_stream_pid): Delete static file-scope variable and all uses.
+	(close_plot_stream): New arg, remove_from_child_list, with default
+	value of true.  Only call octave_child_list::remove if
+	remove_from_child_list is true.
+
+	* pager.cc (octave_pager_pid, saved_interrupt_handler,
+	interrupt_handler_saved): Delete static file-scope variables and
+	all uses.
+	(clear_external_pager): Do nothing if external_pager is 0.
+	(pager_event_handler): Rename from pager_death_handler.
+	Improve warning message.  Return true if pager has exited.
+	(octave_pager_buf::do_sync): Check errno == EPIPE after write.
+	(flush_octave_stdout): No need to check external_pager before
+	calling clear_external_pager.
+
+	* toplev.cc (recover_from_exception): Set octave_signal_caught to zero.
+	(main_loop): Set octave_signal_hook to octave_signal_handler here.
+
+	* sighandlers.cc (octave_signal_handler): New function.
+	* sighanlders.h: Provide decl.
+
+	* sighandlers.cc (install_signal_handlers): Initialize
+	octave_signals_caught.
+
+	* sighandlers.h (octave_child::status, have_status): New data members.
+	(child_event_handler): Rename from dead_child_handler.
+	Change all uses.
+	(octave_child_list::reap, octave_child_list::wait): New functions.
+	(octave_child_list::length, octave_child_list::do_length,
+	octave_child_list::elem, octave_child_list::do_elem,
+	octave_child_list::list, octave_child_list::curr_len): Delete.
+
+	* sighandlers.h, sighandlers.cc
+	(octave_child_list::octave_child_list_rep): New class.
+
+	* src/input.cc (gnu_readline, octave_gets, get_user_input):
+	Call OCTAVE_QUIT before doing anything.
+
+	* base-list.h (octave_base_list<T>::remove_if): New function.
+
+	* TEMPLATE-INST/Array-oc.cc: Delete.
+	* Makefile.in (TI_XSRC): Remove from list.
+
 2005-02-10  Driss Ghaddab  <driss.ghaddab@free.fr>
 
 	* cutils.c (octave_usleep) [HAVE_POLL]: Fix typo.
--- a/src/DLD-FUNCTIONS/gplot.l	Thu Feb 10 18:37:55 2005 +0000
+++ b/src/DLD-FUNCTIONS/gplot.l	Sat Feb 12 02:29:35 2005 +0000
@@ -257,9 +257,6 @@
 // Pipe to gnuplot.
 static oprocstream *plot_stream = 0;
 
-// ID of the plotter process.
-static pid_t plot_stream_pid = 0;
-
 // Gnuplot command strings that we use.
 static std::string Vgnuplot_command_plot;
 static std::string Vgnuplot_command_replot;
@@ -309,13 +306,15 @@
 }
 
 static void
-close_plot_stream (void)
+close_plot_stream (bool remove_from_child_list = true)
 {
-  octave_child_list::remove (plot_stream_pid);
-
   if (plot_stream)
     {
+      if (remove_from_child_list)
+	octave_child_list::remove (plot_stream->pid ());
+
       send_to_plot_stream ("\nquit\n");
+
       delete plot_stream;
       plot_stream = 0;
     }
@@ -323,13 +322,28 @@
   plot_line_count = 0;
 }
 
-static void
-plot_stream_death_handler (pid_t pid, int)
+static bool
+plot_stream_event_handler (pid_t pid, int status)
 {
-  close_plot_stream ();
+  bool retval = false;
+
+  if (pid > 0)
+    {
+      if (WIFEXITED (status) || WIFSIGNALLED (status))
+	{
+	  close_plot_stream (false);
 
-  warning ("connection to external plotter (pid = %d) lost --", pid);
-  warning ("please try your plot command(s) again");
+	  warning ("connection to external plotter (pid = %d) lost --", pid);
+	  warning ("please try your plot command(s) again");
+
+	  // Request removal of this PID from the list of child
+	  // processes.
+
+	  retval = true;
+	}
+    }
+
+  return retval;
 }
 
 static void
@@ -381,11 +395,8 @@
 	      error ("plot: unable to open pipe to `%s'", plot_prog.c_str ());
 	    }
 	  else
-	    {
-	      plot_stream_pid = plot_stream->pid ();
-    	      octave_child_list::insert (plot_stream_pid,
-					 plot_stream_death_handler);
-	    }
+    	    octave_child_list::insert (plot_stream->pid (),
+				       plot_stream_event_handler);
 	}
       else
 	error ("plot: unable to open pipe to `%s'", plot_prog.c_str ());
--- a/src/Makefile.in	Thu Feb 10 18:37:55 2005 +0000
+++ b/src/Makefile.in	Sat Feb 12 02:29:35 2005 +0000
@@ -97,7 +97,7 @@
 	symtab.h sysdep.h token.h toplev.h unwind-prot.h utils.h \
 	variables.h version.h xdiv.h xpow.h $(OV_INCLUDES) $(PT_INCLUDES)
 
-TI_XSRC := Array-oc.cc Array-os.cc Array-sym.cc Array-tc.cc
+TI_XSRC := Array-os.cc Array-sym.cc Array-tc.cc
 
 TI_SRC := $(addprefix TEMPLATE-INST/, $(TI_XSRC))
 
--- a/src/TEMPLATE-INST/Array-oc.cc	Thu Feb 10 18:37:55 2005 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*
-
-Copyright (C) 1996, 1997 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 2, 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, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-
-*/
-
-// Instantiate Arrays of octave_child objects.
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "Array.h"
-#include "Array.cc"
-
-#include "sighandlers.h"
-
-INSTANTIATE_ARRAY (octave_child);
-
-/*
-;;; Local Variables: ***
-;;; mode: C++ ***
-;;; End: ***
-*/
--- a/src/base-list.h	Thu Feb 10 18:37:55 2005 +0000
+++ b/src/base-list.h	Sat Feb 12 02:29:35 2005 +0000
@@ -40,6 +40,9 @@
 
   iterator erase (iterator pos) { return lst.erase (pos); }
 
+  template <class P>
+  void remove_if (P pred) { lst.remove_if (pred); }
+
   void clear (void) { lst.clear (); }
 
   void append (const elt_type& s) { lst.push_back (s); }
--- a/src/input.cc	Thu Feb 10 18:37:55 2005 +0000
+++ b/src/input.cc	Sat Feb 12 02:29:35 2005 +0000
@@ -165,6 +165,8 @@
 std::string
 gnu_readline (const std::string& s, bool force_readline)
 {
+  OCTAVE_QUIT;
+
   std::string retval;
 
   if (line_editing || force_readline)
@@ -204,6 +206,8 @@
 static std::string
 octave_gets (void)
 {
+  OCTAVE_QUIT;
+
   std::string retval;
 
   Vlast_prompt_time.stamp ();
@@ -254,6 +258,8 @@
 static std::string
 get_user_input (void)
 {
+  OCTAVE_QUIT;
+
   std::string retval;
 
   if (get_input_from_eval_string)
--- a/src/pager.cc	Thu Feb 10 18:37:55 2005 +0000
+++ b/src/pager.cc	Sat Feb 12 02:29:35 2005 +0000
@@ -44,8 +44,6 @@
 #include "utils.h"
 #include "variables.h"
 
-static pid_t octave_pager_pid = -1;
-
 // Our actual connection to the external pager.
 static oprocstream *external_pager = 0;
 
@@ -70,11 +68,6 @@
 // through the pager.
 static bool Vpage_screen_output;
 
-// Only one pager can be active at once, so having these at file
-// scope should be ok.
-static octave_interrupt_handler saved_interrupt_handler;
-static bool interrupt_handler_saved = false;
-
 static bool really_flush_to_pager = false;
 
 static bool flushing_output_to_pager = false;
@@ -82,35 +75,40 @@
 static void
 clear_external_pager (void)
 {
-  octave_child_list::remove (octave_pager_pid);
-
-  octave_pager_pid = -1;
+  if (external_pager)
+    {
+      octave_child_list::remove (external_pager->pid ());
 
-  delete external_pager;
-  external_pager = 0;
-
-  if (interrupt_handler_saved)
-    {
-      octave_set_interrupt_handler (saved_interrupt_handler);
-      interrupt_handler_saved = false;
+      delete external_pager;
+      external_pager = 0;
     }
 }
 
-static void
-pager_death_handler (pid_t pid, int status)
+static bool
+pager_event_handler (pid_t pid, int status)
 {
+  bool retval = false;
+
   if (pid > 0)
     {
       if (WIFEXITED (status) || WIFSIGNALLED (status))
 	{
-	  // Avoid warning() or error(), since that will put us back in
-	  // the pager, which would be bad news.
+	  // Avoid warning() since that will put us back in the pager,
+	  // which would be bad news.
 
-	  std::cerr << "warning: connection to external pager (pid = "
-	       << pid << ") lost --\n"
-	       << "warning: attempting to finish pending computations...\n";
+	  std::cerr << "warning: connection to external pager lost (pid = "
+		    << pid << ")" << std::endl;
+	  std::cerr << "warning: flushing pending output (please wait)"
+		    << std::endl;
+
+	  // Request removal of this PID from the list of child
+	  // processes.
+
+	  retval = true;
 	}
     }
+
+  return retval;
 }
 
 static void
@@ -131,47 +129,33 @@
 
 	      if (! pgr.empty ())
 		{
-		  saved_interrupt_handler = octave_ignore_interrupts ();
-		  interrupt_handler_saved = true;
-
 		  external_pager = new oprocstream (pgr.c_str ());
 
 		  if (external_pager)
-		    {
-		      octave_pager_pid = external_pager->pid ();
-
-		      octave_child_list::insert (octave_pager_pid,
-						 pager_death_handler);
-		    }
+		    octave_child_list::insert (external_pager->pid (),
+					       pager_event_handler);
 		}
 	    }
 
 	  if (external_pager)
 	    {
-	      if (octave_pager_pid > 0 && external_pager->good ())
+	      if (external_pager->good ())
 		{
 		  external_pager->write (msg, len);
 
-		  // These checks are needed if a signal handler
-		  // invoked since the last set of checks attempts
-		  // to flush output and then returns
+		  external_pager->flush ();
 
-		  if (octave_pager_pid > 0
-		      && external_pager
-		      && external_pager->good ())
-		    external_pager->flush ();
+#if defined (EPIPE)
+		  if (errno == EPIPE)
+		    external_pager->setstate (std::ios::failbit);
+#endif
 		}
 	      else
 		{
-		  // We had a pager, but it must have died.  Restore
-		  // the interrupt state so we can escape back to the
-		  // prompt if there are lots of computations pending.
-
-		  if (interrupt_handler_saved)
-		    {
-		      octave_set_interrupt_handler (saved_interrupt_handler);
-		      interrupt_handler_saved = false;
-		    }
+		  // XXX FIXME XXX -- omething is not right with the
+		  // pager.  If it died then we should receive a
+		  // signal for that.  If there is some other problem,
+		  // then what?
 		}
 	    }
 	  else
@@ -361,8 +345,7 @@
 
       octave_stdout.flush ();
 
-      if (external_pager)
-	clear_external_pager ();
+      clear_external_pager ();
 
       unwind_protect::run_frame ("flush_octave_stdout");
     }
--- a/src/sighandlers.cc	Thu Feb 10 18:37:55 2005 +0000
+++ b/src/sighandlers.cc	Sat Feb 12 02:29:35 2005 +0000
@@ -93,6 +93,42 @@
   do { } while (0)
 #endif
 
+// List of signals we have caught since last call to octave_signal_handler.
+static bool octave_signals_caught[NSIG];
+
+// 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)
+	    {
+	    case SIGCHLD:
+	      octave_child_list::reap ();
+	      break;
+
+	    case SIGFPE:
+	      std::cerr << "warning: floating point exception -- trying to return to prompt" << std::endl;
+	      break;
+
+	    case SIGPIPE:
+	      std::cerr << "warning: broken pipe -- some output may be lost" << std::endl;
+	      break;
+	    }
+	}
+    }
+}
+
 static void
 my_friendly_exit (const char *sig_name, int sig_number,
 		  bool save_vars = true)
@@ -181,30 +217,13 @@
 
   BLOCK_CHILD (set, oset);
 
-  int n = octave_child_list::length ();
-
-  for (int i = 0; i < n; i++)
+  if (octave_child_list::wait ())
     {
-      octave_child& elt = octave_child_list::elem (i);
-
-      pid_t pid = elt.pid;
-
-      if (pid > 0)
-	{
-	  int status;
+      // The status of some child changed.
 
-	  if (waitpid (pid, &status, WNOHANG) > 0)
-	    {
-	      elt.pid = -1;
-
-	      octave_child::dead_child_handler f = elt.handler;
+      octave_signal_caught = 1;
 
-	      if (f)
-		f (pid, status);
-
-	      break;
-	    }
-	}
+      octave_signals_caught[SIGCHLD] = true;
     }
 
   octave_set_interrupt_handler (saved_interrupt_handler);
@@ -232,13 +251,14 @@
 
   MAYBE_REINSTALL_SIGHANDLER (SIGFPE, sigfpe_handler);
 
-  std::cerr << "error: floating point exception -- trying to return to prompt\n";
+  if (can_interrupt && octave_interrupt_state >= 0)
+    {
+      octave_signal_caught = 1;
 
-  // XXX FIXME XXX -- will setting octave_interrupt_state really help
-  // here?
+      octave_signals_caught[SIGFPE] = true;
 
-  if (can_interrupt && octave_interrupt_state >= 0)
-    octave_interrupt_state++;
+      octave_interrupt_state++;
+    }
 
   SIGHANDLER_RETURN (0);
 }
@@ -341,6 +361,7 @@
 	  if (octave_interrupt_state < 0)
 	    octave_interrupt_state = 0;
 
+	  octave_signal_caught = 1;
 	  octave_interrupt_state++;
 
 	  if (interactive && octave_interrupt_state == 2)
@@ -362,15 +383,13 @@
 
   MAYBE_REINSTALL_SIGHANDLER (SIGPIPE, sigpipe_handler);
 
-  if (pipe_handler_error_count++ == 0)
-    std::cerr << "warning: broken pipe\n";
+  octave_signal_caught = 1;
+
+  octave_signals_caught[SIGPIPE] = true;
 
   // Don't loop forever on account of this.
 
-  // XXX FIXME XXX -- will setting octave_interrupt_state really help
-  // here?
-
-  if (pipe_handler_error_count  > 100 && octave_interrupt_state >= 0)
+  if (pipe_handler_error_count++ > 100 && octave_interrupt_state >= 0)
     octave_interrupt_state++;
 
   SIGHANDLER_RETURN (0);
@@ -430,6 +449,9 @@
 void
 install_signal_handlers (void)
 {
+  for (int i = 0; i < NSIG; i++)
+    octave_signals_caught[i] = false;
+
   octave_catch_interrupts ();
 
 #ifdef SIGABRT
@@ -702,13 +724,7 @@
   return m;
 }
 
-octave_child_list *octave_child_list::instance = 0;
-
-// This needs to be here for linking on AIX, at least for some
-// versions of GCC, otherwise we fail with unresolved references to
-// the Array<octave_child> destructor.
-
-octave_child_list::~octave_child_list (void) { }
+octave_child_list::octave_child_list_rep *octave_child_list::instance = 0;
 
 bool
 octave_child_list::instance_ok (void)
@@ -716,7 +732,7 @@
   bool retval = true;
 
   if (! instance)
-    instance = new octave_child_list ();
+    instance = new octave_child_list_rep ();
 
   if (! instance)
     {
@@ -729,104 +745,112 @@
 }
 
 void
-octave_child_list::insert (pid_t pid, octave_child::dead_child_handler f)
+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->do_insert (pid, f);
+    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->do_remove (pid);
+    instance->remove_if (pid_equal (pid));
 }
 
-int
-octave_child_list::length (void)
-{
-  return (instance_ok ()) ? instance->do_length () : 0;
-}
+#define OCL_REP octave_child_list::octave_child_list_rep
 
-octave_child&
-octave_child_list::elem (int i)
+void
+OCL_REP::insert (pid_t pid, octave_child::child_event_handler f)
 {
-  static octave_child foo;
-
-  return (instance_ok ()) ? instance->do_elem (i) : foo;
+  append (octave_child (pid, f));
 }
 
 void
-octave_child_list::do_insert (pid_t pid, octave_child::dead_child_handler f)
+OCL_REP::reap (void)
 {
-  // Insert item in first open slot, increasing size of list if
-  // necessary.
+  // Mark the record for PID invalid.
 
-  bool enlarge = true;
+  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.
 
-  for (int i = 0; i < curr_len; i++)
-    {
-      octave_child& tmp = list (i);
+      octave_child& oc = *p;
 
-      if (tmp.pid < 0)
+      if (oc.have_status)
 	{
-	  list (i) = octave_child (pid, f);
-	  enlarge = false;
-	  break;
+	  oc.have_status = 0;
+
+	  octave_child::child_event_handler f = oc.handler;
+
+	  if (f && f (oc.pid, oc.status))
+	    oc.pid = -1;
 	}
     }
 
-  if (enlarge)
-    {
-      int total_len = list.length ();
-
-      if (curr_len == total_len)
-	{
-	  if (total_len == 0)
-	    list.resize (16);
-	  else
-	    list.resize (total_len * 2);
-	}
-
-      list (curr_len) = octave_child (pid, f);
-      curr_len++;
-    }
+  remove_if (pid_equal (-1));
 }
 
-void
-octave_child_list::do_remove (pid_t pid)
+// Wait on our children and record any changes in their status.
+
+bool
+OCL_REP::wait (void)
 {
-  // Mark the record for PID invalid.
+  bool retval = false;
 
-  for (int i = 0; i < curr_len; i++)
+  for (iterator p = begin (); p != end (); p++)
     {
-      octave_child& tmp = list (i);
+      octave_child& oc = *p;
+
+      pid_t pid = oc.pid;
+
+      if (pid > 0)
+	{
+	  int status;
 
-      if (tmp.pid == pid)
-	{
-	  tmp.pid = -1;
-	  break;
+	  if (waitpid (pid, &status, WNOHANG) > 0)
+	    {
+	      oc.have_status = 1;
+
+	      oc.status = status;
+
+	      retval = true;
+
+	      break;
+	    }
 	}
     }
-}
 
-int
-octave_child_list::do_length (void) const
-{
-  return curr_len;
-}
-
-octave_child&
-octave_child_list::do_elem (int i)
-{
-  static octave_child foo;
-
-  int n = do_length ();
-
-  if (i >= 0 && i < n)
-    return list (i);
-  else
-    return foo;
+  return retval;
 }
 
 static int
--- a/src/sighandlers.h	Thu Feb 10 18:37:55 2005 +0000
+++ b/src/sighandlers.h	Sat Feb 12 02:29:35 2005 +0000
@@ -41,7 +41,7 @@
 #include "syswait.h"
 #include "siglist.h"
 
-#include <Array.h>
+#include "base-list.h"
 
 // Signal handler return type.
 #ifndef RETSIGTYPE
@@ -96,6 +96,8 @@
 
 extern void install_signal_handlers (void);
 
+extern void octave_signal_handler (void);
+
 extern octave_interrupt_handler octave_catch_interrupts (void);
 
 extern octave_interrupt_handler octave_ignore_interrupts (void);
@@ -111,21 +113,30 @@
 octave_child
 {
 public:
-
-  typedef void (*dead_child_handler) (pid_t, int);
+  
+  // Do whatever to handle event for child with PID (might not
+  // actually be dead, could just be stopped).  Return true if
+  // the list element corresponding to PID should be removed from
+  // list.  This function should not call any functions that modify
+  // the octave_child_list.
 
-  octave_child (pid_t id = -1, dead_child_handler f = 0)
-    : pid (id), handler (f) { }
+  typedef bool (*child_event_handler) (pid_t, int);
+
+  octave_child (pid_t id = -1, child_event_handler f = 0)
+    : pid (id), handler (f), have_status (0), status (0) { }
 
   octave_child (const octave_child& oc)
-    : pid (oc.pid), handler (oc.handler) { }
-
+    : pid (oc.pid), handler (oc.handler),
+      have_status (oc.have_status), status (oc.status) { }
+ 
   octave_child& operator = (const octave_child& oc)
     {
       if (&oc != this)
 	{
 	  pid = oc.pid;
 	  handler = oc.handler;
+	  have_status = oc.have_status;
+	  status = oc.status;
 	}
       return *this;
     }
@@ -135,8 +146,15 @@
   // The process id of this child.
   pid_t pid;
 
-  // The function we call if this child dies.
-  dead_child_handler handler;
+  // The function we call if an event happens for this child.
+  child_event_handler handler;
+
+  // Nonzero if this child has stopped or terminated.
+  sig_atomic_t have_status;
+
+  // The status of this child; 0 if running, otherwise a status value
+  // from waitpid.
+  int status;
 };
 
 class
@@ -144,37 +162,36 @@
 {
 protected:
 
-  octave_child_list (void) : list (0), curr_len (0) { }
+  octave_child_list (void) { }
+
+  class octave_child_list_rep : public octave_base_list<octave_child>
+  {
+  public:
+
+    void insert (pid_t pid, octave_child::child_event_handler f);
+
+    void reap (void);
+
+    bool wait (void);
+  };
 
 public:
 
-  ~octave_child_list (void);
+  ~octave_child_list (void) { }
+
+  static void insert (pid_t pid, octave_child::child_event_handler f);
 
-  static bool instance_ok (void);
+  static void reap (void);
 
-  static void insert (pid_t pid, octave_child::dead_child_handler f);
+  static bool wait (void);
 
   static void remove (pid_t pid);
 
-  static int length (void);
-
-  static octave_child& elem (int i);
-
 private:
 
-  Array<octave_child> list;
-
-  int curr_len;
-
-  static octave_child_list *instance;
+  static bool instance_ok (void);
 
-  void do_insert (pid_t pid, octave_child::dead_child_handler f);
-
-  void do_remove (pid_t pid);
-
-  int do_length (void) const;
-
-  octave_child& do_elem (int i);
+  static octave_child_list_rep *instance;
 };
 
 #endif
--- a/src/toplev.cc	Thu Feb 10 18:37:55 2005 +0000
+++ b/src/toplev.cc	Sat Feb 12 02:29:35 2005 +0000
@@ -104,6 +104,7 @@
   can_interrupt = true;
   octave_interrupt_immediately = 0;
   octave_interrupt_state = 0;
+  octave_signal_caught = 0;
   octave_allocation_error = 0;
   octave_restore_signal_mask ();
   octave_catch_interrupts ();
@@ -128,6 +129,7 @@
 
   can_interrupt = true;
 
+  octave_signal_hook = octave_signal_handler;
   octave_interrupt_hook = unwind_protect::run_all;
   octave_bad_alloc_hook = unwind_protect::run_all;