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