Index: test/functionalities/thread/create_during_instruction_step/main.cpp =================================================================== --- test/functionalities/thread/create_during_instruction_step/main.cpp +++ /dev/null @@ -1,36 +0,0 @@ -//===-- main.cpp ------------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include -#include - -std::atomic flag(false); - -void do_nothing() -{ - while (flag) - ; -} - -int main () -{ - // Instruction-level stepping over a creation of the first thread takes a very long time, so - // we give the threading machinery a chance to initialize all its data structures. - // This way, stepping over the second thread will be much faster. - std::thread dummy(do_nothing); - dummy.join(); - - // Make sure the new thread does not exit before we get a chance to notice the main thread stopped - flag = true; - - std::thread thread(do_nothing); // Set breakpoint here - flag = false; // Release the new thread. - thread.join(); - return 0; -} Index: test/linux/create_during_instruction_step/Makefile =================================================================== --- test/linux/create_during_instruction_step/Makefile +++ test/linux/create_during_instruction_step/Makefile @@ -1,4 +1,4 @@ -LEVEL = ../../../make +LEVEL = ../../make CXX_SOURCES := main.cpp ENABLE_THREADS := YES Index: test/linux/create_during_instruction_step/TestCreateDuringInstructionStep.py =================================================================== --- test/linux/create_during_instruction_step/TestCreateDuringInstructionStep.py +++ test/linux/create_during_instruction_step/TestCreateDuringInstructionStep.py @@ -16,8 +16,6 @@ def setUp(self): # Call super's setUp(). TestBase.setUp(self) - # Find the line numbers to break and continue. - self.breakpoint = line_number('main.cpp', '// Set breakpoint here') @dsym_test def test_step_inst_with_dsym(self): @@ -25,8 +23,6 @@ self.create_during_step_inst_test() @dwarf_test - @skipIfTargetAndroid(archs=['aarch64']) - @expectedFailureAndroid("llvm.org/pr23944", archs=['aarch64']) # We are unable to step through std::thread::_M_start_thread def test_step_inst_with_dwarf(self): self.buildDwarf(dictionary=self.getBuildFlags()) self.create_during_step_inst_test() @@ -37,7 +33,8 @@ self.assertTrue(target and target.IsValid(), "Target is valid") # This should create a breakpoint in the stepping thread. - self.bp_num = lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.breakpoint, num_expected_locations=-1) + breakpoint = target.BreakpointCreateByName("main") + self.assertTrue(breakpoint and breakpoint.IsValid(), "Breakpoint is valid") # Run the program. process = target.LaunchSimple(None, None, self.get_process_working_directory()) @@ -45,31 +42,19 @@ # The stop reason of the thread should be breakpoint. self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED) - self.assertEqual(lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint).IsValid(), 1, - STOPPED_DUE_TO_BREAKPOINT) - # Get the number of threads - num_threads = process.GetNumThreads() + threads = lldbutil.get_threads_stopped_at_breakpoint(process, breakpoint) + self.assertEquals(len(threads), 1, STOPPED_DUE_TO_BREAKPOINT) - # Make sure we see only one threads - self.assertEqual(num_threads, 1, 'Number of expected threads and actual threads do not match.') - - thread = process.GetThreadAtIndex(0) + thread = threads[0] self.assertTrue(thread and thread.IsValid(), "Thread is valid") + # Make sure we see only one threads + self.assertEqual(process.GetNumThreads(), 1, 'Number of expected threads and actual threads do not match.') + # Keep stepping until we see the thread creation while process.GetNumThreads() < 2: - # This skips some functions we have trouble stepping into. Testing stepping - # through these is not the purpose of this test. We just want to find the - # instruction, which creates the thread. - if thread.GetFrameAtIndex(0).GetFunctionName() in [ - '__sync_fetch_and_add_4', # Android arm: unable to set a breakpoint for software single-step - 'pthread_mutex_lock', # Android arm: function contains atomic instruction sequences - 'pthread_mutex_unlock' # Android arm: function contains atomic instruction sequences - ]: - thread.StepOut() - else: - thread.StepInstruction(False) + thread.StepInstruction(False) self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED) self.assertEqual(thread.GetStopReason(), lldb.eStopReasonPlanComplete, "Step operation succeeded") if self.TraceOn(): Index: test/linux/create_during_instruction_step/main.cpp =================================================================== --- /dev/null +++ test/linux/create_during_instruction_step/main.cpp @@ -0,0 +1,55 @@ +//===-- main.cpp ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// This file deliberately uses low level linux-specific API for thread creation because: +// - instruction-stepping over thread creation using higher-level functions was very slow +// - it was also unreliable due to single-stepping bugs unrelated to this test +// - some threading libraries do not create or destroy threads when we would expect them to + +#include + +#include +#include + +enum { STACK_SIZE = 0x2000 }; + +static uint8_t child_stack[STACK_SIZE]; + +pid_t child_tid; + +std::atomic flag(false); + +int thread_main(void *) +{ + while (! flag) // Make sure the child does not exit prematurely + ; + + return 0; +} + +int main () +{ + int ret = clone(thread_main, + child_stack + STACK_SIZE/2, // Don't care whether the stack grows up or down, + // just point to the middle + CLONE_CHILD_CLEARTID | CLONE_FILES | CLONE_FS | CLONE_PARENT_SETTID | CLONE_SETTLS | + CLONE_SIGHAND | CLONE_SYSVSEM | CLONE_THREAD | CLONE_VM, + nullptr, // thread_main argument + &child_tid); + + if (ret == -1) + { + perror("clone"); + return 1; + } + + flag = true; + + return 0; +}