/* Test sending a signal to a fork/execed Windows child when the Cygwin parent has defined a non-default handler for that signal. gcc -Wall -g kill_winproc.c -o kill_winproc.exe; \ gcc -Wall -g -mno-cygwin kill_winproc.c -o winsleep.exe; \ ./kill_winproc.exe */ #ifdef __CYGWIN__ #include #include #include #include #include #include #define WINSLEEP "winsleep.exe" #define WAIT_TIME 5 /* seconds */ pid_t spawn(const char *path, const char * const argv[]) { pid_t pid; pid = fork(); switch (pid) { case -1: /* fork failed */ perror("spawn: fork failed"); break; case 0: /* child */ execv(path, (char * const *)argv); perror("spawn: execv failed"); _exit(127); } return pid; } void parent_term_handler(int sig) { fprintf(stderr, "Child called TERM handler\n"); puts("Fail\n"); exit(-1); } void (*sigset(int sig, void (*disp)(int)))(int) { struct sigaction new, old; new.sa_handler = disp; new.sa_flags = 0; if (sigemptyset(&new.sa_mask) == 0 && sigaction(sig, &new, &old) == 0) return old.sa_handler; return SIG_ERR; } int main(void) { const char * const argv[2] = { WINSLEEP, NULL }; pid_t pid; unsigned int wait; /* Commenting this out makes it pass */ if (sigset(SIGTERM, parent_term_handler) == SIG_ERR) { perror("sigset"); goto fail; } /* Fork sleeping child */ pid = spawn(WINSLEEP, argv); if (pid < 0) goto fail; /* Give it a head start */ for (wait = WAIT_TIME; wait; wait = sleep(wait)); /* Send TERM to child */ if (kill(pid, SIGTERM) < 0) { perror("kill(SIGTERM)"); goto fail; } /* Give time for child to die */ for (wait = WAIT_TIME; wait; wait = sleep(wait)); /* Check child status */ if (kill(pid, 0) == 0) { fprintf(stderr, "Process %d still valid\n", pid); goto fail; } else if (errno != ESRCH) { perror("kill(0)"); goto fail; } puts("Pass"); return 0; fail: puts("Failed"); return -1; } #else /* ndef __CYGWIN__ */ #include int main(void) { for (;;) Sleep(1000); return 0; } #endif /* ndef __CYGWIN__ */