1 /* Test case for hand function calls interrupted by a signal in another thread. 2 3 Copyright 2008-2023 Free Software Foundation, Inc. 4 5 This file is part of GDB. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20 #include <pthread.h> 21 #include <signal.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <time.h> 25 #include <unistd.h> 26 27 #ifndef NR_THREADS 28 #define NR_THREADS 4 29 #endif 30 31 pthread_t threads[NR_THREADS]; 32 33 /* Number of threads currently running. */ 34 int thread_count; 35 36 pthread_mutex_t thread_count_mutex; 37 38 pthread_cond_t thread_count_condvar; 39 40 sig_atomic_t sigabrt_received; 41 42 void 43 incr_thread_count (void) 44 { 45 pthread_mutex_lock (&thread_count_mutex); 46 ++thread_count; 47 if (thread_count == NR_THREADS) 48 pthread_cond_signal (&thread_count_condvar); 49 pthread_mutex_unlock (&thread_count_mutex); 50 } 51 52 void 53 cond_wait (pthread_cond_t *cond, pthread_mutex_t *mut) 54 { 55 pthread_mutex_lock (mut); 56 pthread_cond_wait (cond, mut); 57 pthread_mutex_unlock (mut); 58 } 59 60 void 61 noreturn (void) 62 { 63 pthread_mutex_t mut; 64 pthread_cond_t cond; 65 66 pthread_mutex_init (&mut, NULL); 67 pthread_cond_init (&cond, NULL); 68 69 /* Wait for a condition that will never be signaled, so we effectively 70 block the thread here. */ 71 cond_wait (&cond, &mut); 72 } 73 74 void * 75 thread_entry (void *unused) 76 { 77 incr_thread_count (); 78 noreturn (); 79 } 80 81 void 82 sigabrt_handler (int signo) 83 { 84 sigabrt_received = 1; 85 } 86 87 /* Helper to test a hand-call being "interrupted" by a signal on another 88 thread. */ 89 90 void 91 hand_call_with_signal (void) 92 { 93 const struct timespec ts = { 0, 10000000 }; /* 0.01 sec */ 94 95 sigabrt_received = 0; 96 pthread_kill (threads[0], SIGABRT); 97 while (! sigabrt_received) 98 nanosleep (&ts, NULL); 99 } 100 101 /* Wait until all threads are running. */ 102 103 void 104 wait_all_threads_running (void) 105 { 106 pthread_mutex_lock (&thread_count_mutex); 107 if (thread_count == NR_THREADS) 108 { 109 pthread_mutex_unlock (&thread_count_mutex); 110 return; 111 } 112 pthread_cond_wait (&thread_count_condvar, &thread_count_mutex); 113 if (thread_count == NR_THREADS) 114 { 115 pthread_mutex_unlock (&thread_count_mutex); 116 return; 117 } 118 pthread_mutex_unlock (&thread_count_mutex); 119 printf ("failed waiting for all threads to start\n"); 120 abort (); 121 } 122 123 /* Called when all threads are running. 124 Easy place for a breakpoint. */ 125 126 void 127 all_threads_running (void) 128 { 129 } 130 131 int 132 main (void) 133 { 134 int i; 135 136 signal (SIGABRT, sigabrt_handler); 137 138 pthread_mutex_init (&thread_count_mutex, NULL); 139 pthread_cond_init (&thread_count_condvar, NULL); 140 141 for (i = 0; i < NR_THREADS; ++i) 142 pthread_create (&threads[i], NULL, thread_entry, NULL); 143 144 wait_all_threads_running (); 145 all_threads_running (); 146 147 return 0; 148 } 149 150