xpcom/threads/nsProcessCommon.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 /*****************************************************************************
michael@0 7 *
michael@0 8 * nsProcess is used to execute new processes and specify if you want to
michael@0 9 * wait (blocking) or continue (non-blocking).
michael@0 10 *
michael@0 11 *****************************************************************************
michael@0 12 */
michael@0 13
michael@0 14 #include "mozilla/ArrayUtils.h"
michael@0 15
michael@0 16 #include "nsCOMPtr.h"
michael@0 17 #include "nsAutoPtr.h"
michael@0 18 #include "nsMemory.h"
michael@0 19 #include "nsProcess.h"
michael@0 20 #include "prio.h"
michael@0 21 #include "prenv.h"
michael@0 22 #include "nsCRT.h"
michael@0 23 #include "nsThreadUtils.h"
michael@0 24 #include "nsIObserverService.h"
michael@0 25 #include "mozilla/Services.h"
michael@0 26
michael@0 27 #include <stdlib.h>
michael@0 28
michael@0 29 #if defined(PROCESSMODEL_WINAPI)
michael@0 30 #include "prmem.h"
michael@0 31 #include "nsString.h"
michael@0 32 #include "nsLiteralString.h"
michael@0 33 #include "nsReadableUtils.h"
michael@0 34 #else
michael@0 35 #ifdef XP_MACOSX
michael@0 36 #include <crt_externs.h>
michael@0 37 #include <spawn.h>
michael@0 38 #include <sys/wait.h>
michael@0 39 #endif
michael@0 40 #include <sys/types.h>
michael@0 41 #include <signal.h>
michael@0 42 #endif
michael@0 43
michael@0 44 using namespace mozilla;
michael@0 45
michael@0 46 #ifdef XP_MACOSX
michael@0 47 cpu_type_t pref_cpu_types[2] = {
michael@0 48 #if defined(__i386__)
michael@0 49 CPU_TYPE_X86,
michael@0 50 #elif defined(__x86_64__)
michael@0 51 CPU_TYPE_X86_64,
michael@0 52 #elif defined(__ppc__)
michael@0 53 CPU_TYPE_POWERPC,
michael@0 54 #endif
michael@0 55 CPU_TYPE_ANY };
michael@0 56 #endif
michael@0 57
michael@0 58 //-------------------------------------------------------------------//
michael@0 59 // nsIProcess implementation
michael@0 60 //-------------------------------------------------------------------//
michael@0 61 NS_IMPL_ISUPPORTS(nsProcess, nsIProcess,
michael@0 62 nsIObserver)
michael@0 63
michael@0 64 //Constructor
michael@0 65 nsProcess::nsProcess()
michael@0 66 : mThread(nullptr)
michael@0 67 , mLock("nsProcess.mLock")
michael@0 68 , mShutdown(false)
michael@0 69 , mBlocking(false)
michael@0 70 , mPid(-1)
michael@0 71 , mObserver(nullptr)
michael@0 72 , mWeakObserver(nullptr)
michael@0 73 , mExitValue(-1)
michael@0 74 #if !defined(XP_MACOSX)
michael@0 75 , mProcess(nullptr)
michael@0 76 #endif
michael@0 77 {
michael@0 78 }
michael@0 79
michael@0 80 //Destructor
michael@0 81 nsProcess::~nsProcess()
michael@0 82 {
michael@0 83 }
michael@0 84
michael@0 85 NS_IMETHODIMP
michael@0 86 nsProcess::Init(nsIFile* executable)
michael@0 87 {
michael@0 88 if (mExecutable)
michael@0 89 return NS_ERROR_ALREADY_INITIALIZED;
michael@0 90
michael@0 91 if (NS_WARN_IF(!executable))
michael@0 92 return NS_ERROR_INVALID_ARG;
michael@0 93 bool isFile;
michael@0 94
michael@0 95 //First make sure the file exists
michael@0 96 nsresult rv = executable->IsFile(&isFile);
michael@0 97 if (NS_FAILED(rv)) return rv;
michael@0 98 if (!isFile)
michael@0 99 return NS_ERROR_FAILURE;
michael@0 100
michael@0 101 //Store the nsIFile in mExecutable
michael@0 102 mExecutable = executable;
michael@0 103 //Get the path because it is needed by the NSPR process creation
michael@0 104 #ifdef XP_WIN
michael@0 105 rv = mExecutable->GetTarget(mTargetPath);
michael@0 106 if (NS_FAILED(rv) || mTargetPath.IsEmpty() )
michael@0 107 #endif
michael@0 108 rv = mExecutable->GetPath(mTargetPath);
michael@0 109
michael@0 110 return rv;
michael@0 111 }
michael@0 112
michael@0 113
michael@0 114 #if defined(XP_WIN)
michael@0 115 // Out param `wideCmdLine` must be PR_Freed by the caller.
michael@0 116 static int assembleCmdLine(char *const *argv, wchar_t **wideCmdLine,
michael@0 117 UINT codePage)
michael@0 118 {
michael@0 119 char *const *arg;
michael@0 120 char *p, *q, *cmdLine;
michael@0 121 int cmdLineSize;
michael@0 122 int numBackslashes;
michael@0 123 int i;
michael@0 124 int argNeedQuotes;
michael@0 125
michael@0 126 /*
michael@0 127 * Find out how large the command line buffer should be.
michael@0 128 */
michael@0 129 cmdLineSize = 0;
michael@0 130 for (arg = argv; *arg; arg++) {
michael@0 131 /*
michael@0 132 * \ and " need to be escaped by a \. In the worst case,
michael@0 133 * every character is a \ or ", so the string of length
michael@0 134 * may double. If we quote an argument, that needs two ".
michael@0 135 * Finally, we need a space between arguments, and
michael@0 136 * a null byte at the end of command line.
michael@0 137 */
michael@0 138 cmdLineSize += 2 * strlen(*arg) /* \ and " need to be escaped */
michael@0 139 + 2 /* we quote every argument */
michael@0 140 + 1; /* space in between, or final null */
michael@0 141 }
michael@0 142 p = cmdLine = (char *) PR_MALLOC(cmdLineSize*sizeof(char));
michael@0 143 if (p == nullptr) {
michael@0 144 return -1;
michael@0 145 }
michael@0 146
michael@0 147 for (arg = argv; *arg; arg++) {
michael@0 148 /* Add a space to separates the arguments */
michael@0 149 if (arg != argv) {
michael@0 150 *p++ = ' ';
michael@0 151 }
michael@0 152 q = *arg;
michael@0 153 numBackslashes = 0;
michael@0 154 argNeedQuotes = 0;
michael@0 155
michael@0 156 /* If the argument contains white space, it needs to be quoted. */
michael@0 157 if (strpbrk(*arg, " \f\n\r\t\v")) {
michael@0 158 argNeedQuotes = 1;
michael@0 159 }
michael@0 160
michael@0 161 if (argNeedQuotes) {
michael@0 162 *p++ = '"';
michael@0 163 }
michael@0 164 while (*q) {
michael@0 165 if (*q == '\\') {
michael@0 166 numBackslashes++;
michael@0 167 q++;
michael@0 168 } else if (*q == '"') {
michael@0 169 if (numBackslashes) {
michael@0 170 /*
michael@0 171 * Double the backslashes since they are followed
michael@0 172 * by a quote
michael@0 173 */
michael@0 174 for (i = 0; i < 2 * numBackslashes; i++) {
michael@0 175 *p++ = '\\';
michael@0 176 }
michael@0 177 numBackslashes = 0;
michael@0 178 }
michael@0 179 /* To escape the quote */
michael@0 180 *p++ = '\\';
michael@0 181 *p++ = *q++;
michael@0 182 } else {
michael@0 183 if (numBackslashes) {
michael@0 184 /*
michael@0 185 * Backslashes are not followed by a quote, so
michael@0 186 * don't need to double the backslashes.
michael@0 187 */
michael@0 188 for (i = 0; i < numBackslashes; i++) {
michael@0 189 *p++ = '\\';
michael@0 190 }
michael@0 191 numBackslashes = 0;
michael@0 192 }
michael@0 193 *p++ = *q++;
michael@0 194 }
michael@0 195 }
michael@0 196
michael@0 197 /* Now we are at the end of this argument */
michael@0 198 if (numBackslashes) {
michael@0 199 /*
michael@0 200 * Double the backslashes if we have a quote string
michael@0 201 * delimiter at the end.
michael@0 202 */
michael@0 203 if (argNeedQuotes) {
michael@0 204 numBackslashes *= 2;
michael@0 205 }
michael@0 206 for (i = 0; i < numBackslashes; i++) {
michael@0 207 *p++ = '\\';
michael@0 208 }
michael@0 209 }
michael@0 210 if (argNeedQuotes) {
michael@0 211 *p++ = '"';
michael@0 212 }
michael@0 213 }
michael@0 214
michael@0 215 *p = '\0';
michael@0 216 int32_t numChars = MultiByteToWideChar(codePage, 0, cmdLine, -1, nullptr, 0);
michael@0 217 *wideCmdLine = (wchar_t *) PR_MALLOC(numChars*sizeof(wchar_t));
michael@0 218 MultiByteToWideChar(codePage, 0, cmdLine, -1, *wideCmdLine, numChars);
michael@0 219 PR_Free(cmdLine);
michael@0 220 return 0;
michael@0 221 }
michael@0 222 #endif
michael@0 223
michael@0 224 void nsProcess::Monitor(void *arg)
michael@0 225 {
michael@0 226 nsRefPtr<nsProcess> process = dont_AddRef(static_cast<nsProcess*>(arg));
michael@0 227
michael@0 228 if (!process->mBlocking)
michael@0 229 PR_SetCurrentThreadName("RunProcess");
michael@0 230
michael@0 231 #if defined(PROCESSMODEL_WINAPI)
michael@0 232 DWORD dwRetVal;
michael@0 233 unsigned long exitCode = -1;
michael@0 234
michael@0 235 dwRetVal = WaitForSingleObject(process->mProcess, INFINITE);
michael@0 236 if (dwRetVal != WAIT_FAILED) {
michael@0 237 if (GetExitCodeProcess(process->mProcess, &exitCode) == FALSE)
michael@0 238 exitCode = -1;
michael@0 239 }
michael@0 240
michael@0 241 // Lock in case Kill or GetExitCode are called during this
michael@0 242 {
michael@0 243 MutexAutoLock lock(process->mLock);
michael@0 244 CloseHandle(process->mProcess);
michael@0 245 process->mProcess = nullptr;
michael@0 246 process->mExitValue = exitCode;
michael@0 247 if (process->mShutdown)
michael@0 248 return;
michael@0 249 }
michael@0 250 #else
michael@0 251 #ifdef XP_MACOSX
michael@0 252 int exitCode = -1;
michael@0 253 int status = 0;
michael@0 254 if (waitpid(process->mPid, &status, 0) == process->mPid) {
michael@0 255 if (WIFEXITED(status)) {
michael@0 256 exitCode = WEXITSTATUS(status);
michael@0 257 }
michael@0 258 else if(WIFSIGNALED(status)) {
michael@0 259 exitCode = 256; // match NSPR's signal exit status
michael@0 260 }
michael@0 261 }
michael@0 262 #else
michael@0 263 int32_t exitCode = -1;
michael@0 264 if (PR_WaitProcess(process->mProcess, &exitCode) != PR_SUCCESS)
michael@0 265 exitCode = -1;
michael@0 266 #endif
michael@0 267
michael@0 268 // Lock in case Kill or GetExitCode are called during this
michael@0 269 {
michael@0 270 MutexAutoLock lock(process->mLock);
michael@0 271 #if !defined(XP_MACOSX)
michael@0 272 process->mProcess = nullptr;
michael@0 273 #endif
michael@0 274 process->mExitValue = exitCode;
michael@0 275 if (process->mShutdown)
michael@0 276 return;
michael@0 277 }
michael@0 278 #endif
michael@0 279
michael@0 280 // If we ran a background thread for the monitor then notify on the main
michael@0 281 // thread
michael@0 282 if (NS_IsMainThread()) {
michael@0 283 process->ProcessComplete();
michael@0 284 }
michael@0 285 else {
michael@0 286 nsCOMPtr<nsIRunnable> event =
michael@0 287 NS_NewRunnableMethod(process, &nsProcess::ProcessComplete);
michael@0 288 NS_DispatchToMainThread(event);
michael@0 289 }
michael@0 290 }
michael@0 291
michael@0 292 void nsProcess::ProcessComplete()
michael@0 293 {
michael@0 294 if (mThread) {
michael@0 295 nsCOMPtr<nsIObserverService> os =
michael@0 296 mozilla::services::GetObserverService();
michael@0 297 if (os)
michael@0 298 os->RemoveObserver(this, "xpcom-shutdown");
michael@0 299 PR_JoinThread(mThread);
michael@0 300 mThread = nullptr;
michael@0 301 }
michael@0 302
michael@0 303 const char* topic;
michael@0 304 if (mExitValue < 0)
michael@0 305 topic = "process-failed";
michael@0 306 else
michael@0 307 topic = "process-finished";
michael@0 308
michael@0 309 mPid = -1;
michael@0 310 nsCOMPtr<nsIObserver> observer;
michael@0 311 if (mWeakObserver)
michael@0 312 observer = do_QueryReferent(mWeakObserver);
michael@0 313 else if (mObserver)
michael@0 314 observer = mObserver;
michael@0 315 mObserver = nullptr;
michael@0 316 mWeakObserver = nullptr;
michael@0 317
michael@0 318 if (observer)
michael@0 319 observer->Observe(NS_ISUPPORTS_CAST(nsIProcess*, this), topic, nullptr);
michael@0 320 }
michael@0 321
michael@0 322 // XXXldb |args| has the wrong const-ness
michael@0 323 NS_IMETHODIMP
michael@0 324 nsProcess::Run(bool blocking, const char **args, uint32_t count)
michael@0 325 {
michael@0 326 return CopyArgsAndRunProcess(blocking, args, count, nullptr, false);
michael@0 327 }
michael@0 328
michael@0 329 // XXXldb |args| has the wrong const-ness
michael@0 330 NS_IMETHODIMP
michael@0 331 nsProcess::RunAsync(const char **args, uint32_t count,
michael@0 332 nsIObserver* observer, bool holdWeak)
michael@0 333 {
michael@0 334 return CopyArgsAndRunProcess(false, args, count, observer, holdWeak);
michael@0 335 }
michael@0 336
michael@0 337 nsresult
michael@0 338 nsProcess::CopyArgsAndRunProcess(bool blocking, const char** args,
michael@0 339 uint32_t count, nsIObserver* observer,
michael@0 340 bool holdWeak)
michael@0 341 {
michael@0 342 // Add one to the count for the program name and one for null termination.
michael@0 343 char **my_argv = nullptr;
michael@0 344 my_argv = (char**)NS_Alloc(sizeof(char*) * (count + 2));
michael@0 345 if (!my_argv) {
michael@0 346 return NS_ERROR_OUT_OF_MEMORY;
michael@0 347 }
michael@0 348
michael@0 349 my_argv[0] = ToNewUTF8String(mTargetPath);
michael@0 350
michael@0 351 for (uint32_t i = 0; i < count; i++) {
michael@0 352 my_argv[i + 1] = const_cast<char*>(args[i]);
michael@0 353 }
michael@0 354
michael@0 355 my_argv[count + 1] = nullptr;
michael@0 356
michael@0 357 nsresult rv = RunProcess(blocking, my_argv, observer, holdWeak, false);
michael@0 358
michael@0 359 NS_Free(my_argv[0]);
michael@0 360 NS_Free(my_argv);
michael@0 361 return rv;
michael@0 362 }
michael@0 363
michael@0 364 // XXXldb |args| has the wrong const-ness
michael@0 365 NS_IMETHODIMP
michael@0 366 nsProcess::Runw(bool blocking, const char16_t **args, uint32_t count)
michael@0 367 {
michael@0 368 return CopyArgsAndRunProcessw(blocking, args, count, nullptr, false);
michael@0 369 }
michael@0 370
michael@0 371 // XXXldb |args| has the wrong const-ness
michael@0 372 NS_IMETHODIMP
michael@0 373 nsProcess::RunwAsync(const char16_t **args, uint32_t count,
michael@0 374 nsIObserver* observer, bool holdWeak)
michael@0 375 {
michael@0 376 return CopyArgsAndRunProcessw(false, args, count, observer, holdWeak);
michael@0 377 }
michael@0 378
michael@0 379 nsresult
michael@0 380 nsProcess::CopyArgsAndRunProcessw(bool blocking, const char16_t** args,
michael@0 381 uint32_t count, nsIObserver* observer,
michael@0 382 bool holdWeak)
michael@0 383 {
michael@0 384 // Add one to the count for the program name and one for null termination.
michael@0 385 char **my_argv = nullptr;
michael@0 386 my_argv = (char**)NS_Alloc(sizeof(char*) * (count + 2));
michael@0 387 if (!my_argv) {
michael@0 388 return NS_ERROR_OUT_OF_MEMORY;
michael@0 389 }
michael@0 390
michael@0 391 my_argv[0] = ToNewUTF8String(mTargetPath);
michael@0 392
michael@0 393 for (uint32_t i = 0; i < count; i++) {
michael@0 394 my_argv[i + 1] = ToNewUTF8String(nsDependentString(args[i]));
michael@0 395 }
michael@0 396
michael@0 397 my_argv[count + 1] = nullptr;
michael@0 398
michael@0 399 nsresult rv = RunProcess(blocking, my_argv, observer, holdWeak, true);
michael@0 400
michael@0 401 for (uint32_t i = 0; i <= count; i++) {
michael@0 402 NS_Free(my_argv[i]);
michael@0 403 }
michael@0 404 NS_Free(my_argv);
michael@0 405 return rv;
michael@0 406 }
michael@0 407
michael@0 408 nsresult
michael@0 409 nsProcess::RunProcess(bool blocking, char **my_argv, nsIObserver* observer,
michael@0 410 bool holdWeak, bool argsUTF8)
michael@0 411 {
michael@0 412 if (NS_WARN_IF(!mExecutable))
michael@0 413 return NS_ERROR_NOT_INITIALIZED;
michael@0 414 if (NS_WARN_IF(mThread))
michael@0 415 return NS_ERROR_ALREADY_INITIALIZED;
michael@0 416
michael@0 417 if (observer) {
michael@0 418 if (holdWeak) {
michael@0 419 mWeakObserver = do_GetWeakReference(observer);
michael@0 420 if (!mWeakObserver)
michael@0 421 return NS_NOINTERFACE;
michael@0 422 }
michael@0 423 else {
michael@0 424 mObserver = observer;
michael@0 425 }
michael@0 426 }
michael@0 427
michael@0 428 mExitValue = -1;
michael@0 429 mPid = -1;
michael@0 430
michael@0 431 #if defined(PROCESSMODEL_WINAPI)
michael@0 432 BOOL retVal;
michael@0 433 wchar_t *cmdLine = nullptr;
michael@0 434
michael@0 435 // The 'argv' array is null-terminated and always starts with the program path.
michael@0 436 // If the second slot is non-null then arguments are being passed.
michael@0 437 if (my_argv[1] != nullptr &&
michael@0 438 assembleCmdLine(my_argv + 1, &cmdLine, argsUTF8 ? CP_UTF8 : CP_ACP) == -1) {
michael@0 439 return NS_ERROR_FILE_EXECUTION_FAILED;
michael@0 440 }
michael@0 441
michael@0 442 /* The SEE_MASK_NO_CONSOLE flag is important to prevent console windows
michael@0 443 * from appearing. This makes behavior the same on all platforms. The flag
michael@0 444 * will not have any effect on non-console applications.
michael@0 445 */
michael@0 446
michael@0 447 // The program name in my_argv[0] is always UTF-8
michael@0 448 NS_ConvertUTF8toUTF16 wideFile(my_argv[0]);
michael@0 449
michael@0 450 SHELLEXECUTEINFOW sinfo;
michael@0 451 memset(&sinfo, 0, sizeof(SHELLEXECUTEINFOW));
michael@0 452 sinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
michael@0 453 sinfo.hwnd = nullptr;
michael@0 454 sinfo.lpFile = wideFile.get();
michael@0 455 sinfo.nShow = SW_SHOWNORMAL;
michael@0 456 sinfo.fMask = SEE_MASK_FLAG_DDEWAIT |
michael@0 457 SEE_MASK_NO_CONSOLE |
michael@0 458 SEE_MASK_NOCLOSEPROCESS;
michael@0 459
michael@0 460 if (cmdLine)
michael@0 461 sinfo.lpParameters = cmdLine;
michael@0 462
michael@0 463 retVal = ShellExecuteExW(&sinfo);
michael@0 464 if (!retVal) {
michael@0 465 return NS_ERROR_FILE_EXECUTION_FAILED;
michael@0 466 }
michael@0 467
michael@0 468 mProcess = sinfo.hProcess;
michael@0 469
michael@0 470 if (cmdLine)
michael@0 471 PR_Free(cmdLine);
michael@0 472
michael@0 473 mPid = GetProcessId(mProcess);
michael@0 474 #elif defined(XP_MACOSX)
michael@0 475 // Initialize spawn attributes.
michael@0 476 posix_spawnattr_t spawnattr;
michael@0 477 if (posix_spawnattr_init(&spawnattr) != 0) {
michael@0 478 return NS_ERROR_FAILURE;
michael@0 479 }
michael@0 480
michael@0 481 // Set spawn attributes.
michael@0 482 size_t attr_count = ArrayLength(pref_cpu_types);
michael@0 483 size_t attr_ocount = 0;
michael@0 484 if (posix_spawnattr_setbinpref_np(&spawnattr, attr_count, pref_cpu_types, &attr_ocount) != 0 ||
michael@0 485 attr_ocount != attr_count) {
michael@0 486 posix_spawnattr_destroy(&spawnattr);
michael@0 487 return NS_ERROR_FAILURE;
michael@0 488 }
michael@0 489
michael@0 490 // Note that the 'argv' array is already null-terminated, which 'posix_spawnp' requires.
michael@0 491 pid_t newPid = 0;
michael@0 492 int result = posix_spawnp(&newPid, my_argv[0], nullptr, &spawnattr, my_argv, *_NSGetEnviron());
michael@0 493 mPid = static_cast<int32_t>(newPid);
michael@0 494
michael@0 495 posix_spawnattr_destroy(&spawnattr);
michael@0 496
michael@0 497 if (result != 0) {
michael@0 498 return NS_ERROR_FAILURE;
michael@0 499 }
michael@0 500 #else
michael@0 501 mProcess = PR_CreateProcess(my_argv[0], my_argv, nullptr, nullptr);
michael@0 502 if (!mProcess)
michael@0 503 return NS_ERROR_FAILURE;
michael@0 504 struct MYProcess {
michael@0 505 uint32_t pid;
michael@0 506 };
michael@0 507 MYProcess* ptrProc = (MYProcess *) mProcess;
michael@0 508 mPid = ptrProc->pid;
michael@0 509 #endif
michael@0 510
michael@0 511 NS_ADDREF_THIS();
michael@0 512 mBlocking = blocking;
michael@0 513 if (blocking) {
michael@0 514 Monitor(this);
michael@0 515 if (mExitValue < 0)
michael@0 516 return NS_ERROR_FILE_EXECUTION_FAILED;
michael@0 517 }
michael@0 518 else {
michael@0 519 mThread = PR_CreateThread(PR_SYSTEM_THREAD, Monitor, this,
michael@0 520 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
michael@0 521 PR_JOINABLE_THREAD, 0);
michael@0 522 if (!mThread) {
michael@0 523 NS_RELEASE_THIS();
michael@0 524 return NS_ERROR_FAILURE;
michael@0 525 }
michael@0 526
michael@0 527 // It isn't a failure if we just can't watch for shutdown
michael@0 528 nsCOMPtr<nsIObserverService> os =
michael@0 529 mozilla::services::GetObserverService();
michael@0 530 if (os)
michael@0 531 os->AddObserver(this, "xpcom-shutdown", false);
michael@0 532 }
michael@0 533
michael@0 534 return NS_OK;
michael@0 535 }
michael@0 536
michael@0 537 NS_IMETHODIMP nsProcess::GetIsRunning(bool *aIsRunning)
michael@0 538 {
michael@0 539 if (mThread)
michael@0 540 *aIsRunning = true;
michael@0 541 else
michael@0 542 *aIsRunning = false;
michael@0 543
michael@0 544 return NS_OK;
michael@0 545 }
michael@0 546
michael@0 547 NS_IMETHODIMP
michael@0 548 nsProcess::GetPid(uint32_t *aPid)
michael@0 549 {
michael@0 550 if (!mThread)
michael@0 551 return NS_ERROR_FAILURE;
michael@0 552 if (mPid < 0)
michael@0 553 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 554 *aPid = mPid;
michael@0 555 return NS_OK;
michael@0 556 }
michael@0 557
michael@0 558 NS_IMETHODIMP
michael@0 559 nsProcess::Kill()
michael@0 560 {
michael@0 561 if (!mThread)
michael@0 562 return NS_ERROR_FAILURE;
michael@0 563
michael@0 564 {
michael@0 565 MutexAutoLock lock(mLock);
michael@0 566 #if defined(PROCESSMODEL_WINAPI)
michael@0 567 if (TerminateProcess(mProcess, 0) == 0)
michael@0 568 return NS_ERROR_FAILURE;
michael@0 569 #elif defined(XP_MACOSX)
michael@0 570 if (kill(mPid, SIGKILL) != 0)
michael@0 571 return NS_ERROR_FAILURE;
michael@0 572 #else
michael@0 573 if (!mProcess || (PR_KillProcess(mProcess) != PR_SUCCESS))
michael@0 574 return NS_ERROR_FAILURE;
michael@0 575 #endif
michael@0 576 }
michael@0 577
michael@0 578 // We must null out mThread if we want IsRunning to return false immediately
michael@0 579 // after this call.
michael@0 580 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
michael@0 581 if (os)
michael@0 582 os->RemoveObserver(this, "xpcom-shutdown");
michael@0 583 PR_JoinThread(mThread);
michael@0 584 mThread = nullptr;
michael@0 585
michael@0 586 return NS_OK;
michael@0 587 }
michael@0 588
michael@0 589 NS_IMETHODIMP
michael@0 590 nsProcess::GetExitValue(int32_t *aExitValue)
michael@0 591 {
michael@0 592 MutexAutoLock lock(mLock);
michael@0 593
michael@0 594 *aExitValue = mExitValue;
michael@0 595
michael@0 596 return NS_OK;
michael@0 597 }
michael@0 598
michael@0 599 NS_IMETHODIMP
michael@0 600 nsProcess::Observe(nsISupports* subject, const char* topic, const char16_t* data)
michael@0 601 {
michael@0 602 // Shutting down, drop all references
michael@0 603 if (mThread) {
michael@0 604 nsCOMPtr<nsIObserverService> os =
michael@0 605 mozilla::services::GetObserverService();
michael@0 606 if (os)
michael@0 607 os->RemoveObserver(this, "xpcom-shutdown");
michael@0 608 mThread = nullptr;
michael@0 609 }
michael@0 610
michael@0 611 mObserver = nullptr;
michael@0 612 mWeakObserver = nullptr;
michael@0 613
michael@0 614 MutexAutoLock lock(mLock);
michael@0 615 mShutdown = true;
michael@0 616
michael@0 617 return NS_OK;
michael@0 618 }

mercurial