1 /* Copyright 2007, Red Hat Inc. */
14 #include <sys/syscall.h>
23 #define tkill(tid, sig) syscall (SYS_tkill, (tid), (sig))
26 static volatile int spawned_threads_count; /* Set for the specific spawner. */
28 static struct attach_state_struct *attach_checked (pid_t pid, int redelivered_expect)
30 struct attach_state_struct *attach_state;
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))
36 fprintf (stderr, "Expecting redelivery of %d but found %d\n",
37 redelivered_expect, attach_state_redelivered_get (attach_state));
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));
46 static void detach_checked (struct attach_state_struct *attach_state)
48 pid_t pid = attach_state_pid_get (attach_state);
50 if (attach_state_stopped_get (attach_state) != 0)
52 STATE (pid, 1 << STATE_STOPPED);
53 detach (attach_state);
54 STATE (pid, 1 << STATE_STOPPED);
58 STATE (pid, (1 << STATE_PTRACED));
59 detach (attach_state);
60 STATE (pid, ((1 << STATE_SLEEPING) | (1 << STATE_RUNNING)));
66 struct registry *next;
69 struct registry *registry_list;
71 static void registry_add (pid_t pid)
75 new = malloc (sizeof (*new));
78 new->next = registry_list;
82 static void registry_remove (pid_t pid)
84 struct registry **iter_pointer;
86 for (iter_pointer = ®istry_list; *iter_pointer != NULL;
87 iter_pointer = &(*iter_pointer)->next)
89 struct registry *found = *iter_pointer;
90 if (found->pid != pid)
93 *iter_pointer = found->next;
100 static void registry_atexit (void)
102 struct registry *iter;
104 for (iter = registry_list; iter != NULL; iter = iter->next)
106 tkill (iter->pid, SIGCONT);
107 tkill (iter->pid, SIGKILL);
108 kill (iter->pid, SIGKILL);
112 static void registry_cleanup (void)
114 struct registry *iter;
118 while ((pid = wait (NULL)) != -1)
120 for (iter = registry_list; iter != NULL; iter = iter->next)
121 if (iter->pid == pid)
123 assert (iter != NULL);
125 assert (errno == ECHILD);
126 while (registry_list)
128 iter = registry_list;
129 registry_list = iter->next;
134 static void registry_handler (int signo)
136 signal (signo, SIG_DFL);
141 static __attribute__((__noreturn__)) void child_pause (void)
149 static void child_alrm_handler (int signo)
151 assert (signo == SIGALRM);
155 static __attribute__((__noreturn__)) void child_alrm (void)
157 void (*handler_orig) (int signo);
163 handler_orig = signal (SIGALRM, child_alrm_handler);
164 assert (handler_orig == SIG_DFL);
167 i = sigprocmask (SIG_BLOCK, NULL, &oldset);
169 printf ("sigprocmask () -> sigismember (SIGALRM) == %d\n", sigismember (&oldset, SIGALRM));
178 static pid_t spawn (void *(*child) (void *data, void *input), void *data,
179 void *input, int fd_close)
195 i = close (fd_close);
207 STATE (pid, (1 << STATE_SLEEPING) | (1 << STATE_RUNNING));
211 static void murder (pid_t pid)
220 i = kill (pid, SIGKILL);
223 pid_got = waitpid (pid, &status, 0);
224 if (!(pid_got == -1 && errno == ECHILD))
226 assert (pid_got == pid);
227 assert ((WIFSIGNALED (status) && (WTERMSIG (status) == SIGKILL
228 || WTERMSIG (status) == SIGUSR2))
229 || (WIFEXITED (status) && WEXITSTATUS (status) == 0));
230 STATE (pid, 1 << STATE_ENOENT);
233 STATE (pid, (1 << STATE_ENOENT) | (1 << STATE_ZOMBIE));
235 registry_remove (pid);
241 void *(*child) (void *data, void *input);
246 static __attribute__((__noreturn__)) void *child_spawner (void *param_voidpointer, void *input)
248 struct child_spawner *param = param_voidpointer;
250 ssize_t inferior_size;
253 inferior = spawn (param->child, param->data, input, param->fd);
255 inferior_size = write (param->fd, &inferior, sizeof (inferior));
256 assert (inferior_size == sizeof (inferior));
257 i = close (param->fd);
260 waitpid (inferior, NULL, 0);
261 _exit (EXIT_SUCCESS);
268 void *(*func) (void *data, void *input);
272 static void *spawn_with_waiter (void *data, void *input)
275 struct child_spawner param_local;
279 ssize_t inferior_size;
282 struct spawner *param = data;
284 assert (data != NULL);
289 param_local.child = param->func;
290 param_local.data = param->data;
291 param_local.fd = pipefds[1];
292 waiter = spawn (child_spawner, ¶m_local, input, pipefds[0]);
294 i = close (pipefds[1]);
296 inferior_size = read (pipefds[0], &inferior, sizeof (inferior));
297 assert (inferior_size == sizeof (inferior));
298 buf_size = read (pipefds[0], &buf, sizeof (buf));
299 assert (buf_size == 0);
300 i = close (pipefds[0]);
303 registry_add (inferior);
305 return (void *) (unsigned long) inferior;
308 static void *spawn_without_waiter (void *data, void *input)
310 struct spawner *param = data;
312 return (void *) (unsigned long) spawn (param->func, param->data, input, -1);
315 static void body_spawner (void *(*child) (void *data, void *input), void *data,
319 struct attach_state_struct *attach_state;
322 assert (input == NULL);
324 /* Plain attach/detach. */
325 inferior = (unsigned long) (*child) (data, child_pause);
326 attach_state = attach_checked (inferior, 0);
327 assert (attach_state_stopped_get (attach_state) == 0);
328 detach_checked (attach_state);
331 /* Attach to a process stopped by standard kill(2). */
332 inferior = (unsigned long) (*child) (data, child_pause);
334 i = kill (inferior, SIGSTOP);
336 STATE (inferior, 1 << STATE_STOPPED);
337 attach_state = attach_checked (inferior, 0);
338 assert (attach_state_stopped_get (attach_state) == 1);
339 detach_checked (attach_state);
342 /* Attach to a process stopped by Linux specific tkill(2). */
343 inferior = (unsigned long) (*child) (data, child_pause);
345 i = tkill (inferior, SIGSTOP);
347 STATE (inferior, 1 << STATE_STOPPED);
348 attach_state = attach_checked (inferior, 0);
349 assert (attach_state_stopped_get (attach_state) == 1);
350 detach_checked (attach_state);
353 /* Attach to a stopped process with already pending SIGALRM. */
354 inferior = (unsigned long) (*child) (data, child_alrm);
355 STATE (inferior, 1 << STATE_SLEEPING);
357 i = tkill (inferior, SIGSTOP);
359 /* Wait till it gets stopped otherwise we may get STATE_ENOENT below. */
360 STATE (inferior, 1 << STATE_STOPPED);
362 i = tkill (inferior, SIGALRM);
364 STATE (inferior, 1 << STATE_STOPPED);
365 /* FIXME: SIGALRM did not get redelivered? */
367 attach_state = attach_checked (inferior, SIGALRM);
369 attach_state = attach_checked (inferior, 0);
371 assert (attach_state_stopped_get (attach_state) == 1);
372 detach_checked (attach_state);
373 STATE (inferior, 1 << STATE_STOPPED);
375 i = tkill (inferior, SIGCONT);
377 /* This is a race, we may not prove the successful SIGALRM delivery by it.
378 Rather recheck it below. */
379 STATE (inferior, 1 << STATE_RUNNING);
381 i = tkill (inferior, SIGSTOP);
383 /* Wait till it gets stopped otherwise we may get STATE_ENOENT below. */
384 STATE (inferior, 1 << STATE_STOPPED);
386 i = tkill (inferior, SIGUSR2);
388 STATE (inferior, 1 << STATE_STOPPED);
390 i = tkill (inferior, SIGCONT);
392 /* Not just STATE_ZOMBIE as we can get spawn with waiter. FIXME. */
393 STATE (inferior, (1 << STATE_ENOENT) | (1 << STATE_ZOMBIE) | (1 << STATE_DEAD));
394 /* We would fail on: murder (inferior); */
397 static void *pass (void *data, void *input)
399 struct spawner *param = data;
400 void (*input_func) (void) = input;
403 return (*param->func) (param->data, input);
405 assert (input_func != NULL);
411 static void *spawn_singlethreaded (void *data, void *input)
413 return pass (data, input);
416 static __attribute__((__noreturn__)) void *spawn_threaded_parent_start (void *arg)
424 static void *libpthread_handle;
425 static int (*libpthread_create_pointer) (pthread_t *thread,
426 const pthread_attr_t *attr,
427 void *(*start_routine) (void *),
429 static int (*libpthread_join_pointer) (pthread_t thread, void **value_ptr);
431 static void libpthread_open (void)
433 assert (libpthread_handle == NULL);
435 libpthread_handle = dlopen ("libpthread.so.0", RTLD_LAZY);
436 assert (libpthread_handle != NULL);
438 libpthread_create_pointer = dlsym (libpthread_handle, "pthread_create");
439 assert (libpthread_create_pointer != NULL);
440 libpthread_join_pointer = dlsym (libpthread_handle, "pthread_join");
441 assert (libpthread_join_pointer != NULL);
445 static void libpthread_close (void)
449 assert (libpthread_handle != NULL);
451 i = dlclose (libpthread_handle);
453 libpthread_handle = NULL;
456 static void *spawn_threaded_parent (void *data, void *input)
461 assert (libpthread_create_pointer != NULL);
462 i = (*libpthread_create_pointer) (&thread, NULL, spawn_threaded_parent_start,
465 return pass (data, input);
468 struct spawn_threaded_child_start
474 static void *spawn_threaded_child_start (void *arg_voidpointer)
476 struct spawn_threaded_child_start *arg = arg_voidpointer;
478 return pass (arg->data, arg->input);
481 static __attribute__((__noreturn__)) void *spawn_threaded_child (void *data, void *input)
485 struct spawn_threaded_child_start arg_local;
487 arg_local.data = data;
488 arg_local.input = input;
489 assert (libpthread_create_pointer != NULL);
490 i = (*libpthread_create_pointer) (&thread, NULL, spawn_threaded_child_start,
493 assert (libpthread_join_pointer != NULL);
494 i = (*libpthread_join_pointer) (thread, NULL);
497 _exit (EXIT_SUCCESS);
502 static void body_maywaiter (void *(*child) (void *data, void *input),
503 void *data, void *input)
505 struct spawner param_local;
507 param_local.func = child;
508 param_local.data = data;
509 body_spawner (spawn_without_waiter, ¶m_local, NULL);
510 body_spawner (spawn_with_waiter, ¶m_local, NULL);
513 static volatile unsigned long loops = 0;
514 static volatile int loops_print = 0;
516 static void handler_sigusr1 (int signo)
518 assert (signo == SIGUSR1);
523 static __attribute__((__noreturn__)) void *tests_threaded (void *data, void *input)
527 spawned_threads_count = 2;
528 body_maywaiter (spawn_threaded_parent, NULL, NULL);
530 spawned_threads_count = 2;
531 body_maywaiter (spawn_threaded_child, NULL, NULL);
536 _exit (EXIT_SUCCESS);
541 int main (int argc, char **argv)
546 #ifdef MEASURE_STATE_PERFORMANCE
547 STATE (1, 1 << STATE_ZOMBIE);
549 #endif /* MEASURE_STATE_PERFORMANCE */
553 else if (argc == 2 && strcmp (argv[1], "-l") == 0)
561 atexit (registry_atexit);
562 signal (SIGINT, registry_handler);
563 signal (SIGABRT, registry_handler);
565 signal (SIGUSR1, handler_sigusr1);
569 pid_t pid_threaded, pid_threaded_got;
572 while (loops_print > 0)
574 printf ("%lu\n", loops);
578 spawned_threads_count = 0;
579 body_maywaiter (spawn_singlethreaded, NULL, NULL);
581 /* We cannot rely on LIBPTHREAD_CLOSE as libpthread would be still loaded
582 with ATTACH_STATE_REDELIVERED_GET () reporting 1 for
583 SPAWN_SINGLETHREADED. */
584 pid_threaded = spawn (tests_threaded, NULL, NULL, -1);
585 pid_threaded_got = waitpid (pid_threaded, &status, 0);
586 assert (pid_threaded_got == pid_threaded);
587 assert (!WIFSIGNALED (status)); /* Improve readability in the failed case. */
588 assert (!WIFSTOPPED (status)); /* Improve readability in the failed case. */
589 assert (WIFEXITED (status));
590 assert (WEXITSTATUS (status) == 0);
591 STATE (pid_threaded, 1 << STATE_ENOENT);
592 registry_remove (pid_threaded);
597 /* Run at least twice to test libpthread_close (). */
598 while (loop != 0 || loops == 1);