hal/linux/LinuxPower.cpp
author Nicholas Nethercote <nnethercote@mozilla.com>
Mon, 24 Jul 2017 10:08:55 +1000
changeset 419215 c9b593e3e697f71dedf28c6a40e4db6a5b3462ab
parent 416428 6a629adbb62a299d7208373d1c6f375149d2afdb
permissions -rw-r--r--
Bug 1382099 - Remove MOZ_WIDGET_GONK from hal/. r=gsvelto.

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "Hal.h"
#include "HalLog.h"

#include <unistd.h>
#include <sys/reboot.h>
#include "nsIObserverService.h"
#include "mozilla/Services.h"
#include "MainThreadUtils.h"

namespace mozilla {
namespace hal_impl {

void
Reboot()
{
  if (NS_IsMainThread()) {
    nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService();
    if (obsServ) {
      obsServ->NotifyObservers(nullptr, "system-reboot", nullptr);
    }
  }

  sync();
  reboot(RB_AUTOBOOT);
}

void
PowerOff()
{
  if (NS_IsMainThread()) {
    nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService();
    if (obsServ) {
      obsServ->NotifyObservers(nullptr, "system-power-off", nullptr);
    }
  }

  sync();
  reboot(RB_POWER_OFF);
}

// Structure to specify how watchdog pthread is going to work.
typedef struct watchdogParam
{
  hal::ShutdownMode mode; // Specify how to shutdown the system.
  int32_t timeoutSecs;    // Specify the delayed seconds to shutdown the system.

  watchdogParam(hal::ShutdownMode aMode, int32_t aTimeoutSecs)
    : mode(aMode), timeoutSecs(aTimeoutSecs) {}
} watchdogParam_t;

// Function to complusively shut down the system with a given mode.
static void
QuitHard(hal::ShutdownMode aMode)
{
  switch (aMode)
  {
    case hal::eHalShutdownMode_PowerOff:
      PowerOff();
      break;
    case hal::eHalShutdownMode_Reboot:
      Reboot();
      break;
    case hal::eHalShutdownMode_Restart:
      // Don't let signal handlers affect forced shutdown.
      kill(0, SIGKILL);
      // If we can't SIGKILL our process group, something is badly
      // wrong.  Trying to deliver a catch-able signal to ourselves can
      // invoke signal handlers and might cause problems.  So try
      // _exit() and hope we go away.
      _exit(1);
      break;
    default:
      MOZ_CRASH();
  }
}

// Function to complusively shut down the system with a given mode when timeout.
static void*
ForceQuitWatchdog(void* aParamPtr)
{
  watchdogParam_t* paramPtr = reinterpret_cast<watchdogParam_t*>(aParamPtr);
  if (paramPtr->timeoutSecs > 0 && paramPtr->timeoutSecs <= 30) {
    // If we shut down normally before the timeout, this thread will
    // be harmlessly reaped by the OS.
    TimeStamp deadline =
      (TimeStamp::Now() + TimeDuration::FromSeconds(paramPtr->timeoutSecs));
    while (true) {
      TimeDuration remaining = (deadline - TimeStamp::Now());
      int sleepSeconds = int(remaining.ToSeconds());
      if (sleepSeconds <= 0) {
        break;
      }
      sleep(sleepSeconds);
    }
  }
  hal::ShutdownMode mode = paramPtr->mode;
  delete paramPtr;
  QuitHard(mode);
  return nullptr;
}

void
StartForceQuitWatchdog(hal::ShutdownMode aMode, int32_t aTimeoutSecs)
{
  // Force-quits are intepreted a little more ferociously on Gonk,
  // because while Gecko is in the process of shutting down, the user
  // can't call 911, for example.  And if we hang on shutdown, bad
  // things happen.  So, make sure that doesn't happen.
  if (aTimeoutSecs <= 0) {
    return;
  }

  // Use a raw pthread here to insulate ourselves from bugs in other
  // Gecko code that we're trying to protect!
  //
  // Note that we let the watchdog in charge of releasing |paramPtr|
  // if the pthread is successfully created.
  watchdogParam_t* paramPtr = new watchdogParam_t(aMode, aTimeoutSecs);
  pthread_t watchdog;
  if (pthread_create(&watchdog, nullptr,
                     ForceQuitWatchdog,
                     reinterpret_cast<void*>(paramPtr))) {
    // Better safe than sorry.
    delete paramPtr;
    QuitHard(aMode);
  }
  // The watchdog thread is off and running now.
}

} // hal_impl
} // mozilla