Skip to content

Commit

Permalink
Backed out 3 changesets (bug 1658072) as they are related to previous…
Browse files Browse the repository at this point in the history
…ly backed out changeset CLOSED TREE

Backed out changeset 199d3ecfe13c (bug 1658072)
Backed out changeset a942be3d053d (bug 1658072)
Backed out changeset e0e98ee85f98 (bug 1658072)
  • Loading branch information
Norisz Fay committed Aug 10, 2022
1 parent 936d025 commit fd17201
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 26 deletions.
5 changes: 5 additions & 0 deletions ipc/chromium/src/base/message_loop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -728,4 +728,9 @@ bool MessageLoopForIO::WatchFileDescriptor(int fd, bool persistent, Mode mode,
controller, delegate);
}

bool MessageLoopForIO::CatchSignal(int sig, SignalEvent* sigevent,
SignalWatcher* delegate) {
return pump_libevent()->CatchSignal(sig, sigevent, delegate);
}

#endif
4 changes: 4 additions & 0 deletions ipc/chromium/src/base/message_loop.h
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,10 @@ class MessageLoopForIO : public MessageLoop {
FileDescriptorWatcher* controller,
Watcher* delegate);

typedef base::MessagePumpLibevent::SignalEvent SignalEvent;
typedef base::MessagePumpLibevent::SignalWatcher SignalWatcher;
bool CatchSignal(int sig, SignalEvent* sigevent, SignalWatcher* delegate);

#endif // defined(OS_POSIX)
};

Expand Down
70 changes: 70 additions & 0 deletions ipc/chromium/src/base/message_pump_libevent.cc
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,76 @@ void MessagePumpLibevent::OnLibeventNotification(int fd, short flags,
}
}

MessagePumpLibevent::SignalEvent::SignalEvent() : event_(NULL) {}

MessagePumpLibevent::SignalEvent::~SignalEvent() {
if (event_) {
StopCatching();
}
}

void MessagePumpLibevent::SignalEvent::Init(event* e) {
DCHECK(e);
DCHECK(event_ == NULL);
event_ = e;
}

bool MessagePumpLibevent::SignalEvent::StopCatching() {
// XXX/cjones: this code could be shared with
// FileDescriptorWatcher. ironic that libevent is "more"
// object-oriented than this C++
event* e = ReleaseEvent();
if (e == NULL) return true;

// event_del() is a no-op if the event isn't active.
int rv = event_del(e);
delete e;
return (rv == 0);
}

event* MessagePumpLibevent::SignalEvent::ReleaseEvent() {
event* e = event_;
event_ = NULL;
return e;
}

bool MessagePumpLibevent::CatchSignal(int sig, SignalEvent* sigevent,
SignalWatcher* delegate) {
DCHECK(sig > 0);
DCHECK(sigevent);
DCHECK(delegate);
// TODO if we want to support re-using SignalEvents, this code needs
// to jump through the same hoops as WatchFileDescriptor(). Not
// needed at present
DCHECK(NULL == sigevent->event_);

mozilla::UniquePtr<event> evt = mozilla::MakeUnique<event>();
signal_set(evt.get(), sig, OnLibeventSignalNotification, delegate);

if (event_base_set(event_base_, evt.get())) return false;

if (signal_add(evt.get(), NULL)) return false;

// Transfer ownership of evt to controller.
sigevent->Init(evt.release());
return true;
}

void MessagePumpLibevent::OnLibeventSignalNotification(int sig, short flags,
void* context) {
if (!awake_) {
profiler_thread_wake();
awake_ = true;
}
AUTO_PROFILER_LABEL("MessagePumpLibevent::OnLibeventSignalNotification",
OTHER);

DCHECK(sig > 0);
DCHECK(EV_SIGNAL == flags);
DCHECK(context);
reinterpret_cast<SignalWatcher*>(context)->OnSignal(sig);
}

