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