Hack some races.
[debugger.git] / testsuite.c
1 /* Copyright 2007, Red Hat Inc.  */
2
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <assert.h>
6 #include <sys/types.h>
7 #include <sys/wait.h>
8 #include <linux/unistd.h>
9 #include <limits.h>
10 #include <string.h>
11 #include <pthread.h>
12
13 #include "debugger.h"
14
15 #define LIBRARY 1
16 #include "debugger.c"
17
18
19 _syscall2(int, tkill, int, tid, int, sig)
20 int tkill(int tid, int sig);
21
22
23 static int attach_checked (pid_t pid, int redelivered_expect)
24 {
25   int stopped;
26
27   STATE (pid, (1 << STATE_SLEEPING) | (1 << STATE_RUNNING) | (1 << STATE_STOPPED));
28   stopped = attach (pid);
29   if (attach_redelivered != redelivered_expect)
30     {
31       fprintf (stderr, "Expecting redelivery of %d but found %d\n",
32                redelivered_expect, attach_redelivered);
33       abort ();
34     }
35   /* FIXME: Why also STATE_STOPPED?  */
36   STATE (pid, (1 << STATE_PTRACED) | (1 << STATE_STOPPED));
37   return stopped;
38 }
39
40 static void detach_checked (pid_t pid, int stopped)
41 {
42   /* FIXME: Why STATE_STOPPED?  */
43   STATE (pid, (stopped ? 1 << STATE_STOPPED : 1 << STATE_PTRACED));
44   detach (pid, stopped);
45   STATE (pid, (stopped ? 1 << STATE_STOPPED : (1 << STATE_SLEEPING) | (1 << STATE_RUNNING)));
46 }
47
48 struct registry
49   {
50     struct registry *next;
51     pid_t pid;
52   };
53 struct registry *registry_list;
54
55 static void registry_add (pid_t pid)
56 {
57   struct registry *new;
58
59   new = malloc (sizeof (*new));
60   assert (new != NULL);
61   new->pid = pid;
62   new->next = registry_list;
63   registry_list = new;
64 }
65
66 static void registry_remove (pid_t pid)
67 {
68   struct registry **iter_pointer;
69
70   for (iter_pointer = &registry_list; *iter_pointer != NULL;
71        iter_pointer = &(*iter_pointer)->next)
72     {
73       struct registry *found = *iter_pointer;
74       if (found->pid != pid)
75         continue;
76
77       *iter_pointer = found->next;
78       free (found);
79       return;
80     }
81   abort ();
82 }
83
84 static void registry_atexit (void)
85 {
86   struct registry *iter;
87
88   for (iter = registry_list; iter != NULL; iter = iter->next)
89     kill (iter->pid, SIGKILL);
90 }
91
92 static void registry_cleanup (void)
93 {
94   struct registry *iter;
95   pid_t pid;
96
97   registry_atexit ();
98   while ((pid = wait (NULL)) != -1)
99     {
100       for (iter = registry_list; iter != NULL; iter = iter->next)
101         if (iter->pid == pid)
102           break;
103       assert (iter != NULL);
104     }
105   assert (errno == ECHILD);
106   while (registry_list)
107     {
108       iter = registry_list;
109       registry_list = iter->next;
110       free (iter);
111     }
112 }
113
114 static void registry_handler (int signo)
115 {
116   signal (signo, SIG_DFL);
117   registry_atexit ();
118   raise (signo);
119 }
120
121 static void child_pause (void)
122 {
123   for (;;)
124     pause ();
125   /* NOTREACHED */
126   abort ();
127 }
128
129 static void child_alrm_handler (int signo)
130 {
131   assert (signo == SIGALRM);
132   raise (SIGALRM);
133 }
134
135 static void child_alrm (void)
136 {
137   void (*handler_orig) (int signo);
138 #if 0
139   int i;
140   sigset_t oldset;
141 #endif
142
143   handler_orig = signal (SIGALRM, child_alrm_handler);
144   assert (handler_orig == SIG_DFL);
145
146 #if 0
147   i = sigprocmask (SIG_BLOCK, NULL, &oldset);
148   assert (i == 0);
149   printf ("sigprocmask () -> sigismember (SIGALRM) == %d\n", sigismember (&oldset, SIGALRM));
150 #endif
151
152   for (;;)
153     pause ();
154   /* NOTREACHED */
155   abort ();
156 }
157
158 static pid_t spawn (void *(*child) (void *data, void *input), void *data,
159                     void *input, int fd_close)
160 {
161   pid_t pid;
162
163   pid = fork();
164   switch (pid)
165     {
166       case -1:
167         perror ("fork()");
168         exit (EXIT_FAILURE);
169         /* NOTREACHED */
170       case 0:
171         if (fd_close != -1)
172           {
173             int i;
174
175             i = close (fd_close);
176             assert (i == 0);
177           }
178         child (data, input);
179         /* NOTREACHED */
180         abort ();
181       default:;
182         /* PASSTHRU */
183     }
184   /* Parent.  */
185
186   registry_add (pid);
187   STATE (pid, (1 << STATE_SLEEPING) | (1 << STATE_RUNNING));
188   return pid;
189 }
190
191 static void murder (pid_t pid)
192 {
193   int i;
194   pid_t pid_got;
195   int status;
196
197   if (pid == 0)
198     return;
199
200   i = kill (pid, SIGKILL);
201   assert (i == 0);
202
203   pid_got = waitpid (pid, &status, 0);
204   if (!(pid_got == -1 && errno == ECHILD))
205     {
206       assert (pid_got == pid);
207       assert ((WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL)
208               || (WIFEXITED (status) && WEXITSTATUS (status) == 0));
209       STATE (pid, 1 << STATE_ENOENT);
210     }
211   else
212     STATE (pid, (1 << STATE_ENOENT) | (1 << STATE_ZOMBIE));
213
214   registry_remove (pid);
215 }
216
217
218 struct child_spawner
219   {
220     void *(*child) (void *data, void *input);
221     void *data;
222     int fd;
223   };
224
225 static void *child_spawner (void *param_voidpointer, void *input)
226 {
227   struct child_spawner *param = param_voidpointer;
228   pid_t inferior;
229   ssize_t inferior_size;
230   int i;
231
232   inferior = spawn (param->child, param->data, input, param->fd);
233
234   inferior_size = write (param->fd, &inferior, sizeof (inferior));
235   assert (inferior_size == sizeof (inferior));
236   i = close (param->fd);
237   assert (i == 0);
238
239   waitpid (inferior, NULL, 0);
240   _exit (EXIT_SUCCESS);
241   /* NOTREACHED */
242   abort ();
243 }
244
245 struct spawner
246   {
247     void *(*func) (void *data, void *input);
248     void *data;
249   };
250
251 static void *spawn_with_waiter (void *data, void *input)
252 {
253   pid_t waiter;
254   struct child_spawner param_local;
255   int pipefds[2];
256   int i;
257   pid_t inferior;
258   ssize_t inferior_size;
259   unsigned char buf;
260   ssize_t buf_size;
261   struct spawner *param = data;
262
263   assert (data != NULL);
264
265   i = pipe (pipefds);
266   assert (i == 0);
267
268   param_local.child = param->func;
269   param_local.data = param->data;
270   param_local.fd = pipefds[1];
271   waiter = spawn (child_spawner, &param_local, input, pipefds[0]);
272
273   i = close (pipefds[1]);
274   assert (i == 0);
275   inferior_size = read (pipefds[0], &inferior, sizeof (inferior));
276   assert (inferior_size == sizeof (inferior));
277   buf_size = read (pipefds[0], &buf, sizeof (buf));
278   assert (buf_size == 0);
279   i = close (pipefds[0]);
280   assert (i == 0);
281
282   registry_add (inferior);
283
284   return (void *) (unsigned long) inferior;
285 }
286
287 static void *spawn_without_waiter (void *data, void *input)
288 {
289   struct spawner *param = data;
290
291   return (void *) (unsigned long) spawn (param->func, param->data, input, -1);
292 }
293
294 static void body_spawner (void *(*child) (void *data, void *input), void *data,
295                           void *input)
296 {
297   pid_t inferior;
298   int stopped;
299   int i;
300
301   assert (input == NULL);
302
303   /* Plain attach/detach.  */
304   inferior = (unsigned long) (*child) (data, child_pause);
305   stopped = attach_checked (inferior, 0);
306   assert (stopped == 0);
307   detach_checked (inferior, stopped);
308   murder (inferior);
309
310   /* Attach to a process stopped by standard kill(2).  */
311   inferior = (unsigned long) (*child) (data, child_pause);
312   delay ();
313   i = kill (inferior, SIGSTOP);
314   assert (i == 0);
315   STATE (inferior, 1 << STATE_STOPPED);
316   stopped = attach_checked (inferior, 0);
317   assert (stopped == 1);
318   detach_checked (inferior, stopped);
319   murder (inferior);
320
321   /* Attach to a process stopped by Linux specific tkill(2).  */
322   inferior = (unsigned long) (*child) (data, child_pause);
323   delay ();
324   i = tkill (inferior, SIGSTOP);
325   assert (i == 0);
326   STATE (inferior, 1 << STATE_STOPPED);
327   stopped = attach_checked (inferior, 0);
328   assert (stopped == 1);
329   detach_checked (inferior, stopped);
330   murder (inferior);
331
332   /* Attach to a stopped process with already pending SIGALRM.  */
333   inferior = (unsigned long) (*child) (data, child_alrm);
334   STATE (inferior, 1 << STATE_SLEEPING);
335   delay ();
336   i = tkill (inferior, SIGSTOP);
337   assert (i == 0);
338   /* Wait till it gets stopped otherwise we may get STATE_ENOENT below.  */
339   STATE (inferior, 1 << STATE_STOPPED);
340   delay ();
341   i = tkill (inferior, SIGALRM);
342   assert (i == 0);
343   STATE (inferior, 1 << STATE_STOPPED);
344   /* FIXME: SIGALRM did not get redelivered?  */
345 #if 0
346   stopped = attach_checked (inferior, SIGALRM);
347 #else
348   stopped = attach_checked (inferior, 0);
349 #endif
350   assert (stopped == 1);
351   detach_checked (inferior, stopped);
352   STATE (inferior, 1 << STATE_STOPPED);
353   delay ();
354   i = tkill (inferior, SIGCONT);
355   assert (i == 0);
356   /* This is a race, we may not prove the successful SIGALRM delivery by it.  */
357   STATE (inferior, 1 << STATE_RUNNING);
358   murder (inferior);
359 }
360
361 static void *pass (void *data, void *input)
362 {
363   struct spawner *param = data;
364   void (*input_func) (void) = input;
365
366   if (param != NULL)
367     return (*param->func) (param->data, input);
368
369   assert (input_func != NULL);
370   (*input_func) ();
371   /* NOTREACHED */
372   abort ();
373 }
374
375 static void *spawn_singlethreaded (void *data, void *input)
376 {
377   return pass (data, input);
378 }
379
380 static void *spawn_threaded_parent_start (void *arg)
381 {
382   for (;;)
383     pause ();
384   /* NOTREACHED */
385   abort ();
386 }
387
388 static void *spawn_threaded_parent (void *data, void *input)
389 {
390   pthread_t thread;
391   int i;
392
393   i = pthread_create (&thread, NULL, spawn_threaded_parent_start, NULL);
394   assert (i == 0);
395   return pass (data, input);
396 }
397
398 struct spawn_threaded_child_start
399   {
400     void *data;
401     void *input;
402   };
403
404 static void *spawn_threaded_child_start (void *arg_voidpointer)
405 {
406   struct spawn_threaded_child_start *arg = arg_voidpointer;
407
408   return pass (arg->data, arg->input);
409   /* NOTREACHED */
410 }
411
412 static void *spawn_threaded_child (void *data, void *input)
413 {
414   pthread_t thread;
415   int i;
416   struct spawn_threaded_child_start arg_local;
417
418   arg_local.data = data;
419   arg_local.input = input;
420   i = pthread_create (&thread, NULL, spawn_threaded_child_start, &arg_local);
421   assert (i == 0);
422   i = pthread_join (thread, NULL);
423   assert (i == 0);
424
425   _exit (EXIT_SUCCESS);
426 }
427
428 static void body_maywaiter (void *(*child) (void *data, void *input),
429                             void *data, void *input)
430 {
431   struct spawner param_local;
432
433   param_local.func = child;
434   param_local.data = data;
435   body_spawner (spawn_without_waiter, &param_local, NULL);
436   body_spawner (spawn_with_waiter, &param_local, NULL);
437 }
438
439 static volatile unsigned long loops = 0;
440 static volatile int loops_print = 0;
441
442 static void handler_sigusr1 (int signo)
443 {
444   assert (signo == SIGUSR1);
445
446   loops_print++;
447 }
448
449 int main (int argc, char **argv)
450 {
451   int loop = 0;
452   int i;
453
454   if (argc == 1)
455     ;
456   else if (argc == 2 && strcmp (argv[1], "-l") == 0)
457     loop = 1;
458   else
459     abort ();
460
461   i = nice (10);
462   assert (i != -1);
463
464   atexit (registry_atexit);
465   signal (SIGINT, registry_handler);
466   signal (SIGABRT, registry_handler);
467
468   signal (SIGUSR1, handler_sigusr1);
469
470   do
471     {
472       while (loops_print > 0)
473         {
474           printf ("%lu\n", loops);
475           loops_print--;
476         }
477       body_maywaiter (spawn_singlethreaded, NULL, NULL);
478       body_maywaiter (spawn_threaded_parent, NULL, NULL);
479       body_maywaiter (spawn_threaded_child, NULL, NULL);
480
481       registry_cleanup ();
482       loops++;
483     }
484   while (loop != 0);
485
486   return EXIT_SUCCESS;
487 }