]> git.lyx.org Git - lyx.git/blob - src/support/forkedcontr.C
Remove cruft left over from the removal of the Forks dialog.
[lyx.git] / src / support / forkedcontr.C
1 /**
2  * \file forkedcontr.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Asger Alstrup Nielsen
7  * \author Angus Leeming
8  *
9  * Full author contact details are available in file CREDITS.
10  *
11  * A class for the control of child processes launched using
12  * fork() and execvp().
13  */
14
15 #include <config.h>
16
17 #include "forkedcontr.h"
18 #include "forkedcall.h"
19 #include "lyxfunctional.h"
20 #include "debug.h"
21
22 #include "frontends/Timeout.h"
23
24 #include <boost/bind.hpp>
25
26 #include <cerrno>
27 #include <cstdlib>
28 #include <unistd.h>
29 #include <sys/wait.h>
30
31
32 using boost::bind;
33
34 using std::endl;
35 using std::find_if;
36 using std::string;
37
38 #ifndef CXX_GLOBAL_CSTD
39 using std::strerror;
40 #endif
41
42
43 namespace lyx {
44 namespace support {
45
46 // Ensure, that only one controller exists inside process
47 ForkedcallsController & ForkedcallsController::get()
48 {
49         static ForkedcallsController singleton;
50         return singleton;
51 }
52
53
54 ForkedcallsController::ForkedcallsController()
55 {
56         timeout_ = new Timeout(100, Timeout::ONETIME);
57
58         timeout_->timeout
59                 .connect(bind(&ForkedcallsController::timer, this));
60 }
61
62
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()
67 {
68         for (ListType::iterator it = forkedCalls.begin();
69              it != forkedCalls.end(); ++it) {
70                 delete *it;
71         }
72
73         delete timeout_;
74 }
75
76
77 void ForkedcallsController::addCall(ForkedProcess const & newcall)
78 {
79         if (!timeout_->running())
80                 timeout_->start();
81
82         forkedCalls.push_back(newcall.clone().release());
83 }
84
85
86 // Timer-call
87 // Check the list and, if there is a stopped child, emit the signal.
88 void ForkedcallsController::timer()
89 {
90         ListType::iterator it  = forkedCalls.begin();
91         ListType::iterator end = forkedCalls.end();
92         while (it != end) {
93                 ForkedProcess * actCall = *it;
94
95                 pid_t pid = actCall->pid();
96                 int stat_loc;
97                 pid_t const waitrpid = waitpid(pid, &stat_loc, WNOHANG);
98                 bool remove_it = false;
99
100                 if (waitrpid == -1) {
101                         lyxerr << "LyX: Error waiting for child: "
102                                << strerror(errno) << endl;
103
104                         // Child died, so pretend it returned 1
105                         actCall->setRetValue(1);
106                         remove_it = true;
107
108                 } else if (waitrpid == 0) {
109                         // Still running. Move on to the next child.
110
111                 } else if (WIFEXITED(stat_loc)) {
112                         // Ok, the return value goes into retval.
113                         actCall->setRetValue(WEXITSTATUS(stat_loc));
114                         remove_it = true;
115
116                 } else if (WIFSIGNALED(stat_loc)) {
117                         // Child died, so pretend it returned 1
118                         actCall->setRetValue(1);
119                         remove_it = true;
120
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;
126
127                 } else {
128                         lyxerr << "LyX: Something rotten happened while "
129                                 "waiting for child " << pid << endl;
130
131                         // Child died, so pretend it returned 1
132                         actCall->setRetValue(1);
133                         remove_it = true;
134                 }
135
136                 if (remove_it) {
137                         forkedCalls.erase(it);
138
139                         actCall->emitSignal();
140                         delete actCall;
141
142                         /* start all over: emiting the signal can result
143                          * in changing the list (Ab)
144                          */
145                         it = forkedCalls.begin();
146                 } else {
147                         ++it;
148                 }
149         }
150
151         if (!forkedCalls.empty() && !timeout_->running()) {
152                 timeout_->start();
153         }
154 }
155
156
157 // Kill the process prematurely and remove it from the list
158 // within tolerance secs
159 void ForkedcallsController::kill(pid_t pid, int tolerance)
160 {
161         ListType::iterator it =
162                 find_if(forkedCalls.begin(), forkedCalls.end(),
163                         lyx::compare_memfun(&Forkedcall::pid, pid));
164
165         if (it == forkedCalls.end())
166                 return;
167
168         (*it)->kill(tolerance);
169         forkedCalls.erase(it);
170
171         if (forkedCalls.empty()) {
172                 timeout_->stop();
173         }
174 }
175
176 } // namespace support
177 } // namespace lyx