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 dup2(fd[0], 0);
80 dup2(fd[1], 1);
81 dup2(fd[2], 2);
82 if(!isatty(0) && !isatty(1) && !isatty(2))
83 rfork(RFNOTEG);
84 for(i=3; i<100; i++)
85 if(i != p[1])
86 close(i);
87 execvp(cmd, argv);
88 fprint(p[1], "%d", errno);
89 close(p[1]);
90 _exit(0);
91 }
93 close(p[1]);
94 n = read(p[0], exitstr, sizeof exitstr-1);
95 close(p[0]);
96 if(n > 0){ /* exec failed */
97 free(waitfor(pid));
98 exitstr[n] = 0;
99 errno = atoi(exitstr);
100 return -1;
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;
111 int
112 threadspawn(int fd[3], char *cmd, char *argv[])
114 return _runthreadspawn(fd, cmd, argv);
117 int
118 threadspawnl(int fd[3], char *cmd, ...)
120 char **argv, *s;
121 int n, pid;
122 va_list arg;
124 va_start(arg, cmd);
125 for(n=0; va_arg(arg, char*) != nil; n++)
127 n++;
128 va_end(arg);
130 argv = malloc(n*sizeof(argv[0]));
131 if(argv == nil)
132 return -1;
134 va_start(arg, cmd);
135 for(n=0; (s=va_arg(arg, char*)) != nil; n++)
136 argv[n] = s;
137 argv[n] = 0;
138 va_end(arg);
140 pid = threadspawn(fd, cmd, argv);
141 free(argv);
142 return pid;
145 int
146 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
148 int pid;
150 pid = threadspawn(fd, cmd, argv);
151 if(cpid){
152 if(pid < 0)
153 chansendul(cpid, ~0);
154 else
155 chansendul(cpid, pid);
157 return pid;
160 void
161 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
163 if(_threadexec(cpid, fd, cmd, argv) >= 0)
164 threadexits("threadexec");
167 void
168 threadexecl(Channel *cpid, int fd[3], char *cmd, ...)
170 char **argv, *s;
171 int n, pid;
172 va_list arg;
174 va_start(arg, cmd);
175 for(n=0; va_arg(arg, char*) != nil; n++)
177 n++;
178 va_end(arg);
180 argv = malloc(n*sizeof(argv[0]));
181 if(argv == nil){
182 if(cpid)
183 chansendul(cpid, ~0);
184 return;
187 va_start(arg, cmd);
188 for(n=0; (s=va_arg(arg, char*)) != nil; n++)
189 argv[n] = s;
190 argv[n] = 0;
191 va_end(arg);
193 pid = _threadexec(cpid, fd, cmd, argv);
194 free(argv);
196 if(pid >= 0)
197 threadexits("threadexecl");