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