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 |