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

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

Powered by Google App Engine
This is Rietveld 408576698