mirror of
https://github.com/HeyPuter/gex.git
synced 2026-11-13 20:12:43 -10:00
80 lines
2.2 KiB
C
80 lines
2.2 KiB
C
/* A child that stays alive after fork (like `cmd &`), works in the parent
|
|
* while it does, exchanges messages over pipes, and reaps it at the end.
|
|
*
|
|
* Every line is ordered by an event -- a pipe read, a write, an exit status --
|
|
* never by which process happens to be scheduled.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
|
|
static void put(const char *s) {
|
|
/* Unbuffered, because the interleaving between two processes is the point
|
|
* and stdio would reorder it into whichever flushed last. */
|
|
write(1, s, strlen(s));
|
|
}
|
|
|
|
int main(void) {
|
|
int down[2], up[2];
|
|
if (pipe(down) != 0 || pipe(up) != 0) {
|
|
put("pipe failed\n");
|
|
return 1;
|
|
}
|
|
|
|
pid_t kid = fork();
|
|
if (kid < 0) {
|
|
put("fork failed\n");
|
|
return 1;
|
|
}
|
|
if (kid == 0) {
|
|
close(down[1]);
|
|
close(up[0]);
|
|
/* Nothing is printed before this read: the parent must run to send
|
|
* anything, so reaching the end of it is the whole test. A line before
|
|
* it would be ordered by scheduling alone. */
|
|
char buf[32];
|
|
ssize_t n = read(down[0], buf, sizeof buf - 1);
|
|
if (n <= 0) {
|
|
put("child: the parent never wrote\n");
|
|
_exit(2);
|
|
}
|
|
buf[n] = 0;
|
|
put("child: got ");
|
|
put(buf);
|
|
put("\n");
|
|
write(up[1], "ok", 2);
|
|
_exit(7);
|
|
}
|
|
|
|
close(down[0]);
|
|
close(up[1]);
|
|
/* The parent keeps working while the child is alive. */
|
|
put("parent: still running\n");
|
|
long acc = 0;
|
|
for (long i = 0; i < 200000; i++) {
|
|
acc += i % 7;
|
|
}
|
|
if (acc == 0) {
|
|
put("parent: impossible\n");
|
|
}
|
|
put("parent: sending work\n");
|
|
write(down[1], "hello", 5);
|
|
|
|
char reply[8];
|
|
ssize_t n = read(up[0], reply, sizeof reply - 1);
|
|
reply[n > 0 ? n : 0] = 0;
|
|
put("parent: child replied ");
|
|
put(reply);
|
|
put("\n");
|
|
|
|
int status = 0;
|
|
if (waitpid(kid, &status, 0) != kid) {
|
|
put("parent: waitpid did not find the child\n");
|
|
return 1;
|
|
}
|
|
printf("parent: child exited %d\n", WIFEXITED(status) ? WEXITSTATUS(status) : -1);
|
|
return 0;
|
|
}
|