+SIGUSR1 handler
[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   delay ();
339   i = tkill (inferior, SIGALRM);
340   assert (i == 0);
341   STATE (inferior, 1 << STATE_STOPPED);
342   /* FIXME: SIGALRM did not get redelivered?  */
343 #if 0
344   stopped = attach_checked (inferior, SIGALRM);
345 #else
346   stopped = attach_checked (inferior, 0);
347 #endif
348   assert (stopped == 1);
349   detach_checked (inferior, stopped);
350   STATE (inferior, 1 << STATE_STOPPED);
351   delay ();
352   i = tkill (inferior, SIGCONT);
353   assert (i == 0);
354   STATE (inferior, 1 << STATE_RUNNING);
355   murder (inferior);
356 }
357
358 static void *pass (void *data, void *input)
359 {
360   struct spawner *param = data;
361   void (*input_func) (void) = input;
362
363   if (param != NULL)
364     return (*param->func) (param->data, input);
365
366   assert (input_func != NULL);
367   (*input_func) ();
368   /* NOTREACHED */
369   abort ();
370 }
371
372 static void *spawn_singlethreaded (void *data, void *input)
373 {
374   return pass (data, input);
375 }
376
377 static void *spawn_threaded_parent_start (void *arg)
378 {
379   for (;;)
380     pause ();
381   /* NOTREACHED */
382   abort ();
383 }
384
385 static void *spawn_threaded_parent (void *data, void *input)
386 {
387   pthread_t thread;
388   int i;
389
390   i = pthread_create (&thread, NULL, spawn_threaded_parent_start, NULL);
391   assert (i == 0);
392   return pass (data, input);
393 }
394
395 struct spawn_threaded_child_start
396   {
397     void *data;
398     void *input;
399   };
400
401 static void *spawn_threaded_child_start (void *arg_voidpointer)
402 {
403   struct spawn_threaded_child_start *arg = arg_voidpointer;
404
405   return pass (arg->data, arg->input);
406   /* NOTREACHED */
407 }
408
409 static void *spawn_threaded_child (void *data, void *input)
410 {
411   pthread_t thread;
412   int i;
413   struct spawn_threaded_child_start arg_local;
414
415   arg_local.data = data;
416   arg_local.input = input;
417   i = pthread_create (&thread, NULL, spawn_threaded_child_start, &arg_local);
418   assert (i == 0);
419   i = pthread_join (thread, NULL);
420   assert (i == 0);
421
422   _exit (EXIT_SUCCESS);
423 }
424
425 static void body_maywaiter (void *(*child) (void *data, void *input),
426                             void *data, void *input)
427 {
428   struct spawner param_local;
429
430   param_local.func = child;
431   param_local.data = data;
432   body_spawner (spawn_without_waiter, &param_local, NULL);
433   body_spawner (spawn_with_waiter, &param_local, NULL);
434 }
435
436 static volatile unsigned long loops = 0;
437 static volatile int loops_print = 0;
438
439 static void handler_sigusr1 (int signo)
440 {
441   assert (signo == SIGUSR1);
442
443   loops_print++;
444 }
445
446 int main (int argc, char **argv)
447 {
448   int loop = 0;
449   int i;
450
451   if (argc == 1)
452     ;
453   else if (argc == 2 && strcmp (argv[1], "-l") == 0)
454     loop = 1;
455   else
456     abort ();
457
458   i = nice (10);
459   assert (i != -1);
460
461   atexit (registry_atexit);
462   signal (SIGINT, registry_handler);
463   signal (SIGABRT, registry_handler);
464
465   signal (SIGUSR1, handler_sigusr1);
466
467   do
468     {
469       while (loops_print > 0)
470         {
471           printf ("%lu\n", loops);
472           loops_print--;
473         }
474       body_maywaiter (spawn_singlethreaded, NULL, NULL);
475       body_maywaiter (spawn_threaded_parent, NULL, NULL);
476       body_maywaiter (spawn_threaded_child, NULL, NULL);
477
478       registry_cleanup ();
479       loops++;
480     }
481   while (loop != 0);
482
483   return EXIT_SUCCESS;
484 }