From 3e9e7d28225fd7d262c660cf19429930d3bc2991 Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Fri, 4 Dec 2015 22:59:41 +0000 Subject: Make TestThreadSpecificBreakpoint.py more focused. This test would fail before if conditional breakpoints weren't working correctly, and the nature of the test (spinning up 10 threads, etc) opens the door to raciness. This patch vastly simplifies the test, removes the need for relying on conditional expression evaluation, and as a result makes the correctness of the test vastly easier to reason about and reduces flakiness. Differential Revision: http://reviews.llvm.org/D15241 Reviewed By: Jim Ingham llvm-svn: 254792 --- .../TestThreadSpecificBreakpoint.py | 51 +++++++++-------- .../thread/thread_specific_break/main.cpp | 35 +++--------- .../thread_specific_break_plus_condition/Makefile | 6 ++ .../TestThreadSpecificBpPlusCondition.py | 65 ++++++++++++++++++++++ .../thread_specific_break_plus_condition/main.cpp | 39 +++++++++++++ 5 files changed, 143 insertions(+), 53 deletions(-) create mode 100644 lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/Makefile create mode 100644 lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/TestThreadSpecificBpPlusCondition.py create mode 100644 lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/main.cpp (limited to 'lldb/packages/Python/lldbsuite/test/functionalities/thread') diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/TestThreadSpecificBreakpoint.py b/lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/TestThreadSpecificBreakpoint.py index e02394f075a..3c69b6667f7 100644 --- a/lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/TestThreadSpecificBreakpoint.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/TestThreadSpecificBreakpoint.py @@ -16,49 +16,48 @@ class ThreadSpecificBreakTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) - @skipIfFreeBSD # test frequently times out or hangs - @expectedFailureFreeBSD('llvm.org/pr18522') # hits break in another thread in testrun @add_test_categories(['pyapi']) - @expectedFlakeyLinux # this test fails 6/100 dosep runs + @expectedFailureWindows # Thread specific breakpoints cause the inferior to crash def test_python(self): """Test that we obey thread conditioned breakpoints.""" self.build() exe = os.path.join(os.getcwd(), "a.out") - self.dbg.HandleCommand ("log enable -f /tmp/lldb-testsuite-log.txt lldb step breakpoint process") target = self.dbg.CreateTarget(exe) self.assertTrue(target, VALID_TARGET) + # This test works by setting a breakpoint in a function conditioned to stop only on + # the main thread, and then calling this function on a secondary thread, joining, + # and then calling again on the main thread. If the thread specific breakpoint works + # then it should not be hit on the secondary thread, only on the main thread. + main_source_spec = lldb.SBFileSpec ("main.cpp") - # Set a breakpoint in the thread body, and make it active for only the first thread. - break_thread_body = target.BreakpointCreateBySourceRegex ("Break here in thread body.", main_source_spec) - self.assertTrue (break_thread_body.IsValid() and break_thread_body.GetNumLocations() > 0, "Failed to set thread body breakpoint.") + main_breakpoint = target.BreakpointCreateBySourceRegex("Set main breakpoint here", main_source_spec); + thread_breakpoint = target.BreakpointCreateBySourceRegex("Set thread-specific breakpoint here", main_source_spec) + + self.assertTrue(main_breakpoint.IsValid(), "Failed to set main breakpoint.") + self.assertGreater(main_breakpoint.GetNumLocations(), 0, "main breakpoint has no locations associated with it.") + self.assertTrue(thread_breakpoint.IsValid(), "Failed to set thread breakpoint.") + self.assertGreater(thread_breakpoint.GetNumLocations(), 0, "thread breakpoint has no locations associated with it.") process = target.LaunchSimple (None, None, self.get_process_working_directory()) self.assertTrue(process, PROCESS_IS_VALID) - threads = lldbutil.get_threads_stopped_at_breakpoint (process, break_thread_body) - - victim_thread = threads[0] - - # Pick one of the threads, and change the breakpoint so it ONLY stops for this thread, - # but add a condition that it won't stop for this thread's my_value. The other threads - # pass the condition, so they should stop, but if the thread-specification is working - # they should not stop. So nobody should hit the breakpoint anymore, and we should - # just exit cleanly. + stopped_threads = lldbutil.get_threads_stopped_at_breakpoint(process, main_breakpoint) + self.assertEqual(len(stopped_threads), 1, "main breakpoint stopped at unexpected number of threads") + main_thread = stopped_threads[0] + main_thread_id = main_thread.GetThreadID() - frame = victim_thread.GetFrameAtIndex(0) - value = frame.FindVariable("my_value").GetValueAsSigned(0) - self.assertTrue (value > 0 and value < 11, "Got a reasonable value for my_value.") - - cond_string = "my_value != %d"%(value) - - break_thread_body.SetThreadID(victim_thread.GetThreadID()) - break_thread_body.SetCondition (cond_string) + # Set the thread-specific breakpoint to only stop on the main thread. The run the function + # on another thread and join on it. If the thread-specific breakpoint works, the next + # stop should be on the main thread. + thread_breakpoint.SetThreadID(main_thread_id) process.Continue() - next_stop_state = process.GetState() - self.assertTrue (next_stop_state == lldb.eStateExited, "We should have not hit the breakpoint again.") + self.assertEqual(next_stop_state, lldb.eStateStopped, "We should have stopped at the thread breakpoint.") + stopped_threads = lldbutil.get_threads_stopped_at_breakpoint(process, thread_breakpoint) + self.assertEqual(len(stopped_threads), 1, "thread breakpoint stopped at unexpected number of threads") + self.assertEqual(stopped_threads[0].GetThreadID(), main_thread_id, "thread breakpoint stopped at the wrong thread") diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/main.cpp b/lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/main.cpp index af8ab84157f..7721b5d8432 100644 --- a/lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/main.cpp +++ b/lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/main.cpp @@ -1,39 +1,20 @@ #include #include -#include -void * -thread_function (void *thread_marker) +void +thread_function () { - int keep_going = 1; - int my_value = *((int *)thread_marker); - int counter = 0; - - while (counter < 20) - { - counter++; // Break here in thread body. - std::this_thread::sleep_for(std::chrono::microseconds(10)); - } - return NULL; + // Set thread-specific breakpoint here. + std::this_thread::sleep_for(std::chrono::microseconds(100)); } - int main () { - std::vector threads; - - int thread_value = 0; - int i; - - for (i = 0; i < 10; i++) - { - thread_value += 1; - threads.push_back(std::thread(thread_function, &thread_value)); - } - - for (i = 0; i < 10; i++) - threads[i].join(); + // Set main breakpoint here. + std::thread t(thread_function); + t.join(); + thread_function(); return 0; } diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/Makefile b/lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/Makefile new file mode 100644 index 00000000000..035413ff763 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/Makefile @@ -0,0 +1,6 @@ +LEVEL = ../../../make + +CXX_SOURCES := main.cpp +ENABLE_THREADS := YES + +include $(LEVEL)/Makefile.rules diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/TestThreadSpecificBpPlusCondition.py b/lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/TestThreadSpecificBpPlusCondition.py new file mode 100644 index 00000000000..b4a0b7a5dd4 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/TestThreadSpecificBpPlusCondition.py @@ -0,0 +1,65 @@ +""" +Test that we obey thread conditioned breakpoints and expression +conditioned breakpoints simultaneously +""" + +from __future__ import print_function + + + +import os, time +import re +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * + +class ThreadSpecificBreakPlusConditionTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipIfFreeBSD # test frequently times out or hangs + @expectedFailureFreeBSD('llvm.org/pr18522') # hits break in another thread in testrun + @add_test_categories(['pyapi']) + @expectedFailureWindows # Thread specific breakpoints cause the inferior to crash. + @expectedFlakeyLinux # this test fails 6/100 dosep runs + def test_python(self): + """Test that we obey thread conditioned breakpoints.""" + self.build() + exe = os.path.join(os.getcwd(), "a.out") + + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + main_source_spec = lldb.SBFileSpec ("main.cpp") + + # Set a breakpoint in the thread body, and make it active for only the first thread. + break_thread_body = target.BreakpointCreateBySourceRegex ("Break here in thread body.", main_source_spec) + self.assertTrue (break_thread_body.IsValid() and break_thread_body.GetNumLocations() > 0, "Failed to set thread body breakpoint.") + + process = target.LaunchSimple (None, None, self.get_process_working_directory()) + + self.assertTrue(process, PROCESS_IS_VALID) + + threads = lldbutil.get_threads_stopped_at_breakpoint (process, break_thread_body) + + victim_thread = threads[0] + + # Pick one of the threads, and change the breakpoint so it ONLY stops for this thread, + # but add a condition that it won't stop for this thread's my_value. The other threads + # pass the condition, so they should stop, but if the thread-specification is working + # they should not stop. So nobody should hit the breakpoint anymore, and we should + # just exit cleanly. + + frame = victim_thread.GetFrameAtIndex(0) + value = frame.FindVariable("my_value").GetValueAsSigned(0) + self.assertTrue (value > 0 and value < 11, "Got a reasonable value for my_value.") + + cond_string = "my_value != %d"%(value) + + break_thread_body.SetThreadID(victim_thread.GetThreadID()) + break_thread_body.SetCondition (cond_string) + + process.Continue() + + next_stop_state = process.GetState() + self.assertTrue (next_stop_state == lldb.eStateExited, "We should have not hit the breakpoint again.") diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/main.cpp b/lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/main.cpp new file mode 100644 index 00000000000..af8ab84157f --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/main.cpp @@ -0,0 +1,39 @@ +#include +#include +#include + +void * +thread_function (void *thread_marker) +{ + int keep_going = 1; + int my_value = *((int *)thread_marker); + int counter = 0; + + while (counter < 20) + { + counter++; // Break here in thread body. + std::this_thread::sleep_for(std::chrono::microseconds(10)); + } + return NULL; +} + + +int +main () +{ + std::vector threads; + + int thread_value = 0; + int i; + + for (i = 0; i < 10; i++) + { + thread_value += 1; + threads.push_back(std::thread(thread_function, &thread_value)); + } + + for (i = 0; i < 10; i++) + threads[i].join(); + + return 0; +} -- cgit v1.2.3