3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Asger Alstrup Nielsen
7 * \author Angus Leeming
9 * Full author contact details are available in file CREDITS.
11 * A class for the control of child processes launched using
12 * fork() and execvp().
17 #include "forkedcontr.h"
18 #include "forkedcall.h"
19 #include "lyxfunctional.h"
22 #include "frontends/Timeout.h"
24 #include <boost/bind.hpp>
38 #ifndef CXX_GLOBAL_CSTD
46 // Ensure, that only one controller exists inside process
47 ForkedcallsController & ForkedcallsController::get()
49 static ForkedcallsController singleton;
54 ForkedcallsController::ForkedcallsController()
56 timeout_ = new Timeout(100, Timeout::ONETIME);
59 .connect(bind(&ForkedcallsController::timer, this));
63 // open question: should we stop childs here?
64 // Asger says no: I like to have my xdvi open after closing LyX. Maybe
65 // I want to print or something.
66 ForkedcallsController::~ForkedcallsController()
68 for (ListType::iterator it = forkedCalls.begin();
69 it != forkedCalls.end(); ++it) {
77 void ForkedcallsController::addCall(ForkedProcess const & newcall)
79 if (!timeout_->running())
82 forkedCalls.push_back(newcall.clone().release());
87 // Check the list and, if there is a stopped child, emit the signal.
88 void ForkedcallsController::timer()
90 ListType::iterator it = forkedCalls.begin();
91 ListType::iterator end = forkedCalls.end();
93 ForkedProcess * actCall = *it;
95 pid_t pid = actCall->pid();
97 pid_t const waitrpid = waitpid(pid, &stat_loc, WNOHANG);
98 bool remove_it = false;
100 if (waitrpid == -1) {
101 lyxerr << "LyX: Error waiting for child: "
102 << strerror(errno) << endl;
104 // Child died, so pretend it returned 1
105 actCall->setRetValue(1);
108 } else if (waitrpid == 0) {
109 // Still running. Move on to the next child.
111 } else if (WIFEXITED(stat_loc)) {
112 // Ok, the return value goes into retval.
113 actCall->setRetValue(WEXITSTATUS(stat_loc));
116 } else if (WIFSIGNALED(stat_loc)) {
117 // Child died, so pretend it returned 1
118 actCall->setRetValue(1);
121 } else if (WIFSTOPPED(stat_loc)) {
122 lyxerr << "LyX: Child (pid: " << pid
123 << ") stopped on signal "
124 << WSTOPSIG(stat_loc)
125 << ". Waiting for child to finish." << endl;
128 lyxerr << "LyX: Something rotten happened while "
129 "waiting for child " << pid << endl;
131 // Child died, so pretend it returned 1
132 actCall->setRetValue(1);
137 forkedCalls.erase(it);
139 actCall->emitSignal();
142 /* start all over: emiting the signal can result
143 * in changing the list (Ab)
145 it = forkedCalls.begin();
151 if (!forkedCalls.empty() && !timeout_->running()) {
157 // Kill the process prematurely and remove it from the list
158 // within tolerance secs
159 void ForkedcallsController::kill(pid_t pid, int tolerance)
161 ListType::iterator it =
162 find_if(forkedCalls.begin(), forkedCalls.end(),
163 lyx::compare_memfun(&Forkedcall::pid, pid));
165 if (it == forkedCalls.end())
168 (*it)->kill(tolerance);
169 forkedCalls.erase(it);
171 if (forkedCalls.empty()) {
176 } // namespace support