xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/testsuite/gdb.threads/watchthreads-reorder.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /* This testcase is part of GDB, the GNU debugger.
2 
3    Copyright 2009-2016 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 #define _GNU_SOURCE
19 #include <pthread.h>
20 #include <stdio.h>
21 #include <limits.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26 #include <sys/types.h>
27 #include <signal.h>
28 #include <unistd.h>
29 #include <asm/unistd.h>
30 
31 #define gettid() syscall (__NR_gettid)
32 
33 /* Terminate always in the main task, it can lock up with SIGSTOPped GDB
34    otherwise.  */
35 #define TIMEOUT (gettid () == getpid() ? 10 : 15)
36 
37 static pid_t thread1_tid;
38 static pthread_cond_t thread1_tid_cond = PTHREAD_COND_INITIALIZER;
39 static pthread_mutex_t thread1_tid_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
40 
41 static pid_t thread2_tid;
42 static pthread_cond_t thread2_tid_cond = PTHREAD_COND_INITIALIZER;
43 static pthread_mutex_t thread2_tid_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
44 
45 static pthread_mutex_t terminate_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
46 
47 static pthread_barrier_t threads_started_barrier;
48 
49 /* These variables must have lower in-memory addresses than thread1_rwatch and
50    thread2_rwatch so that they take their watchpoint slots.  */
51 
52 static int unused1_rwatch;
53 static int unused2_rwatch;
54 
55 static volatile int thread1_rwatch;
56 static volatile int thread2_rwatch;
57 
58 /* Do not use alarm as it would create a ptrace event which would hang up us if
59    we are being traced by GDB which we stopped ourselves.  */
60 
61 static void timed_mutex_lock (pthread_mutex_t *mutex)
62 {
63   int i;
64   struct timespec start, now;
65 
66   i = clock_gettime (CLOCK_MONOTONIC, &start);
67   assert (i == 0);
68 
69   do
70     {
71       i = pthread_mutex_trylock (mutex);
72       if (i == 0)
73 	return;
74       assert (i == EBUSY);
75 
76       i = clock_gettime (CLOCK_MONOTONIC, &now);
77       assert (i == 0);
78       assert (now.tv_sec >= start.tv_sec);
79     }
80   while (now.tv_sec - start.tv_sec < TIMEOUT);
81 
82   fprintf (stderr, "Timed out waiting for internal lock!\n");
83   exit (EXIT_FAILURE);
84 }
85 
86 static void *
87 thread1_func (void *unused)
88 {
89   int i;
90   volatile int rwatch_store;
91 
92   pthread_barrier_wait (&threads_started_barrier);
93 
94   timed_mutex_lock (&thread1_tid_mutex);
95 
96   /* THREAD1_TID_MUTEX must be already locked to avoid race.  */
97   thread1_tid = gettid ();
98 
99   i = pthread_cond_signal (&thread1_tid_cond);
100   assert (i == 0);
101   i = pthread_mutex_unlock (&thread1_tid_mutex);
102   assert (i == 0);
103 
104   rwatch_store = thread1_rwatch;
105 
106   /* Be sure the "t (tracing stop)" test can proceed for both threads.  */
107   timed_mutex_lock (&terminate_mutex);
108   i = pthread_mutex_unlock (&terminate_mutex);
109   assert (i == 0);
110 
111   return NULL;
112 }
113 
114 static void *
115 thread2_func (void *unused)
116 {
117   int i;
118   volatile int rwatch_store;
119 
120   pthread_barrier_wait (&threads_started_barrier);
121 
122   timed_mutex_lock (&thread2_tid_mutex);
123 
124   /* THREAD2_TID_MUTEX must be already locked to avoid race.  */
125   thread2_tid = gettid ();
126 
127   i = pthread_cond_signal (&thread2_tid_cond);
128   assert (i == 0);
129   i = pthread_mutex_unlock (&thread2_tid_mutex);
130   assert (i == 0);
131 
132   rwatch_store = thread2_rwatch;
133 
134   /* Be sure the "t (tracing stop)" test can proceed for both threads.  */
135   timed_mutex_lock (&terminate_mutex);
136   i = pthread_mutex_unlock (&terminate_mutex);
137   assert (i == 0);
138 
139   return NULL;
140 }
141 
142 static const char *
143 proc_string (const char *filename, const char *line)
144 {
145   FILE *f;
146   static char buf[LINE_MAX];
147   size_t line_len = strlen (line);
148 
149   f = fopen (filename, "r");
150   if (f == NULL)
151     {
152       fprintf (stderr, "fopen (\"%s\") for \"%s\": %s\n", filename, line,
153 	       strerror (errno));
154       exit (EXIT_FAILURE);
155     }
156   while (errno = 0, fgets (buf, sizeof (buf), f))
157     {
158       char *s;
159 
160       s = strchr (buf, '\n');
161       assert (s != NULL);
162       *s = 0;
163 
164       if (strncmp (buf, line, line_len) != 0)
165 	continue;
166 
167       if (fclose (f))
168 	{
169 	  fprintf (stderr, "fclose (\"%s\") for \"%s\": %s\n", filename, line,
170 		   strerror (errno));
171 	  exit (EXIT_FAILURE);
172 	}
173 
174       return &buf[line_len];
175     }
176   if (errno != 0)
177     {
178       fprintf (stderr, "fgets (\"%s\": %s\n", filename, strerror (errno));
179       exit (EXIT_FAILURE);
180     }
181   fprintf (stderr, "\"%s\": No line \"%s\" found.\n", filename, line);
182   exit (EXIT_FAILURE);
183 }
184 
185 static unsigned long
186 proc_ulong (const char *filename, const char *line)
187 {
188   const char *s = proc_string (filename, line);
189   long retval;
190   char *end;
191 
192   errno = 0;
193   retval = strtol (s, &end, 10);
194   if (retval < 0 || retval >= LONG_MAX || (end && *end))
195     {
196       fprintf (stderr, "\"%s\":\"%s\": %ld, %s\n", filename, line, retval,
197 	       strerror (errno));
198       exit (EXIT_FAILURE);
199     }
200   return retval;
201 }
202 
203 static void
204 state_wait (pid_t process, const char *wanted)
205 {
206   char *filename;
207   int i;
208   struct timespec start, now;
209   const char *state;
210 
211   i = asprintf (&filename, "/proc/%lu/status", (unsigned long) process);
212   assert (i > 0);
213 
214   i = clock_gettime (CLOCK_MONOTONIC, &start);
215   assert (i == 0);
216 
217   do
218     {
219       state = proc_string (filename, "State:\t");
220 
221       /* torvalds/linux-2.6.git 464763cf1c6df632dccc8f2f4c7e50163154a2c0
222 	 has changed "T (tracing stop)" to "t (tracing stop)".  Make the GDB
223 	 testcase backward compatible with older Linux kernels.  */
224       if (strcmp (state, "T (tracing stop)") == 0)
225 	state = "t (tracing stop)";
226 
227       if (strcmp (state, wanted) == 0)
228 	{
229 	  free (filename);
230 	  return;
231 	}
232 
233       if (sched_yield ())
234 	{
235 	  perror ("sched_yield()");
236 	  exit (EXIT_FAILURE);
237 	}
238 
239       i = clock_gettime (CLOCK_MONOTONIC, &now);
240       assert (i == 0);
241       assert (now.tv_sec >= start.tv_sec);
242     }
243   while (now.tv_sec - start.tv_sec < TIMEOUT);
244 
245   fprintf (stderr, "Timed out waiting for PID %lu \"%s\" (now it is \"%s\")!\n",
246 	   (unsigned long) process, wanted, state);
247   exit (EXIT_FAILURE);
248 }
249 
250 static volatile pid_t tracer = 0;
251 static pthread_t thread1, thread2;
252 
253 static void
254 cleanup (void)
255 {
256   printf ("Resuming GDB PID %lu.\n", (unsigned long) tracer);
257 
258   if (tracer)
259     {
260       int i;
261       int tracer_save = tracer;
262 
263       tracer = 0;
264 
265       i = kill (tracer_save, SIGCONT);
266       assert (i == 0);
267     }
268 }
269 
270 int
271 main (int argc, char **argv)
272 {
273   int i;
274   int standalone = 0;
275 
276   if (argc == 2 && strcmp (argv[1], "-s") == 0)
277     standalone = 1;
278   else
279     assert (argc == 1);
280 
281   setbuf (stdout, NULL);
282 
283   timed_mutex_lock (&thread1_tid_mutex);
284   timed_mutex_lock (&thread2_tid_mutex);
285 
286   timed_mutex_lock (&terminate_mutex);
287 
288   pthread_barrier_init (&threads_started_barrier, NULL, 3);
289 
290   i = pthread_create (&thread1, NULL, thread1_func, NULL);
291   assert (i == 0);
292 
293   i = pthread_create (&thread2, NULL, thread2_func, NULL);
294   assert (i == 0);
295 
296   if (!standalone)
297     {
298       tracer = proc_ulong ("/proc/self/status", "TracerPid:\t");
299       if (tracer == 0)
300 	{
301 	  fprintf (stderr, "The testcase must be run by GDB!\n");
302 	  exit (EXIT_FAILURE);
303 	}
304       if (tracer != getppid ())
305 	{
306 	  fprintf (stderr, "The testcase parent must be our GDB tracer!\n");
307 	  exit (EXIT_FAILURE);
308 	}
309     }
310 
311   /* SIGCONT our debugger in the case of our crash as we would deadlock
312      otherwise.  */
313 
314   atexit (cleanup);
315 
316   /* Wait until all threads are seen running.  On Linux (at least),
317      new threads start stopped, and the debugger must resume them.
318      Need to wait for that before stopping GDB.  */
319   pthread_barrier_wait (&threads_started_barrier);
320 
321   printf ("Stopping GDB PID %lu.\n", (unsigned long) tracer);
322 
323   if (tracer)
324     {
325       i = kill (tracer, SIGSTOP);
326       assert (i == 0);
327       state_wait (tracer, "T (stopped)");
328     }
329 
330   /* Threads are now waiting at timed_mutex_lock (thread1_tid_mutex) and so
331      they could not trigger the watchpoints before GDB gets unstopped later.
332      Threads get resumed at pthread_cond_wait below.  Use `while' loops for
333      protection against spurious pthread_cond_wait wakeups.  */
334 
335   printf ("Waiting till the threads initialize their TIDs.\n");
336 
337   while (thread1_tid == 0)
338     {
339       i = pthread_cond_wait (&thread1_tid_cond, &thread1_tid_mutex);
340       assert (i == 0);
341     }
342 
343   while (thread2_tid == 0)
344     {
345       i = pthread_cond_wait (&thread2_tid_cond, &thread2_tid_mutex);
346       assert (i == 0);
347     }
348 
349   printf ("Thread 1 TID = %lu, thread 2 TID = %lu, PID = %lu.\n",
350 	  (unsigned long) thread1_tid, (unsigned long) thread2_tid,
351 	  (unsigned long) getpid ());
352 
353   printf ("Waiting till the threads get trapped by the watchpoints.\n");
354 
355   if (tracer)
356     {
357       /* s390x-unknown-linux-gnu will fail with "R (running)".  */
358 
359       state_wait (thread1_tid, "t (tracing stop)");
360 
361       state_wait (thread2_tid, "t (tracing stop)");
362     }
363 
364   cleanup ();
365 
366   printf ("Joining the threads.\n");
367 
368   i = pthread_mutex_unlock (&terminate_mutex);
369   assert (i == 0);
370 
371   i = pthread_join (thread1, NULL);
372   assert (i == 0);
373 
374   i = pthread_join (thread2, NULL);
375   assert (i == 0);
376 
377   printf ("Exiting.\n");	/* break-at-exit */
378 
379   /* Just prevent compiler `warning: unusedX_rwatch defined but not used'.  */
380   unused1_rwatch = 1;
381   unused2_rwatch = 2;
382 
383   return EXIT_SUCCESS;
384 }
385