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..3607f6a228189da65255695764fba0bd61de9014 100644 |
--- a/ipc/ipc_sync_channel_unittest.cc |
+++ b/ipc/ipc_sync_channel_unittest.cc |
@@ -1257,7 +1257,7 @@ class RestrictedDispatchClient : public Worker { |
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)); |
@@ -1388,7 +1388,7 @@ class RestrictedDispatchDeadlockServer : public Worker { |
} |
void Run() { |
- channel()->SetRestrictDispatchToSameChannel(true); |
+ channel()->SetRestrictDispatchChannelGroup(true); |
Josh Horwich
2012/03/29 18:29:22
Shouldn't this be 1 rather than true now?
|
server_ready_event_->Signal(); |
} |
@@ -1596,6 +1596,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 mus be treated specially. |
Josh Horwich
2012/03/29 18:29:22
Nit: typo (mus -> must)
|
+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 { |