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

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: Update stable test binaries 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
« no previous file with comments | « runtime/bin/process_macos.cc ('k') | tools/testing/bin/linux/dart » ('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) 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 HANDLE wake_up_event = reinterpret_cast<HANDLE>(param);
208
209 while (true) {
210 // Get the list of handles to wait for. Allocate a prefix of one
211 // extra handle for the 'process added' event object.
212 HANDLE* handles;
213 DWORD number_of_handles;
214 intptr_t prefix_size = 1;
215 ProcessInfoList::GetHandleArray(&handles,
216 &number_of_handles,
217 prefix_size);
218 handles[0] = wake_up_event;
219
220 // TODO(1450): support more than 63 processes on Windows.
221 if (number_of_handles > MAXIMUM_WAIT_OBJECTS) {
222 FATAL1("Only %d processes supported on Windows at this point\n",
223 MAXIMUM_WAIT_OBJECTS - 1);
224 }
225
226 // Wait for the handles.
227 DWORD result =
228 WaitForMultipleObjects(number_of_handles, handles, FALSE, INFINITE);
229 if (result == WAIT_FAILED) {
230 FATAL("Failed to wait for multiple objects for exit code handling");
231 }
232
233 if (result == 0) {
234 // If the result is 0 the thread woke up because of process
235 // addition or because the ExitCodeHandler is being shut down.
236 if (ExitCodeHandler::Terminating()) {
237 BOOL success = CloseHandle(wake_up_event_);
238 if (!success) {
239 FATAL("Failed to clse the wake-up event handle");
240 }
241 return;
242 }
243 // This was an addition, we reset the wake up event so we can
244 // get signalled on further additions.
245 BOOL success = ResetEvent(wake_up_event);
246 if (!success) {
247 FATAL("Failed to reset process addition wake-up event");
248 }
64 } else { 249 } else {
65 prev->set_next(current->next()); 250 // The result is the index of the process that was
66 } 251 // signalled. Get its exit code and communicate it to Dart.
67 delete current; 252 int exit_code;
68 return; 253 BOOL ok = GetExitCodeProcess(handles[result],
69 } 254 reinterpret_cast<DWORD*>(&exit_code));
70 prev = current; 255 if (!ok) {
71 current = current->next(); 256 FATAL1("GetExitCodeProcess failed %d\n", GetLastError());
72 } 257 }
73 } 258 int negative = 0;
259 if (exit_code < 0) {
260 exit_code = abs(exit_code);
261 negative = 1;
262 }
263
264 DWORD pid;
265 HANDLE exit_pipe;
266 bool success = ProcessInfoList::LookupProcessByHandle(handles[result],
267 &pid,
268 &exit_pipe);
269 if (!success) {
270 FATAL("Failed to lookup pid and exit pipe from process handle");
271 }
272 int message[2] = { exit_code, negative };
273 DWORD written;
274 ok = WriteFile(exit_pipe, message, sizeof(message), &written, NULL);
275 if (!ok || written != sizeof(message)) {
276 FATAL1("WriteFile to process exit code pipe failed %d\n",
277 GetLastError());
278 }
279 ProcessInfoList::RemoveProcess(pid);
280 }
281 delete[] handles;
282 }
283 }
284
285 static dart::Mutex mutex_;
286 static bool initialized_;
287 static bool terminating_;
288 static HANDLE wake_up_event_;
289 };
290
291
292 dart::Mutex ExitCodeHandler::mutex_;
293 bool ExitCodeHandler::initialized_ = false;
294 bool ExitCodeHandler::terminating_ = false;
295 HANDLE ExitCodeHandler::wake_up_event_ = 0;
74 296
75 297
76 // Types of pipes to create. 298 // Types of pipes to create.
77 enum NamedPipeType { 299 enum NamedPipeType {
78 kInheritRead, 300 kInheritRead,
79 kInheritWrite, 301 kInheritWrite,
80 kInheritNone 302 kInheritNone
81 }; 303 };
82 304
83 305
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { 416 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
195 fprintf(stderr, "FormatMessage failed %d\n", GetLastError()); 417 fprintf(stderr, "FormatMessage failed %d\n", GetLastError());
196 } 418 }
197 snprintf(os_error_message, os_error_message_len, "OS Error %d", error_code); 419 snprintf(os_error_message, os_error_message_len, "OS Error %d", error_code);
198 } 420 }
199 os_error_message[os_error_message_len - 1] = '\0'; 421 os_error_message[os_error_message_len - 1] = '\0';
200 return error_code; 422 return error_code;
201 } 423 }
202 424
203 425
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, 426 int Process::Start(const char* path,
230 char* arguments[], 427 char* arguments[],
231 intptr_t arguments_length, 428 intptr_t arguments_length,
232 const char* working_directory, 429 const char* working_directory,
233 intptr_t* in, 430 intptr_t* in,
234 intptr_t* out, 431 intptr_t* out,
235 intptr_t* err, 432 intptr_t* err,
236 intptr_t* id, 433 intptr_t* id,
237 intptr_t* exit_handler, 434 intptr_t* exit_handler,
238 char* os_error_message, 435 char* os_error_message,
239 int os_error_message_len) { 436 int os_error_message_len) {
437 // Ensure that the process exit handler thread has been started.
438 bool initialized = ExitCodeHandler::EnsureInitialized();
439 if (!initialized) {
440 int error_code = SetOsErrorMessage(os_error_message, os_error_message_len);
441 fprintf(stderr, "Failed to initialize ExitCodeHandler: %d\n", error_code);
442 return error_code;
443 }
444
240 HANDLE stdin_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; 445 HANDLE stdin_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
241 HANDLE stdout_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; 446 HANDLE stdout_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
242 HANDLE stderr_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; 447 HANDLE stderr_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
243 HANDLE exit_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; 448 HANDLE exit_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
244 449
245 // Generate unique pipe names for the four named pipes needed. 450 // Generate unique pipe names for the four named pipes needed.
246 char pipe_names[4][80]; 451 char pipe_names[4][80];
247 UUID uuid; 452 UUID uuid;
248 RPC_STATUS status = UuidCreateSequential(&uuid); 453 RPC_STATUS status = UuidCreateSequential(&uuid);
249 if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) { 454 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. 559 // Deallocate command-line string.
355 delete[] command_line; 560 delete[] command_line;
356 561
357 if (result == 0) { 562 if (result == 0) {
358 int error_code = SetOsErrorMessage(os_error_message, os_error_message_len); 563 int error_code = SetOsErrorMessage(os_error_message, os_error_message_len);
359 CloseProcessPipes( 564 CloseProcessPipes(
360 stdin_handles, stdout_handles, stderr_handles, exit_handles); 565 stdin_handles, stdout_handles, stderr_handles, exit_handles);
361 return error_code; 566 return error_code;
362 } 567 }
363 568
364 ProcessInfo* process = new ProcessInfo(process_info.dwProcessId, 569 ProcessInfoList::AddProcess(process_info.dwProcessId,
365 process_info.hProcess, 570 process_info.hProcess,
366 exit_handles[kWriteHandle]); 571 exit_handles[kWriteHandle]);
367 AddProcess(process); 572 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 573
378 // Connect the three std streams. 574 // Connect the three std streams.
379 FileHandle* stdin_handle = new FileHandle(stdin_handles[kWriteHandle]); 575 FileHandle* stdin_handle = new FileHandle(stdin_handles[kWriteHandle]);
380 CloseHandle(stdin_handles[kReadHandle]); 576 CloseHandle(stdin_handles[kReadHandle]);
381 FileHandle* stdout_handle = new FileHandle(stdout_handles[kReadHandle]); 577 FileHandle* stdout_handle = new FileHandle(stdout_handles[kReadHandle]);
382 CloseHandle(stdout_handles[kWriteHandle]); 578 CloseHandle(stdout_handles[kWriteHandle]);
383 FileHandle* stderr_handle = new FileHandle(stderr_handles[kReadHandle]); 579 FileHandle* stderr_handle = new FileHandle(stderr_handles[kReadHandle]);
384 CloseHandle(stderr_handles[kWriteHandle]); 580 CloseHandle(stderr_handles[kWriteHandle]);
385 FileHandle* exit_handle = new FileHandle(exit_handles[kReadHandle]); 581 FileHandle* exit_handle = new FileHandle(exit_handles[kReadHandle]);
386 *in = reinterpret_cast<intptr_t>(stdout_handle); 582 *in = reinterpret_cast<intptr_t>(stdout_handle);
387 *out = reinterpret_cast<intptr_t>(stdin_handle); 583 *out = reinterpret_cast<intptr_t>(stdin_handle);
388 *err = reinterpret_cast<intptr_t>(stderr_handle); 584 *err = reinterpret_cast<intptr_t>(stderr_handle);
389 *exit_handler = reinterpret_cast<intptr_t>(exit_handle); 585 *exit_handler = reinterpret_cast<intptr_t>(exit_handle);
390 586
391 CloseHandle(process_info.hThread); 587 CloseHandle(process_info.hThread);
392 588
393 // Return process id. 589 // Return process id.
394 *id = process->pid(); 590 *id = process_info.dwProcessId;
395 return 0; 591 return 0;
396 } 592 }
397 593
398 594
399 bool Process::Kill(intptr_t id) { 595 bool Process::Kill(intptr_t id) {
400 ProcessInfo* process = LookupProcess(id); 596 HANDLE process_handle;
401 ASSERT(process != NULL); 597 HANDLE exit_pipe;
402 if (process != NULL) { 598 bool success =
403 BOOL result = TerminateProcess(process->process_handle(), -1); 599 ProcessInfoList::LookupProcess(id, &process_handle, &exit_pipe);
404 if (result == 0) { 600 ASSERT(success);
405 return false; 601 BOOL result = TerminateProcess(process_handle, -1);
406 } 602 if (!result) {
603 return false;
407 } 604 }
408 return true; 605 return true;
409 } 606 }
410 607
411 608
412 void Process::Exit(intptr_t id) { 609 void Process::TerminateExitCodeHandler() {
413 RemoveProcess(id); 610 ExitCodeHandler::Shutdown();
414 } 611 }
OLDNEW
« no previous file with comments | « runtime/bin/process_macos.cc ('k') | tools/testing/bin/linux/dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698