1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
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.
4
5#include "vm/port.h"
6
7#include <utility>
8
9#include "platform/utils.h"
10#include "vm/dart_api_impl.h"
11#include "vm/dart_entry.h"
12#include "vm/isolate.h"
13#include "vm/lockers.h"
14#include "vm/message_handler.h"
15#include "vm/os_thread.h"
16
17namespace dart {
18
19Mutex* PortMap::mutex_ = NULL;
20PortSet<PortMap::Entry>* PortMap::ports_ = NULL;
21MessageHandler* PortMap::deleted_entry_ = reinterpret_cast<MessageHandler*>(1);
22Random* PortMap::prng_ = NULL;
23
24const char* PortMap::PortStateString(PortState kind) {
25 switch (kind) {
26 case kNewPort:
27 return "new";
28 case kLivePort:
29 return "live";
30 case kControlPort:
31 return "control";
32 default:
33 UNREACHABLE();
34 return "UNKNOWN";
35 }
36}
37
38Dart_Port PortMap::AllocatePort() {
39 Dart_Port result;
40
41 // Keep getting new values while we have an illegal port number or the port
42 // number is already in use.
43 do {
44 // Ensure port ids are representable in JavaScript for the benefit of
45 // vm-service clients such as Observatory.
46 const Dart_Port kMask1 = 0xFFFFFFFFFFFFF;
47 // Ensure port ids are never valid object pointers so that reinterpreting
48 // an object pointer as a port id never produces a used port id.
49 const Dart_Port kMask2 = 0x3;
50 result = (prng_->NextUInt64() & kMask1) | kMask2;
51
52 // The two special marker ports are used for the hashset implementation and
53 // cannot be used as actual ports.
54 if (result == PortSet<Entry>::kFreePort ||
55 result == PortSet<Entry>::kDeletedPort) {
56 continue;
57 }
58
59 ASSERT(!static_cast<ObjectPtr>(static_cast<uword>(result))->IsWellFormed());
60 } while (ports_->Contains(result));
61
62 ASSERT(result != 0);
63 ASSERT(!ports_->Contains(result));
64 return result;
65}
66
67void PortMap::SetPortState(Dart_Port port, PortState state) {
68 MutexLocker ml(mutex_);
69
70 auto it = ports_->TryLookup(port);
71 ASSERT(it != ports_->end());
72
73 Entry& entry = *it;
74 PortState old_state = entry.state;
75 ASSERT(old_state == kNewPort);
76 entry.state = state;
77 if (state == kLivePort) {
78 entry.handler->increment_live_ports();
79 }
80 if (FLAG_trace_isolates) {
81 OS::PrintErr(
82 "[^] Port (%s) -> (%s): \n"
83 "\thandler: %s\n"
84 "\tport: %" Pd64 "\n",
85 PortStateString(old_state), PortStateString(state),
86 entry.handler->name(), port);
87 }
88}
89
90Dart_Port PortMap::CreatePort(MessageHandler* handler) {
91 ASSERT(handler != NULL);
92 MutexLocker ml(mutex_);
93#if defined(DEBUG)
94 handler->CheckAccess();
95#endif
96
97 const Dart_Port port = AllocatePort();
98
99 // The MessageHandler::ports_ is only accessed by [PortMap], it is guarded
100 // by the [PortMap::mutex_] we already hold.
101 MessageHandler::PortSetEntry isolate_entry;
102 isolate_entry.port = port;
103 handler->ports_.Insert(isolate_entry);
104
105 Entry entry;
106 entry.port = port;
107 entry.handler = handler;
108 entry.state = kNewPort;
109 ports_->Insert(entry);
110
111 if (FLAG_trace_isolates) {
112 OS::PrintErr(
113 "[+] Opening port: \n"
114 "\thandler: %s\n"
115 "\tport: %" Pd64 "\n",
116 handler->name(), entry.port);
117 }
118
119 return entry.port;
120}
121
122bool PortMap::ClosePort(Dart_Port port) {
123 MessageHandler* handler = NULL;
124 {
125 MutexLocker ml(mutex_);
126 auto it = ports_->TryLookup(port);
127 if (it == ports_->end()) {
128 return false;
129 }
130 Entry entry = *it;
131 handler = entry.handler;
132 ASSERT(handler != nullptr);
133
134#if defined(DEBUG)
135 handler->CheckAccess();
136#endif
137
138 if (entry.state == kLivePort) {
139 handler->decrement_live_ports();
140 }
141
142 // Delete the port entry before releasing the lock to avoid holding the lock
143 // while flushing the messages below.
144 it.Delete();
145 ports_->Rebalance();
146
147 // The MessageHandler::ports_ is only accessed by [PortMap], it is guarded
148 // by the [PortMap::mutex_] we already hold.
149 auto isolate_it = handler->ports_.TryLookup(port);
150 ASSERT(isolate_it != handler->ports_.end());
151 isolate_it.Delete();
152 handler->ports_.Rebalance();
153 }
154 handler->ClosePort(port);
155 if (!handler->HasLivePorts() && handler->OwnedByPortMap()) {
156 // Delete handler as soon as it isn't busy with a task.
157 handler->RequestDeletion();
158 }
159 return true;
160}
161
162void PortMap::ClosePorts(MessageHandler* handler) {
163 {
164 MutexLocker ml(mutex_);
165 // The MessageHandler::ports_ is only accessed by [PortMap], it is guarded
166 // by the [PortMap::mutex_] we already hold.
167 for (auto isolate_it = handler->ports_.begin();
168 isolate_it != handler->ports_.end(); ++isolate_it) {
169 auto it = ports_->TryLookup((*isolate_it).port);
170 ASSERT(it != ports_->end());
171 Entry entry = *it;
172 ASSERT(entry.port == (*isolate_it).port);
173 ASSERT(entry.handler == handler);
174 if (entry.state == kLivePort) {
175 handler->decrement_live_ports();
176 }
177 it.Delete();
178 isolate_it.Delete();
179 }
180 ASSERT(handler->ports_.IsEmpty());
181 ports_->Rebalance();
182 }
183 handler->CloseAllPorts();
184}
185
186bool PortMap::PostMessage(std::unique_ptr<Message> message,
187 bool before_events) {
188 MutexLocker ml(mutex_);
189 auto it = ports_->TryLookup(message->dest_port());
190 if (it == ports_->end()) {
191 // Ownership of external data remains with the poster.
192 message->DropFinalizers();
193 return false;
194 }
195 MessageHandler* handler = (*it).handler;
196 ASSERT(handler != nullptr);
197 handler->PostMessage(std::move(message), before_events);
198 return true;
199}
200
201bool PortMap::IsLocalPort(Dart_Port id) {
202 MutexLocker ml(mutex_);
203 auto it = ports_->TryLookup(id);
204 if (it == ports_->end()) {
205 // Port does not exist.
206 return false;
207 }
208
209 MessageHandler* handler = (*it).handler;
210 ASSERT(handler != nullptr);
211 return handler->IsCurrentIsolate();
212}
213
214Isolate* PortMap::GetIsolate(Dart_Port id) {
215 MutexLocker ml(mutex_);
216 auto it = ports_->TryLookup(id);
217 if (it == ports_->end()) {
218 // Port does not exist.
219 return nullptr;
220 }
221
222 MessageHandler* handler = (*it).handler;
223 return handler->isolate();
224}
225
226bool PortMap::IsReceiverInThisIsolateGroup(Dart_Port receiver,
227 IsolateGroup* group) {
228 MutexLocker ml(mutex_);
229 auto it = ports_->TryLookup(receiver);
230 if (it == ports_->end()) return false;
231 return (*it).handler->isolate()->group() == group;
232}
233
234void PortMap::Init() {
235 // TODO(bkonyi): don't keep ports_ after Dart_Cleanup.
236 if (mutex_ == NULL) {
237 mutex_ = new Mutex();
238 }
239 ASSERT(mutex_ != NULL);
240 if (prng_ == nullptr) {
241 prng_ = new Random();
242 }
243 if (ports_ == nullptr) {
244 ports_ = new PortSet<Entry>();
245 }
246}
247
248void PortMap::Cleanup() {
249 ASSERT(ports_ != nullptr);
250 ASSERT(prng_ != NULL);
251 for (auto it = ports_->begin(); it != ports_->end(); ++it) {
252 const auto& entry = *it;
253 ASSERT(entry.handler != nullptr);
254 if (entry.state == kLivePort) {
255 entry.handler->decrement_live_ports();
256 }
257 delete entry.handler;
258 it.Delete();
259 }
260 ports_->Rebalance();
261
262 delete prng_;
263 prng_ = NULL;
264 // TODO(bkonyi): find out why deleting map_ sometimes causes crashes.
265 // delete ports_;
266 // ports_ = nullptr;
267}
268
269void PortMap::PrintPortsForMessageHandler(MessageHandler* handler,
270 JSONStream* stream) {
271#ifndef PRODUCT
272 JSONObject jsobj(stream);
273 jsobj.AddProperty("type", "_Ports");
274 Object& msg_handler = Object::Handle();
275 {
276 JSONArray ports(&jsobj, "ports");
277 SafepointMutexLocker ml(mutex_);
278 for (auto& entry : *ports_) {
279 if (entry.handler == handler) {
280 if (entry.state == kLivePort) {
281 JSONObject port(&ports);
282 port.AddProperty("type", "_Port");
283 port.AddPropertyF("name", "Isolate Port (%" Pd64 ")", entry.port);
284 msg_handler = DartLibraryCalls::LookupHandler(entry.port);
285 port.AddProperty("handler", msg_handler);
286 }
287 }
288 }
289 }
290#endif
291}
292
293void PortMap::DebugDumpForMessageHandler(MessageHandler* handler) {
294 SafepointMutexLocker ml(mutex_);
295 Object& msg_handler = Object::Handle();
296 for (auto& entry : *ports_) {
297 if (entry.handler == handler) {
298 if (entry.state == kLivePort) {
299 OS::PrintErr("Live Port = %" Pd64 "\n", entry.port);
300 msg_handler = DartLibraryCalls::LookupHandler(entry.port);
301 OS::PrintErr("Handler = %s\n", msg_handler.ToCString());
302 }
303 }
304 }
305}
306
307} // namespace dart
308