This is the mail archive of the
gdb@sourceware.org
mailing list for the GDB project.
Re: GDB hangs when calling inferior functions
- From: Stephen Roberts <Stephen dot Roberts at arm dot com>
- To: Pedro Alves <palves at redhat dot com>, "gdb at sourceware dot org" <gdb at sourceware dot org>
- Cc: nd <nd at arm dot com>
- Date: Thu, 12 Oct 2017 13:33:13 +0000
- Subject: Re: GDB hangs when calling inferior functions
- Authentication-results: sourceware.org; auth=none
- Authentication-results: spf=none (sender IP is ) smtp.mailfrom=Stephen dot Roberts at arm dot com;
- Nodisclaimer: True
- References: <AM3PR08MB0625702F3F55B3A3C6A59031FB4A0@AM3PR08MB0625.eurprd08.prod.outlook.com>,<3b857cc7-e722-f10f-7fea-c3928cc0ac36@redhat.com>
- Spamdiagnosticmetadata: NSPM
- Spamdiagnosticoutput: 1:99
Hi Pedro,
Thanks for your reply. Any light you could shed on this would be very much appreciated. I did read the logs but didn't get very far as I'm not very familiar with this code.
I've included a gdb testcase below - hopefully this format is acceptable. This testcase reproduces the issue around 99% of the time on my ubuntu 16.04 machine. This figure drops closer to 50% when under heavy load, which suggested a race condition. I dug deeper into this and found that the threads which hang are always ones which did not hit the breakpoint but were stopped when another thread did hit a breakpoint. Threads which are stopped at breakpoints are immune to this issue. Loading the system allows more threads to reach the breakpoint before they are stopped by gdb.
Thanks again,
Stephen Roberts.
cat > gdb-hangs-on-infcall.c << SOURCEFILE
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define THREADCOUNT 4
pthread_barrier_t barrier;
pthread_t threads[THREADCOUNT];
int thread_ids[THREADCOUNT];
// Returns the argument back, within range [0..THREADCOUNT)
int get_value(int index) {
return thread_ids[index];
}
unsigned long fast_fib(unsigned int n) {
int a = 0;
int b = 1;
int t;
for (unsigned int i = 0; i < n; ++i) {
t = b;
b = a+b;
a = t;
}
return a;
}
void * thread_function(void *args) {
int tid = get_value(*((int *) args));
(void) args;
int status;
status = pthread_barrier_wait(&barrier);
if (status == PTHREAD_BARRIER_SERIAL_THREAD) {
printf("All threads entering compute region\n");
}
unsigned long result = fast_fib(100); // testmarker01
status = pthread_barrier_wait(&barrier);
if (status == PTHREAD_BARRIER_SERIAL_THREAD) {
printf("All threads outputting results\n");
}
pthread_barrier_wait(&barrier);
printf("Thread %d Result: %lu\n", tid, result);
pthread_exit(NULL);
}
int main(void) {
int err = pthread_barrier_init(&barrier, NULL, THREADCOUNT);
// Create worker threads (main)
printf("Spawining worker threads\n");
for (int tid = 0; tid < THREADCOUNT; ++tid) {
thread_ids[tid] = tid;
err = pthread_create(&threads[tid], NULL, thread_function, (void *) &thread_ids[tid]);
if (err) {
fprintf(stderr, "Thread creation failed\n");
return EXIT_FAILURE;
}
}
// Wait for threads to complete then exit
for (int tid = 0; tid < THREADCOUNT; ++tid) {
pthread_join(threads[tid], NULL);
}
pthread_exit(NULL);
return EXIT_SUCCESS;
}
SOURCEFILE
$ cat > gdb-hangs-on-infcall.exp << EXPECTFILE
standard_testfile .c
# What compiler are we using?
#
if [get_compiler_info] {
return -1
}
if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
return -1
}
clean_restart ${binfile}
if { ![runto main] } then {
fail "run to main"
return
}
gdb_breakpoint [gdb_get_line_number "testmarker01"]
gdb_continue_to_breakpoint "testmarker01"
gdb_test_no_output "set scheduler-locking on"
gdb_test "show scheduler-locking" "Mode for locking scheduler during execution is \"on\"."
gdb_test "thread 4" "Switching to .*"
gdb_test "call get_value(0)" ".* = 0"
gdb_test "thread 3" "Switching to .*"
gdb_test "call get_value(0)" ".* = 0"
gdb_test "thread 2" "Switching to .*"
gdb_test "call get_value(0)" ".* = 0"
gdb_test "thread 1" "Switching to .*"
gdb_test "call get_value(0)" ".* = 0"
EXPECTFILE