 Chromium Code Reviews
 Chromium Code Reviews Issue 9022038:
  Reimplement ReceivedSyncMsgQueue::DispatchMessages  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 9022038:
  Reimplement ReceivedSyncMsgQueue::DispatchMessages  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| OLD | NEW | 
|---|---|
| 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 Loading... | |
| 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 | 
| OLD | NEW |