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-06-02 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