[Lldb-commits] [lldb] r141144 - in /lldb/trunk: include/lldb/Interpreter/CommandInterpreter.h source/Interpreter/CommandInterpreter.cpp test/functionalities/stop-hook/multiple_threads/ test/functionalities/stop-hook/multiple_threads/Makefile test/functionalities/stop-hook/multiple_threads/TestStopHookMultipleThreads.py test/functionalities/stop-hook/multiple_threads/main.cpp

Johnny Chen johnny.chen at apple.com
Tue Oct 4 17:43:00 PDT 2011


Author: johnny
Date: Tue Oct  4 19:42:59 2011
New Revision: 141144

URL: http://llvm.org/viewvc/llvm-project?rev=141144&view=rev
Log:
Fix a problem where the stop-hook command 'frame variable g_val' produces nothing
when newly created threads were subsequently stopped due to breakpoint hit.
The stop-hook mechanism delegates to CommandInterpreter::HandleCommands() to
execuet the commands.  Make sure the execution context is switched only once
at the beginning of HandleCommands() only and don't update the context while looping
on each individual command to be executed.

rdar://problem/10228156

Added:
    lldb/trunk/test/functionalities/stop-hook/multiple_threads/
    lldb/trunk/test/functionalities/stop-hook/multiple_threads/Makefile
    lldb/trunk/test/functionalities/stop-hook/multiple_threads/TestStopHookMultipleThreads.py
    lldb/trunk/test/functionalities/stop-hook/multiple_threads/main.cpp
Modified:
    lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h
    lldb/trunk/source/Interpreter/CommandInterpreter.cpp

Modified: lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h?rev=141144&r1=141143&r2=141144&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h (original)
+++ lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h Tue Oct  4 19:42:59 2011
@@ -147,7 +147,8 @@
                    bool add_to_history, 
                    CommandReturnObject &result, 
                    ExecutionContext *override_context = NULL,
-                   bool repeat_on_empty_command = true);
+                   bool repeat_on_empty_command = true,
+                   bool no_context_switching = false);
     
     //------------------------------------------------------------------
     /// Execute a list of commands in sequence.

Modified: lldb/trunk/source/Interpreter/CommandInterpreter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/CommandInterpreter.cpp?rev=141144&r1=141143&r2=141144&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/CommandInterpreter.cpp (original)
+++ lldb/trunk/source/Interpreter/CommandInterpreter.cpp Tue Oct  4 19:42:59 2011
@@ -952,7 +952,8 @@
                                    bool add_to_history,
                                    CommandReturnObject &result,
                                    ExecutionContext *override_context,
-                                   bool repeat_on_empty_command)
+                                   bool repeat_on_empty_command,
+                                   bool no_context_switching)
 
 {
 
@@ -975,7 +976,8 @@
 
     Timer scoped_timer (__PRETTY_FUNCTION__, "Handling command: %s.", command_line);
     
-    UpdateExecutionContext (override_context);
+    if (!no_context_switching)
+        UpdateExecutionContext (override_context);
 
     bool empty_command = false;
     bool comment_command = false;
@@ -1911,7 +1913,12 @@
         }
 
         CommandReturnObject tmp_result;
-        bool success = HandleCommand(cmd, false, tmp_result, NULL);
+        // If override_context is not NULL, pass no_context_switching = true for
+        // HandleCommand() since we updated our context already.
+        bool success = HandleCommand(cmd, false, tmp_result,
+                                     NULL, /* override_context */
+                                     true, /* repeat_on_empty_command */
+                                     override_context != NULL /* no_context_switching */);
         
         if (print_results)
         {

Added: lldb/trunk/test/functionalities/stop-hook/multiple_threads/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/stop-hook/multiple_threads/Makefile?rev=141144&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/stop-hook/multiple_threads/Makefile (added)
+++ lldb/trunk/test/functionalities/stop-hook/multiple_threads/Makefile Tue Oct  4 19:42:59 2011
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/test/functionalities/stop-hook/multiple_threads/TestStopHookMultipleThreads.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/stop-hook/multiple_threads/TestStopHookMultipleThreads.py?rev=141144&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/stop-hook/multiple_threads/TestStopHookMultipleThreads.py (added)
+++ lldb/trunk/test/functionalities/stop-hook/multiple_threads/TestStopHookMultipleThreads.py Tue Oct  4 19:42:59 2011
@@ -0,0 +1,74 @@
+"""
+Test that lldb stop-hook works for multiple threads.
+"""
+
+import os, time
+import unittest2
+import lldb
+import pexpect
+from lldbtest import *
+
+class StopHookForMultipleThreadsTestCase(TestBase):
+
+    mydir = os.path.join("functionalities", "stop-hook", "multiple_threads")
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    def test_stop_hook_multiple_threads_with_dsym(self):
+        """Test that lldb stop-hook works for multiple threads."""
+        self.buildDsym(dictionary=self.d)
+        self.setTearDownCleanup(dictionary=self.d)
+        self.stop_hook_multiple_threads()
+
+    def test_stop_hook_multiple_threads_with_dwarf(self):
+        """Test that lldb stop-hook works for multiple threads."""
+        self.buildDwarf(dictionary=self.d)
+        self.setTearDownCleanup(dictionary=self.d)
+        self.stop_hook_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.first_stop = line_number(self.source, '// Set break point at this line, and add a stop-hook.')
+        self.thread_function = line_number(self.source, '// Break here to test that the stop-hook mechanism works for multiple threads.')
+        # 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 stop_hook_multiple_threads(self):
+        """Test that lldb stop-hook works for multiple threads."""
+        exe = os.path.join(os.getcwd(), self.exe_name)
+        prompt = "(lldb) "
+
+        # So that the child gets torn down after the test.
+        self.child = pexpect.spawn('%s %s' % (self.lldbHere, exe))
+        child = self.child
+        # Turn on logging for what the child sends back.
+        if self.TraceOn():
+            child.logfile_read = sys.stdout
+
+        # Set the breakpoint, followed by the target stop-hook commands.
+        child.expect_exact(prompt)
+        child.sendline('breakpoint set -f main.cpp -l %d' % self.first_stop)
+        child.expect_exact(prompt)
+        child.sendline('breakpoint set -f main.cpp -l %d' % self.thread_function)
+        child.expect_exact(prompt)
+
+        # Now run the program, expect to stop at the the first breakpoint which is within the stop-hook range.
+        child.sendline('run')
+        child.expect_exact(prompt)
+        child.sendline('target stop-hook add -o "frame variable -g g_val"')
+        child.expect_exact(prompt)
+
+        # Continue and expect to find the output emitted by the firing of our stop hook.
+        child.sendline('continue')
+        child.expect_exact('(uint32_t) g_val = ')
+
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/functionalities/stop-hook/multiple_threads/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/stop-hook/multiple_threads/main.cpp?rev=141144&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/stop-hook/multiple_threads/main.cpp (added)
+++ lldb/trunk/test/functionalities/stop-hook/multiple_threads/main.cpp Tue Oct  4 19:42:59 2011
@@ -0,0 +1,88 @@
+//===-- 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); // Break here to test that the stop-hook mechanism works for multiple threads.
+    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;
+
+    printf ("Before turning all three threads loose...\n"); // Set break point at this line, and add a stop-hook.
+    // 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);
+
+    // 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;
+}





More information about the lldb-commits mailing list