| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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/thread_registry.h" | 5 #include "vm/thread_registry.h" |
| 6 | 6 |
| 7 #include "vm/isolate.h" | 7 #include "vm/isolate.h" |
| 8 #include "vm/lockers.h" | 8 #include "vm/lockers.h" |
| 9 | 9 |
| 10 namespace dart { | 10 namespace dart { |
| 11 | 11 |
| 12 ThreadRegistry::~ThreadRegistry() { | 12 ThreadRegistry::~ThreadRegistry() { |
| 13 // Go over the free thread list and delete the thread objects. | 13 // Go over the free thread list and delete the thread objects. |
| 14 { | 14 { |
| 15 MonitorLocker ml(monitor_); | 15 MonitorLocker ml(threads_lock()); |
| 16 // At this point the active list should be empty. | 16 // At this point the active list should be empty. |
| 17 ASSERT(active_list_ == NULL); | 17 ASSERT(active_list_ == NULL); |
| 18 // We have cached the mutator thread, delete it. | 18 // We have cached the mutator thread, delete it. |
| 19 delete mutator_thread_; | 19 delete mutator_thread_; |
| 20 mutator_thread_ = NULL; | 20 mutator_thread_ = NULL; |
| 21 // Now delete all the threads in the free list. | 21 // Now delete all the threads in the free list. |
| 22 while (free_list_ != NULL) { | 22 while (free_list_ != NULL) { |
| 23 Thread* thread = free_list_; | 23 Thread* thread = free_list_; |
| 24 free_list_ = thread->next_; | 24 free_list_ = thread->next_; |
| 25 delete thread; | 25 delete thread; |
| 26 } | 26 } |
| 27 } | 27 } |
| 28 | 28 |
| 29 // Delete monitor. | 29 // Delete monitor. |
| 30 delete monitor_; | 30 delete threads_lock_; |
| 31 } | 31 } |
| 32 | 32 |
| 33 | 33 |
| 34 void ThreadRegistry::SafepointThreads() { | 34 // Gets a free Thread structure, we special case the mutator thread |
| 35 MonitorLocker ml(monitor_); | 35 // by reusing the cached structure, see comment in 'thread_registry.h'. |
| 36 // First wait for any older rounds that are still in progress. | 36 Thread* ThreadRegistry::GetFreeThreadLocked(Isolate* isolate, bool is_mutator) { |
| 37 while (in_rendezvous_) { | 37 ASSERT(threads_lock()->IsOwnedByCurrentThread()); |
| 38 // Assert we are not the organizer trying to nest calls to SafepointThreads. | 38 Thread* thread; |
| 39 ASSERT(remaining_ > 0); | 39 if (is_mutator) { |
| 40 CheckSafepointLocked(); | 40 if (mutator_thread_ == NULL) { |
| 41 mutator_thread_ = GetFromFreelistLocked(isolate); |
| 42 } |
| 43 thread = mutator_thread_; |
| 44 } else { |
| 45 thread = GetFromFreelistLocked(isolate); |
| 46 ASSERT(thread->api_top_scope() == NULL); |
| 41 } | 47 } |
| 42 // Start a new round. | 48 // Now add this Thread to the active list for the isolate. |
| 43 in_rendezvous_ = true; | 49 AddToActiveListLocked(thread); |
| 44 ++round_; // Overflows after 240+ years @ 10^9 safepoints per second. | |
| 45 remaining_ = CountScheduledLocked(); | |
| 46 Isolate* isolate = Isolate::Current(); | |
| 47 // We only expect this method to be called from within the isolate itself. | |
| 48 ASSERT(isolate->thread_registry() == this); | |
| 49 --remaining_; // Exclude this thread from the count. | |
| 50 // Ensure the main mutator will reach a safepoint (could be running Dart). | |
| 51 if (!Thread::Current()->IsMutatorThread()) { | |
| 52 isolate->ScheduleInterrupts(Isolate::kVMInterrupt); | |
| 53 } | |
| 54 while (remaining_ > 0) { | |
| 55 ml.Wait(Monitor::kNoTimeout); | |
| 56 } | |
| 57 } | |
| 58 | |
| 59 | |
| 60 void ThreadRegistry::ResumeAllThreads() { | |
| 61 MonitorLocker ml(monitor_); | |
| 62 ASSERT(in_rendezvous_); | |
| 63 in_rendezvous_ = false; | |
| 64 ml.NotifyAll(); | |
| 65 } | |
| 66 | |
| 67 | |
| 68 Thread* ThreadRegistry::Schedule(Isolate* isolate, | |
| 69 bool is_mutator, | |
| 70 bool bypass_safepoint) { | |
| 71 MonitorLocker ml(monitor_); | |
| 72 // Wait for any rendezvous in progress. | |
| 73 while (!bypass_safepoint && in_rendezvous_) { | |
| 74 ml.Wait(Monitor::kNoTimeout); | |
| 75 } | |
| 76 Thread* thread = NULL; | |
| 77 OSThread* os_thread = OSThread::Current(); | |
| 78 if (os_thread != NULL) { | |
| 79 ASSERT(isolate->heap() != NULL); | |
| 80 // First get a Thread structure. (we special case the mutator thread | |
| 81 // by reusing the cached structure, see comment in 'thread_registry.h'). | |
| 82 if (is_mutator) { | |
| 83 if (mutator_thread_ == NULL) { | |
| 84 mutator_thread_ = GetThreadFromFreelist(isolate); | |
| 85 } | |
| 86 thread = mutator_thread_; | |
| 87 } else { | |
| 88 thread = GetThreadFromFreelist(isolate); | |
| 89 ASSERT(thread->api_top_scope() == NULL); | |
| 90 } | |
| 91 // Now add this Thread to the active list for the isolate. | |
| 92 AddThreadToActiveList(thread); | |
| 93 // Set up other values and set the TLS value. | |
| 94 thread->isolate_ = isolate; | |
| 95 thread->heap_ = isolate->heap(); | |
| 96 thread->set_os_thread(os_thread); | |
| 97 os_thread->set_thread(thread); | |
| 98 Thread::SetCurrent(thread); | |
| 99 os_thread->EnableThreadInterrupts(); | |
| 100 } | |
| 101 return thread; | 50 return thread; |
| 102 } | 51 } |
| 103 | 52 |
| 104 | 53 |
| 105 void ThreadRegistry::Unschedule(Thread* thread, | 54 void ThreadRegistry::ReturnThreadLocked(bool is_mutator, Thread* thread) { |
| 106 bool is_mutator, | 55 ASSERT(threads_lock()->IsOwnedByCurrentThread()); |
| 107 bool bypass_safepoint) { | |
| 108 MonitorLocker ml(monitor_); | |
| 109 OSThread* os_thread = thread->os_thread(); | |
| 110 ASSERT(os_thread != NULL); | |
| 111 os_thread->DisableThreadInterrupts(); | |
| 112 os_thread->set_thread(NULL); | |
| 113 OSThread::SetCurrent(os_thread); | |
| 114 thread->isolate_ = NULL; | |
| 115 thread->heap_ = NULL; | |
| 116 thread->set_os_thread(NULL); | |
| 117 // Remove thread from the active list for the isolate. | 56 // Remove thread from the active list for the isolate. |
| 118 RemoveThreadFromActiveList(thread); | 57 RemoveFromActiveListLocked(thread); |
| 119 // Return thread to the free list (we special case the mutator | |
| 120 // thread by holding on to it, see comment in 'thread_registry.h'). | |
| 121 if (!is_mutator) { | 58 if (!is_mutator) { |
| 122 ASSERT(thread->api_top_scope() == NULL); | 59 ASSERT(thread->api_top_scope() == NULL); |
| 123 ReturnThreadToFreelist(thread); | 60 ReturnToFreelistLocked(thread); |
| 124 } | |
| 125 if (!bypass_safepoint && in_rendezvous_) { | |
| 126 // Don't wait for this thread. | |
| 127 ASSERT(remaining_ > 0); | |
| 128 if (--remaining_ == 0) { | |
| 129 ml.NotifyAll(); | |
| 130 } | |
| 131 } | 61 } |
| 132 } | 62 } |
| 133 | 63 |
| 134 | 64 |
| 135 void ThreadRegistry::VisitObjectPointers(ObjectPointerVisitor* visitor, | 65 void ThreadRegistry::VisitObjectPointers(ObjectPointerVisitor* visitor, |
| 136 bool validate_frames) { | 66 bool validate_frames) { |
| 137 MonitorLocker ml(monitor_); | 67 MonitorLocker ml(threads_lock()); |
| 138 Thread* thread = active_list_; | 68 Thread* thread = active_list_; |
| 139 while (thread != NULL) { | 69 while (thread != NULL) { |
| 140 if (thread->zone() != NULL) { | 70 if (thread->zone() != NULL) { |
| 141 thread->zone()->VisitObjectPointers(visitor); | 71 thread->zone()->VisitObjectPointers(visitor); |
| 142 } | 72 } |
| 143 thread->VisitObjectPointers(visitor); | 73 thread->VisitObjectPointers(visitor); |
| 144 // Iterate over all the stack frames and visit objects on the stack. | 74 // Iterate over all the stack frames and visit objects on the stack. |
| 145 StackFrameIterator frames_iterator(thread->top_exit_frame_info(), | 75 StackFrameIterator frames_iterator(thread->top_exit_frame_info(), |
| 146 validate_frames); | 76 validate_frames); |
| 147 StackFrame* frame = frames_iterator.NextFrame(); | 77 StackFrame* frame = frames_iterator.NextFrame(); |
| 148 while (frame != NULL) { | 78 while (frame != NULL) { |
| 149 frame->VisitObjectPointers(visitor); | 79 frame->VisitObjectPointers(visitor); |
| 150 frame = frames_iterator.NextFrame(); | 80 frame = frames_iterator.NextFrame(); |
| 151 } | 81 } |
| 152 thread = thread->next_; | 82 thread = thread->next_; |
| 153 } | 83 } |
| 154 } | 84 } |
| 155 | 85 |
| 156 | 86 |
| 157 void ThreadRegistry::PrepareForGC() { | 87 void ThreadRegistry::PrepareForGC() { |
| 158 MonitorLocker ml(monitor_); | 88 MonitorLocker ml(threads_lock()); |
| 159 Thread* thread = active_list_; | 89 Thread* thread = active_list_; |
| 160 while (thread != NULL) { | 90 while (thread != NULL) { |
| 161 thread->PrepareForGC(); | 91 thread->PrepareForGC(); |
| 162 thread = thread->next_; | 92 thread = thread->next_; |
| 163 } | 93 } |
| 164 } | 94 } |
| 165 | 95 |
| 166 | 96 |
| 167 void ThreadRegistry::AddThreadToActiveList(Thread* thread) { | 97 void ThreadRegistry::AddToActiveListLocked(Thread* thread) { |
| 168 ASSERT(thread != NULL); | 98 ASSERT(thread != NULL); |
| 169 ASSERT(monitor_->IsOwnedByCurrentThread()); | 99 ASSERT(threads_lock()->IsOwnedByCurrentThread()); |
| 170 thread->next_ = active_list_; | 100 thread->next_ = active_list_; |
| 171 active_list_ = thread; | 101 active_list_ = thread; |
| 172 } | 102 } |
| 173 | 103 |
| 174 | 104 |
| 175 void ThreadRegistry::RemoveThreadFromActiveList(Thread* thread) { | 105 void ThreadRegistry::RemoveFromActiveListLocked(Thread* thread) { |
| 176 ASSERT(thread != NULL); | 106 ASSERT(thread != NULL); |
| 177 ASSERT(monitor_->IsOwnedByCurrentThread()); | 107 ASSERT(threads_lock()->IsOwnedByCurrentThread()); |
| 178 Thread* prev = NULL; | 108 Thread* prev = NULL; |
| 179 Thread* current = active_list_; | 109 Thread* current = active_list_; |
| 180 while (current != NULL) { | 110 while (current != NULL) { |
| 181 if (current == thread) { | 111 if (current == thread) { |
| 182 if (prev == NULL) { | 112 if (prev == NULL) { |
| 183 active_list_ = current->next_; | 113 active_list_ = current->next_; |
| 184 } else { | 114 } else { |
| 185 prev->next_ = current->next_; | 115 prev->next_ = current->next_; |
| 186 } | 116 } |
| 187 break; | 117 break; |
| 188 } | 118 } |
| 189 prev = current; | 119 prev = current; |
| 190 current = current->next_; | 120 current = current->next_; |
| 191 } | 121 } |
| 192 } | 122 } |
| 193 | 123 |
| 194 | 124 |
| 195 Thread* ThreadRegistry::GetThreadFromFreelist(Isolate* isolate) { | 125 Thread* ThreadRegistry::GetFromFreelistLocked(Isolate* isolate) { |
| 196 ASSERT(monitor_->IsOwnedByCurrentThread()); | 126 ASSERT(threads_lock()->IsOwnedByCurrentThread()); |
| 197 Thread* thread = NULL; | 127 Thread* thread = NULL; |
| 198 // Get thread structure from free list or create a new one. | 128 // Get thread structure from free list or create a new one. |
| 199 if (free_list_ == NULL) { | 129 if (free_list_ == NULL) { |
| 200 thread = new Thread(isolate); | 130 thread = new Thread(isolate); |
| 201 } else { | 131 } else { |
| 202 thread = free_list_; | 132 thread = free_list_; |
| 203 free_list_ = thread->next_; | 133 free_list_ = thread->next_; |
| 204 } | 134 } |
| 205 return thread; | 135 return thread; |
| 206 } | 136 } |
| 207 | 137 |
| 208 void ThreadRegistry::ReturnThreadToFreelist(Thread* thread) { | 138 void ThreadRegistry::ReturnToFreelistLocked(Thread* thread) { |
| 209 ASSERT(thread != NULL); | 139 ASSERT(thread != NULL); |
| 210 ASSERT(thread->os_thread_ == NULL); | 140 ASSERT(thread->os_thread_ == NULL); |
| 211 ASSERT(thread->isolate_ == NULL); | 141 ASSERT(thread->isolate_ == NULL); |
| 212 ASSERT(thread->heap_ == NULL); | 142 ASSERT(thread->heap_ == NULL); |
| 213 ASSERT(monitor_->IsOwnedByCurrentThread()); | 143 ASSERT(threads_lock()->IsOwnedByCurrentThread()); |
| 214 // Add thread to the free list. | 144 // Add thread to the free list. |
| 215 thread->next_ = free_list_; | 145 thread->next_ = free_list_; |
| 216 free_list_ = thread; | 146 free_list_ = thread; |
| 217 } | 147 } |
| 218 | 148 |
| 219 | |
| 220 void ThreadRegistry::CheckSafepointLocked() { | |
| 221 int64_t last_round = -1; | |
| 222 while (in_rendezvous_) { | |
| 223 ASSERT(round_ >= last_round); | |
| 224 if (round_ != last_round) { | |
| 225 ASSERT((last_round == -1) || (round_ == (last_round + 1))); | |
| 226 last_round = round_; | |
| 227 // Participate in this round. | |
| 228 if (--remaining_ == 0) { | |
| 229 // Ensure the organizing thread is notified. | |
| 230 // TODO(koda): Use separate condition variables and plain 'Notify'. | |
| 231 monitor_->NotifyAll(); | |
| 232 } | |
| 233 } | |
| 234 monitor_->Wait(Monitor::kNoTimeout); | |
| 235 // Note: Here, round_ is needed to detect and distinguish two cases: | |
| 236 // a) The old rendezvous is still in progress, so just keep waiting, or | |
| 237 // b) after ResumeAllThreads, another call to SafepointThreads was | |
| 238 // made before this thread got a chance to reaquire monitor_, thus this | |
| 239 // thread should (again) decrease remaining_ to indicate cooperation in | |
| 240 // this new round. | |
| 241 } | |
| 242 } | |
| 243 | |
| 244 | |
| 245 intptr_t ThreadRegistry::CountScheduledLocked() { | |
| 246 intptr_t count = 0; | |
| 247 Thread* current = active_list_; | |
| 248 while (current != NULL) { | |
| 249 ++count; | |
| 250 current = current->next_; | |
| 251 } | |
| 252 return count; | |
| 253 } | |
| 254 | |
| 255 } // namespace dart | 149 } // namespace dart |
| OLD | NEW |