xpcom/threads/nsProcessCommon.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/xpcom/threads/nsProcessCommon.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,618 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*****************************************************************************
    1.10 + * 
    1.11 + * nsProcess is used to execute new processes and specify if you want to
    1.12 + * wait (blocking) or continue (non-blocking).
    1.13 + *
    1.14 + *****************************************************************************
    1.15 + */
    1.16 +
    1.17 +#include "mozilla/ArrayUtils.h"
    1.18 +
    1.19 +#include "nsCOMPtr.h"
    1.20 +#include "nsAutoPtr.h"
    1.21 +#include "nsMemory.h"
    1.22 +#include "nsProcess.h"
    1.23 +#include "prio.h"
    1.24 +#include "prenv.h"
    1.25 +#include "nsCRT.h"
    1.26 +#include "nsThreadUtils.h"
    1.27 +#include "nsIObserverService.h"
    1.28 +#include "mozilla/Services.h"
    1.29 +
    1.30 +#include <stdlib.h>
    1.31 +
    1.32 +#if defined(PROCESSMODEL_WINAPI)
    1.33 +#include "prmem.h"
    1.34 +#include "nsString.h"
    1.35 +#include "nsLiteralString.h"
    1.36 +#include "nsReadableUtils.h"
    1.37 +#else
    1.38 +#ifdef XP_MACOSX
    1.39 +#include <crt_externs.h>
    1.40 +#include <spawn.h>
    1.41 +#include <sys/wait.h>
    1.42 +#endif
    1.43 +#include <sys/types.h>
    1.44 +#include <signal.h>
    1.45 +#endif
    1.46 +
    1.47 +using namespace mozilla;
    1.48 +
    1.49 +#ifdef XP_MACOSX
    1.50 +cpu_type_t pref_cpu_types[2] = {
    1.51 +#if defined(__i386__)
    1.52 +                                 CPU_TYPE_X86,
    1.53 +#elif defined(__x86_64__)
    1.54 +                                 CPU_TYPE_X86_64,
    1.55 +#elif defined(__ppc__)
    1.56 +                                 CPU_TYPE_POWERPC,
    1.57 +#endif
    1.58 +                                 CPU_TYPE_ANY };
    1.59 +#endif
    1.60 +
    1.61 +//-------------------------------------------------------------------//
    1.62 +// nsIProcess implementation
    1.63 +//-------------------------------------------------------------------//
    1.64 +NS_IMPL_ISUPPORTS(nsProcess, nsIProcess,
    1.65 +                  nsIObserver)
    1.66 +
    1.67 +//Constructor
    1.68 +nsProcess::nsProcess()
    1.69 +    : mThread(nullptr)
    1.70 +    , mLock("nsProcess.mLock")
    1.71 +    , mShutdown(false)
    1.72 +    , mBlocking(false)
    1.73 +    , mPid(-1)
    1.74 +    , mObserver(nullptr)
    1.75 +    , mWeakObserver(nullptr)
    1.76 +    , mExitValue(-1)
    1.77 +#if !defined(XP_MACOSX)
    1.78 +    , mProcess(nullptr)
    1.79 +#endif
    1.80 +{
    1.81 +}
    1.82 +
    1.83 +//Destructor
    1.84 +nsProcess::~nsProcess()
    1.85 +{
    1.86 +}
    1.87 +
    1.88 +NS_IMETHODIMP
    1.89 +nsProcess::Init(nsIFile* executable)
    1.90 +{
    1.91 +    if (mExecutable)
    1.92 +        return NS_ERROR_ALREADY_INITIALIZED;
    1.93 +
    1.94 +    if (NS_WARN_IF(!executable))
    1.95 +        return NS_ERROR_INVALID_ARG;
    1.96 +    bool isFile;
    1.97 +
    1.98 +    //First make sure the file exists
    1.99 +    nsresult rv = executable->IsFile(&isFile);
   1.100 +    if (NS_FAILED(rv)) return rv;
   1.101 +    if (!isFile)
   1.102 +        return NS_ERROR_FAILURE;
   1.103 +
   1.104 +    //Store the nsIFile in mExecutable
   1.105 +    mExecutable = executable;
   1.106 +    //Get the path because it is needed by the NSPR process creation
   1.107 +#ifdef XP_WIN 
   1.108 +    rv = mExecutable->GetTarget(mTargetPath);
   1.109 +    if (NS_FAILED(rv) || mTargetPath.IsEmpty() )
   1.110 +#endif
   1.111 +        rv = mExecutable->GetPath(mTargetPath);
   1.112 +
   1.113 +    return rv;
   1.114 +}
   1.115 +
   1.116 +
   1.117 +#if defined(XP_WIN)
   1.118 +// Out param `wideCmdLine` must be PR_Freed by the caller.
   1.119 +static int assembleCmdLine(char *const *argv, wchar_t **wideCmdLine,
   1.120 +                           UINT codePage)
   1.121 +{
   1.122 +    char *const *arg;
   1.123 +    char *p, *q, *cmdLine;
   1.124 +    int cmdLineSize;
   1.125 +    int numBackslashes;
   1.126 +    int i;
   1.127 +    int argNeedQuotes;
   1.128 +
   1.129 +    /*
   1.130 +     * Find out how large the command line buffer should be.
   1.131 +     */
   1.132 +    cmdLineSize = 0;
   1.133 +    for (arg = argv; *arg; arg++) {
   1.134 +        /*
   1.135 +         * \ and " need to be escaped by a \.  In the worst case,
   1.136 +         * every character is a \ or ", so the string of length
   1.137 +         * may double.  If we quote an argument, that needs two ".
   1.138 +         * Finally, we need a space between arguments, and
   1.139 +         * a null byte at the end of command line.
   1.140 +         */
   1.141 +        cmdLineSize += 2 * strlen(*arg)  /* \ and " need to be escaped */
   1.142 +                + 2                      /* we quote every argument */
   1.143 +                + 1;                     /* space in between, or final null */
   1.144 +    }
   1.145 +    p = cmdLine = (char *) PR_MALLOC(cmdLineSize*sizeof(char));
   1.146 +    if (p == nullptr) {
   1.147 +        return -1;
   1.148 +    }
   1.149 +
   1.150 +    for (arg = argv; *arg; arg++) {
   1.151 +        /* Add a space to separates the arguments */
   1.152 +        if (arg != argv) {
   1.153 +            *p++ = ' '; 
   1.154 +        }
   1.155 +        q = *arg;
   1.156 +        numBackslashes = 0;
   1.157 +        argNeedQuotes = 0;
   1.158 +
   1.159 +        /* If the argument contains white space, it needs to be quoted. */
   1.160 +        if (strpbrk(*arg, " \f\n\r\t\v")) {
   1.161 +            argNeedQuotes = 1;
   1.162 +        }
   1.163 +
   1.164 +        if (argNeedQuotes) {
   1.165 +            *p++ = '"';
   1.166 +        }
   1.167 +        while (*q) {
   1.168 +            if (*q == '\\') {
   1.169 +                numBackslashes++;
   1.170 +                q++;
   1.171 +            } else if (*q == '"') {
   1.172 +                if (numBackslashes) {
   1.173 +                    /*
   1.174 +                     * Double the backslashes since they are followed
   1.175 +                     * by a quote
   1.176 +                     */
   1.177 +                    for (i = 0; i < 2 * numBackslashes; i++) {
   1.178 +                        *p++ = '\\';
   1.179 +                    }
   1.180 +                    numBackslashes = 0;
   1.181 +                }
   1.182 +                /* To escape the quote */
   1.183 +                *p++ = '\\';
   1.184 +                *p++ = *q++;
   1.185 +            } else {
   1.186 +                if (numBackslashes) {
   1.187 +                    /*
   1.188 +                     * Backslashes are not followed by a quote, so
   1.189 +                     * don't need to double the backslashes.
   1.190 +                     */
   1.191 +                    for (i = 0; i < numBackslashes; i++) {
   1.192 +                        *p++ = '\\';
   1.193 +                    }
   1.194 +                    numBackslashes = 0;
   1.195 +                }
   1.196 +                *p++ = *q++;
   1.197 +            }
   1.198 +        }
   1.199 +
   1.200 +        /* Now we are at the end of this argument */
   1.201 +        if (numBackslashes) {
   1.202 +            /*
   1.203 +             * Double the backslashes if we have a quote string
   1.204 +             * delimiter at the end.
   1.205 +             */
   1.206 +            if (argNeedQuotes) {
   1.207 +                numBackslashes *= 2;
   1.208 +            }
   1.209 +            for (i = 0; i < numBackslashes; i++) {
   1.210 +                *p++ = '\\';
   1.211 +            }
   1.212 +        }
   1.213 +        if (argNeedQuotes) {
   1.214 +            *p++ = '"';
   1.215 +        }
   1.216 +    } 
   1.217 +
   1.218 +    *p = '\0';
   1.219 +    int32_t numChars = MultiByteToWideChar(codePage, 0, cmdLine, -1, nullptr, 0);
   1.220 +    *wideCmdLine = (wchar_t *) PR_MALLOC(numChars*sizeof(wchar_t));
   1.221 +    MultiByteToWideChar(codePage, 0, cmdLine, -1, *wideCmdLine, numChars); 
   1.222 +    PR_Free(cmdLine);
   1.223 +    return 0;
   1.224 +}
   1.225 +#endif
   1.226 +
   1.227 +void nsProcess::Monitor(void *arg)
   1.228 +{
   1.229 +    nsRefPtr<nsProcess> process = dont_AddRef(static_cast<nsProcess*>(arg));
   1.230 +
   1.231 +    if (!process->mBlocking)
   1.232 +        PR_SetCurrentThreadName("RunProcess");
   1.233 +
   1.234 +#if defined(PROCESSMODEL_WINAPI)
   1.235 +    DWORD dwRetVal;
   1.236 +    unsigned long exitCode = -1;
   1.237 +
   1.238 +    dwRetVal = WaitForSingleObject(process->mProcess, INFINITE);
   1.239 +    if (dwRetVal != WAIT_FAILED) {
   1.240 +        if (GetExitCodeProcess(process->mProcess, &exitCode) == FALSE)
   1.241 +            exitCode = -1;
   1.242 +    }
   1.243 +
   1.244 +    // Lock in case Kill or GetExitCode are called during this
   1.245 +    {
   1.246 +        MutexAutoLock lock(process->mLock);
   1.247 +        CloseHandle(process->mProcess);
   1.248 +        process->mProcess = nullptr;
   1.249 +        process->mExitValue = exitCode;
   1.250 +        if (process->mShutdown)
   1.251 +            return;
   1.252 +    }
   1.253 +#else
   1.254 +#ifdef XP_MACOSX
   1.255 +    int exitCode = -1;
   1.256 +    int status = 0;
   1.257 +    if (waitpid(process->mPid, &status, 0) == process->mPid) {
   1.258 +        if (WIFEXITED(status)) {
   1.259 +            exitCode = WEXITSTATUS(status);
   1.260 +        }
   1.261 +        else if(WIFSIGNALED(status)) {
   1.262 +            exitCode = 256; // match NSPR's signal exit status
   1.263 +        }
   1.264 +    }
   1.265 +#else
   1.266 +    int32_t exitCode = -1;
   1.267 +    if (PR_WaitProcess(process->mProcess, &exitCode) != PR_SUCCESS)
   1.268 +        exitCode = -1;
   1.269 +#endif
   1.270 +
   1.271 +    // Lock in case Kill or GetExitCode are called during this
   1.272 +    {
   1.273 +        MutexAutoLock lock(process->mLock);
   1.274 +#if !defined(XP_MACOSX)
   1.275 +        process->mProcess = nullptr;
   1.276 +#endif
   1.277 +        process->mExitValue = exitCode;
   1.278 +        if (process->mShutdown)
   1.279 +            return;
   1.280 +    }
   1.281 +#endif
   1.282 +
   1.283 +    // If we ran a background thread for the monitor then notify on the main
   1.284 +    // thread
   1.285 +    if (NS_IsMainThread()) {
   1.286 +        process->ProcessComplete();
   1.287 +    }
   1.288 +    else {
   1.289 +        nsCOMPtr<nsIRunnable> event =
   1.290 +            NS_NewRunnableMethod(process, &nsProcess::ProcessComplete);
   1.291 +        NS_DispatchToMainThread(event);
   1.292 +    }
   1.293 +}
   1.294 +
   1.295 +void nsProcess::ProcessComplete()
   1.296 +{
   1.297 +    if (mThread) {
   1.298 +        nsCOMPtr<nsIObserverService> os =
   1.299 +            mozilla::services::GetObserverService();
   1.300 +        if (os)
   1.301 +            os->RemoveObserver(this, "xpcom-shutdown");
   1.302 +        PR_JoinThread(mThread);
   1.303 +        mThread = nullptr;
   1.304 +    }
   1.305 +
   1.306 +    const char* topic;
   1.307 +    if (mExitValue < 0)
   1.308 +        topic = "process-failed";
   1.309 +    else
   1.310 +        topic = "process-finished";
   1.311 +
   1.312 +    mPid = -1;
   1.313 +    nsCOMPtr<nsIObserver> observer;
   1.314 +    if (mWeakObserver)
   1.315 +        observer = do_QueryReferent(mWeakObserver);
   1.316 +    else if (mObserver)
   1.317 +        observer = mObserver;
   1.318 +    mObserver = nullptr;
   1.319 +    mWeakObserver = nullptr;
   1.320 +
   1.321 +    if (observer)
   1.322 +        observer->Observe(NS_ISUPPORTS_CAST(nsIProcess*, this), topic, nullptr);
   1.323 +}
   1.324 +
   1.325 +// XXXldb |args| has the wrong const-ness
   1.326 +NS_IMETHODIMP  
   1.327 +nsProcess::Run(bool blocking, const char **args, uint32_t count)
   1.328 +{
   1.329 +    return CopyArgsAndRunProcess(blocking, args, count, nullptr, false);
   1.330 +}
   1.331 +
   1.332 +// XXXldb |args| has the wrong const-ness
   1.333 +NS_IMETHODIMP  
   1.334 +nsProcess::RunAsync(const char **args, uint32_t count,
   1.335 +                    nsIObserver* observer, bool holdWeak)
   1.336 +{
   1.337 +    return CopyArgsAndRunProcess(false, args, count, observer, holdWeak);
   1.338 +}
   1.339 +
   1.340 +nsresult
   1.341 +nsProcess::CopyArgsAndRunProcess(bool blocking, const char** args,
   1.342 +                                 uint32_t count, nsIObserver* observer,
   1.343 +                                 bool holdWeak)
   1.344 +{
   1.345 +    // Add one to the count for the program name and one for null termination.
   1.346 +    char **my_argv = nullptr;
   1.347 +    my_argv = (char**)NS_Alloc(sizeof(char*) * (count + 2));
   1.348 +    if (!my_argv) {
   1.349 +        return NS_ERROR_OUT_OF_MEMORY;
   1.350 +    }
   1.351 +
   1.352 +    my_argv[0] = ToNewUTF8String(mTargetPath);
   1.353 +
   1.354 +    for (uint32_t i = 0; i < count; i++) {
   1.355 +        my_argv[i + 1] = const_cast<char*>(args[i]);
   1.356 +    }
   1.357 +
   1.358 +    my_argv[count + 1] = nullptr;
   1.359 +
   1.360 +    nsresult rv = RunProcess(blocking, my_argv, observer, holdWeak, false);
   1.361 +
   1.362 +    NS_Free(my_argv[0]);
   1.363 +    NS_Free(my_argv);
   1.364 +    return rv;
   1.365 +}
   1.366 +
   1.367 +// XXXldb |args| has the wrong const-ness
   1.368 +NS_IMETHODIMP  
   1.369 +nsProcess::Runw(bool blocking, const char16_t **args, uint32_t count)
   1.370 +{
   1.371 +    return CopyArgsAndRunProcessw(blocking, args, count, nullptr, false);
   1.372 +}
   1.373 +
   1.374 +// XXXldb |args| has the wrong const-ness
   1.375 +NS_IMETHODIMP  
   1.376 +nsProcess::RunwAsync(const char16_t **args, uint32_t count,
   1.377 +                    nsIObserver* observer, bool holdWeak)
   1.378 +{
   1.379 +    return CopyArgsAndRunProcessw(false, args, count, observer, holdWeak);
   1.380 +}
   1.381 +
   1.382 +nsresult
   1.383 +nsProcess::CopyArgsAndRunProcessw(bool blocking, const char16_t** args,
   1.384 +                                  uint32_t count, nsIObserver* observer,
   1.385 +                                  bool holdWeak)
   1.386 +{
   1.387 +    // Add one to the count for the program name and one for null termination.
   1.388 +    char **my_argv = nullptr;
   1.389 +    my_argv = (char**)NS_Alloc(sizeof(char*) * (count + 2));
   1.390 +    if (!my_argv) {
   1.391 +        return NS_ERROR_OUT_OF_MEMORY;
   1.392 +    }
   1.393 +
   1.394 +    my_argv[0] = ToNewUTF8String(mTargetPath);
   1.395 +
   1.396 +    for (uint32_t i = 0; i < count; i++) {
   1.397 +        my_argv[i + 1] = ToNewUTF8String(nsDependentString(args[i]));
   1.398 +    }
   1.399 +
   1.400 +    my_argv[count + 1] = nullptr;
   1.401 +
   1.402 +    nsresult rv = RunProcess(blocking, my_argv, observer, holdWeak, true);
   1.403 +
   1.404 +    for (uint32_t i = 0; i <= count; i++) {
   1.405 +        NS_Free(my_argv[i]);
   1.406 +    }
   1.407 +    NS_Free(my_argv);
   1.408 +    return rv;
   1.409 +}
   1.410 +
   1.411 +nsresult  
   1.412 +nsProcess::RunProcess(bool blocking, char **my_argv, nsIObserver* observer,
   1.413 +                      bool holdWeak, bool argsUTF8)
   1.414 +{
   1.415 +    if (NS_WARN_IF(!mExecutable))
   1.416 +        return NS_ERROR_NOT_INITIALIZED;
   1.417 +    if (NS_WARN_IF(mThread))
   1.418 +        return NS_ERROR_ALREADY_INITIALIZED;
   1.419 +
   1.420 +    if (observer) {
   1.421 +        if (holdWeak) {
   1.422 +            mWeakObserver = do_GetWeakReference(observer);
   1.423 +            if (!mWeakObserver)
   1.424 +                return NS_NOINTERFACE;
   1.425 +        }
   1.426 +        else {
   1.427 +            mObserver = observer;
   1.428 +        }
   1.429 +    }
   1.430 +
   1.431 +    mExitValue = -1;
   1.432 +    mPid = -1;
   1.433 +
   1.434 +#if defined(PROCESSMODEL_WINAPI)
   1.435 +    BOOL retVal;
   1.436 +    wchar_t *cmdLine = nullptr;
   1.437 +
   1.438 +    // The 'argv' array is null-terminated and always starts with the program path.
   1.439 +    // If the second slot is non-null then arguments are being passed.
   1.440 +    if (my_argv[1] != nullptr &&
   1.441 +        assembleCmdLine(my_argv + 1, &cmdLine, argsUTF8 ? CP_UTF8 : CP_ACP) == -1) {
   1.442 +        return NS_ERROR_FILE_EXECUTION_FAILED;    
   1.443 +    }
   1.444 +
   1.445 +    /* The SEE_MASK_NO_CONSOLE flag is important to prevent console windows
   1.446 +     * from appearing. This makes behavior the same on all platforms. The flag
   1.447 +     * will not have any effect on non-console applications.
   1.448 +     */
   1.449 +
   1.450 +    // The program name in my_argv[0] is always UTF-8
   1.451 +    NS_ConvertUTF8toUTF16 wideFile(my_argv[0]);
   1.452 +
   1.453 +    SHELLEXECUTEINFOW sinfo;
   1.454 +    memset(&sinfo, 0, sizeof(SHELLEXECUTEINFOW));
   1.455 +    sinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
   1.456 +    sinfo.hwnd   = nullptr;
   1.457 +    sinfo.lpFile = wideFile.get();
   1.458 +    sinfo.nShow  = SW_SHOWNORMAL;
   1.459 +    sinfo.fMask  = SEE_MASK_FLAG_DDEWAIT |
   1.460 +                   SEE_MASK_NO_CONSOLE |
   1.461 +                   SEE_MASK_NOCLOSEPROCESS;
   1.462 +
   1.463 +    if (cmdLine)
   1.464 +        sinfo.lpParameters = cmdLine;
   1.465 +
   1.466 +    retVal = ShellExecuteExW(&sinfo);
   1.467 +    if (!retVal) {
   1.468 +        return NS_ERROR_FILE_EXECUTION_FAILED;
   1.469 +    }
   1.470 +
   1.471 +    mProcess = sinfo.hProcess;
   1.472 +
   1.473 +    if (cmdLine)
   1.474 +        PR_Free(cmdLine);
   1.475 +
   1.476 +    mPid = GetProcessId(mProcess);
   1.477 +#elif defined(XP_MACOSX)
   1.478 +    // Initialize spawn attributes.
   1.479 +    posix_spawnattr_t spawnattr;
   1.480 +    if (posix_spawnattr_init(&spawnattr) != 0) {
   1.481 +        return NS_ERROR_FAILURE;
   1.482 +    }
   1.483 +
   1.484 +    // Set spawn attributes.
   1.485 +    size_t attr_count = ArrayLength(pref_cpu_types);
   1.486 +    size_t attr_ocount = 0;
   1.487 +    if (posix_spawnattr_setbinpref_np(&spawnattr, attr_count, pref_cpu_types, &attr_ocount) != 0 ||
   1.488 +        attr_ocount != attr_count) {
   1.489 +        posix_spawnattr_destroy(&spawnattr);
   1.490 +        return NS_ERROR_FAILURE;
   1.491 +    }
   1.492 +
   1.493 +    // Note that the 'argv' array is already null-terminated, which 'posix_spawnp' requires.
   1.494 +    pid_t newPid = 0;
   1.495 +    int result = posix_spawnp(&newPid, my_argv[0], nullptr, &spawnattr, my_argv, *_NSGetEnviron());
   1.496 +    mPid = static_cast<int32_t>(newPid);
   1.497 +
   1.498 +    posix_spawnattr_destroy(&spawnattr);
   1.499 +
   1.500 +    if (result != 0) {
   1.501 +        return NS_ERROR_FAILURE;
   1.502 +    }
   1.503 +#else
   1.504 +    mProcess = PR_CreateProcess(my_argv[0], my_argv, nullptr, nullptr);
   1.505 +    if (!mProcess)
   1.506 +        return NS_ERROR_FAILURE;
   1.507 +    struct MYProcess {
   1.508 +        uint32_t pid;
   1.509 +    };
   1.510 +    MYProcess* ptrProc = (MYProcess *) mProcess;
   1.511 +    mPid = ptrProc->pid;
   1.512 +#endif
   1.513 +
   1.514 +    NS_ADDREF_THIS();
   1.515 +    mBlocking = blocking;
   1.516 +    if (blocking) {
   1.517 +        Monitor(this);
   1.518 +        if (mExitValue < 0)
   1.519 +            return NS_ERROR_FILE_EXECUTION_FAILED;
   1.520 +    }
   1.521 +    else {
   1.522 +        mThread = PR_CreateThread(PR_SYSTEM_THREAD, Monitor, this,
   1.523 +                                  PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
   1.524 +                                  PR_JOINABLE_THREAD, 0);
   1.525 +        if (!mThread) {
   1.526 +            NS_RELEASE_THIS();
   1.527 +            return NS_ERROR_FAILURE;
   1.528 +        }
   1.529 +
   1.530 +        // It isn't a failure if we just can't watch for shutdown
   1.531 +        nsCOMPtr<nsIObserverService> os =
   1.532 +          mozilla::services::GetObserverService();
   1.533 +        if (os)
   1.534 +            os->AddObserver(this, "xpcom-shutdown", false);
   1.535 +    }
   1.536 +
   1.537 +    return NS_OK;
   1.538 +}
   1.539 +
   1.540 +NS_IMETHODIMP nsProcess::GetIsRunning(bool *aIsRunning)
   1.541 +{
   1.542 +    if (mThread)
   1.543 +        *aIsRunning = true;
   1.544 +    else
   1.545 +        *aIsRunning = false;
   1.546 +
   1.547 +    return NS_OK;
   1.548 +}
   1.549 +
   1.550 +NS_IMETHODIMP
   1.551 +nsProcess::GetPid(uint32_t *aPid)
   1.552 +{
   1.553 +    if (!mThread)
   1.554 +        return NS_ERROR_FAILURE;
   1.555 +    if (mPid < 0)
   1.556 +        return NS_ERROR_NOT_IMPLEMENTED;
   1.557 +    *aPid = mPid;
   1.558 +    return NS_OK;
   1.559 +}
   1.560 +
   1.561 +NS_IMETHODIMP
   1.562 +nsProcess::Kill()
   1.563 +{
   1.564 +    if (!mThread)
   1.565 +        return NS_ERROR_FAILURE;
   1.566 +
   1.567 +    {
   1.568 +        MutexAutoLock lock(mLock);
   1.569 +#if defined(PROCESSMODEL_WINAPI)
   1.570 +        if (TerminateProcess(mProcess, 0) == 0)
   1.571 +            return NS_ERROR_FAILURE;
   1.572 +#elif defined(XP_MACOSX)
   1.573 +        if (kill(mPid, SIGKILL) != 0)
   1.574 +            return NS_ERROR_FAILURE;
   1.575 +#else
   1.576 +        if (!mProcess || (PR_KillProcess(mProcess) != PR_SUCCESS))
   1.577 +            return NS_ERROR_FAILURE;
   1.578 +#endif
   1.579 +    }
   1.580 +
   1.581 +    // We must null out mThread if we want IsRunning to return false immediately
   1.582 +    // after this call.
   1.583 +    nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   1.584 +    if (os)
   1.585 +        os->RemoveObserver(this, "xpcom-shutdown");
   1.586 +    PR_JoinThread(mThread);
   1.587 +    mThread = nullptr;
   1.588 +
   1.589 +    return NS_OK;
   1.590 +}
   1.591 +
   1.592 +NS_IMETHODIMP
   1.593 +nsProcess::GetExitValue(int32_t *aExitValue)
   1.594 +{
   1.595 +    MutexAutoLock lock(mLock);
   1.596 +
   1.597 +    *aExitValue = mExitValue;
   1.598 +    
   1.599 +    return NS_OK;
   1.600 +}
   1.601 +
   1.602 +NS_IMETHODIMP
   1.603 +nsProcess::Observe(nsISupports* subject, const char* topic, const char16_t* data)
   1.604 +{
   1.605 +    // Shutting down, drop all references
   1.606 +    if (mThread) {
   1.607 +        nsCOMPtr<nsIObserverService> os =
   1.608 +          mozilla::services::GetObserverService();
   1.609 +        if (os)
   1.610 +            os->RemoveObserver(this, "xpcom-shutdown");
   1.611 +        mThread = nullptr;
   1.612 +    }
   1.613 +
   1.614 +    mObserver = nullptr;
   1.615 +    mWeakObserver = nullptr;
   1.616 +
   1.617 +    MutexAutoLock lock(mLock);
   1.618 +    mShutdown = true;
   1.619 +
   1.620 +    return NS_OK;
   1.621 +}

mercurial