Summary:
Around a third of our test sources have LLVM license headers. This patch removes those headers from all test
sources and also fixes any tests that depended on the length of the license header.
The reasons for this are:
* A few tests verify line numbers and will start failing if the number of lines in the LLVM license header changes. Once I landed my patch for valid SourceLocations in debug info we will probably have even more tests that verify line numbers.
* No other LLVM project is putting license headers in its test files to my knowledge.
* They make the test sources much more verbose than they have to be. Several tests have longer license headers than the actual test source.
For the record, the following tests had their line numbers changed to pass with the removal of the license header:
lldb-api :: functionalities/breakpoint/breakpoint_by_line_and_column/TestBreakpointByLineAndColumn.py
lldb-shell :: Reproducer/TestGDBRemoteRepro.test
lldb-shell :: Reproducer/TestMultipleTargets.test
lldb-shell :: Reproducer/TestReuseDirectory.test
lldb-shell :: ExecControl/StopHook/stop-hook-threads.test
lldb-shell :: ExecControl/StopHook/stop-hook.test
lldb-api :: lang/objc/exceptions/TestObjCExceptions.py
Reviewers: #lldb, espindola, JDevlieghere
Reviewed By: #lldb, JDevlieghere
Subscribers: emaste, aprantl, arphaman, JDevlieghere, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D74839
180 lines
5.2 KiB
C++
180 lines
5.2 KiB
C++
// This test is intended to create a situation in which multiple events
|
|
// (breakpoints, watchpoints, crashes, and signal generation/delivery) happen
|
|
// from multiple threads. The test expects the debugger to set a breakpoint on
|
|
// the main thread (before any worker threads are spawned) and modify variables
|
|
// which control the number of threads that are spawned for each action.
|
|
|
|
#include "pseudo_barrier.h"
|
|
#include <vector>
|
|
using namespace std;
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <signal.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
typedef std::vector<std::pair<unsigned, void*(*)(void*)> > action_counts;
|
|
typedef std::vector<pthread_t> thread_vector;
|
|
|
|
pseudo_barrier_t g_barrier;
|
|
int g_breakpoint = 0;
|
|
int g_sigusr1_count = 0;
|
|
uint32_t g_watchme;
|
|
|
|
struct action_args {
|
|
int delay;
|
|
};
|
|
|
|
// Perform any extra actions required by thread 'input' arg
|
|
void do_action_args(void *input) {
|
|
if (input) {
|
|
action_args *args = static_cast<action_args*>(input);
|
|
sleep(args->delay);
|
|
}
|
|
}
|
|
|
|
void *
|
|
breakpoint_func (void *input)
|
|
{
|
|
// Wait until all threads are running
|
|
pseudo_barrier_wait(g_barrier);
|
|
do_action_args(input);
|
|
|
|
// Do something
|
|
g_breakpoint++; // Set breakpoint here
|
|
return 0;
|
|
}
|
|
|
|
void *
|
|
signal_func (void *input) {
|
|
// Wait until all threads are running
|
|
pseudo_barrier_wait(g_barrier);
|
|
do_action_args(input);
|
|
|
|
// Send a user-defined signal to the current process
|
|
//kill(getpid(), SIGUSR1);
|
|
// Send a user-defined signal to the current thread
|
|
pthread_kill(pthread_self(), SIGUSR1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void *
|
|
watchpoint_func (void *input) {
|
|
pseudo_barrier_wait(g_barrier);
|
|
do_action_args(input);
|
|
|
|
g_watchme = 1; // watchpoint triggers here
|
|
return 0;
|
|
}
|
|
|
|
void *
|
|
crash_func (void *input) {
|
|
pseudo_barrier_wait(g_barrier);
|
|
do_action_args(input);
|
|
|
|
int *a = 0;
|
|
*a = 5; // crash happens here
|
|
return 0;
|
|
}
|
|
|
|
void sigusr1_handler(int sig) {
|
|
if (sig == SIGUSR1)
|
|
g_sigusr1_count += 1; // Break here in signal handler
|
|
}
|
|
|
|
/// Register a simple function for to handle signal
|
|
void register_signal_handler(int signal, void (*handler)(int))
|
|
{
|
|
sigset_t empty_sigset;
|
|
sigemptyset(&empty_sigset);
|
|
|
|
struct sigaction action;
|
|
action.sa_sigaction = 0;
|
|
action.sa_mask = empty_sigset;
|
|
action.sa_flags = 0;
|
|
action.sa_handler = handler;
|
|
sigaction(SIGUSR1, &action, 0);
|
|
}
|
|
|
|
void start_threads(thread_vector& threads,
|
|
action_counts& actions,
|
|
void* args = 0) {
|
|
action_counts::iterator b = actions.begin(), e = actions.end();
|
|
for(action_counts::iterator i = b; i != e; ++i) {
|
|
for(unsigned count = 0; count < i->first; ++count) {
|
|
pthread_t t;
|
|
pthread_create(&t, 0, i->second, args);
|
|
threads.push_back(t);
|
|
}
|
|
}
|
|
}
|
|
|
|
int dotest()
|
|
{
|
|
g_watchme = 0;
|
|
|
|
// Actions are triggered immediately after the thread is spawned
|
|
unsigned num_breakpoint_threads = 1;
|
|
unsigned num_watchpoint_threads = 0;
|
|
unsigned num_signal_threads = 1;
|
|
unsigned num_crash_threads = 0;
|
|
|
|
// Actions below are triggered after a 1-second delay
|
|
unsigned num_delay_breakpoint_threads = 0;
|
|
unsigned num_delay_watchpoint_threads = 0;
|
|
unsigned num_delay_signal_threads = 0;
|
|
unsigned num_delay_crash_threads = 0;
|
|
|
|
register_signal_handler(SIGUSR1, sigusr1_handler); // Break here and adjust num_[breakpoint|watchpoint|signal|crash]_threads
|
|
|
|
unsigned total_threads = num_breakpoint_threads \
|
|
+ num_watchpoint_threads \
|
|
+ num_signal_threads \
|
|
+ num_crash_threads \
|
|
+ num_delay_breakpoint_threads \
|
|
+ num_delay_watchpoint_threads \
|
|
+ num_delay_signal_threads \
|
|
+ num_delay_crash_threads;
|
|
|
|
// Don't let either thread do anything until they're both ready.
|
|
pseudo_barrier_init(g_barrier, total_threads);
|
|
|
|
action_counts actions;
|
|
actions.push_back(std::make_pair(num_breakpoint_threads, breakpoint_func));
|
|
actions.push_back(std::make_pair(num_watchpoint_threads, watchpoint_func));
|
|
actions.push_back(std::make_pair(num_signal_threads, signal_func));
|
|
actions.push_back(std::make_pair(num_crash_threads, crash_func));
|
|
|
|
action_counts delay_actions;
|
|
delay_actions.push_back(std::make_pair(num_delay_breakpoint_threads, breakpoint_func));
|
|
delay_actions.push_back(std::make_pair(num_delay_watchpoint_threads, watchpoint_func));
|
|
delay_actions.push_back(std::make_pair(num_delay_signal_threads, signal_func));
|
|
delay_actions.push_back(std::make_pair(num_delay_crash_threads, crash_func));
|
|
|
|
// Create threads that handle instant actions
|
|
thread_vector threads;
|
|
start_threads(threads, actions);
|
|
|
|
// Create threads that handle delayed actions
|
|
action_args delay_arg;
|
|
delay_arg.delay = 1;
|
|
start_threads(threads, delay_actions, &delay_arg);
|
|
|
|
// Join all threads
|
|
typedef std::vector<pthread_t>::iterator thread_iterator;
|
|
for(thread_iterator t = threads.begin(); t != threads.end(); ++t)
|
|
pthread_join(*t, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main ()
|
|
{
|
|
dotest();
|
|
return 0; // Break here and verify one thread is active.
|
|
}
|
|
|
|
|