1 /* Copyright 2007, Red Hat Inc. */
8 #include <linux/unistd.h>
19 _syscall2(int, tkill, int, tid, int, sig)
20 int tkill(int tid, int 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)
89 kill (iter->pid, SIGKILL);
92 static void registry_handler (int signo)
94 signal (signo, SIG_DFL);
99 static void child_pause (void)
107 static void child_alrm_handler (int signo)
109 assert (signo == SIGALRM);
113 static void child_alrm (void)
115 void (*handler_orig) (int signo);
121 handler_orig = signal (SIGALRM, child_alrm_handler);
122 assert (handler_orig == SIG_DFL);
125 i = sigprocmask (SIG_BLOCK, NULL, &oldset);
127 printf ("sigprocmask () -> sigismember (SIGALRM) == %d\n", sigismember (&oldset, SIGALRM));
136 static pid_t spawn (void *(*child) (void *data, void *input), void *data,
137 void *input, int fd_close)
153 i = close (fd_close);
165 STATE (pid, (1 << STATE_SLEEPING) | (1 << STATE_RUNNING));
169 static void murder (pid_t pid)
178 i = kill (pid, SIGKILL);
181 pid_got = waitpid (pid, &status, 0);
182 if (!(pid_got == -1 && errno == ECHILD))
184 assert (pid_got == pid);
185 assert ((WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL)
186 || (WIFEXITED (status) && WEXITSTATUS (status) == 0));
187 STATE (pid, 1 << STATE_ENOENT);
190 STATE (pid, (1 << STATE_ENOENT) | (1 << STATE_ZOMBIE));
192 registry_remove (pid);
198 void *(*child) (void *data, void *input);
203 static void *child_spawner (void *param_voidpointer, void *input)
205 struct child_spawner *param = param_voidpointer;
207 ssize_t inferior_size;
210 inferior = spawn (param->child, param->data, input, param->fd);
212 inferior_size = write (param->fd, &inferior, sizeof (inferior));
213 assert (inferior_size == sizeof (inferior));
214 i = close (param->fd);
217 waitpid (inferior, NULL, 0);
218 _exit (EXIT_SUCCESS);
225 void *(*func) (void *data, void *input);
229 static void *spawn_with_waiter (void *data, void *input)
232 struct child_spawner param_local;
236 ssize_t inferior_size;
239 struct spawner *param = data;
241 assert (data != NULL);
246 param_local.child = param->func;
247 param_local.data = param->data;
248 param_local.fd = pipefds[1];
249 waiter = spawn (child_spawner, ¶m_local, input, pipefds[0]);
251 i = close (pipefds[1]);
253 inferior_size = read (pipefds[0], &inferior, sizeof (inferior));
254 assert (inferior_size == sizeof (inferior));
255 buf_size = read (pipefds[0], &buf, sizeof (buf));
256 assert (buf_size == 0);
257 i = close (pipefds[0]);
260 registry_add (inferior);
262 return (void *) (unsigned long) inferior;
265 static void *spawn_without_waiter (void *data, void *input)
267 struct spawner *param = data;
269 return (void *) (unsigned long) spawn (param->func, param->data, input, -1);
272 static void body_spawner (void *(*child) (void *data, void *input), void *data,
279 assert (input == NULL);
281 /* Plain attach/detach. */
282 inferior = (unsigned long) (*child) (data, child_pause);
283 stopped = attach_checked (inferior, 0);
284 assert (stopped == 0);
285 detach_checked (inferior, stopped);
288 /* Attach to a process stopped by standard kill(2). */
289 inferior = (unsigned long) (*child) (data, child_pause);
291 i = kill (inferior, SIGSTOP);
293 STATE (inferior, 1 << STATE_STOPPED);
294 stopped = attach_checked (inferior, 0);
295 assert (stopped == 1);
296 detach_checked (inferior, stopped);
299 /* Attach to a process stopped by Linux specific tkill(2). */
300 inferior = (unsigned long) (*child) (data, child_pause);
302 i = tkill (inferior, SIGSTOP);
304 STATE (inferior, 1 << STATE_STOPPED);
305 stopped = attach_checked (inferior, 0);
306 assert (stopped == 1);
307 detach_checked (inferior, stopped);
310 /* Attach to a stopped process with already pending SIGALRM. */
311 inferior = (unsigned long) (*child) (data, child_alrm);
312 STATE (inferior, 1 << STATE_SLEEPING);
314 i = tkill (inferior, SIGSTOP);
317 i = tkill (inferior, SIGALRM);
319 STATE (inferior, 1 << STATE_STOPPED);
320 /* FIXME: SIGALRM did not get redelivered? */
322 stopped = attach_checked (inferior, SIGALRM);
324 stopped = attach_checked (inferior, 0);
326 assert (stopped == 1);
327 detach_checked (inferior, stopped);
328 STATE (inferior, 1 << STATE_STOPPED);
330 i = tkill (inferior, SIGCONT);
332 STATE (inferior, 1 << STATE_RUNNING);
336 static void *pass (void *data, void *input)
338 struct spawner *param = data;
339 void (*input_func) (void) = input;
342 return (*param->func) (param->data, input);
344 assert (input_func != NULL);
350 static void *spawn_singlethreaded (void *data, void *input)
352 return pass (data, input);
355 static void *spawn_threaded_parent_start (void *arg)
363 static void *spawn_threaded_parent (void *data, void *input)
368 i = pthread_create (&thread, NULL, spawn_threaded_parent_start, NULL);
370 return pass (data, input);
373 struct spawn_threaded_child_start
379 static void *spawn_threaded_child_start (void *arg_voidpointer)
381 struct spawn_threaded_child_start *arg = arg_voidpointer;
383 return pass (arg->data, arg->input);
387 static void *spawn_threaded_child (void *data, void *input)
391 struct spawn_threaded_child_start arg_local;
393 arg_local.data = data;
394 arg_local.input = input;
395 i = pthread_create (&thread, NULL, spawn_threaded_child_start, &arg_local);
397 i = pthread_join (thread, NULL);
400 _exit (EXIT_SUCCESS);
403 static void body_maywaiter (void *(*child) (void *data, void *input),
404 void *data, void *input)
406 struct spawner param_local;
408 param_local.func = child;
409 param_local.data = data;
410 body_spawner (spawn_without_waiter, ¶m_local, NULL);
411 body_spawner (spawn_with_waiter, ¶m_local, NULL);
414 int main (int argc, char **argv)
416 atexit (registry_atexit);
417 signal (SIGINT, registry_handler);
418 signal (SIGABRT, registry_handler);
420 body_maywaiter (spawn_singlethreaded, NULL, NULL);
421 body_maywaiter (spawn_threaded_parent, NULL, NULL);
422 body_maywaiter (spawn_threaded_child, NULL, NULL);