Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(277)

Unified Diff: handler/mac/exception_handler_server.cc

Issue 1414533006: mac: Add a mode to crashpad_handler to run from launchd (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Rebase Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « handler/mac/exception_handler_server.h ('k') | handler/main.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: handler/mac/exception_handler_server.cc
diff --git a/handler/mac/exception_handler_server.cc b/handler/mac/exception_handler_server.cc
index 3757c454fbf9f209c594d94049f87ed828f4f8bf..19038293bf104be39b48310cfa139efe57eaaadc 100644
--- a/handler/mac/exception_handler_server.cc
+++ b/handler/mac/exception_handler_server.cc
@@ -14,7 +14,12 @@
#include "handler/mac/exception_handler_server.h"
+#include <signal.h>
+
+#include "base/auto_reset.h"
#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/scoped_generic.h"
#include "base/mac/mach_logging.h"
#include "util/mach/composite_mach_message_server.h"
#include "util/mach/mach_extensions.h"
@@ -26,11 +31,59 @@ namespace crashpad {
namespace {
+struct ResetSIGTERMTraits {
+ static struct sigaction* InvalidValue() {
+ return nullptr;
+ }
+
+ static void Free(struct sigaction* sa) {
+ int rv = sigaction(SIGTERM, sa, nullptr);
+ PLOG_IF(ERROR, rv != 0) << "sigaction";
+ }
+};
+using ScopedResetSIGTERM =
+ base::ScopedGeneric<struct sigaction*, ResetSIGTERMTraits>;
+
+mach_port_t g_signal_notify_port;
+
+// This signal handler is only operative when being run from launchd. It causes
+// the exception handler server to stop running by sending it a synthesized
+// no-senders notification.
+void HandleSIGTERM(int sig, siginfo_t* siginfo, void* context) {
+ DCHECK(g_signal_notify_port);
+
+ // mach_no_senders_notification_t defines the receive side of this structure,
+ // with a trailer element that’s undesirable for the send side.
+ struct {
+ mach_msg_header_t header;
+ NDR_record_t ndr;
+ mach_msg_type_number_t mscount;
+ } no_senders_notification = {};
+ no_senders_notification.header.msgh_bits =
+ MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND_ONCE, 0);
+ no_senders_notification.header.msgh_size = sizeof(no_senders_notification);
+ no_senders_notification.header.msgh_remote_port = g_signal_notify_port;
+ no_senders_notification.header.msgh_local_port = MACH_PORT_NULL;
+ no_senders_notification.header.msgh_id = MACH_NOTIFY_NO_SENDERS;
+ no_senders_notification.ndr = NDR_record;
+ no_senders_notification.mscount = 0;
+
+ kern_return_t kr = mach_msg(&no_senders_notification.header,
+ MACH_SEND_MSG,
+ sizeof(no_senders_notification),
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_msg";
+}
+
class ExceptionHandlerServerRun : public UniversalMachExcServer::Interface,
public NotifyServer::DefaultInterface {
public:
ExceptionHandlerServerRun(
mach_port_t exception_port,
+ bool launchd,
UniversalMachExcServer::Interface* exception_interface)
: UniversalMachExcServer::Interface(),
NotifyServer::DefaultInterface(),
@@ -40,7 +93,8 @@ class ExceptionHandlerServerRun : public UniversalMachExcServer::Interface,
exception_interface_(exception_interface),
exception_port_(exception_port),
notify_port_(NewMachPort(MACH_PORT_RIGHT_RECEIVE)),
- running_(true) {
+ running_(true),
+ launchd_(launchd) {
CHECK(notify_port_.is_valid());
composite_mach_message_server_.AddHandler(&mach_exc_server_);
@@ -53,22 +107,45 @@ class ExceptionHandlerServerRun : public UniversalMachExcServer::Interface,
void Run() {
DCHECK(running_);
- // Request that a no-senders notification for exception_port_ be sent to
- // notify_port_.
- mach_port_t previous;
- kern_return_t kr =
- mach_port_request_notification(mach_task_self(),
- exception_port_,
- MACH_NOTIFY_NO_SENDERS,
- 0,
- notify_port_.get(),
- MACH_MSG_TYPE_MAKE_SEND_ONCE,
- &previous);
- MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_request_notification";
-
- if (previous != MACH_PORT_NULL) {
- kr = mach_port_deallocate(mach_task_self(), previous);
- MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_deallocate";
+ kern_return_t kr;
+ scoped_ptr<base::AutoReset<mach_port_t>> reset_signal_notify_port;
+ struct sigaction old_sa;
+ ScopedResetSIGTERM reset_sigterm;
+ if (!launchd_) {
+ // Request that a no-senders notification for exception_port_ be sent to
+ // notify_port_.
+ mach_port_t previous;
+ kr = mach_port_request_notification(mach_task_self(),
+ exception_port_,
+ MACH_NOTIFY_NO_SENDERS,
+ 0,
+ notify_port_.get(),
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &previous);
+ MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_request_notification";
+
+ if (previous != MACH_PORT_NULL) {
+ kr = mach_port_deallocate(mach_task_self(), previous);
+ MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_deallocate";
+ }
+ } else {
+ // A real no-senders notification would never be triggered, because
+ // launchd maintains a send right to the service. When launchd wants the
+ // job to exit, it will send a SIGTERM. See launchd.plist(5).
+ //
+ // Set up a SIGTERM handler that will cause Run() to return (incidentally,
+ // by sending a synthetic no-senders notification).
+ struct sigaction sa = {};
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_SIGINFO;
+ sa.sa_sigaction = HandleSIGTERM;
+ int rv = sigaction(SIGTERM, &sa, &old_sa);
+ PCHECK(rv == 0) << "sigaction";
+ reset_sigterm.reset(&old_sa);
+
+ DCHECK(!g_signal_notify_port);
+ reset_signal_notify_port.reset(new base::AutoReset<mach_port_t>(
+ &g_signal_notify_port, notify_port_.get()));
}
// A single CompositeMachMessageServer will dispatch both exception messages
@@ -81,6 +158,7 @@ class ExceptionHandlerServerRun : public UniversalMachExcServer::Interface,
// the proper send right.
base::mac::ScopedMachPortSet server_port_set(
NewMachPort(MACH_PORT_RIGHT_PORT_SET));
+ CHECK(server_port_set.is_valid());
kr = mach_port_insert_member(
mach_task_self(), exception_port_, server_port_set.get());
@@ -173,6 +251,7 @@ class ExceptionHandlerServerRun : public UniversalMachExcServer::Interface,
mach_port_t exception_port_; // weak
base::mac::ScopedMachReceiveRight notify_port_;
bool running_;
+ bool launchd_;
DISALLOW_COPY_AND_ASSIGN(ExceptionHandlerServerRun);
};
@@ -180,8 +259,10 @@ class ExceptionHandlerServerRun : public UniversalMachExcServer::Interface,
} // namespace
ExceptionHandlerServer::ExceptionHandlerServer(
- base::mac::ScopedMachReceiveRight receive_port)
- : receive_port_(receive_port.Pass()) {
+ base::mac::ScopedMachReceiveRight receive_port,
+ bool launchd)
+ : receive_port_(receive_port.Pass()),
+ launchd_(launchd) {
CHECK(receive_port_.is_valid());
}
@@ -190,7 +271,8 @@ ExceptionHandlerServer::~ExceptionHandlerServer() {
void ExceptionHandlerServer::Run(
UniversalMachExcServer::Interface* exception_interface) {
- ExceptionHandlerServerRun run(receive_port_.get(), exception_interface);
+ ExceptionHandlerServerRun run(
+ receive_port_.get(), launchd_, exception_interface);
run.Run();
}
« no previous file with comments | « handler/mac/exception_handler_server.h ('k') | handler/main.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698