1 /* This testcase is part of GDB, the GNU debugger. 2 3 Copyright 2015-2019 Free Software Foundation, Inc. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17 18 #include <assert.h> 19 #include <pthread.h> 20 #include <unistd.h> 21 #include <stdio.h> 22 #include <sys/types.h> 23 #include <sys/wait.h> 24 #include <stdlib.h> 25 #include <errno.h> 26 27 /* Number of threads. Each thread continuously spawns a fork and wait 28 for it. If we have another thread continuously start a step over, 29 gdbserver should end up finding new forks while suspending 30 threads. */ 31 #define NTHREADS 10 32 33 pthread_t threads[NTHREADS]; 34 35 pthread_barrier_t barrier; 36 37 #define NFORKS 10 38 39 /* Used to create a conditional breakpoint that always fails. */ 40 volatile int zero; 41 42 static void * 43 thread_forks (void *arg) 44 { 45 int i; 46 47 pthread_barrier_wait (&barrier); 48 49 for (i = 0; i < NFORKS; i++) 50 { 51 pid_t pid; 52 53 do 54 { 55 pid = fork (); 56 } 57 while (pid == -1 && errno == EINTR); 58 59 if (pid > 0) 60 { 61 int status; 62 63 /* Parent. */ 64 do 65 { 66 pid = waitpid (pid, &status, 0); 67 } 68 while (pid == -1 && errno == EINTR); 69 70 if (pid == -1) 71 { 72 perror ("wait"); 73 exit (1); 74 } 75 76 if (!WIFEXITED (status)) 77 { 78 printf ("Unexpected wait status 0x%x from child %d\n", 79 status, pid); 80 } 81 } 82 else if (pid == 0) 83 { 84 /* Child. */ 85 exit (0); 86 } 87 else 88 { 89 perror ("fork"); 90 exit (1); 91 } 92 } 93 } 94 95 /* Set this to tell the thread_breakpoint thread to exit. */ 96 volatile int break_out; 97 98 static void * 99 thread_breakpoint (void *arg) 100 { 101 pthread_barrier_wait (&barrier); 102 103 while (!break_out) 104 { 105 usleep (1); /* set break here */ 106 } 107 108 return NULL; 109 } 110 111 pthread_barrier_t barrier; 112 113 int 114 main (void) 115 { 116 int i; 117 int ret; 118 pthread_t bp_thread; 119 120 /* Don't run forever. */ 121 alarm (180); 122 123 pthread_barrier_init (&barrier, NULL, NTHREADS + 1); 124 125 /* Start the threads that constantly fork. */ 126 for (i = 0; i < NTHREADS; i++) 127 { 128 ret = pthread_create (&threads[i], NULL, thread_forks, NULL); 129 assert (ret == 0); 130 } 131 132 /* Start the thread that constantly hit a conditional breakpoint 133 that needs to be stepped over. */ 134 ret = pthread_create (&bp_thread, NULL, thread_breakpoint, NULL); 135 assert (ret == 0); 136 137 /* Wait for forking to stop. */ 138 for (i = 0; i < NTHREADS; i++) 139 { 140 ret = pthread_join (threads[i], NULL); 141 assert (ret == 0); 142 } 143 144 break_out = 1; 145 pthread_join (bp_thread, NULL); 146 assert (ret == 0); 147 148 return 0; 149 } 150