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 rfork(RFNOTEG);
79 dup2(fd[0], 0);
80 dup2(fd[1], 1);
81 dup2(fd[2], 2);
82 for(i=3; i<100; i++)
83 if(i != p[1])
84 close(i);
85 execvp(cmd, argv);
86 fprint(p[1], "%d", errno);
87 close(p[1]);
88 _exit(0);
89 }
91 close(p[1]);
92 n = read(p[0], exitstr, sizeof exitstr-1);
93 close(p[0]);
94 if(n > 0){ /* exec failed */
95 exitstr[n] = 0;
96 errno = atoi(exitstr);
97 return -1;
98 }
100 close(fd[0]);
101 if(fd[1] != fd[0])
102 close(fd[1]);
103 if(fd[2] != fd[1] && fd[2] != fd[0])
104 close(fd[2]);
105 return pid;
108 int
109 threadspawn(int fd[3], char *cmd, char *argv[])
111 return _runthreadspawn(fd, cmd, argv);
114 int
115 threadspawnl(int fd[3], char *cmd, ...)
117 char **argv, *s;
118 int n, pid;
119 va_list arg;
121 va_start(arg, cmd);
122 for(n=0; va_arg(arg, char*) != nil; n++)
124 n++;
125 va_end(arg);
127 argv = malloc(n*sizeof(argv[0]));
128 if(argv == nil)
129 return -1;
131 va_start(arg, cmd);
132 for(n=0; (s=va_arg(arg, char*)) != nil; n++)
133 argv[n] = s;
134 argv[n] = 0;
135 va_end(arg);
137 pid = threadspawn(fd, cmd, argv);
138 free(argv);
139 return pid;
142 int
143 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
145 int pid;
147 pid = threadspawn(fd, cmd, argv);
148 if(cpid){
149 if(pid < 0)
150 chansendul(cpid, ~0);
151 else
152 chansendul(cpid, pid);
154 return pid;
157 void
158 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
160 if(_threadexec(cpid, fd, cmd, argv) >= 0)
161 threadexits("threadexec");
164 void
165 threadexecl(Channel *cpid, int fd[3], char *cmd, ...)
167 char **argv, *s;
168 int n, pid;
169 va_list arg;
171 va_start(arg, cmd);
172 for(n=0; va_arg(arg, char*) != nil; n++)
174 n++;
175 va_end(arg);
177 argv = malloc(n*sizeof(argv[0]));
178 if(argv == nil){
179 if(cpid)
180 chansendul(cpid, ~0);
181 return;
184 va_start(arg, cmd);
185 for(n=0; (s=va_arg(arg, char*)) != nil; n++)
186 argv[n] = s;
187 argv[n] = 0;
188 va_end(arg);
190 pid = _threadexec(cpid, fd, cmd, argv);
191 free(argv);
193 if(pid >= 0)
194 threadexits("threadexecl");