Blob


1 #include "threadimpl.h"
3 static Lock thewaitlock;
4 static Channel *thewaitchan;
6 static void
7 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 else
22 free(w);
23 }
24 threadexits(nil);
25 }
27 int
28 _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 int
60 _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 /* can't RFNOTEG - will lose tty */
79 /* rfork(RFNOTEG); */
80 dup2(fd[0], 0);
81 dup2(fd[1], 1);
82 dup2(fd[2], 2);
83 for(i=3; i<100; i++)
84 if(i != p[1])
85 close(i);
86 execvp(cmd, argv);
87 fprint(p[1], "%d", errno);
88 close(p[1]);
89 _exit(0);
90 }
92 close(p[1]);
93 n = read(p[0], exitstr, sizeof exitstr-1);
94 close(p[0]);
95 if(n > 0){ /* exec failed */
96 exitstr[n] = 0;
97 errno = atoi(exitstr);
98 return -1;
99 }
101 close(fd[0]);
102 if(fd[1] != fd[0])
103 close(fd[1]);
104 if(fd[2] != fd[1] && fd[2] != fd[0])
105 close(fd[2]);
106 return pid;
109 int
110 threadspawn(int fd[3], char *cmd, char *argv[])
112 return _runthreadspawn(fd, cmd, argv);
115 int
116 threadspawnl(int fd[3], char *cmd, ...)
118 char **argv, *s;
119 int n, pid;
120 va_list arg;
122 va_start(arg, cmd);
123 for(n=0; va_arg(arg, char*) != nil; n++)
125 n++;
126 va_end(arg);
128 argv = malloc(n*sizeof(argv[0]));
129 if(argv == nil)
130 return -1;
132 va_start(arg, cmd);
133 for(n=0; (s=va_arg(arg, char*)) != nil; n++)
134 argv[n] = s;
135 argv[n] = 0;
136 va_end(arg);
138 pid = threadspawn(fd, cmd, argv);
139 free(argv);
140 return pid;
143 int
144 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
146 int pid;
148 pid = threadspawn(fd, cmd, argv);
149 if(cpid){
150 if(pid < 0)
151 chansendul(cpid, ~0);
152 else
153 chansendul(cpid, pid);
155 return pid;
158 void
159 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
161 if(_threadexec(cpid, fd, cmd, argv) >= 0)
162 threadexits("threadexec");
165 void
166 threadexecl(Channel *cpid, int fd[3], char *cmd, ...)
168 char **argv, *s;
169 int n, pid;
170 va_list arg;
172 va_start(arg, cmd);
173 for(n=0; va_arg(arg, char*) != nil; n++)
175 n++;
176 va_end(arg);
178 argv = malloc(n*sizeof(argv[0]));
179 if(argv == nil){
180 if(cpid)
181 chansendul(cpid, ~0);
182 return;
185 va_start(arg, cmd);
186 for(n=0; (s=va_arg(arg, char*)) != nil; n++)
187 argv[n] = s;
188 argv[n] = 0;
189 va_end(arg);
191 pid = _threadexec(cpid, fd, cmd, argv);
192 free(argv);
194 if(pid >= 0)
195 threadexits("threadexecl");