Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(24)

Side by Side Diff: runtime/vm/thread_registry.cc

Issue 1541073002: Implement safepointing of threads (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: fix-typo Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/thread_registry.h ('k') | runtime/vm/thread_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
OLDNEW
« no previous file with comments | « runtime/vm/thread_registry.h ('k') | runtime/vm/thread_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698