aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-04-21 22:44:37 +0000
committerrsc <devnull@localhost>2004-04-21 22:44:37 +0000
commit06c4fd06cae9dd155eb284eac046f54d1c75bb24 (patch)
tree6ec3e9519d2692896466284d62524537c74843fb
parentee6d04f9feec5011da240a9e08704c775806c331 (diff)
downloadplan9port-06c4fd06cae9dd155eb284eac046f54d1c75bb24.tar.gz
plan9port-06c4fd06cae9dd155eb284eac046f54d1c75bb24.tar.bz2
plan9port-06c4fd06cae9dd155eb284eac046f54d1c75bb24.zip
add RFNOWAIT. this was probably a bad idea.
-rw-r--r--src/lib9/mkfile1
-rw-r--r--src/lib9/rfork.c67
2 files changed, 65 insertions, 3 deletions
diff --git a/src/lib9/mkfile b/src/lib9/mkfile
index a3fe8df0..bdc8841f 100644
--- a/src/lib9/mkfile
+++ b/src/lib9/mkfile
@@ -118,6 +118,7 @@ LIB9OFILES=\
mallocz.$O\
nan.$O\
needsrcquote.$O\
+ needstack.$O\
netmkaddr.$O\
notify.$O\
nrand.$O\
diff --git a/src/lib9/rfork.c b/src/lib9/rfork.c
index 21dc17e8..d3c8f8b2 100644
--- a/src/lib9/rfork.c
+++ b/src/lib9/rfork.c
@@ -1,4 +1,6 @@
#include <u.h>
+#include <sys/wait.h>
+#include <signal.h>
#include <libc.h>
#include "9proc.h"
#undef rfork
@@ -6,16 +8,71 @@
int
p9rfork(int flags)
{
- int pid;
+ int pid, status;
+ int p[2];
+ int n;
+ char buf[128], *q;
+ _p9uproc(0);
if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
/* check other flags before we commit */
flags &= ~(RFPROC|RFFDG);
- if(flags & ~(RFNOTEG|RFNAMEG)){
- werrstr("unknown flags %08ux in rfork", flags);
+ n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT));
+ if(n){
+ werrstr("unknown flags %08ux in rfork", n);
return -1;
}
+ if(flags&RFNOWAIT){
+ if(pipe(p) < 0)
+ return -1;
+ }
pid = fork();
+ if(pid == -1)
+ return -1;
+ if(flags&RFNOWAIT){
+ flags &= ~RFNOWAIT;
+ if(pid){
+ /*
+ * Parent - wait for child to fork wait-free child.
+ * Then read pid from pipe. Assume pipe buffer can absorb the write.
+ */
+ close(p[1]);
+ wait4(pid, &status, 0, 0);
+ n = readn(p[0], buf, sizeof buf-1);
+ close(p[0]);
+ if(!WIFEXITED(status) || WEXITSTATUS(status)!=0 || n <= 0){
+ werrstr("pipe dance failed in rfork");
+ return -1;
+ }
+ buf[n] = 0;
+ n = strtol(buf, &q, 0);
+ if(*q != 0){
+ werrstr("%s", q);
+ return -1;
+ }
+ pid = n;
+ }else{
+ /*
+ * Child - fork a new child whose wait message can't
+ * get back to the parent because we're going to exit!
+ */
+ signal(SIGCHLD, SIG_IGN);
+ close(p[0]);
+ pid = fork();
+ if(pid){
+ /* Child parent - send status over pipe and exit. */
+ if(pid > 0)
+ fprint(p[1], "%d", pid);
+ else
+ fprint(p[1], " %r");
+ close(p[1]);
+ _exit(0);
+ }else{
+ /* Child child - close pipe. */
+ close(p[1]);
+ }
+ }
+ }
_p9uproc(0);
if(pid != 0)
return pid;
@@ -32,6 +89,10 @@ p9rfork(int flags)
setpgid(0, getpid());
flags &= ~RFNOTEG;
}
+ if(flags&RFNOWAIT){
+ werrstr("cannot use RFNOWAIT without RFPROC");
+ return -1;
+ }
if(flags){
werrstr("unknown flags %08ux in rfork", flags);
return -1;