aboutsummaryrefslogtreecommitdiff
path: root/src/libthread/exec.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-12-25 21:56:33 +0000
committerrsc <devnull@localhost>2004-12-25 21:56:33 +0000
commit1544f90960275dc9211bde30329c3258e0e1bf38 (patch)
treef55e7a73c03aaa24daa7cc2ad02822b921c477f9 /src/libthread/exec.c
parent7788fd54094693384ef5c92c475656dba8819feb (diff)
downloadplan9port-1544f90960275dc9211bde30329c3258e0e1bf38.tar.gz
plan9port-1544f90960275dc9211bde30329c3258e0e1bf38.tar.bz2
plan9port-1544f90960275dc9211bde30329c3258e0e1bf38.zip
New thread library
Diffstat (limited to 'src/libthread/exec.c')
-rw-r--r--src/libthread/exec.c153
1 files changed, 153 insertions, 0 deletions
diff --git a/src/libthread/exec.c b/src/libthread/exec.c
new file mode 100644
index 00000000..2cbb4437
--- /dev/null
+++ b/src/libthread/exec.c
@@ -0,0 +1,153 @@
+#include "u.h"
+#include <errno.h>
+#include "libc.h"
+#include "thread.h"
+#include "threadimpl.h"
+
+static Lock thewaitlock;
+static Channel *thewaitchan;
+static Channel *dowaitchan;
+
+/* BUG - start waitproc on first exec, not when threadwaitchan is called */
+static void
+waitproc(void *v)
+{
+ Channel *c;
+ Waitmsg *w;
+
+ _threadsetsysproc();
+ for(;;){
+ while((w = wait()) == nil){
+ if(errno == ECHILD)
+ recvul(dowaitchan);
+ }
+ if((c = thewaitchan) != nil)
+ sendp(c, w);
+ else
+ free(w);
+ }
+}
+
+Channel*
+threadwaitchan(void)
+{
+ if(thewaitchan)
+ return thewaitchan;
+ lock(&thewaitlock);
+ if(thewaitchan){
+ unlock(&thewaitlock);
+ return thewaitchan;
+ }
+ thewaitchan = chancreate(sizeof(Waitmsg*), 4);
+ chansetname(thewaitchan, "threadwaitchan");
+ dowaitchan = chancreate(sizeof(ulong), 1);
+ chansetname(dowaitchan, "dowaitchan");
+ proccreate(waitproc, nil, STACK);
+ unlock(&thewaitlock);
+ return thewaitchan;
+}
+
+int
+threadspawn(int fd[3], char *cmd, char *argv[])
+{
+ int i, n, p[2], pid;
+ char exitstr[100];
+
+ if(pipe(p) < 0)
+ return -1;
+ if(fcntl(p[0], F_SETFD, 1) < 0 || fcntl(p[1], F_SETFD, 1) < 0){
+ close(p[0]);
+ close(p[1]);
+ return -1;
+ }
+ switch(pid = fork()){
+ case -1:
+ close(p[0]);
+ close(p[1]);
+ return -1;
+ case 0:
+ dup2(fd[0], 0);
+ dup2(fd[1], 1);
+ dup2(fd[2], 2);
+ for(i=3; i<100; i++)
+ if(i != p[1])
+ close(i);
+ execvp(cmd, argv);
+ fprint(p[1], "%d", errno);
+ close(p[1]);
+ _exit(0);
+ }
+
+ close(p[1]);
+ n = read(p[0], exitstr, sizeof exitstr-1);
+ close(p[0]);
+ if(n > 0){ /* exec failed */
+ exitstr[n] = 0;
+ errno = atoi(exitstr);
+ return -1;
+ }
+
+ close(fd[0]);
+ if(fd[1] != fd[0])
+ close(fd[1]);
+ if(fd[2] != fd[1] && fd[2] != fd[0])
+ close(fd[2]);
+ channbsendul(dowaitchan, 1);
+ return pid;
+}
+
+int
+_threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
+{
+ int pid;
+
+ pid = threadspawn(fd, cmd, argv);
+ if(cpid){
+ if(pid < 0)
+ chansendul(cpid, ~0);
+ else
+ chansendul(cpid, pid);
+ }
+ return pid;
+}
+
+void
+threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
+{
+ if(_threadexec(cpid, fd, cmd, argv) >= 0)
+ threadexits("threadexec");
+}
+
+void
+threadexecl(Channel *cpid, int fd[3], char *cmd, ...)
+{
+ char **argv, *s;
+ int n, pid;
+ va_list arg;
+
+ va_start(arg, cmd);
+ for(n=0; va_arg(arg, char*) != nil; n++)
+ ;
+ n++;
+ va_end(arg);
+
+ argv = malloc(n*sizeof(argv[0]));
+ if(argv == nil){
+ if(cpid)
+ chansendul(cpid, ~0);
+ return;
+ }
+
+ va_start(arg, cmd);
+ for(n=0; (s=va_arg(arg, char*)) != nil; n++)
+ argv[n] = s;
+ argv[n] = 0;
+ va_end(arg);
+
+ pid = _threadexec(cpid, fd, cmd, argv);
+ free(argv);
+
+ if(pid >= 0)
+ threadexits("threadexecl");
+}
+