diff options
Diffstat (limited to 'gdb/testsuite/gdb.threads/forking-threads-plus-breakpoint.c')
-rw-r--r-- | gdb/testsuite/gdb.threads/forking-threads-plus-breakpoint.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/gdb/testsuite/gdb.threads/forking-threads-plus-breakpoint.c b/gdb/testsuite/gdb.threads/forking-threads-plus-breakpoint.c new file mode 100644 index 0000000..a6ff0fd --- /dev/null +++ b/gdb/testsuite/gdb.threads/forking-threads-plus-breakpoint.c @@ -0,0 +1,139 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2015 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <pthread.h> +#include <unistd.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <stdlib.h> + +/* Number of threads. Each thread continuously spawns a fork and wait + for it. If we have another thread continuously start a step over, + gdbserver should end up finding new forks while suspending + threads. */ +#define NTHREADS 10 + +pthread_t threads[NTHREADS]; + +pthread_barrier_t barrier; + +#define NFORKS 10 + +/* Used to create a conditional breakpoint that always fails. */ +volatile int zero; + +static void * +thread_forks (void *arg) +{ + int i; + + pthread_barrier_wait (&barrier); + + for (i = 0; i < NFORKS; i++) + { + pid_t pid; + + pid = fork (); + + if (pid > 0) + { + int status; + + /* Parent. */ + pid = waitpid (pid, &status, 0); + if (pid == -1) + { + perror ("wait"); + exit (1); + } + + if (!WIFEXITED (status)) + { + printf ("Unexpected wait status 0x%x from child %d\n", + status, pid); + } + } + else if (pid == 0) + { + /* Child. */ + exit (0); + } + else + { + perror ("fork"); + exit (1); + } + } +} + +/* Set this to tell the thread_breakpoint thread to exit. */ +volatile int break_out; + +static void * +thread_breakpoint (void *arg) +{ + pthread_barrier_wait (&barrier); + + while (!break_out) + { + usleep (1); /* set break here */ + } + + return NULL; +} + +pthread_barrier_t barrier; + +int +main (void) +{ + int i; + int ret; + pthread_t bp_thread; + + /* Don't run forever. */ + alarm (180); + + pthread_barrier_init (&barrier, NULL, NTHREADS + 1); + + /* Start the threads that constantly fork. */ + for (i = 0; i < NTHREADS; i++) + { + ret = pthread_create (&threads[i], NULL, thread_forks, NULL); + assert (ret == 0); + } + + /* Start the thread that constantly hit a conditional breakpoint + that needs to be stepped over. */ + ret = pthread_create (&bp_thread, NULL, thread_breakpoint, NULL); + assert (ret == 0); + + /* Wait for forking to stop. */ + for (i = 0; i < NTHREADS; i++) + { + ret = pthread_join (threads[i], NULL); + assert (ret == 0); + } + + break_out = 1; + pthread_join (bp_thread, NULL); + assert (ret == 0); + + return 0; +} |