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 void
13 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 else
27 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 int
51 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 int
100 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
102 int pid;
104 pid = threadspawn(fd, cmd, argv);
105 if(cpid){
106 if(pid < 0)
107 chansendul(cpid, ~0);
108 else
109 chansendul(cpid, pid);
111 return pid;
114 void
115 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
117 if(_threadexec(cpid, fd, cmd, argv) >= 0)
118 threadexits("threadexec");
121 void
122 threadexecl(Channel *cpid, int fd[3], char *cmd, ...)
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++)
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;
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");