Commit | Line | Data |
---|---|---|
8c15b8c7 TJ |
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 | */ | |
5c8a3d40 RP |
20 | /** @file |
21 | * | |
22 | * simple process handling based on simple io classes. | |
23 | * | |
24 | * (c) Copyright 2007-2008 by Intra2net AG | |
5c8a3d40 RP |
25 | */ |
26 | ||
42b7c46d RP |
27 | #ifndef __ASYNC_PROCESS_HPP__ |
28 | #define __ASYNC_PROCESS_HPP__ | |
5c8a3d40 RP |
29 | |
30 | #include <vector> | |
31 | #include <utility> | |
32 | ||
33 | #include <sys/types.h> | |
34 | ||
ce4ab835 RP |
35 | #include <asyncio_containerfunc.hpp> |
36 | #include <asyncio_signalfunc.hpp> | |
42b7c46d | 37 | #include "async_io.hpp" |
5c8a3d40 RP |
38 | |
39 | ||
42b7c46d | 40 | namespace AsyncIo |
5c8a3d40 RP |
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 | ||
811f4e70 | 126 | bool kill(const Signal signal); |
5c8a3d40 | 127 | |
811f4e70 | 128 | /// returns the pid of the child process |
2491b8a2 | 129 | pid_t pid() const { return m_pid; } |
5c8a3d40 | 130 | |
811f4e70 | 131 | protected: |
5c8a3d40 RP |
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 | */ | |
983acc1f | 196 | boost::signals2::signal<void(pid_t,int)> m_foreign_child_state_changed_signal; |
5c8a3d40 RP |
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 | ||
42b7c46d | 212 | } // eo namespace AsyncIo |
5c8a3d40 RP |
213 | |
214 | #endif |