| 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 |