Migrate libasyncio from boost.signal to signals2 (#8756)
[libasyncio] / asyncio / async_process.hpp
1 /*
2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
4
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
7
8 As a special exception, if other files instantiate templates or use macros
9 or inline functions from this file, or you compile this file and link it
10 with other works to produce a work based on this file, this file
11 does not by itself cause the resulting work to be covered
12 by the GNU General Public License.
13
14 However the source code for this file must still be made available
15 in accordance with section (3) of the GNU General Public License.
16
17 This exception does not invalidate any other reasons why a work based
18 on this file might be covered by the GNU General Public License.
19 */
20 /** @file
21  *
22  * simple process handling based on simple io classes.
23  *
24  * (c) Copyright 2007-2008 by Intra2net AG
25  */
26
27 #ifndef __ASYNC_PROCESS_HPP__
28 #define __ASYNC_PROCESS_HPP__
29
30 #include <vector>
31 #include <utility>
32
33 #include <sys/types.h>
34
35 #include <asyncio_containerfunc.hpp>
36 #include <asyncio_signalfunc.hpp>
37 #include "async_io.hpp"
38
39
40 namespace AsyncIo
41 {
42
43 using SystemTools::Signal;
44 using SystemTools::ScopedSignalBlocker;
45
46
47 class ProcessManager;
48
49
50 typedef std::pair< pid_t, int >      PidStatePair;
51 typedef std::vector< PidStatePair >  PidStateList;
52
53
54 /**
55  * represents process states.
56  */
57 struct ProcessState
58 {
59    enum _ProcessState
60    {
61       stopped = 0,
62       running,
63       suspended
64    }; // eo enum _ProcessState
65
66    _ProcessState m_state;
67
68    ProcessState(_ProcessState _state = stopped) : m_state(_state) {}
69
70    operator _ProcessState() const { return m_state; }
71 }; // eo struct ProcessState
72
73
74 /**
75  * specialisation of the io implementation class which fork/exec's a subprocess and
76  * connects with the new child's stdin/stdout.
77  *
78  * @note the signal @a IOImplementation::m_signal_eof of the base class can be used to detect when the
79  * new child closes it's stdout (which usually means that the child ended).
80  */
81 class ProcessImplementation : public IOImplementation
82 {
83       typedef IOImplementation inherited;
84
85       friend class ProcessManager;
86
87    public:
88
89       enum StderrMode
90       {
91          /// "magic" constant to pass to start() when childs stderr should be the same as parents stderr.
92          UseParentsStderr= 0,
93          /// "magic" constant to pass to start() when stderr should be the same as stdout for the new process.
94          StderrOnStdout
95       }; // eo enum StderrMode
96
97    public:
98       ProcessImplementation(
99          const std::string& path,
100          const std::vector<std::string>& args = std::vector<std::string>());
101       virtual ~ProcessImplementation();
102
103       virtual void close(Direction direction = Direction::both);
104
105       virtual bool startProcess( IOImplementation2* stderr );
106       bool startProcess( StderrMode stderr_mode = UseParentsStderr );
107
108       virtual void stopProcess(bool force=false);
109
110       PushBackFiller<std::string, std::vector > getArgAdder();
111
112       bool setCreateNewSession( bool enable= true);
113
114       bool setNice(int nice);
115
116       bool setWorkDir(const std::string& workdir);
117
118       void resetArgs( const std::vector< std::string >& args = std::vector< std::string >() );
119
120       /// returns the current process state
121       ProcessState processState() const { return m_state; }
122
123       ///returns the exit code of the process (if in stopped state)
124       int exitCode() const { return m_exit_code; }
125
126       bool kill(const Signal signal);
127
128       /// returns the pid of the child process
129       pid_t pid() const { return m_pid; }
130
131    protected:
132
133       void setChildState(pid_t pid, int status);
134
135    protected:
136       /// the path to the binary
137       std::string m_path;
138       /// argument list (starting with argv0, usually the name of the binary)
139       std::vector<std::string> m_args;
140       /// increment of the nice level when the new child is started
141       int  m_nice_inc;
142       /// determines if the child should start a new session.
143       bool m_create_new_session;
144       /// determines the workdir where the child process should be started with.
145       std::string m_workdir;
146
147       /// the pid of the child process
148       pid_t m_pid;
149       /// the state of the child process
150       ProcessState m_state;
151       /// the exit code of the child (-1 if not available yet)
152       int  m_exit_code;
153
154       /// signal which is fired when the child terminated
155       SignalType m_signal_terminated;
156
157
158       /// "magic" constant to pass to start() when childs stderr should be the same as parents stderr.
159       static IOImplementation2* _UseParentsStderr;
160       /// "magic" constant to pass to start() when stderr should be the same as stdout for the new process.
161       static IOImplementation2* _StderrOnStdout;
162
163    private:
164
165 }; // eo class ProcessImplementation
166
167
168 /**
169  * manages overall process related stuff.
170  *
171  * @note this class is implemented as a singleton.
172  * @note this class uses the io timer interface to be called within the backend loops when necessary.
173  */
174 class ProcessManager : public TimerBase
175 {
176    public:
177
178       static ProcessManager* getInstance();
179
180    protected:
181       ProcessManager();
182       ProcessManager(const ProcessManager&);
183
184       virtual void execute();
185
186       void activateMe();
187
188    public:
189
190       /**
191        * the signal which is fired when waitpid() returns a status for a child process
192        * which is not managed by this process subsystem.
193        * Another module which forks child processes can connect to this signal to receive
194        * the information when these child processes are terminated.
195        */
196       boost::signals2::signal<void(pid_t,int)> m_foreign_child_state_changed_signal;
197
198    protected:
199
200       static ProcessManager *the_instance;
201
202       PidStateList  m_foreign_pid_states;
203
204    private:
205 };
206
207
208 bool installChildHandler();
209 bool restoreChildHandler();
210
211
212 } // eo namespace AsyncIo
213
214 #endif