MachMessageServer test: deal with short receive queue lengths on 10.10.

The queue length of a new receive port appears to be 2 on Mac OS X 10.10
DP8 14A361c. The value of MACH_PORT_QLIMIT_DEFAULT in the 10.10 SDK is
still 5, so a read of the kernel source should be interesting, if we
ever get to see it.

In the meantime, mach_port_set_attributes() can be used to set a
traditional queue length.

TEST=util_test MachMessageServer.PersistentNonblockingFourMessages
R=rsesek@chromium.org

Review URL: https://codereview.chromium.org/584293003
This commit is contained in:
Mark Mentovai 2014-09-22 13:15:14 -04:00
parent 75988925f9
commit 8eec7874fd

View File

@ -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 its 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 ports 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 ports 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 its 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 its 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();
}