1/* This testcase is part of GDB, the GNU debugger. 2 3 Copyright 2015-2023 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 33pthread_t threads[NTHREADS]; 34 35pthread_barrier_t barrier; 36 37#define NFORKS 10 38 39/* Used to create a conditional breakpoint that always fails. */ 40volatile int zero; 41 42static void * 43thread_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 return NULL; 95} 96 97/* Set this to tell the thread_breakpoint thread to exit. */ 98volatile int break_out; 99 100static void * 101thread_breakpoint (void *arg) 102{ 103 pthread_barrier_wait (&barrier); 104 105 while (!break_out) 106 { 107 usleep (1); /* set break here */ 108 } 109 110 return NULL; 111} 112 113pthread_barrier_t barrier; 114 115int 116main (void) 117{ 118 int i; 119 int ret; 120 pthread_t bp_thread; 121 122 /* Don't run forever. */ 123 alarm (180); 124 125 pthread_barrier_init (&barrier, NULL, NTHREADS + 1); 126 127 /* Start the threads that constantly fork. */ 128 for (i = 0; i < NTHREADS; i++) 129 { 130 ret = pthread_create (&threads[i], NULL, thread_forks, NULL); 131 assert (ret == 0); 132 } 133 134 /* Start the thread that constantly hit a conditional breakpoint 135 that needs to be stepped over. */ 136 ret = pthread_create (&bp_thread, NULL, thread_breakpoint, NULL); 137 assert (ret == 0); 138 139 /* Wait for forking to stop. */ 140 for (i = 0; i < NTHREADS; i++) 141 { 142 ret = pthread_join (threads[i], NULL); 143 assert (ret == 0); 144 } 145 146 break_out = 1; 147 pthread_join (bp_thread, NULL); 148 assert (ret == 0); 149 150 return 0; 151} 152