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 dup2(fd[0], 0);
79 dup2(fd[1], 1);
80 dup2(fd[2], 2);
81 for(i=3; i<100; i++)
82 if(i != p[1])
83 close(i);
84 execvp(cmd, argv);
85 fprint(p[1], "%d", errno);
86 close(p[1]);
87 _exit(0);
88 }
90 close(p[1]);
91 n = read(p[0], exitstr, sizeof exitstr-1);
92 close(p[0]);
93 if(n > 0){ /* exec failed */
94 exitstr[n] = 0;
95 errno = atoi(exitstr);
96 return -1;
97 }
99 close(fd[0]);
100 if(fd[1] != fd[0])
101 close(fd[1]);
102 if(fd[2] != fd[1] && fd[2] != fd[0])
103 close(fd[2]);
104 return pid;
107 int
108 threadspawn(int fd[3], char *cmd, char *argv[])
110 return _runthreadspawn(fd, cmd, argv);
113 int
114 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
116 int pid;
118 pid = threadspawn(fd, cmd, argv);
119 if(cpid){
120 if(pid < 0)
121 chansendul(cpid, ~0);
122 else
123 chansendul(cpid, pid);
125 return pid;
128 void
129 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
131 if(_threadexec(cpid, fd, cmd, argv) >= 0)
132 threadexits("threadexec");
135 void
136 threadexecl(Channel *cpid, int fd[3], char *cmd, ...)
138 char **argv, *s;
139 int n, pid;
140 va_list arg;
142 va_start(arg, cmd);
143 for(n=0; va_arg(arg, char*) != nil; n++)
145 n++;
146 va_end(arg);
148 argv = malloc(n*sizeof(argv[0]));
149 if(argv == nil){
150 if(cpid)
151 chansendul(cpid, ~0);
152 return;
155 va_start(arg, cmd);
156 for(n=0; (s=va_arg(arg, char*)) != nil; n++)
157 argv[n] = s;
158 argv[n] = 0;
159 va_end(arg);
161 pid = _threadexec(cpid, fd, cmd, argv);
162 free(argv);
164 if(pid >= 0)
165 threadexits("threadexecl");