Blob
1 #include "u.h"2 #include <errno.h>3 #include "libc.h"4 #include "thread.h"5 #include "threadimpl.h"7 static Lock thewaitlock;8 static Channel *thewaitchan;10 static void11 execproc(void *v)12 {13 int pid;14 Channel *c;15 Execjob *e;16 Waitmsg *w;18 e = v;19 pid = _threadspawn(e->fd, e->cmd, e->argv);20 sendul(e->c, pid);21 if(pid > 0){22 w = waitfor(pid);23 if((c = thewaitchan) != nil)24 sendp(c, w);25 else26 free(w);27 }28 threadexits(nil);29 }31 int32 _runthreadspawn(int *fd, char *cmd, char **argv)33 {34 int pid;35 Execjob e;37 e.fd = fd;38 e.cmd = cmd;39 e.argv = argv;40 e.c = chancreate(sizeof(void*), 0);41 proccreate(execproc, &e, 65536);42 pid = recvul(e.c);43 chanfree(e.c);44 return pid;45 }47 Channel*48 threadwaitchan(void)49 {50 if(thewaitchan)51 return thewaitchan;52 lock(&thewaitlock);53 if(thewaitchan){54 unlock(&thewaitlock);55 return thewaitchan;56 }57 thewaitchan = chancreate(sizeof(Waitmsg*), 4);58 chansetname(thewaitchan, "threadwaitchan");59 unlock(&thewaitlock);60 return thewaitchan;61 }63 int64 _threadspawn(int fd[3], char *cmd, char *argv[])65 {66 int i, n, p[2], pid;67 char exitstr[100];69 if(pipe(p) < 0)70 return -1;71 if(fcntl(p[0], F_SETFD, 1) < 0 || fcntl(p[1], F_SETFD, 1) < 0){72 close(p[0]);73 close(p[1]);74 return -1;75 }76 switch(pid = fork()){77 case -1:78 close(p[0]);79 close(p[1]);80 return -1;81 case 0:82 dup2(fd[0], 0);83 dup2(fd[1], 1);84 dup2(fd[2], 2);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 exitstr[n] = 0;99 errno = atoi(exitstr);100 return -1;101 }103 close(fd[0]);104 if(fd[1] != fd[0])105 close(fd[1]);106 if(fd[2] != fd[1] && fd[2] != fd[0])107 close(fd[2]);108 return pid;109 }111 int112 threadspawn(int fd[3], char *cmd, char *argv[])113 {114 return _runthreadspawn(fd, cmd, argv);115 }117 int118 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])119 {120 int pid;122 pid = threadspawn(fd, cmd, argv);123 if(cpid){124 if(pid < 0)125 chansendul(cpid, ~0);126 else127 chansendul(cpid, pid);128 }129 return pid;130 }132 void133 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])134 {135 if(_threadexec(cpid, fd, cmd, argv) >= 0)136 threadexits("threadexec");137 }139 void140 threadexecl(Channel *cpid, int fd[3], char *cmd, ...)141 {142 char **argv, *s;143 int n, pid;144 va_list arg;146 va_start(arg, cmd);147 for(n=0; va_arg(arg, char*) != nil; n++)148 ;149 n++;150 va_end(arg);152 argv = malloc(n*sizeof(argv[0]));153 if(argv == nil){154 if(cpid)155 chansendul(cpid, ~0);156 return;157 }159 va_start(arg, cmd);160 for(n=0; (s=va_arg(arg, char*)) != nil; n++)161 argv[n] = s;162 argv[n] = 0;163 va_end(arg);165 pid = _threadexec(cpid, fd, cmd, argv);166 free(argv);168 if(pid >= 0)169 threadexits("threadexecl");170 }