plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

rfork.c (2758B)


      1 #include <u.h>
      2 #include <sys/wait.h>
      3 #include <signal.h>
      4 #include <libc.h>
      5 #undef rfork
      6 
      7 static void
      8 nop(int x)
      9 {
     10 	USED(x);
     11 }
     12 
     13 int
     14 p9rfork(int flags)
     15 {
     16 	int pid, status;
     17 	int p[2];
     18 	int n;
     19 	char buf[128], *q;
     20 	extern char **environ;
     21 	struct sigaction oldchld;
     22 
     23 	memset(&oldchld, 0, sizeof oldchld);
     24 
     25 	if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
     26 		/* check other flags before we commit */
     27 		flags &= ~(RFPROC|RFFDG|RFENVG);
     28 		n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT|RFCENVG));
     29 		if(n){
     30 			werrstr("unknown flags %08ux in rfork", n);
     31 			return -1;
     32 		}
     33 		if(flags&RFNOWAIT){
     34 			sigaction(SIGCHLD, nil, &oldchld);
     35 			signal(SIGCHLD, nop);
     36 			if(pipe(p) < 0)
     37 				return -1;
     38 		}
     39 		pid = fork();
     40 		if(pid == -1)
     41 			return -1;
     42 		if(flags&RFNOWAIT){
     43 			flags &= ~RFNOWAIT;
     44 			if(pid){
     45 				/*
     46 				 * Parent - wait for child to fork wait-free child.
     47 				 * Then read pid from pipe.  Assume pipe buffer can absorb the write.
     48 				 */
     49 				close(p[1]);
     50 				status = 0;
     51 				if(wait4(pid, &status, 0, 0) < 0){
     52 					werrstr("pipe dance - wait4 - %r");
     53 					close(p[0]);
     54 					return -1;
     55 				}
     56 				n = readn(p[0], buf, sizeof buf-1);
     57 				close(p[0]);
     58 				if(!WIFEXITED(status) || WEXITSTATUS(status)!=0 || n <= 0){
     59 					if(!WIFEXITED(status))
     60 						werrstr("pipe dance - !exited 0x%ux", status);
     61 					else if(WEXITSTATUS(status) != 0)
     62 						werrstr("pipe dance - non-zero status 0x%ux", status);
     63 					else if(n < 0)
     64 						werrstr("pipe dance - pipe read error - %r");
     65 					else if(n == 0)
     66 						werrstr("pipe dance - pipe read eof");
     67 					else
     68 						werrstr("pipe dance - unknown failure");
     69 					return -1;
     70 				}
     71 				buf[n] = 0;
     72 				if(buf[0] == 'x'){
     73 					werrstr("%s", buf+2);
     74 					return -1;
     75 				}
     76 				pid = strtol(buf, &q, 0);
     77 			}else{
     78 				/*
     79 				 * Child - fork a new child whose wait message can't
     80 				 * get back to the parent because we're going to exit!
     81 				 */
     82 				signal(SIGCHLD, SIG_IGN);
     83 				close(p[0]);
     84 				pid = fork();
     85 				if(pid){
     86 					/* Child parent - send status over pipe and exit. */
     87 					if(pid > 0)
     88 						fprint(p[1], "%d", pid);
     89 					else
     90 						fprint(p[1], "x %r");
     91 					close(p[1]);
     92 					_exit(0);
     93 				}else{
     94 					/* Child child - close pipe. */
     95 					close(p[1]);
     96 				}
     97 			}
     98 			sigaction(SIGCHLD, &oldchld, nil);
     99 		}
    100 		if(pid != 0)
    101 			return pid;
    102 		if(flags&RFCENVG)
    103 			if(environ)
    104 				*environ = nil;
    105 	}
    106 	if(flags&RFPROC){
    107 		werrstr("cannot use rfork for shared memory -- use libthread");
    108 		return -1;
    109 	}
    110 	if(flags&RFNAMEG){
    111 		/* XXX set $NAMESPACE to a new directory */
    112 		flags &= ~RFNAMEG;
    113 	}
    114 	if(flags&RFNOTEG){
    115 		setpgid(0, getpid());
    116 		flags &= ~RFNOTEG;
    117 	}
    118 	if(flags&RFNOWAIT){
    119 		werrstr("cannot use RFNOWAIT without RFPROC");
    120 		return -1;
    121 	}
    122 	if(flags){
    123 		werrstr("unknown flags %08ux in rfork", flags);
    124 		return -1;
    125 	}
    126 	return 0;
    127 }