Ok, this code should be able to handle multiple simultaneaous SIGCHLD 
signals safely and no cycles are wasted in a busy GUI loop. In fact 
things will just work automagically even if there is *no* GUI loop.

Of course, Win32 users are stuffed ;-)

-- 
Angus
? src/support/lyxlib-orig.C
? src/support/lyxlib.C
Index: src/support/forkedcontr.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/forkedcontr.C,v
retrieving revision 1.18
diff -u -p -r1.18 forkedcontr.C
--- src/support/forkedcontr.C	22 Mar 2004 14:10:20 -0000	1.18
+++ src/support/forkedcontr.C	22 Mar 2004 22:20:53 -0000
@@ -17,25 +17,22 @@
 #include "forkedcontr.h"
 #include "forkedcall.h"
 #include "lyxfunctional.h"
-#include "debug.h"
-
-#include "frontends/Timeout.h"
 
-#include <boost/bind.hpp>
+#include "debug.h"
 
 #include <cerrno>
+#include <csignal>
 #include <cstdlib>
 #include <unistd.h>
 #include <sys/wait.h>
 
 
-using boost::bind;
-
 using std::endl;
 using std::find_if;
 using std::string;
 
 #ifndef CXX_GLOBAL_CSTD
+using std::signal;
 using std::strerror;
 #endif
 
@@ -43,6 +40,40 @@ using std::strerror;
 namespace lyx {
 namespace support {
 
+namespace {
+
+extern "C"
+void child_handler(int)
+{
+	// This code is safe because SIGCHLD is not an error signal,
+	// so the main program will be in a robust state.
+
+	// Nonetheless, the asynchronous nature of the signals means that
+	// some care is needed to prevent the signal handler from being
+	// interrupted by the delivery of another signal.
+
+	// A flag to prevent us reaching the while loop
+	// if a previous signal is still being executed.
+	static bool processing_signal = false;
+	// A flag to control exit from the while loop.
+	bool process_signal = true;
+
+	if (processing_signal)
+		return;
+	processing_signal = true;
+
+	// Use a while loop to ensure that we process any signals that were
+	// received whilst we were processing a previous signal.
+	while (process_signal) {
+		process_signal = false;
+		ForkedcallsController::get().handleCompletedProcesses();
+	}
+
+	processing_signal = false;
+}
+
+} // namespace anon
+
 // Ensure, that only one controller exists inside process
 ForkedcallsController & ForkedcallsController::get()
 {
@@ -53,10 +84,7 @@ ForkedcallsController & ForkedcallsContr
 
 ForkedcallsController::ForkedcallsController()
 {
-	timeout_ = new Timeout(100, Timeout::ONETIME);
-
-	timeout_->timeout
-		.connect(bind(&ForkedcallsController::timer, this));
+	signal(SIGCHLD, child_handler);
 }
 
 
@@ -70,22 +98,18 @@ ForkedcallsController::~ForkedcallsContr
 		delete *it;
 	}
 
-	delete timeout_;
+	// Deinstall the signal handler
+	signal(SIGCHLD, SIG_DFL);
 }
 
 
 void ForkedcallsController::addCall(ForkedProcess const & newcall)
 {
-	if (!timeout_->running())
-		timeout_->start();
-
 	forkedCalls.push_back(newcall.clone().release());
 }
 
 
-// Timer-call
-// Check the list and, if there is a stopped child, emit the signal.
-void ForkedcallsController::timer()
+void ForkedcallsController::handleCompletedProcesses()
 {
 	ListType::iterator it  = forkedCalls.begin();
 	ListType::iterator end = forkedCalls.end();
@@ -147,10 +171,6 @@ void ForkedcallsController::timer()
 			++it;
 		}
 	}
-
-	if (!forkedCalls.empty() && !timeout_->running()) {
-		timeout_->start();
-	}
 }
 
 
@@ -167,10 +187,6 @@ void ForkedcallsController::kill(pid_t p
 
 	(*it)->kill(tolerance);
 	forkedCalls.erase(it);
-
-	if (forkedCalls.empty()) {
-		timeout_->stop();
-	}
 }
 
 } // namespace support
Index: src/support/forkedcontr.h
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/forkedcontr.h,v
retrieving revision 1.14
diff -u -p -r1.14 forkedcontr.h
--- src/support/forkedcontr.h	22 Mar 2004 14:10:20 -0000	1.14
+++ src/support/forkedcontr.h	22 Mar 2004 22:20:53 -0000
@@ -20,8 +20,6 @@
 
 #include <list>
 
-class Timeout;
-
 namespace lyx {
 namespace support {
 
@@ -32,6 +30,13 @@ public:
 	/// Get hold of the only controller that can exist inside the process.
 	static ForkedcallsController & get();
 
+	/** Those child processes that are found to have finished are removed
+	 *  from the list and their callback function is passed the final
+	 *  return state.
+	 *  Invoked by the handler triggered by a SIGCHLD signal.
+	 */
+    	void handleCompletedProcesses();
+
 	/// Add a new child process to the list of controlled processes.
 	void addCall(ForkedProcess const &);
 
@@ -46,22 +51,10 @@ private:
 	ForkedcallsController(ForkedcallsController const &);
 	~ForkedcallsController();
 
-	/** This method is connected to the timer. Every XX ms it is called
-	 *  so that we can check on the status of the children. Those that
-	 *  are found to have finished are removed from the list and their
-	 *  callback function is passed the final return state.
-	 */
-	void timer();
-
 	/// The child processes
 	typedef std::list<ForkedProcess *> ListType;
 	///
 	ListType forkedCalls;
-
-	/** The timer. Enables us to check the status of the children
-	 *  every XX ms and to invoke a callback on completion.
-	 */
-	Timeout * timeout_;
 };
 
 } // namespace support

Reply via email to