1 /* Copyright 2007, Red Hat Inc. */
14 #include <sys/syscall.h>
23 #define TIMEOUT_SECS 4
25 #define LOOPS_MIN 1000
28 #define tkill(tid, sig) syscall (SYS_tkill, (tid), (sig))
31 static void detach_checked (struct attach_state_struct *attach_state)
33 pid_t pid = attach_state_pid_get (attach_state);
35 if (attach_state_stopped_get (attach_state) != 0)
37 STATE (pid, 1 << STATE_STOPPED);
38 detach (attach_state);
39 STATE (pid, 1 << STATE_STOPPED);
43 STATE (pid, (1 << STATE_PTRACED));
44 detach (attach_state);
45 STATE (pid, ((1 << STATE_SLEEPING) | (1 << STATE_RUNNING)));
49 static volatile int spawned_threads_count; /* Set for the specific spawner. */
51 static struct attach_state_struct *attach_checked (pid_t pid, int redelivered_expect)
53 struct attach_state_struct *attach_state;
54 time_t timeout = time (NULL) + TIMEOUT_SECS;
57 STATE (pid, (1 << STATE_SLEEPING) | (1 << STATE_RUNNING) | (1 << STATE_STOPPED));
60 attach_state = attach (pid);
61 if (redelivered_expect != attach_state_redelivered_get (attach_state))
63 fprintf (stderr, "Expecting redelivery of %d but found %d\n",
65 attach_state_redelivered_get (attach_state));
68 /* During the inferior's initialization we may catch less threads. */
69 assert (attach_state_threads_count_get (attach_state)
70 <= spawned_threads_count);
71 if (attach_state_threads_count_get (attach_state)
72 == spawned_threads_count
73 /* Inferior may got stopped before it could initialize. */
74 || attach_state_stopped_get (attach_state) == 1)
76 /* FIXME: Why also STATE_STOPPED? */
77 STATE (pid, (1 << STATE_PTRACED) | (1 << STATE_STOPPED));
80 /* WARNING: Currently we never use REDELIVERED_EXPECT but we would have to
81 probably reset it back to 0 otherwise. */
82 assert (redelivered_expect == 0);
83 detach_checked (attach_state);
85 while (loops++ < LOOPS_MIN || time (NULL) < timeout);
91 struct registry *next;
94 struct registry *registry_list;
96 static void registry_add (pid_t pid)
100 new = malloc (sizeof (*new));
101 assert (new != NULL);
103 new->next = registry_list;
107 static void registry_remove (pid_t pid)
109 struct registry **iter_pointer;
111 for (iter_pointer = ®istry_list; *iter_pointer != NULL;
112 iter_pointer = &(*iter_pointer)->next)
114 struct registry *found = *iter_pointer;
115 if (found->pid != pid)
118 *iter_pointer = found->next;
125 static void registry_atexit (void)
127 struct registry *iter;
129 for (iter = registry_list; iter != NULL; iter = iter->next)
131 tkill (iter->pid, SIGCONT);
132 tkill (iter->pid, SIGKILL);
133 kill (iter->pid, SIGKILL);
137 static void registry_cleanup (void)
139 struct registry *iter;
143 while ((pid = wait (NULL)) != -1)
145 for (iter = registry_list; iter != NULL; iter = iter->next)
146 if (iter->pid == pid)
148 assert (iter != NULL);
150 assert (errno == ECHILD);
151 while (registry_list)
153 iter = registry_list;
154 registry_list = iter->next;
159 static void registry_handler (int signo)
161 signal (signo, SIG_DFL);
166 static __attribute__((__noreturn__)) void child_pause (void)
174 static void child_alrm_handler (int signo)
176 assert (signo == SIGALRM);
180 static __attribute__((__noreturn__)) void child_alrm (void)
187 /* Assumed already setup SIGALRM for CHILD_ALRM_HANDLER. */
190 i = sigprocmask (SIG_BLOCK, NULL, &oldset);
192 printf ("sigprocmask () -> sigismember (SIGALRM) == %d\n", sigismember (&oldset, SIGALRM));
201 static pid_t spawn (void *(*child) (void *data, void *input), void *data,
202 void *input, int fd_close)
218 i = close (fd_close);
230 STATE (pid, (1 << STATE_SLEEPING) | (1 << STATE_RUNNING));
234 static void murder (pid_t pid)
243 i = kill (pid, SIGKILL);
246 pid_got = waitpid (pid, &status, 0);
247 if (!(pid_got == -1 && errno == ECHILD))
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);
256 STATE (pid, (1 << STATE_ENOENT) | (1 << STATE_ZOMBIE));
258 registry_remove (pid);
264 void *(*child) (void *data, void *input);
269 static __attribute__((__noreturn__)) void *child_spawner (void *param_voidpointer, void *input)
271 struct child_spawner *param = param_voidpointer;
273 ssize_t inferior_size;
276 inferior = spawn (param->child, param->data, input, param->fd);
278 inferior_size = write (param->fd, &inferior, sizeof (inferior));
279 assert (inferior_size == sizeof (inferior));
280 i = close (param->fd);
283 waitpid (inferior, NULL, 0);
284 _exit (EXIT_SUCCESS);
291 void *(*func) (void *data, void *input);
295 static void *spawn_with_waiter (void *data, void *input)
298 struct child_spawner param_local;
302 ssize_t inferior_size;
305 struct spawner *param = data;
307 assert (data != NULL);
312 param_local.child = param->func;
313 param_local.data = param->data;
314 param_local.fd = pipefds[1];
315 waiter = spawn (child_spawner, ¶m_local, input, pipefds[0]);
317 i = close (pipefds[1]);
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]);
326 registry_add (inferior);
328 return (void *) (unsigned long) inferior;
331 static void *spawn_without_waiter (void *data, void *input)
333 struct spawner *param = data;
335 return (void *) (unsigned long) spawn (param->func, param->data, input, -1);
338 static void body_spawner (void *(*child) (void *data, void *input), void *data,
342 struct attach_state_struct *attach_state;
344 void (*handler_orig) (int signo);
346 assert (input == NULL);
348 /* Plain attach/detach. */
349 inferior = (unsigned long) (*child) (data, child_pause);
350 attach_state = attach_checked (inferior, 0);
351 assert (attach_state_stopped_get (attach_state) == 0);
352 detach_checked (attach_state);
355 /* Attach to a process stopped by standard kill(2). */
356 inferior = (unsigned long) (*child) (data, child_pause);
358 i = kill (inferior, SIGSTOP);
360 STATE (inferior, 1 << STATE_STOPPED);
361 attach_state = attach_checked (inferior, 0);
362 assert (attach_state_stopped_get (attach_state) == 1);
363 detach_checked (attach_state);
366 /* Attach to a process stopped by Linux specific tkill(2). */
367 inferior = (unsigned long) (*child) (data, child_pause);
369 i = tkill (inferior, SIGSTOP);
371 STATE (inferior, 1 << STATE_STOPPED);
372 attach_state = attach_checked (inferior, 0);
373 assert (attach_state_stopped_get (attach_state) == 1);
374 detach_checked (attach_state);
377 /* Attach to a stopped process with already pending SIGALRM. */
378 /* Setup the handler already in the parent to avoid the child race. */
379 handler_orig = signal (SIGALRM, child_alrm_handler);
380 assert (handler_orig == SIG_DFL);
381 inferior = (unsigned long) (*child) (data, child_alrm);
382 handler_orig = signal (SIGALRM, handler_orig);
383 assert (handler_orig == child_alrm_handler);
384 STATE (inferior, 1 << STATE_SLEEPING);
386 i = tkill (inferior, SIGSTOP);
388 /* Wait till it gets stopped otherwise we may get STATE_ENOENT below. */
389 STATE (inferior, 1 << STATE_STOPPED);
391 i = tkill (inferior, SIGALRM);
393 STATE (inferior, 1 << STATE_STOPPED);
394 /* FIXME: SIGALRM did not get redelivered? */
396 attach_state = attach_checked (inferior, SIGALRM);
398 attach_state = attach_checked (inferior, 0);
400 assert (attach_state_stopped_get (attach_state) == 1);
401 detach_checked (attach_state);
402 STATE (inferior, 1 << STATE_STOPPED);
404 i = tkill (inferior, SIGCONT);
406 /* This is a race, we may not prove the successful SIGALRM delivery by it.
407 Rather recheck it below. */
408 STATE (inferior, 1 << STATE_RUNNING);
410 i = tkill (inferior, SIGSTOP);
412 /* Wait till it gets stopped otherwise we may get STATE_ENOENT below. */
413 STATE (inferior, 1 << STATE_STOPPED);
415 i = tkill (inferior, SIGUSR2);
417 STATE (inferior, 1 << STATE_STOPPED);
419 i = tkill (inferior, SIGCONT);
421 /* Not just STATE_ZOMBIE as we can get spawn with waiter. FIXME. */
422 STATE (inferior, (1 << STATE_ENOENT) | (1 << STATE_ZOMBIE) | (1 << STATE_DEAD));
423 /* We would fail on: murder (inferior); */
426 static void *pass (void *data, void *input)
428 struct spawner *param = data;
429 void (*input_func) (void) = input;
432 return (*param->func) (param->data, input);
434 assert (input_func != NULL);
440 static void *spawn_singlethreaded (void *data, void *input)
442 return pass (data, input);
445 static __attribute__((__noreturn__)) void *spawn_threaded_parent_start (void *arg)
453 static void *libpthread_handle;
454 static int (*libpthread_create_pointer) (pthread_t *thread,
455 const pthread_attr_t *attr,
456 void *(*start_routine) (void *),
458 static int (*libpthread_join_pointer) (pthread_t thread, void **value_ptr);
460 static void libpthread_open (void)
462 assert (libpthread_handle == NULL);
464 libpthread_handle = dlopen ("libpthread.so.0", RTLD_LAZY);
465 assert (libpthread_handle != NULL);
467 libpthread_create_pointer = dlsym (libpthread_handle, "pthread_create");
468 assert (libpthread_create_pointer != NULL);
469 libpthread_join_pointer = dlsym (libpthread_handle, "pthread_join");
470 assert (libpthread_join_pointer != NULL);
474 static void libpthread_close (void)
478 assert (libpthread_handle != NULL);
480 i = dlclose (libpthread_handle);
482 libpthread_handle = NULL;
485 static void *spawn_threaded_parent (void *data, void *input)
490 assert (libpthread_create_pointer != NULL);
491 i = (*libpthread_create_pointer) (&thread, NULL, spawn_threaded_parent_start,
494 return pass (data, input);
497 struct spawn_threaded_child_start
503 static void *spawn_threaded_child_start (void *arg_voidpointer)
505 struct spawn_threaded_child_start *arg = arg_voidpointer;
507 return pass (arg->data, arg->input);
510 static __attribute__((__noreturn__)) void *spawn_threaded_child (void *data, void *input)
514 struct spawn_threaded_child_start arg_local;
516 arg_local.data = data;
517 arg_local.input = input;
518 assert (libpthread_create_pointer != NULL);
519 i = (*libpthread_create_pointer) (&thread, NULL, spawn_threaded_child_start,
522 assert (libpthread_join_pointer != NULL);
523 i = (*libpthread_join_pointer) (thread, NULL);
526 _exit (EXIT_SUCCESS);
531 static void body_maywaiter (void *(*child) (void *data, void *input),
532 void *data, void *input)
534 struct spawner param_local;
536 param_local.func = child;
537 param_local.data = data;
538 body_spawner (spawn_without_waiter, ¶m_local, NULL);
539 body_spawner (spawn_with_waiter, ¶m_local, NULL);
542 static volatile unsigned long loops = 0;
543 static volatile int loops_print = 0;
545 static void handler_sigusr1 (int signo)
547 assert (signo == SIGUSR1);
552 static __attribute__((__noreturn__)) void *tests_threaded (void *data, void *input)
556 spawned_threads_count = 2;
557 body_maywaiter (spawn_threaded_parent, NULL, NULL);
559 spawned_threads_count = 2;
560 body_maywaiter (spawn_threaded_child, NULL, NULL);
565 _exit (EXIT_SUCCESS);
570 int main (int argc, char **argv)
575 #ifdef MEASURE_STATE_PERFORMANCE
576 STATE (1, 1 << STATE_ZOMBIE);
578 #endif /* MEASURE_STATE_PERFORMANCE */
582 else if (argc == 2 && strcmp (argv[1], "-l") == 0)
590 atexit (registry_atexit);
591 signal (SIGINT, registry_handler);
592 signal (SIGABRT, registry_handler);
594 signal (SIGUSR1, handler_sigusr1);
598 pid_t pid_threaded, pid_threaded_got;
601 while (loops_print > 0)
603 printf ("%lu\n", loops);
607 spawned_threads_count = 0;
608 body_maywaiter (spawn_singlethreaded, NULL, NULL);
610 /* We cannot rely on LIBPTHREAD_CLOSE as libpthread would be still loaded
611 with ATTACH_STATE_REDELIVERED_GET () reporting 1 for
612 SPAWN_SINGLETHREADED. */
613 pid_threaded = spawn (tests_threaded, NULL, NULL, -1);
614 pid_threaded_got = waitpid (pid_threaded, &status, 0);
615 assert (pid_threaded_got == pid_threaded);
616 assert (!WIFSIGNALED (status)); /* Improve readability in the failed case. */
617 assert (!WIFSTOPPED (status)); /* Improve readability in the failed case. */
618 assert (WIFEXITED (status));
619 assert (WEXITSTATUS (status) == 0);
620 STATE (pid_threaded, 1 << STATE_ENOENT);
621 registry_remove (pid_threaded);
626 /* Run at least twice to test libpthread_close (). */
627 while (loop != 0 || loops == 1);