| Index: runtime/vm/thread_registry.h
|
| diff --git a/runtime/vm/thread_registry.h b/runtime/vm/thread_registry.h
|
| index 20f4d95d55da3a53a40d95ba0fc4afce8405145c..51ebceb46dbefed785cc0123941ed45b0e7ba6bc 100644
|
| --- a/runtime/vm/thread_registry.h
|
| +++ b/runtime/vm/thread_registry.h
|
| @@ -19,13 +19,17 @@ class ThreadRegistry {
|
| public:
|
| ThreadRegistry()
|
| : monitor_(new Monitor()),
|
| - entries_(),
|
| + active_list_(NULL),
|
| + free_list_(NULL),
|
| + mutator_thread_(NULL),
|
| in_rendezvous_(false),
|
| remaining_(0),
|
| round_(0) {}
|
|
|
| ~ThreadRegistry();
|
|
|
| + Thread* active_list() const { return active_list_; }
|
| +
|
| // Bring all threads in this isolate to a safepoint. The caller is
|
| // expected to be implicitly at a safepoint. The threads will wait
|
| // until ResumeAllThreads is called. First participates in any
|
| @@ -48,145 +52,13 @@ class ThreadRegistry {
|
| CheckSafepointLocked();
|
| }
|
|
|
| - bool RestoreStateTo(Thread* thread, Thread::State* state,
|
| - bool bypass_safepoint) {
|
| - MonitorLocker ml(monitor_);
|
| - // Wait for any rendezvous in progress.
|
| - while (!bypass_safepoint && in_rendezvous_) {
|
| - ml.Wait(Monitor::kNoTimeout);
|
| - }
|
| - Entry* entry = FindEntry(thread);
|
| - if (entry != NULL) {
|
| - Thread::State st = entry->state;
|
| - // TODO(koda): Support same thread re-entering same isolate with
|
| - // Dart frames in between. For now, just assert it doesn't happen.
|
| - if (st.top_exit_frame_info != thread->top_exit_frame_info()) {
|
| - ASSERT(thread->top_exit_frame_info() == 0 ||
|
| - thread->top_exit_frame_info() > st.top_exit_frame_info);
|
| - }
|
| - ASSERT(!entry->scheduled);
|
| - entry->scheduled = true;
|
| -#if defined(DEBUG)
|
| - // State field is not in use, so zap it.
|
| - memset(&entry->state, 0xda, sizeof(entry->state));
|
| -#endif
|
| - *state = st;
|
| - return true;
|
| - }
|
| - Entry new_entry;
|
| - new_entry.thread = thread;
|
| - new_entry.scheduled = true;
|
| -#if defined(DEBUG)
|
| - // State field is not in use, so zap it.
|
| - memset(&new_entry.state, 0xda, sizeof(new_entry.state));
|
| -#endif
|
| - entries_.Add(new_entry);
|
| - return false;
|
| - }
|
| -
|
| - void SaveStateFrom(Thread* thread, const Thread::State& state,
|
| - bool bypass_safepoint) {
|
| - MonitorLocker ml(monitor_);
|
| - Entry* entry = FindEntry(thread);
|
| - ASSERT(entry != NULL);
|
| - ASSERT(entry->scheduled);
|
| - entry->scheduled = false;
|
| - entry->state = state;
|
| - if (!bypass_safepoint && in_rendezvous_) {
|
| - // Don't wait for this thread.
|
| - ASSERT(remaining_ > 0);
|
| - if (--remaining_ == 0) {
|
| - ml.NotifyAll();
|
| - }
|
| - }
|
| - }
|
| -
|
| - bool Contains(Thread* thread) {
|
| - MonitorLocker ml(monitor_);
|
| - return (FindEntry(thread) != NULL);
|
| - }
|
| -
|
| - void CheckNotScheduled(Isolate* isolate) {
|
| - MonitorLocker ml(monitor_);
|
| - for (int i = 0; i < entries_.length(); ++i) {
|
| - const Entry& entry = entries_[i];
|
| - if (entry.scheduled) {
|
| - FATAL3("Isolate %p still scheduled on %p (whose isolate_ is %p)\n",
|
| - isolate,
|
| - entry.thread,
|
| - entry.thread->isolate());
|
| - }
|
| - }
|
| - }
|
| -
|
| - void VisitObjectPointers(ObjectPointerVisitor* visitor,
|
| - bool validate_frames) {
|
| - MonitorLocker ml(monitor_);
|
| - for (int i = 0; i < entries_.length(); ++i) {
|
| - const Entry& entry = entries_[i];
|
| - const Thread::State& state =
|
| - entry.scheduled ? entry.thread->state_ : entry.state;
|
| - if (state.zone != NULL) {
|
| - state.zone->VisitObjectPointers(visitor);
|
| - }
|
| - if (entry.scheduled) {
|
| - ASSERT(entry.thread != NULL);
|
| - entry.thread->VisitObjectPointers(visitor);
|
| - }
|
| - // Iterate over all the stack frames and visit objects on the stack.
|
| - StackFrameIterator frames_iterator(state.top_exit_frame_info,
|
| - validate_frames);
|
| - StackFrame* frame = frames_iterator.NextFrame();
|
| - while (frame != NULL) {
|
| - frame->VisitObjectPointers(visitor);
|
| - frame = frames_iterator.NextFrame();
|
| - }
|
| - }
|
| - }
|
| -
|
| - void PruneThread(Thread* thread);
|
| -
|
| - void ReclaimTimelineBlocks();
|
| -
|
| - struct Entry {
|
| - // NOTE: |thread| is deleted automatically when the thread exits.
|
| - // In other words, it is not safe to dereference |thread| unless you are on
|
| - // the thread itself.
|
| - Thread* thread;
|
| - bool scheduled;
|
| - Thread::State state;
|
| - };
|
| -
|
| - class EntryIterator {
|
| - public:
|
| - explicit EntryIterator(ThreadRegistry* registry);
|
| - ~EntryIterator();
|
| -
|
| - // Returns false when there are no more entries.
|
| - bool HasNext() const;
|
| -
|
| - // Returns the next entry and moves forward.
|
| - const Entry& Next();
|
| -
|
| - private:
|
| - void Reset(ThreadRegistry* registry);
|
| -
|
| - intptr_t index_;
|
| - ThreadRegistry* registry_;
|
| - };
|
| + Thread* Schedule(Isolate* isolate, bool is_mutator, bool bypass_safepoint);
|
| + void Unschedule(Thread* thread, bool is_mutator, bool bypass_safepoint);
|
| + void VisitObjectPointers(ObjectPointerVisitor* visitor, bool validate_frames);
|
|
|
| private:
|
| - // Returns Entry corresponding to thread in registry or NULL.
|
| - // Note: Lock should be taken before this function is called.
|
| - // TODO(koda): Add method Monitor::IsOwnedByCurrentThread.
|
| - Entry* FindEntry(Thread* thread) {
|
| - for (int i = 0; i < entries_.length(); ++i) {
|
| - if (entries_[i].thread == thread) {
|
| - return &entries_[i];
|
| - }
|
| - }
|
| - return NULL;
|
| - }
|
| + Thread* GetThreadFromFreelist(Isolate* isolate);
|
| + void ReturnThreadToFreelist(Thread* thread);
|
|
|
| // Note: Lock should be taken before this function is called.
|
| void CheckSafepointLocked();
|
| @@ -196,7 +68,16 @@ class ThreadRegistry {
|
| intptr_t CountScheduledLocked();
|
|
|
| Monitor* monitor_; // All access is synchronized through this monitor.
|
| - MallocGrowableArray<Entry> entries_;
|
| + Thread* active_list_; // List of active threads in the isolate.
|
| + Thread* free_list_; // Free list of Thread objects that can be reused.
|
| + // TODO(asiva): Currently we treat a mutator thread as a special thread
|
| + // and always schedule execution of Dart code on the same mutator thread
|
| + // object. This is because ApiState is still an object associated with
|
| + // the isolate and switching execution to another thread causes problems.
|
| + // Once ApiState is made a per Thread object it should be possible to
|
| + // free a mutator thread like all other threads and continue running on
|
| + // a different thread.
|
| + Thread* mutator_thread_;
|
|
|
| // Safepoint rendezvous state.
|
| bool in_rendezvous_; // A safepoint rendezvous request is in progress.
|
|
|