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, e->dir);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, char *dir)29 {30 int pid;31 Execjob e;33 e.fd = fd;34 e.cmd = cmd;35 e.argv = argv;36 e.dir = dir;37 e.c = chancreate(sizeof(void*), 0);38 proccreate(execproc, &e, 65536);39 pid = recvul(e.c);40 chanfree(e.c);41 return pid;42 }44 Channel*45 threadwaitchan(void)46 {47 if(thewaitchan)48 return thewaitchan;49 lock(&thewaitlock);50 if(thewaitchan){51 unlock(&thewaitlock);52 return thewaitchan;53 }54 thewaitchan = chancreate(sizeof(Waitmsg*), 4);55 chansetname(thewaitchan, "threadwaitchan");56 unlock(&thewaitlock);57 return thewaitchan;58 }60 int61 _threadspawn(int fd[3], char *cmd, char *argv[], char *dir)62 {63 int i, n, p[2], pid;64 char exitstr[100];66 notifyoff("sys: child"); /* do not let child note kill us */67 if(pipe(p) < 0)68 return -1;69 if(fcntl(p[0], F_SETFD, 1) < 0 || fcntl(p[1], F_SETFD, 1) < 0){70 close(p[0]);71 close(p[1]);72 return -1;73 }74 switch(pid = fork()){75 case -1:76 close(p[0]);77 close(p[1]);78 return -1;79 case 0:80 /* can't RFNOTEG - will lose tty */81 if(dir != nil )82 chdir(dir); /* best effort */83 dup2(fd[0], 0);84 dup2(fd[1], 1);85 dup2(fd[2], 2);86 if(!isatty(0) && !isatty(1) && !isatty(2))87 rfork(RFNOTEG);88 for(i=3; i<100; i++)89 if(i != p[1])90 close(i);91 execvp(cmd, argv);92 fprint(p[1], "%d", errno);93 close(p[1]);94 _exit(0);95 }97 close(p[1]);98 n = read(p[0], exitstr, sizeof exitstr-1);99 close(p[0]);100 if(n > 0){ /* exec failed */101 free(waitfor(pid));102 exitstr[n] = 0;103 errno = atoi(exitstr);104 return -1;105 }107 close(fd[0]);108 if(fd[1] != fd[0])109 close(fd[1]);110 if(fd[2] != fd[1] && fd[2] != fd[0])111 close(fd[2]);112 return pid;113 }115 int116 threadspawn(int fd[3], char *cmd, char *argv[])117 {118 return _runthreadspawn(fd, cmd, argv, nil);119 }121 int122 threadspawnd(int fd[3], char *cmd, char *argv[], char *dir)123 {124 return _runthreadspawn(fd, cmd, argv, dir);125 }127 int128 threadspawnl(int fd[3], char *cmd, ...)129 {130 char **argv, *s;131 int n, pid;132 va_list arg;134 va_start(arg, cmd);135 for(n=0; va_arg(arg, char*) != nil; n++)136 ;137 n++;138 va_end(arg);140 argv = malloc(n*sizeof(argv[0]));141 if(argv == nil)142 return -1;144 va_start(arg, cmd);145 for(n=0; (s=va_arg(arg, char*)) != nil; n++)146 argv[n] = s;147 argv[n] = 0;148 va_end(arg);150 pid = threadspawn(fd, cmd, argv);151 free(argv);152 return pid;153 }155 int156 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])157 {158 int pid;160 pid = threadspawn(fd, cmd, argv);161 if(cpid){162 if(pid < 0)163 chansendul(cpid, ~0);164 else165 chansendul(cpid, pid);166 }167 return pid;168 }170 void171 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])172 {173 if(_threadexec(cpid, fd, cmd, argv) >= 0)174 threadexits("threadexec");175 }177 void178 threadexecl(Channel *cpid, int fd[3], char *cmd, ...)179 {180 char **argv, *s;181 int n, pid;182 va_list arg;184 va_start(arg, cmd);185 for(n=0; va_arg(arg, char*) != nil; n++)186 ;187 n++;188 va_end(arg);190 argv = malloc(n*sizeof(argv[0]));191 if(argv == nil){192 if(cpid)193 chansendul(cpid, ~0);194 return;195 }197 va_start(arg, cmd);198 for(n=0; (s=va_arg(arg, char*)) != nil; n++)199 argv[n] = s;200 argv[n] = 0;201 va_end(arg);203 pid = _threadexec(cpid, fd, cmd, argv);204 free(argv);206 if(pid >= 0)207 threadexits("threadexecl");208 }