Michał Górny 9790406a92 Reland "[lldb] [test] Improve stability of llgs vCont-threads tests"
Perform a major refactoring of vCont-threads tests in order to attempt
to improve their stability and performance.

Split test_vCont_run_subset_of_threads() into smaller test cases,
and split the whole suite into two files: one for signal-related tests,
the running-subset-of tests.

Eliminate output_match checks entirely, as they are fragile to
fragmentation of output.  Instead, for the initial thread list capture
raise an explicit SIGINT from inside the test program, and for
the remaining output let the test program run until exit, and check all
the captured output afterwards.

For resume tests, capture the LLDB's thread view before and after
starting new threads in order to determine the IDs corresponding
to subthreads rather than relying on program output for that.

Add a mutex for output to guarantee serialization.  A barrier is used
to guarantee that all threads start before SIGINT, and an atomic bool
is used to delay prints from happening until after SIGINT.

Call std::this_thread::yield() to reduce the risk of one of the threads
not being run.

This fixes the test hangs on FreeBSD.  Hopefully, it will also fix all
the flakiness on buildbots.

Thanks to Pavel Labath for figuring out why the original version did not
work on Debian.

Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.llvm.org/D129012
2022-07-11 18:05:14 +02:00

129 lines
4.7 KiB
Python

import re
import gdbremote_testcase
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
class TestPartialResume(gdbremote_testcase.GdbRemoteTestCaseBase):
THREAD_MATCH_RE = re.compile(r"thread ([0-9a-f]+) running")
def start_vCont_run_subset_of_threads_test(self):
self.build()
self.set_inferior_startup_launch()
procs = self.prep_debug_monitor_and_inferior(inferior_args=["3"])
# grab the main thread id
self.add_threadinfo_collection_packets()
main_thread = self.parse_threadinfo_packets(
self.expect_gdbremote_sequence())
self.assertEqual(len(main_thread), 1)
self.reset_test_sequence()
# run until threads start, then grab full thread list
self.test_sequence.add_log_lines([
"read packet: $c#63",
{"direction": "send", "regex": "[$]T.*;reason:signal.*"},
], True)
self.add_threadinfo_collection_packets()
all_threads = self.parse_threadinfo_packets(
self.expect_gdbremote_sequence())
self.assertEqual(len(all_threads), 4)
self.assertIn(main_thread[0], all_threads)
self.reset_test_sequence()
all_subthreads = set(all_threads) - set(main_thread)
self.assertEqual(len(all_subthreads), 3)
return (main_thread[0], list(all_subthreads))
def continue_and_get_threads_running(self, main_thread, vCont_req):
self.test_sequence.add_log_lines(
["read packet: $vCont;c:{:x};{}#00".format(main_thread, vCont_req),
"send packet: $W00#00",
], True)
exp = self.expect_gdbremote_sequence()
self.reset_test_sequence()
found = set()
for line in exp["O_content"].decode().splitlines():
m = self.THREAD_MATCH_RE.match(line)
if m is not None:
found.add(int(m.group(1), 16))
return found
@skipIfWindows
@add_test_categories(["llgs"])
def test_vCont_cxcx(self):
main_thread, all_subthreads_list = (
self.start_vCont_run_subset_of_threads_test())
# resume two threads explicitly, stop the third one implicitly
self.assertEqual(
self.continue_and_get_threads_running(
main_thread,
"c:{:x};c:{:x}".format(*all_subthreads_list[:2])),
set(all_subthreads_list[:2]))
@skipIfWindows
@add_test_categories(["llgs"])
def test_vCont_cxcxt(self):
main_thread, all_subthreads_list = (
self.start_vCont_run_subset_of_threads_test())
# resume two threads explicitly, stop others explicitly
self.assertEqual(
self.continue_and_get_threads_running(
main_thread,
"c:{:x};c:{:x};t".format(*all_subthreads_list[:2])),
set(all_subthreads_list[:2]))
@skipIfWindows
@add_test_categories(["llgs"])
def test_vCont_txc(self):
main_thread, all_subthreads_list = (
self.start_vCont_run_subset_of_threads_test())
# stop one thread explicitly, resume others
self.assertEqual(
self.continue_and_get_threads_running(
main_thread,
"t:{:x};c".format(all_subthreads_list[-1])),
set(all_subthreads_list[:2]))
@skipIfWindows
@add_test_categories(["llgs"])
def test_vCont_cxtxc(self):
main_thread, all_subthreads_list = (
self.start_vCont_run_subset_of_threads_test())
# resume one thread explicitly, stop one explicitly,
# resume others
self.assertEqual(
self.continue_and_get_threads_running(
main_thread,
"c:{:x};t:{:x};c".format(*all_subthreads_list[-2:])),
set(all_subthreads_list[:2]))
@skipIfWindows
@add_test_categories(["llgs"])
def test_vCont_txcx(self):
main_thread, all_subthreads_list = (
self.start_vCont_run_subset_of_threads_test())
# resume one thread explicitly, stop one explicitly,
# stop others implicitly
self.assertEqual(
self.continue_and_get_threads_running(
main_thread,
"t:{:x};c:{:x}".format(*all_subthreads_list[:2])),
set(all_subthreads_list[1:2]))
@skipIfWindows
@add_test_categories(["llgs"])
def test_vCont_txcxt(self):
main_thread, all_subthreads_list = (
self.start_vCont_run_subset_of_threads_test())
# resume one thread explicitly, stop one explicitly,
# stop others explicitly
self.assertEqual(
self.continue_and_get_threads_running(
main_thread,
"t:{:x};c:{:x};t".format(*all_subthreads_list[:2])),
set(all_subthreads_list[1:2]))