Index: util/mach/mach_message_server_test.cc |
diff --git a/util/mach/mach_message_server_test.cc b/util/mach/mach_message_server_test.cc |
index c0991e7cf757950b0623345075ccf0208383b74a..cb97e5ba8dbb2e45c97362372708c227a4b3626b 100644 |
--- a/util/mach/mach_message_server_test.cc |
+++ b/util/mach/mach_message_server_test.cc |
@@ -65,13 +65,14 @@ class TestMachMessageServer : public MachMessageServer::Interface, |
expect_server_destroyed_complex(true), |
expect_server_result(KERN_SUCCESS), |
expect_server_transaction_count(1), |
+ child_wait_for_parent_pipe_early(false), |
client_send_request_count(1), |
client_send_complex(false), |
client_send_large(false), |
client_reply_port_type(kReplyPortNormal), |
client_expect_reply(true), |
child_send_all_requests_before_receiving_any_replies(false), |
- child_wait_for_parent_pipe(false) { |
+ child_wait_for_parent_pipe_late(false) { |
} |
// true if MachMessageServerFunction() is expected to be called. |
@@ -118,6 +119,14 @@ class TestMachMessageServer : public MachMessageServer::Interface, |
// The number of transactions that the server is expected to handle. |
size_t expect_server_transaction_count; |
+ // true if the child should wait for the parent to signal that it’s ready |
+ // for the child to begin sending requests via the pipe. This is done if the |
+ // parent needs to perform operations on its receive port before the child |
+ // should be permitted to send anything to it. Currently, this is used to |
+ // allow the parent to ensure that the receive port’s queue length is high |
+ // enough before the child begins attempting to fill it. |
+ bool child_wait_for_parent_pipe_early; |
+ |
// The number of requests that the client should send to the server. |
size_t client_send_request_count; |
@@ -155,7 +164,7 @@ class TestMachMessageServer : public MachMessageServer::Interface, |
// Otherwise, the right might appear in the parent as a dead name if the |
// child exited before the parent had a chance to examine it. This would be |
// a race. |
- bool child_wait_for_parent_pipe; |
+ bool child_wait_for_parent_pipe_late; |
}; |
explicit TestMachMessageServer(const Options& options) |
@@ -297,6 +306,30 @@ class TestMachMessageServer : public MachMessageServer::Interface, |
// MachMultiprocess: |
virtual void MachMultiprocessParent() override { |
+ mach_port_t local_port = LocalPort(); |
+ |
+ kern_return_t kr; |
+ if (options_.child_send_all_requests_before_receiving_any_replies) { |
+ // On Mac OS X 10.10, the queue limit of a new Mach port seems to be 2 |
+ // by default, which is below the value of MACH_PORT_QLIMIT_DEFAULT. Set |
+ // the port’s queue limit explicitly here. |
+ mach_port_limits limits = {}; |
+ limits.mpl_qlimit = MACH_PORT_QLIMIT_DEFAULT; |
+ kr = mach_port_set_attributes(mach_task_self(), |
+ local_port, |
+ MACH_PORT_LIMITS_INFO, |
+ reinterpret_cast<mach_port_info_t>(&limits), |
+ MACH_PORT_LIMITS_INFO_COUNT); |
+ ASSERT_EQ(KERN_SUCCESS, kr) |
+ << MachErrorMessage(kr, "mach_port_set_attributes"); |
+ } |
+ |
+ if (options_.child_wait_for_parent_pipe_early) { |
+ // Tell the child to begin sending messages. |
+ char c = '\0'; |
+ CheckedWriteFD(WritePipeFD(), &c, 1); |
+ } |
+ |
if (options_.parent_wait_for_child_pipe) { |
// Wait until the child is done sending what it’s going to send. |
char c; |
@@ -304,10 +337,9 @@ class TestMachMessageServer : public MachMessageServer::Interface, |
EXPECT_EQ('\0', c); |
} |
- kern_return_t kr; |
ASSERT_EQ(options_.expect_server_result, |
(kr = MachMessageServer::Run(this, |
- LocalPort(), |
+ local_port, |
options_.server_options, |
options_.server_persistent, |
options_.server_nonblocking, |
@@ -343,7 +375,7 @@ class TestMachMessageServer : public MachMessageServer::Interface, |
<< MachErrorMessage(kr, "mach_port_type"); |
} |
- if (options_.child_wait_for_parent_pipe) { |
+ if (options_.child_wait_for_parent_pipe_late) { |
// Let the child know it’s safe to exit. |
char c = '\0'; |
CheckedWriteFD(WritePipeFD(), &c, 1); |
@@ -351,6 +383,13 @@ class TestMachMessageServer : public MachMessageServer::Interface, |
} |
virtual void MachMultiprocessChild() override { |
+ if (options_.child_wait_for_parent_pipe_early) { |
+ // Wait until the parent is done setting things up on its end. |
+ char c; |
+ CheckedReadFD(ReadPipeFD(), &c, 1); |
+ EXPECT_EQ('\0', c); |
+ } |
+ |
for (size_t index = 0; |
index < options_.client_send_request_count; |
++index) { |
@@ -388,7 +427,7 @@ class TestMachMessageServer : public MachMessageServer::Interface, |
} |
} |
- if (options_.child_wait_for_parent_pipe) { |
+ if (options_.child_wait_for_parent_pipe_late) { |
char c; |
CheckedReadFD(ReadPipeFD(), &c, 1); |
ASSERT_EQ('\0', c); |
@@ -649,6 +688,13 @@ TEST(MachMessageServer, PersistentNonblockingFourMessages) { |
// MACH_PORT_QLIMIT_BASIC, or 5). The number of messages sent for this test |
// must be below this, because the server does not begin dequeueing request |
// messages until the client has finished sending them. |
+ // |
+ // The queue limit on new ports has been seen to be below |
+ // MACH_PORT_QLIMIT_DEFAULT, so it will explicitly be set by |
+ // mach_port_set_attributes() for this test. This needs to happen before the |
+ // child is allowed to begin sending messages, so |
+ // child_wait_for_parent_pipe_early is used to make the child wait until the |
+ // parent is ready. |
const size_t kTransactionCount = 4; |
COMPILE_ASSERT(kTransactionCount <= MACH_PORT_QLIMIT_DEFAULT, |
must_not_exceed_queue_limit); |
@@ -659,6 +705,7 @@ TEST(MachMessageServer, PersistentNonblockingFourMessages) { |
options.server_nonblocking = MachMessageServer::kNonblocking; |
options.expect_server_result = MACH_RCV_TIMED_OUT; |
options.expect_server_transaction_count = kTransactionCount; |
+ options.child_wait_for_parent_pipe_early = true; |
options.client_send_request_count = kTransactionCount; |
options.child_send_all_requests_before_receiving_any_replies = true; |
TestMachMessageServer test_mach_message_server(options); |
@@ -680,7 +727,7 @@ TEST(MachMessageServer, ReturnCodeNoReply) { |
TestMachMessageServer::Options options; |
options.server_mig_retcode = MIG_NO_REPLY; |
options.client_expect_reply = false; |
- options.child_wait_for_parent_pipe = true; |
+ options.child_wait_for_parent_pipe_late = true; |
TestMachMessageServer test_mach_message_server(options); |
test_mach_message_server.Test(); |
} |
@@ -766,7 +813,7 @@ TEST(MachMessageServer, ComplexNotDestroyedNoReply) { |
options.expect_server_destroyed_complex = false; |
options.client_send_complex = true; |
options.client_expect_reply = false; |
- options.child_wait_for_parent_pipe = true; |
+ options.child_wait_for_parent_pipe_late = true; |
TestMachMessageServer test_mach_message_server(options); |
test_mach_message_server.Test(); |
} |