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