]> git.lyx.org Git - lyx.git/blobdiff - src/support/forkedcontr.C
* src/text2.C: deleteEmptyParagraphMechanism(): fix a crash in
[lyx.git] / src / support / forkedcontr.C
index e45c4002ba99c945a81a1a1f1757e39497dbe903..708509aa6c27fd63198de8ef1ed0fa98bb1d2b4c 100644 (file)
 
 #include <config.h>
 
-#include "forkedcontr.h"
-#include "forkedcall.h"
-#include "lyxfunctional.h"
+#include "support/forkedcontr.h"
+#include "support/forkedcall.h"
+
 #include "debug.h"
 
-#include "frontends/Timeout.h"
+#ifdef _WIN32
+# include <sstream>
+# include <windows.h>
+
+#else
+# include <cerrno>
+# include <csignal>
+# include <cstdlib>
+# ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+# endif
+# include <sys/wait.h>
+
+# ifndef CXX_GLOBAL_CSTD
+  using std::signal;
+  using std::strerror;
+# endif
+#endif
 
 #include <boost/bind.hpp>
-#include <boost/iterator/indirect_iterator.hpp>
-
-#include <cerrno>
-#include <cstdlib>
-#include <unistd.h>
-#include <sys/wait.h>
-
 
 using boost::bind;
 
 using std::endl;
+using std::equal_to;
 using std::find_if;
-using std::string;
-
-#ifndef CXX_GLOBAL_CSTD
-using std::strerror;
-#endif
 
+using std::string;
+using std::vector;
 
 namespace lyx {
 namespace support {
 
+#if defined(_WIN32)
+string const getChildErrorMessage()
+{
+       DWORD const error_code = ::GetLastError();
+
+       HLOCAL t_message = 0;
+       bool const ok = ::FormatMessage(
+               FORMAT_MESSAGE_ALLOCATE_BUFFER |
+               FORMAT_MESSAGE_FROM_SYSTEM,
+               0, error_code,
+               MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+               (LPTSTR) &t_message, 0, 0
+               ) != 0;
+
+       std::ostringstream ss;
+       ss << "LyX: Error waiting for child: " << error_code;
+
+       if (ok) {
+               ss << ": " << (LPTSTR)t_message;
+               ::LocalFree(t_message);
+       } else
+               ss << ": Error unknown.";
+
+       return ss.str().c_str();
+}
+#endif
+
+
 // Ensure, that only one controller exists inside process
 ForkedcallsController & ForkedcallsController::get()
 {
@@ -53,45 +89,64 @@ ForkedcallsController & ForkedcallsController::get()
 
 
 ForkedcallsController::ForkedcallsController()
-{
-       timeout_ = new Timeout(100, Timeout::ONETIME);
-
-       timeout_->timeout
-               .connect(bind(&ForkedcallsController::timer, this));
-}
+{}
 
 
 // open question: should we stop childs here?
 // Asger says no: I like to have my xdvi open after closing LyX. Maybe
 // I want to print or something.
 ForkedcallsController::~ForkedcallsController()
-{
-       delete timeout_;
-}
+{}
 
 
 void ForkedcallsController::addCall(ForkedProcess const & newcall)
 {
-       if (!timeout_->running())
-               timeout_->start();
-
        forkedCalls.push_back(newcall.clone());
 }
 
 
-// Timer-call
-// Check the list and, if there is a stopped child, emit the signal.
-void ForkedcallsController::timer()
+// Check the list of dead children and emit any associated signals.
+void ForkedcallsController::handleCompletedProcesses()
 {
        ListType::iterator it  = forkedCalls.begin();
        ListType::iterator end = forkedCalls.end();
        while (it != end) {
-               ForkedProcess * actCall = it->get();
+               ForkedProcessPtr actCall = *it;
+               bool remove_it = false;
 
+#if defined(_WIN32)
+               HANDLE const hProcess = HANDLE(actCall->pid());
+
+               DWORD const wait_status = ::WaitForSingleObject(hProcess, 0);
+
+               switch (wait_status) {
+               case WAIT_TIMEOUT:
+                       // Still running
+                       break;
+               case WAIT_OBJECT_0: {
+                       DWORD exit_code = 0;
+                       if (!GetExitCodeProcess(hProcess, &exit_code)) {
+                               lyxerr << "GetExitCodeProcess failed waiting for child\n"
+                                      << getChildErrorMessage() << std::endl;
+                               // Child died, so pretend it returned 1
+                               actCall->setRetValue(1);
+                       } else {
+                               actCall->setRetValue(exit_code);
+                       }
+                       remove_it = true;
+                       break;
+               }
+               case WAIT_FAILED:
+                       lyxerr << "WaitForSingleObject failed waiting for child\n"
+                              << getChildErrorMessage() << std::endl;
+                       actCall->setRetValue(1);
+                       remove_it = true;
+                       break;
+               }
+#else
                pid_t pid = actCall->pid();
                int stat_loc;
                pid_t const waitrpid = waitpid(pid, &stat_loc, WNOHANG);
-               bool remove_it = false;
 
                if (waitrpid == -1) {
                        lyxerr << "LyX: Error waiting for child: "
@@ -128,10 +183,11 @@ void ForkedcallsController::timer()
                        actCall->setRetValue(1);
                        remove_it = true;
                }
+#endif
 
                if (remove_it) {
-                       actCall->emitSignal();
                        forkedCalls.erase(it);
+                       actCall->emitSignal();
 
                        /* start all over: emiting the signal can result
                         * in changing the list (Ab)
@@ -141,10 +197,16 @@ void ForkedcallsController::timer()
                        ++it;
                }
        }
+}
 
-       if (!forkedCalls.empty() && !timeout_->running()) {
-               timeout_->start();
-       }
+
+ForkedcallsController::iterator
+ForkedcallsController::find_pid(pid_t pid)
+{
+       return find_if(forkedCalls.begin(), forkedCalls.end(),
+                      bind(equal_to<pid_t>(),
+                           bind(&Forkedcall::pid, _1),
+                           pid));
 }
 
 
@@ -152,21 +214,12 @@ void ForkedcallsController::timer()
 // within tolerance secs
 void ForkedcallsController::kill(pid_t pid, int tolerance)
 {
-       typedef boost::indirect_iterator<ListType::iterator> iterator;
-
-       iterator begin = boost::make_indirect_iterator(forkedCalls.begin());
-       iterator end   = boost::make_indirect_iterator(forkedCalls.end());
-       iterator it = find_if(begin, end,
-                             lyx::compare_memfun(&Forkedcall::pid, pid));
-
-       if (it == end)
+       ListType::iterator it = find_pid(pid);
+       if (it == forkedCalls.end())
                return;
 
-       it->kill(tolerance);
-       forkedCalls.erase(it.base());
-
-       if (forkedCalls.empty())
-               timeout_->stop();
+       (*it)->kill(tolerance);
+       forkedCalls.erase(it);
 }
 
 } // namespace support