Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(261)

Side by Side Diff: ipc/ipc_sync_channel_unittest.cc

Issue 9022038: Reimplement ReceivedSyncMsgQueue::DispatchMessages (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add descriptive comment to unittest Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ipc/ipc_sync_channel.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 // Unit test for SyncChannel. 5 // Unit test for SyncChannel.
6 6
7 #include "ipc/ipc_sync_channel.h" 7 #include "ipc/ipc_sync_channel.h"
8 8
9 #include <string> 9 #include <string>
10 #include <vector> 10 #include <vector>
(...skipping 1316 matching lines...) Expand 10 before | Expand all | Expand 10 after
1327 int success = 0; 1327 int success = 0;
1328 std::vector<Worker*> workers; 1328 std::vector<Worker*> workers;
1329 workers.push_back(new NonRestrictedDispatchServer); 1329 workers.push_back(new NonRestrictedDispatchServer);
1330 workers.push_back(server); 1330 workers.push_back(server);
1331 workers.push_back( 1331 workers.push_back(
1332 new RestrictedDispatchClient(&sent_ping_event, server, &success)); 1332 new RestrictedDispatchClient(&sent_ping_event, server, &success));
1333 RunTest(workers); 1333 RunTest(workers);
1334 EXPECT_EQ(3, success); 1334 EXPECT_EQ(3, success);
1335 } 1335 }
1336 1336
1337 //-----------------------------------------------------------------------------
1338
1339 // This test case inspired by crbug.com/108491
1340 // We create two servers that use the same ListenerThread but have
1341 // SetRestrictDispatchToSameChannel set to true.
1342 // We create clients, then use some specific WaitableEvent wait/signalling to
1343 // ensure that messages get dispatched in a way that causes a deadlock due to
1344 // a nested dispatch and an eligible message in a higher-level dispatch's
1345 // delayed_queue. Specifically, we start with client1 about so send an
piman 2012/01/10 20:52:14 typo: "about so send" -> "about to send"
1346 // unblocking message to server1, while the shared listener thread for the
1347 // servers server1 and server2 is about to send a non-unblocking message to
1348 // client1. At the same time, client2 will be about to send an unblocking
1349 // message to server2. Server1 will handle the client1->server1 message by
1350 // telling server2 to send a non-unblocking message to client2.
1351 // What should happen is that the send to server2 should find the pending,
1352 // same-context client2->server2 message to dispatch, causing client2 to
1353 // unblock then handle the server2->client2 message, so that the shared
1354 // servers' listener thread can then respond to the client1->server1 message.
1355 // Then client1 can handle the non-unblocking server1->client1 message.
1356 // The old code would end up in a state where the server2->client2 message is
1357 // sent, but the client2->server2 message (which is eligible for dispatch, and
1358 // which is what client2 is waiting for) is stashed in a local delayed_queue
1359 // that has server1's channel context, causing a deadlock.
1360 // WaitableEvents in the events array are used to:
1361 // event 0: indicate to client1 that server listener is in OnDoServerTask
1362 // event 1: indicate to client1 that client2 listener is in OnDoClient2Task
1363 // event 2: indicate to server1 that client2 listener is in OnDoClient2Task
1364 // event 3: indicate to client2 that server listener is in OnDoServerTask
1365
1366 namespace {
1367
1368 class RestrictedDispatchDeadlockServer : public Worker {
1369 public:
1370 RestrictedDispatchDeadlockServer(int server_num,
1371 WaitableEvent* server_ready_event,
1372 WaitableEvent** events,
1373 RestrictedDispatchDeadlockServer* peer)
1374 : Worker(server_num == 1 ? "channel1" : "channel2", Channel::MODE_SERVER),
1375 server_num_(server_num),
1376 server_ready_event_(server_ready_event),
1377 events_(events),
1378 peer_(peer),
1379 client_kicked_(false) { }
1380
1381 void OnDoServerTask() {
1382 events_[3]->Signal();
1383 events_[2]->Wait();
1384 events_[0]->Signal();
1385 SendMessageToClient();
1386 }
1387
1388 void Run() {
1389 channel()->SetRestrictDispatchToSameChannel(true);
1390 server_ready_event_->Signal();
1391 }
1392
1393 base::Thread* ListenerThread() { return Worker::ListenerThread(); }
1394
1395 private:
1396 bool OnMessageReceived(const Message& message) {
1397 IPC_BEGIN_MESSAGE_MAP(RestrictedDispatchDeadlockServer, message)
1398 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_NoArgs, OnNoArgs)
1399 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_Done, Done)
1400 IPC_END_MESSAGE_MAP()
1401 return true;
1402 }
1403
1404 void OnNoArgs() {
1405 if (server_num_ == 1) {
1406 DCHECK(peer_ != NULL);
1407 peer_->SendMessageToClient();
1408 }
1409 }
1410
1411 void SendMessageToClient() {
1412 Message* msg = new SyncChannelTestMsg_NoArgs;
1413 msg->set_unblock(false);
1414 DCHECK(!msg->should_unblock());
1415 Send(msg);
1416 }
1417
1418 int server_num_;
1419 WaitableEvent* server_ready_event_;
1420 WaitableEvent** events_;
1421 RestrictedDispatchDeadlockServer* peer_;
1422 bool client_kicked_;
1423 };
1424
1425 class RestrictedDispatchDeadlockClient2 : public Worker {
1426 public:
1427 RestrictedDispatchDeadlockClient2(RestrictedDispatchDeadlockServer* server,
1428 WaitableEvent* server_ready_event,
1429 WaitableEvent** events)
1430 : Worker("channel2", Channel::MODE_CLIENT),
1431 server_(server),
1432 server_ready_event_(server_ready_event),
1433 events_(events),
1434 received_msg_(false),
1435 received_noarg_reply_(false),
1436 done_issued_(false) {}
1437
1438 void Run() {
1439 server_ready_event_->Wait();
1440 }
1441
1442 void OnDoClient2Task() {
1443 events_[3]->Wait();
1444 events_[1]->Signal();
1445 events_[2]->Signal();
1446 DCHECK(received_msg_ == false);
1447
1448 Message* message = new SyncChannelTestMsg_NoArgs;
1449 message->set_unblock(true);
1450 Send(message);
1451 received_noarg_reply_ = true;
1452 }
1453
1454 base::Thread* ListenerThread() { return Worker::ListenerThread(); }
1455 private:
1456 bool OnMessageReceived(const Message& message) {
1457 IPC_BEGIN_MESSAGE_MAP(RestrictedDispatchDeadlockClient2, message)
1458 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_NoArgs, OnNoArgs)
1459 IPC_END_MESSAGE_MAP()
1460 return true;
1461 }
1462
1463 void OnNoArgs() {
1464 received_msg_ = true;
1465 PossiblyDone();
1466 }
1467
1468 void PossiblyDone() {
1469 if (received_noarg_reply_ && received_msg_) {
1470 DCHECK(done_issued_ == false);
1471 done_issued_ = true;
1472 Send(new SyncChannelTestMsg_Done);
1473 Done();
1474 }
1475 }
1476
1477 RestrictedDispatchDeadlockServer* server_;
1478 WaitableEvent* server_ready_event_;
1479 WaitableEvent** events_;
1480 bool received_msg_;
1481 bool received_noarg_reply_;
1482 bool done_issued_;
1483 };
1484
1485 class RestrictedDispatchDeadlockClient1 : public Worker {
1486 public:
1487 RestrictedDispatchDeadlockClient1(RestrictedDispatchDeadlockServer* server,
1488 RestrictedDispatchDeadlockClient2* peer,
1489 WaitableEvent* server_ready_event,
1490 WaitableEvent** events)
1491 : Worker("channel1", Channel::MODE_CLIENT),
1492 server_(server),
1493 peer_(peer),
1494 server_ready_event_(server_ready_event),
1495 events_(events),
1496 received_msg_(false),
1497 received_noarg_reply_(false),
1498 done_issued_(false) {}
1499
1500 void Run() {
1501 server_ready_event_->Wait();
1502 server_->ListenerThread()->message_loop()->PostTask(
1503 FROM_HERE,
1504 base::Bind(&RestrictedDispatchDeadlockServer::OnDoServerTask, server_));
1505 peer_->ListenerThread()->message_loop()->PostTask(
1506 FROM_HERE,
1507 base::Bind(&RestrictedDispatchDeadlockClient2::OnDoClient2Task, peer_));
1508 events_[0]->Wait();
1509 events_[1]->Wait();
1510 DCHECK(received_msg_ == false);
1511
1512 Message* message = new SyncChannelTestMsg_NoArgs;
1513 message->set_unblock(true);
1514 Send(message);
1515 received_noarg_reply_ = true;
1516 PossiblyDone();
1517 }
1518
1519 base::Thread* ListenerThread() { return Worker::ListenerThread(); }
1520 private:
1521 bool OnMessageReceived(const Message& message) {
1522 IPC_BEGIN_MESSAGE_MAP(RestrictedDispatchDeadlockClient1, message)
1523 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_NoArgs, OnNoArgs)
1524 IPC_END_MESSAGE_MAP()
1525 return true;
1526 }
1527
1528 void OnNoArgs() {
1529 received_msg_ = true;
1530 PossiblyDone();
1531 }
1532
1533 void PossiblyDone() {
1534 if (received_noarg_reply_ && received_msg_) {
1535 DCHECK(done_issued_ == false);
1536 done_issued_ = true;
1537 Send(new SyncChannelTestMsg_Done);
1538 Done();
1539 }
1540 }
1541
1542 RestrictedDispatchDeadlockServer* server_;
1543 RestrictedDispatchDeadlockClient2* peer_;
1544 WaitableEvent* server_ready_event_;
1545 WaitableEvent** events_;
1546 bool received_msg_;
1547 bool received_noarg_reply_;
1548 bool done_issued_;
1549 };
1550
1551 } // namespace
1552
1553 TEST_F(IPCSyncChannelTest, RestrictedDispatchDeadlock) {
1554 std::vector<Worker*> workers;
1555
1556 // A shared worker thread so that server1 and server2 run on one thread.
1557 base::Thread worker_thread("RestrictedDispatchDeadlock");
1558 ASSERT_TRUE(worker_thread.Start());
1559
1560 WaitableEvent server1_ready(false, false);
1561 WaitableEvent server2_ready(false, false);
1562
1563 WaitableEvent event0(false, false);
1564 WaitableEvent event1(false, false);
1565 WaitableEvent event2(false, false);
1566 WaitableEvent event3(false, false);
1567 WaitableEvent* events[4] = {&event0, &event1, &event2, &event3};
1568
1569 RestrictedDispatchDeadlockServer* server1;
1570 RestrictedDispatchDeadlockServer* server2;
1571 RestrictedDispatchDeadlockClient1* client1;
1572 RestrictedDispatchDeadlockClient2* client2;
1573
1574 server2 = new RestrictedDispatchDeadlockServer(2, &server2_ready, events,
1575 NULL);
1576 server2->OverrideThread(&worker_thread);
1577 workers.push_back(server2);
1578
1579 client2 = new RestrictedDispatchDeadlockClient2(server2, &server2_ready,
1580 events);
1581 workers.push_back(client2);
1582
1583 server1 = new RestrictedDispatchDeadlockServer(1, &server1_ready, events,
1584 server2);
1585 server1->OverrideThread(&worker_thread);
1586 workers.push_back(server1);
1587
1588 client1 = new RestrictedDispatchDeadlockClient1(server1, client2,
1589 &server1_ready, events);
1590 workers.push_back(client1);
1591
1592 RunTest(workers);
1593 }
1594
1337 } // namespace IPC 1595 } // namespace IPC
OLDNEW
« no previous file with comments | « ipc/ipc_sync_channel.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698