Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "mojo/edk/system/channel_manager.h" | 5 #include "mojo/edk/system/channel_manager.h" |
| 6 | 6 |
| 7 #include "base/callback.h" | 7 #include "base/callback.h" |
| 8 #include "base/macros.h" | 8 #include "base/macros.h" |
| 9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
| 10 #include "base/message_loop/message_loop_proxy.h" | 10 #include "base/message_loop/message_loop_proxy.h" |
| 11 #include "base/run_loop.h" | 11 #include "base/run_loop.h" |
| 12 #include "base/task_runner.h" | 12 #include "base/task_runner.h" |
| 13 #include "base/test/test_timeouts.h" | 13 #include "base/test/test_timeouts.h" |
| 14 #include "base/threading/platform_thread.h" | 14 #include "base/threading/platform_thread.h" |
| 15 #include "base/threading/simple_thread.h" | 15 #include "base/threading/simple_thread.h" |
| 16 #include "base/time/time.h" | 16 #include "base/time/time.h" |
| 17 #include "mojo/edk/embedder/platform_channel_pair.h" | 17 #include "mojo/edk/embedder/platform_channel_pair.h" |
| 18 #include "mojo/edk/embedder/simple_platform_support.h" | 18 #include "mojo/edk/embedder/simple_platform_support.h" |
| 19 #include "mojo/edk/system/channel.h" | 19 #include "mojo/edk/system/channel.h" |
| 20 #include "mojo/edk/system/channel_endpoint.h" | |
| 21 #include "mojo/edk/system/message_pipe_dispatcher.h" | |
| 20 #include "testing/gtest/include/gtest/gtest.h" | 22 #include "testing/gtest/include/gtest/gtest.h" |
| 21 | 23 |
| 22 namespace mojo { | 24 namespace mojo { |
| 23 namespace system { | 25 namespace system { |
| 24 namespace { | 26 namespace { |
| 25 | 27 |
| 26 class ChannelManagerTest : public testing::Test { | 28 class ChannelManagerTest : public testing::Test { |
| 27 public: | 29 public: |
| 28 ChannelManagerTest() : message_loop_(base::MessageLoop::TYPE_IO) {} | 30 ChannelManagerTest() : message_loop_(base::MessageLoop::TYPE_IO) {} |
| 29 ~ChannelManagerTest() override {} | 31 ~ChannelManagerTest() override {} |
| 30 | 32 |
| 31 protected: | 33 protected: |
| 32 embedder::SimplePlatformSupport* platform_support() { | 34 embedder::SimplePlatformSupport* platform_support() { |
| 33 return &platform_support_; | 35 return &platform_support_; |
| 34 } | 36 } |
| 35 base::MessageLoop* message_loop() { return &message_loop_; } | 37 base::MessageLoop* message_loop() { return &message_loop_; } |
| 36 | 38 |
| 37 private: | 39 private: |
| 38 embedder::SimplePlatformSupport platform_support_; | 40 embedder::SimplePlatformSupport platform_support_; |
| 39 base::MessageLoop message_loop_; | 41 base::MessageLoop message_loop_; |
| 40 | 42 |
| 41 DISALLOW_COPY_AND_ASSIGN(ChannelManagerTest); | 43 DISALLOW_COPY_AND_ASSIGN(ChannelManagerTest); |
| 42 }; | 44 }; |
| 43 | 45 |
| 44 TEST_F(ChannelManagerTest, Basic) { | 46 TEST_F(ChannelManagerTest, Basic) { |
| 45 ChannelManager cm(platform_support()); | 47 ChannelManager cm(platform_support()); |
| 46 | 48 |
| 47 // Hang on to a ref to the |Channel|, so that we can check that the | 49 embedder::PlatformChannelPair channel_pair; |
| 48 // |ChannelManager| takes/releases refs to it. | |
| 49 scoped_refptr<Channel> ch(new Channel(platform_support())); | |
| 50 ASSERT_TRUE(ch->HasOneRef()); | |
| 51 | 50 |
| 52 embedder::PlatformChannelPair channel_pair; | 51 scoped_refptr<ChannelEndpoint> cep; |
|
yzshen1
2015/02/04 17:26:39
nit: naming variables like this is probably disfav
| |
| 53 ch->Init(RawChannel::Create(channel_pair.PassServerHandle())); | 52 scoped_refptr<MessagePipeDispatcher> d = |
| 53 MessagePipeDispatcher::CreateRemoteMessagePipe(&cep); | |
| 54 const ChannelId id = 1; | |
| 55 cm.CreateChannelOnIOThread(id, channel_pair.PassServerHandle(), cep); | |
| 56 cep = nullptr; | |
| 54 | 57 |
| 55 const ChannelId id = 1; | 58 scoped_refptr<Channel> ch = cm.GetChannel(id); |
| 56 cm.AddChannel(id, ch, base::MessageLoopProxy::current()); | 59 EXPECT_TRUE(ch); |
| 57 // |ChannelManager| should take a ref. | 60 // |ChannelManager| should have a ref. |
| 58 EXPECT_FALSE(ch->HasOneRef()); | 61 EXPECT_FALSE(ch->HasOneRef()); |
| 59 | 62 |
| 60 cm.WillShutdownChannel(id); | 63 cm.WillShutdownChannel(id); |
| 61 // |ChannelManager| should still have a ref. | 64 // |ChannelManager| should still have a ref. |
| 62 EXPECT_FALSE(ch->HasOneRef()); | 65 EXPECT_FALSE(ch->HasOneRef()); |
| 63 | 66 |
| 64 cm.ShutdownChannel(id); | 67 cm.ShutdownChannel(id); |
| 65 // On the "I/O" thread, so shutdown should happen synchronously. | 68 // On the "I/O" thread, so shutdown should happen synchronously. |
| 66 // |ChannelManager| should have given up its ref. | 69 // |ChannelManager| should have given up its ref. |
| 67 EXPECT_TRUE(ch->HasOneRef()); | 70 EXPECT_TRUE(ch->HasOneRef()); |
| 71 | |
| 72 EXPECT_EQ(MOJO_RESULT_OK, d->Close()); | |
| 68 } | 73 } |
| 69 | 74 |
| 70 TEST_F(ChannelManagerTest, TwoChannels) { | 75 TEST_F(ChannelManagerTest, TwoChannels) { |
| 71 ChannelManager cm(platform_support()); | 76 ChannelManager cm(platform_support()); |
| 72 | 77 |
| 73 // Hang on to a ref to each |Channel|, so that we can check that the | 78 embedder::PlatformChannelPair channel_pair; |
| 74 // |ChannelManager| takes/releases refs to them. | |
| 75 scoped_refptr<Channel> ch1(new Channel(platform_support())); | |
| 76 ASSERT_TRUE(ch1->HasOneRef()); | |
| 77 scoped_refptr<Channel> ch2(new Channel(platform_support())); | |
| 78 ASSERT_TRUE(ch2->HasOneRef()); | |
| 79 | 79 |
| 80 embedder::PlatformChannelPair channel_pair; | 80 scoped_refptr<ChannelEndpoint> cep1; |
| 81 ch1->Init(RawChannel::Create(channel_pair.PassServerHandle())); | 81 scoped_refptr<MessagePipeDispatcher> d1 = |
| 82 ch2->Init(RawChannel::Create(channel_pair.PassClientHandle())); | 82 MessagePipeDispatcher::CreateRemoteMessagePipe(&cep1); |
| 83 const ChannelId id1 = 1; | |
| 84 cm.CreateChannelOnIOThread(id1, channel_pair.PassServerHandle(), cep1); | |
| 85 cep1 = nullptr; | |
| 83 | 86 |
| 84 const ChannelId id1 = 1; | 87 scoped_refptr<ChannelEndpoint> cep2; |
| 85 cm.AddChannel(id1, ch1, base::MessageLoopProxy::current()); | 88 scoped_refptr<MessagePipeDispatcher> d2 = |
| 86 EXPECT_FALSE(ch1->HasOneRef()); | 89 MessagePipeDispatcher::CreateRemoteMessagePipe(&cep2); |
| 90 const ChannelId id2 = 2; | |
| 91 cm.CreateChannelOnIOThread(id2, channel_pair.PassClientHandle(), cep2); | |
| 92 cep2 = nullptr; | |
| 87 | 93 |
| 88 const ChannelId id2 = 2; | 94 scoped_refptr<Channel> ch1 = cm.GetChannel(id1); |
| 89 cm.AddChannel(id2, ch2, base::MessageLoopProxy::current()); | 95 EXPECT_TRUE(ch1); |
| 90 EXPECT_FALSE(ch2->HasOneRef()); | 96 |
| 97 scoped_refptr<Channel> ch2 = cm.GetChannel(id2); | |
| 98 EXPECT_TRUE(ch2); | |
| 91 | 99 |
| 92 // Calling |WillShutdownChannel()| multiple times (on |id1|) is okay. | 100 // Calling |WillShutdownChannel()| multiple times (on |id1|) is okay. |
| 93 cm.WillShutdownChannel(id1); | 101 cm.WillShutdownChannel(id1); |
| 94 cm.WillShutdownChannel(id1); | 102 cm.WillShutdownChannel(id1); |
| 95 EXPECT_FALSE(ch1->HasOneRef()); | 103 EXPECT_FALSE(ch1->HasOneRef()); |
| 96 // Not calling |WillShutdownChannel()| (on |id2|) is okay too. | 104 // Not calling |WillShutdownChannel()| (on |id2|) is okay too. |
| 97 | 105 |
| 98 cm.ShutdownChannel(id1); | 106 cm.ShutdownChannel(id1); |
| 99 EXPECT_TRUE(ch1->HasOneRef()); | 107 EXPECT_TRUE(ch1->HasOneRef()); |
| 100 cm.ShutdownChannel(id2); | 108 cm.ShutdownChannel(id2); |
| 101 EXPECT_TRUE(ch2->HasOneRef()); | 109 EXPECT_TRUE(ch2->HasOneRef()); |
| 110 | |
| 111 EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); | |
| 112 EXPECT_EQ(MOJO_RESULT_OK, d2->Close()); | |
| 102 } | 113 } |
| 103 | 114 |
| 104 class OtherThread : public base::SimpleThread { | 115 class OtherThread : public base::SimpleThread { |
| 105 public: | 116 public: |
| 106 // Note: We rely on the main thread keeping *exactly one* reference to | 117 // Note: There should be no other refs to the channel identified by |
| 107 // |channel|. | 118 // |channel_id| outside the channel manager. |
| 108 OtherThread(scoped_refptr<base::TaskRunner> task_runner, | 119 OtherThread(scoped_refptr<base::TaskRunner> task_runner, |
| 109 ChannelManager* channel_manager, | 120 ChannelManager* channel_manager, |
| 110 Channel* channel, | 121 ChannelId channel_id, |
| 111 base::Closure quit_closure) | 122 base::Closure quit_closure) |
| 112 : base::SimpleThread("other_thread"), | 123 : base::SimpleThread("other_thread"), |
| 113 task_runner_(task_runner), | 124 task_runner_(task_runner), |
| 114 channel_manager_(channel_manager), | 125 channel_manager_(channel_manager), |
| 115 channel_(channel), | 126 channel_id_(channel_id), |
| 116 quit_closure_(quit_closure) {} | 127 quit_closure_(quit_closure) {} |
| 117 ~OtherThread() override {} | 128 ~OtherThread() override {} |
| 118 | 129 |
| 119 private: | 130 private: |
| 120 void Run() override { | 131 void Run() override { |
| 121 // See comment above constructor. | 132 // TODO(vtl): Once we have a way of creating a channel from off the I/O |
| 122 ASSERT_TRUE(channel_->HasOneRef()); | 133 // thread, do that here instead. |
| 123 | 134 |
| 124 // You can use any unique, nonzero value as the ID. | 135 // You can use any unique, nonzero value as the ID. |
| 125 const ChannelId id = | 136 scoped_refptr<Channel> ch = channel_manager_->GetChannel(channel_id_); |
| 126 static_cast<ChannelId>(reinterpret_cast<uintptr_t>(channel_)); | 137 // |ChannelManager| should have a ref. |
| 127 channel_manager_->AddChannel(id, make_scoped_refptr(channel_), | 138 EXPECT_FALSE(ch->HasOneRef()); |
| 128 task_runner_); | |
| 129 // |ChannelManager| should take a ref. | |
| 130 EXPECT_FALSE(channel_->HasOneRef()); | |
| 131 | 139 |
| 132 channel_manager_->WillShutdownChannel(id); | 140 channel_manager_->WillShutdownChannel(channel_id_); |
| 133 // |ChannelManager| should still have a ref. | 141 // |ChannelManager| should still have a ref. |
| 134 EXPECT_FALSE(channel_->HasOneRef()); | 142 EXPECT_FALSE(ch->HasOneRef()); |
| 135 | 143 |
| 136 channel_manager_->ShutdownChannel(id); | 144 channel_manager_->ShutdownChannel(channel_id_); |
| 137 // This doesn't happen synchronously, so we "wait" until it does. | 145 // This doesn't happen synchronously, so we "wait" until it does. |
| 138 // TODO(vtl): Possibly |Channel| should provide some notification of being | 146 // TODO(vtl): Probably |Channel| should provide some notification of being |
| 139 // shut down. | 147 // shut down. |
| 140 base::TimeTicks start_time(base::TimeTicks::Now()); | 148 base::TimeTicks start_time(base::TimeTicks::Now()); |
| 141 for (;;) { | 149 for (;;) { |
| 142 if (channel_->HasOneRef()) | 150 if (ch->HasOneRef()) |
| 143 break; | 151 break; |
| 144 | 152 |
| 145 // Check, instead of assert, since if things go wrong, dying is more | 153 // Check, instead of assert, since if things go wrong, dying is more |
| 146 // reliable than tearing down. | 154 // reliable than tearing down. |
| 147 CHECK_LT(base::TimeTicks::Now() - start_time, | 155 CHECK_LT(base::TimeTicks::Now() - start_time, |
| 148 TestTimeouts::action_timeout()); | 156 TestTimeouts::action_timeout()); |
| 149 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); | 157 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); |
| 150 } | 158 } |
| 151 | 159 |
| 152 CHECK(task_runner_->PostTask(FROM_HERE, quit_closure_)); | 160 CHECK(task_runner_->PostTask(FROM_HERE, quit_closure_)); |
| 153 } | 161 } |
| 154 | 162 |
| 155 scoped_refptr<base::TaskRunner> task_runner_; | 163 scoped_refptr<base::TaskRunner> task_runner_; |
| 156 ChannelManager* channel_manager_; | 164 ChannelManager* channel_manager_; |
| 157 Channel* channel_; | 165 ChannelId channel_id_; |
| 158 base::Closure quit_closure_; | 166 base::Closure quit_closure_; |
| 159 | 167 |
| 160 DISALLOW_COPY_AND_ASSIGN(OtherThread); | 168 DISALLOW_COPY_AND_ASSIGN(OtherThread); |
| 161 }; | 169 }; |
| 162 | 170 |
| 163 TEST_F(ChannelManagerTest, CallsFromOtherThread) { | 171 TEST_F(ChannelManagerTest, CallsFromOtherThread) { |
| 164 ChannelManager cm(platform_support()); | 172 ChannelManager cm(platform_support()); |
| 165 | 173 |
| 166 // Hang on to a ref to the |Channel|, so that we can check that the | 174 embedder::PlatformChannelPair channel_pair; |
| 167 // |ChannelManager| takes/releases refs to it. | |
| 168 scoped_refptr<Channel> ch(new Channel(platform_support())); | |
| 169 ASSERT_TRUE(ch->HasOneRef()); | |
| 170 | 175 |
| 171 embedder::PlatformChannelPair channel_pair; | 176 scoped_refptr<ChannelEndpoint> cep; |
| 172 ch->Init(RawChannel::Create(channel_pair.PassServerHandle())); | 177 scoped_refptr<MessagePipeDispatcher> d = |
| 178 MessagePipeDispatcher::CreateRemoteMessagePipe(&cep); | |
| 179 const ChannelId id = 1; | |
| 180 cm.CreateChannelOnIOThread(id, channel_pair.PassServerHandle(), cep); | |
| 181 cep = nullptr; | |
| 173 | 182 |
| 174 base::RunLoop run_loop; | 183 base::RunLoop run_loop; |
| 175 OtherThread thread(base::MessageLoopProxy::current(), &cm, ch.get(), | 184 OtherThread thread(base::MessageLoopProxy::current(), &cm, id, |
| 176 run_loop.QuitClosure()); | 185 run_loop.QuitClosure()); |
| 177 thread.Start(); | 186 thread.Start(); |
| 178 run_loop.Run(); | 187 run_loop.Run(); |
| 179 thread.Join(); | 188 thread.Join(); |
| 189 | |
| 190 EXPECT_EQ(MOJO_RESULT_OK, d->Close()); | |
| 180 } | 191 } |
| 181 | 192 |
| 182 } // namespace | 193 } // namespace |
| 183 } // namespace system | 194 } // namespace system |
| 184 } // namespace mojo | 195 } // namespace mojo |
| OLD | NEW |