07608c768f
The current behaviour of the kernel to deadlock itself instead of returning an error on fork. This might change in the future, so prepare libthread to handle this case. For _schedfork(), we'r going to just retry forking on every switch, while for _schedexec(), the exec will fail and send ~0 down the pid channel.
81 lines
1.8 KiB
C
81 lines
1.8 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <thread.h>
|
|
#include "threadimpl.h"
|
|
|
|
void
|
|
procexec(Channel *pidc, 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:
|
|
if(pidc)
|
|
sendul(pidc, ~0);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* We want procexec 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.
|
|
* To provide the semantics, we open a pipe with the
|
|
* write end close-on-exec and hand it to the proc that
|
|
* is doing the exec. If the exec succeeds, the pipe will
|
|
* close so that our read below fails. If the exec fails,
|
|
* then the proc doing the exec sends the errstr down the
|
|
* pipe to us.
|
|
*/
|
|
if(pipe(p->exec.fd) < 0)
|
|
goto Bad;
|
|
snprint(p->exitstr, ERRMAX, "/fd/%d", p->exec.fd[1]);
|
|
if((n = open(p->exitstr, OWRITE|OCEXEC)) < 0){
|
|
close(p->exec.fd[0]);
|
|
close(p->exec.fd[1]);
|
|
goto Bad;
|
|
}
|
|
close(p->exec.fd[1]);
|
|
p->exec.fd[1] = n;
|
|
|
|
while(p->needexec || p->newproc)
|
|
_sched();
|
|
|
|
/* exec in parallel via the scheduler */
|
|
p->exec.prog = prog;
|
|
p->exec.args = args;
|
|
p->needexec = 1;
|
|
_sched();
|
|
|
|
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]);
|
|
goto Bad;
|
|
}
|
|
close(p->exec.fd[0]);
|
|
|
|
if(t->ret == -1)
|
|
goto Bad;
|
|
if(pidc)
|
|
sendul(pidc, t->ret);
|
|
|
|
/* wait for exec'ed program, then exit */
|
|
_schedexecwait();
|
|
}
|
|
|
|
void
|
|
procexecl(Channel *pidc, char *f, ...)
|
|
{
|
|
procexec(pidc, f, &f+1);
|
|
}
|
|
|