// Reentrant!
void MessagePumpLibevent::Run(Delegate* delegate) {
DCHECK(keep_running_) << "Quit must have been called outside of Run!";
Expand Down
45 changes: 45 additions & 0 deletions ipc/chromium/src/base/message_pump_libevent.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,48 @@ class MessagePumpLibevent : public MessagePump {
FileDescriptorWatcher* controller,
Watcher* delegate);

// This is analagous to FileDescriptorWatcher above, which really is
// just a wrapper around libevent's |struct event|. This class acts
// as a sort of "scoped event watcher" in that it guarantees that
// when this class is out of scope, the signal-event it wraps is
// removed from libevent's guts.
//
// XXX/cjones: this isn't my favorite API, but preserving it in
// order to match code above
class SignalEvent {
friend class MessagePumpLibevent;

public:
SignalEvent();
~SignalEvent(); // implicitly calls StopCatching()

// Have libevent forget this event.
bool StopCatching();

private:
void Init(event* e);
event* ReleaseEvent();

event* event_;

DISALLOW_COPY_AND_ASSIGN(SignalEvent);
};

class SignalWatcher {
public:
virtual ~SignalWatcher() {}
// Called from MessageLoop::Run when |sig| has been delivered to
// this process
virtual void OnSignal(int sig) = 0;
};

// Have the current thread's message loop catch the signal |sig|.
// Multiple watchers can catch the same signal; they're all notified
// upon its delivery. Callers must provide a preallocated
// SignalEvent object which can be used to manage the lifetime of
// this event. Returns true on success.
bool CatchSignal(int sig, SignalEvent* sigevent, SignalWatcher* delegate);

// MessagePump methods:
virtual void Run(Delegate* delegate) override;
virtual void Quit() override;
Expand Down Expand Up @@ -111,6 +153,9 @@ class MessagePumpLibevent : public MessagePump {
// Called by libevent to tell us a registered FD can be read/written to.
static void OnLibeventNotification(int fd, short flags, void* context);

// Called by libevent upon receiving a signal
static void OnLibeventSignalNotification(int sig, short flags, void* context);

// Unix pipe used to implement ScheduleWork()
// ... callback; called by libevent inside Run() when pipe is ready to read
static void OnWakeup(int socket, short flags, void* context);
Expand Down
9 changes: 9 additions & 0 deletions ipc/chromium/src/base/process_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,15 @@ bool LaunchApp(const CommandLine& cl, const LaunchOptions&,
// Returns true if this is successful, false otherwise.
bool KillProcess(ProcessHandle process, int exit_code);

// Get the termination status (exit code) of the process and return true if the
// status indicates the process crashed. |child_exited| is set to true iff the
// child process has terminated. (|child_exited| may be NULL.)
//
// On Windows, it is an error to call this if the process hasn't terminated
// yet. On POSIX, |child_exited| is set correctly since we detect terminate in
// a different manner on POSIX.
bool DidProcessCrash(bool* child_exited, ProcessHandle handle);

} // namespace base

namespace mozilla {
Expand Down
61 changes: 61 additions & 0 deletions ipc/chromium/src/base/process_util_posix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,67 @@ void CloseSuperfluousFds(void* aCtx, bool (*aShouldPreserve)(void*, int)) {
}
}

bool DidProcessCrash(bool* child_exited, ProcessHandle handle) {
#ifdef MOZ_ENABLE_FORKSERVER
if (mozilla::ipc::ForkServiceChild::Get()) {
// We only know if a process exists, but not if it has crashed.
//
// Since content processes are not direct children of the chrome
// process any more, it is impossible to use |waitpid()| to wait for
// them.
const int r = kill(handle, 0);
if (r < 0 && errno == ESRCH) {
if (child_exited) *child_exited = true;
} else {
if (child_exited) *child_exited = false;
}

return false;
}
#endif
int status;
const int result = HANDLE_EINTR(waitpid(handle, &status, WNOHANG));
if (result == -1) {
// This shouldn't happen, but sometimes it does. The error is
// probably ECHILD and the reason is probably that a pid was
// waited on again after a previous wait reclaimed its zombie.
// (It could also occur if the process isn't a direct child, but
// don't do that.) This is bad, because it risks interfering with
// an unrelated child process if the pid is reused.
//
// So, lacking reliable information, we indicate that the process
// is dead, in the hope that the caller will give up and stop
// calling us. See also bug 943174 and bug 933680.
CHROMIUM_LOG(ERROR) << "waitpid failed pid:" << handle
<< " errno:" << errno;
if (child_exited) *child_exited = true;
return false;
} else if (result == 0) {
// the child hasn't exited yet.
if (child_exited) *child_exited = false;
return false;
}

if (child_exited) *child_exited = true;

if (WIFSIGNALED(status)) {
switch (WTERMSIG(status)) {
case SIGSYS:
case SIGSEGV:
case SIGILL:
case SIGABRT:
case SIGFPE:
return true;
default:
return false;
}
}

if (WIFEXITED(status)) return WEXITSTATUS(status) != 0;

return false;
}

void FreeEnvVarsArray::operator()(char** array) {
for (char** varPtr = array; *varPtr != nullptr; ++varPtr) {
free(*varPtr);
Expand Down
31 changes: 31 additions & 0 deletions ipc/chromium/src/base/process_util_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,37 @@ bool KillProcess(ProcessHandle process, int exit_code) {
return result;
}

bool DidProcessCrash(bool* child_exited, ProcessHandle handle) {
DWORD exitcode = 0;

if (child_exited)
*child_exited = true; // On Windows it an error to call this function if
// the child hasn't already exited.
if (!::GetExitCodeProcess(handle, &exitcode)) {
NOTREACHED();
return false;
}
if (exitcode == STILL_ACTIVE) {
// The process is likely not dead or it used 0x103 as exit code.
NOTREACHED();
return false;
}

// Warning, this is not generic code; it heavily depends on the way
// the rest of the code kills a process.

if (exitcode == PROCESS_END_NORMAL_TERMINATON ||
exitcode == PROCESS_END_KILLED_BY_USER ||
exitcode == PROCESS_END_PROCESS_WAS_HUNG ||
exitcode == 0xC0000354 || // STATUS_DEBUGGER_INACTIVE.
exitcode == 0xC000013A || // Control-C/end session.
exitcode == 0x40010004) { // Debugger terminated process/end session.
return false;
}

return true;
}

} // namespace base

namespace mozilla {
Expand Down

This file was deleted.

4 changes: 0 additions & 4 deletions ipc/chromium/src/third_party/libevent/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@
#include "evmap-internal.h"
#include "evthread-internal.h"

#include "mozilla/Assertions.h"

/*
signal.c
Expand Down Expand Up @@ -284,8 +282,6 @@ evsig_add(struct event_base *base, evutil_socket_t evsignal, short old, short ev
struct evsig_info *sig = &base->sig;
(void)p;

MOZ_CRASH("Don't use this; see bug 1616462");

EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);

/* catch signals if they happen quickly */
Expand Down
4 changes: 4 additions & 0 deletions xpcom/base/nsDumpUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ using namespace mozilla;
* This scheme is similar to using signalfd(), except it's portable and it
* doesn't require the use of sigprocmask, which is problematic because it
* masks signals received by child processes.
*
* In theory, we could use Chromium's MessageLoopForIO::CatchSignal() for this.
* But that uses libevent, which does not handle the realtime signals (bug
* 794074).
*/

// This is the write-end of a pipe that we use to notice when a
Expand Down
4 changes: 4 additions & 0 deletions xpcom/base/nsMemoryInfoDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ namespace {
* This scheme is similar to using signalfd(), except it's portable and it
* doesn't require the use of sigprocmask, which is problematic because it
* masks signals received by child processes.
*
* In theory, we could use Chromium's MessageLoopForIO::CatchSignal() for this.
* But that uses libevent, which does not handle the realtime signals (bug
* 794074).
*/

// It turns out that at least on some systems, SIGRTMIN is not a compile-time
Expand Down

0 comments on commit fd17201

Please sign in to comment.