OLD | NEW |
---|---|
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 #if !defined(DART_IO_DISABLED) | 5 #if !defined(DART_IO_DISABLED) |
6 | 6 |
7 #include "platform/globals.h" | 7 #include "platform/globals.h" |
8 #if defined(TARGET_OS_FUCHSIA) | 8 #if defined(TARGET_OS_FUCHSIA) |
9 | 9 |
10 #include "bin/process.h" | 10 #include "bin/process.h" |
11 | 11 |
12 #include <errno.h> | |
13 #include <fcntl.h> | |
14 #include <launchpad/launchpad.h> | |
15 #include <launchpad/vmo.h> | |
16 #include <magenta/status.h> | |
17 #include <magenta/syscalls.h> | |
18 #include <magenta/syscalls/object.h> | |
19 #include <mxio/util.h> | |
20 #include <pthread.h> | |
21 #include <stdbool.h> | |
22 #include <stdio.h> | |
23 #include <stdlib.h> | |
24 #include <string.h> | |
25 #include <unistd.h> | |
26 | |
27 #include "bin/dartutils.h" | |
28 #include "bin/fdutils.h" | |
12 #include "bin/lockers.h" | 29 #include "bin/lockers.h" |
13 #include "platform/assert.h" | 30 #include "bin/log.h" |
31 #include "platform/signal_blocker.h" | |
14 | 32 |
33 // #define PROCESS_LOGGING 1 | |
34 #if defined(PROCESS_LOGGING) | |
35 #define LOG_ERR(msg, ...) Log::PrintErr("Dart Process: " msg, ##__VA_ARGS__) | |
36 #define LOG_INFO(msg, ...) Log::Print("Dart Process: " msg, ##__VA_ARGS__) | |
37 #else | |
38 #define LOG_ERR(msg, ...) | |
39 #define LOG_INFO(msg, ...) | |
40 #endif // defined(PROCESS_LOGGING) | |
15 | 41 |
16 namespace dart { | 42 namespace dart { |
17 namespace bin { | 43 namespace bin { |
18 | 44 |
19 int Process::global_exit_code_ = 0; | 45 int Process::global_exit_code_ = 0; |
20 Mutex* Process::global_exit_code_mutex_ = new Mutex(); | 46 Mutex* Process::global_exit_code_mutex_ = new Mutex(); |
21 Process::ExitHook Process::exit_hook_ = NULL; | 47 Process::ExitHook Process::exit_hook_ = NULL; |
22 | 48 |
23 void Process::TerminateExitCodeHandler() {} | 49 // ProcessInfo is used to map a process id to the file descriptor for |
50 // the pipe used to communicate the exit code of the process to Dart. | |
51 // ProcessInfo objects are kept in the static singly-linked | |
52 // ProcessInfoList. | |
53 class ProcessInfo { | |
54 public: | |
55 ProcessInfo(mx_handle_t process, intptr_t fd) : process_(process), fd_(fd) {} | |
56 ~ProcessInfo() { | |
57 int closed = NO_RETRY_EXPECTED(close(fd_)); | |
58 if (closed != 0) { | |
59 FATAL("Failed to close process exit code pipe"); | |
60 } | |
61 } | |
62 mx_handle_t process() const { return process_; } | |
63 intptr_t fd() const { return fd_; } | |
64 ProcessInfo* next() const { return next_; } | |
65 void set_next(ProcessInfo* info) { next_ = info; } | |
66 | |
67 private: | |
68 mx_handle_t process_; | |
69 intptr_t fd_; | |
rmacnak
2016/12/12 18:18:20
exit_pipe_fd_
zra
2016/12/13 19:07:50
Done.
| |
70 ProcessInfo* next_; | |
71 | |
72 DISALLOW_COPY_AND_ASSIGN(ProcessInfo); | |
73 }; | |
74 | |
75 | |
76 // Singly-linked list of ProcessInfo objects for all active processes | |
77 // started from Dart. | |
78 class ProcessInfoList { | |
79 public: | |
80 static void AddProcess(mx_handle_t process, intptr_t fd) { | |
81 MutexLocker locker(mutex_); | |
82 ProcessInfo* info = new ProcessInfo(process, fd); | |
83 info->set_next(active_processes_); | |
84 active_processes_ = info; | |
85 } | |
86 | |
87 | |
88 static intptr_t LookupProcessExitFd(mx_handle_t process) { | |
89 MutexLocker locker(mutex_); | |
90 ProcessInfo* current = active_processes_; | |
91 while (current != NULL) { | |
92 if (current->process() == process) { | |
93 return current->fd(); | |
94 } | |
95 current = current->next(); | |
96 } | |
97 return 0; | |
98 } | |
99 | |
100 | |
101 static void RemoveProcess(mx_handle_t process) { | |
102 MutexLocker locker(mutex_); | |
103 ProcessInfo* prev = NULL; | |
104 ProcessInfo* current = active_processes_; | |
105 while (current != NULL) { | |
106 if (current->process() == process) { | |
107 if (prev == NULL) { | |
108 active_processes_ = current->next(); | |
109 } else { | |
110 prev->set_next(current->next()); | |
111 } | |
112 delete current; | |
113 return; | |
114 } | |
115 prev = current; | |
116 current = current->next(); | |
117 } | |
118 } | |
119 | |
120 private: | |
121 // Linked list of ProcessInfo objects for all active processes | |
122 // started from Dart code. | |
123 static ProcessInfo* active_processes_; | |
124 // Mutex protecting all accesses to the linked list of active | |
125 // processes. | |
126 static Mutex* mutex_; | |
127 | |
128 DISALLOW_ALLOCATION(); | |
129 DISALLOW_IMPLICIT_CONSTRUCTORS(ProcessInfoList); | |
130 }; | |
131 | |
132 ProcessInfo* ProcessInfoList::active_processes_ = NULL; | |
133 Mutex* ProcessInfoList::mutex_ = new Mutex(); | |
134 | |
135 // The exit code handler sets up a separate thread which waits for child | |
136 // processes to terminate. That separate thread can then get the exit code from | |
137 // processes that have exited and communicate it to Dart through the | |
138 // event loop. | |
139 class ExitCodeHandler { | |
140 public: | |
141 // Notify the ExitCodeHandler that another process exists. | |
142 static void Start() { | |
143 // Multiple isolates could be starting processes at the same | |
144 // time. Make sure that only one ExitCodeHandler thread exists. | |
145 MonitorLocker locker(monitor_); | |
146 if (running_) { | |
147 return; | |
148 } | |
149 | |
150 LOG_INFO("ExitCodeHandler Starting\n"); | |
151 | |
152 mx_status_t status = mx_socket_create(0, &interrupt_in_, &interrupt_out_); | |
153 if (status < 0) { | |
154 FATAL1("Failed to create exit code handler interrupt socket: %s\n", | |
155 mx_status_get_string(status)); | |
156 } | |
157 | |
158 // Start thread that handles process exits when wait returns. | |
159 intptr_t result = Thread::Start( | |
160 ExitCodeHandlerEntry, static_cast<uword>(interrupt_out_)); | |
161 if (result != 0) { | |
162 FATAL1("Failed to start exit code handler worker thread %ld", result); | |
163 } | |
164 | |
165 running_ = true; | |
166 } | |
167 | |
168 static void Add(mx_handle_t process) { | |
169 MonitorLocker locker(monitor_); | |
170 LOG_INFO("ExitCodeHandler Adding Process: %ld\n", process); | |
171 SendMessage(Message::kAdd, process); | |
172 } | |
173 | |
174 static void Terminate() { | |
175 MonitorLocker locker(monitor_); | |
176 if (!running_) { | |
177 return; | |
178 } | |
179 running_ = false; | |
180 | |
181 LOG_INFO("ExitCodeHandler Terminating\n"); | |
182 SendMessage(Message::kShutdown, MX_HANDLE_INVALID); | |
183 | |
184 while (!terminate_done_) { | |
185 monitor_->Wait(Monitor::kNoTimeout); | |
186 } | |
187 mx_handle_close(interrupt_in_); | |
188 LOG_INFO("ExitCodeHandler Terminated\n"); | |
189 } | |
190 | |
191 private: | |
192 class Message { | |
193 public: | |
194 enum MessageId { | |
195 kAdd, | |
196 kShutdown, | |
197 }; | |
198 MessageId id; | |
rmacnak
2016/12/12 18:18:20
id -> type/kind/command
zra
2016/12/13 19:07:50
Done.
| |
199 mx_handle_t handle; | |
200 }; | |
201 | |
202 static void SendMessage(Message::MessageId id, mx_handle_t handle) { | |
203 Message msg; | |
204 msg.id = id; | |
205 msg.handle = handle; | |
206 size_t actual; | |
207 mx_status_t status = | |
208 mx_socket_write(interrupt_in_, 0, &msg, sizeof(msg), &actual); | |
209 if (status < 0) { | |
210 FATAL1("Write to exit handler interrupt handle failed: %s\n", | |
211 mx_status_get_string(status)); | |
212 } | |
213 ASSERT(actual == sizeof(msg)); | |
214 } | |
215 | |
216 // Entry point for the separate exit code handler thread started by | |
217 // the ExitCodeHandler. | |
218 static void ExitCodeHandlerEntry(uword param) { | |
219 LOG_INFO("ExitCodeHandler Entering ExitCodeHandler thread\n"); | |
220 item_capacity_ = 16; | |
221 items_ = reinterpret_cast<mx_wait_item_t*>( | |
222 malloc(item_capacity_ * sizeof(*items_))); | |
223 items_to_remove_ = reinterpret_cast<intptr_t*>( | |
224 malloc(item_capacity_ * sizeof(*items_to_remove_))); | |
225 | |
226 // The interrupt handle is fixed to the first entry. | |
227 items_[0].handle = interrupt_out_; | |
228 items_[0].waitfor = MX_SOCKET_READABLE | MX_SOCKET_PEER_CLOSED; | |
229 items_[0].pending = MX_SIGNAL_NONE; | |
230 item_count_ = 1; | |
231 | |
232 while (!do_shutdown_) { | |
233 LOG_INFO("ExitCodeHandler Calling mx_handle_wait_many: %ld items\n", | |
234 item_count_); | |
235 mx_status_t status = | |
236 mx_handle_wait_many(items_, item_count_, MX_TIME_INFINITE); | |
237 if (status < 0) { | |
238 FATAL1("Exit code handler handle wait failed: %s\n", | |
239 mx_status_get_string(status)); | |
240 } | |
241 LOG_INFO("ExitCodeHandler mx_handle_wait_many returned\n"); | |
242 | |
243 bool have_interrupt = false; | |
244 intptr_t remove_count = 0; | |
245 for (intptr_t i = 0; i < item_count_; i++) { | |
246 if (items_[i].pending == MX_SIGNAL_NONE) { | |
247 continue; | |
248 } | |
249 if (i == 0) { | |
250 LOG_INFO("ExitCodeHandler thread saw interrupt\n"); | |
251 have_interrupt = true; | |
252 continue; | |
253 } | |
254 ASSERT(items_[i].waitfor == MX_TASK_TERMINATED); | |
255 ASSERT((items_[i].pending & MX_TASK_TERMINATED) != 0); | |
256 LOG_INFO("ExitCodeHandler signal for %ld\n", items_[i].handle); | |
257 SendProcessStatus(items_[i].handle); | |
258 items_to_remove_[remove_count++] = i; | |
259 } | |
260 for (intptr_t i = 0; i < remove_count; i++) { | |
261 RemoveItem(items_to_remove_[i]); | |
262 } | |
263 if (have_interrupt) { | |
264 HandleInterruptMsg(); | |
265 } | |
266 } | |
267 | |
268 LOG_INFO("ExitCodeHandler thread shutting down\n"); | |
269 mx_handle_close(interrupt_out_); | |
270 free(items_); | |
271 items_ = NULL; | |
272 free(items_to_remove_); | |
273 items_to_remove_ = NULL; | |
274 item_count_ = 0; | |
275 item_capacity_ = 0; | |
276 | |
277 terminate_done_ = true; | |
278 monitor_->Notify(); | |
279 } | |
280 | |
281 static void SendProcessStatus(mx_handle_t process) { | |
282 LOG_INFO("ExitCodeHandler thread getting process status: %ld\n", process); | |
283 mx_info_process_t proc_info; | |
284 mx_status_t status = mx_object_get_info( | |
285 process, MX_INFO_PROCESS, &proc_info, sizeof(proc_info), NULL, NULL); | |
286 if (status < 0) { | |
287 FATAL1("mx_object_get_info failed on process handle: %s\n", | |
288 mx_status_get_string(status)); | |
289 } | |
290 | |
291 const int return_code = proc_info.return_code; | |
292 status = mx_handle_close(process); | |
293 if (status < 0) { | |
294 FATAL1("Failed to close process handle: %s\n", | |
295 mx_status_get_string(status)); | |
296 } | |
297 LOG_INFO("ExitCodeHandler thread process %ld exited with %d\n", | |
298 process, return_code); | |
299 | |
300 const intptr_t exit_code_fd = ProcessInfoList::LookupProcessExitFd(process); | |
301 LOG_INFO("ExitCodeHandler thread sending %ld code %d on fd %ld\n", | |
302 process, return_code, exit_code_fd); | |
303 if (exit_code_fd != 0) { | |
304 int exit_message[2]; | |
305 exit_message[0] = return_code; | |
306 exit_message[1] = 0; // Do not negate return_code. | |
307 intptr_t result = FDUtils::WriteToBlocking( | |
308 exit_code_fd, &exit_message, sizeof(exit_message)); | |
309 ASSERT((result == -1) || (result == sizeof(exit_code_fd))); | |
310 if ((result == -1) && (errno != EPIPE)) { | |
311 int err = errno; | |
312 FATAL1("Failed to write exit code to pipe: %d\n", err); | |
313 } | |
314 LOG_INFO("ExitCodeHandler thread wrote %ld bytes to fd %ld\n", | |
315 result, exit_code_fd); | |
316 LOG_INFO("ExitCodeHandler thread removing process %ld from list\n", | |
317 process); | |
318 ProcessInfoList::RemoveProcess(process); | |
319 } | |
320 } | |
321 | |
322 static void HandleInterruptMsg() { | |
323 ASSERT(items_[0].handle == interrupt_out_); | |
324 ASSERT(items_[0].waitfor == MX_SOCKET_READABLE); | |
325 ASSERT((items_[0].pending & MX_SOCKET_READABLE) != 0); | |
326 while (true) { | |
327 Message msg; | |
328 size_t actual = 0; | |
329 LOG_INFO("ExitCodeHandler thread reading interrupt message\n"); | |
330 mx_status_t status = | |
331 mx_socket_read(interrupt_out_, 0, &msg, sizeof(msg), &actual); | |
332 if (status == ERR_SHOULD_WAIT) { | |
333 LOG_INFO("ExitCodeHandler thread done reading interrupt messages\n"); | |
334 return; | |
335 } | |
336 if (status < 0) { | |
337 FATAL1("Failed to read exit handler interrupt handle: %s\n", | |
338 mx_status_get_string(status)); | |
339 } | |
340 if (actual < sizeof(msg)) { | |
341 FATAL1("Short read from exit handler interrupt handle: %ld\n", | |
342 actual); | |
343 } | |
344 switch (msg.id) { | |
345 case Message::kShutdown: | |
346 LOG_INFO("ExitCodeHandler thread got shutdown message\n"); | |
347 do_shutdown_ = true; | |
348 break; | |
349 case Message::kAdd: | |
350 LOG_INFO("ExitCodeHandler thread got add message: %ld\n", msg.handle); | |
351 AddItem(msg.handle); | |
352 break; | |
353 } | |
354 } | |
355 } | |
356 | |
357 static void AddItem(mx_handle_t h) { | |
358 if (item_count_ == item_capacity_) { | |
359 item_capacity_ = item_capacity_ + (item_capacity_ >> 1); | |
360 items_ = reinterpret_cast<mx_wait_item_t*>( | |
361 realloc(items_, item_capacity_)); | |
362 items_to_remove_ = reinterpret_cast<intptr_t*>( | |
363 realloc(items_to_remove_, item_capacity_)); | |
364 } | |
365 LOG_INFO("ExitCodeHandler thread adding item %ld at %ld\n", h, item_count_); | |
366 items_[item_count_].handle = h; | |
367 items_[item_count_].waitfor = MX_TASK_TERMINATED; | |
368 items_[item_count_].pending = MX_SIGNAL_NONE; | |
369 item_count_++; | |
370 } | |
371 | |
372 static void RemoveItem(intptr_t idx) { | |
373 LOG_INFO("ExitCodeHandler thread removing item %ld at %ld\n", | |
374 items_[idx].handle, idx); | |
375 ASSERT(idx != 0); | |
376 const intptr_t last = item_count_ - 1; | |
377 items_[idx].handle = MX_HANDLE_INVALID; | |
378 items_[idx].waitfor = MX_SIGNAL_NONE; | |
379 items_[idx].pending = MX_SIGNAL_NONE; | |
380 if (idx != last) { | |
381 items_[idx] = items_[last]; | |
382 } | |
383 item_count_--; | |
384 } | |
385 | |
386 // Interrupt message pipe. | |
387 static mx_handle_t interrupt_in_; | |
388 static mx_handle_t interrupt_out_; | |
389 | |
390 // Accessed only by the ExitCodeHandler thread. | |
391 static mx_wait_item_t* items_; | |
392 static intptr_t* items_to_remove_; | |
393 static intptr_t item_count_; | |
394 static intptr_t item_capacity_; | |
395 | |
396 // Protected by monitor_. | |
397 static bool do_shutdown_; | |
398 static bool terminate_done_; | |
399 static bool running_; | |
400 static Monitor* monitor_; | |
401 | |
402 DISALLOW_ALLOCATION(); | |
403 DISALLOW_IMPLICIT_CONSTRUCTORS(ExitCodeHandler); | |
404 }; | |
405 | |
406 mx_handle_t ExitCodeHandler::interrupt_in_ = MX_HANDLE_INVALID; | |
407 mx_handle_t ExitCodeHandler::interrupt_out_ = MX_HANDLE_INVALID; | |
408 mx_wait_item_t* ExitCodeHandler::items_ = NULL; | |
409 intptr_t* ExitCodeHandler::items_to_remove_ = NULL; | |
410 intptr_t ExitCodeHandler::item_count_ = 0; | |
411 intptr_t ExitCodeHandler::item_capacity_ = 0; | |
412 | |
413 bool ExitCodeHandler::do_shutdown_ = false; | |
414 bool ExitCodeHandler::running_ = false; | |
415 bool ExitCodeHandler::terminate_done_ = false; | |
416 Monitor* ExitCodeHandler::monitor_ = new Monitor(); | |
417 | |
418 void Process::TerminateExitCodeHandler() { | |
419 ExitCodeHandler::Terminate(); | |
420 } | |
421 | |
24 | 422 |
25 intptr_t Process::CurrentProcessId() { | 423 intptr_t Process::CurrentProcessId() { |
26 UNIMPLEMENTED(); | 424 return static_cast<intptr_t>(getpid()); |
27 return 0; | |
28 } | 425 } |
29 | 426 |
30 intptr_t Process::SetSignalHandler(intptr_t signal) { | |
31 UNIMPLEMENTED(); | |
32 return -1; | |
33 } | |
34 | |
35 | |
36 void Process::ClearSignalHandler(intptr_t signal) { | |
37 UNIMPLEMENTED(); | |
38 } | |
39 | 427 |
40 bool Process::Wait(intptr_t pid, | 428 bool Process::Wait(intptr_t pid, |
41 intptr_t in, | 429 intptr_t in, |
42 intptr_t out, | 430 intptr_t out, |
43 intptr_t err, | 431 intptr_t err, |
44 intptr_t exit_event, | 432 intptr_t exit_event, |
45 ProcessResult* result) { | 433 ProcessResult* result) { |
46 UNIMPLEMENTED(); | 434 UNIMPLEMENTED(); |
47 return false; | 435 return false; |
48 } | 436 } |
49 | 437 |
438 | |
50 bool Process::Kill(intptr_t id, int signal) { | 439 bool Process::Kill(intptr_t id, int signal) { |
51 UNIMPLEMENTED(); | 440 UNIMPLEMENTED(); |
52 return false; | 441 return false; |
53 } | 442 } |
54 | 443 |
444 | |
445 class ProcessStarter { | |
446 public: | |
447 ProcessStarter(const char* path, | |
448 char* arguments[], | |
449 intptr_t arguments_length, | |
450 const char* working_directory, | |
451 char* environment[], | |
452 intptr_t environment_length, | |
453 ProcessStartMode mode, | |
454 intptr_t* in, | |
455 intptr_t* out, | |
456 intptr_t* err, | |
457 intptr_t* id, | |
458 intptr_t* exit_event, | |
459 char** os_error_message) | |
460 : path_(path), | |
461 working_directory_(working_directory), | |
462 mode_(mode), | |
463 in_(in), | |
464 out_(out), | |
465 err_(err), | |
466 id_(id), | |
467 exit_event_(exit_event), | |
468 os_error_message_(os_error_message) { | |
469 LOG_INFO("ProcessStarter: ctor %s with %ld args, mode = %d\n", | |
470 path, arguments_length, mode); | |
471 | |
472 read_in_ = -1; | |
473 read_err_ = -1; | |
474 write_out_ = -1; | |
475 | |
476 program_arguments_ = reinterpret_cast<char**>(Dart_ScopeAllocate( | |
477 (arguments_length + 2) * sizeof(*program_arguments_))); | |
478 program_arguments_[0] = const_cast<char*>(path_); | |
479 for (int i = 0; i < arguments_length; i++) { | |
480 program_arguments_[i + 1] = arguments[i]; | |
481 } | |
482 program_arguments_[arguments_length + 1] = NULL; | |
483 program_arguments_count_ = arguments_length + 1; | |
484 | |
485 program_environment_ = NULL; | |
486 if (environment != NULL) { | |
487 program_environment_ = reinterpret_cast<char**>(Dart_ScopeAllocate( | |
488 (environment_length + 1) * sizeof(*program_environment_))); | |
489 for (int i = 0; i < environment_length; i++) { | |
490 program_environment_[i] = environment[i]; | |
491 } | |
492 program_environment_[environment_length] = NULL; | |
493 } | |
494 | |
495 binary_vmo_ = MX_HANDLE_INVALID; | |
496 launchpad_ = NULL; | |
497 } | |
498 | |
499 ~ProcessStarter() { | |
500 if (binary_vmo_ != MX_HANDLE_INVALID) { | |
501 mx_handle_close(binary_vmo_); | |
502 } | |
503 if (launchpad_ != NULL) { | |
504 launchpad_destroy(launchpad_); | |
505 } | |
506 if (read_in_ != -1) { | |
507 close(read_in_); | |
508 } | |
509 if (read_err_ != -1) { | |
510 close(read_err_); | |
511 } | |
512 if (write_out_ != -1) { | |
513 close(write_out_); | |
514 } | |
515 } | |
516 | |
517 int Start() { | |
518 LOG_INFO("ProcessStarter: Start()\n"); | |
519 int exit_pipe_fds[2]; | |
520 intptr_t result = NO_RETRY_EXPECTED(pipe(exit_pipe_fds)); | |
521 if (result != 0) { | |
522 *os_error_message_ = DartUtils::ScopedCopyCString( | |
523 "Failed to create exit code pipe for process start."); | |
524 return result; | |
525 } | |
526 LOG_INFO("ProcessStarter: Start() set up exit_pipe_fds (%d, %d)\n", | |
527 exit_pipe_fds[0], exit_pipe_fds[1]); | |
528 | |
529 mx_status_t status = SetupLaunchpad(); | |
530 if (status != NO_ERROR) { | |
531 close(exit_pipe_fds[0]); | |
532 close(exit_pipe_fds[1]); | |
533 return status; | |
534 } | |
535 | |
536 LOG_INFO("ProcessStarter: Start() Calling launchpad_start\n"); | |
537 mx_handle_t process = launchpad_start(launchpad_); | |
538 launchpad_destroy(launchpad_); | |
539 launchpad_ = NULL; | |
540 if (process < 0) { | |
541 LOG_INFO("ProcessStarter: Start() launchpad_start failed\n"); | |
542 const intptr_t kMaxMessageSize = 256; | |
543 close(exit_pipe_fds[0]); | |
544 close(exit_pipe_fds[1]); | |
545 char* message = DartUtils::ScopedCString(kMaxMessageSize); | |
546 snprintf(message, kMaxMessageSize, "%s:%d: launchpad_start failed: %s\n", | |
547 __FILE__, __LINE__, mx_status_get_string(process)); | |
548 *os_error_message_ = message; | |
549 return process; | |
550 } | |
551 | |
552 LOG_INFO("ProcessStarter: Start() adding %ld to list with exit_pipe %d\n", | |
553 process, exit_pipe_fds[1]); | |
554 ProcessInfoList::AddProcess(process, exit_pipe_fds[1]); | |
555 ExitCodeHandler::Start(); | |
556 ExitCodeHandler::Add(process); | |
557 | |
558 *id_ = process; | |
559 FDUtils::SetNonBlocking(read_in_); | |
560 *in_ = read_in_; | |
561 read_in_ = -1; | |
562 FDUtils::SetNonBlocking(read_err_); | |
563 *err_ = read_err_; | |
564 read_err_ = -1; | |
565 FDUtils::SetNonBlocking(write_out_); | |
566 *out_ = write_out_; | |
567 write_out_ = -1; | |
568 FDUtils::SetNonBlocking(exit_pipe_fds[0]); | |
569 *exit_event_ = exit_pipe_fds[0]; | |
570 return 0; | |
571 } | |
572 | |
573 private: | |
574 #define CHECK_FOR_ERROR(status, msg) \ | |
575 if (status < 0) { \ | |
576 const intptr_t kMaxMessageSize = 256; \ | |
577 char* message = DartUtils::ScopedCString(kMaxMessageSize); \ | |
578 snprintf(message, kMaxMessageSize, "%s:%d: %s: %s\n", \ | |
579 __FILE__, __LINE__, msg, mx_status_get_string(status)); \ | |
580 *os_error_message_ = message; \ | |
581 return status; \ | |
582 } | |
583 | |
584 mx_status_t SetupLaunchpad() { | |
585 mx_handle_t binary_vmo = launchpad_vmo_from_file(path_); | |
586 CHECK_FOR_ERROR(binary_vmo, "launchpad_vmo_from_file"); | |
587 binary_vmo_ = binary_vmo; | |
588 | |
589 launchpad_t* lp; | |
590 mx_status_t status; | |
591 | |
592 status = launchpad_create(0, program_arguments_[0], &lp); | |
593 CHECK_FOR_ERROR(status, "launchpad_create"); | |
594 launchpad_ = lp; | |
595 | |
596 status = launchpad_arguments( | |
597 lp, program_arguments_count_, program_arguments_); | |
598 CHECK_FOR_ERROR(status, "launchpad_arguments"); | |
599 | |
600 status = launchpad_environ(lp, program_environment_); | |
601 CHECK_FOR_ERROR(status, "launchpad_environ"); | |
602 | |
603 status = launchpad_clone_mxio_root(lp); | |
604 CHECK_FOR_ERROR(status, "launchpad_clone_mxio_root"); | |
605 | |
606 status = launchpad_add_pipe(lp, &write_out_, 0); | |
607 CHECK_FOR_ERROR(status, "launchpad_add_pipe"); | |
608 | |
609 status = launchpad_add_pipe(lp, &read_in_, 1); | |
610 CHECK_FOR_ERROR(status, "launchpad_add_pipe"); | |
611 | |
612 status = launchpad_add_pipe(lp, &read_err_, 2); | |
613 CHECK_FOR_ERROR(status, "launchpad_add_pipe"); | |
614 | |
615 status = launchpad_add_vdso_vmo(lp); | |
616 CHECK_FOR_ERROR(status, "launchpad_add_vdso_vmo"); | |
617 | |
618 status = launchpad_elf_load(lp, binary_vmo); | |
619 CHECK_FOR_ERROR(status, "launchpad_elf_load"); | |
620 binary_vmo_ = MX_HANDLE_INVALID; // launchpad_elf_load consumes the handle. | |
621 | |
622 status = launchpad_load_vdso(lp, MX_HANDLE_INVALID); | |
623 CHECK_FOR_ERROR(status, "launchpad_load_vdso"); | |
624 | |
625 status = launchpad_clone_mxio_cwd(lp); | |
626 CHECK_FOR_ERROR(status, "launchpad_clone_mxio_cwd"); | |
rmacnak
2016/12/12 18:18:21
Add a TODO to use the supplied working directory w
zra
2016/12/13 19:07:50
Done.
| |
627 | |
628 return NO_ERROR; | |
629 } | |
630 | |
631 #undef CHECK_FOR_ERROR | |
632 | |
633 int read_in_; // Pipe for stdout to child process. | |
634 int read_err_; // Pipe for stderr to child process. | |
635 int write_out_; // Pipe for stdin to child process. | |
636 | |
637 char** program_arguments_; | |
638 intptr_t program_arguments_count_; | |
639 char** program_environment_; | |
640 | |
641 mx_handle_t binary_vmo_; | |
642 launchpad_t* launchpad_; | |
643 | |
644 const char* path_; | |
645 const char* working_directory_; | |
646 ProcessStartMode mode_; | |
647 intptr_t* in_; | |
648 intptr_t* out_; | |
649 intptr_t* err_; | |
650 intptr_t* id_; | |
651 intptr_t* exit_event_; | |
652 char** os_error_message_; | |
653 | |
654 DISALLOW_ALLOCATION(); | |
655 DISALLOW_IMPLICIT_CONSTRUCTORS(ProcessStarter); | |
656 }; | |
657 | |
658 | |
55 int Process::Start(const char* path, | 659 int Process::Start(const char* path, |
56 char* arguments[], | 660 char* arguments[], |
57 intptr_t arguments_length, | 661 intptr_t arguments_length, |
58 const char* working_directory, | 662 const char* working_directory, |
59 char* environment[], | 663 char* environment[], |
60 intptr_t environment_length, | 664 intptr_t environment_length, |
61 ProcessStartMode mode, | 665 ProcessStartMode mode, |
62 intptr_t* in, | 666 intptr_t* in, |
63 intptr_t* out, | 667 intptr_t* out, |
64 intptr_t* err, | 668 intptr_t* err, |
65 intptr_t* id, | 669 intptr_t* id, |
66 intptr_t* exit_event, | 670 intptr_t* exit_event, |
67 char** os_error_message) { | 671 char** os_error_message) { |
672 if (mode != kNormal) { | |
673 *os_error_message = DartUtils::ScopedCopyCString( | |
674 "Only ProcessStartMode.NORMAL is supported on this platform"); | |
675 return -1; | |
676 } | |
677 ProcessStarter starter(path, arguments, arguments_length, working_directory, | |
678 environment, environment_length, mode, in, out, err, | |
679 id, exit_event, os_error_message); | |
680 return starter.Start(); | |
681 } | |
682 | |
683 | |
684 intptr_t Process::SetSignalHandler(intptr_t signal) { | |
68 UNIMPLEMENTED(); | 685 UNIMPLEMENTED(); |
69 return -1; | 686 return -1; |
70 } | 687 } |
71 | 688 |
689 | |
690 void Process::ClearSignalHandler(intptr_t signal) { | |
691 UNIMPLEMENTED(); | |
692 } | |
693 | |
72 } // namespace bin | 694 } // namespace bin |
73 } // namespace dart | 695 } // namespace dart |
74 | 696 |
75 #endif // defined(TARGET_OS_FUCHSIA) | 697 #endif // defined(TARGET_OS_FUCHSIA) |
76 | 698 |
77 #endif // !defined(DART_IO_DISABLED) | 699 #endif // !defined(DART_IO_DISABLED) |
OLD | NEW |