This is the mail archive of the gdb@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: GDB hangs when calling inferior functions


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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]