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