| Index: ipc/ipc_sync_channel_unittest.cc
|
| diff --git a/ipc/ipc_sync_channel_unittest.cc b/ipc/ipc_sync_channel_unittest.cc
|
| index 6cb745773295b14efbb54b5a72afa53b6019d08d..81f5d11917c08d20ef415ab7014ba58329be8f29 100644
|
| --- a/ipc/ipc_sync_channel_unittest.cc
|
| +++ b/ipc/ipc_sync_channel_unittest.cc
|
| @@ -1192,9 +1192,11 @@ namespace {
|
|
|
| class RestrictedDispatchServer : public Worker {
|
| public:
|
| - RestrictedDispatchServer(WaitableEvent* sent_ping_event)
|
| + RestrictedDispatchServer(WaitableEvent* sent_ping_event,
|
| + WaitableEvent* wait_event)
|
| : Worker("restricted_channel", Channel::MODE_SERVER),
|
| - sent_ping_event_(sent_ping_event) { }
|
| + sent_ping_event_(sent_ping_event),
|
| + wait_event_(wait_event) { }
|
|
|
| void OnDoPing(int ping) {
|
| // Send an asynchronous message that unblocks the caller.
|
| @@ -1207,12 +1209,18 @@ class RestrictedDispatchServer : public Worker {
|
| FROM_HERE, base::Bind(&RestrictedDispatchServer::OnPingSent, this));
|
| }
|
|
|
| + void OnPingTTL(int ping, int* out) {
|
| + *out = ping;
|
| + wait_event_->Wait();
|
| + }
|
| +
|
| base::Thread* ListenerThread() { return Worker::ListenerThread(); }
|
|
|
| private:
|
| bool OnMessageReceived(const Message& message) {
|
| IPC_BEGIN_MESSAGE_MAP(RestrictedDispatchServer, message)
|
| IPC_MESSAGE_HANDLER(SyncChannelTestMsg_NoArgs, OnNoArgs)
|
| + IPC_MESSAGE_HANDLER(SyncChannelTestMsg_PingTTL, OnPingTTL)
|
| IPC_MESSAGE_HANDLER(SyncChannelTestMsg_Done, Done)
|
| IPC_END_MESSAGE_MAP()
|
| return true;
|
| @@ -1224,12 +1232,22 @@ class RestrictedDispatchServer : public Worker {
|
|
|
| void OnNoArgs() { }
|
| WaitableEvent* sent_ping_event_;
|
| + WaitableEvent* wait_event_;
|
| };
|
|
|
| class NonRestrictedDispatchServer : public Worker {
|
| public:
|
| - NonRestrictedDispatchServer()
|
| - : Worker("non_restricted_channel", Channel::MODE_SERVER) {}
|
| + NonRestrictedDispatchServer(WaitableEvent* signal_event)
|
| + : Worker("non_restricted_channel", Channel::MODE_SERVER),
|
| + signal_event_(signal_event) {}
|
| +
|
| + base::Thread* ListenerThread() { return Worker::ListenerThread(); }
|
| +
|
| + void OnDoPingTTL(int ping) {
|
| + int value = 0;
|
| + Send(new SyncChannelTestMsg_PingTTL(ping, &value));
|
| + signal_event_->Signal();
|
| + }
|
|
|
| private:
|
| bool OnMessageReceived(const Message& message) {
|
| @@ -1241,23 +1259,26 @@ class NonRestrictedDispatchServer : public Worker {
|
| }
|
|
|
| void OnNoArgs() { }
|
| + WaitableEvent* signal_event_;
|
| };
|
|
|
| class RestrictedDispatchClient : public Worker {
|
| public:
|
| RestrictedDispatchClient(WaitableEvent* sent_ping_event,
|
| RestrictedDispatchServer* server,
|
| + NonRestrictedDispatchServer* server2,
|
| int* success)
|
| : Worker("restricted_channel", Channel::MODE_CLIENT),
|
| ping_(0),
|
| server_(server),
|
| + server2_(server2),
|
| success_(success),
|
| sent_ping_event_(sent_ping_event) {}
|
|
|
| void Run() {
|
| // Incoming messages from our channel should only be dispatched when we
|
| // send a message on that same channel.
|
| - channel()->SetRestrictDispatchToSameChannel(true);
|
| + channel()->SetRestrictDispatchChannelGroup(1);
|
|
|
| server_->ListenerThread()->message_loop()->PostTask(
|
| FROM_HERE, base::Bind(&RestrictedDispatchServer::OnDoPing, server_, 1));
|
| @@ -1268,7 +1289,7 @@ class RestrictedDispatchClient : public Worker {
|
| else
|
| LOG(ERROR) << "Send failed to dispatch incoming message on same channel";
|
|
|
| - scoped_ptr<SyncChannel> non_restricted_channel(new SyncChannel(
|
| + non_restricted_channel_.reset(new SyncChannel(
|
| "non_restricted_channel", Channel::MODE_CLIENT, this,
|
| ipc_thread().message_loop_proxy(), true, shutdown_event()));
|
|
|
| @@ -1283,7 +1304,7 @@ class RestrictedDispatchClient : public Worker {
|
| // without hooking into the internals of SyncChannel. I haven't seen it in
|
| // practice (i.e. not setting SetRestrictDispatchToSameChannel does cause
|
| // the following to fail).
|
| - non_restricted_channel->Send(new SyncChannelTestMsg_NoArgs);
|
| + non_restricted_channel_->Send(new SyncChannelTestMsg_NoArgs);
|
| if (ping_ == 1)
|
| ++*success_;
|
| else
|
| @@ -1295,8 +1316,20 @@ class RestrictedDispatchClient : public Worker {
|
| else
|
| LOG(ERROR) << "Send failed to dispatch incoming message on same channel";
|
|
|
| - non_restricted_channel->Send(new SyncChannelTestMsg_Done);
|
| - non_restricted_channel.reset();
|
| + // Check that the incoming message on the non-restricted channel is
|
| + // dispatched when sending on the restricted channel.
|
| + server2_->ListenerThread()->message_loop()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&NonRestrictedDispatchServer::OnDoPingTTL, server2_, 3));
|
| + int value = 0;
|
| + Send(new SyncChannelTestMsg_PingTTL(4, &value));
|
| + if (ping_ == 3 && value == 4)
|
| + ++*success_;
|
| + else
|
| + LOG(ERROR) << "Send failed to dispatch message from unrestricted channel";
|
| +
|
| + non_restricted_channel_->Send(new SyncChannelTestMsg_Done);
|
| + non_restricted_channel_.reset();
|
| Send(new SyncChannelTestMsg_Done);
|
| Done();
|
| }
|
| @@ -1305,6 +1338,7 @@ class RestrictedDispatchClient : public Worker {
|
| bool OnMessageReceived(const Message& message) {
|
| IPC_BEGIN_MESSAGE_MAP(RestrictedDispatchClient, message)
|
| IPC_MESSAGE_HANDLER(SyncChannelTestMsg_Ping, OnPing)
|
| + IPC_MESSAGE_HANDLER_DELAY_REPLY(SyncChannelTestMsg_PingTTL, OnPingTTL)
|
| IPC_END_MESSAGE_MAP()
|
| return true;
|
| }
|
| @@ -1313,27 +1347,40 @@ class RestrictedDispatchClient : public Worker {
|
| ping_ = ping;
|
| }
|
|
|
| + void OnPingTTL(int ping, IPC::Message* reply) {
|
| + ping_ = ping;
|
| + // This message comes from the NonRestrictedDispatchServer, we have to send
|
| + // the reply back manually.
|
| + SyncChannelTestMsg_PingTTL::WriteReplyParams(reply, ping);
|
| + non_restricted_channel_->Send(reply);
|
| + }
|
| +
|
| int ping_;
|
| RestrictedDispatchServer* server_;
|
| + NonRestrictedDispatchServer* server2_;
|
| int* success_;
|
| WaitableEvent* sent_ping_event_;
|
| + scoped_ptr<SyncChannel> non_restricted_channel_;
|
| };
|
|
|
| } // namespace
|
|
|
| TEST_F(IPCSyncChannelTest, RestrictedDispatch) {
|
| WaitableEvent sent_ping_event(false, false);
|
| -
|
| + WaitableEvent wait_event(false, false);
|
| RestrictedDispatchServer* server =
|
| - new RestrictedDispatchServer(&sent_ping_event);
|
| + new RestrictedDispatchServer(&sent_ping_event, &wait_event);
|
| + NonRestrictedDispatchServer* server2 =
|
| + new NonRestrictedDispatchServer(&wait_event);
|
| +
|
| int success = 0;
|
| std::vector<Worker*> workers;
|
| - workers.push_back(new NonRestrictedDispatchServer);
|
| workers.push_back(server);
|
| - workers.push_back(
|
| - new RestrictedDispatchClient(&sent_ping_event, server, &success));
|
| + workers.push_back(server2);
|
| + workers.push_back(new RestrictedDispatchClient(
|
| + &sent_ping_event, server, server2, &success));
|
| RunTest(workers);
|
| - EXPECT_EQ(3, success);
|
| + EXPECT_EQ(4, success);
|
| }
|
|
|
| //-----------------------------------------------------------------------------
|
| @@ -1388,7 +1435,7 @@ class RestrictedDispatchDeadlockServer : public Worker {
|
| }
|
|
|
| void Run() {
|
| - channel()->SetRestrictDispatchToSameChannel(true);
|
| + channel()->SetRestrictDispatchChannelGroup(1);
|
| server_ready_event_->Signal();
|
| }
|
|
|
| @@ -1596,6 +1643,114 @@ TEST_F(IPCSyncChannelTest, RestrictedDispatchDeadlock) {
|
|
|
| //-----------------------------------------------------------------------------
|
|
|
| +// This test case inspired by crbug.com/120530
|
| +// We create 4 workers that pipe to each other W1->W2->W3->W4->W1 then we send a
|
| +// message that recurses through 3, 4 or 5 steps to make sure, say, W1 can
|
| +// re-enter when called from W4 while it's sending a message to W2.
|
| +// The first worker drives the whole test so it must be treated specially.
|
| +namespace {
|
| +
|
| +class RestrictedDispatchPipeWorker : public Worker {
|
| + public:
|
| + RestrictedDispatchPipeWorker(
|
| + const std::string &channel1,
|
| + WaitableEvent* event1,
|
| + const std::string &channel2,
|
| + WaitableEvent* event2,
|
| + int group,
|
| + int* success)
|
| + : Worker(channel1, Channel::MODE_SERVER),
|
| + event1_(event1),
|
| + event2_(event2),
|
| + other_channel_name_(channel2),
|
| + group_(group),
|
| + success_(success) {
|
| + }
|
| +
|
| + void OnPingTTL(int ping, int* ret) {
|
| + *ret = 0;
|
| + if (!ping)
|
| + return;
|
| + other_channel_->Send(new SyncChannelTestMsg_PingTTL(ping - 1, ret));
|
| + ++*ret;
|
| + }
|
| +
|
| + void OnDone() {
|
| + if (is_first())
|
| + return;
|
| + other_channel_->Send(new SyncChannelTestMsg_Done);
|
| + other_channel_.reset();
|
| + Done();
|
| + }
|
| +
|
| + void Run() {
|
| + channel()->SetRestrictDispatchChannelGroup(group_);
|
| + if (is_first())
|
| + event1_->Signal();
|
| + event2_->Wait();
|
| + other_channel_.reset(new SyncChannel(
|
| + other_channel_name_, Channel::MODE_CLIENT, this,
|
| + ipc_thread().message_loop_proxy(), true, shutdown_event()));
|
| + other_channel_->SetRestrictDispatchChannelGroup(group_);
|
| + if (!is_first()) {
|
| + event1_->Signal();
|
| + return;
|
| + }
|
| + *success_ = 0;
|
| + int value = 0;
|
| + OnPingTTL(3, &value);
|
| + *success_ += (value == 3);
|
| + OnPingTTL(4, &value);
|
| + *success_ += (value == 4);
|
| + OnPingTTL(5, &value);
|
| + *success_ += (value == 5);
|
| + other_channel_->Send(new SyncChannelTestMsg_Done);
|
| + other_channel_.reset();
|
| + Done();
|
| + }
|
| +
|
| + bool is_first() { return !!success_; }
|
| +
|
| + private:
|
| + bool OnMessageReceived(const Message& message) {
|
| + IPC_BEGIN_MESSAGE_MAP(RestrictedDispatchPipeWorker, message)
|
| + IPC_MESSAGE_HANDLER(SyncChannelTestMsg_PingTTL, OnPingTTL)
|
| + IPC_MESSAGE_HANDLER(SyncChannelTestMsg_Done, OnDone)
|
| + IPC_END_MESSAGE_MAP()
|
| + return true;
|
| + }
|
| +
|
| + scoped_ptr<SyncChannel> other_channel_;
|
| + WaitableEvent* event1_;
|
| + WaitableEvent* event2_;
|
| + std::string other_channel_name_;
|
| + int group_;
|
| + int* success_;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +TEST_F(IPCSyncChannelTest, RestrictedDispatch4WayDeadlock) {
|
| + int success = 0;
|
| + std::vector<Worker*> workers;
|
| + WaitableEvent event0(true, false);
|
| + WaitableEvent event1(true, false);
|
| + WaitableEvent event2(true, false);
|
| + WaitableEvent event3(true, false);
|
| + workers.push_back(new RestrictedDispatchPipeWorker(
|
| + "channel0", &event0, "channel1", &event1, 1, &success));
|
| + workers.push_back(new RestrictedDispatchPipeWorker(
|
| + "channel1", &event1, "channel2", &event2, 2, NULL));
|
| + workers.push_back(new RestrictedDispatchPipeWorker(
|
| + "channel2", &event2, "channel3", &event3, 3, NULL));
|
| + workers.push_back(new RestrictedDispatchPipeWorker(
|
| + "channel3", &event3, "channel0", &event0, 4, NULL));
|
| + RunTest(workers);
|
| + EXPECT_EQ(3, success);
|
| +}
|
| +
|
| +//-----------------------------------------------------------------------------
|
| +
|
| // Generate a validated channel ID using Channel::GenerateVerifiedChannelID().
|
| namespace {
|
|
|
|
|