LCOV - app.info - xpcom/threads/nsProcessCommon.cpp

LCOV - code coverage report
| Current view: | directory - xpcom/threads - nsProcessCommon.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 154 | 119 | 77.3 %
| Date: | 2012-04-21 | Functions: | 20 | 17 | 85.0 %

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

Generated by: LCOV version 1.7