OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 } | 98 } |
99 } | 99 } |
100 return 0; | 100 return 0; |
101 } | 101 } |
102 | 102 |
103 | 103 |
104 // Suspends the thread until there is data available from the child process. | 104 // Suspends the thread until there is data available from the child process. |
105 // Returns false on timeout, true on data ready. | 105 // Returns false on timeout, true on data ready. |
106 static bool WaitOnFD(int fd, | 106 static bool WaitOnFD(int fd, |
107 int read_timeout, | 107 int read_timeout, |
108 int* total_timeout, | 108 int total_timeout, |
109 struct timeval& start_time) { | 109 struct timeval& start_time) { |
110 fd_set readfds, writefds, exceptfds; | 110 fd_set readfds, writefds, exceptfds; |
111 struct timeval timeout; | 111 struct timeval timeout; |
112 if (*total_timeout != -1) { | 112 int gone = 0; |
| 113 if (total_timeout != -1) { |
113 struct timeval time_now; | 114 struct timeval time_now; |
114 gettimeofday(&time_now, NULL); | 115 gettimeofday(&time_now, NULL); |
115 int seconds = time_now.tv_sec - start_time.tv_sec; | 116 int seconds = time_now.tv_sec - start_time.tv_sec; |
116 int gone = seconds * 1000 + (time_now.tv_usec - start_time.tv_usec) / 1000; | 117 gone = seconds * 1000 + (time_now.tv_usec - start_time.tv_usec) / 1000; |
117 if (gone >= *total_timeout) return false; | 118 if (gone >= total_timeout) return false; |
118 *total_timeout -= gone; | |
119 } | 119 } |
120 FD_ZERO(&readfds); | 120 FD_ZERO(&readfds); |
121 FD_ZERO(&writefds); | 121 FD_ZERO(&writefds); |
122 FD_ZERO(&exceptfds); | 122 FD_ZERO(&exceptfds); |
123 FD_SET(fd, &readfds); | 123 FD_SET(fd, &readfds); |
124 FD_SET(fd, &exceptfds); | 124 FD_SET(fd, &exceptfds); |
125 if (read_timeout == -1 || | 125 if (read_timeout == -1 || |
126 (*total_timeout != -1 && *total_timeout < read_timeout)) { | 126 (total_timeout != -1 && total_timeout - gone < read_timeout)) { |
127 read_timeout = *total_timeout; | 127 read_timeout = total_timeout - gone; |
128 } | 128 } |
129 timeout.tv_usec = (read_timeout % 1000) * 1000; | 129 timeout.tv_usec = (read_timeout % 1000) * 1000; |
130 timeout.tv_sec = read_timeout / 1000; | 130 timeout.tv_sec = read_timeout / 1000; |
131 int number_of_fds_ready = select(fd + 1, | 131 int number_of_fds_ready = select(fd + 1, |
132 &readfds, | 132 &readfds, |
133 &writefds, | 133 &writefds, |
134 &exceptfds, | 134 &exceptfds, |
135 read_timeout != -1 ? &timeout : NULL); | 135 read_timeout != -1 ? &timeout : NULL); |
136 return number_of_fds_ready == 1; | 136 return number_of_fds_ready == 1; |
137 } | 137 } |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
299 } | 299 } |
300 return true; | 300 return true; |
301 } | 301 } |
302 | 302 |
303 | 303 |
304 // Accumulates the output from the child in a string handle. Returns true if it | 304 // Accumulates the output from the child in a string handle. Returns true if it |
305 // succeeded or false if an exception was thrown. | 305 // succeeded or false if an exception was thrown. |
306 static Handle<Value> GetStdout(int child_fd, | 306 static Handle<Value> GetStdout(int child_fd, |
307 struct timeval& start_time, | 307 struct timeval& start_time, |
308 int read_timeout, | 308 int read_timeout, |
309 int* total_timeout) { | 309 int total_timeout) { |
310 Handle<String> accumulator = String::Empty(); | 310 Handle<String> accumulator = String::Empty(); |
311 const char* source = "function(a, b) { return a + b; }"; | 311 const char* source = "function(a, b) { return a + b; }"; |
312 Handle<Value> cons_as_obj(Script::Compile(String::New(source))->Run()); | 312 Handle<Value> cons_as_obj(Script::Compile(String::New(source))->Run()); |
313 Handle<Function> cons_function(Function::Cast(*cons_as_obj)); | 313 Handle<Function> cons_function(Function::Cast(*cons_as_obj)); |
314 Handle<Value> cons_args[2]; | 314 Handle<Value> cons_args[2]; |
315 | 315 |
316 int fullness = 0; | 316 int fullness = 0; |
317 static const int kStdoutReadBufferSize = 4096; | 317 static const int kStdoutReadBufferSize = 4096; |
318 char buffer[kStdoutReadBufferSize]; | 318 char buffer[kStdoutReadBufferSize]; |
319 | 319 |
320 if (fcntl(child_fd, F_SETFL, O_NONBLOCK) != 0) { | 320 if (fcntl(child_fd, F_SETFL, O_NONBLOCK) != 0) { |
321 return ThrowException(String::New(strerror(errno))); | 321 return ThrowException(String::New(strerror(errno))); |
322 } | 322 } |
323 | 323 |
324 int bytes_read; | 324 int bytes_read; |
325 do { | 325 do { |
326 bytes_read = read(child_fd, | 326 bytes_read = read(child_fd, |
327 buffer + fullness, | 327 buffer + fullness, |
328 kStdoutReadBufferSize - fullness); | 328 kStdoutReadBufferSize - fullness); |
329 if (bytes_read == -1) { | 329 if (bytes_read == -1) { |
330 if (errno == EAGAIN) { | 330 if (errno == EAGAIN) { |
331 if (!WaitOnFD(child_fd, | 331 if (!WaitOnFD(child_fd, |
332 read_timeout, | 332 read_timeout, |
333 total_timeout, | 333 total_timeout, |
334 start_time) || | 334 start_time) || |
335 (TimeIsOut(start_time, *total_timeout))) { | 335 (TimeIsOut(start_time, total_timeout))) { |
336 return ThrowException(String::New("Timed out waiting for output")); | 336 return ThrowException(String::New("Timed out waiting for output")); |
337 } | 337 } |
338 continue; | 338 continue; |
339 } else if (errno == EINTR) { | 339 } else if (errno == EINTR) { |
340 continue; | 340 continue; |
341 } else { | 341 } else { |
342 break; | 342 break; |
343 } | 343 } |
344 } | 344 } |
345 if (bytes_read + fullness > 0) { | 345 if (bytes_read + fullness > 0) { |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
495 close(exec_error_fds[kWriteFD]); | 495 close(exec_error_fds[kWriteFD]); |
496 close(stdout_fds[kWriteFD]); | 496 close(stdout_fds[kWriteFD]); |
497 OpenFDCloser error_read_closer(exec_error_fds[kReadFD]); | 497 OpenFDCloser error_read_closer(exec_error_fds[kReadFD]); |
498 OpenFDCloser stdout_read_closer(stdout_fds[kReadFD]); | 498 OpenFDCloser stdout_read_closer(stdout_fds[kReadFD]); |
499 | 499 |
500 if (!ChildLaunchedOK(exec_error_fds)) return v8::Undefined(); | 500 if (!ChildLaunchedOK(exec_error_fds)) return v8::Undefined(); |
501 | 501 |
502 Handle<Value> accumulator = GetStdout(stdout_fds[kReadFD], | 502 Handle<Value> accumulator = GetStdout(stdout_fds[kReadFD], |
503 start_time, | 503 start_time, |
504 read_timeout, | 504 read_timeout, |
505 &total_timeout); | 505 total_timeout); |
506 if (accumulator->IsUndefined()) { | 506 if (accumulator->IsUndefined()) { |
507 kill(pid, SIGINT); // On timeout, kill the subprocess. | 507 kill(pid, SIGINT); // On timeout, kill the subprocess. |
508 return accumulator; | 508 return accumulator; |
509 } | 509 } |
510 | 510 |
511 if (!WaitForChild(pid, | 511 if (!WaitForChild(pid, |
512 child_waiter, | 512 child_waiter, |
513 start_time, | 513 start_time, |
514 read_timeout, | 514 read_timeout, |
515 total_timeout)) { | 515 total_timeout)) { |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
659 void Shell::AddOSMethods(Handle<ObjectTemplate> os_templ) { | 659 void Shell::AddOSMethods(Handle<ObjectTemplate> os_templ) { |
660 os_templ->Set(String::New("system"), FunctionTemplate::New(System)); | 660 os_templ->Set(String::New("system"), FunctionTemplate::New(System)); |
661 os_templ->Set(String::New("chdir"), FunctionTemplate::New(ChangeDirectory)); | 661 os_templ->Set(String::New("chdir"), FunctionTemplate::New(ChangeDirectory)); |
662 os_templ->Set(String::New("setenv"), FunctionTemplate::New(SetEnvironment)); | 662 os_templ->Set(String::New("setenv"), FunctionTemplate::New(SetEnvironment)); |
663 os_templ->Set(String::New("umask"), FunctionTemplate::New(SetUMask)); | 663 os_templ->Set(String::New("umask"), FunctionTemplate::New(SetUMask)); |
664 os_templ->Set(String::New("mkdirp"), FunctionTemplate::New(MakeDirectory)); | 664 os_templ->Set(String::New("mkdirp"), FunctionTemplate::New(MakeDirectory)); |
665 os_templ->Set(String::New("rmdir"), FunctionTemplate::New(RemoveDirectory)); | 665 os_templ->Set(String::New("rmdir"), FunctionTemplate::New(RemoveDirectory)); |
666 } | 666 } |
667 | 667 |
668 } // namespace v8 | 668 } // namespace v8 |
OLD | NEW |