Fighting the good fight.

Move libfmt, libutf into subdirectories of lib9.

Add poll-based socket i/o to libthread, so that we can
avoid using multiple procs when possible, thus removing
dependence on crappy pthreads implementations.

Convert samterm, acme to the single-proc libthread.

Bring libcomplete, acme up-to-date w.r.t. Plan 9 distribution.
This commit is contained in:
rsc 2004-02-29 22:10:26 +00:00
parent d51419bf43
commit 5a8e63b2f0
107 changed files with 665 additions and 6637 deletions

View file

@ -2,28 +2,18 @@
#include <unistd.h>
#include "threadimpl.h"
static void efork(int[3], int[2], char*, char**);
void
procexec(Channel *pidc, int fd[3], char *prog, char *args[])
threadexec(Channel *pidc, int fd[3], char *prog, char *args[])
{
int n;
Proc *p;
Thread *t;
_threaddebug(DBGEXEC, "procexec %s", prog);
/* must be only thread in proc */
p = _threadgetproc();
t = p->thread;
if(p->threads.head != t || p->threads.head->nextt != nil){
werrstr("not only thread in proc");
Bad:
_threaddebug(DBGEXEC, "procexec bad %r");
if(pidc)
sendul(pidc, ~0);
return;
}
int pfd[2];
int n, pid;
char exitstr[ERRMAX];
_threaddebug(DBGEXEC, "threadexec %s", prog);
/*
* We want procexec to behave like exec; if exec succeeds,
* We want threadexec to behave like exec; if exec succeeds,
* never return, and if it fails, return with errstr set.
* Unfortunately, the exec happens in another proc since
* we have to wait for the exec'ed process to finish.
@ -34,114 +24,77 @@ procexec(Channel *pidc, int fd[3], char *prog, char *args[])
* then the proc doing the exec sends the errstr down the
* pipe to us.
*/
if(pipe(p->exec.fd) < 0)
if(pipe(pfd) < 0)
goto Bad;
if(fcntl(p->exec.fd[0], F_SETFD, 1) < 0)
if(fcntl(pfd[0], F_SETFD, 1) < 0)
goto Bad;
if(fcntl(p->exec.fd[1], F_SETFD, 1) < 0)
if(fcntl(pfd[1], F_SETFD, 1) < 0)
goto Bad;
/* exec in parallel via the scheduler */
assert(p->needexec==0);
p->exec.prog = prog;
p->exec.args = args;
p->exec.stdfd = fd;
p->needexec = 1;
_sched();
switch(pid = fork()){
case -1:
close(pfd[0]);
close(pfd[1]);
goto Bad;
case 0:
efork(fd, pfd, prog, args);
_exit(0);
default:
break;
}
close(p->exec.fd[1]);
if((n = read(p->exec.fd[0], p->exitstr, ERRMAX-1)) > 0){ /* exec failed */
p->exitstr[n] = '\0';
errstr(p->exitstr, ERRMAX);
close(p->exec.fd[0]);
close(pfd[1]);
if((n = read(pfd[0], exitstr, ERRMAX-1)) > 0){ /* exec failed */
exitstr[n] = '\0';
errstr(exitstr, ERRMAX);
close(pfd[0]);
goto Bad;
}
close(p->exec.fd[0]);
close(pfd[0]);
close(fd[0]);
if(fd[1] != fd[0])
close(fd[1]);
if(fd[2] != fd[1] && fd[2] != fd[0])
close(fd[2]);
if(pidc)
sendul(pidc, t->ret);
sendul(pidc, pid);
_threaddebug(DBGEXEC, "procexec schedexecwait");
/* wait for exec'ed program, then exit */
_schedexecwait();
_threaddebug(DBGEXEC, "threadexec schedexecwait");
threadexits(0);
Bad:
_threaddebug(DBGEXEC, "threadexec bad %r");
if(pidc)
sendul(pidc, ~0);
}
void
procexecl(Channel *pidc, int fd[3], char *f, ...)
threadexecl(Channel *pidc, int fd[3], char *f, ...)
{
procexec(pidc, fd, f, &f+1);
}
void
_schedexecwait(void)
{
int pid;
Channel *c;
Proc *p;
Thread *t;
Waitmsg *w;
p = _threadgetproc();
t = p->thread;
pid = t->ret;
_threaddebug(DBGEXEC, "_schedexecwait %d", t->ret);
for(;;){
w = wait();
if(w == nil)
break;
if(w->pid == pid)
break;
free(w);
}
if(w != nil){
if((c = _threadwaitchan) != nil)
sendp(c, w);
else
free(w);
}
threadexits("procexec");
threadexec(pidc, fd, f, &f+1);
}
static void
efork(void *ve)
efork(int stdfd[3], int fd[2], char *prog, char **args)
{
char buf[ERRMAX];
Execargs *e;
int i;
e = ve;
_threaddebug(DBGEXEC, "_schedexec %s -- calling execv", e->prog);
dup(e->stdfd[0], 0);
dup(e->stdfd[1], 1);
dup(e->stdfd[2], 2);
_threaddebug(DBGEXEC, "_schedexec %s -- calling execv", prog);
dup(stdfd[0], 0);
dup(stdfd[1], 1);
dup(stdfd[2], 2);
for(i=3; i<40; i++)
if(i != e->fd[1])
if(i != fd[1])
close(i);
rfork(RFNOTEG);
execvp(e->prog, e->args);
execvp(prog, args);
_threaddebug(DBGEXEC, "_schedexec failed: %r");
rerrstr(buf, sizeof buf);
if(buf[0]=='\0')
strcpy(buf, "exec failed");
write(e->fd[1], buf, strlen(buf));
close(e->fd[1]);
write(fd[1], buf, strlen(buf));
close(fd[1]);
_exits(buf);
}
int
_schedexec(Execargs *e)
{
int pid;
pid = fork();
if(pid == 0){
efork(e);
_exit(1);
}
return pid;
}