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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « handler/mac/exception_handler_server.h ('k') | handler/main.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Crashpad Authors. All rights reserved. 1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 // 2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License. 4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at 5 // You may obtain a copy of the License at
6 // 6 //
7 // http://www.apache.org/licenses/LICENSE-2.0 7 // http://www.apache.org/licenses/LICENSE-2.0
8 // 8 //
9 // Unless required by applicable law or agreed to in writing, software 9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and 12 // See the License for the specific language governing permissions and
13 // limitations under the License. 13 // limitations under the License.
14 14
15 #include "handler/mac/exception_handler_server.h" 15 #include "handler/mac/exception_handler_server.h"
16 16
17 #include <signal.h>
18
19 #include "base/auto_reset.h"
17 #include "base/logging.h" 20 #include "base/logging.h"
21 #include "base/memory/scoped_ptr.h"
22 #include "base/scoped_generic.h"
18 #include "base/mac/mach_logging.h" 23 #include "base/mac/mach_logging.h"
19 #include "util/mach/composite_mach_message_server.h" 24 #include "util/mach/composite_mach_message_server.h"
20 #include "util/mach/mach_extensions.h" 25 #include "util/mach/mach_extensions.h"
21 #include "util/mach/mach_message.h" 26 #include "util/mach/mach_message.h"
22 #include "util/mach/mach_message_server.h" 27 #include "util/mach/mach_message_server.h"
23 #include "util/mach/notify_server.h" 28 #include "util/mach/notify_server.h"
24 29
25 namespace crashpad { 30 namespace crashpad {
26 31
27 namespace { 32 namespace {
28 33
34 struct ResetSIGTERMTraits {
35 static struct sigaction* InvalidValue() {
36 return nullptr;
37 }
38
39 static void Free(struct sigaction* sa) {
40 int rv = sigaction(SIGTERM, sa, nullptr);
41 PLOG_IF(ERROR, rv != 0) << "sigaction";
42 }
43 };
44 using ScopedResetSIGTERM =
45 base::ScopedGeneric<struct sigaction*, ResetSIGTERMTraits>;
46
47 mach_port_t g_signal_notify_port;
48
49 // This signal handler is only operative when being run from launchd. It causes
50 // the exception handler server to stop running by sending it a synthesized
51 // no-senders notification.
52 void HandleSIGTERM(int sig, siginfo_t* siginfo, void* context) {
53 DCHECK(g_signal_notify_port);
54
55 // mach_no_senders_notification_t defines the receive side of this structure,
56 // with a trailer element that’s undesirable for the send side.
57 struct {
58 mach_msg_header_t header;
59 NDR_record_t ndr;
60 mach_msg_type_number_t mscount;
61 } no_senders_notification = {};
62 no_senders_notification.header.msgh_bits =
63 MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND_ONCE, 0);
64 no_senders_notification.header.msgh_size = sizeof(no_senders_notification);
65 no_senders_notification.header.msgh_remote_port = g_signal_notify_port;
66 no_senders_notification.header.msgh_local_port = MACH_PORT_NULL;
67 no_senders_notification.header.msgh_id = MACH_NOTIFY_NO_SENDERS;
68 no_senders_notification.ndr = NDR_record;
69 no_senders_notification.mscount = 0;
70
71 kern_return_t kr = mach_msg(&no_senders_notification.header,
72 MACH_SEND_MSG,
73 sizeof(no_senders_notification),
74 0,
75 MACH_PORT_NULL,
76 MACH_MSG_TIMEOUT_NONE,
77 MACH_PORT_NULL);
78 MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_msg";
79 }
80
29 class ExceptionHandlerServerRun : public UniversalMachExcServer::Interface, 81 class ExceptionHandlerServerRun : public UniversalMachExcServer::Interface,
30 public NotifyServer::DefaultInterface { 82 public NotifyServer::DefaultInterface {
31 public: 83 public:
32 ExceptionHandlerServerRun( 84 ExceptionHandlerServerRun(
33 mach_port_t exception_port, 85 mach_port_t exception_port,
86 bool launchd,
34 UniversalMachExcServer::Interface* exception_interface) 87 UniversalMachExcServer::Interface* exception_interface)
35 : UniversalMachExcServer::Interface(), 88 : UniversalMachExcServer::Interface(),
36 NotifyServer::DefaultInterface(), 89 NotifyServer::DefaultInterface(),
37 mach_exc_server_(this), 90 mach_exc_server_(this),
38 notify_server_(this), 91 notify_server_(this),
39 composite_mach_message_server_(), 92 composite_mach_message_server_(),
40 exception_interface_(exception_interface), 93 exception_interface_(exception_interface),
41 exception_port_(exception_port), 94 exception_port_(exception_port),
42 notify_port_(NewMachPort(MACH_PORT_RIGHT_RECEIVE)), 95 notify_port_(NewMachPort(MACH_PORT_RIGHT_RECEIVE)),
43 running_(true) { 96 running_(true),
97 launchd_(launchd) {
44 CHECK(notify_port_.is_valid()); 98 CHECK(notify_port_.is_valid());
45 99
46 composite_mach_message_server_.AddHandler(&mach_exc_server_); 100 composite_mach_message_server_.AddHandler(&mach_exc_server_);
47 composite_mach_message_server_.AddHandler(&notify_server_); 101 composite_mach_message_server_.AddHandler(&notify_server_);
48 } 102 }
49 103
50 ~ExceptionHandlerServerRun() { 104 ~ExceptionHandlerServerRun() {
51 } 105 }
52 106
53 void Run() { 107 void Run() {
54 DCHECK(running_); 108 DCHECK(running_);
55 109
56 // Request that a no-senders notification for exception_port_ be sent to 110 kern_return_t kr;
57 // notify_port_. 111 scoped_ptr<base::AutoReset<mach_port_t>> reset_signal_notify_port;
58 mach_port_t previous; 112 struct sigaction old_sa;
59 kern_return_t kr = 113 ScopedResetSIGTERM reset_sigterm;
60 mach_port_request_notification(mach_task_self(), 114 if (!launchd_) {
61 exception_port_, 115 // Request that a no-senders notification for exception_port_ be sent to
62 MACH_NOTIFY_NO_SENDERS, 116 // notify_port_.
63 0, 117 mach_port_t previous;
64 notify_port_.get(), 118 kr = mach_port_request_notification(mach_task_self(),
65 MACH_MSG_TYPE_MAKE_SEND_ONCE, 119 exception_port_,
66 &previous); 120 MACH_NOTIFY_NO_SENDERS,
67 MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_request_notification"; 121 0,
122 notify_port_.get(),
123 MACH_MSG_TYPE_MAKE_SEND_ONCE,
124 &previous);
125 MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_request_notification";
68 126
69 if (previous != MACH_PORT_NULL) { 127 if (previous != MACH_PORT_NULL) {
70 kr = mach_port_deallocate(mach_task_self(), previous); 128 kr = mach_port_deallocate(mach_task_self(), previous);
71 MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_deallocate"; 129 MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_deallocate";
130 }
131 } else {
132 // A real no-senders notification would never be triggered, because
133 // launchd maintains a send right to the service. When launchd wants the
134 // job to exit, it will send a SIGTERM. See launchd.plist(5).
135 //
136 // Set up a SIGTERM handler that will cause Run() to return (incidentally,
137 // by sending a synthetic no-senders notification).
138 struct sigaction sa = {};
139 sigemptyset(&sa.sa_mask);
140 sa.sa_flags = SA_SIGINFO;
141 sa.sa_sigaction = HandleSIGTERM;
142 int rv = sigaction(SIGTERM, &sa, &old_sa);
143 PCHECK(rv == 0) << "sigaction";
144 reset_sigterm.reset(&old_sa);
145
146 DCHECK(!g_signal_notify_port);
147 reset_signal_notify_port.reset(new base::AutoReset<mach_port_t>(
148 &g_signal_notify_port, notify_port_.get()));
72 } 149 }
73 150
74 // A single CompositeMachMessageServer will dispatch both exception messages 151 // A single CompositeMachMessageServer will dispatch both exception messages
75 // and the no-senders notification. Put both receive rights into a port set. 152 // and the no-senders notification. Put both receive rights into a port set.
76 // 153 //
77 // A single receive right can’t be used because the notification request 154 // A single receive right can’t be used because the notification request
78 // requires a send-once right, which would prevent the no-senders condition 155 // requires a send-once right, which would prevent the no-senders condition
79 // from ever existing. Using distinct receive rights also allows the handler 156 // from ever existing. Using distinct receive rights also allows the handler
80 // methods to ensure that the messages they process were sent by a holder of 157 // methods to ensure that the messages they process were sent by a holder of
81 // the proper send right. 158 // the proper send right.
82 base::mac::ScopedMachPortSet server_port_set( 159 base::mac::ScopedMachPortSet server_port_set(
83 NewMachPort(MACH_PORT_RIGHT_PORT_SET)); 160 NewMachPort(MACH_PORT_RIGHT_PORT_SET));
161 CHECK(server_port_set.is_valid());
84 162
85 kr = mach_port_insert_member( 163 kr = mach_port_insert_member(
86 mach_task_self(), exception_port_, server_port_set.get()); 164 mach_task_self(), exception_port_, server_port_set.get());
87 MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_insert_member"; 165 MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_insert_member";
88 166
89 kr = mach_port_insert_member( 167 kr = mach_port_insert_member(
90 mach_task_self(), notify_port_.get(), server_port_set.get()); 168 mach_task_self(), notify_port_.get(), server_port_set.get());
91 MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_insert_member"; 169 MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_insert_member";
92 170
93 // Run the server in kOneShot mode so that running_ can be reevaluated after 171 // Run the server in kOneShot mode so that running_ can be reevaluated after
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 } 244 }
167 245
168 private: 246 private:
169 UniversalMachExcServer mach_exc_server_; 247 UniversalMachExcServer mach_exc_server_;
170 NotifyServer notify_server_; 248 NotifyServer notify_server_;
171 CompositeMachMessageServer composite_mach_message_server_; 249 CompositeMachMessageServer composite_mach_message_server_;
172 UniversalMachExcServer::Interface* exception_interface_; // weak 250 UniversalMachExcServer::Interface* exception_interface_; // weak
173 mach_port_t exception_port_; // weak 251 mach_port_t exception_port_; // weak
174 base::mac::ScopedMachReceiveRight notify_port_; 252 base::mac::ScopedMachReceiveRight notify_port_;
175 bool running_; 253 bool running_;
254 bool launchd_;
176 255
177 DISALLOW_COPY_AND_ASSIGN(ExceptionHandlerServerRun); 256 DISALLOW_COPY_AND_ASSIGN(ExceptionHandlerServerRun);
178 }; 257 };
179 258
180 } // namespace 259 } // namespace
181 260
182 ExceptionHandlerServer::ExceptionHandlerServer( 261 ExceptionHandlerServer::ExceptionHandlerServer(
183 base::mac::ScopedMachReceiveRight receive_port) 262 base::mac::ScopedMachReceiveRight receive_port,
184 : receive_port_(receive_port.Pass()) { 263 bool launchd)
264 : receive_port_(receive_port.Pass()),
265 launchd_(launchd) {
185 CHECK(receive_port_.is_valid()); 266 CHECK(receive_port_.is_valid());
186 } 267 }
187 268
188 ExceptionHandlerServer::~ExceptionHandlerServer() { 269 ExceptionHandlerServer::~ExceptionHandlerServer() {
189 } 270 }
190 271
191 void ExceptionHandlerServer::Run( 272 void ExceptionHandlerServer::Run(
192 UniversalMachExcServer::Interface* exception_interface) { 273 UniversalMachExcServer::Interface* exception_interface) {
193 ExceptionHandlerServerRun run(receive_port_.get(), exception_interface); 274 ExceptionHandlerServerRun run(
275 receive_port_.get(), launchd_, exception_interface);
194 run.Run(); 276 run.Run();
195 } 277 }
196 278
197 } // namespace crashpad 279 } // namespace crashpad
OLDNEW
« 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