Mypal/hal/linux/LinuxPower.cpp

137 lines
3.8 KiB
C++

/* -*- 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