Coverage Report

Created: 2018-09-25 14:53

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