| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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/port.h" | 5 #include "vm/port.h" |
| 6 | 6 |
| 7 #include "platform/utils.h" | 7 #include "platform/utils.h" |
| 8 #include "vm/dart_api_impl.h" | 8 #include "vm/dart_api_impl.h" |
| 9 #include "vm/isolate.h" | 9 #include "vm/isolate.h" |
| 10 #include "vm/message_queue.h" | 10 #include "vm/message.h" |
| 11 #include "vm/thread.h" | 11 #include "vm/thread.h" |
| 12 | 12 |
| 13 namespace dart { | 13 namespace dart { |
| 14 | 14 |
| 15 DECLARE_FLAG(bool, trace_isolates); | 15 DECLARE_FLAG(bool, trace_isolates); |
| 16 | 16 |
| 17 Mutex* PortMap::mutex_ = NULL; | 17 Mutex* PortMap::mutex_ = NULL; |
| 18 | |
| 19 PortMap::Entry* PortMap::map_ = NULL; | 18 PortMap::Entry* PortMap::map_ = NULL; |
| 20 Isolate* PortMap::deleted_entry_ = reinterpret_cast<Isolate*>(1); | 19 MessageHandler* PortMap::deleted_entry_ = reinterpret_cast<MessageHandler*>(1); |
| 21 intptr_t PortMap::capacity_ = 0; | 20 intptr_t PortMap::capacity_ = 0; |
| 22 intptr_t PortMap::used_ = 0; | 21 intptr_t PortMap::used_ = 0; |
| 23 intptr_t PortMap::deleted_ = 0; | 22 intptr_t PortMap::deleted_ = 0; |
| 24 | |
| 25 Dart_Port PortMap::next_port_ = 7111; | 23 Dart_Port PortMap::next_port_ = 7111; |
| 26 | 24 |
| 27 | 25 |
| 28 intptr_t PortMap::FindPort(Dart_Port port) { | 26 intptr_t PortMap::FindPort(Dart_Port port) { |
| 29 intptr_t index = port % capacity_; | 27 intptr_t index = port % capacity_; |
| 30 intptr_t start_index = index; | 28 intptr_t start_index = index; |
| 31 Entry entry = map_[index]; | 29 Entry entry = map_[index]; |
| 32 while (entry.isolate != NULL) { | 30 while (entry.handler != NULL) { |
| 33 if (entry.port == port) { | 31 if (entry.port == port) { |
| 34 return index; | 32 return index; |
| 35 } | 33 } |
| 36 index = (index + 1) % capacity_; | 34 index = (index + 1) % capacity_; |
| 37 // Prevent endless loops. | 35 // Prevent endless loops. |
| 38 ASSERT(index != start_index); | 36 ASSERT(index != start_index); |
| 39 entry = map_[index]; | 37 entry = map_[index]; |
| 40 } | 38 } |
| 41 return -1; | 39 return -1; |
| 42 } | 40 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 76 ASSERT(result != 0); | 74 ASSERT(result != 0); |
| 77 return result; | 75 return result; |
| 78 } | 76 } |
| 79 | 77 |
| 80 | 78 |
| 81 void PortMap::SetLive(Dart_Port port) { | 79 void PortMap::SetLive(Dart_Port port) { |
| 82 MutexLocker ml(mutex_); | 80 MutexLocker ml(mutex_); |
| 83 intptr_t index = FindPort(port); | 81 intptr_t index = FindPort(port); |
| 84 ASSERT(index >= 0); | 82 ASSERT(index >= 0); |
| 85 map_[index].live = true; | 83 map_[index].live = true; |
| 86 map_[index].isolate->increment_live_ports(); | 84 map_[index].handler->increment_live_ports(); |
| 87 } | 85 } |
| 88 | 86 |
| 89 | 87 |
| 90 void PortMap::MaintainInvariants() { | 88 void PortMap::MaintainInvariants() { |
| 91 intptr_t empty = capacity_ - used_ - deleted_; | 89 intptr_t empty = capacity_ - used_ - deleted_; |
| 92 if (used_ > ((capacity_ / 4) * 3)) { | 90 if (used_ > ((capacity_ / 4) * 3)) { |
| 93 // Grow the port map. | 91 // Grow the port map. |
| 94 Rehash(capacity_ * 2); | 92 Rehash(capacity_ * 2); |
| 95 } else if (empty < deleted_) { | 93 } else if (empty < deleted_) { |
| 96 // Rehash without growing the table to flush the deleted slots out of the | 94 // Rehash without growing the table to flush the deleted slots out of the |
| 97 // map. | 95 // map. |
| 98 Rehash(capacity_); | 96 Rehash(capacity_); |
| 99 } | 97 } |
| 100 } | 98 } |
| 101 | 99 |
| 102 | 100 |
| 103 Dart_Port PortMap::CreatePort() { | 101 Dart_Port PortMap::CreatePort(MessageHandler* handler) { |
| 104 Isolate* isolate = Isolate::Current(); | 102 ASSERT(handler != NULL); |
| 105 MutexLocker ml(mutex_); | 103 MutexLocker ml(mutex_); |
| 104 #if defined(DEBUG) |
| 105 handler->CheckAccess(); |
| 106 #endif |
| 106 | 107 |
| 107 Entry entry; | 108 Entry entry; |
| 108 entry.port = AllocatePort(); | 109 entry.port = AllocatePort(); |
| 109 entry.isolate = isolate; | 110 entry.handler = handler; |
| 110 entry.live = false; | 111 entry.live = false; |
| 111 | 112 |
| 112 // Search for the first unused slot. Make use of the knowledge that here is | 113 // Search for the first unused slot. Make use of the knowledge that here is |
| 113 // currently no port with this id in the port map. | 114 // currently no port with this id in the port map. |
| 114 ASSERT(FindPort(entry.port) < 0); | 115 ASSERT(FindPort(entry.port) < 0); |
| 115 intptr_t index = entry.port % capacity_; | 116 intptr_t index = entry.port % capacity_; |
| 116 Entry cur = map_[index]; | 117 Entry cur = map_[index]; |
| 117 // Stop the search at the first found unused (free or deleted) slot. | 118 // Stop the search at the first found unused (free or deleted) slot. |
| 118 while (cur.port != 0) { | 119 while (cur.port != 0) { |
| 119 index = (index + 1) % capacity_; | 120 index = (index + 1) % capacity_; |
| 120 cur = map_[index]; | 121 cur = map_[index]; |
| 121 } | 122 } |
| 122 | 123 |
| 123 // Insert the newly created port at the index. | 124 // Insert the newly created port at the index. |
| 124 ASSERT(index >= 0); | 125 ASSERT(index >= 0); |
| 125 ASSERT(index < capacity_); | 126 ASSERT(index < capacity_); |
| 126 ASSERT(map_[index].port == 0); | 127 ASSERT(map_[index].port == 0); |
| 127 ASSERT((map_[index].isolate == NULL) || | 128 ASSERT((map_[index].handler == NULL) || |
| 128 (map_[index].isolate == deleted_entry_)); | 129 (map_[index].handler == deleted_entry_)); |
| 129 if (map_[index].isolate == deleted_entry_) { | 130 if (map_[index].handler == deleted_entry_) { |
| 130 // Consuming a deleted entry. | 131 // Consuming a deleted entry. |
| 131 deleted_--; | 132 deleted_--; |
| 132 } | 133 } |
| 133 map_[index] = entry; | 134 map_[index] = entry; |
| 134 isolate->increment_num_ports(); | |
| 135 | 135 |
| 136 // Increment number of used slots and grow if necessary. | 136 // Increment number of used slots and grow if necessary. |
| 137 used_++; | 137 used_++; |
| 138 MaintainInvariants(); | 138 MaintainInvariants(); |
| 139 | 139 |
| 140 return entry.port; | 140 return entry.port; |
| 141 } | 141 } |
| 142 | 142 |
| 143 | 143 |
| 144 void PortMap::ClosePort(Dart_Port port) { | 144 bool PortMap::ClosePort(Dart_Port port) { |
| 145 Isolate* isolate = Isolate::Current(); | 145 MessageHandler* handler = NULL; |
| 146 { | 146 { |
| 147 MutexLocker ml(mutex_); | 147 MutexLocker ml(mutex_); |
| 148 intptr_t index = FindPort(port); | 148 intptr_t index = FindPort(port); |
| 149 if (index < 0) { | 149 if (index < 0) { |
| 150 return; | 150 return false; |
| 151 } | 151 } |
| 152 ASSERT(index < capacity_); | 152 ASSERT(index < capacity_); |
| 153 ASSERT(map_[index].port != 0); | 153 ASSERT(map_[index].port != 0); |
| 154 ASSERT(map_[index].isolate == isolate); | 154 ASSERT(map_[index].handler != deleted_entry_); |
| 155 ASSERT(map_[index].handler != NULL); |
| 156 |
| 157 handler = map_[index].handler; |
| 158 #if defined(DEBUG) |
| 159 handler->CheckAccess(); |
| 160 #endif |
| 155 // Before releasing the lock mark the slot in the map as deleted. This makes | 161 // Before releasing the lock mark the slot in the map as deleted. This makes |
| 156 // it possible to release the port map lock before flushing all of its | 162 // it possible to release the port map lock before flushing all of its |
| 157 // pending messages below. | 163 // pending messages below. |
| 158 map_[index].port = 0; | 164 map_[index].port = 0; |
| 159 map_[index].isolate = deleted_entry_; | 165 map_[index].handler = deleted_entry_; |
| 160 isolate->decrement_num_ports(); | |
| 161 if (map_[index].live) { | 166 if (map_[index].live) { |
| 162 isolate->decrement_live_ports(); | 167 handler->decrement_live_ports(); |
| 163 } | 168 } |
| 164 | 169 |
| 165 used_--; | 170 used_--; |
| 166 deleted_++; | 171 deleted_++; |
| 167 MaintainInvariants(); | 172 MaintainInvariants(); |
| 168 } | 173 } |
| 169 isolate->ClosePort(port); | 174 handler->ClosePort(port); |
| 175 if (!handler->HasLivePorts() && handler->OwnedByPortMap()) { |
| 176 delete handler; |
| 177 } |
| 178 return true; |
| 170 } | 179 } |
| 171 | 180 |
| 172 | 181 |
| 173 void PortMap::ClosePorts() { | 182 void PortMap::ClosePorts(MessageHandler* handler) { |
| 174 Isolate* isolate = Isolate::Current(); | |
| 175 { | 183 { |
| 176 MutexLocker ml(mutex_); | 184 MutexLocker ml(mutex_); |
| 177 for (intptr_t i = 0; i < capacity_; i++) { | 185 for (intptr_t i = 0; i < capacity_; i++) { |
| 178 if (map_[i].isolate == isolate) { | 186 if (map_[i].handler == handler) { |
| 179 // Mark the slot as deleted. | 187 // Mark the slot as deleted. |
| 180 map_[i].port = 0; | 188 map_[i].port = 0; |
| 181 map_[i].isolate = deleted_entry_; | 189 map_[i].handler = deleted_entry_; |
| 182 isolate->decrement_num_ports(); | 190 if (map_[i].live) { |
| 183 | 191 handler->decrement_live_ports(); |
| 192 } |
| 184 used_--; | 193 used_--; |
| 185 deleted_++; | 194 deleted_++; |
| 186 } | 195 } |
| 187 } | 196 } |
| 188 MaintainInvariants(); | 197 MaintainInvariants(); |
| 189 } | 198 } |
| 190 isolate->CloseAllPorts(); | 199 handler->CloseAllPorts(); |
| 191 } | 200 } |
| 192 | 201 |
| 193 | 202 |
| 194 bool PortMap::PostMessage(Message* message) { | 203 bool PortMap::PostMessage(Message* message) { |
| 195 // TODO(turnidge): Add a scoped locker for mutexes which is not a | 204 MutexLocker ml(mutex_); |
| 196 // stack resource. This would probably be useful in the platform | |
| 197 // headers. | |
| 198 mutex_->Lock(); | |
| 199 intptr_t index = FindPort(message->dest_port()); | 205 intptr_t index = FindPort(message->dest_port()); |
| 200 if (index < 0) { | 206 if (index < 0) { |
| 201 free(message); | 207 free(message); |
| 202 mutex_->Unlock(); | |
| 203 return false; | 208 return false; |
| 204 } | 209 } |
| 205 ASSERT(index >= 0); | 210 ASSERT(index >= 0); |
| 206 ASSERT(index < capacity_); | 211 ASSERT(index < capacity_); |
| 207 Isolate* isolate = map_[index].isolate; | 212 MessageHandler* handler = map_[index].handler; |
| 208 ASSERT(map_[index].port != 0); | 213 ASSERT(map_[index].port != 0); |
| 209 ASSERT((isolate != NULL) && (isolate != deleted_entry_)); | 214 ASSERT((handler != NULL) && (handler != deleted_entry_)); |
| 210 isolate->PostMessage(message); | 215 handler->PostMessage(message); |
| 211 mutex_->Unlock(); | |
| 212 return true; | 216 return true; |
| 213 } | 217 } |
| 214 | 218 |
| 215 | 219 |
| 216 void PortMap::InitOnce() { | 220 void PortMap::InitOnce() { |
| 217 mutex_ = new Mutex(); | 221 mutex_ = new Mutex(); |
| 218 | 222 |
| 219 static const intptr_t kInitialCapacity = 8; | 223 static const intptr_t kInitialCapacity = 8; |
| 220 // TODO(iposva): Verify whether we want to keep exponentially growing. | 224 // TODO(iposva): Verify whether we want to keep exponentially growing. |
| 221 ASSERT(Utils::IsPowerOfTwo(kInitialCapacity)); | 225 ASSERT(Utils::IsPowerOfTwo(kInitialCapacity)); |
| 222 map_ = new Entry[kInitialCapacity]; | 226 map_ = new Entry[kInitialCapacity]; |
| 223 memset(map_, 0, kInitialCapacity * sizeof(Entry)); | 227 memset(map_, 0, kInitialCapacity * sizeof(Entry)); |
| 224 capacity_ = kInitialCapacity; | 228 capacity_ = kInitialCapacity; |
| 225 used_ = 0; | 229 used_ = 0; |
| 226 deleted_ = 0; | 230 deleted_ = 0; |
| 227 } | 231 } |
| 228 | 232 |
| 229 | |
| 230 } // namespace dart | 233 } // namespace dart |
| OLD | NEW |