Blob
1 #include "threadimpl.h"3 static Lock thewaitlock;4 static Channel *thewaitchan;6 static void7 execproc(void *v)8 {9 int pid;10 Channel *c;11 Execjob *e;12 Waitmsg *w;14 e = v;15 pid = _threadspawn(e->fd, e->cmd, e->argv);16 sendul(e->c, pid);17 if(pid > 0){18 w = waitfor(pid);19 if((c = thewaitchan) != nil)20 sendp(c, w);21 else22 free(w);23 }24 threadexits(nil);25 }27 int28 _runthreadspawn(int *fd, char *cmd, char **argv)29 {30 int pid;31 Execjob e;33 e.fd = fd;34 e.cmd = cmd;35 e.argv = argv;36 e.c = chancreate(sizeof(void*), 0);37 proccreate(execproc, &e, 65536);38 pid = recvul(e.c);39 chanfree(e.c);40 return pid;41 }43 Channel*44 threadwaitchan(void)45 {46 if(thewaitchan)47 return thewaitchan;48 lock(&thewaitlock);49 if(thewaitchan){50 unlock(&thewaitlock);51 return thewaitchan;52 }53 thewaitchan = chancreate(sizeof(Waitmsg*), 4);54 chansetname(thewaitchan, "threadwaitchan");55 unlock(&thewaitlock);56 return thewaitchan;57 }59 int60 _threadspawn(int fd[3], char *cmd, char *argv[])61 {62 int i, n, p[2], pid;63 char exitstr[100];65 if(pipe(p) < 0)66 return -1;67 if(fcntl(p[0], F_SETFD, 1) < 0 || fcntl(p[1], F_SETFD, 1) < 0){68 close(p[0]);69 close(p[1]);70 return -1;71 }72 switch(pid = fork()){73 case -1:74 close(p[0]);75 close(p[1]);76 return -1;77 case 0:78 /* can't RFNOTEG - will lose tty */79 dup2(fd[0], 0);80 dup2(fd[1], 1);81 dup2(fd[2], 2);82 if(!isatty(0) && !isatty(1) && !isatty(2))83 rfork(RFNOTEG);84 for(i=3; i<100; i++)85 if(i != p[1])86 close(i);87 execvp(cmd, argv);88 fprint(p[1], "%d", errno);89 close(p[1]);90 _exit(0);91 }93 close(p[1]);94 n = read(p[0], exitstr, sizeof exitstr-1);95 close(p[0]);96 if(n > 0){ /* exec failed */97 free(waitfor(pid));98 exitstr[n] = 0;99 errno = atoi(exitstr);100 return -1;101 }103 close(fd[0]);104 if(fd[1] != fd[0])105 close(fd[1]);106 if(fd[2] != fd[1] && fd[2] != fd[0])107 close(fd[2]);108 return pid;109 }111 int112 threadspawn(int fd[3], char *cmd, char *argv[])113 {114 return _runthreadspawn(fd, cmd, argv);115 }117 int118 threadspawnl(int fd[3], char *cmd, ...)119 {120 char **argv, *s;121 int n, pid;122 va_list arg;124 va_start(arg, cmd);125 for(n=0; va_arg(arg, char*) != nil; n++)126 ;127 n++;128 va_end(arg);130 argv = malloc(n*sizeof(argv[0]));131 if(argv == nil)132 return -1;134 va_start(arg, cmd);135 for(n=0; (s=va_arg(arg, char*)) != nil; n++)136 argv[n] = s;137 argv[n] = 0;138 va_end(arg);140 pid = threadspawn(fd, cmd, argv);141 free(argv);142 return pid;143 }145 int146 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])147 {148 int pid;150 pid = threadspawn(fd, cmd, argv);151 if(cpid){152 if(pid < 0)153 chansendul(cpid, ~0);154 else155 chansendul(cpid, pid);156 }157 return pid;158 }160 void161 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])162 {163 if(_threadexec(cpid, fd, cmd, argv) >= 0)164 threadexits("threadexec");165 }167 void168 threadexecl(Channel *cpid, int fd[3], char *cmd, ...)169 {170 char **argv, *s;171 int n, pid;172 va_list arg;174 va_start(arg, cmd);175 for(n=0; va_arg(arg, char*) != nil; n++)176 ;177 n++;178 va_end(arg);180 argv = malloc(n*sizeof(argv[0]));181 if(argv == nil){182 if(cpid)183 chansendul(cpid, ~0);184 return;185 }187 va_start(arg, cmd);188 for(n=0; (s=va_arg(arg, char*)) != nil; n++)189 argv[n] = s;190 argv[n] = 0;191 va_end(arg);193 pid = _threadexec(cpid, fd, cmd, argv);194 free(argv);196 if(pid >= 0)197 threadexits("threadexecl");198 }