1 /* Copyright 2007, Red Hat Inc. */
12 #include <sys/syscall.h>
20 #define tkill(tid, sig) syscall (SYS_tkill, (tid), (sig))
23 static int attach_checked (pid_t pid, int redelivered_expect)
27 STATE (pid, (1 << STATE_SLEEPING) | (1 << STATE_RUNNING) | (1 << STATE_STOPPED));
28 stopped = attach (pid);
29 if (attach_redelivered != redelivered_expect)
31 fprintf (stderr, "Expecting redelivery of %d but found %d\n",
32 redelivered_expect, attach_redelivered);
35 /* FIXME: Why also STATE_STOPPED? */
36 STATE (pid, (1 << STATE_PTRACED) | (1 << STATE_STOPPED));
40 static void detach_checked (pid_t pid, int stopped)
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)));
50 struct registry *next;
53 struct registry *registry_list;
55 static void registry_add (pid_t pid)
59 new = malloc (sizeof (*new));
62 new->next = registry_list;
66 static void registry_remove (pid_t pid)
68 struct registry **iter_pointer;
70 for (iter_pointer = ®istry_list; *iter_pointer != NULL;
71 iter_pointer = &(*iter_pointer)->next)
73 struct registry *found = *iter_pointer;
74 if (found->pid != pid)
77 *iter_pointer = found->next;
84 static void registry_atexit (void)
86 struct registry *iter;
88 for (iter = registry_list; iter != NULL; iter = iter->next)
90 tkill (iter->pid, SIGCONT);
91 tkill (iter->pid, SIGKILL);
92 kill (iter->pid, SIGKILL);
96 static void registry_cleanup (void)
98 struct registry *iter;
102 while ((pid = wait (NULL)) != -1)
104 for (iter = registry_list; iter != NULL; iter = iter->next)
105 if (iter->pid == pid)
107 assert (iter != NULL);
109 assert (errno == ECHILD);
110 while (registry_list)
112 iter = registry_list;
113 registry_list = iter->next;
118 static void registry_handler (int signo)
120 signal (signo, SIG_DFL);
125 static void child_pause (void)
133 static void child_alrm_handler (int signo)
135 assert (signo == SIGALRM);
139 static void child_alrm (void)
141 void (*handler_orig) (int signo);
147 handler_orig = signal (SIGALRM, child_alrm_handler);
148 assert (handler_orig == SIG_DFL);
151 i = sigprocmask (SIG_BLOCK, NULL, &oldset);
153 printf ("sigprocmask () -> sigismember (SIGALRM) == %d\n", sigismember (&oldset, SIGALRM));
162 static pid_t spawn (void *(*child) (void *data, void *input), void *data,
163 void *input, int fd_close)
179 i = close (fd_close);
191 STATE (pid, (1 << STATE_SLEEPING) | (1 << STATE_RUNNING));
195 static void murder (pid_t pid)
204 i = kill (pid, SIGKILL);
207 pid_got = waitpid (pid, &status, 0);
208 if (!(pid_got == -1 && errno == ECHILD))
210 assert (pid_got == pid);
211 assert ((WIFSIGNALED (status) && (WTERMSIG (status) == SIGKILL
212 || WTERMSIG (status) == SIGUSR2))
213 || (WIFEXITED (status) && WEXITSTATUS (status) == 0));
214 STATE (pid, 1 << STATE_ENOENT);
217 STATE (pid, (1 << STATE_ENOENT) | (1 << STATE_ZOMBIE));
219 registry_remove (pid);
225 void *(*child) (void *data, void *input);
230 static void *child_spawner (void *param_voidpointer, void *input)
232 struct child_spawner *param = param_voidpointer;
234 ssize_t inferior_size;
237 inferior = spawn (param->child, param->data, input, param->fd);
239 inferior_size = write (param->fd, &inferior, sizeof (inferior));
240 assert (inferior_size == sizeof (inferior));
241 i = close (param->fd);
244 waitpid (inferior, NULL, 0);
245 _exit (EXIT_SUCCESS);
252 void *(*func) (void *data, void *input);
256 static void *spawn_with_waiter (void *data, void *input)
259 struct child_spawner param_local;
263 ssize_t inferior_size;
266 struct spawner *param = data;
268 assert (data != NULL);
273 param_local.child = param->func;
274 param_local.data = param->data;
275 param_local.fd = pipefds[1];
276 waiter = spawn (child_spawner, ¶m_local, input, pipefds[0]);
278 i = close (pipefds[1]);
280 inferior_size = read (pipefds[0], &inferior, sizeof (inferior));
281 assert (inferior_size == sizeof (inferior));
282 buf_size = read (pipefds[0], &buf, sizeof (buf));
283 assert (buf_size == 0);
284 i = close (pipefds[0]);
287 registry_add (inferior);
289 return (void *) (unsigned long) inferior;
292 static void *spawn_without_waiter (void *data, void *input)
294 struct spawner *param = data;
296 return (void *) (unsigned long) spawn (param->func, param->data, input, -1);
299 static void body_spawner (void *(*child) (void *data, void *input), void *data,
306 assert (input == NULL);
308 /* Plain attach/detach. */
309 inferior = (unsigned long) (*child) (data, child_pause);
310 stopped = attach_checked (inferior, 0);
311 assert (stopped == 0);
312 detach_checked (inferior, stopped);
315 /* Attach to a process stopped by standard kill(2). */
316 inferior = (unsigned long) (*child) (data, child_pause);
318 i = kill (inferior, SIGSTOP);
320 STATE (inferior, 1 << STATE_STOPPED);
321 stopped = attach_checked (inferior, 0);
322 assert (stopped == 1);
323 detach_checked (inferior, stopped);
326 /* Attach to a process stopped by Linux specific tkill(2). */
327 inferior = (unsigned long) (*child) (data, child_pause);
329 i = tkill (inferior, SIGSTOP);
331 STATE (inferior, 1 << STATE_STOPPED);
332 stopped = attach_checked (inferior, 0);
333 assert (stopped == 1);
334 detach_checked (inferior, stopped);
337 /* Attach to a stopped process with already pending SIGALRM. */
338 inferior = (unsigned long) (*child) (data, child_alrm);
339 STATE (inferior, 1 << STATE_SLEEPING);
341 i = tkill (inferior, SIGSTOP);
343 /* Wait till it gets stopped otherwise we may get STATE_ENOENT below. */
344 STATE (inferior, 1 << STATE_STOPPED);
346 i = tkill (inferior, SIGALRM);
348 STATE (inferior, 1 << STATE_STOPPED);
349 /* FIXME: SIGALRM did not get redelivered? */
351 stopped = attach_checked (inferior, SIGALRM);
353 stopped = attach_checked (inferior, 0);
355 assert (stopped == 1);
356 detach_checked (inferior, stopped);
357 STATE (inferior, 1 << STATE_STOPPED);
359 i = tkill (inferior, SIGCONT);
361 /* This is a race, we may not prove the successful SIGALRM delivery by it.
362 Rather recheck it below. */
363 STATE (inferior, 1 << STATE_RUNNING);
365 i = tkill (inferior, SIGSTOP);
367 /* Wait till it gets stopped otherwise we may get STATE_ENOENT below. */
368 STATE (inferior, 1 << STATE_STOPPED);
370 i = tkill (inferior, SIGUSR2);
372 STATE (inferior, 1 << STATE_STOPPED);
374 i = tkill (inferior, SIGCONT);
376 /* Not just STATE_ZOMBIE as we can get spawn with waiter. FIXME. */
377 STATE (inferior, (1 << STATE_ENOENT) | (1 << STATE_ZOMBIE) | (1 << STATE_DEAD));
378 /* We would fail on: murder (inferior); */
381 static void *pass (void *data, void *input)
383 struct spawner *param = data;
384 void (*input_func) (void) = input;
387 return (*param->func) (param->data, input);
389 assert (input_func != NULL);
395 static void *spawn_singlethreaded (void *data, void *input)
397 return pass (data, input);
400 static void *spawn_threaded_parent_start (void *arg)
408 static void *spawn_threaded_parent (void *data, void *input)
413 i = pthread_create (&thread, NULL, spawn_threaded_parent_start, NULL);
415 return pass (data, input);
418 struct spawn_threaded_child_start
424 static void *spawn_threaded_child_start (void *arg_voidpointer)
426 struct spawn_threaded_child_start *arg = arg_voidpointer;
428 return pass (arg->data, arg->input);
432 static void *spawn_threaded_child (void *data, void *input)
436 struct spawn_threaded_child_start arg_local;
438 arg_local.data = data;
439 arg_local.input = input;
440 i = pthread_create (&thread, NULL, spawn_threaded_child_start, &arg_local);
442 i = pthread_join (thread, NULL);
445 _exit (EXIT_SUCCESS);
448 static void body_maywaiter (void *(*child) (void *data, void *input),
449 void *data, void *input)
451 struct spawner param_local;
453 param_local.func = child;
454 param_local.data = data;
455 body_spawner (spawn_without_waiter, ¶m_local, NULL);
456 body_spawner (spawn_with_waiter, ¶m_local, NULL);
459 static volatile unsigned long loops = 0;
460 static volatile int loops_print = 0;
462 static void handler_sigusr1 (int signo)
464 assert (signo == SIGUSR1);
469 int main (int argc, char **argv)
474 #ifdef MEASURE_STATE_PERFORMANCE
475 STATE (1, 1 << STATE_ZOMBIE);
477 #endif /* MEASURE_STATE_PERFORMANCE */
481 else if (argc == 2 && strcmp (argv[1], "-l") == 0)
489 atexit (registry_atexit);
490 signal (SIGINT, registry_handler);
491 signal (SIGABRT, registry_handler);
493 signal (SIGUSR1, handler_sigusr1);
497 while (loops_print > 0)
499 printf ("%lu\n", loops);
502 body_maywaiter (spawn_singlethreaded, NULL, NULL);
503 body_maywaiter (spawn_threaded_parent, NULL, NULL);
504 body_maywaiter (spawn_threaded_child, NULL, NULL);