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/message_queue.h" | |
| 7 #include "vm/os.h" | |
| 6 #include "vm/port.h" | 8 #include "vm/port.h" |
| 7 #include "vm/unit_test.h" | 9 #include "vm/unit_test.h" |
| 8 | 10 |
| 9 namespace dart { | 11 namespace dart { |
| 10 | 12 |
| 11 TEST_CASE(Port) { | |
| 12 const char* msg_data = "Hallo Velo!"; | |
| 13 | 13 |
| 14 intptr_t port1 = PortMap::CreatePort(); | 14 // Intercept the post message callback and just store a copy of the message. |
| 15 intptr_t port2 = PortMap::CreatePort(); | 15 static const int kMaxSavedMsg = 80; |
| 16 EXPECT(port1 != port2); | 16 static char saved_msg[kMaxSavedMsg]; |
| 17 static bool MyPostMessageCallback(Dart_Isolate dest_isolate, | |
| 18 Dart_Port dest_port, | |
| 19 Dart_Port reply_port, | |
| 20 Dart_Message dart_message) { | |
| 21 const char* msg = reinterpret_cast<char*>(dart_message); | |
| 22 OS::SNPrint(saved_msg, kMaxSavedMsg, "%s", msg); | |
| 23 bool result = (strcmp(msg, "fail") != 0); | |
| 24 free(dart_message); | |
| 25 return result; | |
| 26 } | |
| 17 | 27 |
| 18 PortMessage* msg1 = new PortMessage(port1, 0, strdup(msg_data)); | |
| 19 EXPECT_EQ(true, PortMap::PostMessage(msg1)); | |
| 20 PortMessage* msg = PortMap::ReceiveMessage(10); | |
| 21 EXPECT_EQ(port1, msg->dest_id()); | |
| 22 EXPECT_EQ(msg1, msg); | |
| 23 delete msg1; | |
| 24 | 28 |
| 25 msg1 = new PortMessage(port2, 0, strdup(msg_data)); | 29 // Intercept the close port callback and remember which port was closed. |
| 26 EXPECT_EQ(true, PortMap::PostMessage(msg1)); | 30 static Dart_Port saved_port = 0; |
| 27 msg = PortMap::ReceiveMessage(10); | 31 static void MyClosePortCallback(Dart_Isolate dart_isolate, |
| 28 EXPECT_EQ(port2, msg->dest_id()); | 32 Dart_Port port) { |
| 29 EXPECT_EQ(msg1, msg); | 33 saved_port = port; |
| 30 delete msg1; | 34 } |
| 35 | |
| 36 | |
| 37 static void InitPortMapTest() { | |
| 38 Dart_SetPostMessageCallback(&MyPostMessageCallback); | |
| 39 Dart_SetClosePortCallback(&MyClosePortCallback); | |
| 40 saved_port = 0; | |
| 41 saved_msg[0] = '\0'; | |
| 42 } | |
| 43 | |
| 44 | |
| 45 TEST_CASE(PortMap_CreateAndCloseOnePort) { | |
| 46 InitPortMapTest(); | |
| 47 intptr_t port = PortMap::CreatePort(); | |
| 48 EXPECT_NE(0, port); | |
| 49 EXPECT(PortMap::IsActivePort(port)); | |
| 50 | |
| 51 PortMap::ClosePort(port); | |
| 52 EXPECT(!PortMap::IsActivePort(port)); | |
| 53 | |
| 54 // Embedder was notified of port closure. | |
| 55 EXPECT_EQ(port, saved_port); | |
| 56 } | |
| 57 | |
| 58 | |
| 59 TEST_CASE(PortMap_CreateAndCloseTwoPorts) { | |
| 60 InitPortMapTest(); | |
| 61 Dart_Port port1 = PortMap::CreatePort(); | |
| 62 Dart_Port port2 = PortMap::CreatePort(); | |
| 63 EXPECT(PortMap::IsActivePort(port1)); | |
| 64 EXPECT(PortMap::IsActivePort(port2)); | |
| 65 | |
| 66 // Uniqueness | |
|
siva
2011/10/14 21:01:52
'.'
turnidge
2011/10/14 23:08:02
Done.
| |
| 67 EXPECT_NE(port1, port2); | |
| 31 | 68 |
| 32 PortMap::ClosePort(port1); | 69 PortMap::ClosePort(port1); |
| 33 EXPECT_EQ(false, PortMap::IsActivePort(port1)); | 70 EXPECT(!PortMap::IsActivePort(port1)); |
| 34 msg1 = new PortMessage(port1, 0, strdup(msg_data)); | 71 EXPECT(PortMap::IsActivePort(port2)); |
| 35 EXPECT_EQ(false, PortMap::PostMessage(msg1)); | 72 EXPECT_EQ(port1, saved_port); |
| 36 delete msg1; | |
| 37 EXPECT(PortMap::ReceiveMessage(10) == NULL); | |
| 38 | 73 |
| 39 EXPECT_EQ(true, PortMap::IsActivePort(port2)); | |
| 40 msg1 = new PortMessage(port2, 0, strdup(msg_data)); | |
| 41 EXPECT_EQ(true, PortMap::PostMessage(msg1)); | |
| 42 PortMap::ClosePort(port2); | 74 PortMap::ClosePort(port2); |
| 43 EXPECT(PortMap::ReceiveMessage(10) == NULL); | 75 EXPECT(!PortMap::IsActivePort(port1)); |
| 76 EXPECT(!PortMap::IsActivePort(port2)); | |
| 77 EXPECT_EQ(port2, saved_port); | |
| 78 } | |
| 44 | 79 |
| 80 | |
| 81 TEST_CASE(PortMap_ClosePorts) { | |
| 82 InitPortMapTest(); | |
| 83 Dart_Port port1 = PortMap::CreatePort(); | |
| 84 Dart_Port port2 = PortMap::CreatePort(); | |
| 85 EXPECT(PortMap::IsActivePort(port1)); | |
| 86 EXPECT(PortMap::IsActivePort(port2)); | |
| 87 | |
| 88 // Close all ports at once | |
|
siva
2011/10/14 21:01:52
once.
turnidge
2011/10/14 23:08:02
Done.
| |
| 89 PortMap::ClosePorts(); | |
| 90 EXPECT(!PortMap::IsActivePort(port1)); | |
| 91 EXPECT(!PortMap::IsActivePort(port2)); | |
| 92 | |
| 93 // Embedder is notified to close all ports as well. | |
| 94 EXPECT_EQ(kCloseAllPorts, saved_port); | |
| 95 } | |
| 96 | |
| 97 | |
| 98 TEST_CASE(PortMap_CreateManyPorts) { | |
| 99 InitPortMapTest(); | |
| 45 for (int i = 0; i < 32; i++) { | 100 for (int i = 0; i < 32; i++) { |
| 46 intptr_t port = PortMap::CreatePort(); | 101 Dart_Port port = PortMap::CreatePort(); |
| 102 EXPECT(PortMap::IsActivePort(port)); | |
| 47 PortMap::ClosePort(port); | 103 PortMap::ClosePort(port); |
| 104 EXPECT(!PortMap::IsActivePort(port)); | |
| 48 } | 105 } |
| 49 } | 106 } |
| 50 | 107 |
| 51 | 108 |
| 109 TEST_CASE(PortMap_PostMessage) { | |
| 110 InitPortMapTest(); | |
| 111 Dart_Port port = PortMap::CreatePort(); | |
| 112 EXPECT(PortMap::PostMessage( | |
| 113 port, 0, reinterpret_cast<Dart_Message>(strdup("msg")))); | |
| 114 | |
| 115 // Check that the post message callback was called. | |
| 116 EXPECT_STREQ("msg", saved_msg); | |
| 117 PortMap::ClosePorts(); | |
| 118 } | |
| 119 | |
| 120 | |
| 121 TEST_CASE(PortMap_PostMessageInvalidPort) { | |
| 122 InitPortMapTest(); | |
| 123 EXPECT(!PortMap::PostMessage( | |
| 124 0, 0, reinterpret_cast<Dart_Message>(strdup("msg")))); | |
| 125 | |
| 126 // Check that the post message callback was not called. | |
| 127 EXPECT_STREQ("", saved_msg); | |
|
siva
2011/10/14 21:01:52
The duped string is leaked in this case.
turnidge
2011/10/14 23:08:02
Ah. Good catch. I have added a call to free() in
| |
| 128 } | |
| 129 | |
| 130 | |
| 131 TEST_CASE(PortMap_PostMessageFailureInCallback) { | |
| 132 InitPortMapTest(); | |
| 133 Dart_Port port = PortMap::CreatePort(); | |
| 134 | |
| 135 // Our callback is rigged to return false when it sees the message | |
| 136 // "fail". This return value is propagated out of PostMessage. | |
| 137 EXPECT(!PortMap::PostMessage( | |
| 138 port, 0, reinterpret_cast<Dart_Message>(strdup("fail")))); | |
| 139 | |
| 140 // Check that the post message callback was called. | |
| 141 EXPECT_STREQ("fail", saved_msg); | |
| 142 PortMap::ClosePorts(); | |
| 143 } | |
| 144 | |
| 145 | |
| 52 // End-of-test marker. | 146 // End-of-test marker. |
| 53 static const intptr_t kEOT = 0xFFFF; | 147 static const intptr_t kEOT = 0xFFFF; |
| 54 | 148 |
| 55 void* AllocIntData(intptr_t payload) { | 149 void* AllocIntData(intptr_t payload) { |
| 56 intptr_t* result = reinterpret_cast<intptr_t*>(malloc(sizeof(payload))); | 150 intptr_t* result = reinterpret_cast<intptr_t*>(malloc(sizeof(payload))); |
| 57 *result = payload; | 151 *result = payload; |
| 58 return result; | 152 return result; |
| 59 } | 153 } |
| 60 | 154 |
| 61 | 155 |
| 62 intptr_t GetIntData(void* data) { | 156 intptr_t GetIntData(void* data) { |
| 63 return *reinterpret_cast<intptr_t*>(data); | 157 return *reinterpret_cast<intptr_t*>(data); |
| 64 } | 158 } |
| 65 | 159 |
| 66 | 160 |
| 161 static PortMessage* NextMessage() { | |
| 162 // Since only the isolate owning the port can close the port and remove it | |
| 163 // from the port map and flush its messages, we can safely assume that the | |
| 164 // all messages in the message queue are for active ports. | |
|
siva
2011/10/14 21:01:52
"that the all messages ..." => "that all messages
turnidge
2011/10/14 23:08:02
I have just deleted this comment.
| |
| 165 Isolate* isolate = Isolate::Current(); | |
| 166 { | |
| 167 PortMessage* result = isolate->message_queue()->Dequeue(); | |
| 168 if (result == NULL) { | |
| 169 isolate->message_queue()->Wait(0); | |
| 170 result = isolate->message_queue()->Dequeue(); | |
| 171 } | |
| 172 return result; | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 | |
| 67 void ThreadedPort_start(uword parameter) { | 177 void ThreadedPort_start(uword parameter) { |
| 68 Dart::CreateIsolate(NULL, NULL); | 178 Dart::CreateIsolate(NULL, NULL); |
| 69 | 179 |
| 70 intptr_t remote = parameter; | 180 intptr_t remote = parameter; |
| 71 intptr_t local = PortMap::CreatePort(); | 181 intptr_t local = PortMap::CreatePort(); |
| 72 | 182 |
| 73 PortMap::PostMessage(new PortMessage(remote, 0, AllocIntData(local))); | 183 PortMap::PostMessage(remote, 0, AllocIntData(local)); |
| 74 | 184 |
| 75 intptr_t count = 0; | 185 intptr_t count = 0; |
| 76 while (true) { | 186 while (true) { |
| 77 PortMessage* msg = PortMap::ReceiveMessage(0); | 187 PortMessage* msg = NextMessage(); |
| 78 EXPECT_EQ(local, msg->dest_id()); | 188 EXPECT_EQ(local, msg->dest_port()); |
| 79 EXPECT(msg != NULL); | 189 EXPECT(msg != NULL); |
| 80 if (GetIntData(msg->data()) == kEOT) { | 190 if (GetIntData(msg->data()) == kEOT) { |
| 81 break; | 191 break; |
| 82 } | 192 } |
| 83 EXPECT(GetIntData(msg->data()) == count); | 193 EXPECT(GetIntData(msg->data()) == count); |
| 84 delete msg; | 194 delete msg; |
| 85 PortMap::PostMessage(new PortMessage(remote, 0, AllocIntData(count * 2))); | 195 PortMap::PostMessage(remote, 0, AllocIntData(count * 2)); |
| 86 count++; | 196 count++; |
| 87 } | 197 } |
| 88 PortMap::PostMessage(new PortMessage(remote, 0, AllocIntData(kEOT))); | 198 PortMap::PostMessage(remote, 0, AllocIntData(kEOT)); |
| 89 | 199 |
| 90 Dart::ShutdownIsolate(); | 200 Dart::ShutdownIsolate(); |
| 91 } | 201 } |
| 92 | 202 |
| 93 | 203 |
| 94 TEST_CASE(ThreadedPort) { | 204 TEST_CASE(ThreadedPort) { |
| 95 intptr_t local = PortMap::CreatePort(); | 205 intptr_t local = PortMap::CreatePort(); |
| 96 | 206 |
| 97 Thread* thr = new Thread(ThreadedPort_start, local); | 207 Thread* thr = new Thread(ThreadedPort_start, local); |
| 98 EXPECT(thr != NULL); | 208 EXPECT(thr != NULL); |
| 99 | 209 |
| 100 PortMessage* msg = PortMap::ReceiveMessage(0); | 210 PortMessage* msg = NextMessage(); |
| 101 EXPECT_EQ(local, msg->dest_id()); | 211 EXPECT_EQ(local, msg->dest_port()); |
| 102 EXPECT(msg != NULL); | 212 EXPECT(msg != NULL); |
| 103 intptr_t remote = GetIntData(msg->data()); // Get the remote port. | 213 intptr_t remote = GetIntData(msg->data()); // Get the remote port. |
| 104 delete msg; | 214 delete msg; |
| 105 | 215 |
| 106 for (intptr_t i = 0; i < 10; i++) { | 216 for (intptr_t i = 0; i < 10; i++) { |
| 107 PortMap::PostMessage(new PortMessage(remote, 0, AllocIntData(i))); | 217 PortMap::PostMessage(remote, 0, AllocIntData(i)); |
| 108 PortMessage* msg = PortMap::ReceiveMessage(0); | 218 PortMessage* msg = NextMessage(); |
| 109 EXPECT_EQ(local, msg->dest_id()); | 219 EXPECT_EQ(local, msg->dest_port()); |
| 110 EXPECT(msg != NULL); | 220 EXPECT(msg != NULL); |
| 111 EXPECT_EQ(i * 2, GetIntData(msg->data())); | 221 EXPECT_EQ(i * 2, GetIntData(msg->data())); |
| 112 delete msg; | 222 delete msg; |
| 113 } | 223 } |
| 114 | 224 |
| 115 PortMap::PostMessage(new PortMessage(remote, 0, AllocIntData(kEOT))); | 225 PortMap::PostMessage(remote, 0, AllocIntData(kEOT)); |
| 116 msg = PortMap::ReceiveMessage(0); | 226 msg = NextMessage(); |
| 117 EXPECT_EQ(local, msg->dest_id()); | 227 EXPECT_EQ(local, msg->dest_port()); |
| 118 EXPECT(msg != NULL); | 228 EXPECT(msg != NULL); |
| 119 EXPECT_EQ(kEOT, GetIntData(msg->data())); | 229 EXPECT_EQ(kEOT, GetIntData(msg->data())); |
| 120 delete msg; | 230 delete msg; |
| 121 | 231 |
| 122 // Give the spawned thread enough time to properly exit. | 232 // Give the spawned thread enough time to properly exit. |
| 123 Monitor* waiter = new Monitor(); | 233 Monitor* waiter = new Monitor(); |
| 124 { | 234 { |
| 125 MonitorLocker ml(waiter); | 235 MonitorLocker ml(waiter); |
| 126 ml.Wait(20); | 236 ml.Wait(20); |
| 127 } | 237 } |
| 128 delete waiter; | 238 delete waiter; |
| 129 } | 239 } |
| 130 | 240 |
| 131 } // namespace dart | 241 } // namespace dart |
| OLD | NEW |