/* This testcase is part of GDB, the GNU debugger. Copyright 2007 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include static void action(int sig, siginfo_t * info, void *uc) { raise (SIGALRM); } static void loop (void) { struct sigaction act; memset (&act, 0, sizeof(struct sigaction)); act.sa_sigaction = action; act.sa_flags = SA_RESTART; sigaction (SIGALRM, &act, 0); raise (SIGALRM); putchar ('!'); for (;;) pause (); /* NOTREACHED */ abort (); } static pid_t child; static void cleanup (void) { kill (child, SIGKILL); } static void handler (int signo) { cleanup (); } int main (void) { void (*handler_orig) (int signo); setbuf (stdout, NULL); child = fork (); switch (child) { case -1: abort (); case 0: loop (); /* NOTREACHED */ abort (); default: break; } atexit (cleanup); handler_orig = signal (SIGABRT, handler); assert (handler_orig == SIG_DFL); for (;;) { errno = 0; ptrace (PTRACE_ATTACH, child, NULL, NULL); assert_perror (errno); unsigned long sig; /* Deliver one SIGSTOP just for sure. If the process was already stopped AND some other process (like shell) has already waited for it we would get stuck in waitpid (). */ sig = SIGSTOP; do { pid_t got_pid; int status; errno = 0; ptrace (PT_CONTINUE, child, (void *) 1UL, (void *) sig); /* For unstopped processes the preventive signal may ESRCH. */ if (sig != SIGSTOP) { assert_perror (errno); putchar ('.'); } got_pid = waitpid (child, &status, 0); assert (got_pid == child); /* Check if the thread has exited. */ assert (!WIFEXITED (status)); assert (!WIFSIGNALED (status)); assert (WIFSTOPPED (status)); sig = WSTOPSIG (status); assert (sig != 0); } while (sig != SIGSTOP); errno = 0; ptrace (PTRACE_DETACH, child, (void *) 1UL, (void *) 0UL); assert_perror (errno); } return 0; }