1/* This testcase is part of GDB, the GNU debugger. 2 3 Copyright 2014-2020 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 <pthread.h> 19#include <signal.h> 20#include <stdlib.h> 21#include <unistd.h> 22 23/* Used to individually advance each thread to the desired stopping point. */ 24int ready; 25 26sig_atomic_t sigusr1_received; 27sig_atomic_t sigusr2_received; 28sig_atomic_t sigabrt_received; 29 30/* Number of threads currently running. */ 31int thread_count; 32pthread_mutex_t thread_count_mutex; 33pthread_cond_t thread_count_condvar; 34 35static void 36incr_thread_count (void) 37{ 38 pthread_mutex_lock (&thread_count_mutex); 39 ++thread_count; 40 pthread_cond_signal (&thread_count_condvar); 41 pthread_mutex_unlock (&thread_count_mutex); 42} 43 44static void 45sigusr1_handler (int sig) 46{ 47 sigusr1_received = 1; 48} 49 50static void 51sigusr2_handler (int sig) 52{ 53 sigusr2_received = 1; 54} 55 56static void 57sigabrt_handler (int sig) 58{ 59 sigabrt_received = 1; 60} 61 62static void * 63sigusr1_thread_function (void *unused) 64{ 65 incr_thread_count (); 66 while (!ready) 67 usleep (100); 68 pthread_kill (pthread_self (), SIGUSR1); 69} 70 71static void * 72sigusr2_thread_function (void *unused) 73{ 74 incr_thread_count (); 75 while (!ready) 76 usleep (100); 77 /* pthread_kill (pthread_self (), SIGUSR2); - manually injected by gdb */ 78} 79 80/* Wait until all threads are at a point where a backtrace will 81 show the thread entry point function. */ 82 83static void 84wait_all_threads_running (int nr_threads) 85{ 86 pthread_mutex_lock (&thread_count_mutex); 87 88 while (1) 89 { 90 if (thread_count == nr_threads) 91 { 92 pthread_mutex_unlock (&thread_count_mutex); 93 return; 94 } 95 pthread_cond_wait (&thread_count_condvar, &thread_count_mutex); 96 } 97} 98 99static void 100all_threads_running (void) 101{ 102 while (!ready) 103 usleep (100); 104} 105 106static void 107all_threads_done (void) 108{ 109} 110 111int 112main () 113{ 114 pthread_t sigusr1_thread, sigusr2_thread; 115 116 /* Protect against running forever. */ 117 alarm (60); 118 119 signal (SIGUSR1, sigusr1_handler); 120 signal (SIGUSR2, sigusr2_handler); 121 signal (SIGABRT, sigabrt_handler); 122 123 /* Don't let any thread advance past initialization. */ 124 ready = 0; 125 126 pthread_mutex_init (&thread_count_mutex, NULL); 127 pthread_cond_init (&thread_count_condvar, NULL); 128 129#define NR_THREADS 2 130 pthread_create (&sigusr1_thread, NULL, sigusr1_thread_function, NULL); 131 pthread_create (&sigusr2_thread, NULL, sigusr2_thread_function, NULL); 132 wait_all_threads_running (NR_THREADS); 133 all_threads_running (); 134 135 pthread_kill (pthread_self (), SIGABRT); 136 137 pthread_join (sigusr1_thread, NULL); 138 pthread_join (sigusr2_thread, NULL); 139 all_threads_done (); 140 141 return 0; 142} 143