1/* Test case for hand function calls interrupted by a signal in another thread. 2 3 Copyright 2008-2020 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 31pthread_t threads[NR_THREADS]; 32 33/* Number of threads currently running. */ 34int thread_count; 35 36pthread_mutex_t thread_count_mutex; 37 38pthread_cond_t thread_count_condvar; 39 40sig_atomic_t sigabrt_received; 41 42void 43incr_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 52void 53cond_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 60void 61noreturn (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 74void * 75thread_entry (void *unused) 76{ 77 incr_thread_count (); 78 noreturn (); 79} 80 81void 82sigabrt_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 90void 91hand_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 103void 104wait_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 126void 127all_threads_running (void) 128{ 129} 130 131int 132main (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