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 dup2(fd[0], 0);79 dup2(fd[1], 1);80 dup2(fd[2], 2);81 for(i=3; i<100; i++)82 if(i != p[1])83 close(i);84 execvp(cmd, argv);85 fprint(p[1], "%d", errno);86 close(p[1]);87 _exit(0);88 }90 close(p[1]);91 n = read(p[0], exitstr, sizeof exitstr-1);92 close(p[0]);93 if(n > 0){ /* exec failed */94 exitstr[n] = 0;95 errno = atoi(exitstr);96 return -1;97 }99 close(fd[0]);100 if(fd[1] != fd[0])101 close(fd[1]);102 if(fd[2] != fd[1] && fd[2] != fd[0])103 close(fd[2]);104 return pid;105 }107 int108 threadspawn(int fd[3], char *cmd, char *argv[])109 {110 return _runthreadspawn(fd, cmd, argv);111 }113 int114 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])115 {116 int pid;118 pid = threadspawn(fd, cmd, argv);119 if(cpid){120 if(pid < 0)121 chansendul(cpid, ~0);122 else123 chansendul(cpid, pid);124 }125 return pid;126 }128 void129 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])130 {131 if(_threadexec(cpid, fd, cmd, argv) >= 0)132 threadexits("threadexec");133 }135 void136 threadexecl(Channel *cpid, int fd[3], char *cmd, ...)137 {138 char **argv, *s;139 int n, pid;140 va_list arg;142 va_start(arg, cmd);143 for(n=0; va_arg(arg, char*) != nil; n++)144 ;145 n++;146 va_end(arg);148 argv = malloc(n*sizeof(argv[0]));149 if(argv == nil){150 if(cpid)151 chansendul(cpid, ~0);152 return;153 }155 va_start(arg, cmd);156 for(n=0; (s=va_arg(arg, char*)) != nil; n++)157 argv[n] = s;158 argv[n] = 0;159 va_end(arg);161 pid = _threadexec(cpid, fd, cmd, argv);162 free(argv);164 if(pid >= 0)165 threadexits("threadexecl");166 }