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;9 static Channel *dowaitchan;11 /* BUG - start waitproc on first exec, not when threadwaitchan is called */12 static void13 waitproc(void *v)14 {15 Channel *c;16 Waitmsg *w;18 _threadsetsysproc();19 for(;;){20 while((w = wait()) == nil){21 if(errno == ECHILD)22 recvul(dowaitchan);23 }24 if((c = thewaitchan) != nil)25 sendp(c, w);26 else27 free(w);28 }29 }31 Channel*32 threadwaitchan(void)33 {34 if(thewaitchan)35 return thewaitchan;36 lock(&thewaitlock);37 if(thewaitchan){38 unlock(&thewaitlock);39 return thewaitchan;40 }41 thewaitchan = chancreate(sizeof(Waitmsg*), 4);42 chansetname(thewaitchan, "threadwaitchan");43 dowaitchan = chancreate(sizeof(ulong), 1);44 chansetname(dowaitchan, "dowaitchan");45 proccreate(waitproc, nil, STACK);46 unlock(&thewaitlock);47 return thewaitchan;48 }50 int51 threadspawn(int fd[3], char *cmd, char *argv[])52 {53 int i, n, p[2], pid;54 char exitstr[100];56 if(pipe(p) < 0)57 return -1;58 if(fcntl(p[0], F_SETFD, 1) < 0 || fcntl(p[1], F_SETFD, 1) < 0){59 close(p[0]);60 close(p[1]);61 return -1;62 }63 switch(pid = fork()){64 case -1:65 close(p[0]);66 close(p[1]);67 return -1;68 case 0:69 dup2(fd[0], 0);70 dup2(fd[1], 1);71 dup2(fd[2], 2);72 for(i=3; i<100; i++)73 if(i != p[1])74 close(i);75 execvp(cmd, argv);76 fprint(p[1], "%d", errno);77 close(p[1]);78 _exit(0);79 }81 close(p[1]);82 n = read(p[0], exitstr, sizeof exitstr-1);83 close(p[0]);84 if(n > 0){ /* exec failed */85 exitstr[n] = 0;86 errno = atoi(exitstr);87 return -1;88 }90 close(fd[0]);91 if(fd[1] != fd[0])92 close(fd[1]);93 if(fd[2] != fd[1] && fd[2] != fd[0])94 close(fd[2]);95 channbsendul(dowaitchan, 1);96 return pid;97 }99 int100 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])101 {102 int pid;104 pid = threadspawn(fd, cmd, argv);105 if(cpid){106 if(pid < 0)107 chansendul(cpid, ~0);108 else109 chansendul(cpid, pid);110 }111 return pid;112 }114 void115 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])116 {117 if(_threadexec(cpid, fd, cmd, argv) >= 0)118 threadexits("threadexec");119 }121 void122 threadexecl(Channel *cpid, int fd[3], char *cmd, ...)123 {124 char **argv, *s;125 int n, pid;126 va_list arg;128 va_start(arg, cmd);129 for(n=0; va_arg(arg, char*) != nil; n++)130 ;131 n++;132 va_end(arg);134 argv = malloc(n*sizeof(argv[0]));135 if(argv == nil){136 if(cpid)137 chansendul(cpid, ~0);138 return;139 }141 va_start(arg, cmd);142 for(n=0; (s=va_arg(arg, char*)) != nil; n++)143 argv[n] = s;144 argv[n] = 0;145 va_end(arg);147 pid = _threadexec(cpid, fd, cmd, argv);148 free(argv);150 if(pid >= 0)151 threadexits("threadexecl");152 }