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