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 |