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 /* rfork(RFNOTEG); */80 dup2(fd[0], 0);81 dup2(fd[1], 1);82 dup2(fd[2], 2);83 for(i=3; i<100; i++)84 if(i != p[1])85 close(i);86 execvp(cmd, argv);87 fprint(p[1], "%d", errno);88 close(p[1]);89 _exit(0);90 }92 close(p[1]);93 n = read(p[0], exitstr, sizeof exitstr-1);94 close(p[0]);95 if(n > 0){ /* exec failed */96 exitstr[n] = 0;97 errno = atoi(exitstr);98 return -1;99 }101 close(fd[0]);102 if(fd[1] != fd[0])103 close(fd[1]);104 if(fd[2] != fd[1] && fd[2] != fd[0])105 close(fd[2]);106 return pid;107 }109 int110 threadspawn(int fd[3], char *cmd, char *argv[])111 {112 return _runthreadspawn(fd, cmd, argv);113 }115 int116 threadspawnl(int fd[3], char *cmd, ...)117 {118 char **argv, *s;119 int n, pid;120 va_list arg;122 va_start(arg, cmd);123 for(n=0; va_arg(arg, char*) != nil; n++)124 ;125 n++;126 va_end(arg);128 argv = malloc(n*sizeof(argv[0]));129 if(argv == nil)130 return -1;132 va_start(arg, cmd);133 for(n=0; (s=va_arg(arg, char*)) != nil; n++)134 argv[n] = s;135 argv[n] = 0;136 va_end(arg);138 pid = threadspawn(fd, cmd, argv);139 free(argv);140 return pid;141 }143 int144 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])145 {146 int pid;148 pid = threadspawn(fd, cmd, argv);149 if(cpid){150 if(pid < 0)151 chansendul(cpid, ~0);152 else153 chansendul(cpid, pid);154 }155 return pid;156 }158 void159 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])160 {161 if(_threadexec(cpid, fd, cmd, argv) >= 0)162 threadexits("threadexec");163 }165 void166 threadexecl(Channel *cpid, int fd[3], char *cmd, ...)167 {168 char **argv, *s;169 int n, pid;170 va_list arg;172 va_start(arg, cmd);173 for(n=0; va_arg(arg, char*) != nil; n++)174 ;175 n++;176 va_end(arg);178 argv = malloc(n*sizeof(argv[0]));179 if(argv == nil){180 if(cpid)181 chansendul(cpid, ~0);182 return;183 }185 va_start(arg, cmd);186 for(n=0; (s=va_arg(arg, char*)) != nil; n++)187 argv[n] = s;188 argv[n] = 0;189 va_end(arg);191 pid = _threadexec(cpid, fd, cmd, argv);192 free(argv);194 if(pid >= 0)195 threadexits("threadexecl");196 }