| #include "threadimpl.h" |
| |
| static Lock thewaitlock; |
| static Channel *thewaitchan; |
| |
| static void |
| execproc(void *v) |
| { |
| int pid; |
| Channel *c; |
| Execjob *e; |
| Waitmsg *w; |
| |
| e = v; |
| pid = _threadspawn(e->fd, e->cmd, e->argv, e->dir); |
| sendul(e->c, pid); |
| if(pid > 0){ |
| w = waitfor(pid); |
| if((c = thewaitchan) != nil) |
| sendp(c, w); |
| else |
| free(w); |
| } |
| threadexits(nil); |
| } |
| |
| int |
| _runthreadspawn(int *fd, char *cmd, char **argv, char *dir) |
| { |
| int pid; |
| Execjob e; |
| |
| e.fd = fd; |
| e.cmd = cmd; |
| e.argv = argv; |
| e.dir = dir; |
| e.c = chancreate(sizeof(void*), 0); |
| proccreate(execproc, &e, 65536); |
| pid = recvul(e.c); |
| chanfree(e.c); |
| return pid; |
| } |
| |
| Channel* |
| threadwaitchan(void) |
| { |
| if(thewaitchan) |
| return thewaitchan; |
| lock(&thewaitlock); |
| if(thewaitchan){ |
| unlock(&thewaitlock); |
| return thewaitchan; |
| } |
| thewaitchan = chancreate(sizeof(Waitmsg*), 4); |
| chansetname(thewaitchan, "threadwaitchan"); |
| unlock(&thewaitlock); |
| return thewaitchan; |
| } |
| |
| int |
| _threadspawn(int fd[3], char *cmd, char *argv[], char *dir) |
| { |
| int i, n, p[2], pid; |
| char exitstr[100]; |
| |
| notifyoff("sys: child"); /* do not let child note kill us */ |
| if(pipe(p) < 0) |
| return -1; |
| if(fcntl(p[0], F_SETFD, 1) < 0 || fcntl(p[1], F_SETFD, 1) < 0){ |
| close(p[0]); |
| close(p[1]); |
| return -1; |
| } |
| switch(pid = fork()){ |
| case -1: |
| close(p[0]); |
| close(p[1]); |
| return -1; |
| case 0: |
| /* can't RFNOTEG - will lose tty */ |
| if(dir != nil ) |
| chdir(dir); /* best effort */ |
| dup2(fd[0], 0); |
| dup2(fd[1], 1); |
| dup2(fd[2], 2); |
| if(!isatty(0) && !isatty(1) && !isatty(2)) |
| rfork(RFNOTEG); |
| for(i=3; i<100; i++) |
| if(i != p[1]) |
| close(i); |
| execvp(cmd, argv); |
| fprint(p[1], "%d", errno); |
| close(p[1]); |
| _exit(0); |
| } |
| |
| close(p[1]); |
| n = read(p[0], exitstr, sizeof exitstr-1); |
| close(p[0]); |
| if(n > 0){ /* exec failed */ |
| free(waitfor(pid)); |
| exitstr[n] = 0; |
| errno = atoi(exitstr); |
| return -1; |
| } |
| |
| close(fd[0]); |
| if(fd[1] != fd[0]) |
| close(fd[1]); |
| if(fd[2] != fd[1] && fd[2] != fd[0]) |
| close(fd[2]); |
| return pid; |
| } |
| |
| int |
| threadspawn(int fd[3], char *cmd, char *argv[]) |
| { |
| return _runthreadspawn(fd, cmd, argv, nil); |
| } |
| |
| int |
| threadspawnd(int fd[3], char *cmd, char *argv[], char *dir) |
| { |
| return _runthreadspawn(fd, cmd, argv, dir); |
| } |
| |
| int |
| threadspawnl(int fd[3], char *cmd, ...) |
| { |
| char **argv, *s; |
| int n, pid; |
| va_list arg; |
| |
| va_start(arg, cmd); |
| for(n=0; va_arg(arg, char*) != nil; n++) |
| ; |
| n++; |
| va_end(arg); |
| |
| argv = malloc(n*sizeof(argv[0])); |
| if(argv == nil) |
| return -1; |
| |
| va_start(arg, cmd); |
| for(n=0; (s=va_arg(arg, char*)) != nil; n++) |
| argv[n] = s; |
| argv[n] = 0; |
| va_end(arg); |
| |
| pid = threadspawn(fd, cmd, argv); |
| free(argv); |
| return pid; |
| } |
| |
| int |
| _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[]) |
| { |
| int pid; |
| |
| pid = threadspawn(fd, cmd, argv); |
| if(cpid){ |
| if(pid < 0) |
| chansendul(cpid, ~0); |
| else |
| chansendul(cpid, pid); |
| } |
| return pid; |
| } |
| |
| void |
| threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[]) |
| { |
| if(_threadexec(cpid, fd, cmd, argv) >= 0) |
| threadexits("threadexec"); |
| } |
| |
| void |
| threadexecl(Channel *cpid, int fd[3], char *cmd, ...) |
| { |
| char **argv, *s; |
| int n, pid; |
| va_list arg; |
| |
| va_start(arg, cmd); |
| for(n=0; va_arg(arg, char*) != nil; n++) |
| ; |
| n++; |
| va_end(arg); |
| |
| argv = malloc(n*sizeof(argv[0])); |
| if(argv == nil){ |
| if(cpid) |
| chansendul(cpid, ~0); |
| return; |
| } |
| |
| va_start(arg, cmd); |
| for(n=0; (s=va_arg(arg, char*)) != nil; n++) |
| argv[n] = s; |
| argv[n] = 0; |
| va_end(arg); |
| |
| pid = _threadexec(cpid, fd, cmd, argv); |
| free(argv); |
| |
| if(pid >= 0) |
| threadexits("threadexecl"); |
| } |
| |