From 1544f90960275dc9211bde30329c3258e0e1bf38 Mon Sep 17 00:00:00 2001 From: rsc Date: Sat, 25 Dec 2004 21:56:33 +0000 Subject: New thread library --- src/libthread/exec.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 src/libthread/exec.c (limited to 'src/libthread/exec.c') 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 +#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"); +} + -- cgit v1.2.3