space_voyager
space_voyager

Reputation: 2034

GDB breakpoint in routine of a simple Pthread?

I have the following code (source):

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

#define NUM_THREADS 5

void *PrintHello(void *threadid) {
  long tid;
  tid = (long)threadid;
  printf("Hello World! It's me, thread #%ld\n", tid);
  pthread_exit(NULL);
}

int main(int argc, char *argv[]) {
  pthread_t threads[NUM_THREADS];
  int rc;
  long t;
  for (t=0; t<NUM_THREADS; t++) {
    printf("In main: creating thread %ld\n", t);
    rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
    if (rc) {
      printf("ERROR; return code from pthread_create() is %d\n", rc);
      exit(-1);
    }
  }

  // wait for all threads to die
  pthread_exit(NULL);
}

I compile with gcc -g main.c -o main -lpthread. I am using GDB for debugging. What I want is to place a breakpoint at the second line of PrintHello, i.e. at tid = (long)threadid, and have the execution stop there (whatever the thread) and let me do stuff like look at the value of variable threadid.

I want to achieve this in Emacs' GDB implementation - which we may assume for the purposes of this question as simply GDB (don't worry that it's run inside Emacs). So far I can place the breakpoint at the desired line, and sometimes the little arrow showing the current line where the program is at does indeed stop at this line:

arrow

However when I type into the GDB prompt print threadid I get back No symbol "threadid" in current context. and the arrow jumps immediately to some breakpoint that I set in main():

im2

My guess is that this occurs because the "pausing" of program execution happens for the main thread, which is not the thread running PrintHello. PrintHello is run by thread t - since this is not the thread paused by GDB, it prints the hello world message and exists immediately. By the time I get around to typing print threadid, this thread is already dead and the program is back in main()... hence the effect.

I tried to resolve this by typing something like break <LineNumber> thread <ThreadID> but this is no good since in this program the created threads last for a split second. So I am never actually at a point where info thread shows anything except the main thread. It's simply not humanly possible to "catch" the program at a point where there is the main thread and a newly created thread running PrintHello - since this situation lasts for I guess a few microseconds.

Please help me to achieve this simple debug objective of halting execution of whatever thread is executing PrintHello at the line tid = (long)threadid;.

Upvotes: 2

Views: 590

Answers (1)

space_voyager
space_voyager

Reputation: 2034

Solved it, there wasn't much a problem after all. Here are instructions, if anyone has a similar issue:

  1. Compile with gcc -ggdb main.c -o main -lpthread (yes, that's -ggdb and not -g, it appears to make a difference)
  2. Run the debugger with gdb main or, in Emacs, with M-x gdb (and the command gdb -i=mi main)
    • Hugely important here: Emacs has by default the variable gdb-non-stop-setting set to t, which means it tries to run GDB in non-stop mode. According to docs, this is NOT what I want - I want all-stop mode. Thus, either do a set-variable or put (setq gdb-non-stop-setting nil) in your init file (e.g. ~/.emacs.d/init.el). Only once this is done should you launch M-x gdb from inside Emacs...
  3. (gdb) b 9 to set the breakpoint to line 9
  4. (gdb) r to run the program. Execution will stop when one of the threads reaches line 9, i.e. tid = (long)threadid;. All other threads will also stop! Perfect!
  5. (gdb) c to continue. Execution will stop when another thread reaches line 9. Great!
  6. Continue doing whatever, we have the desired behavior now :)

Upvotes: 1

Related Questions