diff options
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 | |||