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>
25 #include <boost/iterator/indirect_iterator.hpp>
39 #ifndef CXX_GLOBAL_CSTD
47 // Ensure, that only one controller exists inside process
48 ForkedcallsController & ForkedcallsController::get()
50 static ForkedcallsController singleton;
55 ForkedcallsController::ForkedcallsController()
57 timeout_ = new Timeout(100, Timeout::ONETIME);
60 .connect(bind(&ForkedcallsController::timer, this));
64 // open question: should we stop childs here?
65 // Asger says no: I like to have my xdvi open after closing LyX. Maybe
66 // I want to print or something.
67 ForkedcallsController::~ForkedcallsController()
73 void ForkedcallsController::addCall(ForkedProcess const & newcall)
75 if (!timeout_->running())
78 forkedCalls.push_back(newcall.clone());
83 // Check the list and, if there is a stopped child, emit the signal.
84 void ForkedcallsController::timer()
86 ListType::iterator it = forkedCalls.begin();
87 ListType::iterator end = forkedCalls.end();
89 ForkedProcess * actCall = it->get();
91 pid_t pid = actCall->pid();
93 pid_t const waitrpid = waitpid(pid, &stat_loc, WNOHANG);
94 bool remove_it = false;
97 lyxerr << "LyX: Error waiting for child: "
98 << strerror(errno) << endl;
100 // Child died, so pretend it returned 1
101 actCall->setRetValue(1);
104 } else if (waitrpid == 0) {
105 // Still running. Move on to the next child.
107 } else if (WIFEXITED(stat_loc)) {
108 // Ok, the return value goes into retval.
109 actCall->setRetValue(WEXITSTATUS(stat_loc));
112 } else if (WIFSIGNALED(stat_loc)) {
113 // Child died, so pretend it returned 1
114 actCall->setRetValue(1);
117 } else if (WIFSTOPPED(stat_loc)) {
118 lyxerr << "LyX: Child (pid: " << pid
119 << ") stopped on signal "
120 << WSTOPSIG(stat_loc)
121 << ". Waiting for child to finish." << endl;
124 lyxerr << "LyX: Something rotten happened while "
125 "waiting for child " << pid << endl;
127 // Child died, so pretend it returned 1
128 actCall->setRetValue(1);
133 actCall->emitSignal();
134 forkedCalls.erase(it);
136 /* start all over: emiting the signal can result
137 * in changing the list (Ab)
139 it = forkedCalls.begin();
145 if (!forkedCalls.empty() && !timeout_->running()) {
151 // Kill the process prematurely and remove it from the list
152 // within tolerance secs
153 void ForkedcallsController::kill(pid_t pid, int tolerance)
155 typedef boost::indirect_iterator<ListType::iterator> iterator;
157 iterator begin = boost::make_indirect_iterator(forkedCalls.begin());
158 iterator end = boost::make_indirect_iterator(forkedCalls.end());
159 iterator it = find_if(begin, end,
160 lyx::compare_memfun(&Forkedcall::pid, pid));
166 forkedCalls.erase(it.base());
168 if (forkedCalls.empty())
172 } // namespace support