Consider below test case (not all of it is necessary for reproducing the behavior in question, but I wanted to cover related cases as well to make sure they behave as expected). In this test case, the last group-stop (after PTRACE_INTERRUPT) is delivered with a WSTOPSIG(status) of SIGTTIN, which was the signr of the previous group stop. From reading the man-page, I would have expected SIGTRAP. Now, I understand that if there is another stop pending, PTRACE_INTERRUPT will simply piggy-backs off that one, but I don't believe that is happening in this case. Further, the current behavior seems to make it very hard (impossible?) to reliably tell a true group-stop from a PTRACE_INTERRUPT generated one. Is this behavior intended? If so, I would be happy to update the man page accordingly, but would like some guidance on what the intended semantics are.
``` #include <assert.h> #include <stdlib.h> #include <stdio.h> #include <signal.h> #include <unistd.h> #include <sys/ptrace.h> #include <sys/wait.h> #include <linux/ptrace.h> int main() { pid_t child, ret; int err; int status; if (0 == (child = fork())) { kill(getpid(), SIGSTOP); kill(getpid(), SIGSTOP); kill(getpid(), SIGTTIN); sleep(1000); exit(0); } ret = waitpid(child, &status, WSTOPPED); assert(ret == child); err = ptrace(PTRACE_SEIZE, child, NULL, NULL); assert(err == 0); err = ptrace(PTRACE_CONT, child, NULL, NULL); assert(err == 0); // Should now hit SIGSTOP signal-stop ret = waitpid(child, &status, 0); assert(ret == child && WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP); err = ptrace(PTRACE_CONT, child, NULL, (void*)SIGSTOP); assert(err == 0); // Should now hit SIGSTOP group-stop ret = waitpid(child, &status, 0); assert(ret == child && (status>>16 == PTRACE_EVENT_STOP) && WSTOPSIG(status) == SIGSTOP); err = ptrace(PTRACE_CONT, child, NULL, NULL); assert(err == 0); // Should now hit SIGTTIN signal-stop ret = waitpid(child, &status, 0); assert(ret == child && WIFSTOPPED(status) && WSTOPSIG(status) == SIGTTIN); err = ptrace(PTRACE_CONT, child, NULL, (void*)SIGTTIN); assert(err == 0); // Should now hit SIGTTIN group-stop ret = waitpid(child, &status, 0); assert(ret == child && (status>>16 == PTRACE_EVENT_STOP) && WSTOPSIG(status) == SIGTTIN); err = ptrace(PTRACE_CONT, child, NULL, NULL); assert(err == 0); // Now interrupt it err = ptrace(PTRACE_INTERRUPT, child, NULL, NULL); assert(err == 0); // Should now hit interrupt group-stop ret = waitpid(child, &status, 0); printf("Interrupt group-stop delivered with signal %d\n", WSTOPSIG(status)); assert(ret == child && (status>>16 == PTRACE_EVENT_STOP) && WSTOPSIG(status) == SIGTRAP); exit(0); } ```