Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(122)

Side by Side Diff: runtime/bin/process_linux.cc

Issue 9139011: Handle EINTR on all IO operations (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fixed building on Mac OS Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/bin/file_macos.cc ('k') | runtime/bin/process_macos.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "bin/process.h" 5 #include "bin/process.h"
6 6
7 #include <errno.h> 7 #include <errno.h>
8 #include <fcntl.h> 8 #include <fcntl.h>
9 #include <signal.h> 9 #include <signal.h>
10 #include <stdio.h> 10 #include <stdio.h>
11 #include <stdlib.h> 11 #include <stdlib.h>
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 81
82 static void SetChildOsErrorMessage(char* os_error_message, 82 static void SetChildOsErrorMessage(char* os_error_message,
83 int os_error_message_len) { 83 int os_error_message_len) {
84 SafeStrNCpy(os_error_message, strerror(errno), os_error_message_len); 84 SafeStrNCpy(os_error_message, strerror(errno), os_error_message_len);
85 } 85 }
86 86
87 87
88 void ExitHandler(int process_signal, siginfo_t* siginfo, void* tmp) { 88 void ExitHandler(int process_signal, siginfo_t* siginfo, void* tmp) {
89 int pid = 0; 89 int pid = 0;
90 int status = 0; 90 int status = 0;
91 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { 91 while ((pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG))) > 0) {
92 int exit_code = 0; 92 int exit_code = 0;
93 int negative = 0; 93 int negative = 0;
94 if (WIFEXITED(status)) { 94 if (WIFEXITED(status)) {
95 exit_code = WEXITSTATUS(status); 95 exit_code = WEXITSTATUS(status);
96 } 96 }
97 if (WIFSIGNALED(status)) { 97 if (WIFSIGNALED(status)) {
98 exit_code = WTERMSIG(status); 98 exit_code = WTERMSIG(status);
99 negative = 1; 99 negative = 1;
100 } 100 }
101 ProcessInfo* process = LookupProcess(pid); 101 ProcessInfo* process = LookupProcess(pid);
102 if (process != NULL) { 102 if (process != NULL) {
103 int message[3] = { pid, exit_code, negative }; 103 int message[3] = { pid, exit_code, negative };
104 intptr_t result = 104 intptr_t result =
105 FDUtils::WriteToBlocking(process->fd(), &message, sizeof(message)); 105 FDUtils::WriteToBlocking(process->fd(), &message, sizeof(message));
106 if (result != sizeof(message) && errno != EPIPE) { 106 if (result != sizeof(message) && errno != EPIPE) {
107 perror("ExitHandler notification failed"); 107 perror("ExitHandler notification failed");
108 } 108 }
109 close(process->fd()); 109 TEMP_FAILURE_RETRY(close(process->fd()));
110 } 110 }
111 } 111 }
112 } 112 }
113 113
114 114
115 static void ReportChildError(int exec_control_fd) { 115 static void ReportChildError(int exec_control_fd) {
116 // In the case of failure in the child process write the errno and 116 // In the case of failure in the child process write the errno and
117 // the OS error message to the exec control pipe and exit. 117 // the OS error message to the exec control pipe and exit.
118 int child_errno = errno; 118 int child_errno = errno;
119 char* os_error_message = strerror(errno); 119 char* os_error_message = strerror(errno);
120 ASSERT(sizeof(child_errno) == sizeof(errno)); 120 ASSERT(sizeof(child_errno) == sizeof(errno));
121 int bytes_written = 121 int bytes_written =
122 FDUtils::WriteToBlocking( 122 FDUtils::WriteToBlocking(
123 exec_control_fd, &child_errno, sizeof(child_errno)); 123 exec_control_fd, &child_errno, sizeof(child_errno));
124 if (bytes_written == sizeof(child_errno)) { 124 if (bytes_written == sizeof(child_errno)) {
125 FDUtils::WriteToBlocking( 125 FDUtils::WriteToBlocking(
126 exec_control_fd, os_error_message, strlen(os_error_message) + 1); 126 exec_control_fd, os_error_message, strlen(os_error_message) + 1);
127 } 127 }
128 close(exec_control_fd); 128 TEMP_FAILURE_RETRY(close(exec_control_fd));
129 exit(1); 129 exit(1);
130 } 130 }
131 131
132 132
133 int Process::Start(const char* path, 133 int Process::Start(const char* path,
134 char* arguments[], 134 char* arguments[],
135 intptr_t arguments_length, 135 intptr_t arguments_length,
136 const char* working_directory, 136 const char* working_directory,
137 intptr_t* in, 137 intptr_t* in,
138 intptr_t* out, 138 intptr_t* out,
139 intptr_t* err, 139 intptr_t* err,
140 intptr_t* id, 140 intptr_t* id,
141 intptr_t* exit_event, 141 intptr_t* exit_event,
142 char* os_error_message, 142 char* os_error_message,
143 int os_error_message_len) { 143 int os_error_message_len) {
144 pid_t pid; 144 pid_t pid;
145 int read_in[2]; // Pipe for stdout to child process. 145 int read_in[2]; // Pipe for stdout to child process.
146 int read_err[2]; // Pipe for stderr to child process. 146 int read_err[2]; // Pipe for stderr to child process.
147 int write_out[2]; // Pipe for stdin to child process. 147 int write_out[2]; // Pipe for stdin to child process.
148 int exec_control[2]; // Pipe to get the result from exec. 148 int exec_control[2]; // Pipe to get the result from exec.
149 int result; 149 int result;
150 150
151 result = pipe(read_in); 151 result = TEMP_FAILURE_RETRY(pipe(read_in));
152 if (result < 0) { 152 if (result < 0) {
153 SetChildOsErrorMessage(os_error_message, os_error_message_len); 153 SetChildOsErrorMessage(os_error_message, os_error_message_len);
154 fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message); 154 fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
155 return errno; 155 return errno;
156 } 156 }
157 157
158 result = pipe(read_err); 158 result = TEMP_FAILURE_RETRY(pipe(read_err));
159 if (result < 0) { 159 if (result < 0) {
160 SetChildOsErrorMessage(os_error_message, os_error_message_len); 160 SetChildOsErrorMessage(os_error_message, os_error_message_len);
161 close(read_in[0]); 161 TEMP_FAILURE_RETRY(close(read_in[0]));
162 close(read_in[1]); 162 TEMP_FAILURE_RETRY(close(read_in[1]));
163 fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message); 163 fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
164 return errno; 164 return errno;
165 } 165 }
166 166
167 result = pipe(write_out); 167 result = TEMP_FAILURE_RETRY(pipe(write_out));
168 if (result < 0) { 168 if (result < 0) {
169 SetChildOsErrorMessage(os_error_message, os_error_message_len); 169 SetChildOsErrorMessage(os_error_message, os_error_message_len);
170 close(read_in[0]); 170 TEMP_FAILURE_RETRY(close(read_in[0]));
171 close(read_in[1]); 171 TEMP_FAILURE_RETRY(close(read_in[1]));
172 close(read_err[0]); 172 TEMP_FAILURE_RETRY(close(read_err[0]));
173 close(read_err[1]); 173 TEMP_FAILURE_RETRY(close(read_err[1]));
174 fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message); 174 fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
175 return errno; 175 return errno;
176 } 176 }
177 177
178 result = pipe(exec_control); 178 result = TEMP_FAILURE_RETRY(pipe(exec_control));
179 if (result < 0) { 179 if (result < 0) {
180 SetChildOsErrorMessage(os_error_message, os_error_message_len); 180 SetChildOsErrorMessage(os_error_message, os_error_message_len);
181 close(read_in[0]); 181 TEMP_FAILURE_RETRY(close(read_in[0]));
182 close(read_in[1]); 182 TEMP_FAILURE_RETRY(close(read_in[1]));
183 close(read_err[0]); 183 TEMP_FAILURE_RETRY(close(read_err[0]));
184 close(read_err[1]); 184 TEMP_FAILURE_RETRY(close(read_err[1]));
185 close(write_out[0]); 185 TEMP_FAILURE_RETRY(close(write_out[0]));
186 close(write_out[1]); 186 TEMP_FAILURE_RETRY(close(write_out[1]));
187 fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message); 187 fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
188 return errno; 188 return errno;
189 } 189 }
190 190
191 // Set close on exec on the write file descriptor of the exec control pipe. 191 // Set close on exec on the write file descriptor of the exec control pipe.
192 result = fcntl( 192 result = TEMP_FAILURE_RETRY(
193 exec_control[1], F_SETFD, fcntl(exec_control[1], F_GETFD) | FD_CLOEXEC); 193 fcntl(exec_control[1],
194 F_SETFD,
195 TEMP_FAILURE_RETRY(fcntl(exec_control[1], F_GETFD)) | FD_CLOEXEC));
194 if (result < 0) { 196 if (result < 0) {
195 SetChildOsErrorMessage(os_error_message, os_error_message_len); 197 SetChildOsErrorMessage(os_error_message, os_error_message_len);
196 close(read_in[0]); 198 TEMP_FAILURE_RETRY(close(read_in[0]));
197 close(read_in[1]); 199 TEMP_FAILURE_RETRY(close(read_in[1]));
198 close(read_err[0]); 200 TEMP_FAILURE_RETRY(close(read_err[0]));
199 close(read_err[1]); 201 TEMP_FAILURE_RETRY(close(read_err[1]));
200 close(write_out[0]); 202 TEMP_FAILURE_RETRY(close(write_out[0]));
201 close(write_out[1]); 203 TEMP_FAILURE_RETRY(close(write_out[1]));
202 close(exec_control[0]); 204 TEMP_FAILURE_RETRY(close(exec_control[0]));
203 close(exec_control[1]); 205 TEMP_FAILURE_RETRY(close(exec_control[1]));
204 fprintf(stderr, "fcntl failed: %s\n", os_error_message); 206 fprintf(stderr, "fcntl failed: %s\n", os_error_message);
205 return errno; 207 return errno;
206 } 208 }
207 209
208 char** program_arguments = new char*[arguments_length + 2]; 210 char** program_arguments = new char*[arguments_length + 2];
209 program_arguments[0] = const_cast<char *>(path); 211 program_arguments[0] = const_cast<char *>(path);
210 for (int i = 0; i < arguments_length; i++) { 212 for (int i = 0; i < arguments_length; i++) {
211 program_arguments[i + 1] = arguments[i]; 213 program_arguments[i + 1] = arguments[i];
212 } 214 }
213 program_arguments[arguments_length + 1] = NULL; 215 program_arguments[arguments_length + 1] = NULL;
214 216
215 struct sigaction act; 217 struct sigaction act;
216 bzero(&act, sizeof(act)); 218 bzero(&act, sizeof(act));
217 act.sa_sigaction = ExitHandler; 219 act.sa_sigaction = ExitHandler;
218 act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; 220 act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
219 if (sigaction(SIGCHLD, &act, 0) != 0) { 221 if (sigaction(SIGCHLD, &act, 0) != 0) {
220 perror("Process start: setting signal handler failed"); 222 perror("Process start: setting signal handler failed");
221 } 223 }
222 pid = fork(); 224 pid = TEMP_FAILURE_RETRY(fork());
223 if (pid < 0) { 225 if (pid < 0) {
224 SetChildOsErrorMessage(os_error_message, os_error_message_len); 226 SetChildOsErrorMessage(os_error_message, os_error_message_len);
225 delete[] program_arguments; 227 delete[] program_arguments;
226 close(read_in[0]); 228 TEMP_FAILURE_RETRY(close(read_in[0]));
227 close(read_in[1]); 229 TEMP_FAILURE_RETRY(close(read_in[1]));
228 close(read_err[0]); 230 TEMP_FAILURE_RETRY(close(read_err[0]));
229 close(read_err[1]); 231 TEMP_FAILURE_RETRY(close(read_err[1]));
230 close(write_out[0]); 232 TEMP_FAILURE_RETRY(close(write_out[0]));
231 close(write_out[1]); 233 TEMP_FAILURE_RETRY(close(write_out[1]));
232 close(exec_control[0]); 234 TEMP_FAILURE_RETRY(close(exec_control[0]));
233 close(exec_control[1]); 235 TEMP_FAILURE_RETRY(close(exec_control[1]));
234 return errno; 236 return errno;
235 } else if (pid == 0) { 237 } else if (pid == 0) {
236 // Wait for parent process before setting up the child process. 238 // Wait for parent process before setting up the child process.
237 char msg; 239 char msg;
238 int bytes_read = FDUtils::ReadFromBlocking(read_in[0], &msg, sizeof(msg)); 240 int bytes_read = FDUtils::ReadFromBlocking(read_in[0], &msg, sizeof(msg));
239 if (bytes_read != sizeof(msg)) { 241 if (bytes_read != sizeof(msg)) {
240 perror("Failed receiving notification message"); 242 perror("Failed receiving notification message");
241 exit(1); 243 exit(1);
242 } 244 }
243 245
244 close(write_out[1]); 246 TEMP_FAILURE_RETRY(close(write_out[1]));
245 close(read_in[0]); 247 TEMP_FAILURE_RETRY(close(read_in[0]));
246 close(read_err[0]); 248 TEMP_FAILURE_RETRY(close(read_err[0]));
247 close(exec_control[0]); 249 TEMP_FAILURE_RETRY(close(exec_control[0]));
248 250
249 if (dup2(write_out[0], STDIN_FILENO) == -1) { 251 if (TEMP_FAILURE_RETRY(dup2(write_out[0], STDIN_FILENO)) == -1) {
250 ReportChildError(exec_control[1]); 252 ReportChildError(exec_control[1]);
251 } 253 }
252 close(write_out[0]); 254 TEMP_FAILURE_RETRY(close(write_out[0]));
253 255
254 if (dup2(read_in[1], STDOUT_FILENO) == -1) { 256 if (TEMP_FAILURE_RETRY(dup2(read_in[1], STDOUT_FILENO)) == -1) {
255 ReportChildError(exec_control[1]); 257 ReportChildError(exec_control[1]);
256 } 258 }
257 close(read_in[1]); 259 TEMP_FAILURE_RETRY(close(read_in[1]));
258 260
259 if (dup2(read_err[1], STDERR_FILENO) == -1) { 261 if (TEMP_FAILURE_RETRY(dup2(read_err[1], STDERR_FILENO)) == -1) {
260 ReportChildError(exec_control[1]); 262 ReportChildError(exec_control[1]);
261 } 263 }
262 close(read_err[1]); 264 TEMP_FAILURE_RETRY(close(read_err[1]));
263 265
264 if (working_directory != NULL && chdir(working_directory) == -1) { 266 if (working_directory != NULL &&
267 TEMP_FAILURE_RETRY(chdir(working_directory)) == -1) {
265 ReportChildError(exec_control[1]); 268 ReportChildError(exec_control[1]);
266 } 269 }
267 270
268 execvp(path, const_cast<char* const*>(program_arguments)); 271 TEMP_FAILURE_RETRY(
272 execvp(path, const_cast<char* const*>(program_arguments)));
269 ReportChildError(exec_control[1]); 273 ReportChildError(exec_control[1]);
270 } 274 }
271 275
272 // The arguments for the spawned process are not needed any longer. 276 // The arguments for the spawned process are not needed any longer.
273 delete[] program_arguments; 277 delete[] program_arguments;
274 278
275 int event_fds[2]; 279 int event_fds[2];
276 result = pipe(event_fds); 280 result = TEMP_FAILURE_RETRY(pipe(event_fds));
277 if (result < 0) { 281 if (result < 0) {
278 SetChildOsErrorMessage(os_error_message, os_error_message_len); 282 SetChildOsErrorMessage(os_error_message, os_error_message_len);
279 close(read_in[0]); 283 TEMP_FAILURE_RETRY(close(read_in[0]));
280 close(read_in[1]); 284 TEMP_FAILURE_RETRY(close(read_in[1]));
281 close(read_err[0]); 285 TEMP_FAILURE_RETRY(close(read_err[0]));
282 close(read_err[1]); 286 TEMP_FAILURE_RETRY(close(read_err[1]));
283 close(write_out[0]); 287 TEMP_FAILURE_RETRY(close(write_out[0]));
284 close(write_out[1]); 288 TEMP_FAILURE_RETRY(close(write_out[1]));
285 fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message); 289 fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
286 return errno; 290 return errno;
287 } 291 }
288 292
289 ProcessInfo* process = new ProcessInfo(pid, event_fds[1]); 293 ProcessInfo* process = new ProcessInfo(pid, event_fds[1]);
290 AddProcess(process); 294 AddProcess(process);
291 *exit_event = event_fds[0]; 295 *exit_event = event_fds[0];
292 FDUtils::SetNonBlocking(event_fds[0]); 296 FDUtils::SetNonBlocking(event_fds[0]);
293 297
294 // Notify child process to start. 298 // Notify child process to start.
295 char msg = '1'; 299 char msg = '1';
296 result = FDUtils::WriteToBlocking(read_in[1], &msg, sizeof(msg)); 300 result = FDUtils::WriteToBlocking(read_in[1], &msg, sizeof(msg));
297 if (result != sizeof(msg)) { 301 if (result != sizeof(msg)) {
298 perror("Failed sending notification message"); 302 perror("Failed sending notification message");
299 } 303 }
300 304
301 // Read exec result from child. If no data is returned the exec was 305 // Read exec result from child. If no data is returned the exec was
302 // successful and the exec call closed the pipe. Otherwise the errno 306 // successful and the exec call closed the pipe. Otherwise the errno
303 // is written to the pipe. 307 // is written to the pipe.
304 close(exec_control[1]); 308 TEMP_FAILURE_RETRY(close(exec_control[1]));
305 int child_errno; 309 int child_errno;
306 int bytes_read = -1; 310 int bytes_read = -1;
307 ASSERT(sizeof(child_errno) == sizeof(errno)); 311 ASSERT(sizeof(child_errno) == sizeof(errno));
308 bytes_read = 312 bytes_read =
309 FDUtils::ReadFromBlocking( 313 FDUtils::ReadFromBlocking(
310 exec_control[0], &child_errno, sizeof(child_errno)); 314 exec_control[0], &child_errno, sizeof(child_errno));
311 if (bytes_read == sizeof(child_errno)) { 315 if (bytes_read == sizeof(child_errno)) {
312 bytes_read = FDUtils::ReadFromBlocking(exec_control[0], 316 bytes_read = FDUtils::ReadFromBlocking(exec_control[0],
313 os_error_message, 317 os_error_message,
314 os_error_message_len); 318 os_error_message_len);
315 os_error_message[os_error_message_len - 1] = '\0'; 319 os_error_message[os_error_message_len - 1] = '\0';
316 } 320 }
317 close(exec_control[0]); 321 TEMP_FAILURE_RETRY(close(exec_control[0]));
318 322
319 // Return error code if any failures. 323 // Return error code if any failures.
320 if (bytes_read != 0) { 324 if (bytes_read != 0) {
321 close(read_in[0]); 325 TEMP_FAILURE_RETRY(close(read_in[0]));
322 close(read_in[1]); 326 TEMP_FAILURE_RETRY(close(read_in[1]));
323 close(read_err[0]); 327 TEMP_FAILURE_RETRY(close(read_err[0]));
324 close(read_err[1]); 328 TEMP_FAILURE_RETRY(close(read_err[1]));
325 close(write_out[0]); 329 TEMP_FAILURE_RETRY(close(write_out[0]));
326 close(write_out[1]); 330 TEMP_FAILURE_RETRY(close(write_out[1]));
327 if (bytes_read == -1) { 331 if (bytes_read == -1) {
328 return errno; // Read failed. 332 return errno; // Read failed.
329 } else { 333 } else {
330 return child_errno; // Exec failed. 334 return child_errno; // Exec failed.
331 } 335 }
332 } 336 }
333 337
334 FDUtils::SetNonBlocking(read_in[0]); 338 FDUtils::SetNonBlocking(read_in[0]);
335 *in = read_in[0]; 339 *in = read_in[0];
336 close(read_in[1]); 340 TEMP_FAILURE_RETRY(close(read_in[1]));
337 FDUtils::SetNonBlocking(write_out[1]); 341 FDUtils::SetNonBlocking(write_out[1]);
338 *out = write_out[1]; 342 *out = write_out[1];
339 close(write_out[0]); 343 TEMP_FAILURE_RETRY(close(write_out[0]));
340 FDUtils::SetNonBlocking(read_err[0]); 344 FDUtils::SetNonBlocking(read_err[0]);
341 *err = read_err[0]; 345 *err = read_err[0];
342 close(read_err[1]); 346 TEMP_FAILURE_RETRY(close(read_err[1]));
343 347
344 *id = pid; 348 *id = pid;
345 return 0; 349 return 0;
346 } 350 }
347 351
348 352
349 bool Process::Kill(intptr_t id) { 353 bool Process::Kill(intptr_t id) {
350 int result = kill(id, SIGKILL); 354 int result = TEMP_FAILURE_RETRY(kill(id, SIGKILL));
351 if (result == -1) { 355 if (result == -1) {
352 return false; 356 return false;
353 } 357 }
354 return true; 358 return true;
355 } 359 }
356 360
357 361
358 void Process::Exit(intptr_t id) { 362 void Process::Exit(intptr_t id) {
359 RemoveProcess(id); 363 RemoveProcess(id);
360 } 364 }
OLDNEW
« no previous file with comments | « runtime/bin/file_macos.cc ('k') | runtime/bin/process_macos.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698