gdb: fix vfork with multiple threads
[deliverable/binutils-gdb.git] / gdb / testsuite / gdb.threads / vfork-multi-thread.c
CommitLineData
5de96253
SM
1#include <assert.h>
2#include <pthread.h>
3#include <stdio.h>
4#include <unistd.h>
5
6// Start with:
7//
8// ./gdb -nx -q --data-directory=data-directory repro -ex "tb break_here_first" -ex r -ex "b should_break_here"
9//
10// Then do "continue".
11//
12// The main thread will likely cross should_break_here while we are handling
13// the vfork and breakpoints are removed, therefore missing the breakpoint.
14
15static volatile int release_vfork = 0;
16static volatile int release_main = 0;
17
18static void *vforker(void *arg)
19{
20 while (!release_vfork);
21
22 if (!vfork()) {
23 /* A vfork child is not supposed to mess with the state of the program,
24 but it is helpful for the purpose of this test. */
25 release_main = 1;
26 _exit(0);
27 }
28
29 return NULL;
30}
31
32static void should_break_here(void) {}
33
34int main()
35{
36
37 pthread_t thread;
38 int ret = pthread_create(&thread, NULL, vforker, NULL);
39 assert(ret == 0);
40
41 /* We break here first, while the thread is stuck on `!release_fork`. */
42 release_vfork = 1;
43
44 /* We set a breakpoint on should_break_here.
45
46 We then set "release_fork" from the debugger and continue. The main
47 thread hangs on `!release_main` while the non-main thread vforks. During
48 the window of time where the two processes have a shared address space
49 (after vfork, before _exit), GDB removes the breakpoints from the address
50 space. During that window, only the vfork-ing thread (the non-main
51 thread) is frozen by the kernel. The main thread is free to execute. The
52 child process sets `release_main`, releasing the main thread. A buggy GDB
53 would let the main thread execute during that window, leading to the
54 breakpoint on should_break_here being missed. A fixed GDB does not resume
55 the threads of the vforking process other than the vforking thread. When
56 the vfork child exits, the fixed GDB resumes the main thread, after
57 breakpoints are reinserted, so the breakpoint is not missed. */
58
59 while (!release_main);
60
61 should_break_here();
62
63 pthread_join (thread, NULL);
64
65 return 0;
66}
This page took 0.025789 seconds and 4 git commands to generate.