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

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

Issue 9307003: Changes to the process implementation. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Close the wake-up handle at the right time. Created 8 years, 10 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
« runtime/bin/process_linux.cc ('K') | « runtime/bin/process_macos.cc ('k') | no next file » | 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) 2012, 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 <process.h> 5 #include <process.h>
6 6
7 #include "bin/builtin.h" 7 #include "bin/builtin.h"
8 #include "bin/process.h" 8 #include "bin/process.h"
9 #include "bin/eventhandler.h" 9 #include "bin/eventhandler.h"
10 #include "bin/thread.h"
10 #include "platform/globals.h" 11 #include "platform/globals.h"
11 12
12 static const int kReadHandle = 0; 13 static const int kReadHandle = 0;
13 static const int kWriteHandle = 1; 14 static const int kWriteHandle = 1;
14 15
16
17 // ProcessInfo is used to map a process id to the process handle and
18 // the pipe used to communicate the exit code of the process to Dart.
19 // ProcessInfo objects are kept in the static singly-linked
20 // ProcessInfoList.
15 class ProcessInfo { 21 class ProcessInfo {
16 public: 22 public:
17 ProcessInfo(DWORD process_id, HANDLE process_handle, HANDLE exit_pipe) 23 ProcessInfo(DWORD process_id, HANDLE process_handle, HANDLE exit_pipe)
18 : process_id_(process_id), 24 : process_id_(process_id),
19 process_handle_(process_handle), 25 process_handle_(process_handle),
20 exit_pipe_(exit_pipe) { } 26 exit_pipe_(exit_pipe) { }
21 27
22 intptr_t pid() { return process_id_; } 28 ~ProcessInfo() {
29 BOOL success = CloseHandle(process_handle_);
30 if (!success) {
31 FATAL("Failed to close process handle");
32 }
33 success = CloseHandle(exit_pipe_);
34 if (!success) {
35 FATAL("Failed to close process exit code pipe");
36 }
37 }
38
39 DWORD pid() { return process_id_; }
23 HANDLE process_handle() { return process_handle_; } 40 HANDLE process_handle() { return process_handle_; }
24 HANDLE exit_pipe() { return exit_pipe_; } 41 HANDLE exit_pipe() { return exit_pipe_; }
25 ProcessInfo* next() { return next_; } 42 ProcessInfo* next() { return next_; }
26 void set_next(ProcessInfo* next) { next_ = next; } 43 void set_next(ProcessInfo* next) { next_ = next; }
27 44
28 private: 45 private:
29 DWORD process_id_; // Process id. 46 DWORD process_id_; // Process id.
30 HANDLE process_handle_; // Process handle. 47 HANDLE process_handle_; // Process handle.
31 HANDLE exit_pipe_; // File descriptor for pipe to report exit code. 48 HANDLE exit_pipe_; // File descriptor for pipe to report exit code.
32 ProcessInfo* next_; 49 ProcessInfo* next_;
33 }; 50 };
34 51
35 52
36 ProcessInfo* active_processes = NULL; 53 // Singly-linked list of ProcessInfo objects for all active processes
37 54 // started from Dart.
38 55 class ProcessInfoList {
39 static void AddProcess(ProcessInfo* process) { 56 public:
40 process->set_next(active_processes); 57 static void AddProcess(DWORD pid, HANDLE handle, HANDLE pipe) {
41 active_processes = process; 58 MutexLocker locker(&mutex_);
42 } 59 ProcessInfo* info = new ProcessInfo(pid, handle, pipe);
43 60 info->set_next(active_processes_);
44 61 active_processes_ = info;
45 static ProcessInfo* LookupProcess(intptr_t pid) { 62 ++number_of_processes_;
46 ProcessInfo* current = active_processes; 63 }
47 while (current != NULL) { 64
48 if (current->pid() == pid) { 65 static bool LookupProcess(DWORD pid, HANDLE* handle, HANDLE* pipe) {
49 return current; 66 MutexLocker locker(&mutex_);
50 } 67 ProcessInfo* current = active_processes_;
51 current = current->next(); 68 while (current != NULL) {
52 } 69 if (current->pid() == pid) {
53 return NULL; 70 *handle = current->process_handle();
54 } 71 *pipe = current->exit_pipe();
55 72 return true;
56 73 }
57 static void RemoveProcess(intptr_t pid) { 74 current = current->next();
58 ProcessInfo* prev = NULL; 75 }
59 ProcessInfo* current = active_processes; 76 return false;
60 while (current != NULL) { 77 }
61 if (current->pid() == pid) { 78
62 if (prev == NULL) { 79 static DWORD LookupProcessByHandle(HANDLE handle, DWORD* pid, HANDLE* pipe) {
63 active_processes = current->next(); 80 MutexLocker locker(&mutex_);
81 ProcessInfo* current = active_processes_;
82 while (current != NULL) {
83 if (current->process_handle() == handle) {
84 *pid = current->pid();
85 *pipe = current->exit_pipe();
86 return true;
87 }
88 current = current->next();
89 }
90 return false;
91 }
92
93 static void RemoveProcess(DWORD pid) {
94 MutexLocker locker(&mutex_);
95 ProcessInfo* prev = NULL;
96 ProcessInfo* current = active_processes_;
97 while (current != NULL) {
98 if (current->pid() == pid) {
99 if (prev == NULL) {
100 active_processes_ = current->next();
101 } else {
102 prev->set_next(current->next());
103 }
104 delete current;
105 --number_of_processes_;
106 return;
107 }
108 prev = current;
109 current = current->next();
110 }
111 }
112
113 static void GetHandleArray(HANDLE** handles,
114 DWORD* number_of_handles,
115 intptr_t prefix_size) {
116 ASSERT(prefix_size >= 0);
117 *number_of_handles = prefix_size + number_of_processes_;
118 *handles = new HANDLE[*number_of_handles];
119 intptr_t i = prefix_size;
120 ProcessInfo* current = active_processes_;
121 while (current != NULL) {
122 (*handles)[i++] = current->process_handle();
123 current = current->next();
124 }
125 ASSERT(i == *number_of_handles);
126 }
127
128 private:
129 // Number of processes currently in the list.
130 static intptr_t number_of_processes_;
131 // Linked list of ProcessInfo objects for all active processes
132 // started from Dart code.
133 static ProcessInfo* active_processes_;
134 // Mutex protecting all accesses to the linked list of active
135 // processes.
136 static dart::Mutex mutex_;
137 };
138
139
140 intptr_t ProcessInfoList::number_of_processes_ = 0;
141 ProcessInfo* ProcessInfoList::active_processes_ = NULL;
142 dart::Mutex ProcessInfoList::mutex_;
143
144
145 // The exit code handler sets up a separate thread which is waiting
146 // for Dart process termination and process start. When a process
147 // terminates the exit code is extracted and communicated to Dart
148 // through the event loop.
149 class ExitCodeHandler {
150 public:
151 // Ensure that the ExitCodeHandler has been initialized.
152 static bool EnsureInitialized() {
153 // Multiple isolates could be starting processes at the same
154 // time. Make sure that only one of them initializes the
155 // ExitCodeHandler.
156 MutexLocker locker(&mutex_);
157 if (initialized_) {
158 return true;
159 }
160
161 // Allocate an event object to be signaled when new processes are
162 // added.
163 wake_up_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
164 if (wake_up_event_ == NULL) {
165 return false;
166 }
167
168 // Start thread that waits for the process-addition handle as well
169 // as all process handles for all active processes.
170 new dart::Thread(ExitCodeHandlerEntry,
171 reinterpret_cast<uword>(wake_up_event_));
172
173 // Thread started and the ExitCodeHandler is initialized.
174 initialized_ = true;
175 return true;
176 }
177
178 static void Shutdown() {
179 MutexLocker locker(&mutex_);
180 if (!initialized_) {
181 return;
182 }
183 terminating_ = true;
184 BOOL success = SetEvent(wake_up_event_);
185 if (!success) {
186 FATAL("Failed to set wake-up event for exit code handler shutdown");
187 }
188 }
189
190 static void ProcessAdded() {
191 MutexLocker locker(&mutex_);
192 BOOL success = SetEvent(wake_up_event_);
193 if (!success) {
194 FATAL("Failed to set the process addition wake-up event");
195 }
196 }
197
198 static bool Terminating() {
199 MutexLocker locker(&mutex_);
200 return terminating_;
201 }
202
203 private:
204 // Entry point for the exit code handler thread started by the
205 // ExitCodeHandler.
206 static void ExitCodeHandlerEntry(uword param) {
207 while (true) {
208 // Get the list of handles to wait for. Allocate a prefix of one
209 // extra handle for the 'process added' event object.
210 HANDLE* handles;
211 DWORD number_of_handles;
212 intptr_t prefix_size = 1;
213 ProcessInfoList::GetHandleArray(&handles,
214 &number_of_handles,
215 prefix_size);
216 HANDLE wake_up_event = reinterpret_cast<HANDLE>(param);
Søren Gjesse 2012/02/01 07:39:17 Maybe move he line HANDLE wake_up_event ... out
Mads Ager (google) 2012/02/01 09:08:57 Done.
217 handles[0] = wake_up_event;
218
219 // Wait for the handles.
220 DWORD result =
221 WaitForMultipleObjects(number_of_handles, handles, FALSE, INFINITE);
222 if (result == WAIT_FAILED) {
223 FATAL("Failed to wait for multiple objects for exit code handling");
224 }
225
226 if (result == 0) {
227 // If the result is 0 the thread woke up because of process
228 // addition or because the ExitCodeHandler is being shut down.
229 if (ExitCodeHandler::Terminating()) {
230 BOOL success = CloseHandle(wake_up_event_);
231 if (!success) {
232 FATAL("Failed to clse the wake-up event handle");
233 }
234 return;
235 }
236 // This was an addition, we reset the wake up event so we can
237 // get signalled on further additions.
238 BOOL success = ResetEvent(wake_up_event);
239 if (!success) {
240 FATAL("Failed to reset process addition wake-up event");
241 }
64 } else { 242 } else {
65 prev->set_next(current->next()); 243 // The result is the index of the process that was
66 } 244 // signalled. Get its exit code and communicate it to Dart.
67 delete current; 245 int exit_code;
68 return; 246 BOOL ok = GetExitCodeProcess(handles[result],
69 } 247 reinterpret_cast<DWORD*>(&exit_code));
70 prev = current; 248 if (!ok) {
71 current = current->next(); 249 FATAL1("GetExitCodeProcess failed %d\n", GetLastError());
72 } 250 }
73 } 251 int negative = 0;
252 if (exit_code < 0) {
253 exit_code = abs(exit_code);
254 negative = 1;
255 }
256
257 DWORD pid;
258 HANDLE exit_pipe;
259 bool success = ProcessInfoList::LookupProcessByHandle(handles[result],
260 &pid,
261 &exit_pipe);
262 if (!success) {
263 FATAL("Failed to lookup pid and exit pipe from process handle");
264 }
265 int message[3] = { exit_code, negative };
Søren Gjesse 2012/02/01 07:39:17 3 -> 2.
Mads Ager (google) 2012/02/01 09:08:57 Whoops. Good catch!
266 DWORD written;
267 ok = WriteFile(exit_pipe, message, sizeof(message), &written, NULL);
268 if (!ok || written != sizeof(message)) {
269 FATAL1("WriteFile to process exit code pipe failed %d\n",
270 GetLastError());
271 }
272 ProcessInfoList::RemoveProcess(pid);
273 }
274 delete[] handles;
275 }
276 }
277
278 static dart::Mutex mutex_;
279 static bool initialized_;
280 static bool terminating_;
281 static HANDLE wake_up_event_;
282 };
283
284
285 dart::Mutex ExitCodeHandler::mutex_;
286 bool ExitCodeHandler::initialized_ = false;
287 bool ExitCodeHandler::terminating_ = false;
288 HANDLE ExitCodeHandler::wake_up_event_ = 0;
74 289
75 290
76 // Types of pipes to create. 291 // Types of pipes to create.
77 enum NamedPipeType { 292 enum NamedPipeType {
78 kInheritRead, 293 kInheritRead,
79 kInheritWrite, 294 kInheritWrite,
80 kInheritNone 295 kInheritNone
81 }; 296 };
82 297
83 298
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { 409 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
195 fprintf(stderr, "FormatMessage failed %d\n", GetLastError()); 410 fprintf(stderr, "FormatMessage failed %d\n", GetLastError());
196 } 411 }
197 snprintf(os_error_message, os_error_message_len, "OS Error %d", error_code); 412 snprintf(os_error_message, os_error_message_len, "OS Error %d", error_code);
198 } 413 }
199 os_error_message[os_error_message_len - 1] = '\0'; 414 os_error_message[os_error_message_len - 1] = '\0';
200 return error_code; 415 return error_code;
201 } 416 }
202 417
203 418
204 static unsigned int __stdcall TerminationWaitThread(void* args) {
205 ProcessInfo* process = reinterpret_cast<ProcessInfo*>(args);
206 WaitForSingleObject(process->process_handle(), INFINITE);
207 int exit_code;
208 BOOL ok = GetExitCodeProcess(process->process_handle(),
209 reinterpret_cast<DWORD*>(&exit_code));
210 if (!ok) {
211 fprintf(stderr, "GetExitCodeProcess failed %d\n", GetLastError());
212 }
213 int negative = 0;
214 if (exit_code < 0) {
215 exit_code = abs(exit_code);
216 negative = 1;
217 }
218 int message[3] = { process->pid(), exit_code, negative };
219 DWORD written;
220 ok = WriteFile(
221 process->exit_pipe(), message, sizeof(message), &written, NULL);
222 if (!ok || written != sizeof(message)) {
223 fprintf(stderr, "WriteFile failed %d\n", GetLastError());
224 }
225 return 0;
226 }
227
228
229 int Process::Start(const char* path, 419 int Process::Start(const char* path,
230 char* arguments[], 420 char* arguments[],
231 intptr_t arguments_length, 421 intptr_t arguments_length,
232 const char* working_directory, 422 const char* working_directory,
233 intptr_t* in, 423 intptr_t* in,
234 intptr_t* out, 424 intptr_t* out,
235 intptr_t* err, 425 intptr_t* err,
236 intptr_t* id, 426 intptr_t* id,
237 intptr_t* exit_handler, 427 intptr_t* exit_handler,
238 char* os_error_message, 428 char* os_error_message,
239 int os_error_message_len) { 429 int os_error_message_len) {
430 // Ensure that the process exit handler thread has been started.
431 bool initialized = ExitCodeHandler::EnsureInitialized();
432 if (!initialized) {
433 int error_code = SetOsErrorMessage(os_error_message, os_error_message_len);
434 fprintf(stderr, "Failed to initialize ExitCodeHandler: %d\n", error_code);
435 return error_code;
436 }
437
240 HANDLE stdin_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; 438 HANDLE stdin_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
241 HANDLE stdout_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; 439 HANDLE stdout_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
242 HANDLE stderr_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; 440 HANDLE stderr_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
243 HANDLE exit_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; 441 HANDLE exit_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
244 442
245 // Generate unique pipe names for the four named pipes needed. 443 // Generate unique pipe names for the four named pipes needed.
246 char pipe_names[4][80]; 444 char pipe_names[4][80];
247 UUID uuid; 445 UUID uuid;
248 RPC_STATUS status = UuidCreateSequential(&uuid); 446 RPC_STATUS status = UuidCreateSequential(&uuid);
249 if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) { 447 if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) {
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
354 // Deallocate command-line string. 552 // Deallocate command-line string.
355 delete[] command_line; 553 delete[] command_line;
356 554
357 if (result == 0) { 555 if (result == 0) {
358 int error_code = SetOsErrorMessage(os_error_message, os_error_message_len); 556 int error_code = SetOsErrorMessage(os_error_message, os_error_message_len);
359 CloseProcessPipes( 557 CloseProcessPipes(
360 stdin_handles, stdout_handles, stderr_handles, exit_handles); 558 stdin_handles, stdout_handles, stderr_handles, exit_handles);
361 return error_code; 559 return error_code;
362 } 560 }
363 561
364 ProcessInfo* process = new ProcessInfo(process_info.dwProcessId, 562 ProcessInfoList::AddProcess(process_info.dwProcessId,
365 process_info.hProcess, 563 process_info.hProcess,
366 exit_handles[kWriteHandle]); 564 exit_handles[kWriteHandle]);
367 AddProcess(process); 565 ExitCodeHandler::ProcessAdded();
368
369 // TODO(sgjesse): Don't use a separate thread for waiting for each process to
370 // terminate.
371 uint32_t tid;
372 uintptr_t thread_handle =
373 _beginthreadex(NULL, 32 * 1024, TerminationWaitThread, process, 0, &tid);
374 if (thread_handle == -1) {
375 FATAL("Failed to start process termination wait thread");
376 }
377 566
378 // Connect the three std streams. 567 // Connect the three std streams.
379 FileHandle* stdin_handle = new FileHandle(stdin_handles[kWriteHandle]); 568 FileHandle* stdin_handle = new FileHandle(stdin_handles[kWriteHandle]);
380 CloseHandle(stdin_handles[kReadHandle]); 569 CloseHandle(stdin_handles[kReadHandle]);
381 FileHandle* stdout_handle = new FileHandle(stdout_handles[kReadHandle]); 570 FileHandle* stdout_handle = new FileHandle(stdout_handles[kReadHandle]);
382 CloseHandle(stdout_handles[kWriteHandle]); 571 CloseHandle(stdout_handles[kWriteHandle]);
383 FileHandle* stderr_handle = new FileHandle(stderr_handles[kReadHandle]); 572 FileHandle* stderr_handle = new FileHandle(stderr_handles[kReadHandle]);
384 CloseHandle(stderr_handles[kWriteHandle]); 573 CloseHandle(stderr_handles[kWriteHandle]);
385 FileHandle* exit_handle = new FileHandle(exit_handles[kReadHandle]); 574 FileHandle* exit_handle = new FileHandle(exit_handles[kReadHandle]);
386 *in = reinterpret_cast<intptr_t>(stdout_handle); 575 *in = reinterpret_cast<intptr_t>(stdout_handle);
387 *out = reinterpret_cast<intptr_t>(stdin_handle); 576 *out = reinterpret_cast<intptr_t>(stdin_handle);
388 *err = reinterpret_cast<intptr_t>(stderr_handle); 577 *err = reinterpret_cast<intptr_t>(stderr_handle);
389 *exit_handler = reinterpret_cast<intptr_t>(exit_handle); 578 *exit_handler = reinterpret_cast<intptr_t>(exit_handle);
390 579
391 CloseHandle(process_info.hThread); 580 CloseHandle(process_info.hThread);
392 581
393 // Return process id. 582 // Return process id.
394 *id = process->pid(); 583 *id = process_info.dwProcessId;
395 return 0; 584 return 0;
396 } 585 }
397 586
398 587
399 bool Process::Kill(intptr_t id) { 588 bool Process::Kill(intptr_t id) {
400 ProcessInfo* process = LookupProcess(id); 589 HANDLE process_handle;
401 ASSERT(process != NULL); 590 HANDLE exit_pipe;
402 if (process != NULL) { 591 bool success =
403 BOOL result = TerminateProcess(process->process_handle(), -1); 592 ProcessInfoList::LookupProcess(id, &process_handle, &exit_pipe);
404 if (result == 0) { 593 ASSERT(success);
405 return false; 594 BOOL result = TerminateProcess(process_handle, -1);
406 } 595 if (!result) {
596 return false;
407 } 597 }
408 return true; 598 return true;
409 } 599 }
410 600
411 601
412 void Process::Exit(intptr_t id) { 602 void Process::TerminateExitCodeHandler() {
413 RemoveProcess(id); 603 ExitCodeHandler::Shutdown();
414 } 604 }
OLDNEW
« runtime/bin/process_linux.cc ('K') | « runtime/bin/process_macos.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698