Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/assert.h" | 5 #include "vm/assert.h" |
| 6 #include "vm/port.h" | 6 #include "vm/message_queue.h" |
| 7 #include "vm/unit_test.h" | 7 #include "vm/unit_test.h" |
| 8 | 8 |
| 9 namespace dart { | 9 namespace dart { |
| 10 | 10 |
| 11 TEST_CASE(Port) { | |
| 12 const char* msg_data = "Hallo Velo!"; | |
| 13 | 11 |
| 14 intptr_t port1 = PortMap::CreatePort(); | 12 // Provide access to private members of MessageQueue for testing. |
| 15 intptr_t port2 = PortMap::CreatePort(); | 13 class MessageQueueTestPeer { |
| 16 EXPECT(port1 != port2); | 14 public: |
| 15 explicit MessageQueueTestPeer(MessageQueue* queue) : queue_(queue) {} | |
| 17 | 16 |
| 18 PortMessage* msg1 = new PortMessage(port1, 0, strdup(msg_data)); | 17 bool HasMessage() const { return queue_->head_ != NULL; } |
| 19 EXPECT_EQ(true, PortMap::PostMessage(msg1)); | 18 |
| 20 PortMessage* msg = PortMap::ReceiveMessage(10); | 19 private: |
| 21 EXPECT_EQ(port1, msg->dest_id()); | 20 MessageQueue* queue_; |
| 22 EXPECT_EQ(msg1, msg); | 21 }; |
| 22 | |
| 23 | |
| 24 TEST_CASE(MessageQueue_BasicOperations) { | |
| 25 MessageQueue queue; | |
| 26 MessageQueueTestPeer queue_peer(&queue); | |
| 27 EXPECT(!queue_peer.HasMessage()); | |
| 28 | |
| 29 Dart_Port port = 1; | |
| 30 | |
| 31 // Add two elements. | |
| 32 PortMessage* msg1 = new PortMessage(port, 0, strdup("msg1")); | |
| 33 queue.Enqueue(msg1); | |
| 34 EXPECT(queue_peer.HasMessage()); | |
| 35 | |
| 36 PortMessage* msg2 = new PortMessage(port, 0, strdup("msg2")); | |
| 37 queue.Enqueue(msg2); | |
| 38 EXPECT(queue_peer.HasMessage()); | |
| 39 | |
| 40 // Remove two elements. | |
| 41 PortMessage* msg = queue.Dequeue(); | |
| 42 EXPECT(msg != NULL); | |
| 43 EXPECT_STREQ("msg1", reinterpret_cast<char*>(msg->data())); | |
| 44 EXPECT(queue_peer.HasMessage()); | |
| 45 | |
| 46 msg = queue.Dequeue(); | |
| 47 EXPECT(msg != NULL); | |
| 48 EXPECT_STREQ("msg2", reinterpret_cast<char*>(msg->data())); | |
| 49 EXPECT(!queue_peer.HasMessage()); | |
| 50 | |
| 51 // Remove a message from an empty queue. | |
| 52 msg = queue.Dequeue(); | |
| 53 EXPECT(msg == NULL); | |
| 54 EXPECT(!queue_peer.HasMessage()); | |
| 55 | |
| 23 delete msg1; | 56 delete msg1; |
| 57 delete msg2; | |
| 58 } | |
| 24 | 59 |
| 25 msg1 = new PortMessage(port2, 0, strdup(msg_data)); | |
| 26 EXPECT_EQ(true, PortMap::PostMessage(msg1)); | |
| 27 msg = PortMap::ReceiveMessage(10); | |
| 28 EXPECT_EQ(port2, msg->dest_id()); | |
| 29 EXPECT_EQ(msg1, msg); | |
| 30 delete msg1; | |
| 31 | 60 |
| 32 PortMap::ClosePort(port1); | 61 // A thread which receives an expected sequence of messages. |
| 33 EXPECT_EQ(false, PortMap::IsActivePort(port1)); | 62 static MessageQueue* shared_queue = NULL; |
| 34 msg1 = new PortMessage(port1, 0, strdup(msg_data)); | 63 void MessageReceiver_start(uword unused) { |
| 35 EXPECT_EQ(false, PortMap::PostMessage(msg1)); | 64 // We only need an isolate here because the MonitorLocker in the |
| 36 delete msg1; | 65 // MessageQueue expects it. |
| 37 EXPECT(PortMap::ReceiveMessage(10) == NULL); | 66 Dart::CreateIsolate(NULL, NULL); |
| 38 | 67 |
| 39 EXPECT_EQ(true, PortMap::IsActivePort(port2)); | 68 // Create a message queue and share it. |
| 40 msg1 = new PortMessage(port2, 0, strdup(msg_data)); | 69 MessageQueue* queue = new MessageQueue(); |
| 41 EXPECT_EQ(true, PortMap::PostMessage(msg1)); | 70 shared_queue = queue; |
| 42 PortMap::ClosePort(port2); | |
| 43 EXPECT(PortMap::ReceiveMessage(10) == NULL); | |
| 44 | 71 |
| 45 for (int i = 0; i < 32; i++) { | 72 // Receive 5 messages with different payloads. |
| 46 intptr_t port = PortMap::CreatePort(); | 73 for (int i = 0; i < 5; i++) { |
| 47 PortMap::ClosePort(port); | 74 queue->Wait(0); // Waits on internal monitor |
|
siva
2011/10/14 21:01:52
monitor.
turnidge
2011/10/14 23:08:02
Line removed.
| |
| 75 PortMessage* msg = queue->Dequeue(); | |
| 76 EXPECT(msg != NULL); | |
| 77 EXPECT_EQ(i+10, msg->dest_port()); | |
| 78 EXPECT_EQ(i+100, msg->reply_port()); | |
| 79 EXPECT_EQ(i+1000, *(reinterpret_cast<int*>(msg->data()))); | |
| 80 delete msg; | |
| 81 } | |
| 82 shared_queue = NULL; | |
| 83 delete queue; | |
| 84 Dart::ShutdownIsolate(); | |
| 85 } | |
| 86 | |
| 87 | |
| 88 TEST_CASE(MessageQueue_WaitNotify) { | |
| 89 Thread* thread = new Thread(MessageReceiver_start, 0); | |
| 90 EXPECT(thread != NULL); | |
| 91 | |
| 92 // Wait for the shared queue to be created. | |
| 93 Monitor waiter; | |
| 94 while (shared_queue == NULL) { | |
| 95 MonitorLocker ml(&waiter); | |
| 96 ml.Wait(5); | |
|
siva
2011/10/14 21:01:52
Instead of a timed wait why not share the waiter m
turnidge
2011/10/14 23:08:02
Done.
| |
| 97 } | |
| 98 | |
| 99 // Send 5 messages with different payloads. | |
| 100 for (int i = 0; i < 5; i++) { | |
| 101 int* data = reinterpret_cast<int*>(malloc(sizeof(*data))); | |
| 102 *data = i+1000; | |
| 103 PortMessage* msg = new PortMessage(i+10, i+100, data); | |
| 104 shared_queue->Enqueue(msg); // Enqueue notifies internal monitor | |
| 105 MonitorLocker ml(&waiter); | |
| 106 ml.Wait(i+1); | |
|
siva
2011/10/14 21:01:52
Why do you need this wait here?
turnidge
2011/10/14 23:08:02
I wanted to exercise the path where the monitor is
| |
| 48 } | 107 } |
| 49 } | 108 } |
| 50 | 109 |
| 51 | 110 |
| 52 // End-of-test marker. | 111 TEST_CASE(MessageQueue_FlushAll) { |
| 53 static const intptr_t kEOT = 0xFFFF; | 112 MessageQueue queue; |
| 113 MessageQueueTestPeer queue_peer(&queue); | |
| 114 Dart_Port port1 = 1; | |
| 115 Dart_Port port2 = 2; | |
| 54 | 116 |
| 55 void* AllocIntData(intptr_t payload) { | 117 // Add two elements. |
| 56 intptr_t* result = reinterpret_cast<intptr_t*>(malloc(sizeof(payload))); | 118 PortMessage* msg1 = new PortMessage(port1, 0, strdup("msg1")); |
| 57 *result = payload; | 119 queue.Enqueue(msg1); |
| 58 return result; | 120 PortMessage* msg2 = new PortMessage(port2, 0, strdup("msg2")); |
| 121 queue.Enqueue(msg2); | |
| 122 | |
| 123 EXPECT(queue_peer.HasMessage()); | |
| 124 queue.FlushAll(); | |
| 125 EXPECT(!queue_peer.HasMessage()); | |
| 126 | |
| 127 // msg1 and msg2 already delete by FlushAll. | |
| 59 } | 128 } |
| 60 | 129 |
| 61 | 130 |
| 62 intptr_t GetIntData(void* data) { | 131 TEST_CASE(MessageQueue_Flush) { |
| 63 return *reinterpret_cast<intptr_t*>(data); | 132 MessageQueue queue; |
| 133 MessageQueueTestPeer queue_peer(&queue); | |
| 134 Dart_Port port1 = 1; | |
| 135 Dart_Port port2 = 2; | |
| 136 | |
| 137 // Add two elements on different ports. | |
| 138 PortMessage* msg1 = new PortMessage(port1, 0, strdup("msg1")); | |
| 139 queue.Enqueue(msg1); | |
| 140 PortMessage* msg2 = new PortMessage(port2, 0, strdup("msg2")); | |
| 141 queue.Enqueue(msg2); | |
| 142 EXPECT(queue_peer.HasMessage()); | |
| 143 | |
| 144 queue.Flush(port1); | |
|
siva
2011/10/14 21:01:52
Would be good to have two additional tests
- a por
turnidge
2011/10/14 23:08:02
I added two test cases, but I'm not sure that they
| |
| 145 | |
| 146 // One message is left in the queue. | |
| 147 EXPECT(queue_peer.HasMessage()); | |
| 148 PortMessage* msg = queue.Dequeue(); | |
| 149 EXPECT(msg != NULL); | |
| 150 EXPECT_STREQ("msg2", reinterpret_cast<char*>(msg->data())); | |
| 151 | |
| 152 EXPECT(!queue_peer.HasMessage()); | |
| 153 | |
| 154 // msg1 is already deleted by Flush | |
|
siva
2011/10/14 21:01:52
Flush.
turnidge
2011/10/14 23:08:02
Fixed.
| |
| 155 delete msg2; | |
| 64 } | 156 } |
| 65 | 157 |
| 66 | 158 |
| 67 void ThreadedPort_start(uword parameter) { | |
| 68 Dart::CreateIsolate(NULL, NULL); | |
| 69 | |
| 70 intptr_t remote = parameter; | |
| 71 intptr_t local = PortMap::CreatePort(); | |
| 72 | |
| 73 PortMap::PostMessage(new PortMessage(remote, 0, AllocIntData(local))); | |
| 74 | |
| 75 intptr_t count = 0; | |
| 76 while (true) { | |
| 77 PortMessage* msg = PortMap::ReceiveMessage(0); | |
| 78 EXPECT_EQ(local, msg->dest_id()); | |
| 79 EXPECT(msg != NULL); | |
| 80 if (GetIntData(msg->data()) == kEOT) { | |
| 81 break; | |
| 82 } | |
| 83 EXPECT(GetIntData(msg->data()) == count); | |
| 84 delete msg; | |
| 85 PortMap::PostMessage(new PortMessage(remote, 0, AllocIntData(count * 2))); | |
| 86 count++; | |
| 87 } | |
| 88 PortMap::PostMessage(new PortMessage(remote, 0, AllocIntData(kEOT))); | |
| 89 | |
| 90 Dart::ShutdownIsolate(); | |
| 91 } | |
| 92 | |
| 93 | |
| 94 TEST_CASE(ThreadedPort) { | |
| 95 intptr_t local = PortMap::CreatePort(); | |
| 96 | |
| 97 Thread* thr = new Thread(ThreadedPort_start, local); | |
| 98 EXPECT(thr != NULL); | |
| 99 | |
| 100 PortMessage* msg = PortMap::ReceiveMessage(0); | |
| 101 EXPECT_EQ(local, msg->dest_id()); | |
| 102 EXPECT(msg != NULL); | |
| 103 intptr_t remote = GetIntData(msg->data()); // Get the remote port. | |
| 104 delete msg; | |
| 105 | |
| 106 for (intptr_t i = 0; i < 10; i++) { | |
| 107 PortMap::PostMessage(new PortMessage(remote, 0, AllocIntData(i))); | |
| 108 PortMessage* msg = PortMap::ReceiveMessage(0); | |
| 109 EXPECT_EQ(local, msg->dest_id()); | |
| 110 EXPECT(msg != NULL); | |
| 111 EXPECT_EQ(i * 2, GetIntData(msg->data())); | |
| 112 delete msg; | |
| 113 } | |
| 114 | |
| 115 PortMap::PostMessage(new PortMessage(remote, 0, AllocIntData(kEOT))); | |
| 116 msg = PortMap::ReceiveMessage(0); | |
| 117 EXPECT_EQ(local, msg->dest_id()); | |
| 118 EXPECT(msg != NULL); | |
| 119 EXPECT_EQ(kEOT, GetIntData(msg->data())); | |
| 120 delete msg; | |
| 121 | |
| 122 // Give the spawned thread enough time to properly exit. | |
| 123 Monitor* waiter = new Monitor(); | |
| 124 { | |
| 125 MonitorLocker ml(waiter); | |
| 126 ml.Wait(20); | |
| 127 } | |
| 128 delete waiter; | |
| 129 } | |
| 130 | |
| 131 } // namespace dart | 159 } // namespace dart |
| OLD | NEW |