#include #include #include #include #include #include #include #include static void sighup(int sig __unused) { } static void sleep_forever(void) { while (1) sleep(1); } static void * thread(void *arg __unused) { sleep_forever(); return (NULL); } int main(int argc, char **argv) { struct sigaction act; sigset_t set; pthread_t t; pid_t pid, ret; int try, limit, status; pid = fork(); if (pid < 0) err(1, "fork"); if (pid == 0) { act.sa_handler = sighup; act.sa_flags = 0; sigemptyset(&act.sa_mask); if (sigaction(SIGHUP, &act, NULL) != 0) err(1, "sigaction"); if (pthread_create(&t, NULL, thread, NULL) != 0) err(1, "pthread_create"); /* Force SIGHUP to be delivered to the new thread. */ sigemptyset(&set); sigaddset(&set, SIGHUP); if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) err(1, "pthread_sigmask"); sleep_forever(); } else { sleep(1); /* give the child a chance to set itself up */ limit = 100; for (try = 1; try <= limit; try++) { printf("attempt %d of %d\n", try, limit); if (kill(pid, SIGHUP) != 0) err(1, "kill(SIGHUP)"); if (ptrace(PT_ATTACH, pid, NULL, 0) != 0) err(1, "ptrace(PT_ATTACH)"); if (waitpid(pid, &status, WUNTRACED) != pid) err(1, "waitpid 1"); if (!WIFSTOPPED(status)) errx(1, "unexpected status %d after PT_ATTACH", status); if (ptrace(PT_DETACH, pid, NULL, 0) != 0) err(1, "ptrace(PT_DETACH)"); sleep(1); ret = waitpid(pid, &status, WUNTRACED | WNOHANG); if (ret < 0) err(1, "waitpid"); if (ret == 0) continue; if (!WIFSTOPPED(status)) errx(1, "unexpected status %d after PT_DETACH", status); printf("stopped on signal %d after detach\n", WSTOPSIG(status)); sleep_forever(); } } return (0); }