Logo Search packages:      
Sourcecode: 9base version File versions  Download package

rfork.c

#include <u.h>
#include <sys/wait.h>
#include <signal.h>
#include <libc.h>
#undef rfork

static void
nop(int x)
{
      USED(x);
}

int
p9rfork(int flags)
{
      int pid, status;
      int p[2];
      int n;
      char buf[128], *q;

      if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
            /* check other flags before we commit */
            flags &= ~(RFPROC|RFFDG);
            n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT));
            if(n){
                  werrstr("unknown flags %08ux in rfork", n);
                  return -1;
            }
            if(flags&RFNOWAIT){
                  /*
                   * BUG - should put the signal handler back after we
                   * finish, but I just don't care.  If a program calls with
                   * NOWAIT once, they're not likely to want child notes
                   * after that.
                   */
                  signal(SIGCHLD, nop);
                  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]);
                        status = 0;
                        if(wait4(pid, &status, 0, 0) < 0){
                              werrstr("pipe dance - wait4 - %r");
                              close(p[0]);
                              return -1;
                        }
                        n = readn(p[0], buf, sizeof buf-1);
                        close(p[0]);
                        if(!WIFEXITED(status) || WEXITSTATUS(status)!=0 || n <= 0){
                              if(!WIFEXITED(status))
                                    werrstr("pipe dance - !exited 0x%ux", status);
                              else if(WEXITSTATUS(status) != 0)
                                    werrstr("pipe dance - non-zero status 0x%ux", status);
                              else if(n < 0)
                                    werrstr("pipe dance - pipe read error - %r");
                              else if(n == 0)
                                    werrstr("pipe dance - pipe read eof");
                              else
                                    werrstr("pipe dance - unknown failure");
                              return -1;
                        }
                        buf[n] = 0;
                        if(buf[0] == 'x'){
                              werrstr("%s", buf+2);
                              return -1;
                        }
                        pid = strtol(buf, &q, 0);
                  }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], "x %r");
                              close(p[1]);
                              _exit(0);
                        }else{
                              /* Child child - close pipe. */
                              close(p[1]);
                        }
                  }
            }
            if(pid != 0)
                  return pid;
      }
      if(flags&RFPROC){
            werrstr("cannot use rfork for shared memory -- use ffork");
            return -1;
      }
      if(flags&RFNAMEG){
            /* XXX set $NAMESPACE to a new directory */
            flags &= ~RFNAMEG;
      }
      if(flags&RFNOTEG){
            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;
      }
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index