Last active
December 28, 2019 21:50
-
-
Save frehberg/58cac82a332febd6aff0e188c825b699 to your computer and use it in GitHub Desktop.
C death pipe
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <poll.h> | |
#include <string.h> | |
#include <sys/wait.h> | |
#include <fcntl.h> | |
/** | |
* This application is creating a child-process and waiting until the child-process | |
* did terminate. | |
* | |
* Between parent process and child-process a death-pipe is established. When the child-process | |
* terminates, an event appears on the read-end of the death-pipe. The parent-process | |
* will poll for the POLLIN-event, waiting for the termination of the child-process. | |
* | |
* The parent process can be executed in two modes: | |
* 1) The NOT-QT_MODE is keeping the write-end in child-process and keeping the read-end | |
* in parent-process. | |
* > a.out not-qt-mode | |
* | |
* 2) The QT_MODE is closing all file descriptors in child-process and keeping both file-descriptors in | |
* parent-process. | |
* > a.out qt-mode | |
* | |
* Finally the parent process will verify the status of the child-process. In case the child-process | |
* did not terminate as expected, an error message will be printed. | |
*/ | |
#define NOT_QT_MODE "not-qt-mode" | |
#define QT_MODE "qt-mode" | |
// seceonds | |
#define SLEEP_SECONDS 3 | |
int main(int argc, char *argv[], char *envp[]) { | |
char *mode = argc > 1 ? argv[1] : NOT_QT_MODE; | |
int qtmode = strcmp(QT_MODE, mode) == 0; | |
int isChild = argc > 2; | |
int pid; | |
int death_pipe[2]; | |
if (isChild) { | |
printf("[child] sub-process via execve\n"); | |
printf("[child] ..sleeping\n"); | |
sleep(SLEEP_SECONDS); | |
printf("[child] ..terminating\n"); | |
exit(0); | |
} | |
printf("[parent] forking child using '%s'\n", mode); | |
if (pipe(death_pipe) < 0) { | |
printf("[parent] ..failed to create pipe"); | |
exit(1); | |
} | |
if ((pid = fork()) < 0) { | |
printf("[parent] ..failed to fork"); | |
exit(1); | |
} | |
if (0 == pid) { | |
// child | |
printf("[child] setting up child-context\n"); | |
if (qtmode) { | |
// working the way QtProcess is working | |
// closing both ends of death_pipe in child-process | |
close(death_pipe[0]); | |
close(death_pipe[1]); | |
} else { | |
// working the other way | |
// in child-process, prevent the writing end will be inherited to further child-processes, | |
// and closing just the reading end of the death_pipe | |
close(death_pipe[0]); | |
} | |
// in child-process context, execute a new binary | |
char * const command[] = {argv[0], mode, "child", NULL}; | |
if (execve(argv[0], command, envp) < 0) { | |
printf("[child] ..failed to execve\n"); | |
printf("[child] ..terminating with error\n"); | |
exit(1); | |
} | |
} else { | |
// parent | |
int milli_timeout = 500; | |
int pollcnt = 0; | |
struct pollfd pollset[1]; | |
pollset[0].fd = death_pipe[0]; | |
pollset[0].events = POLLIN; | |
pollset[0].revents = 0; | |
int cnt_down = 2 * SLEEP_SECONDS * 1000 / milli_timeout; | |
if (qtmode) { | |
// keeping both ends of death_üpipe in parent-process | |
// don't close anything | |
} else { | |
// closing the writng end of the pipe | |
close(death_pipe[1]); | |
} | |
while (--cnt_down > 0 && (pollcnt = poll(pollset, 1, milli_timeout)) == 0) { | |
printf("[parent] ..awaiting child-proc termination %d\n", cnt_down); | |
} | |
if (cnt_down <= 0) { | |
printf("[parent] FAILURE, ime exceeded, death_pipe did not trigger event\n"); | |
} else { | |
printf("[parent] death_pipe triggered event: pollrv=%d\n", pollcnt); | |
} | |
// death_pipe signal occured, now verify the child did terminate | |
if (waitpid(pid, NULL, WNOHANG)==0) { | |
printf("[parent] FAILURE, faulty death_pipe event, the child-process did not terminate yet\n"); | |
printf("[parent] ..waiting for child-process termination\n"); | |
wait(NULL); | |
} | |
} | |
printf("[parent] terminating\n"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment