blob: a4e9bd8b374b2d266137a59ab3593f280f0a596c [file] [log] [blame]
jhorwich@chromium.org3c3a8132012-01-12 07:39:54 +09001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4//
5// Unit test for SyncChannel.
6
dmaclach@chromium.orgc1d3d422010-12-20 15:59:23 +09007#include "ipc/ipc_sync_channel.h"
8
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09009#include <string>
10#include <vector>
11
12#include "base/basictypes.h"
jhawkins@chromium.org9827bd12011-11-13 06:16:41 +090013#include "base/bind.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090014#include "base/logging.h"
levin@chromium.org5c528682011-03-28 10:54:15 +090015#include "base/memory/scoped_ptr.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090016#include "base/message_loop.h"
jschuh@chromium.orga5cd0762012-04-05 11:38:34 +090017#include "base/process_util.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090018#include "base/string_util.h"
brettw@google.com7c5cc672011-01-01 11:17:08 +090019#include "base/threading/platform_thread.h"
brettw@chromium.org5b5f5e02011-01-01 10:01:06 +090020#include "base/threading/thread.h"
brettw@chromium.org5238c7d2011-01-02 15:05:39 +090021#include "base/synchronization/waitable_event.h"
brettw@chromium.orgf947ed02012-06-12 07:35:26 +090022#include "ipc/ipc_listener.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090023#include "ipc/ipc_message.h"
brettw@chromium.orgf947ed02012-06-12 07:35:26 +090024#include "ipc/ipc_sender.h"
jabdelmalek@google.comeb921652010-04-07 05:33:36 +090025#include "ipc/ipc_sync_message_filter.h"
jam@chromium.org86a8de12010-12-09 08:34:16 +090026#include "ipc/ipc_sync_message_unittest.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090027#include "testing/gtest/include/gtest/gtest.h"
28
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090029using base::WaitableEvent;
30
kushi.p@gmail.com5948bf42011-05-14 07:42:41 +090031namespace IPC {
32
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090033namespace {
34
35// Base class for a "process" with listener and IPC threads.
brettw@chromium.orgf947ed02012-06-12 07:35:26 +090036class Worker : public Listener, public Sender {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090037 public:
38 // Will create a channel without a name.
39 Worker(Channel::Mode mode, const std::string& thread_name)
40 : done_(new WaitableEvent(false, false)),
41 channel_created_(new WaitableEvent(false, false)),
42 mode_(mode),
43 ipc_thread_((thread_name + "_ipc").c_str()),
44 listener_thread_((thread_name + "_listener").c_str()),
45 overrided_thread_(NULL),
viettrungluu@chromium.org42575b02013-01-08 15:09:07 +090046 shutdown_event_(true, false),
47 is_shutdown_(false) {
timurrrr@chromium.org03100a82009-10-27 20:28:58 +090048 }
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090049
50 // Will create a named channel and use this name for the threads' name.
51 Worker(const std::string& channel_name, Channel::Mode mode)
52 : done_(new WaitableEvent(false, false)),
53 channel_created_(new WaitableEvent(false, false)),
54 channel_name_(channel_name),
55 mode_(mode),
56 ipc_thread_((channel_name + "_ipc").c_str()),
57 listener_thread_((channel_name + "_listener").c_str()),
58 overrided_thread_(NULL),
viettrungluu@chromium.org42575b02013-01-08 15:09:07 +090059 shutdown_event_(true, false),
60 is_shutdown_(false) {
timurrrr@chromium.org03100a82009-10-27 20:28:58 +090061 }
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090062
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090063 virtual ~Worker() {
viettrungluu@chromium.org42575b02013-01-08 15:09:07 +090064 // Shutdown() must be called before destruction.
65 CHECK(is_shutdown_);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090066 }
67 void AddRef() { }
68 void Release() { }
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090069 bool Send(Message* msg) { return channel_->Send(msg); }
70 bool SendWithTimeout(Message* msg, int timeout_ms) {
71 return channel_->SendWithTimeout(msg, timeout_ms);
72 }
73 void WaitForChannelCreation() { channel_created_->Wait(); }
74 void CloseChannel() {
75 DCHECK(MessageLoop::current() == ListenerThread()->message_loop());
76 channel_->Close();
77 }
78 void Start() {
79 StartThread(&listener_thread_, MessageLoop::TYPE_DEFAULT);
jhawkins@chromium.org9827bd12011-11-13 06:16:41 +090080 ListenerThread()->message_loop()->PostTask(
81 FROM_HERE, base::Bind(&Worker::OnStart, this));
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090082 }
viettrungluu@chromium.org42575b02013-01-08 15:09:07 +090083 void Shutdown() {
84 // The IPC thread needs to outlive SyncChannel. We can't do this in
85 // ~Worker(), since that'll reset the vtable pointer (to Worker's), which
86 // may result in a race conditions. See http://crbug.com/25841.
87 WaitableEvent listener_done(false, false), ipc_done(false, false);
88 ListenerThread()->message_loop()->PostTask(
89 FROM_HERE, base::Bind(&Worker::OnListenerThreadShutdown1, this,
90 &listener_done, &ipc_done));
91 listener_done.Wait();
92 ipc_done.Wait();
93 ipc_thread_.Stop();
94 listener_thread_.Stop();
95 is_shutdown_ = true;
96 }
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090097 void OverrideThread(base::Thread* overrided_thread) {
98 DCHECK(overrided_thread_ == NULL);
99 overrided_thread_ = overrided_thread;
100 }
101 bool SendAnswerToLife(bool pump, int timeout, bool succeed) {
102 int answer = 0;
103 SyncMessage* msg = new SyncChannelTestMsg_AnswerToLife(&answer);
104 if (pump)
105 msg->EnableMessagePumping();
106 bool result = SendWithTimeout(msg, timeout);
jam@chromium.orgebd07182009-12-01 11:34:18 +0900107 DCHECK_EQ(result, succeed);
108 DCHECK_EQ(answer, (succeed ? 42 : 0));
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900109 return result;
110 }
111 bool SendDouble(bool pump, bool succeed) {
112 int answer = 0;
113 SyncMessage* msg = new SyncChannelTestMsg_Double(5, &answer);
114 if (pump)
115 msg->EnableMessagePumping();
116 bool result = Send(msg);
jam@chromium.orgebd07182009-12-01 11:34:18 +0900117 DCHECK_EQ(result, succeed);
118 DCHECK_EQ(answer, (succeed ? 10 : 0));
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900119 return result;
120 }
kkania@chromium.org9ccb4692011-11-16 10:06:46 +0900121 const std::string& channel_name() { return channel_name_; }
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900122 Channel::Mode mode() { return mode_; }
123 WaitableEvent* done_event() { return done_.get(); }
jabdelmalek@google.comeb921652010-04-07 05:33:36 +0900124 WaitableEvent* shutdown_event() { return &shutdown_event_; }
jam@chromium.orgebd07182009-12-01 11:34:18 +0900125 void ResetChannel() { channel_.reset(); }
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900126 // Derived classes need to call this when they've completed their part of
127 // the test.
128 void Done() { done_->Signal(); }
jabdelmalek@google.comeb921652010-04-07 05:33:36 +0900129
130 protected:
kushi.p@gmail.com5948bf42011-05-14 07:42:41 +0900131 SyncChannel* channel() { return channel_.get(); }
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900132 // Functions for dervied classes to implement if they wish.
133 virtual void Run() { }
134 virtual void OnAnswer(int* answer) { NOTREACHED(); }
135 virtual void OnAnswerDelay(Message* reply_msg) {
136 // The message handler map below can only take one entry for
137 // SyncChannelTestMsg_AnswerToLife, so since some classes want
138 // the normal version while other want the delayed reply, we
139 // call the normal version if the derived class didn't override
140 // this function.
141 int answer;
142 OnAnswer(&answer);
143 SyncChannelTestMsg_AnswerToLife::WriteReplyParams(reply_msg, answer);
144 Send(reply_msg);
145 }
146 virtual void OnDouble(int in, int* out) { NOTREACHED(); }
147 virtual void OnDoubleDelay(int in, Message* reply_msg) {
148 int result;
149 OnDouble(in, &result);
150 SyncChannelTestMsg_Double::WriteReplyParams(reply_msg, result);
151 Send(reply_msg);
152 }
153
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900154 virtual void OnNestedTestMsg(Message* reply_msg) {
155 NOTREACHED();
156 }
157
kkania@chromium.org9ccb4692011-11-16 10:06:46 +0900158 virtual SyncChannel* CreateChannel() {
159 return new SyncChannel(
160 channel_name_, mode_, this, ipc_thread_.message_loop_proxy(), true,
161 &shutdown_event_);
162 }
163
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900164 base::Thread* ListenerThread() {
165 return overrided_thread_ ? overrided_thread_ : &listener_thread_;
166 }
ananta@chromium.org999f2972010-09-03 06:45:50 +0900167
piman@google.com0cbefaa2011-04-08 12:38:21 +0900168 const base::Thread& ipc_thread() const { return ipc_thread_; }
169
ananta@chromium.org999f2972010-09-03 06:45:50 +0900170 private:
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900171 // Called on the listener thread to create the sync channel.
172 void OnStart() {
173 // Link ipc_thread_, listener_thread_ and channel_ altogether.
174 StartThread(&ipc_thread_, MessageLoop::TYPE_IO);
kkania@chromium.org9ccb4692011-11-16 10:06:46 +0900175 channel_.reset(CreateChannel());
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900176 channel_created_->Signal();
177 Run();
178 }
179
180 void OnListenerThreadShutdown1(WaitableEvent* listener_event,
181 WaitableEvent* ipc_event) {
182 // SyncChannel needs to be destructed on the thread that it was created on.
183 channel_.reset();
184
tfarina@chromium.org969f3202012-11-17 08:41:19 +0900185 MessageLoop::current()->RunUntilIdle();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900186
jhawkins@chromium.org9827bd12011-11-13 06:16:41 +0900187 ipc_thread_.message_loop()->PostTask(
188 FROM_HERE, base::Bind(&Worker::OnIPCThreadShutdown, this,
189 listener_event, ipc_event));
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900190 }
191
192 void OnIPCThreadShutdown(WaitableEvent* listener_event,
193 WaitableEvent* ipc_event) {
tfarina@chromium.org969f3202012-11-17 08:41:19 +0900194 MessageLoop::current()->RunUntilIdle();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900195 ipc_event->Signal();
196
jhawkins@chromium.org9827bd12011-11-13 06:16:41 +0900197 listener_thread_.message_loop()->PostTask(
198 FROM_HERE, base::Bind(&Worker::OnListenerThreadShutdown2, this,
199 listener_event));
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900200 }
201
202 void OnListenerThreadShutdown2(WaitableEvent* listener_event) {
tfarina@chromium.org969f3202012-11-17 08:41:19 +0900203 MessageLoop::current()->RunUntilIdle();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900204 listener_event->Signal();
205 }
206
jam@chromium.org8a2c7842010-12-24 15:19:28 +0900207 bool OnMessageReceived(const Message& message) {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900208 IPC_BEGIN_MESSAGE_MAP(Worker, message)
209 IPC_MESSAGE_HANDLER_DELAY_REPLY(SyncChannelTestMsg_Double, OnDoubleDelay)
210 IPC_MESSAGE_HANDLER_DELAY_REPLY(SyncChannelTestMsg_AnswerToLife,
211 OnAnswerDelay)
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900212 IPC_MESSAGE_HANDLER_DELAY_REPLY(SyncChannelNestedTestMsg_String,
213 OnNestedTestMsg)
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900214 IPC_END_MESSAGE_MAP()
jam@chromium.org8a2c7842010-12-24 15:19:28 +0900215 return true;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900216 }
217
218 void StartThread(base::Thread* thread, MessageLoop::Type type) {
219 base::Thread::Options options;
220 options.message_loop_type = type;
221 thread->StartWithOptions(options);
222 }
223
224 scoped_ptr<WaitableEvent> done_;
225 scoped_ptr<WaitableEvent> channel_created_;
226 std::string channel_name_;
227 Channel::Mode mode_;
228 scoped_ptr<SyncChannel> channel_;
229 base::Thread ipc_thread_;
230 base::Thread listener_thread_;
231 base::Thread* overrided_thread_;
232
233 base::WaitableEvent shutdown_event_;
234
viettrungluu@chromium.org42575b02013-01-08 15:09:07 +0900235 bool is_shutdown_;
236
tfarina@chromium.orgb73eaee2010-06-07 11:10:18 +0900237 DISALLOW_COPY_AND_ASSIGN(Worker);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900238};
239
240
241// Starts the test with the given workers. This function deletes the workers
242// when it's done.
243void RunTest(std::vector<Worker*> workers) {
244 // First we create the workers that are channel servers, or else the other
245 // workers' channel initialization might fail because the pipe isn't created..
246 for (size_t i = 0; i < workers.size(); ++i) {
dmaclach@chromium.orgf146c292011-02-04 05:35:09 +0900247 if (workers[i]->mode() & Channel::MODE_SERVER_FLAG) {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900248 workers[i]->Start();
249 workers[i]->WaitForChannelCreation();
250 }
251 }
252
253 // now create the clients
254 for (size_t i = 0; i < workers.size(); ++i) {
dmaclach@chromium.orgf146c292011-02-04 05:35:09 +0900255 if (workers[i]->mode() & Channel::MODE_CLIENT_FLAG)
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900256 workers[i]->Start();
257 }
258
259 // wait for all the workers to finish
260 for (size_t i = 0; i < workers.size(); ++i)
261 workers[i]->done_event()->Wait();
262
viettrungluu@chromium.org42575b02013-01-08 15:09:07 +0900263 for (size_t i = 0; i < workers.size(); ++i) {
264 workers[i]->Shutdown();
265 delete workers[i];
266 }
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900267}
268
269} // namespace
270
271class IPCSyncChannelTest : public testing::Test {
272 private:
273 MessageLoop message_loop_;
274};
275
276//-----------------------------------------------------------------------------
277
278namespace {
279
280class SimpleServer : public Worker {
281 public:
thestig@chromium.org60bd7c02010-07-23 14:23:13 +0900282 explicit SimpleServer(bool pump_during_send)
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900283 : Worker(Channel::MODE_SERVER, "simpler_server"),
284 pump_during_send_(pump_during_send) { }
285 void Run() {
286 SendAnswerToLife(pump_during_send_, base::kNoTimeout, true);
287 Done();
288 }
289
290 bool pump_during_send_;
291};
292
293class SimpleClient : public Worker {
294 public:
295 SimpleClient() : Worker(Channel::MODE_CLIENT, "simple_client") { }
296
297 void OnAnswer(int* answer) {
298 *answer = 42;
299 Done();
300 }
301};
302
303void Simple(bool pump_during_send) {
304 std::vector<Worker*> workers;
305 workers.push_back(new SimpleServer(pump_during_send));
306 workers.push_back(new SimpleClient());
307 RunTest(workers);
308}
309
310} // namespace
311
312// Tests basic synchronous call
313TEST_F(IPCSyncChannelTest, Simple) {
314 Simple(false);
315 Simple(true);
316}
317
318//-----------------------------------------------------------------------------
319
320namespace {
321
kkania@chromium.org9ccb4692011-11-16 10:06:46 +0900322// Worker classes which override how the sync channel is created to use the
323// two-step initialization (calling the lightweight constructor and then
324// ChannelProxy::Init separately) process.
325class TwoStepServer : public Worker {
326 public:
327 explicit TwoStepServer(bool create_pipe_now)
328 : Worker(Channel::MODE_SERVER, "simpler_server"),
329 create_pipe_now_(create_pipe_now) { }
330
331 void Run() {
332 SendAnswerToLife(false, base::kNoTimeout, true);
333 Done();
334 }
335
336 virtual SyncChannel* CreateChannel() {
337 SyncChannel* channel = new SyncChannel(
338 this, ipc_thread().message_loop_proxy(), shutdown_event());
339 channel->Init(channel_name(), mode(), create_pipe_now_);
340 return channel;
341 }
342
343 bool create_pipe_now_;
344};
345
346class TwoStepClient : public Worker {
347 public:
348 TwoStepClient(bool create_pipe_now)
349 : Worker(Channel::MODE_CLIENT, "simple_client"),
350 create_pipe_now_(create_pipe_now) { }
351
352 void OnAnswer(int* answer) {
353 *answer = 42;
354 Done();
355 }
356
357 virtual SyncChannel* CreateChannel() {
358 SyncChannel* channel = new SyncChannel(
359 this, ipc_thread().message_loop_proxy(), shutdown_event());
360 channel->Init(channel_name(), mode(), create_pipe_now_);
361 return channel;
362 }
363
364 bool create_pipe_now_;
365};
366
367void TwoStep(bool create_server_pipe_now, bool create_client_pipe_now) {
368 std::vector<Worker*> workers;
369 workers.push_back(new TwoStepServer(create_server_pipe_now));
370 workers.push_back(new TwoStepClient(create_client_pipe_now));
371 RunTest(workers);
372}
373
374} // namespace
375
376// Tests basic two-step initialization, where you call the lightweight
377// constructor then Init.
378TEST_F(IPCSyncChannelTest, TwoStepInitialization) {
379 TwoStep(false, false);
380 TwoStep(false, true);
381 TwoStep(true, false);
382 TwoStep(true, true);
383}
384
385
386//-----------------------------------------------------------------------------
387
388namespace {
389
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900390class DelayClient : public Worker {
391 public:
392 DelayClient() : Worker(Channel::MODE_CLIENT, "delay_client") { }
393
394 void OnAnswerDelay(Message* reply_msg) {
395 SyncChannelTestMsg_AnswerToLife::WriteReplyParams(reply_msg, 42);
396 Send(reply_msg);
397 Done();
398 }
399};
400
401void DelayReply(bool pump_during_send) {
402 std::vector<Worker*> workers;
403 workers.push_back(new SimpleServer(pump_during_send));
404 workers.push_back(new DelayClient());
405 RunTest(workers);
406}
407
408} // namespace
409
410// Tests that asynchronous replies work
411TEST_F(IPCSyncChannelTest, DelayReply) {
412 DelayReply(false);
413 DelayReply(true);
414}
415
416//-----------------------------------------------------------------------------
417
418namespace {
419
420class NoHangServer : public Worker {
421 public:
dilmah@chromium.org92b4c8e2011-07-27 02:25:25 +0900422 NoHangServer(WaitableEvent* got_first_reply, bool pump_during_send)
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900423 : Worker(Channel::MODE_SERVER, "no_hang_server"),
424 got_first_reply_(got_first_reply),
425 pump_during_send_(pump_during_send) { }
426 void Run() {
427 SendAnswerToLife(pump_during_send_, base::kNoTimeout, true);
428 got_first_reply_->Signal();
429
430 SendAnswerToLife(pump_during_send_, base::kNoTimeout, false);
431 Done();
432 }
433
434 WaitableEvent* got_first_reply_;
435 bool pump_during_send_;
436};
437
438class NoHangClient : public Worker {
439 public:
440 explicit NoHangClient(WaitableEvent* got_first_reply)
441 : Worker(Channel::MODE_CLIENT, "no_hang_client"),
442 got_first_reply_(got_first_reply) { }
443
444 virtual void OnAnswerDelay(Message* reply_msg) {
445 // Use the DELAY_REPLY macro so that we can force the reply to be sent
446 // before this function returns (when the channel will be reset).
447 SyncChannelTestMsg_AnswerToLife::WriteReplyParams(reply_msg, 42);
448 Send(reply_msg);
449 got_first_reply_->Wait();
450 CloseChannel();
451 Done();
452 }
453
454 WaitableEvent* got_first_reply_;
455};
456
457void NoHang(bool pump_during_send) {
458 WaitableEvent got_first_reply(false, false);
459 std::vector<Worker*> workers;
460 workers.push_back(new NoHangServer(&got_first_reply, pump_during_send));
461 workers.push_back(new NoHangClient(&got_first_reply));
462 RunTest(workers);
463}
464
465} // namespace
466
467// Tests that caller doesn't hang if receiver dies
468TEST_F(IPCSyncChannelTest, NoHang) {
469 NoHang(false);
470 NoHang(true);
471}
472
473//-----------------------------------------------------------------------------
474
475namespace {
476
477class UnblockServer : public Worker {
478 public:
jam@chromium.orgebd07182009-12-01 11:34:18 +0900479 UnblockServer(bool pump_during_send, bool delete_during_send)
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900480 : Worker(Channel::MODE_SERVER, "unblock_server"),
jam@chromium.orgebd07182009-12-01 11:34:18 +0900481 pump_during_send_(pump_during_send),
482 delete_during_send_(delete_during_send) { }
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900483 void Run() {
jam@chromium.orgebd07182009-12-01 11:34:18 +0900484 if (delete_during_send_) {
485 // Use custom code since race conditions mean the answer may or may not be
486 // available.
487 int answer = 0;
488 SyncMessage* msg = new SyncChannelTestMsg_AnswerToLife(&answer);
489 if (pump_during_send_)
490 msg->EnableMessagePumping();
491 Send(msg);
492 } else {
493 SendAnswerToLife(pump_during_send_, base::kNoTimeout, true);
494 }
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900495 Done();
496 }
497
jam@chromium.orgebd07182009-12-01 11:34:18 +0900498 void OnDoubleDelay(int in, Message* reply_msg) {
499 SyncChannelTestMsg_Double::WriteReplyParams(reply_msg, in * 2);
500 Send(reply_msg);
501 if (delete_during_send_)
502 ResetChannel();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900503 }
504
505 bool pump_during_send_;
jam@chromium.orgebd07182009-12-01 11:34:18 +0900506 bool delete_during_send_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900507};
508
509class UnblockClient : public Worker {
510 public:
thestig@chromium.org60bd7c02010-07-23 14:23:13 +0900511 explicit UnblockClient(bool pump_during_send)
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900512 : Worker(Channel::MODE_CLIENT, "unblock_client"),
513 pump_during_send_(pump_during_send) { }
514
515 void OnAnswer(int* answer) {
516 SendDouble(pump_during_send_, true);
517 *answer = 42;
518 Done();
519 }
520
521 bool pump_during_send_;
522};
523
jam@chromium.orgebd07182009-12-01 11:34:18 +0900524void Unblock(bool server_pump, bool client_pump, bool delete_during_send) {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900525 std::vector<Worker*> workers;
jam@chromium.orgebd07182009-12-01 11:34:18 +0900526 workers.push_back(new UnblockServer(server_pump, delete_during_send));
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900527 workers.push_back(new UnblockClient(client_pump));
528 RunTest(workers);
529}
530
531} // namespace
532
533// Tests that the caller unblocks to answer a sync message from the receiver.
534TEST_F(IPCSyncChannelTest, Unblock) {
jam@chromium.orgebd07182009-12-01 11:34:18 +0900535 Unblock(false, false, false);
536 Unblock(false, true, false);
537 Unblock(true, false, false);
538 Unblock(true, true, false);
539}
540
541//-----------------------------------------------------------------------------
542
kushi.p@gmail.com5948bf42011-05-14 07:42:41 +0900543// Tests that the the SyncChannel object can be deleted during a Send.
jam@chromium.orgebd07182009-12-01 11:34:18 +0900544TEST_F(IPCSyncChannelTest, ChannelDeleteDuringSend) {
545 Unblock(false, false, true);
546 Unblock(false, true, true);
547 Unblock(true, false, true);
548 Unblock(true, true, true);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900549}
550
551//-----------------------------------------------------------------------------
552
553namespace {
554
555class RecursiveServer : public Worker {
556 public:
dilmah@chromium.org92b4c8e2011-07-27 02:25:25 +0900557 RecursiveServer(bool expected_send_result, bool pump_first, bool pump_second)
558 : Worker(Channel::MODE_SERVER, "recursive_server"),
559 expected_send_result_(expected_send_result),
560 pump_first_(pump_first), pump_second_(pump_second) {}
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900561 void Run() {
562 SendDouble(pump_first_, expected_send_result_);
563 Done();
564 }
565
566 void OnDouble(int in, int* out) {
567 *out = in * 2;
568 SendAnswerToLife(pump_second_, base::kNoTimeout, expected_send_result_);
569 }
570
571 bool expected_send_result_, pump_first_, pump_second_;
572};
573
574class RecursiveClient : public Worker {
575 public:
dilmah@chromium.org92b4c8e2011-07-27 02:25:25 +0900576 RecursiveClient(bool pump_during_send, bool close_channel)
577 : Worker(Channel::MODE_CLIENT, "recursive_client"),
578 pump_during_send_(pump_during_send), close_channel_(close_channel) {}
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900579
580 void OnDoubleDelay(int in, Message* reply_msg) {
581 SendDouble(pump_during_send_, !close_channel_);
582 if (close_channel_) {
583 delete reply_msg;
584 } else {
585 SyncChannelTestMsg_Double::WriteReplyParams(reply_msg, in * 2);
586 Send(reply_msg);
587 }
588 Done();
589 }
590
591 void OnAnswerDelay(Message* reply_msg) {
592 if (close_channel_) {
593 delete reply_msg;
594 CloseChannel();
595 } else {
596 SyncChannelTestMsg_AnswerToLife::WriteReplyParams(reply_msg, 42);
597 Send(reply_msg);
598 }
599 }
600
601 bool pump_during_send_, close_channel_;
602};
603
604void Recursive(
605 bool server_pump_first, bool server_pump_second, bool client_pump) {
606 std::vector<Worker*> workers;
607 workers.push_back(
608 new RecursiveServer(true, server_pump_first, server_pump_second));
609 workers.push_back(new RecursiveClient(client_pump, false));
610 RunTest(workers);
611}
612
613} // namespace
614
615// Tests a server calling Send while another Send is pending.
616TEST_F(IPCSyncChannelTest, Recursive) {
617 Recursive(false, false, false);
618 Recursive(false, false, true);
619 Recursive(false, true, false);
620 Recursive(false, true, true);
621 Recursive(true, false, false);
622 Recursive(true, false, true);
623 Recursive(true, true, false);
624 Recursive(true, true, true);
625}
626
627//-----------------------------------------------------------------------------
628
629namespace {
630
631void RecursiveNoHang(
632 bool server_pump_first, bool server_pump_second, bool client_pump) {
633 std::vector<Worker*> workers;
634 workers.push_back(
635 new RecursiveServer(false, server_pump_first, server_pump_second));
636 workers.push_back(new RecursiveClient(client_pump, true));
637 RunTest(workers);
638}
639
640} // namespace
641
642// Tests that if a caller makes a sync call during an existing sync call and
643// the receiver dies, neither of the Send() calls hang.
644TEST_F(IPCSyncChannelTest, RecursiveNoHang) {
645 RecursiveNoHang(false, false, false);
646 RecursiveNoHang(false, false, true);
647 RecursiveNoHang(false, true, false);
648 RecursiveNoHang(false, true, true);
649 RecursiveNoHang(true, false, false);
650 RecursiveNoHang(true, false, true);
651 RecursiveNoHang(true, true, false);
652 RecursiveNoHang(true, true, true);
653}
654
655//-----------------------------------------------------------------------------
656
657namespace {
658
659class MultipleServer1 : public Worker {
660 public:
thestig@chromium.org60bd7c02010-07-23 14:23:13 +0900661 explicit MultipleServer1(bool pump_during_send)
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900662 : Worker("test_channel1", Channel::MODE_SERVER),
663 pump_during_send_(pump_during_send) { }
664
665 void Run() {
666 SendDouble(pump_during_send_, true);
667 Done();
668 }
669
670 bool pump_during_send_;
671};
672
673class MultipleClient1 : public Worker {
674 public:
675 MultipleClient1(WaitableEvent* client1_msg_received,
676 WaitableEvent* client1_can_reply) :
677 Worker("test_channel1", Channel::MODE_CLIENT),
678 client1_msg_received_(client1_msg_received),
679 client1_can_reply_(client1_can_reply) { }
680
681 void OnDouble(int in, int* out) {
682 client1_msg_received_->Signal();
683 *out = in * 2;
684 client1_can_reply_->Wait();
685 Done();
686 }
687
688 private:
689 WaitableEvent *client1_msg_received_, *client1_can_reply_;
690};
691
692class MultipleServer2 : public Worker {
693 public:
694 MultipleServer2() : Worker("test_channel2", Channel::MODE_SERVER) { }
695
696 void OnAnswer(int* result) {
697 *result = 42;
698 Done();
699 }
700};
701
702class MultipleClient2 : public Worker {
703 public:
704 MultipleClient2(
705 WaitableEvent* client1_msg_received, WaitableEvent* client1_can_reply,
706 bool pump_during_send)
707 : Worker("test_channel2", Channel::MODE_CLIENT),
708 client1_msg_received_(client1_msg_received),
709 client1_can_reply_(client1_can_reply),
710 pump_during_send_(pump_during_send) { }
711
712 void Run() {
713 client1_msg_received_->Wait();
714 SendAnswerToLife(pump_during_send_, base::kNoTimeout, true);
715 client1_can_reply_->Signal();
716 Done();
717 }
718
719 private:
720 WaitableEvent *client1_msg_received_, *client1_can_reply_;
721 bool pump_during_send_;
722};
723
724void Multiple(bool server_pump, bool client_pump) {
725 std::vector<Worker*> workers;
726
727 // A shared worker thread so that server1 and server2 run on one thread.
728 base::Thread worker_thread("Multiple");
729 ASSERT_TRUE(worker_thread.Start());
730
731 // Server1 sends a sync msg to client1, which blocks the reply until
732 // server2 (which runs on the same worker thread as server1) responds
733 // to a sync msg from client2.
734 WaitableEvent client1_msg_received(false, false);
735 WaitableEvent client1_can_reply(false, false);
736
737 Worker* worker;
738
739 worker = new MultipleServer2();
740 worker->OverrideThread(&worker_thread);
741 workers.push_back(worker);
742
743 worker = new MultipleClient2(
744 &client1_msg_received, &client1_can_reply, client_pump);
745 workers.push_back(worker);
746
747 worker = new MultipleServer1(server_pump);
748 worker->OverrideThread(&worker_thread);
749 workers.push_back(worker);
750
751 worker = new MultipleClient1(
752 &client1_msg_received, &client1_can_reply);
753 workers.push_back(worker);
754
755 RunTest(workers);
756}
757
758} // namespace
759
760// Tests that multiple SyncObjects on the same listener thread can unblock each
761// other.
762TEST_F(IPCSyncChannelTest, Multiple) {
763 Multiple(false, false);
764 Multiple(false, true);
765 Multiple(true, false);
766 Multiple(true, true);
767}
768
769//-----------------------------------------------------------------------------
770
771namespace {
772
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900773// This class provides server side functionality to test the case where
774// multiple sync channels are in use on the same thread on the client and
775// nested calls are issued.
776class QueuedReplyServer : public Worker {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900777 public:
thestig@chromium.org60bd7c02010-07-23 14:23:13 +0900778 QueuedReplyServer(base::Thread* listener_thread,
779 const std::string& channel_name,
780 const std::string& reply_text)
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900781 : Worker(channel_name, Channel::MODE_SERVER),
782 reply_text_(reply_text) {
783 Worker::OverrideThread(listener_thread);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900784 }
785
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900786 virtual void OnNestedTestMsg(Message* reply_msg) {
pkasting@chromium.orgfcdd54b2010-10-20 08:50:00 +0900787 VLOG(1) << __FUNCTION__ << " Sending reply: " << reply_text_;
788 SyncChannelNestedTestMsg_String::WriteReplyParams(reply_msg, reply_text_);
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900789 Send(reply_msg);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900790 Done();
791 }
792
793 private:
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900794 std::string reply_text_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900795};
796
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900797// The QueuedReplyClient class provides functionality to test the case where
798// multiple sync channels are in use on the same thread and they make nested
799// sync calls, i.e. while the first channel waits for a response it makes a
800// sync call on another channel.
801// The callstack should unwind correctly, i.e. the outermost call should
802// complete first, and so on.
803class QueuedReplyClient : public Worker {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900804 public:
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900805 QueuedReplyClient(base::Thread* listener_thread,
806 const std::string& channel_name,
807 const std::string& expected_text,
808 bool pump_during_send)
809 : Worker(channel_name, Channel::MODE_CLIENT),
thomasvl@google.com9a242072010-07-23 23:18:59 +0900810 pump_during_send_(pump_during_send),
811 expected_text_(expected_text) {
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900812 Worker::OverrideThread(listener_thread);
813 }
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900814
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900815 virtual void Run() {
816 std::string response;
817 SyncMessage* msg = new SyncChannelNestedTestMsg_String(&response);
818 if (pump_during_send_)
819 msg->EnableMessagePumping();
820 bool result = Send(msg);
821 DCHECK(result);
jam@chromium.orgebd07182009-12-01 11:34:18 +0900822 DCHECK_EQ(response, expected_text_);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900823
pkasting@chromium.orgfcdd54b2010-10-20 08:50:00 +0900824 VLOG(1) << __FUNCTION__ << " Received reply: " << response;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900825 Done();
826 }
827
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900828 private:
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900829 bool pump_during_send_;
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900830 std::string expected_text_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900831};
832
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900833void QueuedReply(bool client_pump) {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900834 std::vector<Worker*> workers;
835
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900836 // A shared worker thread for servers
837 base::Thread server_worker_thread("QueuedReply_ServerListener");
838 ASSERT_TRUE(server_worker_thread.Start());
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900839
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900840 base::Thread client_worker_thread("QueuedReply_ClientListener");
841 ASSERT_TRUE(client_worker_thread.Start());
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900842
843 Worker* worker;
844
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900845 worker = new QueuedReplyServer(&server_worker_thread,
846 "QueuedReply_Server1",
847 "Got first message");
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900848 workers.push_back(worker);
849
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900850 worker = new QueuedReplyServer(&server_worker_thread,
851 "QueuedReply_Server2",
852 "Got second message");
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900853 workers.push_back(worker);
854
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900855 worker = new QueuedReplyClient(&client_worker_thread,
856 "QueuedReply_Server1",
857 "Got first message",
858 client_pump);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900859 workers.push_back(worker);
860
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900861 worker = new QueuedReplyClient(&client_worker_thread,
862 "QueuedReply_Server2",
863 "Got second message",
864 client_pump);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900865 workers.push_back(worker);
866
867 RunTest(workers);
868}
869
870} // namespace
871
872// While a blocking send is in progress, the listener thread might answer other
873// synchronous messages. This tests that if during the response to another
874// message the reply to the original messages comes, it is queued up correctly
875// and the original Send is unblocked later.
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900876// We also test that the send call stacks unwind correctly when the channel
877// pumps messages while waiting for a response.
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900878TEST_F(IPCSyncChannelTest, QueuedReply) {
ananta@chromium.org31b338f2009-10-15 01:22:02 +0900879 QueuedReply(false);
880 QueuedReply(true);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900881}
882
883//-----------------------------------------------------------------------------
884
885namespace {
886
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900887class ChattyClient : public Worker {
888 public:
889 ChattyClient() :
890 Worker(Channel::MODE_CLIENT, "chatty_client") { }
891
892 void OnAnswer(int* answer) {
893 // The PostMessage limit is 10k. Send 20% more than that.
894 const int kMessageLimit = 10000;
895 const int kMessagesToSend = kMessageLimit * 120 / 100;
896 for (int i = 0; i < kMessagesToSend; ++i) {
897 if (!SendDouble(false, true))
898 break;
899 }
900 *answer = 42;
901 Done();
902 }
903};
904
905void ChattyServer(bool pump_during_send) {
906 std::vector<Worker*> workers;
jam@chromium.orgebd07182009-12-01 11:34:18 +0900907 workers.push_back(new UnblockServer(pump_during_send, false));
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900908 workers.push_back(new ChattyClient());
909 RunTest(workers);
910}
911
912} // namespace
913
914// Tests http://b/1093251 - that sending lots of sync messages while
915// the receiver is waiting for a sync reply does not overflow the PostMessage
916// queue.
917TEST_F(IPCSyncChannelTest, ChattyServer) {
918 ChattyServer(false);
919 ChattyServer(true);
920}
921
922//------------------------------------------------------------------------------
923
924namespace {
925
926class TimeoutServer : public Worker {
927 public:
thestig@chromium.org60bd7c02010-07-23 14:23:13 +0900928 TimeoutServer(int timeout_ms,
929 std::vector<bool> timeout_seq,
930 bool pump_during_send)
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900931 : Worker(Channel::MODE_SERVER, "timeout_server"),
932 timeout_ms_(timeout_ms),
933 timeout_seq_(timeout_seq),
934 pump_during_send_(pump_during_send) {
935 }
936
937 void Run() {
938 for (std::vector<bool>::const_iterator iter = timeout_seq_.begin();
939 iter != timeout_seq_.end(); ++iter) {
940 SendAnswerToLife(pump_during_send_, timeout_ms_, !*iter);
941 }
942 Done();
943 }
944
945 private:
946 int timeout_ms_;
947 std::vector<bool> timeout_seq_;
948 bool pump_during_send_;
949};
950
951class UnresponsiveClient : public Worker {
952 public:
thestig@chromium.org60bd7c02010-07-23 14:23:13 +0900953 explicit UnresponsiveClient(std::vector<bool> timeout_seq)
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900954 : Worker(Channel::MODE_CLIENT, "unresponsive_client"),
955 timeout_seq_(timeout_seq) {
thestig@chromium.org60bd7c02010-07-23 14:23:13 +0900956 }
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900957
958 void OnAnswerDelay(Message* reply_msg) {
959 DCHECK(!timeout_seq_.empty());
960 if (!timeout_seq_[0]) {
961 SyncChannelTestMsg_AnswerToLife::WriteReplyParams(reply_msg, 42);
962 Send(reply_msg);
963 } else {
964 // Don't reply.
965 delete reply_msg;
966 }
967 timeout_seq_.erase(timeout_seq_.begin());
968 if (timeout_seq_.empty())
969 Done();
970 }
971
972 private:
973 // Whether we should time-out or respond to the various messages we receive.
974 std::vector<bool> timeout_seq_;
975};
976
977void SendWithTimeoutOK(bool pump_during_send) {
978 std::vector<Worker*> workers;
979 std::vector<bool> timeout_seq;
980 timeout_seq.push_back(false);
981 timeout_seq.push_back(false);
982 timeout_seq.push_back(false);
983 workers.push_back(new TimeoutServer(5000, timeout_seq, pump_during_send));
984 workers.push_back(new SimpleClient());
985 RunTest(workers);
986}
987
988void SendWithTimeoutTimeout(bool pump_during_send) {
989 std::vector<Worker*> workers;
990 std::vector<bool> timeout_seq;
991 timeout_seq.push_back(true);
992 timeout_seq.push_back(false);
993 timeout_seq.push_back(false);
994 workers.push_back(new TimeoutServer(100, timeout_seq, pump_during_send));
995 workers.push_back(new UnresponsiveClient(timeout_seq));
996 RunTest(workers);
997}
998
999void SendWithTimeoutMixedOKAndTimeout(bool pump_during_send) {
1000 std::vector<Worker*> workers;
1001 std::vector<bool> timeout_seq;
1002 timeout_seq.push_back(true);
1003 timeout_seq.push_back(false);
1004 timeout_seq.push_back(false);
1005 timeout_seq.push_back(true);
1006 timeout_seq.push_back(false);
1007 workers.push_back(new TimeoutServer(100, timeout_seq, pump_during_send));
1008 workers.push_back(new UnresponsiveClient(timeout_seq));
1009 RunTest(workers);
1010}
1011
1012} // namespace
1013
1014// Tests that SendWithTimeout does not time-out if the response comes back fast
1015// enough.
1016TEST_F(IPCSyncChannelTest, SendWithTimeoutOK) {
1017 SendWithTimeoutOK(false);
1018 SendWithTimeoutOK(true);
1019}
1020
1021// Tests that SendWithTimeout does time-out.
1022TEST_F(IPCSyncChannelTest, SendWithTimeoutTimeout) {
1023 SendWithTimeoutTimeout(false);
1024 SendWithTimeoutTimeout(true);
1025}
1026
1027// Sends some message that time-out and some that succeed.
phajdan.jr@chromium.orga8e3c092011-01-19 17:11:56 +09001028// Crashes flakily, http://crbug.com/70075.
1029TEST_F(IPCSyncChannelTest, DISABLED_SendWithTimeoutMixedOKAndTimeout) {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09001030 SendWithTimeoutMixedOKAndTimeout(false);
1031 SendWithTimeoutMixedOKAndTimeout(true);
1032}
1033
1034//------------------------------------------------------------------------------
1035
1036namespace {
1037
jhawkins@chromium.orgdc0f37f2011-11-29 03:35:39 +09001038void NestedCallback(Worker* server) {
1039 // Sleep a bit so that we wake up after the reply has been received.
tedvessenes@gmail.com30dbbaa2012-01-13 09:11:01 +09001040 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(250));
jhawkins@chromium.orgdc0f37f2011-11-29 03:35:39 +09001041 server->SendAnswerToLife(true, base::kNoTimeout, true);
1042}
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09001043
jhawkins@chromium.orgdc0f37f2011-11-29 03:35:39 +09001044bool timeout_occurred = false;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09001045
jhawkins@chromium.orgdc0f37f2011-11-29 03:35:39 +09001046void TimeoutCallback() {
1047 timeout_occurred = true;
1048}
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09001049
1050class DoneEventRaceServer : public Worker {
1051 public:
1052 DoneEventRaceServer()
1053 : Worker(Channel::MODE_SERVER, "done_event_race_server") { }
1054
1055 void Run() {
jhawkins@chromium.orgdc0f37f2011-11-29 03:35:39 +09001056 MessageLoop::current()->PostTask(FROM_HERE,
1057 base::Bind(&NestedCallback, this));
1058 MessageLoop::current()->PostDelayedTask(
tedvessenes@gmail.com56b33702012-03-07 13:41:40 +09001059 FROM_HERE,
1060 base::Bind(&TimeoutCallback),
1061 base::TimeDelta::FromSeconds(9));
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09001062 // Even though we have a timeout on the Send, it will succeed since for this
1063 // bug, the reply message comes back and is deserialized, however the done
1064 // event wasn't set. So we indirectly use the timeout task to notice if a
1065 // timeout occurred.
1066 SendAnswerToLife(true, 10000, true);
jhawkins@chromium.orgdc0f37f2011-11-29 03:35:39 +09001067 DCHECK(!timeout_occurred);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09001068 Done();
1069 }
1070};
1071
1072} // namespace
1073
1074// Tests http://b/1474092 - that if after the done_event is set but before
1075// OnObjectSignaled is called another message is sent out, then after its
1076// reply comes back OnObjectSignaled will be called for the first message.
1077TEST_F(IPCSyncChannelTest, DoneEventRace) {
1078 std::vector<Worker*> workers;
1079 workers.push_back(new DoneEventRaceServer());
1080 workers.push_back(new SimpleClient());
1081 RunTest(workers);
1082}
jabdelmalek@google.comeb921652010-04-07 05:33:36 +09001083
1084//-----------------------------------------------------------------------------
1085
1086namespace {
1087
kushi.p@gmail.com5948bf42011-05-14 07:42:41 +09001088class TestSyncMessageFilter : public SyncMessageFilter {
jabdelmalek@google.comeb921652010-04-07 05:33:36 +09001089 public:
piman@chromium.org0345c812012-09-08 10:24:49 +09001090 TestSyncMessageFilter(base::WaitableEvent* shutdown_event,
1091 Worker* worker,
1092 scoped_refptr<base::MessageLoopProxy> message_loop)
jabdelmalek@google.comeb921652010-04-07 05:33:36 +09001093 : SyncMessageFilter(shutdown_event),
1094 worker_(worker),
piman@chromium.org0345c812012-09-08 10:24:49 +09001095 message_loop_(message_loop) {
jabdelmalek@google.comeb921652010-04-07 05:33:36 +09001096 }
1097
1098 virtual void OnFilterAdded(Channel* channel) {
1099 SyncMessageFilter::OnFilterAdded(channel);
piman@chromium.org0345c812012-09-08 10:24:49 +09001100 message_loop_->PostTask(
jhawkins@chromium.org9827bd12011-11-13 06:16:41 +09001101 FROM_HERE,
1102 base::Bind(&TestSyncMessageFilter::SendMessageOnHelperThread, this));
jabdelmalek@google.comeb921652010-04-07 05:33:36 +09001103 }
1104
1105 void SendMessageOnHelperThread() {
1106 int answer = 0;
1107 bool result = Send(new SyncChannelTestMsg_AnswerToLife(&answer));
1108 DCHECK(result);
1109 DCHECK_EQ(answer, 42);
1110
1111 worker_->Done();
1112 }
1113
rsleevi@chromium.org997c1d42012-04-28 11:12:00 +09001114 private:
1115 virtual ~TestSyncMessageFilter() {}
1116
jabdelmalek@google.comeb921652010-04-07 05:33:36 +09001117 Worker* worker_;
piman@chromium.org0345c812012-09-08 10:24:49 +09001118 scoped_refptr<base::MessageLoopProxy> message_loop_;
jabdelmalek@google.comeb921652010-04-07 05:33:36 +09001119};
1120
1121class SyncMessageFilterServer : public Worker {
1122 public:
1123 SyncMessageFilterServer()
piman@chromium.org0345c812012-09-08 10:24:49 +09001124 : Worker(Channel::MODE_SERVER, "sync_message_filter_server"),
1125 thread_("helper_thread") {
1126 base::Thread::Options options;
1127 options.message_loop_type = MessageLoop::TYPE_DEFAULT;
1128 thread_.StartWithOptions(options);
1129 filter_ = new TestSyncMessageFilter(shutdown_event(), this,
1130 thread_.message_loop_proxy());
jabdelmalek@google.comeb921652010-04-07 05:33:36 +09001131 }
1132
1133 void Run() {
1134 channel()->AddFilter(filter_.get());
1135 }
1136
piman@chromium.org0345c812012-09-08 10:24:49 +09001137 base::Thread thread_;
jabdelmalek@google.comeb921652010-04-07 05:33:36 +09001138 scoped_refptr<TestSyncMessageFilter> filter_;
1139};
1140
ananta@chromium.org999f2972010-09-03 06:45:50 +09001141// This class provides functionality to test the case that a Send on the sync
1142// channel does not crash after the channel has been closed.
1143class ServerSendAfterClose : public Worker {
1144 public:
1145 ServerSendAfterClose()
1146 : Worker(Channel::MODE_SERVER, "simpler_server"),
1147 send_result_(true) {
1148 }
1149
1150 bool SendDummy() {
jhawkins@chromium.org9827bd12011-11-13 06:16:41 +09001151 ListenerThread()->message_loop()->PostTask(
ajwong@chromium.orgc1e632d2012-01-06 11:37:17 +09001152 FROM_HERE, base::Bind(base::IgnoreResult(&ServerSendAfterClose::Send),
1153 this, new SyncChannelTestMsg_NoArgs));
ananta@chromium.org999f2972010-09-03 06:45:50 +09001154 return true;
1155 }
1156
1157 bool send_result() const {
1158 return send_result_;
1159 }
1160
1161 private:
1162 virtual void Run() {
1163 CloseChannel();
1164 Done();
1165 }
1166
1167 bool Send(Message* msg) {
1168 send_result_ = Worker::Send(msg);
1169 Done();
1170 return send_result_;
1171 }
1172
1173 bool send_result_;
1174};
1175
jabdelmalek@google.comeb921652010-04-07 05:33:36 +09001176} // namespace
1177
1178// Tests basic synchronous call
1179TEST_F(IPCSyncChannelTest, SyncMessageFilter) {
1180 std::vector<Worker*> workers;
1181 workers.push_back(new SyncMessageFilterServer());
1182 workers.push_back(new SimpleClient());
1183 RunTest(workers);
1184}
ananta@chromium.org999f2972010-09-03 06:45:50 +09001185
1186// Test the case when the channel is closed and a Send is attempted after that.
1187TEST_F(IPCSyncChannelTest, SendAfterClose) {
1188 ServerSendAfterClose server;
1189 server.Start();
1190
1191 server.done_event()->Wait();
1192 server.done_event()->Reset();
1193
1194 server.SendDummy();
1195 server.done_event()->Wait();
1196
1197 EXPECT_FALSE(server.send_result());
viettrungluu@chromium.org42575b02013-01-08 15:09:07 +09001198
1199 server.Shutdown();
ananta@chromium.org999f2972010-09-03 06:45:50 +09001200}
1201
piman@google.com0cbefaa2011-04-08 12:38:21 +09001202//-----------------------------------------------------------------------------
ananta@chromium.org999f2972010-09-03 06:45:50 +09001203
piman@google.com0cbefaa2011-04-08 12:38:21 +09001204namespace {
1205
1206class RestrictedDispatchServer : public Worker {
1207 public:
piman@chromium.org5a00b882012-03-31 06:29:30 +09001208 RestrictedDispatchServer(WaitableEvent* sent_ping_event,
1209 WaitableEvent* wait_event)
piman@google.com0cbefaa2011-04-08 12:38:21 +09001210 : Worker("restricted_channel", Channel::MODE_SERVER),
piman@chromium.org5a00b882012-03-31 06:29:30 +09001211 sent_ping_event_(sent_ping_event),
1212 wait_event_(wait_event) { }
piman@google.com0cbefaa2011-04-08 12:38:21 +09001213
1214 void OnDoPing(int ping) {
1215 // Send an asynchronous message that unblocks the caller.
kushi.p@gmail.com5948bf42011-05-14 07:42:41 +09001216 Message* msg = new SyncChannelTestMsg_Ping(ping);
piman@google.com0cbefaa2011-04-08 12:38:21 +09001217 msg->set_unblock(true);
1218 Send(msg);
1219 // Signal the event after the message has been sent on the channel, on the
1220 // IPC thread.
jhawkins@chromium.org9827bd12011-11-13 06:16:41 +09001221 ipc_thread().message_loop()->PostTask(
1222 FROM_HERE, base::Bind(&RestrictedDispatchServer::OnPingSent, this));
piman@google.com0cbefaa2011-04-08 12:38:21 +09001223 }
1224
piman@chromium.org5a00b882012-03-31 06:29:30 +09001225 void OnPingTTL(int ping, int* out) {
1226 *out = ping;
1227 wait_event_->Wait();
1228 }
1229
piman@google.com0cbefaa2011-04-08 12:38:21 +09001230 base::Thread* ListenerThread() { return Worker::ListenerThread(); }
1231
1232 private:
1233 bool OnMessageReceived(const Message& message) {
1234 IPC_BEGIN_MESSAGE_MAP(RestrictedDispatchServer, message)
1235 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_NoArgs, OnNoArgs)
piman@chromium.org5a00b882012-03-31 06:29:30 +09001236 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_PingTTL, OnPingTTL)
piman@google.com0cbefaa2011-04-08 12:38:21 +09001237 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_Done, Done)
1238 IPC_END_MESSAGE_MAP()
1239 return true;
1240 }
1241
1242 void OnPingSent() {
1243 sent_ping_event_->Signal();
1244 }
1245
1246 void OnNoArgs() { }
1247 WaitableEvent* sent_ping_event_;
piman@chromium.org5a00b882012-03-31 06:29:30 +09001248 WaitableEvent* wait_event_;
piman@google.com0cbefaa2011-04-08 12:38:21 +09001249};
1250
1251class NonRestrictedDispatchServer : public Worker {
1252 public:
piman@chromium.org5a00b882012-03-31 06:29:30 +09001253 NonRestrictedDispatchServer(WaitableEvent* signal_event)
1254 : Worker("non_restricted_channel", Channel::MODE_SERVER),
1255 signal_event_(signal_event) {}
1256
1257 base::Thread* ListenerThread() { return Worker::ListenerThread(); }
1258
1259 void OnDoPingTTL(int ping) {
1260 int value = 0;
1261 Send(new SyncChannelTestMsg_PingTTL(ping, &value));
1262 signal_event_->Signal();
1263 }
piman@google.com0cbefaa2011-04-08 12:38:21 +09001264
1265 private:
1266 bool OnMessageReceived(const Message& message) {
1267 IPC_BEGIN_MESSAGE_MAP(NonRestrictedDispatchServer, message)
1268 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_NoArgs, OnNoArgs)
1269 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_Done, Done)
1270 IPC_END_MESSAGE_MAP()
1271 return true;
1272 }
1273
1274 void OnNoArgs() { }
piman@chromium.org5a00b882012-03-31 06:29:30 +09001275 WaitableEvent* signal_event_;
piman@google.com0cbefaa2011-04-08 12:38:21 +09001276};
1277
1278class RestrictedDispatchClient : public Worker {
1279 public:
1280 RestrictedDispatchClient(WaitableEvent* sent_ping_event,
1281 RestrictedDispatchServer* server,
piman@chromium.org5a00b882012-03-31 06:29:30 +09001282 NonRestrictedDispatchServer* server2,
piman@google.com0cbefaa2011-04-08 12:38:21 +09001283 int* success)
1284 : Worker("restricted_channel", Channel::MODE_CLIENT),
1285 ping_(0),
1286 server_(server),
piman@chromium.org5a00b882012-03-31 06:29:30 +09001287 server2_(server2),
piman@google.com0cbefaa2011-04-08 12:38:21 +09001288 success_(success),
1289 sent_ping_event_(sent_ping_event) {}
1290
1291 void Run() {
1292 // Incoming messages from our channel should only be dispatched when we
1293 // send a message on that same channel.
piman@chromium.org5a00b882012-03-31 06:29:30 +09001294 channel()->SetRestrictDispatchChannelGroup(1);
piman@google.com0cbefaa2011-04-08 12:38:21 +09001295
jhawkins@chromium.org9827bd12011-11-13 06:16:41 +09001296 server_->ListenerThread()->message_loop()->PostTask(
1297 FROM_HERE, base::Bind(&RestrictedDispatchServer::OnDoPing, server_, 1));
piman@google.com0cbefaa2011-04-08 12:38:21 +09001298 sent_ping_event_->Wait();
1299 Send(new SyncChannelTestMsg_NoArgs);
1300 if (ping_ == 1)
1301 ++*success_;
1302 else
1303 LOG(ERROR) << "Send failed to dispatch incoming message on same channel";
1304
piman@chromium.org5a00b882012-03-31 06:29:30 +09001305 non_restricted_channel_.reset(new SyncChannel(
piman@google.com0cbefaa2011-04-08 12:38:21 +09001306 "non_restricted_channel", Channel::MODE_CLIENT, this,
jam@chromium.org06d18442011-05-03 03:00:49 +09001307 ipc_thread().message_loop_proxy(), true, shutdown_event()));
piman@google.com0cbefaa2011-04-08 12:38:21 +09001308
jhawkins@chromium.org9827bd12011-11-13 06:16:41 +09001309 server_->ListenerThread()->message_loop()->PostTask(
1310 FROM_HERE, base::Bind(&RestrictedDispatchServer::OnDoPing, server_, 2));
piman@google.com0cbefaa2011-04-08 12:38:21 +09001311 sent_ping_event_->Wait();
1312 // Check that the incoming message is *not* dispatched when sending on the
1313 // non restricted channel.
1314 // TODO(piman): there is a possibility of a false positive race condition
1315 // here, if the message that was posted on the server-side end of the pipe
1316 // is not visible yet on the client side, but I don't know how to solve this
1317 // without hooking into the internals of SyncChannel. I haven't seen it in
1318 // practice (i.e. not setting SetRestrictDispatchToSameChannel does cause
1319 // the following to fail).
piman@chromium.org5a00b882012-03-31 06:29:30 +09001320 non_restricted_channel_->Send(new SyncChannelTestMsg_NoArgs);
piman@google.com0cbefaa2011-04-08 12:38:21 +09001321 if (ping_ == 1)
1322 ++*success_;
1323 else
1324 LOG(ERROR) << "Send dispatched message from restricted channel";
1325
1326 Send(new SyncChannelTestMsg_NoArgs);
1327 if (ping_ == 2)
1328 ++*success_;
1329 else
1330 LOG(ERROR) << "Send failed to dispatch incoming message on same channel";
1331
piman@chromium.org5a00b882012-03-31 06:29:30 +09001332 // Check that the incoming message on the non-restricted channel is
1333 // dispatched when sending on the restricted channel.
1334 server2_->ListenerThread()->message_loop()->PostTask(
1335 FROM_HERE,
1336 base::Bind(&NonRestrictedDispatchServer::OnDoPingTTL, server2_, 3));
1337 int value = 0;
1338 Send(new SyncChannelTestMsg_PingTTL(4, &value));
1339 if (ping_ == 3 && value == 4)
1340 ++*success_;
1341 else
1342 LOG(ERROR) << "Send failed to dispatch message from unrestricted channel";
1343
1344 non_restricted_channel_->Send(new SyncChannelTestMsg_Done);
1345 non_restricted_channel_.reset();
piman@google.com0cbefaa2011-04-08 12:38:21 +09001346 Send(new SyncChannelTestMsg_Done);
1347 Done();
1348 }
1349
1350 private:
1351 bool OnMessageReceived(const Message& message) {
1352 IPC_BEGIN_MESSAGE_MAP(RestrictedDispatchClient, message)
1353 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_Ping, OnPing)
piman@chromium.org5a00b882012-03-31 06:29:30 +09001354 IPC_MESSAGE_HANDLER_DELAY_REPLY(SyncChannelTestMsg_PingTTL, OnPingTTL)
piman@google.com0cbefaa2011-04-08 12:38:21 +09001355 IPC_END_MESSAGE_MAP()
1356 return true;
1357 }
1358
1359 void OnPing(int ping) {
1360 ping_ = ping;
1361 }
1362
piman@chromium.org5a00b882012-03-31 06:29:30 +09001363 void OnPingTTL(int ping, IPC::Message* reply) {
1364 ping_ = ping;
1365 // This message comes from the NonRestrictedDispatchServer, we have to send
1366 // the reply back manually.
1367 SyncChannelTestMsg_PingTTL::WriteReplyParams(reply, ping);
1368 non_restricted_channel_->Send(reply);
1369 }
1370
piman@google.com0cbefaa2011-04-08 12:38:21 +09001371 int ping_;
1372 RestrictedDispatchServer* server_;
piman@chromium.org5a00b882012-03-31 06:29:30 +09001373 NonRestrictedDispatchServer* server2_;
piman@google.com0cbefaa2011-04-08 12:38:21 +09001374 int* success_;
1375 WaitableEvent* sent_ping_event_;
piman@chromium.org5a00b882012-03-31 06:29:30 +09001376 scoped_ptr<SyncChannel> non_restricted_channel_;
piman@google.com0cbefaa2011-04-08 12:38:21 +09001377};
1378
1379} // namespace
1380
1381TEST_F(IPCSyncChannelTest, RestrictedDispatch) {
1382 WaitableEvent sent_ping_event(false, false);
piman@chromium.org5a00b882012-03-31 06:29:30 +09001383 WaitableEvent wait_event(false, false);
piman@google.com0cbefaa2011-04-08 12:38:21 +09001384 RestrictedDispatchServer* server =
piman@chromium.org5a00b882012-03-31 06:29:30 +09001385 new RestrictedDispatchServer(&sent_ping_event, &wait_event);
1386 NonRestrictedDispatchServer* server2 =
1387 new NonRestrictedDispatchServer(&wait_event);
1388
piman@google.com0cbefaa2011-04-08 12:38:21 +09001389 int success = 0;
1390 std::vector<Worker*> workers;
piman@google.com0cbefaa2011-04-08 12:38:21 +09001391 workers.push_back(server);
piman@chromium.org5a00b882012-03-31 06:29:30 +09001392 workers.push_back(server2);
1393 workers.push_back(new RestrictedDispatchClient(
1394 &sent_ping_event, server, server2, &success));
piman@google.com0cbefaa2011-04-08 12:38:21 +09001395 RunTest(workers);
piman@chromium.org5a00b882012-03-31 06:29:30 +09001396 EXPECT_EQ(4, success);
piman@google.com0cbefaa2011-04-08 12:38:21 +09001397}
kushi.p@gmail.com5948bf42011-05-14 07:42:41 +09001398
jhorwich@chromium.org3c3a8132012-01-12 07:39:54 +09001399//-----------------------------------------------------------------------------
1400
1401// This test case inspired by crbug.com/108491
1402// We create two servers that use the same ListenerThread but have
1403// SetRestrictDispatchToSameChannel set to true.
1404// We create clients, then use some specific WaitableEvent wait/signalling to
1405// ensure that messages get dispatched in a way that causes a deadlock due to
1406// a nested dispatch and an eligible message in a higher-level dispatch's
1407// delayed_queue. Specifically, we start with client1 about so send an
1408// unblocking message to server1, while the shared listener thread for the
1409// servers server1 and server2 is about to send a non-unblocking message to
1410// client1. At the same time, client2 will be about to send an unblocking
1411// message to server2. Server1 will handle the client1->server1 message by
1412// telling server2 to send a non-unblocking message to client2.
1413// What should happen is that the send to server2 should find the pending,
1414// same-context client2->server2 message to dispatch, causing client2 to
1415// unblock then handle the server2->client2 message, so that the shared
1416// servers' listener thread can then respond to the client1->server1 message.
1417// Then client1 can handle the non-unblocking server1->client1 message.
1418// The old code would end up in a state where the server2->client2 message is
1419// sent, but the client2->server2 message (which is eligible for dispatch, and
1420// which is what client2 is waiting for) is stashed in a local delayed_queue
1421// that has server1's channel context, causing a deadlock.
1422// WaitableEvents in the events array are used to:
1423// event 0: indicate to client1 that server listener is in OnDoServerTask
1424// event 1: indicate to client1 that client2 listener is in OnDoClient2Task
1425// event 2: indicate to server1 that client2 listener is in OnDoClient2Task
1426// event 3: indicate to client2 that server listener is in OnDoServerTask
1427
1428namespace {
1429
1430class RestrictedDispatchDeadlockServer : public Worker {
1431 public:
1432 RestrictedDispatchDeadlockServer(int server_num,
1433 WaitableEvent* server_ready_event,
1434 WaitableEvent** events,
1435 RestrictedDispatchDeadlockServer* peer)
1436 : Worker(server_num == 1 ? "channel1" : "channel2", Channel::MODE_SERVER),
1437 server_num_(server_num),
1438 server_ready_event_(server_ready_event),
1439 events_(events),
thakis@chromium.orgad1a2c52012-07-21 01:17:29 +09001440 peer_(peer) { }
jhorwich@chromium.org3c3a8132012-01-12 07:39:54 +09001441
1442 void OnDoServerTask() {
1443 events_[3]->Signal();
1444 events_[2]->Wait();
1445 events_[0]->Signal();
1446 SendMessageToClient();
1447 }
1448
1449 void Run() {
piman@chromium.org5a00b882012-03-31 06:29:30 +09001450 channel()->SetRestrictDispatchChannelGroup(1);
jhorwich@chromium.org3c3a8132012-01-12 07:39:54 +09001451 server_ready_event_->Signal();
1452 }
1453
1454 base::Thread* ListenerThread() { return Worker::ListenerThread(); }
1455
1456 private:
1457 bool OnMessageReceived(const Message& message) {
1458 IPC_BEGIN_MESSAGE_MAP(RestrictedDispatchDeadlockServer, message)
1459 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_NoArgs, OnNoArgs)
1460 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_Done, Done)
1461 IPC_END_MESSAGE_MAP()
1462 return true;
1463 }
1464
1465 void OnNoArgs() {
1466 if (server_num_ == 1) {
1467 DCHECK(peer_ != NULL);
1468 peer_->SendMessageToClient();
1469 }
1470 }
1471
1472 void SendMessageToClient() {
1473 Message* msg = new SyncChannelTestMsg_NoArgs;
1474 msg->set_unblock(false);
1475 DCHECK(!msg->should_unblock());
1476 Send(msg);
1477 }
1478
1479 int server_num_;
1480 WaitableEvent* server_ready_event_;
1481 WaitableEvent** events_;
1482 RestrictedDispatchDeadlockServer* peer_;
jhorwich@chromium.org3c3a8132012-01-12 07:39:54 +09001483};
1484
1485class RestrictedDispatchDeadlockClient2 : public Worker {
1486 public:
1487 RestrictedDispatchDeadlockClient2(RestrictedDispatchDeadlockServer* server,
1488 WaitableEvent* server_ready_event,
1489 WaitableEvent** events)
1490 : Worker("channel2", Channel::MODE_CLIENT),
jhorwich@chromium.org3c3a8132012-01-12 07:39:54 +09001491 server_ready_event_(server_ready_event),
1492 events_(events),
1493 received_msg_(false),
1494 received_noarg_reply_(false),
1495 done_issued_(false) {}
1496
1497 void Run() {
1498 server_ready_event_->Wait();
1499 }
1500
1501 void OnDoClient2Task() {
1502 events_[3]->Wait();
1503 events_[1]->Signal();
1504 events_[2]->Signal();
1505 DCHECK(received_msg_ == false);
1506
1507 Message* message = new SyncChannelTestMsg_NoArgs;
1508 message->set_unblock(true);
1509 Send(message);
1510 received_noarg_reply_ = true;
1511 }
1512
1513 base::Thread* ListenerThread() { return Worker::ListenerThread(); }
1514 private:
1515 bool OnMessageReceived(const Message& message) {
1516 IPC_BEGIN_MESSAGE_MAP(RestrictedDispatchDeadlockClient2, message)
1517 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_NoArgs, OnNoArgs)
1518 IPC_END_MESSAGE_MAP()
1519 return true;
1520 }
1521
1522 void OnNoArgs() {
1523 received_msg_ = true;
1524 PossiblyDone();
1525 }
1526
1527 void PossiblyDone() {
1528 if (received_noarg_reply_ && received_msg_) {
1529 DCHECK(done_issued_ == false);
1530 done_issued_ = true;
1531 Send(new SyncChannelTestMsg_Done);
1532 Done();
1533 }
1534 }
1535
jhorwich@chromium.org3c3a8132012-01-12 07:39:54 +09001536 WaitableEvent* server_ready_event_;
1537 WaitableEvent** events_;
1538 bool received_msg_;
1539 bool received_noarg_reply_;
1540 bool done_issued_;
1541};
1542
1543class RestrictedDispatchDeadlockClient1 : public Worker {
1544 public:
1545 RestrictedDispatchDeadlockClient1(RestrictedDispatchDeadlockServer* server,
1546 RestrictedDispatchDeadlockClient2* peer,
1547 WaitableEvent* server_ready_event,
1548 WaitableEvent** events)
1549 : Worker("channel1", Channel::MODE_CLIENT),
1550 server_(server),
1551 peer_(peer),
1552 server_ready_event_(server_ready_event),
1553 events_(events),
1554 received_msg_(false),
1555 received_noarg_reply_(false),
1556 done_issued_(false) {}
1557
1558 void Run() {
1559 server_ready_event_->Wait();
1560 server_->ListenerThread()->message_loop()->PostTask(
1561 FROM_HERE,
1562 base::Bind(&RestrictedDispatchDeadlockServer::OnDoServerTask, server_));
1563 peer_->ListenerThread()->message_loop()->PostTask(
1564 FROM_HERE,
1565 base::Bind(&RestrictedDispatchDeadlockClient2::OnDoClient2Task, peer_));
1566 events_[0]->Wait();
1567 events_[1]->Wait();
1568 DCHECK(received_msg_ == false);
1569
1570 Message* message = new SyncChannelTestMsg_NoArgs;
1571 message->set_unblock(true);
1572 Send(message);
1573 received_noarg_reply_ = true;
1574 PossiblyDone();
1575 }
1576
1577 base::Thread* ListenerThread() { return Worker::ListenerThread(); }
1578 private:
1579 bool OnMessageReceived(const Message& message) {
1580 IPC_BEGIN_MESSAGE_MAP(RestrictedDispatchDeadlockClient1, message)
1581 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_NoArgs, OnNoArgs)
1582 IPC_END_MESSAGE_MAP()
1583 return true;
1584 }
1585
1586 void OnNoArgs() {
1587 received_msg_ = true;
1588 PossiblyDone();
1589 }
1590
1591 void PossiblyDone() {
1592 if (received_noarg_reply_ && received_msg_) {
1593 DCHECK(done_issued_ == false);
1594 done_issued_ = true;
1595 Send(new SyncChannelTestMsg_Done);
1596 Done();
1597 }
1598 }
1599
1600 RestrictedDispatchDeadlockServer* server_;
1601 RestrictedDispatchDeadlockClient2* peer_;
1602 WaitableEvent* server_ready_event_;
1603 WaitableEvent** events_;
1604 bool received_msg_;
1605 bool received_noarg_reply_;
1606 bool done_issued_;
1607};
1608
1609} // namespace
1610
1611TEST_F(IPCSyncChannelTest, RestrictedDispatchDeadlock) {
1612 std::vector<Worker*> workers;
1613
1614 // A shared worker thread so that server1 and server2 run on one thread.
1615 base::Thread worker_thread("RestrictedDispatchDeadlock");
1616 ASSERT_TRUE(worker_thread.Start());
1617
1618 WaitableEvent server1_ready(false, false);
1619 WaitableEvent server2_ready(false, false);
1620
1621 WaitableEvent event0(false, false);
1622 WaitableEvent event1(false, false);
1623 WaitableEvent event2(false, false);
1624 WaitableEvent event3(false, false);
1625 WaitableEvent* events[4] = {&event0, &event1, &event2, &event3};
1626
1627 RestrictedDispatchDeadlockServer* server1;
1628 RestrictedDispatchDeadlockServer* server2;
1629 RestrictedDispatchDeadlockClient1* client1;
1630 RestrictedDispatchDeadlockClient2* client2;
1631
1632 server2 = new RestrictedDispatchDeadlockServer(2, &server2_ready, events,
1633 NULL);
1634 server2->OverrideThread(&worker_thread);
1635 workers.push_back(server2);
1636
1637 client2 = new RestrictedDispatchDeadlockClient2(server2, &server2_ready,
1638 events);
1639 workers.push_back(client2);
1640
1641 server1 = new RestrictedDispatchDeadlockServer(1, &server1_ready, events,
1642 server2);
1643 server1->OverrideThread(&worker_thread);
1644 workers.push_back(server1);
1645
1646 client1 = new RestrictedDispatchDeadlockClient1(server1, client2,
1647 &server1_ready, events);
1648 workers.push_back(client1);
1649
1650 RunTest(workers);
1651}
1652
jschuh@chromium.orgf75a4d12012-03-17 11:20:46 +09001653//-----------------------------------------------------------------------------
1654
piman@chromium.org5a00b882012-03-31 06:29:30 +09001655// This test case inspired by crbug.com/120530
1656// We create 4 workers that pipe to each other W1->W2->W3->W4->W1 then we send a
1657// message that recurses through 3, 4 or 5 steps to make sure, say, W1 can
1658// re-enter when called from W4 while it's sending a message to W2.
1659// The first worker drives the whole test so it must be treated specially.
1660namespace {
1661
1662class RestrictedDispatchPipeWorker : public Worker {
1663 public:
1664 RestrictedDispatchPipeWorker(
1665 const std::string &channel1,
1666 WaitableEvent* event1,
1667 const std::string &channel2,
1668 WaitableEvent* event2,
1669 int group,
1670 int* success)
1671 : Worker(channel1, Channel::MODE_SERVER),
1672 event1_(event1),
1673 event2_(event2),
1674 other_channel_name_(channel2),
1675 group_(group),
1676 success_(success) {
1677 }
1678
1679 void OnPingTTL(int ping, int* ret) {
1680 *ret = 0;
1681 if (!ping)
1682 return;
1683 other_channel_->Send(new SyncChannelTestMsg_PingTTL(ping - 1, ret));
1684 ++*ret;
1685 }
1686
1687 void OnDone() {
1688 if (is_first())
1689 return;
1690 other_channel_->Send(new SyncChannelTestMsg_Done);
1691 other_channel_.reset();
1692 Done();
1693 }
1694
1695 void Run() {
1696 channel()->SetRestrictDispatchChannelGroup(group_);
1697 if (is_first())
1698 event1_->Signal();
1699 event2_->Wait();
1700 other_channel_.reset(new SyncChannel(
1701 other_channel_name_, Channel::MODE_CLIENT, this,
1702 ipc_thread().message_loop_proxy(), true, shutdown_event()));
1703 other_channel_->SetRestrictDispatchChannelGroup(group_);
1704 if (!is_first()) {
1705 event1_->Signal();
1706 return;
1707 }
1708 *success_ = 0;
1709 int value = 0;
1710 OnPingTTL(3, &value);
1711 *success_ += (value == 3);
1712 OnPingTTL(4, &value);
1713 *success_ += (value == 4);
1714 OnPingTTL(5, &value);
1715 *success_ += (value == 5);
1716 other_channel_->Send(new SyncChannelTestMsg_Done);
1717 other_channel_.reset();
1718 Done();
1719 }
1720
1721 bool is_first() { return !!success_; }
1722
1723 private:
1724 bool OnMessageReceived(const Message& message) {
1725 IPC_BEGIN_MESSAGE_MAP(RestrictedDispatchPipeWorker, message)
1726 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_PingTTL, OnPingTTL)
1727 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_Done, OnDone)
1728 IPC_END_MESSAGE_MAP()
1729 return true;
1730 }
1731
1732 scoped_ptr<SyncChannel> other_channel_;
1733 WaitableEvent* event1_;
1734 WaitableEvent* event2_;
1735 std::string other_channel_name_;
1736 int group_;
1737 int* success_;
1738};
1739
1740} // namespace
1741
1742TEST_F(IPCSyncChannelTest, RestrictedDispatch4WayDeadlock) {
1743 int success = 0;
1744 std::vector<Worker*> workers;
1745 WaitableEvent event0(true, false);
1746 WaitableEvent event1(true, false);
1747 WaitableEvent event2(true, false);
1748 WaitableEvent event3(true, false);
1749 workers.push_back(new RestrictedDispatchPipeWorker(
1750 "channel0", &event0, "channel1", &event1, 1, &success));
1751 workers.push_back(new RestrictedDispatchPipeWorker(
1752 "channel1", &event1, "channel2", &event2, 2, NULL));
1753 workers.push_back(new RestrictedDispatchPipeWorker(
1754 "channel2", &event2, "channel3", &event3, 3, NULL));
1755 workers.push_back(new RestrictedDispatchPipeWorker(
1756 "channel3", &event3, "channel0", &event0, 4, NULL));
1757 RunTest(workers);
1758 EXPECT_EQ(3, success);
1759}
1760
piman@chromium.orgde4e75e2012-04-11 05:07:53 +09001761
1762//-----------------------------------------------------------------------------
1763//
1764// This test case inspired by crbug.com/122443
1765// We want to make sure a reply message with the unblock flag set correctly
1766// behaves as a reply, not a regular message.
1767// We have 3 workers. Server1 will send a message to Server2 (which will block),
1768// during which it will dispatch a message comming from Client, at which point
1769// it will send another message to Server2. While sending that second message it
1770// will receive a reply from Server1 with the unblock flag.
1771
1772namespace {
1773
1774class ReentrantReplyServer1 : public Worker {
1775 public:
1776 ReentrantReplyServer1(WaitableEvent* server_ready)
1777 : Worker("reentrant_reply1", Channel::MODE_SERVER),
1778 server_ready_(server_ready) { }
1779
1780 void Run() {
1781 server2_channel_.reset(new SyncChannel(
1782 "reentrant_reply2", Channel::MODE_CLIENT, this,
1783 ipc_thread().message_loop_proxy(), true, shutdown_event()));
1784 server_ready_->Signal();
1785 Message* msg = new SyncChannelTestMsg_Reentrant1();
1786 server2_channel_->Send(msg);
1787 server2_channel_.reset();
1788 Done();
1789 }
1790
1791 private:
1792 bool OnMessageReceived(const Message& message) {
1793 IPC_BEGIN_MESSAGE_MAP(ReentrantReplyServer1, message)
1794 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_Reentrant2, OnReentrant2)
1795 IPC_REPLY_HANDLER(OnReply)
1796 IPC_END_MESSAGE_MAP()
1797 return true;
1798 }
1799
1800 void OnReentrant2() {
1801 Message* msg = new SyncChannelTestMsg_Reentrant3();
1802 server2_channel_->Send(msg);
1803 }
1804
1805 void OnReply(const Message& message) {
1806 // If we get here, the Send() will never receive the reply (thus would
1807 // hang), so abort instead.
1808 LOG(FATAL) << "Reply message was dispatched";
1809 }
1810
1811 WaitableEvent* server_ready_;
1812 scoped_ptr<SyncChannel> server2_channel_;
1813};
1814
1815class ReentrantReplyServer2 : public Worker {
1816 public:
1817 ReentrantReplyServer2()
1818 : Worker("reentrant_reply2", Channel::MODE_SERVER),
1819 reply_(NULL) { }
1820
1821 private:
1822 bool OnMessageReceived(const Message& message) {
1823 IPC_BEGIN_MESSAGE_MAP(ReentrantReplyServer2, message)
1824 IPC_MESSAGE_HANDLER_DELAY_REPLY(
1825 SyncChannelTestMsg_Reentrant1, OnReentrant1)
1826 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_Reentrant3, OnReentrant3)
1827 IPC_END_MESSAGE_MAP()
1828 return true;
1829 }
1830
1831 void OnReentrant1(Message* reply) {
1832 DCHECK(!reply_);
1833 reply_ = reply;
1834 }
1835
1836 void OnReentrant3() {
1837 DCHECK(reply_);
1838 Message* reply = reply_;
1839 reply_ = NULL;
1840 reply->set_unblock(true);
1841 Send(reply);
1842 Done();
1843 }
1844
1845 Message* reply_;
1846};
1847
1848class ReentrantReplyClient : public Worker {
1849 public:
1850 ReentrantReplyClient(WaitableEvent* server_ready)
1851 : Worker("reentrant_reply1", Channel::MODE_CLIENT),
1852 server_ready_(server_ready) { }
1853
1854 void Run() {
1855 server_ready_->Wait();
1856 Send(new SyncChannelTestMsg_Reentrant2());
1857 Done();
1858 }
1859
1860 private:
1861 WaitableEvent* server_ready_;
1862};
1863
1864} // namespace
1865
1866TEST_F(IPCSyncChannelTest, ReentrantReply) {
1867 std::vector<Worker*> workers;
1868 WaitableEvent server_ready(false, false);
1869 workers.push_back(new ReentrantReplyServer2());
1870 workers.push_back(new ReentrantReplyServer1(&server_ready));
1871 workers.push_back(new ReentrantReplyClient(&server_ready));
1872 RunTest(workers);
1873}
1874
piman@chromium.org5a00b882012-03-31 06:29:30 +09001875//-----------------------------------------------------------------------------
1876
jschuh@chromium.orgf75a4d12012-03-17 11:20:46 +09001877// Generate a validated channel ID using Channel::GenerateVerifiedChannelID().
1878namespace {
1879
1880class VerifiedServer : public Worker {
1881 public:
1882 VerifiedServer(base::Thread* listener_thread,
1883 const std::string& channel_name,
1884 const std::string& reply_text)
1885 : Worker(channel_name, Channel::MODE_SERVER),
1886 reply_text_(reply_text) {
1887 Worker::OverrideThread(listener_thread);
1888 }
1889
1890 virtual void OnNestedTestMsg(Message* reply_msg) {
1891 VLOG(1) << __FUNCTION__ << " Sending reply: " << reply_text_;
1892 SyncChannelNestedTestMsg_String::WriteReplyParams(reply_msg, reply_text_);
1893 Send(reply_msg);
jschuh@chromium.orga5cd0762012-04-05 11:38:34 +09001894 ASSERT_EQ(channel()->peer_pid(), base::GetCurrentProcId());
jschuh@chromium.orgf75a4d12012-03-17 11:20:46 +09001895 Done();
1896 }
1897
1898 private:
1899 std::string reply_text_;
1900};
1901
1902class VerifiedClient : public Worker {
1903 public:
1904 VerifiedClient(base::Thread* listener_thread,
1905 const std::string& channel_name,
1906 const std::string& expected_text)
1907 : Worker(channel_name, Channel::MODE_CLIENT),
1908 expected_text_(expected_text) {
1909 Worker::OverrideThread(listener_thread);
1910 }
1911
1912 virtual void Run() {
1913 std::string response;
1914 SyncMessage* msg = new SyncChannelNestedTestMsg_String(&response);
1915 bool result = Send(msg);
1916 DCHECK(result);
1917 DCHECK_EQ(response, expected_text_);
thakis@chromium.orgcdf5b3b2012-06-28 01:07:34 +09001918 // expected_text_ is only used in the above DCHECK. This line suppresses the
1919 // "unused private field" warning in release builds.
1920 (void)expected_text_;
jschuh@chromium.orgf75a4d12012-03-17 11:20:46 +09001921
1922 VLOG(1) << __FUNCTION__ << " Received reply: " << response;
jschuh@chromium.orga5cd0762012-04-05 11:38:34 +09001923 ASSERT_EQ(channel()->peer_pid(), base::GetCurrentProcId());
jschuh@chromium.orgf75a4d12012-03-17 11:20:46 +09001924 Done();
1925 }
1926
1927 private:
jschuh@chromium.orgf75a4d12012-03-17 11:20:46 +09001928 std::string expected_text_;
1929};
1930
1931void Verified() {
1932 std::vector<Worker*> workers;
1933
1934 // A shared worker thread for servers
1935 base::Thread server_worker_thread("Verified_ServerListener");
1936 ASSERT_TRUE(server_worker_thread.Start());
1937
1938 base::Thread client_worker_thread("Verified_ClientListener");
1939 ASSERT_TRUE(client_worker_thread.Start());
1940
1941 std::string channel_id = Channel::GenerateVerifiedChannelID("Verified");
1942 Worker* worker;
1943
1944 worker = new VerifiedServer(&server_worker_thread,
1945 channel_id,
1946 "Got first message");
1947 workers.push_back(worker);
1948
1949 worker = new VerifiedClient(&client_worker_thread,
1950 channel_id,
1951 "Got first message");
1952 workers.push_back(worker);
1953
1954 RunTest(workers);
1955
1956#if defined(OS_WIN)
1957#endif
1958}
1959
1960} // namespace
1961
1962// Windows needs to send an out-of-band secret to verify the client end of the
1963// channel. Test that we still connect correctly in that case.
1964TEST_F(IPCSyncChannelTest, Verified) {
1965 Verified();
1966}
1967
kushi.p@gmail.com5948bf42011-05-14 07:42:41 +09001968} // namespace IPC