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 notifyoff("sys: child"); /* do not let child note kill us */66 if(pipe(p) < 0)67 return -1;68 if(fcntl(p[0], F_SETFD, 1) < 0 || fcntl(p[1], F_SETFD, 1) < 0){69 close(p[0]);70 close(p[1]);71 return -1;72 }73 switch(pid = fork()){74 case -1:75 close(p[0]);76 close(p[1]);77 return -1;78 case 0:79 /* can't RFNOTEG - will lose tty */80 dup2(fd[0], 0);81 dup2(fd[1], 1);82 dup2(fd[2], 2);83 if(!isatty(0) && !isatty(1) && !isatty(2))84 rfork(RFNOTEG);85 for(i=3; i<100; i++)86 if(i != p[1])87 close(i);88 execvp(cmd, argv);89 fprint(p[1], "%d", errno);90 close(p[1]);91 _exit(0);92 }94 close(p[1]);95 n = read(p[0], exitstr, sizeof exitstr-1);96 close(p[0]);97 if(n > 0){ /* exec failed */98 free(waitfor(pid));99 exitstr[n] = 0;100 errno = atoi(exitstr);101 return -1;102 }104 close(fd[0]);105 if(fd[1] != fd[0])106 close(fd[1]);107 if(fd[2] != fd[1] && fd[2] != fd[0])108 close(fd[2]);109 return pid;110 }112 int113 threadspawn(int fd[3], char *cmd, char *argv[])114 {115 return _runthreadspawn(fd, cmd, argv);116 }118 int119 threadspawnl(int fd[3], char *cmd, ...)120 {121 char **argv, *s;122 int n, pid;123 va_list arg;125 va_start(arg, cmd);126 for(n=0; va_arg(arg, char*) != nil; n++)127 ;128 n++;129 va_end(arg);131 argv = malloc(n*sizeof(argv[0]));132 if(argv == nil)133 return -1;135 va_start(arg, cmd);136 for(n=0; (s=va_arg(arg, char*)) != nil; n++)137 argv[n] = s;138 argv[n] = 0;139 va_end(arg);141 pid = threadspawn(fd, cmd, argv);142 free(argv);143 return pid;144 }146 int147 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])148 {149 int pid;151 pid = threadspawn(fd, cmd, argv);152 if(cpid){153 if(pid < 0)154 chansendul(cpid, ~0);155 else156 chansendul(cpid, pid);157 }158 return pid;159 }161 void162 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])163 {164 if(_threadexec(cpid, fd, cmd, argv) >= 0)165 threadexits("threadexec");166 }168 void169 threadexecl(Channel *cpid, int fd[3], char *cmd, ...)170 {171 char **argv, *s;172 int n, pid;173 va_list arg;175 va_start(arg, cmd);176 for(n=0; va_arg(arg, char*) != nil; n++)177 ;178 n++;179 va_end(arg);181 argv = malloc(n*sizeof(argv[0]));182 if(argv == nil){183 if(cpid)184 chansendul(cpid, ~0);185 return;186 }188 va_start(arg, cmd);189 for(n=0; (s=va_arg(arg, char*)) != nil; n++)190 argv[n] = s;191 argv[n] = 0;192 va_end(arg);194 pid = _threadexec(cpid, fd, cmd, argv);195 free(argv);197 if(pid >= 0)198 threadexits("threadexecl");199 }