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

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

Issue 9307033: Revert "Changes to the process implementation." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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"
11 #include "platform/globals.h" 10 #include "platform/globals.h"
12 11
13 static const int kReadHandle = 0; 12 static const int kReadHandle = 0;
14 static const int kWriteHandle = 1; 13 static const int kWriteHandle = 1;
15 14
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.
21 class ProcessInfo { 15 class ProcessInfo {
22 public: 16 public:
23 ProcessInfo(DWORD process_id, HANDLE process_handle, HANDLE exit_pipe) 17 ProcessInfo(DWORD process_id, HANDLE process_handle, HANDLE exit_pipe)
24 : process_id_(process_id), 18 : process_id_(process_id),
25 process_handle_(process_handle), 19 process_handle_(process_handle),
26 exit_pipe_(exit_pipe) { } 20 exit_pipe_(exit_pipe) { }
27 21
28 ~ProcessInfo() { 22 intptr_t pid() { return process_id_; }
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_; }
40 HANDLE process_handle() { return process_handle_; } 23 HANDLE process_handle() { return process_handle_; }
41 HANDLE exit_pipe() { return exit_pipe_; } 24 HANDLE exit_pipe() { return exit_pipe_; }
42 ProcessInfo* next() { return next_; } 25 ProcessInfo* next() { return next_; }
43 void set_next(ProcessInfo* next) { next_ = next; } 26 void set_next(ProcessInfo* next) { next_ = next; }
44 27
45 private: 28 private:
46 DWORD process_id_; // Process id. 29 DWORD process_id_; // Process id.
47 HANDLE process_handle_; // Process handle. 30 HANDLE process_handle_; // Process handle.
48 HANDLE exit_pipe_; // File descriptor for pipe to report exit code. 31 HANDLE exit_pipe_; // File descriptor for pipe to report exit code.
49 ProcessInfo* next_; 32 ProcessInfo* next_;
50 }; 33 };
51 34
52 35
53 // Singly-linked list of ProcessInfo objects for all active processes 36 ProcessInfo* active_processes = NULL;
54 // started from Dart.
55 class ProcessInfoList {
56 public:
57 static void AddProcess(DWORD pid, HANDLE handle, HANDLE pipe) {
58 MutexLocker locker(&mutex_);
59 ProcessInfo* info = new ProcessInfo(pid, handle, pipe);
60 info->set_next(active_processes_);
61 active_processes_ = info;
62 ++number_of_processes_;
63 }
64
65 static bool LookupProcess(DWORD pid, HANDLE* handle, HANDLE* pipe) {
66 MutexLocker locker(&mutex_);
67 ProcessInfo* current = active_processes_;
68 while (current != NULL) {
69 if (current->pid() == pid) {
70 *handle = current->process_handle();
71 *pipe = current->exit_pipe();
72 return true;
73 }
74 current = current->next();
75 }
76 return false;
77 }
78
79 static DWORD LookupProcessByHandle(HANDLE handle, DWORD* pid, HANDLE* pipe) {
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 37
139 38
140 intptr_t ProcessInfoList::number_of_processes_ = 0; 39 static void AddProcess(ProcessInfo* process) {
141 ProcessInfo* ProcessInfoList::active_processes_ = NULL; 40 process->set_next(active_processes);
142 dart::Mutex ProcessInfoList::mutex_; 41 active_processes = process;
42 }
143 43
144 44
145 // The exit code handler sets up a separate thread which is waiting 45 static ProcessInfo* LookupProcess(intptr_t pid) {
146 // for Dart process termination and process start. When a process 46 ProcessInfo* current = active_processes;
147 // terminates the exit code is extracted and communicated to Dart 47 while (current != NULL) {
148 // through the event loop. 48 if (current->pid() == pid) {
149 class ExitCodeHandler { 49 return current;
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 } 50 }
51 current = current->next();
52 }
53 return NULL;
54 }
160 55
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 56
168 // Start thread that waits for the process-addition handle as well 57 static void RemoveProcess(intptr_t pid) {
169 // as all process handles for all active processes. 58 ProcessInfo* prev = NULL;
170 new dart::Thread(ExitCodeHandlerEntry, 59 ProcessInfo* current = active_processes;
171 reinterpret_cast<uword>(wake_up_event_)); 60 while (current != NULL) {
172 61 if (current->pid() == pid) {
173 // Thread started and the ExitCodeHandler is initialized. 62 if (prev == NULL) {
174 initialized_ = true; 63 active_processes = current->next();
175 return true; 64 } else {
176 } 65 prev->set_next(current->next());
177 66 }
178 static void Shutdown() { 67 delete current;
179 MutexLocker locker(&mutex_);
180 if (!initialized_) {
181 return; 68 return;
182 } 69 }
183 terminating_ = true; 70 prev = current;
184 BOOL success = SetEvent(wake_up_event_); 71 current = current->next();
185 if (!success) {
186 FATAL("Failed to set wake-up event for exit code handler shutdown");
187 }
188 } 72 }
189 73 }
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 }
249 } else {
250 // The result is the index of the process that was
251 // signalled. Get its exit code and communicate it to Dart.
252 int exit_code;
253 BOOL ok = GetExitCodeProcess(handles[result],
254 reinterpret_cast<DWORD*>(&exit_code));
255 if (!ok) {
256 FATAL1("GetExitCodeProcess failed %d\n", GetLastError());
257 }
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;
296 74
297 75
298 // Types of pipes to create. 76 // Types of pipes to create.
299 enum NamedPipeType { 77 enum NamedPipeType {
300 kInheritRead, 78 kInheritRead,
301 kInheritWrite, 79 kInheritWrite,
302 kInheritNone 80 kInheritNone
303 }; 81 };
304 82
305 83
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
416 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { 194 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
417 fprintf(stderr, "FormatMessage failed %d\n", GetLastError()); 195 fprintf(stderr, "FormatMessage failed %d\n", GetLastError());
418 } 196 }
419 snprintf(os_error_message, os_error_message_len, "OS Error %d", error_code); 197 snprintf(os_error_message, os_error_message_len, "OS Error %d", error_code);
420 } 198 }
421 os_error_message[os_error_message_len - 1] = '\0'; 199 os_error_message[os_error_message_len - 1] = '\0';
422 return error_code; 200 return error_code;
423 } 201 }
424 202
425 203
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
426 int Process::Start(const char* path, 229 int Process::Start(const char* path,
427 char* arguments[], 230 char* arguments[],
428 intptr_t arguments_length, 231 intptr_t arguments_length,
429 const char* working_directory, 232 const char* working_directory,
430 intptr_t* in, 233 intptr_t* in,
431 intptr_t* out, 234 intptr_t* out,
432 intptr_t* err, 235 intptr_t* err,
433 intptr_t* id, 236 intptr_t* id,
434 intptr_t* exit_handler, 237 intptr_t* exit_handler,
435 char* os_error_message, 238 char* os_error_message,
436 int os_error_message_len) { 239 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
445 HANDLE stdin_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; 240 HANDLE stdin_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
446 HANDLE stdout_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; 241 HANDLE stdout_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
447 HANDLE stderr_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; 242 HANDLE stderr_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
448 HANDLE exit_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; 243 HANDLE exit_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
449 244
450 // Generate unique pipe names for the four named pipes needed. 245 // Generate unique pipe names for the four named pipes needed.
451 char pipe_names[4][80]; 246 char pipe_names[4][80];
452 UUID uuid; 247 UUID uuid;
453 RPC_STATUS status = UuidCreateSequential(&uuid); 248 RPC_STATUS status = UuidCreateSequential(&uuid);
454 if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) { 249 if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) {
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
559 // Deallocate command-line string. 354 // Deallocate command-line string.
560 delete[] command_line; 355 delete[] command_line;
561 356
562 if (result == 0) { 357 if (result == 0) {
563 int error_code = SetOsErrorMessage(os_error_message, os_error_message_len); 358 int error_code = SetOsErrorMessage(os_error_message, os_error_message_len);
564 CloseProcessPipes( 359 CloseProcessPipes(
565 stdin_handles, stdout_handles, stderr_handles, exit_handles); 360 stdin_handles, stdout_handles, stderr_handles, exit_handles);
566 return error_code; 361 return error_code;
567 } 362 }
568 363
569 ProcessInfoList::AddProcess(process_info.dwProcessId, 364 ProcessInfo* process = new ProcessInfo(process_info.dwProcessId,
570 process_info.hProcess, 365 process_info.hProcess,
571 exit_handles[kWriteHandle]); 366 exit_handles[kWriteHandle]);
572 ExitCodeHandler::ProcessAdded(); 367 AddProcess(process);
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 }
573 377
574 // Connect the three std streams. 378 // Connect the three std streams.
575 FileHandle* stdin_handle = new FileHandle(stdin_handles[kWriteHandle]); 379 FileHandle* stdin_handle = new FileHandle(stdin_handles[kWriteHandle]);
576 CloseHandle(stdin_handles[kReadHandle]); 380 CloseHandle(stdin_handles[kReadHandle]);
577 FileHandle* stdout_handle = new FileHandle(stdout_handles[kReadHandle]); 381 FileHandle* stdout_handle = new FileHandle(stdout_handles[kReadHandle]);
578 CloseHandle(stdout_handles[kWriteHandle]); 382 CloseHandle(stdout_handles[kWriteHandle]);
579 FileHandle* stderr_handle = new FileHandle(stderr_handles[kReadHandle]); 383 FileHandle* stderr_handle = new FileHandle(stderr_handles[kReadHandle]);
580 CloseHandle(stderr_handles[kWriteHandle]); 384 CloseHandle(stderr_handles[kWriteHandle]);
581 FileHandle* exit_handle = new FileHandle(exit_handles[kReadHandle]); 385 FileHandle* exit_handle = new FileHandle(exit_handles[kReadHandle]);
582 *in = reinterpret_cast<intptr_t>(stdout_handle); 386 *in = reinterpret_cast<intptr_t>(stdout_handle);
583 *out = reinterpret_cast<intptr_t>(stdin_handle); 387 *out = reinterpret_cast<intptr_t>(stdin_handle);
584 *err = reinterpret_cast<intptr_t>(stderr_handle); 388 *err = reinterpret_cast<intptr_t>(stderr_handle);
585 *exit_handler = reinterpret_cast<intptr_t>(exit_handle); 389 *exit_handler = reinterpret_cast<intptr_t>(exit_handle);
586 390
587 CloseHandle(process_info.hThread); 391 CloseHandle(process_info.hThread);
588 392
589 // Return process id. 393 // Return process id.
590 *id = process_info.dwProcessId; 394 *id = process->pid();
591 return 0; 395 return 0;
592 } 396 }
593 397
594 398
595 bool Process::Kill(intptr_t id) { 399 bool Process::Kill(intptr_t id) {
596 HANDLE process_handle; 400 ProcessInfo* process = LookupProcess(id);
597 HANDLE exit_pipe; 401 ASSERT(process != NULL);
598 bool success = 402 if (process != NULL) {
599 ProcessInfoList::LookupProcess(id, &process_handle, &exit_pipe); 403 BOOL result = TerminateProcess(process->process_handle(), -1);
600 ASSERT(success); 404 if (result == 0) {
601 BOOL result = TerminateProcess(process_handle, -1); 405 return false;
602 if (!result) { 406 }
603 return false;
604 } 407 }
605 return true; 408 return true;
606 } 409 }
607 410
608 411
609 void Process::TerminateExitCodeHandler() { 412 void Process::Exit(intptr_t id) {
610 ExitCodeHandler::Shutdown(); 413 RemoveProcess(id);
611 } 414 }
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