xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/testsuite/gdb.threads/watchpoint-fork-mt.c (revision 9616dacfef448e70e3fbbd865bddf60d54b656c5)
1 /* Test case for forgotten hw-watchpoints after fork()-off of a process.
2 
3    Copyright 2012-2015 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 <assert.h>
21 #include <unistd.h>
22 #include <sys/wait.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 
26 /* pthread_yield is a GNU extension.  */
27 #define _GNU_SOURCE
28 #include <pthread.h>
29 
30 #include <asm/unistd.h>
31 #include <unistd.h>
32 #define gettid() syscall (__NR_gettid)
33 
34 #include "watchpoint-fork.h"
35 
36 /* Non-atomic `var++' should not hurt as we synchronize the threads by the STEP
37    variable.  Hit-comments need to be duplicated there to catch both at-stops
38    and behind-stops, depending on the target.  */
39 
40 volatile int var;
41 
42 void
43 marker (void)
44 {
45 }
46 
47 static void
48 empty (void)
49 {
50 }
51 
52 static void
53 mark_exit (void)
54 {
55 }
56 
57 pthread_t thread;
58 volatile int step;
59 
60 static void *
61 start (void *arg)
62 {
63   int i;
64 
65   if (step >= 3)
66     goto step_3;
67 
68   while (step != 1)
69     {
70       i = pthread_yield ();
71       assert (i == 0);
72     }
73 
74   var++;	/* validity-thread-B */
75   empty ();	/* validity-thread-B */
76   step = 2;
77   while (step != 3)
78     {
79       if (step == 99)
80 	goto step_99;
81 
82       i = pthread_yield ();
83       assert (i == 0);
84     }
85 
86 step_3:
87   if (step >= 5)
88     goto step_5;
89 
90   var++;	/* after-fork1-B */
91   empty ();	/* after-fork1-B */
92   step = 4;
93   while (step != 5)
94     {
95       if (step == 99)
96 	goto step_99;
97 
98       i = pthread_yield ();
99       assert (i == 0);
100     }
101 
102 step_5:
103   var++;	/* after-fork2-B */
104   empty ();	/* after-fork2-B */
105   return (void *) 5UL;
106 
107 step_99:
108   /* We must not get caught here (against a forgotten breakpoint).  */
109   var++;
110   marker ();
111   return (void *) 99UL;
112 }
113 
114 int
115 main (void)
116 {
117   int i;
118   void *thread_result;
119 
120   setbuf (stdout, NULL);
121   printf ("main: %d\n", (int) gettid ());
122 
123   /* General hardware breakpoints and watchpoints validity.  */
124   marker ();
125   var++;	/* validity-first */
126   empty ();	/* validity-first */
127 
128   i = pthread_create (&thread, NULL, start, NULL);
129   assert (i == 0);
130 
131   var++;	/* validity-thread-A */
132   empty ();	/* validity-thread-A */
133   step = 1;
134   while (step != 2)
135     {
136       i = pthread_yield ();
137       assert (i == 0);
138     }
139 
140   /* Hardware watchpoints got disarmed here.  */
141   forkoff (1);
142 
143   var++;	/* after-fork1-A */
144   empty ();	/* after-fork1-A */
145   step = 3;
146 #ifdef FOLLOW_CHILD
147   /* Spawn new thread as it was deleted in the child of FORK.  */
148   i = pthread_create (&thread, NULL, start, NULL);
149   assert (i == 0);
150 #endif
151   while (step != 4)
152     {
153       i = pthread_yield ();
154       assert (i == 0);
155     }
156 
157   /* A sanity check for double hardware watchpoints removal.  */
158   forkoff (2);
159 
160   var++;	/* after-fork2-A */
161   empty ();	/* after-fork2-A */
162   step = 5;
163 #ifdef FOLLOW_CHILD
164   /* Spawn new thread as it was deleted in the child of FORK.  */
165   i = pthread_create (&thread, NULL, start, NULL);
166   assert (i == 0);
167 #endif
168 
169   i = pthread_join (thread, &thread_result);
170   assert (i == 0);
171   assert (thread_result == (void *) 5UL);
172 
173   mark_exit ();
174   return 0;
175 }
176