4 * This file is part of LyX, the document processor.
5 * Licence details can be found in the file COPYING.
7 * \author Asger Alstrup
8 * \author Angus Leeming
9 * \author Alfredo Braunstein
11 * Full author contact details are available in file CREDITS.
17 #include <boost/shared_ptr.hpp>
18 #include <boost/signal.hpp>
20 #ifdef HAVE_SYS_TYPES_H
21 # include <sys/types.h>
47 virtual ~ForkedProcess() {}
49 virtual boost::shared_ptr<ForkedProcess> clone() const = 0;
51 /** A SignalType signal is can be emitted once the forked process
52 * has finished. It passes:
53 * the PID of the child and;
54 * the return value from the child.
56 * We use a signal rather than simply a callback function so that
57 * we can return easily to C++ methods, rather than just globally
58 * accessible functions.
60 typedef boost::signal<void(pid_t, int)> SignalType;
62 /** The signal is connected in the calling routine to the desired
63 * slot. We pass a shared_ptr rather than a reference to the signal
64 * because it is eminently possible for the instance of the calling
65 * class (and hence the signal) to be destructed before the forked
68 * It doesn't matter if the slot disappears, SigC takes care of that.
70 typedef boost::shared_ptr<SignalType> SignalTypePtr;
72 /** Invoking the following methods makes sense only if the command
73 * is running asynchronously!
76 /** gets the PID of the child process.
79 pid_t pid() const { return pid_; }
86 /** Set the return value of the child process.
89 void setRetValue(int r) { retval_ = r; }
91 /// Returns the identifying command (for display in the GUI perhaps).
92 std::string const & command() const { return command_; }
94 /// is the process running ?
97 /** Kill child prematurely.
98 * First, a SIGHUP is sent to the child.
99 * If that does not end the child process within "tolerance"
100 * seconds, the SIGKILL signal is sent to the child.
101 * When the child is dead, the callback is called.
103 void kill(int tolerance = 5);
106 /** Spawn the child process.
107 * Returns returncode from child.
109 int run(Starttype type);
111 /// Callback function
112 SignalTypePtr signal_;
114 /// identifying command (for display in the GUI perhaps).
115 std::string command_;
117 /// Process ID of child
120 /// Return value from child
123 /// generate child in background
124 virtual int generateChild() = 0;
126 /// Wait for child process to finish. Updates returncode from child.
132 * An instance of class ForkedCall represents a single child process.
134 * Class ForkedCall uses fork() and execvp() to lauch the child process.
136 * Once launched, control is returned immediately to the parent process
137 * but a Signal can be emitted upon completion of the child.
139 * The child process is not killed when the ForkedCall instance goes out of
140 * scope, but it can be killed by an explicit invocation of the kill() member
144 class ForkedCall : public ForkedProcess {
147 virtual boost::shared_ptr<ForkedProcess> clone() const {
148 return boost::shared_ptr<ForkedProcess>(new ForkedCall(*this));
151 /** Start the child process.
153 * The command "what" is passed to execvp() for execution.
155 * There are two startScript commands available. They differ in that
156 * the second receives a signal that is executed on completion of
157 * the command. This makes sense only for a command executed
158 * in the background, ie DontWait.
160 * The other startscript command can be executed either blocking
161 * or non-blocking, but no signal will be emitted on finishing.
163 int startScript(Starttype, std::string const & what);
166 int startScript(std::string const & what, SignalTypePtr);
170 virtual int generateChild();
175 * This class implements a queue of forked processes. In order not to
176 * hose the system with multiple processes running simultaneously, you can
177 * request the addition of your process to this queue and it will be
178 * executed when its turn comes.
182 class ForkedCallQueue {
184 /// A process in the queue
185 typedef std::pair<std::string, ForkedCall::SignalTypePtr> Process;
186 /** Add a process to the queue. Processes are forked sequentially
187 * only one is running at a time.
188 * Connect to the returned signal and you'll be informed when
189 * the process has ended.
191 ForkedCall::SignalTypePtr add(std::string const & process);
192 /// Query whether the queue is running a forked process now.
193 bool running() const;
194 /// Get the and only instance of the class
195 static ForkedCallQueue & get();
198 /** this class is a singleton class... use
199 * ForkedCallQueue::get() instead
202 /// in-progress queue
203 std::queue<Process> callQueue_;
213 void callback(pid_t, int);
218 * A class for the control of child processes launched using
219 * fork() and execvp().
222 class ForkedCallsController {
224 /// Get hold of the only controller that can exist inside the process.
225 static ForkedCallsController & get();
227 /// Add a new child process to the list of controlled processes.
228 void addCall(ForkedProcess const &);
230 /** Those child processes that are found to have finished are removed
231 * from the list and their callback function is passed the final
234 void handleCompletedProcesses();
236 /** Kill this process prematurely and remove it from the list.
237 * The process is killed within tolerance secs.
238 * See forkedcall.[Ch] for details.
240 void kill(pid_t, int tolerance = 5);
243 ForkedCallsController();
244 ForkedCallsController(ForkedCallsController const &);
245 ~ForkedCallsController();
247 typedef boost::shared_ptr<ForkedProcess> ForkedProcessPtr;
248 typedef std::list<ForkedProcessPtr> ListType;
249 typedef ListType::iterator iterator;
251 iterator find_pid(pid_t);
253 /// The child processes
254 ListType forkedCalls;
259 // a wrapper for GetLastError() and FormatMessage().
260 std::string const getChildErrorMessage();
263 } // namespace support
266 #endif // FORKEDCALLS_H