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 rfork(RFNOTEG);79 dup2(fd[0], 0);80 dup2(fd[1], 1);81 dup2(fd[2], 2);82 for(i=3; i<100; i++)83 if(i != p[1])84 close(i);85 execvp(cmd, argv);86 fprint(p[1], "%d", errno);87 close(p[1]);88 _exit(0);89 }91 close(p[1]);92 n = read(p[0], exitstr, sizeof exitstr-1);93 close(p[0]);94 if(n > 0){ /* exec failed */95 exitstr[n] = 0;96 errno = atoi(exitstr);97 return -1;98 }100 close(fd[0]);101 if(fd[1] != fd[0])102 close(fd[1]);103 if(fd[2] != fd[1] && fd[2] != fd[0])104 close(fd[2]);105 return pid;106 }108 int109 threadspawn(int fd[3], char *cmd, char *argv[])110 {111 return _runthreadspawn(fd, cmd, argv);112 }114 int115 threadspawnl(int fd[3], char *cmd, ...)116 {117 char **argv, *s;118 int n, pid;119 va_list arg;121 va_start(arg, cmd);122 for(n=0; va_arg(arg, char*) != nil; n++)123 ;124 n++;125 va_end(arg);127 argv = malloc(n*sizeof(argv[0]));128 if(argv == nil)129 return -1;131 va_start(arg, cmd);132 for(n=0; (s=va_arg(arg, char*)) != nil; n++)133 argv[n] = s;134 argv[n] = 0;135 va_end(arg);137 pid = threadspawn(fd, cmd, argv);138 free(argv);139 return pid;140 }142 int143 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])144 {145 int pid;147 pid = threadspawn(fd, cmd, argv);148 if(cpid){149 if(pid < 0)150 chansendul(cpid, ~0);151 else152 chansendul(cpid, pid);153 }154 return pid;155 }157 void158 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])159 {160 if(_threadexec(cpid, fd, cmd, argv) >= 0)161 threadexits("threadexec");162 }164 void165 threadexecl(Channel *cpid, int fd[3], char *cmd, ...)166 {167 char **argv, *s;168 int n, pid;169 va_list arg;171 va_start(arg, cmd);172 for(n=0; va_arg(arg, char*) != nil; n++)173 ;174 n++;175 va_end(arg);177 argv = malloc(n*sizeof(argv[0]));178 if(argv == nil){179 if(cpid)180 chansendul(cpid, ~0);181 return;182 }184 va_start(arg, cmd);185 for(n=0; (s=va_arg(arg, char*)) != nil; n++)186 argv[n] = s;187 argv[n] = 0;188 va_end(arg);190 pid = _threadexec(cpid, fd, cmd, argv);191 free(argv);193 if(pid >= 0)194 threadexits("threadexecl");195 }