1 //------------------------------------------------------------------------------
2 // emProcess.h
3 //
4 // Copyright (C) 2006-2010,2014,2017-2018 Oliver Hamann.
5 //
6 // Homepage: http://eaglemode.sourceforge.net/
7 //
8 // This program is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU General Public License version 3 as published by the
10 // Free Software Foundation.
11 //
12 // This program is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License version 3
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //------------------------------------------------------------------------------
20 
21 #ifndef emProcess_h
22 #define emProcess_h
23 
24 #ifndef emStd2_h
25 #include <emCore/emStd2.h>
26 #endif
27 
28 struct emProcessPrivate;
29 
30 
31 //==============================================================================
32 //================================= emProcess ==================================
33 //==============================================================================
34 
35 class emProcess : public emUncopyable {
36 
37 public:
38 
39 	// This class helps in creating and managing system processes.
40 
41 	emProcess();
42 		// Construct with no child process running.
43 
44 	virtual ~emProcess();
45 		// If a child process is still running, Terminate() is called.
46 
47 	enum StartFlags {
48 		SF_SHARE_STDIN  = 1<<0,
49 		SF_PIPE_STDIN   = 1<<1,
50 		SF_SHARE_STDOUT = 1<<2,
51 		SF_PIPE_STDOUT  = 1<<3,
52 		SF_SHARE_STDERR = 1<<4,
53 		SF_PIPE_STDERR  = 1<<5,
54 		SF_NO_WINDOW    = 1<<6
55 	};
56 
57 	void TryStart(
58 		const emArray<emString> & args,
59 		const emArray<emString> & extraEnv=emArray<emString>(),
60 		const char * dirPath=NULL,
61 		int flags=SF_SHARE_STDIN|SF_SHARE_STDOUT|SF_SHARE_STDERR
62 	);
63 		// Start a managed child process.
64 		// Arguments:
65 		//   args     - Program arguments for the child process. The
66 		//              first entry is the program name itself, either
67 		//              as a file path, or just the name (PATH is
68 		//              searched then). The array must not be empty.
69 		//   extraEnv - The child process inherits the environment from
70 		//              this process, and in addition, it gets the
71 		//              environment variables given here. The array can
72 		//              have any number of environment variables, each
73 		//              of the form <Name>[=<value>]. If it's just the
74 		//              name, the variable is removed (on UNIX: only if
75 		//              supported by putenv), otherwise the variable is
76 		//              set or changed to the given value (which can be
77 		//              empty).
78 		//   dirPath  - Current working directory for the child process,
79 		//              or NULL for inheriting the current directory
80 		//              from this process.
81 		//   flags    - Combination of start flags from enum StartFlags.
82 		//              The flags SF_SHARE_STDIN and SF_PIPE_STDIN
83 		//              control the type of the standard input handle
84 		//              for the child process. Giving none of these
85 		//              flags means to have no standard input (closed
86 		//              handle). SF_SHARE_STDIN means to inherit the
87 		//              handle from this process. SF_PIPE_STDIN means to
88 		//              create a pipe (see methods TryWrite and
89 		//              CloseWrite). Setting both flags is not allowed.
90 		//              The other SF_*_STD* flags are for standard
91 		//              output and standard error analogously.
92 		//              SF_NO_WINDOW means to omit the console window of
93 		//              a console process on Windows.
94 		// Throws: An error message on failure.
95 
96 	static void TryStartUnmanaged(
97 		const emArray<emString> & args,
98 		const emArray<emString> & extraEnv=emArray<emString>(),
99 		const char * dirPath=NULL,
100 		int flags=SF_SHARE_STDIN|SF_SHARE_STDOUT|SF_SHARE_STDERR
101 	);
102 		// This function(!) is like the method TryStart, but the new
103 		// process is not managed by an emProcess object. Pipelining is
104 		// not possible with this. On UNIX, the new process is detached
105 		// from this process, so that it does not become a child
106 		// process.
107 
108 	int TryWrite(const char * buf, int len);
109 		// Write to standard input of the child process, without
110 		// blocking. The child process should have been started with
111 		// SF_PIPE_STDIN.
112 		// Arguments:
113 		//   buf - Array of bytes to be written.
114 		//   len - Number of bytes to be written.
115 		// Returns:
116 		//   >0 - Number of bytes actually written.
117 		//    0 - No writing possible at this moment, please try again
118 		//        later (or wait by calling WaitPipes).
119 		//   -1 - Any end of the pipe has been closed (e.g. child
120 		//        process exited).
121 		// Throws: An error message on failure.
122 
123 	int TryRead(char * buf, int maxLen);
124 		// Read from standard output of the child process, without
125 		// blocking. The child process should have been started with
126 		// SF_PIPE_STDOUT.
127 		// Arguments:
128 		//   buf - Array for storing the bytes.
129 		//   len - Maximum number of bytes to be read.
130 		// Returns:
131 		//   >0 - Number of bytes actually read.
132 		//    0 - No bytes available at this moment, please try again
133 		//        later (or wait by calling WaitPipes).
134 		//   -1 - Any end of the pipe has been closed (e.g. child
135 		//        process exited).
136 		// Throws: An error message on failure.
137 
138 	int TryReadErr(char * buf, int maxLen);
139 		// Like TryRead, but for standard error (SF_PIPE_STDERR).
140 
141 	enum WaitFlags {
142 		WF_WAIT_STDIN  = 1<<0,
143 		WF_WAIT_STDOUT = 1<<1,
144 		WF_WAIT_STDERR = 1<<2
145 	};
146 	void WaitPipes(int waitFlags, unsigned timeoutMS=UINT_MAX);
147 		// Wait until a pipe is ready for writing and/or reading.
148 		// Arguments:
149 		//   waitFlags - Combination of flags from enum WaitFlags. This
150 		//               specifies the pipes to wait for. The method
151 		//               returns when at least one of these pipes is
152 		//               ready.
153 		//   timeoutMS - After this time-out in milliseconds, the
154 		//               method returns even if no pipe is ready.
155 		//               UINT_MAX means infinite.
156 
157 	void CloseWriting();
158 	void CloseReading();
159 	void CloseReadingErr();
160 		// Close this end of a pipe.
161 
162 	void SendTerminationSignal();
163 		// Send a termination request to the child process. On UNIX, the
164 		// signal SIGTERM is sent to the child process. On Windows, the
165 		// message WM_QUIT is sent to the primary thread of the child
166 		// process. Note that this does not work with a normal Windows
167 		// console program, except the latter is explicitly programmed
168 		// for receiving WM_QUIT.
169 
170 	void SendKillSignal();
171 		// Hardly kill the child process. Usually this should never be
172 		// called. On UNIX, the signal SIGKILL is sent to the child
173 		// process. On Windows, the SDK function TerminateProcess is
174 		// called.
175 
176 	bool WaitForTermination(unsigned timeoutMS=UINT_MAX);
177 		// Wait for the child process to terminate.
178 		// Arguments:
179 		//   timeoutMS - Time-out in milliseconds. UINT_MAX means
180 		//               infinite.
181 		// Returns:
182 		//   true  - Child process terminated (or never started).
183 		//   false - Timed out.
184 
185 	bool IsRunning();
186 		// true if a child process has been started and not yet
187 		// terminated.
188 
189 	void Terminate(unsigned fatalTimeoutMS=20000);
190 		// Like SendTerminationSignal plus WaitForTermination. But if
191 		// the process does not terminate within the given time-out in
192 		// milliseconds, emFatalError is called (because it is assumed
193 		// to have a programming error somewhere). The time-out should
194 		// be quite large, for the case of a badly overloaded system.
195 
196 	int GetExitStatus() const;
197 		// Get the exit status of a terminated child process.
198 
199 private:
200 
201 	emProcessPrivate * P;
202 
203 };
204 
205 
206 #endif
207