Skip to content

Commit

Permalink
Revert "[lldb] [test] Improve stability of llgs vCont-threads tests"
Browse files Browse the repository at this point in the history
This reverts commit 86e4723.
It breaks Debian buildbot, for some reason.
  • Loading branch information
mgorny committed Jul 7, 2022
1 parent cab44c5 commit fad93cd
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 175 deletions.
@@ -1,18 +1,23 @@
import json
import re
import time

import gdbremote_testcase
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil

class TestGdbRemote_vContThreads(gdbremote_testcase.GdbRemoteTestCaseBase):

class TestSignal(gdbremote_testcase.GdbRemoteTestCaseBase):
def start_threads(self, num):
procs = self.prep_debug_monitor_and_inferior(inferior_args=[str(num)])
# start the process and wait for output
self.test_sequence.add_log_lines([
"read packet: $c#63",
{"direction": "send", "regex": "[$]T.*;reason:signal.*"},
{"type": "output_match", "regex": r".*@started\r\n.*"},
], True)
# then interrupt it
self.add_interrupt_packets()
self.add_threadinfo_collection_packets()

context = self.expect_gdbremote_sequence()
Expand All @@ -24,21 +29,22 @@ def start_threads(self, num):
self.reset_test_sequence()
return threads

SIGNAL_MATCH_RE = re.compile(r"received SIGUSR1 on thread id: ([0-9a-f]+)")

def send_and_check_signal(self, vCont_data, threads):
self.test_sequence.add_log_lines([
"read packet: $vCont;{0}#00".format(vCont_data),
"send packet: $W00#00",
{"type": "output_match",
"regex": len(threads) *
r".*received SIGUSR1 on thread id: ([0-9a-f]+)\r\n.*",
"capture": dict((i, "tid{0}".format(i)) for i
in range(1, len(threads)+1)),
},
], True)
exp = self.expect_gdbremote_sequence()
self.reset_test_sequence()
tids = []
for line in exp["O_content"].decode().splitlines():
m = self.SIGNAL_MATCH_RE.match(line)
if m is not None:
tids.append(int(m.group(1), 16))
self.assertEqual(sorted(tids), sorted(threads))

context = self.expect_gdbremote_sequence()
self.assertIsNotNone(context)
tids = sorted(int(context["tid{0}".format(x)], 16)
for x in range(1, len(threads)+1))
self.assertEqual(tids, sorted(threads))

def get_pid(self):
self.add_process_info_collection_packets()
Expand Down Expand Up @@ -236,3 +242,72 @@ def test_signal_two_signals(self):

context = self.expect_gdbremote_sequence()
self.assertIsNotNone(context)

THREAD_MATCH_RE = re.compile(r"thread ([0-9a-f]+) running")

def continue_and_get_threads_running(self, continue_packet):
self.test_sequence.add_log_lines(
["read packet: ${}#00".format(continue_packet),
], True)
self.expect_gdbremote_sequence()
self.reset_test_sequence()
time.sleep(1)
self.add_interrupt_packets()
exp = self.expect_gdbremote_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_run_subset_of_threads(self):
self.build()
self.set_inferior_startup_launch()

threads = set(self.start_threads(3))
all_subthreads = self.continue_and_get_threads_running("c")
all_subthreads_list = list(all_subthreads)
self.assertEqual(len(all_subthreads), 3)
self.assertEqual(threads & all_subthreads, all_subthreads)

# resume two threads explicitly, stop the third one implicitly
self.assertEqual(
self.continue_and_get_threads_running(
"vCont;c:{:x};c:{:x}".format(*all_subthreads_list[:2])),
set(all_subthreads_list[:2]))

# resume two threads explicitly, stop others explicitly
self.assertEqual(
self.continue_and_get_threads_running(
"vCont;c:{:x};c:{:x};t".format(*all_subthreads_list[:2])),
set(all_subthreads_list[:2]))

# stop one thread explicitly, resume others
self.assertEqual(
self.continue_and_get_threads_running(
"vCont;t:{:x};c".format(all_subthreads_list[-1])),
set(all_subthreads_list[:2]))

# resume one thread explicitly, stop one explicitly,
# resume others
self.assertEqual(
self.continue_and_get_threads_running(
"vCont;c:{:x};t:{:x};c".format(*all_subthreads_list[-2:])),
set(all_subthreads_list[:2]))

# resume one thread explicitly, stop one explicitly,
# stop others implicitly
self.assertEqual(
self.continue_and_get_threads_running(
"vCont;t:{:x};c:{:x}".format(*all_subthreads_list[:2])),
set(all_subthreads_list[1:2]))

# resume one thread explicitly, stop one explicitly,
# stop others explicitly
self.assertEqual(
self.continue_and_get_threads_running(
"vCont;t:{:x};c:{:x};t".format(*all_subthreads_list[:2])),
set(all_subthreads_list[1:2]))
128 changes: 0 additions & 128 deletions lldb/test/API/tools/lldb-server/vCont-threads/TestPartialResume.py

This file was deleted.

42 changes: 8 additions & 34 deletions lldb/test/API/tools/lldb-server/vCont-threads/main.cpp
@@ -1,54 +1,31 @@
#include "pseudo_barrier.h"
#include "thread.h"
#include <atomic>
#include <chrono>
#include <cinttypes>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <mutex>
#include <thread>
#include <unistd.h>
#include <vector>

pseudo_barrier_t barrier;
std::mutex print_mutex;
std::atomic<bool> can_work = ATOMIC_VAR_INIT(false);
thread_local volatile sig_atomic_t can_exit_now = false;

static void sigusr1_handler(int signo) {
std::lock_guard<std::mutex> lock{print_mutex};
std::printf("received SIGUSR1 on thread id: %" PRIx64 "\n", get_thread_id());
can_exit_now = true;
char buf[100];
std::snprintf(buf, sizeof(buf),
"received SIGUSR1 on thread id: %" PRIx64 "\n",
get_thread_id());
write(STDOUT_FILENO, buf, strlen(buf));
}

static void thread_func() {
// this ensures that all threads start before we SIGSTOP
pseudo_barrier_wait(barrier);

// wait till the main thread indicates that we can go
// (note: using a mutex here causes hang on FreeBSD when another thread
// is suspended)
while (!can_work.load())
std::this_thread::sleep_for(std::chrono::milliseconds(50));

// the mutex guarantees that two writes don't get interspersed
{
std::lock_guard<std::mutex> lock{print_mutex};
for (int i = 0; i < 300; ++i) {
std::printf("thread %" PRIx64 " running\n", get_thread_id());
}

// give other threads a fair chance to run
for (int i = 0; i < 5; ++i) {
std::this_thread::yield();
std::this_thread::sleep_for(std::chrono::milliseconds(200));
if (can_exit_now)
return;
}

// if we didn't get signaled, terminate the program explicitly.
_exit(0);
}

int main(int argc, char **argv) {
Expand All @@ -59,15 +36,12 @@ int main(int argc, char **argv) {
signal(SIGUSR1, sigusr1_handler);

std::vector<std::thread> threads;
for (int i = 0; i < num; ++i)
for(int i = 0; i < num; ++i)
threads.emplace_back(thread_func);

// use the barrier to make sure all threads start before we SIGSTOP
pseudo_barrier_wait(barrier);
std::raise(SIGSTOP);

// allow the threads to work
can_work.store(true);
std::puts("@started");

for (std::thread &thread : threads)
thread.join();
Expand Down

0 comments on commit fad93cd

Please sign in to comment.