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 #ifndef VM_THREAD_REGISTRY_H_ | 5 #ifndef VM_THREAD_REGISTRY_H_ |
6 #define VM_THREAD_REGISTRY_H_ | 6 #define VM_THREAD_REGISTRY_H_ |
7 | 7 |
8 #include "vm/globals.h" | 8 #include "vm/globals.h" |
9 #include "vm/growable_array.h" | 9 #include "vm/growable_array.h" |
10 #include "vm/isolate.h" | 10 #include "vm/isolate.h" |
11 #include "vm/lockers.h" | 11 #include "vm/lockers.h" |
12 #include "vm/stack_frame.h" | 12 #include "vm/stack_frame.h" |
13 #include "vm/thread.h" | 13 #include "vm/thread.h" |
14 | 14 |
15 namespace dart { | 15 namespace dart { |
16 | 16 |
17 // Unordered collection of threads relating to a particular isolate. | 17 // Unordered collection of threads relating to a particular isolate. |
18 class ThreadRegistry { | 18 class ThreadRegistry { |
19 public: | 19 public: |
20 ThreadRegistry() | 20 ThreadRegistry() |
21 : monitor_(new Monitor()), | 21 : monitor_(new Monitor()), |
22 entries_(), | 22 active_list_(NULL), |
| 23 free_list_(NULL), |
| 24 mutator_thread_(NULL), |
23 in_rendezvous_(false), | 25 in_rendezvous_(false), |
24 remaining_(0), | 26 remaining_(0), |
25 round_(0) {} | 27 round_(0) {} |
26 | 28 |
27 ~ThreadRegistry(); | 29 ~ThreadRegistry(); |
28 | 30 |
| 31 Thread* active_list() const { return active_list_; } |
| 32 |
29 // Bring all threads in this isolate to a safepoint. The caller is | 33 // Bring all threads in this isolate to a safepoint. The caller is |
30 // expected to be implicitly at a safepoint. The threads will wait | 34 // expected to be implicitly at a safepoint. The threads will wait |
31 // until ResumeAllThreads is called. First participates in any | 35 // until ResumeAllThreads is called. First participates in any |
32 // already pending rendezvous requested by another thread. Any | 36 // already pending rendezvous requested by another thread. Any |
33 // thread that tries to enter this isolate during rendezvous will | 37 // thread that tries to enter this isolate during rendezvous will |
34 // wait in RestoreStateTo. Nesting is not supported: the caller must | 38 // wait in RestoreStateTo. Nesting is not supported: the caller must |
35 // call ResumeAllThreads before making further calls to | 39 // call ResumeAllThreads before making further calls to |
36 // SafepointThreads. | 40 // SafepointThreads. |
37 void SafepointThreads(); | 41 void SafepointThreads(); |
38 | 42 |
39 // Unblocks all threads participating in the rendezvous that was organized | 43 // Unblocks all threads participating in the rendezvous that was organized |
40 // by a prior call to SafepointThreads. | 44 // by a prior call to SafepointThreads. |
41 // TODO(koda): Consider adding a scope helper to avoid omitting this call. | 45 // TODO(koda): Consider adding a scope helper to avoid omitting this call. |
42 void ResumeAllThreads(); | 46 void ResumeAllThreads(); |
43 | 47 |
44 // Indicate that the current thread is at a safepoint, and offer to wait for | 48 // Indicate that the current thread is at a safepoint, and offer to wait for |
45 // any pending rendezvous request (if none, returns immediately). | 49 // any pending rendezvous request (if none, returns immediately). |
46 void CheckSafepoint() { | 50 void CheckSafepoint() { |
47 MonitorLocker ml(monitor_); | 51 MonitorLocker ml(monitor_); |
48 CheckSafepointLocked(); | 52 CheckSafepointLocked(); |
49 } | 53 } |
50 | 54 |
51 bool RestoreStateTo(Thread* thread, Thread::State* state, | 55 Thread* Schedule(Isolate* isolate, bool is_mutator, bool bypass_safepoint); |
52 bool bypass_safepoint) { | 56 void Unschedule(Thread* thread, bool is_mutator, bool bypass_safepoint); |
53 MonitorLocker ml(monitor_); | 57 void VisitObjectPointers(ObjectPointerVisitor* visitor, bool validate_frames); |
54 // Wait for any rendezvous in progress. | |
55 while (!bypass_safepoint && in_rendezvous_) { | |
56 ml.Wait(Monitor::kNoTimeout); | |
57 } | |
58 Entry* entry = FindEntry(thread); | |
59 if (entry != NULL) { | |
60 Thread::State st = entry->state; | |
61 // TODO(koda): Support same thread re-entering same isolate with | |
62 // Dart frames in between. For now, just assert it doesn't happen. | |
63 if (st.top_exit_frame_info != thread->top_exit_frame_info()) { | |
64 ASSERT(thread->top_exit_frame_info() == 0 || | |
65 thread->top_exit_frame_info() > st.top_exit_frame_info); | |
66 } | |
67 ASSERT(!entry->scheduled); | |
68 entry->scheduled = true; | |
69 #if defined(DEBUG) | |
70 // State field is not in use, so zap it. | |
71 memset(&entry->state, 0xda, sizeof(entry->state)); | |
72 #endif | |
73 *state = st; | |
74 return true; | |
75 } | |
76 Entry new_entry; | |
77 new_entry.thread = thread; | |
78 new_entry.scheduled = true; | |
79 #if defined(DEBUG) | |
80 // State field is not in use, so zap it. | |
81 memset(&new_entry.state, 0xda, sizeof(new_entry.state)); | |
82 #endif | |
83 entries_.Add(new_entry); | |
84 return false; | |
85 } | |
86 | |
87 void SaveStateFrom(Thread* thread, const Thread::State& state, | |
88 bool bypass_safepoint) { | |
89 MonitorLocker ml(monitor_); | |
90 Entry* entry = FindEntry(thread); | |
91 ASSERT(entry != NULL); | |
92 ASSERT(entry->scheduled); | |
93 entry->scheduled = false; | |
94 entry->state = state; | |
95 if (!bypass_safepoint && in_rendezvous_) { | |
96 // Don't wait for this thread. | |
97 ASSERT(remaining_ > 0); | |
98 if (--remaining_ == 0) { | |
99 ml.NotifyAll(); | |
100 } | |
101 } | |
102 } | |
103 | |
104 bool Contains(Thread* thread) { | |
105 MonitorLocker ml(monitor_); | |
106 return (FindEntry(thread) != NULL); | |
107 } | |
108 | |
109 void CheckNotScheduled(Isolate* isolate) { | |
110 MonitorLocker ml(monitor_); | |
111 for (int i = 0; i < entries_.length(); ++i) { | |
112 const Entry& entry = entries_[i]; | |
113 if (entry.scheduled) { | |
114 FATAL3("Isolate %p still scheduled on %p (whose isolate_ is %p)\n", | |
115 isolate, | |
116 entry.thread, | |
117 entry.thread->isolate()); | |
118 } | |
119 } | |
120 } | |
121 | |
122 void VisitObjectPointers(ObjectPointerVisitor* visitor, | |
123 bool validate_frames) { | |
124 MonitorLocker ml(monitor_); | |
125 for (int i = 0; i < entries_.length(); ++i) { | |
126 const Entry& entry = entries_[i]; | |
127 const Thread::State& state = | |
128 entry.scheduled ? entry.thread->state_ : entry.state; | |
129 if (state.zone != NULL) { | |
130 state.zone->VisitObjectPointers(visitor); | |
131 } | |
132 if (entry.scheduled) { | |
133 ASSERT(entry.thread != NULL); | |
134 entry.thread->VisitObjectPointers(visitor); | |
135 } | |
136 // Iterate over all the stack frames and visit objects on the stack. | |
137 StackFrameIterator frames_iterator(state.top_exit_frame_info, | |
138 validate_frames); | |
139 StackFrame* frame = frames_iterator.NextFrame(); | |
140 while (frame != NULL) { | |
141 frame->VisitObjectPointers(visitor); | |
142 frame = frames_iterator.NextFrame(); | |
143 } | |
144 } | |
145 } | |
146 | |
147 void PruneThread(Thread* thread); | |
148 | |
149 void ReclaimTimelineBlocks(); | |
150 | |
151 struct Entry { | |
152 // NOTE: |thread| is deleted automatically when the thread exits. | |
153 // In other words, it is not safe to dereference |thread| unless you are on | |
154 // the thread itself. | |
155 Thread* thread; | |
156 bool scheduled; | |
157 Thread::State state; | |
158 }; | |
159 | |
160 class EntryIterator { | |
161 public: | |
162 explicit EntryIterator(ThreadRegistry* registry); | |
163 ~EntryIterator(); | |
164 | |
165 // Returns false when there are no more entries. | |
166 bool HasNext() const; | |
167 | |
168 // Returns the next entry and moves forward. | |
169 const Entry& Next(); | |
170 | |
171 private: | |
172 void Reset(ThreadRegistry* registry); | |
173 | |
174 intptr_t index_; | |
175 ThreadRegistry* registry_; | |
176 }; | |
177 | 58 |
178 private: | 59 private: |
179 // Returns Entry corresponding to thread in registry or NULL. | 60 Thread* GetThreadFromFreelist(Isolate* isolate); |
180 // Note: Lock should be taken before this function is called. | 61 void ReturnThreadToFreelist(Thread* thread); |
181 // TODO(koda): Add method Monitor::IsOwnedByCurrentThread. | |
182 Entry* FindEntry(Thread* thread) { | |
183 for (int i = 0; i < entries_.length(); ++i) { | |
184 if (entries_[i].thread == thread) { | |
185 return &entries_[i]; | |
186 } | |
187 } | |
188 return NULL; | |
189 } | |
190 | 62 |
191 // Note: Lock should be taken before this function is called. | 63 // Note: Lock should be taken before this function is called. |
192 void CheckSafepointLocked(); | 64 void CheckSafepointLocked(); |
193 | 65 |
194 // Returns the number threads that are scheduled on this isolate. | 66 // Returns the number threads that are scheduled on this isolate. |
195 // Note: Lock should be taken before this function is called. | 67 // Note: Lock should be taken before this function is called. |
196 intptr_t CountScheduledLocked(); | 68 intptr_t CountScheduledLocked(); |
197 | 69 |
198 Monitor* monitor_; // All access is synchronized through this monitor. | 70 Monitor* monitor_; // All access is synchronized through this monitor. |
199 MallocGrowableArray<Entry> entries_; | 71 Thread* active_list_; // List of active threads in the isolate. |
| 72 Thread* free_list_; // Free list of Thread objects that can be reused. |
| 73 // TODO(asiva): Currently we treat a mutator thread as a special thread |
| 74 // and always schedule execution of Dart code on the same mutator thread |
| 75 // object. This is because ApiState is still an object associated with |
| 76 // the isolate and switching execution to another thread causes problems. |
| 77 // Once ApiState is made a per Thread object it should be possible to |
| 78 // free a mutator thread like all other threads and continue running on |
| 79 // a different thread. |
| 80 Thread* mutator_thread_; |
200 | 81 |
201 // Safepoint rendezvous state. | 82 // Safepoint rendezvous state. |
202 bool in_rendezvous_; // A safepoint rendezvous request is in progress. | 83 bool in_rendezvous_; // A safepoint rendezvous request is in progress. |
203 intptr_t remaining_; // Number of threads yet to reach their safepoint. | 84 intptr_t remaining_; // Number of threads yet to reach their safepoint. |
204 int64_t round_; // Counter, to prevent missing updates to remaining_ | 85 int64_t round_; // Counter, to prevent missing updates to remaining_ |
205 // (see comments in CheckSafepointLocked). | 86 // (see comments in CheckSafepointLocked). |
206 | 87 |
207 DISALLOW_COPY_AND_ASSIGN(ThreadRegistry); | 88 DISALLOW_COPY_AND_ASSIGN(ThreadRegistry); |
208 }; | 89 }; |
209 | 90 |
210 } // namespace dart | 91 } // namespace dart |
211 | 92 |
212 #endif // VM_THREAD_REGISTRY_H_ | 93 #endif // VM_THREAD_REGISTRY_H_ |
OLD | NEW |