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