[Lldb-commits] [lldb] r140757 - in /lldb/trunk: test/functionalities/watchpoint/multiple_threads/ test/functionalities/watchpoint/multiple_threads/Makefile test/functionalities/watchpoint/multiple_threads/TestWatchpointMultipleThreads.py test/functionalities/watchpoint/multiple_threads/main.cpp tools/debugserver/source/MacOSX/MachThreadList.cpp

Johnny Chen johnny.chen at apple.com
Wed Sep 28 18:20:42 PDT 2011


Author: johnny
Date: Wed Sep 28 20:20:42 2011
New Revision: 140757

URL: http://llvm.org/viewvc/llvm-project?rev=140757&view=rev
Log:
Fix a bug in the current MacOSX MachThreadList::EnableHardwareWatchpoint() impl so that
it enables the hardware watchpoint for all existing threads.  Add a test file for that.
Also fix MachThreadList::DisableHardwareWatchpoint().

Added:
    lldb/trunk/test/functionalities/watchpoint/multiple_threads/
    lldb/trunk/test/functionalities/watchpoint/multiple_threads/Makefile
    lldb/trunk/test/functionalities/watchpoint/multiple_threads/TestWatchpointMultipleThreads.py
    lldb/trunk/test/functionalities/watchpoint/multiple_threads/main.cpp
Modified:
    lldb/trunk/tools/debugserver/source/MacOSX/MachThreadList.cpp

