diff options
author | Mike Buland <eichlan@xagasoft.com> | 2009-12-21 17:56:32 +0000 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2009-12-21 17:56:32 +0000 |
commit | 184669188717673c4cb36698192fe8c14aa3af68 (patch) | |
tree | a91583c0e383a38852d6b64f3bebd5778630c0bb /src/process.cpp | |
parent | 5399dd17a944464ced0c8618c46a367e4188d29b (diff) | |
download | libbu++-184669188717673c4cb36698192fe8c14aa3af68.tar.gz libbu++-184669188717673c4cb36698192fe8c14aa3af68.tar.bz2 libbu++-184669188717673c4cb36698192fe8c14aa3af68.tar.xz libbu++-184669188717673c4cb36698192fe8c14aa3af68.zip |
Ok, Process has been updated. You now must specify flags as the first parameter
of both constructors, this allows you to control which streams to bind to.
To preserve the old behaviour, simply put Bu::Process::StdOut before your old
first parameters.
Diffstat (limited to 'src/process.cpp')
-rw-r--r-- | src/process.cpp | 241 |
1 files changed, 181 insertions, 60 deletions
diff --git a/src/process.cpp b/src/process.cpp index 9340647..1c18626 100644 --- a/src/process.cpp +++ b/src/process.cpp | |||
@@ -14,14 +14,33 @@ | |||
14 | #include <fcntl.h> | 14 | #include <fcntl.h> |
15 | #include <errno.h> | 15 | #include <errno.h> |
16 | 16 | ||
17 | Bu::Process::Process( const char *sName, char *const argv[] ) : | 17 | #include <sys/select.h> |
18 | iPid( 0 ) | 18 | #include "bu/osx_compatibility.h" |
19 | #include "bu/win32_compatibility.h" | ||
20 | #include "bu/linux_compatibility.h" | ||
21 | |||
22 | Bu::Process::Process( Flags eFlags, const char *sName, char *const argv[] ) : | ||
23 | iStdIn( -1 ), | ||
24 | iStdOut( -1 ), | ||
25 | iStdErr( -1 ), | ||
26 | iPid( 0 ), | ||
27 | iProcStatus( 0 ), | ||
28 | bBlocking( true ), | ||
29 | bStdOutEos( true ), | ||
30 | bStdErrEos( true ) | ||
19 | { | 31 | { |
20 | gexec( sName, argv ); | 32 | gexec( eFlags, sName, argv ); |
21 | } | 33 | } |
22 | 34 | ||
23 | Bu::Process::Process( const char *sName, const char *argv, ...) : | 35 | Bu::Process::Process( Flags eFlags, const char *sName, const char *argv, ...) : |
24 | iPid( 0 ) | 36 | iStdIn( -1 ), |
37 | iStdOut( -1 ), | ||
38 | iStdErr( -1 ), | ||
39 | iPid( 0 ), | ||
40 | iProcStatus( 0 ), | ||
41 | bBlocking( true ), | ||
42 | bStdOutEos( true ), | ||
43 | bStdErrEos( true ) | ||
25 | { | 44 | { |
26 | int iCnt = 0; | 45 | int iCnt = 0; |
27 | va_list ap; | 46 | va_list ap; |
@@ -39,7 +58,7 @@ Bu::Process::Process( const char *sName, const char *argv, ...) : | |||
39 | list[iCnt+1] = NULL; | 58 | list[iCnt+1] = NULL; |
40 | va_end( ap ); | 59 | va_end( ap ); |
41 | 60 | ||
42 | gexec( sName, (char *const *)list ); | 61 | gexec( eFlags, sName, (char *const *)list ); |
43 | delete[] list; | 62 | delete[] list; |
44 | } | 63 | } |
45 | 64 | ||
@@ -48,18 +67,26 @@ Bu::Process::~Process() | |||
48 | close(); | 67 | close(); |
49 | } | 68 | } |
50 | 69 | ||
51 | void Bu::Process::gexec( const char *sName, char *const argv[] ) | 70 | void Bu::Process::gexec( Flags eFlags, const char *sName, char *const argv[] ) |
52 | { | 71 | { |
53 | int iaStdIn[2]; | 72 | int iaStdIn[2]; |
54 | int iaStdOut[2]; | 73 | int iaStdOut[2]; |
55 | // int iaStdErr[2]; | 74 | int iaStdErr[2]; |
56 | pipe( iaStdIn ); | 75 | pipe( iaStdIn ); |
57 | pipe( iaStdOut ); | 76 | if( eFlags & StdOut ) |
58 | // pipe( iaStdErr ); | 77 | { |
78 | pipe( iaStdOut ); | ||
79 | iStdOut = iaStdOut[0]; | ||
80 | bStdOutEos = false; | ||
81 | } | ||
82 | if( eFlags & StdErr ) | ||
83 | { | ||
84 | pipe( iaStdErr ); | ||
85 | iStdErr = iaStdErr[0]; | ||
86 | bStdErrEos = false; | ||
87 | } | ||
59 | 88 | ||
60 | iStdIn = iaStdIn[1]; | 89 | iStdIn = iaStdIn[1]; |
61 | iStdOut = iaStdOut[0]; | ||
62 | // iStdErr = iaStdErr[0]; | ||
63 | 90 | ||
64 | // fcntl( iStdOut, F_SETFL, fcntl( iStdOut, F_GETFL, 0 )|O_NONBLOCK ); | 91 | // fcntl( iStdOut, F_SETFL, fcntl( iStdOut, F_GETFL, 0 )|O_NONBLOCK ); |
65 | 92 | ||
@@ -67,17 +94,25 @@ void Bu::Process::gexec( const char *sName, char *const argv[] ) | |||
67 | if( iPid == 0 ) | 94 | if( iPid == 0 ) |
68 | { | 95 | { |
69 | ::close( iaStdIn[1] ); | 96 | ::close( iaStdIn[1] ); |
70 | ::close( iaStdOut[0] ); | ||
71 | // ::close( iaStdErr[0] ); | ||
72 | dup2( iaStdIn[0], 0 ); | 97 | dup2( iaStdIn[0], 0 ); |
73 | dup2( iaStdOut[1], 1 ); | 98 | if( eFlags & StdOut ) |
74 | // dup2( iaStdErr[1], 2 ); | 99 | { |
100 | ::close( iaStdOut[0] ); | ||
101 | dup2( iaStdOut[1], 1 ); | ||
102 | } | ||
103 | if( eFlags & StdErr ) | ||
104 | { | ||
105 | ::close( iaStdErr[0] ); | ||
106 | dup2( iaStdErr[1], 2 ); | ||
107 | } | ||
75 | execvp( sName, argv ); | 108 | execvp( sName, argv ); |
76 | throw Bu::ExceptionBase("Hey, execvp failed!"); | 109 | throw Bu::ExceptionBase("Hey, execvp failed!"); |
77 | } | 110 | } |
78 | ::close( iaStdIn[0] ); | 111 | ::close( iaStdIn[0] ); |
79 | ::close( iaStdOut[1] ); | 112 | if( eFlags & StdOut ) |
80 | // ::close( iaStdErr[1] ); | 113 | ::close( iaStdOut[1] ); |
114 | if( eFlags & StdErr ) | ||
115 | ::close( iaStdErr[1] ); | ||
81 | } | 116 | } |
82 | 117 | ||
83 | void Bu::Process::close() | 118 | void Bu::Process::close() |
@@ -85,63 +120,73 @@ void Bu::Process::close() | |||
85 | if( iPid ) | 120 | if( iPid ) |
86 | { | 121 | { |
87 | ::close( iStdIn ); | 122 | ::close( iStdIn ); |
88 | ::close( iStdOut ); | 123 | if( iStdErr > -1 ) |
89 | int status; | 124 | ::close( iStdOut ); |
90 | waitpid( iPid, &status, 0 ); | 125 | if( iStdErr > -1 ) |
126 | ::close( iStdErr ); | ||
127 | waitpid( iPid, &iProcStatus, 0 ); | ||
91 | iPid = 0; | 128 | iPid = 0; |
92 | } | 129 | } |
93 | } | 130 | } |
94 | 131 | ||
95 | size_t Bu::Process::read( void *pBuf, size_t nBytes ) | 132 | size_t Bu::Process::read( void *pBuf, size_t nBytes ) |
96 | { | 133 | { |
97 | size_t nRead = TEMP_FAILURE_RETRY( ::read( iStdOut, pBuf, nBytes ) ); | 134 | if( bStdOutEos ) |
98 | if( nRead == 0 ) | ||
99 | { | ||
100 | close(); | ||
101 | return 0; | 135 | return 0; |
102 | } | 136 | fd_set rfds; |
103 | return nRead; | 137 | FD_ZERO( &rfds ); |
104 | /* | 138 | FD_SET( iStdOut, &rfds ); |
105 | size_t iTotal = 0; | 139 | struct timeval tv = {0, 0}; |
106 | for(;;) | 140 | if( ::bu_select( iStdOut+1, &rfds, NULL, NULL, &tv ) < 0 ) |
141 | throw Bu::ExceptionBase( strerror( errno ) ); | ||
142 | if( FD_ISSET( iStdOut, &rfds ) || bBlocking ) | ||
107 | { | 143 | { |
108 | size_t iRet = ::read( iStdOut, (char *)pBuf+iTotal, nBytes-iTotal ); | 144 | ssize_t nRead = TEMP_FAILURE_RETRY( ::read( iStdOut, pBuf, nBytes ) ); |
109 | if( iRet == 0 ) | 145 | if( nRead == 0 ) |
110 | return iTotal; | ||
111 | iTotal += iRet; | ||
112 | if( iTotal == nBytes ) | ||
113 | return iTotal; | ||
114 | } | ||
115 | */ | ||
116 | /* | ||
117 | size_t iTotal = 0; | ||
118 | fd_set rfs; | ||
119 | FD_ZERO( &rfs ); | ||
120 | for(;;) | ||
121 | { | ||
122 | if( waitpid( iPid, NULL, WNOHANG ) ) | ||
123 | { | 146 | { |
124 | printf("!!!wait failed!\n"); | 147 | bStdOutEos = true; |
125 | size_t iRet = ::read( iStdOut, (char *)pBuf+iTotal, | 148 | checkClose(); |
126 | nBytes-iTotal ); | 149 | return 0; |
127 | iTotal += iRet; | ||
128 | return iTotal; | ||
129 | } | 150 | } |
130 | 151 | if( nRead < 0 ) | |
131 | FD_SET( iStdOut, &rfs ); | 152 | { |
132 | select( iStdOut+1, &rfs, NULL, &rfs, NULL ); | 153 | if( errno == EAGAIN ) |
133 | size_t iRet = ::read( iStdOut, (char *)pBuf+iTotal, nBytes-iTotal ); | 154 | return 0; |
134 | printf("--read=%d / %d--\n", iRet, iTotal+iRet ); | 155 | throw Bu::ExceptionBase( strerror( errno ) ); |
135 | iTotal += iRet; | 156 | } |
136 | if( iTotal == nBytes ) | 157 | return nRead; |
137 | return iTotal; | ||
138 | } | 158 | } |
139 | */ | 159 | return 0; |
140 | } | 160 | } |
141 | 161 | ||
142 | size_t Bu::Process::readErr( void *pBuf, size_t nBytes ) | 162 | size_t Bu::Process::readErr( void *pBuf, size_t nBytes ) |
143 | { | 163 | { |
144 | return ::read( iStdErr, pBuf, nBytes ); | 164 | if( bStdErrEos ) |
165 | return 0; | ||
166 | fd_set rfds; | ||
167 | FD_ZERO( &rfds ); | ||
168 | FD_SET( iStdErr, &rfds ); | ||
169 | struct timeval tv = {0, 0}; | ||
170 | if( ::bu_select( iStdErr+1, &rfds, NULL, NULL, &tv ) < 0 ) | ||
171 | throw Bu::ExceptionBase( strerror( errno ) ); | ||
172 | if( FD_ISSET( iStdErr, &rfds ) || bBlocking ) | ||
173 | { | ||
174 | ssize_t nRead = TEMP_FAILURE_RETRY( ::read( iStdErr, pBuf, nBytes ) ); | ||
175 | if( nRead == 0 ) | ||
176 | { | ||
177 | bStdErrEos = true; | ||
178 | checkClose(); | ||
179 | return 0; | ||
180 | } | ||
181 | if( nRead < 0 ) | ||
182 | { | ||
183 | if( errno == EAGAIN ) | ||
184 | return 0; | ||
185 | throw Bu::ExceptionBase( strerror( errno ) ); | ||
186 | } | ||
187 | return nRead; | ||
188 | } | ||
189 | return 0; | ||
145 | } | 190 | } |
146 | 191 | ||
147 | size_t Bu::Process::write( const void *pBuf, size_t nBytes ) | 192 | size_t Bu::Process::write( const void *pBuf, size_t nBytes ) |
@@ -213,9 +258,52 @@ bool Bu::Process::isBlocking() | |||
213 | void Bu::Process::setBlocking( bool bBlocking ) | 258 | void Bu::Process::setBlocking( bool bBlocking ) |
214 | { | 259 | { |
215 | if( bBlocking ) | 260 | if( bBlocking ) |
261 | { | ||
216 | fcntl( iStdOut, F_SETFL, fcntl( iStdOut, F_GETFL, 0 )&(~O_NONBLOCK) ); | 262 | fcntl( iStdOut, F_SETFL, fcntl( iStdOut, F_GETFL, 0 )&(~O_NONBLOCK) ); |
263 | fcntl( iStdErr, F_SETFL, fcntl( iStdErr, F_GETFL, 0 )&(~O_NONBLOCK) ); | ||
264 | } | ||
217 | else | 265 | else |
266 | { | ||
218 | fcntl( iStdOut, F_SETFL, fcntl( iStdOut, F_GETFL, 0 )|O_NONBLOCK ); | 267 | fcntl( iStdOut, F_SETFL, fcntl( iStdOut, F_GETFL, 0 )|O_NONBLOCK ); |
268 | fcntl( iStdErr, F_SETFL, fcntl( iStdErr, F_GETFL, 0 )|O_NONBLOCK ); | ||
269 | } | ||
270 | this->bBlocking = bBlocking; | ||
271 | } | ||
272 | |||
273 | void Bu::Process::select( bool &bStdOut, bool &bStdErr ) | ||
274 | { | ||
275 | fd_set rfds; | ||
276 | FD_ZERO( &rfds ); | ||
277 | if( !bStdOutEos ) | ||
278 | FD_SET( iStdOut, &rfds ); | ||
279 | if( !bStdErrEos ) | ||
280 | FD_SET( iStdErr, &rfds ); | ||
281 | if( ::bu_select( iStdErr+1, &rfds, NULL, NULL, NULL ) < 0 ) | ||
282 | throw Bu::ExceptionBase( strerror( errno ) ); | ||
283 | |||
284 | if( FD_ISSET( iStdOut, &rfds ) ) | ||
285 | bStdOut = true; | ||
286 | else | ||
287 | bStdOut = false; | ||
288 | |||
289 | if( FD_ISSET( iStdErr, &rfds ) ) | ||
290 | bStdErr = true; | ||
291 | else | ||
292 | bStdErr = false; | ||
293 | } | ||
294 | |||
295 | bool Bu::Process::isRunning() | ||
296 | { | ||
297 | return iPid != 0; | ||
298 | } | ||
299 | |||
300 | void Bu::Process::ignoreStdErr() | ||
301 | { | ||
302 | if( iStdErr == -1 ) | ||
303 | return; | ||
304 | ::close( iStdErr ); | ||
305 | iStdErr = -1; | ||
306 | bStdErrEos = true; | ||
219 | } | 307 | } |
220 | 308 | ||
221 | pid_t Bu::Process::getPid() | 309 | pid_t Bu::Process::getPid() |
@@ -223,3 +311,36 @@ pid_t Bu::Process::getPid() | |||
223 | return iPid; | 311 | return iPid; |
224 | } | 312 | } |
225 | 313 | ||
314 | bool Bu::Process::childExited() | ||
315 | { | ||
316 | return WIFEXITED( iProcStatus ); | ||
317 | } | ||
318 | |||
319 | int Bu::Process::childExitStatus() | ||
320 | { | ||
321 | return WEXITSTATUS( iProcStatus ); | ||
322 | } | ||
323 | |||
324 | bool Bu::Process::childSignaled() | ||
325 | { | ||
326 | return WIFSIGNALED( iProcStatus ); | ||
327 | } | ||
328 | |||
329 | int Bu::Process::childSignal() | ||
330 | { | ||
331 | return WTERMSIG( iProcStatus ); | ||
332 | } | ||
333 | |||
334 | bool Bu::Process::childCoreDumped() | ||
335 | { | ||
336 | return WCOREDUMP( iProcStatus ); | ||
337 | } | ||
338 | |||
339 | void Bu::Process::checkClose() | ||
340 | { | ||
341 | if( bStdOutEos && bStdErrEos ) | ||
342 | { | ||
343 | close(); | ||
344 | } | ||
345 | } | ||
346 | |||