| 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" | |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |