Initial checkin of lldb code from internal Apple repo.


git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@105619 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Target/ThreadList.cpp b/source/Target/ThreadList.cpp
new file mode 100644
index 0000000..6bc2271
--- /dev/null
+++ b/source/Target/ThreadList.cpp
@@ -0,0 +1,460 @@
+//===-- ThreadList.cpp ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <stdlib.h>
+
+#include <algorithm>
+
+#include "lldb/Target/ThreadList.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ThreadList::ThreadList (Process *process) :
+    m_process (process),
+    m_stop_id (0),
+    m_threads(),
+    m_threads_mutex (Mutex::eMutexTypeRecursive),
+    m_current_tid (LLDB_INVALID_THREAD_ID)
+{
+}
+
+ThreadList::ThreadList (const ThreadList &rhs) :
+    m_process (),
+    m_stop_id (),
+    m_threads (),
+    m_threads_mutex (Mutex::eMutexTypeRecursive),
+    m_current_tid ()
+{
+    // Use the assignment operator since it uses the mutex
+    *this = rhs;
+}
+
+const ThreadList&
+ThreadList::operator = (const ThreadList& rhs)
+{
+    if (this != &rhs)
+    {
+        // Lock both mutexes to make sure neither side changes anyone on us
+        // while the assignement occurs
+        Mutex::Locker locker_this(m_threads_mutex);
+        Mutex::Locker locker_rhs(rhs.m_threads_mutex);
+        m_process = rhs.m_process;
+        m_stop_id = rhs.m_stop_id;
+        m_threads = rhs.m_threads;
+        m_current_tid = rhs.m_current_tid;
+    }
+    return *this;
+}
+
+
+ThreadList::~ThreadList()
+{
+}
+
+
+uint32_t
+ThreadList::GetStopID () const
+{
+    return m_stop_id;
+}
+
+void
+ThreadList::SetStopID (uint32_t stop_id)
+{
+    m_stop_id = stop_id;
+}
+
+
+void
+ThreadList::AddThread (ThreadSP &thread_sp)
+{
+    Mutex::Locker locker(m_threads_mutex);
+    m_threads.push_back(thread_sp);
+}
+
+uint32_t
+ThreadList::GetSize (bool can_update)
+{
+    Mutex::Locker locker(m_threads_mutex);
+    if (can_update)
+        m_process->UpdateThreadListIfNeeded();
+    return m_threads.size();
+}
+
+ThreadSP
+ThreadList::GetThreadAtIndex (uint32_t idx, bool can_update)
+{
+    Mutex::Locker locker(m_threads_mutex);
+    if (can_update)
+        m_process->UpdateThreadListIfNeeded();
+
+    ThreadSP thread_sp;
+    if (idx < m_threads.size())
+        thread_sp = m_threads[idx];
+    return thread_sp;
+}
+
+ThreadSP
+ThreadList::FindThreadByID (lldb::tid_t tid, bool can_update)
+{
+    Mutex::Locker locker(m_threads_mutex);
+
+    if (can_update)
+        m_process->UpdateThreadListIfNeeded();
+
+    ThreadSP thread_sp;
+    uint32_t idx = 0;
+    const uint32_t num_threads = m_threads.size();
+    for (idx = 0; idx < num_threads; ++idx)
+    {
+        if (m_threads[idx]->GetID() == tid)
+        {
+            thread_sp = m_threads[idx];
+            break;
+        }
+    }
+    return thread_sp;
+}
+
+ThreadSP
+ThreadList::GetThreadSPForThreadPtr (Thread *thread_ptr)
+{
+    ThreadSP thread_sp;
+    if (thread_ptr)
+    {
+        Mutex::Locker locker(m_threads_mutex);
+
+        uint32_t idx = 0;
+        const uint32_t num_threads = m_threads.size();
+        for (idx = 0; idx < num_threads; ++idx)
+        {
+            if (m_threads[idx].get() == thread_ptr)
+            {
+                thread_sp = m_threads[idx];
+                break;
+            }
+        }
+    }
+    return thread_sp;
+}
+
+
+
+ThreadSP
+ThreadList::FindThreadByIndexID (uint32_t index_id, bool can_update)
+{
+    Mutex::Locker locker(m_threads_mutex);
+
+    if (can_update)
+        m_process->UpdateThreadListIfNeeded();
+
+    ThreadSP thread_sp;
+    const uint32_t num_threads = m_threads.size();
+    for (uint32_t idx = 0; idx < num_threads; ++idx)
+    {
+        if (m_threads[idx]->GetIndexID() == index_id)
+        {
+            thread_sp = m_threads[idx];
+            break;
+        }
+    }
+    return thread_sp;
+}
+
+bool
+ThreadList::ShouldStop (Event *event_ptr)
+{
+    Mutex::Locker locker(m_threads_mutex);
+
+    // Running events should never stop, obviously...
+
+
+    bool should_stop = false;
+    m_process->UpdateThreadListIfNeeded();
+
+    collection::iterator pos, end = m_threads.end();
+
+    // Run through the threads and ask whether we should stop.  Don't ask
+    // suspended threads, however, it makes more sense for them to preserve their
+    // state across the times the process runs but they don't get a chance to.
+    for (pos = m_threads.begin(); pos != end; ++pos)
+    {
+        ThreadSP thread_sp(*pos);
+        if ((thread_sp->ThreadStoppedForAReason())
+            && (thread_sp->GetResumeState () != eStateSuspended))
+        {
+            should_stop |= thread_sp->ShouldStop(event_ptr);
+        }
+    }
+    if (should_stop)
+    {
+        for (pos = m_threads.begin(); pos != end; ++pos)
+        {
+            ThreadSP thread_sp(*pos);
+            thread_sp->WillStop ();
+        }
+    }
+
+    return should_stop;
+}
+
+Vote
+ThreadList::ShouldReportStop (Event *event_ptr)
+{
+    Vote result = eVoteNoOpinion;
+    m_process->UpdateThreadListIfNeeded();
+    collection::iterator pos, end = m_threads.end();
+
+    // Run through the threads and ask whether we should report this event.
+    // For stopping, a YES vote wins over everything.  A NO vote wins over NO opinion.
+    for (pos = m_threads.begin(); pos != end; ++pos)
+    {
+        ThreadSP thread_sp(*pos);
+        if (thread_sp->ThreadStoppedForAReason() && (thread_sp->GetResumeState () != eStateSuspended))
+        {
+            switch (thread_sp->ShouldReportStop (event_ptr))
+            {
+                case eVoteNoOpinion:
+                    continue;
+                case eVoteYes:
+                    result = eVoteYes;
+                    break;
+                case eVoteNo:
+                    if (result == eVoteNoOpinion)
+                        result = eVoteNo;
+                    break;
+            }
+        }
+    }
+    return result;
+}
+
+Vote
+ThreadList::ShouldReportRun (Event *event_ptr)
+{
+    Vote result = eVoteNoOpinion;
+    m_process->UpdateThreadListIfNeeded();
+    collection::iterator pos, end = m_threads.end();
+
+    // Run through the threads and ask whether we should report this event.
+    // The rule is NO vote wins over everything, a YES vote wins over no opinion.
+
+    for (pos = m_threads.begin(); pos != end; ++pos)
+    {
+        ThreadSP thread_sp(*pos);
+        if (thread_sp->GetResumeState () != eStateSuspended)
+
+        switch (thread_sp->ShouldReportRun (event_ptr))
+        {
+            case eVoteNoOpinion:
+                continue;
+            case eVoteYes:
+                if (result == eVoteNoOpinion)
+                    result = eVoteYes;
+                break;
+            case eVoteNo:
+                result = eVoteNo;
+                break;
+        }
+    }
+    return result;
+}
+
+void
+ThreadList::Clear()
+{
+    m_stop_id = 0;
+    m_threads.clear();
+    m_current_tid = LLDB_INVALID_THREAD_ID;
+}
+
+void
+ThreadList::RefreshStateAfterStop ()
+{
+    Mutex::Locker locker(m_threads_mutex);
+
+    m_process->UpdateThreadListIfNeeded();
+
+    collection::iterator pos, end = m_threads.end();
+    for (pos = m_threads.begin(); pos != end; ++pos)
+        (*pos)->RefreshStateAfterStop ();
+}
+
+void
+ThreadList::DiscardThreadPlans ()
+{
+    // You don't need to update the thread list here, because only threads
+    // that you currently know about have any thread plans.
+    Mutex::Locker locker(m_threads_mutex);
+
+    collection::iterator pos, end = m_threads.end();
+    for (pos = m_threads.begin(); pos != end; ++pos)
+        (*pos)->DiscardThreadPlans (true);
+
+}
+
+bool
+ThreadList::WillResume ()
+{
+    // Run through the threads and perform their momentary actions.
+    // But we only do this for threads that are running, user suspended
+    // threads stay where they are.
+    bool success = true;
+
+    Mutex::Locker locker(m_threads_mutex);
+    m_process->UpdateThreadListIfNeeded();
+
+    collection::iterator pos, end = m_threads.end();
+    
+    // Give all the threads a last chance to set up their state before we
+    // negotiate who is actually going to get a chance to run...
+
+    for (pos = m_threads.begin(); pos != end; ++pos)
+        (*pos)->SetupForResume ();
+    
+    // Now go through the threads and see if any thread wants to run just itself.
+    // if so then pick one and run it.
+    ThreadList run_me_only_list (m_process);
+    
+    run_me_only_list.SetStopID(m_process->GetStopID());
+
+    ThreadSP immediate_thread_sp;
+    bool run_only_current_thread = false;
+
+    for (pos = m_threads.begin(); pos != end; ++pos)
+    {
+        ThreadSP thread_sp(*pos);
+        if (thread_sp->GetCurrentPlan()->IsImmediate())
+        {
+            // We first do all the immediate plans, so if we find one, set
+            // immediate_thread_sp and break out, and we'll pick it up first thing
+            // when we're negotiating which threads get to run.
+            immediate_thread_sp = thread_sp;
+            break;
+        }
+        else if (thread_sp->GetResumeState() != eStateSuspended &&
+                 thread_sp->GetCurrentPlan()->StopOthers())
+        {
+            // You can't say "stop others" and also want yourself to be suspended.
+            assert (thread_sp->GetCurrentPlan()->RunState() != eStateSuspended);
+
+            if (thread_sp == GetCurrentThread())
+            {
+                run_only_current_thread = true;
+                run_me_only_list.Clear();
+                run_me_only_list.AddThread (thread_sp);
+                break;
+            }
+
+            run_me_only_list.AddThread (thread_sp);
+        }
+
+    }
+
+    if (immediate_thread_sp)
+    {
+        for (pos = m_threads.begin(); pos != end; ++pos)
+        {
+            ThreadSP thread_sp(*pos);
+            if (thread_sp.get() == immediate_thread_sp.get())
+                thread_sp->WillResume(thread_sp->GetCurrentPlan()->RunState());
+            else
+                thread_sp->WillResume (eStateSuspended);
+        }
+    }
+    else if (run_me_only_list.GetSize (false) == 0)
+    {
+        // Everybody runs as they wish:
+        for (pos = m_threads.begin(); pos != end; ++pos)
+        {
+            ThreadSP thread_sp(*pos);
+            thread_sp->WillResume(thread_sp->GetCurrentPlan()->RunState());
+        }
+    }
+    else
+    {
+        ThreadSP thread_to_run;
+
+        if (run_only_current_thread)
+        {
+            thread_to_run = GetCurrentThread();
+        }
+        else if (run_me_only_list.GetSize (false) == 1)
+        {
+            thread_to_run = run_me_only_list.GetThreadAtIndex (0);
+        }
+        else
+        {
+            int random_thread = (int)
+                    ((run_me_only_list.GetSize (false) * (double) rand ()) / (RAND_MAX + 1.0));
+            thread_to_run = run_me_only_list.GetThreadAtIndex (random_thread);
+        }
+
+        for (pos = m_threads.begin(); pos != end; ++pos)
+        {
+            ThreadSP thread_sp(*pos);
+            if (thread_sp == thread_to_run)
+                thread_sp->WillResume(thread_sp->GetCurrentPlan()->RunState());
+            else
+                thread_sp->WillResume (eStateSuspended);
+        }
+    }
+
+    return success;
+}
+
+void
+ThreadList::DidResume ()
+{
+    collection::iterator pos, end = m_threads.end();
+    for (pos = m_threads.begin(); pos != end; ++pos)
+    {
+        // Don't clear out threads that aren't going to get a chance to run, rather
+        // leave their state for the next time around.
+        ThreadSP thread_sp(*pos);
+        if (thread_sp->GetResumeState() != eStateSuspended)
+            thread_sp->DidResume ();
+    }
+}
+
+ThreadSP
+ThreadList::GetCurrentThread ()
+{
+    Mutex::Locker locker(m_threads_mutex);
+    return FindThreadByID(m_current_tid);
+}
+
+bool
+ThreadList::SetCurrentThreadByID (lldb::tid_t tid)
+{
+    Mutex::Locker locker(m_threads_mutex);
+    if  (FindThreadByID(tid).get())
+        m_current_tid = tid;
+    else
+        m_current_tid = LLDB_INVALID_THREAD_ID;
+
+    return m_current_tid != LLDB_INVALID_THREAD_ID;
+}
+
+bool
+ThreadList::SetCurrentThreadByIndexID (uint32_t index_id)
+{
+    Mutex::Locker locker(m_threads_mutex);
+    ThreadSP thread_sp (FindThreadByIndexID(index_id));
+    if  (thread_sp.get())
+        m_current_tid = thread_sp->GetID();
+    else
+        m_current_tid = LLDB_INVALID_THREAD_ID;
+
+    return m_current_tid != LLDB_INVALID_THREAD_ID;
+}
+