URI:
       trfork.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       trfork.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 }