3 * Copyright 2001 The LyX Team
6 * \author Asger Alstrup Nielsen
7 * \author Angus Leeming
9 * A class for the control of child processes launched using
10 * fork() and execvp().
16 #pragma implementation
19 #include "forkedcontr.h"
20 #include "forkedcall.h"
21 #include "lyxfunctional.h"
22 #include "frontends/Timeout.h"
34 #ifndef CXX_GLOBAL_CSTD
38 // Ensure, that only one controller exists inside process
39 ForkedcallsController & ForkedcallsController::get()
41 static ForkedcallsController singleton;
46 ForkedcallsController::ForkedcallsController()
48 timeout_ = new Timeout(100, Timeout::CONTINUOUS);
51 .connect(SigC::slot(this, &ForkedcallsController::timer));
55 // open question: should we stop childs here?
56 // Asger says no: I like to have my xdvi open after closing LyX. Maybe
57 // I want to print or something.
58 ForkedcallsController::~ForkedcallsController()
60 for (ListType::iterator it = forkedCalls.begin();
61 it != forkedCalls.end(); ++it) {
69 // Add child process information to the list of controlled processes
70 void ForkedcallsController::addCall(Forkedcall const &newcall)
72 if (!timeout_->running())
75 Forkedcall * call = new Forkedcall(newcall);
76 forkedCalls.push_back(call);
77 childrenChanged.emit();
82 // Check the list and, if there is a stopped child, emit the signal.
83 void ForkedcallsController::timer()
85 ListType::size_type start_size = forkedCalls.size();
87 for (ListType::iterator it = forkedCalls.begin();
88 it != forkedCalls.end(); ++it) {
89 Forkedcall * actCall = *it;
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.
108 } else if (WIFEXITED(stat_loc)) {
109 // Ok, the return value goes into retval.
110 actCall->setRetValue(WEXITSTATUS(stat_loc));
113 } else if (WIFSIGNALED(stat_loc)) {
114 // Child died, so pretend it returned 1
115 actCall->setRetValue(1);
118 } else if (WIFSTOPPED(stat_loc)) {
119 lyxerr << "LyX: Child (pid: " << pid
120 << ") stopped on signal "
121 << WSTOPSIG(stat_loc)
122 << ". Waiting for child to finish." << endl;
125 lyxerr << "LyX: Something rotten happened while "
126 "waiting for child " << pid << endl;
128 // Child died, so pretend it returned 1
129 actCall->setRetValue(1);
134 // Emit signal and remove the item from the list
135 actCall->emitSignal();
137 // erase returns the next iterator, so decrement it
138 // to continue the loop.
139 ListType::iterator prev = it;
141 forkedCalls.erase(it);
146 if (forkedCalls.empty()) {
150 if (start_size != forkedCalls.size())
151 childrenChanged.emit();
155 // Return a vector of the pids of all the controlled processes.
156 vector<pid_t> const ForkedcallsController::getPIDs() const
160 if (forkedCalls.empty())
163 pids.resize(forkedCalls.size());
165 vector<pid_t>::iterator vit = pids.begin();
166 for (ListType::const_iterator lit = forkedCalls.begin();
167 lit != forkedCalls.end(); ++lit, ++vit) {
168 *vit = (*lit)->pid();
171 std::sort(pids.begin(), pids.end());
176 // Get the command string of the process.
177 string const ForkedcallsController::getCommand(pid_t pid) const
179 ListType::const_iterator it =
180 find_if(forkedCalls.begin(), forkedCalls.end(),
181 lyx::compare_memfun(&Forkedcall::pid, pid));
183 if (it == forkedCalls.end())
186 return (*it)->command();
190 // Kill the process prematurely and remove it from the list
191 // within tolerance secs
192 void ForkedcallsController::kill(pid_t pid, int tolerance)
194 ListType::iterator it =
195 find_if(forkedCalls.begin(), forkedCalls.end(),
196 lyx::compare_memfun(&Forkedcall::pid, pid));
198 if (it == forkedCalls.end())
201 (*it)->kill(tolerance);
202 forkedCalls.erase(it);
204 if (forkedCalls.empty()) {