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 |