Blob


1 #include "u.h"
2 #include <errno.h>
3 #include "libc.h"
4 #include "thread.h"
5 #include "threadimpl.h"
7 static Lock thewaitlock;
8 static Channel *thewaitchan;
10 static void
11 execproc(void *v)
12 {
13 int pid;
14 Channel *c;
15 Execjob *e;
16 Waitmsg *w;
18 e = v;
19 pid = _threadspawn(e->fd, e->cmd, e->argv);
20 sendul(e->c, pid);
21 if(pid > 0){
22 w = waitfor(pid);
23 if((c = thewaitchan) != nil)
24 sendp(c, w);
25 else
26 free(w);
27 }
28 threadexits(nil);
29 }
31 int
32 _runthreadspawn(int *fd, char *cmd, char **argv)
33 {
34 int pid;
35 Execjob e;
37 e.fd = fd;
38 e.cmd = cmd;
39 e.argv = argv;
40 e.c = chancreate(sizeof(void*), 0);
41 proccreate(execproc, &e, 65536);
42 pid = recvul(e.c);
43 chanfree(e.c);
44 return pid;
45 }
47 Channel*
48 threadwaitchan(void)
49 {
50 if(thewaitchan)
51 return thewaitchan;
52 lock(&thewaitlock);
53 if(thewaitchan){
54 unlock(&thewaitlock);
55 return thewaitchan;
56 }
57 thewaitchan = chancreate(sizeof(Waitmsg*), 4);
58 chansetname(thewaitchan, "threadwaitchan");
59 unlock(&thewaitlock);
60 return thewaitchan;
61 }
63 int
64 _threadspawn(int fd[3], char *cmd, char *argv[])
65 {
66 int i, n, p[2], pid;
67 char exitstr[100];
69 if(pipe(p) < 0)
70 return -1;
71 if(fcntl(p[0], F_SETFD, 1) < 0 || fcntl(p[1], F_SETFD, 1) < 0){
72 close(p[0]);
73 close(p[1]);
74 return -1;
75 }
76 switch(pid = fork()){
77 case -1:
78 close(p[0]);
79 close(p[1]);
80 return -1;
81 case 0:
82 dup2(fd[0], 0);
83 dup2(fd[1], 1);
84 dup2(fd[2], 2);
85 for(i=3; i<100; i++)
86 if(i != p[1])
87 close(i);
88 execvp(cmd, argv);
89 fprint(p[1], "%d", errno);
90 close(p[1]);
91 _exit(0);
92 }
94 close(p[1]);
95 n = read(p[0], exitstr, sizeof exitstr-1);
96 close(p[0]);
97 if(n > 0){ /* exec failed */
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 _threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
120 int pid;
122 pid = threadspawn(fd, cmd, argv);
123 if(cpid){
124 if(pid < 0)
125 chansendul(cpid, ~0);
126 else
127 chansendul(cpid, pid);
129 return pid;
132 void
133 threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
135 if(_threadexec(cpid, fd, cmd, argv) >= 0)
136 threadexits("threadexec");
139 void
140 threadexecl(Channel *cpid, int fd[3], char *cmd, ...)
142 char **argv, *s;
143 int n, pid;
144 va_list arg;
146 va_start(arg, cmd);
147 for(n=0; va_arg(arg, char*) != nil; n++)
149 n++;
150 va_end(arg);
152 argv = malloc(n*sizeof(argv[0]));
153 if(argv == nil){
154 if(cpid)
155 chansendul(cpid, ~0);
156 return;
159 va_start(arg, cmd);
160 for(n=0; (s=va_arg(arg, char*)) != nil; n++)
161 argv[n] = s;
162 argv[n] = 0;
163 va_end(arg);
165 pid = _threadexec(cpid, fd, cmd, argv);
166 free(argv);
168 if(pid >= 0)
169 threadexits("threadexecl");