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