Added a new Host class: ReadWriteLock

This abstracts read/write locks on the current host system. It is currently backed by pthread_rwlock_t objects so it should work on all unix systems.

We also need a way to control multi-threaded access to the process through the public API when it is running. For example it isn't a good idea to try and get stack frames while the process is running. To implement this, the lldb_private::Process class now contains a ReadWriteLock member variable named m_run_lock which is used to control the public process state. The public process state represents the state of the process as the client knows it. The private is used to control the actual current process state. So the public state of the process can be stopped, yet the private state can be running when evaluating an expression for example. 

Adding the read/write lock where readers are clients that want the process to stay stopped, and writers are clients that run the process, allows us to accurately control multi-threaded access to the process.

Switched the SBThread and SBFrame over to us shared pointers to the ExecutionContextRef class instead of making their own class to track this. This fixed an issue with assigning on SBFrame to another and will also centralize the code that tracks weak references to execution context objects into one location.



git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@154099 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp
index 973fc54..8fdfaf9 100644
--- a/source/Target/Process.cpp
+++ b/source/Target/Process.cpp
@@ -788,7 +788,8 @@
     m_allocated_memory_cache (*this),
     m_should_detach (false),
     m_next_event_action_ap(),
-    m_can_jit(eCanJITDontKnow)
+    m_can_jit(eCanJITDontKnow),
+    m_run_lock ()
 {
     UpdateInstanceName();
     
@@ -1265,7 +1266,28 @@
     LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS));
     if (log)
         log->Printf("Process::SetPublicState (%s)", StateAsCString(new_state));
+    const StateType old_state = m_public_state.GetValue();
     m_public_state.SetValue (new_state);
+    if (!IsHijackedForEvent(eBroadcastBitStateChanged))
+    {
+        const bool old_state_is_stopped = StateIsStoppedState(old_state, false);
+        const bool new_state_is_stopped = StateIsStoppedState(new_state, false);
+        if (old_state_is_stopped != new_state_is_stopped)
+        {
+            if (new_state_is_stopped)
+            {
+                if (log)
+                    log->Printf("Process::SetPublicState (%s) -- unlocking run lock", StateAsCString(new_state));
+                m_run_lock.WriteUnlock();
+            }
+            else
+            {
+                if (log)
+                    log->Printf("Process::SetPublicState (%s) -- locking run lock", StateAsCString(new_state));
+                m_run_lock.WriteLock();
+            }
+        }
+    }
 }
 
 StateType
@@ -1287,6 +1309,20 @@
 
     const StateType old_state = m_private_state.GetValueNoLock ();
     state_changed = old_state != new_state;
+    // This code is left commented out in case we ever need to control
+    // the private process state with another run lock. Right now it doesn't
+    // seem like we need to do this, but if we ever do, we can uncomment and
+    // use this code.
+//    const bool old_state_is_stopped = StateIsStoppedState(old_state, false);
+//    const bool new_state_is_stopped = StateIsStoppedState(new_state, false);
+//    if (old_state_is_stopped != new_state_is_stopped)
+//    {
+//        if (new_state_is_stopped)
+//            m_private_run_lock.WriteUnlock();
+//        else
+//            m_private_run_lock.WriteLock();
+//    }
+
     if (state_changed)
     {
         m_private_state.SetValueNoLock (new_state);