| OLD | NEW |
| 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, |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 namespace crashpad { | 60 namespace crashpad { |
| 61 namespace test { | 61 namespace test { |
| 62 | 62 |
| 63 using namespace testing; | 63 using namespace testing; |
| 64 | 64 |
| 65 namespace internal { | 65 namespace internal { |
| 66 | 66 |
| 67 struct MachMultiprocessInfo { | 67 struct MachMultiprocessInfo { |
| 68 MachMultiprocessInfo() | 68 MachMultiprocessInfo() |
| 69 : service_name(), | 69 : service_name(), |
| 70 read_pipe(-1), | 70 pipe_c2p_read(-1), |
| 71 write_pipe(-1), | 71 pipe_c2p_write(-1), |
| 72 pipe_p2c_read(-1), |
| 73 pipe_p2c_write(-1), |
| 72 child_pid(0), | 74 child_pid(0), |
| 73 pipe_fd(-1), | 75 read_pipe_fd(-1), |
| 76 write_pipe_fd(-1), |
| 74 local_port(MACH_PORT_NULL), | 77 local_port(MACH_PORT_NULL), |
| 75 remote_port(MACH_PORT_NULL), | 78 remote_port(MACH_PORT_NULL), |
| 76 child_task(MACH_PORT_NULL) {} | 79 child_task(MACH_PORT_NULL) {} |
| 77 | 80 |
| 78 std::string service_name; | 81 std::string service_name; |
| 79 base::ScopedFD read_pipe; | 82 base::ScopedFD pipe_c2p_read; // child to parent |
| 80 base::ScopedFD write_pipe; | 83 base::ScopedFD pipe_c2p_write; // child to parent |
| 84 base::ScopedFD pipe_p2c_read; // parent to child |
| 85 base::ScopedFD pipe_p2c_write; // parent to child |
| 81 pid_t child_pid; // valid only in parent | 86 pid_t child_pid; // valid only in parent |
| 82 int pipe_fd; // read_pipe in parent, write_pipe in child | 87 int read_pipe_fd; // pipe_c2p_read in parent, pipe_p2c_read in child |
| 88 int write_pipe_fd; // pipe_p2c_write in parent, pipe_c2p_write in child |
| 83 base::mac::ScopedMachReceiveRight local_port; | 89 base::mac::ScopedMachReceiveRight local_port; |
| 84 base::mac::ScopedMachSendRight remote_port; | 90 base::mac::ScopedMachSendRight remote_port; |
| 85 base::mac::ScopedMachSendRight child_task; // valid only in parent | 91 base::mac::ScopedMachSendRight child_task; // valid only in parent |
| 86 }; | 92 }; |
| 87 | 93 |
| 88 } // namespace internal | 94 } // namespace internal |
| 89 | 95 |
| 90 MachMultiprocess::MachMultiprocess() : info_(NULL) { | 96 MachMultiprocess::MachMultiprocess() : info_(NULL) { |
| 91 } | 97 } |
| 92 | 98 |
| 93 void MachMultiprocess::Run() { | 99 void MachMultiprocess::Run() { |
| 94 ASSERT_EQ(NULL, info_); | 100 ASSERT_EQ(NULL, info_); |
| 95 scoped_ptr<internal::MachMultiprocessInfo> info( | 101 scoped_ptr<internal::MachMultiprocessInfo> info( |
| 96 new internal::MachMultiprocessInfo); | 102 new internal::MachMultiprocessInfo); |
| 97 base::AutoReset<internal::MachMultiprocessInfo*> reset_info(&info_, | 103 base::AutoReset<internal::MachMultiprocessInfo*> reset_info(&info_, |
| 98 info.get()); | 104 info.get()); |
| 99 | 105 |
| 100 int pipe_fds[2]; | 106 int pipe_fds_c2p[2]; |
| 101 int rv = pipe(pipe_fds); | 107 int rv = pipe(pipe_fds_c2p); |
| 102 ASSERT_EQ(0, rv) << ErrnoMessage("pipe"); | 108 ASSERT_EQ(0, rv) << ErrnoMessage("pipe"); |
| 103 | 109 |
| 104 info_->read_pipe.reset(pipe_fds[0]); | 110 info_->pipe_c2p_read.reset(pipe_fds_c2p[0]); |
| 105 info_->write_pipe.reset(pipe_fds[1]); | 111 info_->pipe_c2p_write.reset(pipe_fds_c2p[1]); |
| 112 |
| 113 int pipe_fds_p2c[2]; |
| 114 rv = pipe(pipe_fds_p2c); |
| 115 ASSERT_EQ(0, rv) << ErrnoMessage("pipe"); |
| 116 |
| 117 info_->pipe_p2c_read.reset(pipe_fds_p2c[0]); |
| 118 info_->pipe_p2c_write.reset(pipe_fds_p2c[1]); |
| 106 | 119 |
| 107 // Set up the parent port and register it with the bootstrap server before | 120 // Set up the parent port and register it with the bootstrap server before |
| 108 // forking, so that it’s guaranteed to be there when the child attempts to | 121 // forking, so that it’s guaranteed to be there when the child attempts to |
| 109 // look it up. | 122 // look it up. |
| 110 info_->service_name = "com.googlecode.crashpad.test.mach_multiprocess."; | 123 info_->service_name = "com.googlecode.crashpad.test.mach_multiprocess."; |
| 111 for (int index = 0; index < 16; ++index) { | 124 for (int index = 0; index < 16; ++index) { |
| 112 info_->service_name.append(1, base::RandInt('A', 'Z')); | 125 info_->service_name.append(1, base::RandInt('A', 'Z')); |
| 113 } | 126 } |
| 114 | 127 |
| 115 mach_port_t local_port; | 128 mach_port_t local_port; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 162 } | 175 } |
| 163 | 176 |
| 164 MachMultiprocess::~MachMultiprocess() { | 177 MachMultiprocess::~MachMultiprocess() { |
| 165 } | 178 } |
| 166 | 179 |
| 167 pid_t MachMultiprocess::ChildPID() const { | 180 pid_t MachMultiprocess::ChildPID() const { |
| 168 EXPECT_NE(0, info_->child_pid); | 181 EXPECT_NE(0, info_->child_pid); |
| 169 return info_->child_pid; | 182 return info_->child_pid; |
| 170 } | 183 } |
| 171 | 184 |
| 172 int MachMultiprocess::PipeFD() const { | 185 int MachMultiprocess::ReadPipeFD() const { |
| 173 EXPECT_NE(-1, info_->pipe_fd); | 186 EXPECT_NE(-1, info_->read_pipe_fd); |
| 174 return info_->pipe_fd; | 187 return info_->read_pipe_fd; |
| 188 } |
| 189 |
| 190 int MachMultiprocess::WritePipeFD() const { |
| 191 EXPECT_NE(-1, info_->write_pipe_fd); |
| 192 return info_->write_pipe_fd; |
| 175 } | 193 } |
| 176 | 194 |
| 177 mach_port_t MachMultiprocess::LocalPort() const { | 195 mach_port_t MachMultiprocess::LocalPort() const { |
| 178 EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL), info_->local_port); | 196 EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL), info_->local_port); |
| 179 return info_->local_port; | 197 return info_->local_port; |
| 180 } | 198 } |
| 181 | 199 |
| 182 mach_port_t MachMultiprocess::RemotePort() const { | 200 mach_port_t MachMultiprocess::RemotePort() const { |
| 183 EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL), info_->remote_port); | 201 EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL), info_->remote_port); |
| 184 return info_->remote_port; | 202 return info_->remote_port; |
| 185 } | 203 } |
| 186 | 204 |
| 187 mach_port_t MachMultiprocess::ChildTask() const { | 205 mach_port_t MachMultiprocess::ChildTask() const { |
| 188 EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL), info_->child_task); | 206 EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL), info_->child_task); |
| 189 return info_->child_task; | 207 return info_->child_task; |
| 190 } | 208 } |
| 191 | 209 |
| 192 void MachMultiprocess::RunParent() { | 210 void MachMultiprocess::RunParent() { |
| 193 // The parent uses the read end of the pipe. | 211 // The parent uses the read end of c2p and the write end of p2c. |
| 194 info_->write_pipe.reset(); | 212 info_->pipe_c2p_write.reset(); |
| 195 info_->pipe_fd = info_->read_pipe.get(); | 213 info_->read_pipe_fd = info_->pipe_c2p_read.get(); |
| 214 info_->pipe_p2c_read.reset(); |
| 215 info_->write_pipe_fd = info_->pipe_p2c_write.get(); |
| 196 | 216 |
| 197 ReceiveHelloMessage message = {}; | 217 ReceiveHelloMessage message = {}; |
| 198 | 218 |
| 199 kern_return_t kr = | 219 kern_return_t kr = |
| 200 mach_msg(&message.header, | 220 mach_msg(&message.header, |
| 201 MACH_RCV_MSG | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) | | 221 MACH_RCV_MSG | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) | |
| 202 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT), | 222 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT), |
| 203 0, | 223 0, |
| 204 sizeof(message), | 224 sizeof(message), |
| 205 info_->local_port, | 225 info_->local_port, |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 277 int mach_pid; | 297 int mach_pid; |
| 278 kr = pid_for_task(info_->child_task, &mach_pid); | 298 kr = pid_for_task(info_->child_task, &mach_pid); |
| 279 ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "pid_for_task"); | 299 ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "pid_for_task"); |
| 280 ASSERT_EQ(ChildPID(), mach_pid); | 300 ASSERT_EQ(ChildPID(), mach_pid); |
| 281 | 301 |
| 282 Parent(); | 302 Parent(); |
| 283 | 303 |
| 284 info_->remote_port.reset(); | 304 info_->remote_port.reset(); |
| 285 info_->local_port.reset(); | 305 info_->local_port.reset(); |
| 286 | 306 |
| 287 info_->pipe_fd = -1; | 307 info_->read_pipe_fd = -1; |
| 288 info_->read_pipe.reset(); | 308 info_->pipe_c2p_read.reset(); |
| 309 info_->write_pipe_fd = -1; |
| 310 info_->pipe_p2c_write.reset(); |
| 289 } | 311 } |
| 290 | 312 |
| 291 void MachMultiprocess::RunChild() { | 313 void MachMultiprocess::RunChild() { |
| 292 ScopedNotReached must_not_leave_this_scope; | 314 ScopedNotReached must_not_leave_this_scope; |
| 293 | 315 |
| 294 // local_port is not valid in the forked child process. | 316 // local_port is not valid in the forked child process. |
| 295 ignore_result(info_->local_port.release()); | 317 ignore_result(info_->local_port.release()); |
| 296 | 318 |
| 297 // The child uses the write end of the pipe. | 319 // The child uses the write end of c2p and the read end of p2c. |
| 298 info_->read_pipe.reset(); | 320 info_->pipe_c2p_read.reset(); |
| 299 info_->pipe_fd = info_->write_pipe.get(); | 321 info_->write_pipe_fd = info_->pipe_c2p_write.get(); |
| 322 info_->pipe_p2c_write.reset(); |
| 323 info_->read_pipe_fd = info_->pipe_p2c_read.get(); |
| 300 | 324 |
| 301 mach_port_t local_port; | 325 mach_port_t local_port; |
| 302 kern_return_t kr = mach_port_allocate( | 326 kern_return_t kr = mach_port_allocate( |
| 303 mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &local_port); | 327 mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &local_port); |
| 304 ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "mach_port_allocate"); | 328 ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "mach_port_allocate"); |
| 305 info_->local_port.reset(local_port); | 329 info_->local_port.reset(local_port); |
| 306 | 330 |
| 307 // The remote port can be obtained from the bootstrap server. | 331 // The remote port can be obtained from the bootstrap server. |
| 308 mach_port_t remote_port; | 332 mach_port_t remote_port; |
| 309 kr = bootstrap_look_up( | 333 kr = bootstrap_look_up( |
| (...skipping 24 matching lines...) Expand all Loading... |
| 334 MACH_PORT_NULL, | 358 MACH_PORT_NULL, |
| 335 MACH_MSG_TIMEOUT_NONE, | 359 MACH_MSG_TIMEOUT_NONE, |
| 336 MACH_PORT_NULL); | 360 MACH_PORT_NULL); |
| 337 ASSERT_EQ(MACH_MSG_SUCCESS, kr) << MachErrorMessage(kr, "mach_msg"); | 361 ASSERT_EQ(MACH_MSG_SUCCESS, kr) << MachErrorMessage(kr, "mach_msg"); |
| 338 | 362 |
| 339 Child(); | 363 Child(); |
| 340 | 364 |
| 341 info_->remote_port.reset(); | 365 info_->remote_port.reset(); |
| 342 info_->local_port.reset(); | 366 info_->local_port.reset(); |
| 343 | 367 |
| 344 info_->pipe_fd = -1; | 368 info_->write_pipe_fd = -1; |
| 345 info_->write_pipe.reset(); | 369 info_->pipe_c2p_write.reset(); |
| 370 info_->read_pipe_fd = -1; |
| 371 info_->pipe_p2c_read.reset(); |
| 346 | 372 |
| 347 if (Test::HasFailure()) { | 373 if (Test::HasFailure()) { |
| 348 // Trigger the ScopedNotReached destructor. | 374 // Trigger the ScopedNotReached destructor. |
| 349 return; | 375 return; |
| 350 } | 376 } |
| 351 | 377 |
| 352 exit(0); | 378 exit(0); |
| 353 } | 379 } |
| 354 | 380 |
| 355 } // namespace test | 381 } // namespace test |
| 356 } // namespace crashpad | 382 } // namespace crashpad |
| OLD | NEW |