Added: lldb/trunk/test/functionalities/watchpoint/multiple_threads/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/multiple_threads/Makefile?rev=140757&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/multiple_threads/Makefile (added)
+++ lldb/trunk/test/functionalities/watchpoint/multiple_threads/Makefile Wed Sep 28 20:20:42 2011
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/test/functionalities/watchpoint/multiple_threads/TestWatchpointMultipleThreads.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/multiple_threads/TestWatchpointMultipleThreads.py?rev=140757&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/multiple_threads/TestWatchpointMultipleThreads.py (added)
+++ lldb/trunk/test/functionalities/watchpoint/multiple_threads/TestWatchpointMultipleThreads.py Wed Sep 28 20:20:42 2011
@@ -0,0 +1,90 @@
+"""
+Test that lldb watchpoint works for multiple threads.
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+
+class WatchpointForMultipleThreadsTestCase(TestBase):
+
+    mydir = os.path.join("functionalities", "watchpoint", "multiple_threads")
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    def test_watchpoint_multiple_threads_with_dsym(self):
+        """Test that lldb watchpoint works for multiple threads."""
+        self.buildDsym(dictionary=self.d)
+        self.setTearDownCleanup(dictionary=self.d)
+        self.hello_multiple_threads()
+
+    def test_watchpoint_multiple_threads_with_dwarf(self):
+        """Test that lldb watchpoint works for multiple threads."""
+        self.buildDwarf(dictionary=self.d)
+        self.setTearDownCleanup(dictionary=self.d)
+        self.hello_multiple_threads()
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Our simple source filename.
+        self.source = 'main.cpp'
+        # Find the line number to break inside main().
+        self.line = line_number(self.source, '// Set break point at this line.')
+        # Build dictionary to have unique executable names for each test method.
+        self.exe_name = self.testMethodName
+        self.d = {'CXX_SOURCES': self.source, 'EXE': self.exe_name}
+
+    def hello_multiple_threads(self):
+        """Test that lldb watchpoint works for multiple threads."""
+        exe = os.path.join(os.getcwd(), self.exe_name)
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        # Add a breakpoint to set a watchpoint when stopped on the breakpoint.
+        self.expect("breakpoint set -l %d" % self.line, BREAKPOINT_CREATED,
+            startstr = "Breakpoint created: 1: file ='%s', line = %d, locations = 1" %
+                       (self.source, self.line))
+
+        # Run the program.
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # We should be stopped again due to the breakpoint.
+        # The stop reason of the thread should be breakpoint.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+            substrs = ['stopped',
+                       'stop reason = breakpoint'])
+
+        # Now let's set a write-type watchpoint for variable 'g_val'.
+        # The main.cpp, by design, misbehaves by not following the agreed upon
+        # protocol of using a mutex while accessing the global pool and by not
+        # writing to the variable.
+        self.expect("frame variable -w write -g g_val", WATCHPOINT_CREATED,
+            substrs = ['Watchpoint created', 'size = 4', 'type = w'])
+
+        # Use the '-v' option to do verbose listing of the watchpoint.
+        # The hit count should be 0 initially.
+        self.expect("watchpoint list -v",
+            substrs = ['hit_count = 0'])
+
+        self.runCmd("process continue")
+
+        # We should be stopped again due to the watchpoint (write type) in a
+        # different work thread.  And the stop reason of the thread should be
+        # watchpoint.
+        self.expect("thread list", STOPPED_DUE_TO_WATCHPOINT,
+            substrs = ['stopped',
+                       'stop reason = watchpoint'])
+
+        # Use the '-v' option to do verbose listing of the watchpoint.
+        # The hit count should now be 1.
+        self.expect("watchpoint list -v",
+            substrs = ['hit_count = 1'])
+
+        self.runCmd("thread backtrace all")
+
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/functionalities/watchpoint/multiple_threads/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/multiple_threads/main.cpp?rev=140757&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/multiple_threads/main.cpp (added)
+++ lldb/trunk/test/functionalities/watchpoint/multiple_threads/main.cpp Wed Sep 28 20:20:42 2011
@@ -0,0 +1,89 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C includes
+#include <pthread.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+pthread_t g_thread_1 = NULL;
+pthread_t g_thread_2 = NULL;
+pthread_t g_thread_3 = NULL;
+
+uint32_t g_val = 0;
+
+uint32_t access_pool (uint32_t flag = 0);
+
+uint32_t
+access_pool (uint32_t flag)
+{
+    static pthread_mutex_t g_access_mutex = PTHREAD_MUTEX_INITIALIZER;
+    if (flag == 0)
+        ::pthread_mutex_lock (&g_access_mutex);
+
+    uint32_t old_val = g_val;
+    if (flag != 0)
+        g_val = old_val + 1;
+
+    if (flag == 0)
+        ::pthread_mutex_unlock (&g_access_mutex);
+    return g_val;
+}
+
+void *
+thread_func (void *arg)
+{
+    uint32_t thread_index = *((uint32_t *)arg);
+    printf ("%s (thread index = %u) startng...\n", __FUNCTION__, thread_index);
+
+    uint32_t count = 0;
+    uint32_t val;
+    while (count++ < 15)
+    {
+        // random micro second sleep from zero to 3 seconds
+        int usec = ::rand() % 3000000;
+        printf ("%s (thread = %u) doing a usleep (%d)...\n", __FUNCTION__, thread_index, usec);
+        ::usleep (usec);
+        
+        if (count < 7)
+            val = access_pool ();
+        else
+            val = access_pool (1);
+                
+        printf ("%s (thread = %u) after usleep access_pool returns %d (count=%d)...\n", __FUNCTION__, thread_index, val, count);
+    }
+    printf ("%s (thread index = %u) exiting...\n", __FUNCTION__, thread_index);
+    return NULL;
+}
+
+
+int main (int argc, char const *argv[])
+{
+    int err;
+    void *thread_result = NULL;
+    uint32_t thread_index_1 = 1;
+    uint32_t thread_index_2 = 2;
+    uint32_t thread_index_3 = 3;
+
+    // Create 3 threads
+    err = ::pthread_create (&g_thread_1, NULL, thread_func, &thread_index_1);
+    err = ::pthread_create (&g_thread_2, NULL, thread_func, &thread_index_2);
+    err = ::pthread_create (&g_thread_3, NULL, thread_func, &thread_index_3);
+
+    printf ("Before turning all three threads loose...\n"); // Set break point at this line.
+
+    // Join all of our threads
+    err = ::pthread_join (g_thread_1, &thread_result);
+    err = ::pthread_join (g_thread_2, &thread_result);
+    err = ::pthread_join (g_thread_3, &thread_result);
+
+    return 0;
+}

Modified: lldb/trunk/tools/debugserver/source/MacOSX/MachThreadList.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachThreadList.cpp?rev=140757&r1=140756&r2=140757&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/MachThreadList.cpp (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/MachThreadList.cpp Wed Sep 28 20:20:42 2011
@@ -99,26 +99,14 @@
     PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
     MachThreadSP thread_sp;
     const size_t num_threads = m_threads.size();
-    if (MachThread::ThreadIDIsValid(tid))
+    for (size_t idx = 0; idx < num_threads; ++idx)
     {
-        for (size_t idx = 0; idx < num_threads; ++idx)
+        if (m_threads[idx]->ThreadID() == tid)
         {
-            if (m_threads[idx]->ThreadID() == tid)
-            {
-                thread_sp = m_threads[idx];
-                break;
-            }
+            thread_sp = m_threads[idx];
+            break;
         }
     }
-    else if (num_threads > 0)
-    {
-        // See DNBWatchpointSet() -> MachProcess::CreateWatchpoint() -> MachProcess::EnableWatchpoint()
-        // -> MachThreadList::EnableHardwareWatchpoint() for a use case of this branch.
-        if (m_current_thread)
-            thread_sp = m_current_thread;
-        else
-            thread_sp = m_threads[0];
-    }
     return thread_sp;
 }
 
@@ -477,14 +465,22 @@
     return false;
 }
 
+// DNBWatchpointSet() -> MachProcess::CreateWatchpoint() -> MachProcess::EnableWatchpoint()
+// -> MachThreadList::EnableHardwareWatchpoint().
 uint32_t
 MachThreadList::EnableHardwareWatchpoint (const DNBBreakpoint* wp) const
 {
     if (wp != NULL)
     {
-        MachThreadSP thread_sp (GetThreadByID (wp->ThreadID()));
-        if (thread_sp)
-            return thread_sp->EnableHardwareWatchpoint(wp);
+        uint32_t hw_index;
+        PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
+        const uint32_t num_threads = m_threads.size();
+        for (uint32_t idx = 0; idx < num_threads; ++idx)
+        {
+            if ((hw_index = m_threads[idx]->EnableHardwareWatchpoint(wp)) == INVALID_NUB_HW_INDEX)
+                return INVALID_NUB_HW_INDEX;
+        }
+        return hw_index;
     }
     return INVALID_NUB_HW_INDEX;
 }
@@ -494,9 +490,14 @@
 {
     if (wp != NULL)
     {
-        MachThreadSP thread_sp (GetThreadByID (wp->ThreadID()));
-        if (thread_sp)
-            return thread_sp->DisableHardwareWatchpoint(wp);
+        PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
+        const uint32_t num_threads = m_threads.size();
+        for (uint32_t idx = 0; idx < num_threads; ++idx)
+        {
+            if (!m_threads[idx]->DisableHardwareWatchpoint(wp))
+                return false;
+        }
+        return true;
     }
     return false;
 }





More information about the lldb-commits mailing list