Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |