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, e->dir);
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, char *dir)
29 {
30 int pid;
31 Execjob e;
33 e.fd = fd;
34 e.cmd = cmd;
35 e.argv = argv;
36 e.dir = dir;
37 e.c = chancreate(sizeof(void*), 0);
38 proccreate(execproc, &e, 65536);
39 pid = recvul(e.c);
40 chanfree(e.c);
41 return pid;
42 }
44 Channel*
45 threadwaitchan(void)
46 {
47 if(thewaitchan)
48 return thewaitchan;
49 lock(&thewaitlock);
50 if(thewaitchan){
51 unlock(&thewaitlock);
52 return thewaitchan;
53 }
54 thewaitchan = chancreate(sizeof(Waitmsg*), 4);
55 chansetname(thewaitchan, "threadwaitchan");
56 unlock(&thewaitlock);
57 return thewaitchan;
58 }
60 int
61 _threadspawn(int fd[3], char *cmd, char *argv[], char *dir)
62 {
63 int i, n, p[2], pid;
64 char exitstr[100];
66 notifyoff("sys: child"); /* do not let child note kill us */
67 if(pipe(p) < 0)
68 return -1;
69 if(fcntl(p[0], F_SETFD, 1) < 0 || fcntl(p[1], F_SETFD, 1) < 0){
70 close(p[0]);
71 close(p[1]);
72 return -1;
73 }
74 switch(pid = fork()){
75 case -1:
76 close(p[0]);
77 close(p[1]);
78 return -1;
79 case 0:
80 /* can't RFNOTEG - will lose tty */
81 if(dir != nil )
82 chdir(dir); /* best effort */
83 dup2(fd[0], 0);
84 dup2(fd[1], 1);
85 dup2(fd[2], 2);
86 if(!isatty(0) && !isatty(1) && !isatty(2))
87 rfork(RFNOTEG);
88 for(i=3; i<100; i++)
89 if(i != p[1])
90 close(i);
91 execvp(cmd, argv);
92 fprint(p[1], "%d", errno);
93 close(p[1]);
94 _exit(0);
95 }
97 close(p[1]);
98 n = read(p[0], exitstr, sizeof exitstr-1);
99 close(p[0]);
100 if(n > 0){ /* exec failed */
101 free(waitfor(pid));
102 exitstr[n] = 0;
103 errno = atoi(exitstr);
104 return -1;
107 close(fd[0]);
108 if(fd[1] != fd[0])
109 close(fd[1]);
110 if(fd[2] != fd[1] && fd[2] != fd[0])
111 close(fd[2]);
112 return pid;
115 int
116 threadspawn(int fd[3], char *cmd, char *argv[])
118 return _runthreadspawn(fd, cmd, argv, nil);
121 int
122 threadspawnd(int fd[3], char *cmd, char *argv[], char *dir)
124 return _runthreadspawn(fd, cmd, argv, dir);
127 int
128 threadspawnl(int fd[3], char *cmd, ...)
130 char **argv, *s;
131 int n, pid;
132 va_list arg;
134 va_start(arg, cmd);
135 for(n=0; va_arg(arg, char*) != nil; n++)
137 n++;
138 va_end(arg);
140 argv = malloc(n*sizeof(argv[0]));
141 if(argv == nil)
142 return -1;
144 va_start(arg, cmd);
145 for(n=0; (s=va_arg(arg, char*)) != nil; n++)
146 argv[n] = s;
147 argv[n] = 0;
148 va_end(arg);
150 pid = threadspawn(fd, cmd, argv);
151 free(argv);
152 return pid;
155 int
156 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
158 int pid;
160 pid = threadspawn(fd, cmd, argv);
161 if(cpid){
162 if(pid < 0)
163 chansendul(cpid, ~0);
164 else
165 chansendul(cpid, pid);
167 return pid;
170 void
171 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
173 if(_threadexec(cpid, fd, cmd, argv) >= 0)
174 threadexits("threadexec");
177 void
178 threadexecl(Channel *cpid, int fd[3], char *cmd, ...)
180 char **argv, *s;
181 int n, pid;
182 va_list arg;
184 va_start(arg, cmd);
185 for(n=0; va_arg(arg, char*) != nil; n++)
187 n++;
188 va_end(arg);
190 argv = malloc(n*sizeof(argv[0]));
191 if(argv == nil){
192 if(cpid)
193 chansendul(cpid, ~0);
194 return;
197 va_start(arg, cmd);
198 for(n=0; (s=va_arg(arg, char*)) != nil; n++)
199 argv[n] = s;
200 argv[n] = 0;
201 va_end(arg);
203 pid = _threadexec(cpid, fd, cmd, argv);
204 free(argv);
206 if(pid >= 0)
207 threadexits("threadexecl");