aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2021-10-20 14:21:06 -0700
committerNicholas Noll <nbnoll@eml.cc>2021-10-20 14:21:06 -0700
commit7e1eaee616365799cfc4cc787fdaa9448958536b (patch)
treefe48164500a72b86ae0a04bf90783b4ea3186dbe
parent888679027c2e9b43d1485d970df8170ac4fda29f (diff)
Feat: now execs instead of exec + fork if going to exit.
One quick solution to the lack of tracking deep into the command line is to note that the pattern of code emitted for an async is: Xasync |__ child (command) |__ parent (continues) The child creates a process group, as described before. If the child is a simple command, we will now "exec" as it will exit immediately after the command. This gives us the correct behavior, at least for simple cases. This also fixed pipes. However, if child has to be forked, i.e. can't be immediately execed, then I don't think this process works...
-rw-r--r--sys/cmd/rc/exec.c25
-rw-r--r--sys/cmd/rc/lex.c2
-rw-r--r--sys/cmd/rc/sys.c2
-rw-r--r--sys/cmd/rc/wait.c22
4 files changed, 44 insertions, 7 deletions
diff --git a/sys/cmd/rc/exec.c b/sys/cmd/rc/exec.c
index f9af866..eede516 100644
--- a/sys/cmd/rc/exec.c
+++ b/sys/cmd/rc/exec.c
@@ -151,6 +151,17 @@ undoredirs(void)
}
static inline
+int
+exitsnext(void)
+{
+ Code *c = &runner->code.exe[runner->code.i];
+ while(c->f == Xpopredir)
+ c++;
+
+ return c->f == Xexit;
+}
+
+static inline
void
defaultsignal(void)
{
@@ -507,8 +518,8 @@ xfg(void)
poplist(); // this goes here?
wakeup(job);
- foreground(job, 1);
job->caller = runner, runner = job; // XXX: can this leave zombies?
+ foreground(job, 1);
}
void
@@ -778,7 +789,7 @@ Xpipe(void)
initchild(runner,1);
/* child 0 (writer) forked process */
- run(runner->code.exe, pc+2, runner->local, 0);
+ run(runner->code.exe, pc+2, runner->local, 1);
runner->caller = nil;
close(pfd[0]);
@@ -789,10 +800,12 @@ Xpipe(void)
initparent(runner,pid,0);
/* child 1 (reader) subprocess*/
- run(runner->code.exe, runner->code.exe[pc].i, runner->local, 0);
+ run(runner->code.exe, runner->code.exe[pc].i, runner->local, 1);
close(pfd[1]);
pushredir(Ropen, pfd[0], rfd);
+
+ orig->code.i = orig->code.exe[pc+1].i;
break;
}
}
@@ -825,7 +838,11 @@ Xbasic(void)
}
/* if we are here then it's an external command */
- // TODO: check for if we will exit, don't need to fork, just exec
+ if(exitsnext()){ // if we exit immediately, no need to fork
+ pushword("exec");
+ xx();
+ Xexit();
+ }
// run the external command
if((pid = xforkx()) < 0) {
diff --git a/sys/cmd/rc/lex.c b/sys/cmd/rc/lex.c
index 373edd5..eb3a268 100644
--- a/sys/cmd/rc/lex.c
+++ b/sys/cmd/rc/lex.c
@@ -209,7 +209,7 @@ yylex(void)
node->type = Tpipe;
node->redir.fd[0] = 1;
- node->redir.fd[1] = 1;
+ node->redir.fd[1] = 0;
goto redir;
case '>':
diff --git a/sys/cmd/rc/sys.c b/sys/cmd/rc/sys.c
index 496c2e6..a24545f 100644
--- a/sys/cmd/rc/sys.c
+++ b/sys/cmd/rc/sys.c
@@ -99,6 +99,8 @@ redirect(Redir *r)
switch(r->type){
case Ropen:
if(r->from != r->to){
+ dup2(r->from, r->to);
+ close(r->from);
}
break;
case Rdup:
diff --git a/sys/cmd/rc/wait.c b/sys/cmd/rc/wait.c
index 4d45e4b..911601c 100644
--- a/sys/cmd/rc/wait.c
+++ b/sys/cmd/rc/wait.c
@@ -27,6 +27,10 @@ await(int pid4, int opt, struct WaitMsg *msg)
/* event loop */
for(;;){
if((pid = wait4(pid4, &status, opt, &ru)) <= 0){
+ if(errno == ECHILD){
+ msg->pid = -1;
+ return 1;
+ }
msg->pid = 0;
perror("failed wait4");
return 0;
@@ -168,9 +172,16 @@ waitall(Thread *job)
struct WaitMsg msg;
while(shouldwait(job) && await(-job->pgid, WUNTRACED, &msg)){
- if(msg.pid == 0){
+ switch(msg.pid){
+ case 0: // error
perror("wait job");
return 0;
+ case -1: // no children: assume they have exited
+ job->wait.status = Pdone;
+ clearwait(job);
+ return 1;
+ default:
+ ;
}
notify(job, msg);
@@ -186,9 +197,16 @@ waitfor(Thread *job, int pid)
struct WaitMsg msg;
while(shouldwait(job) && await(-job->pgid, WUNTRACED, &msg)){
- if(msg.pid == 0){
+ switch(msg.pid){
+ case 0: // error
perror("wait for");
return 0;
+ case -1: // no children: assume they have exited
+ job->wait.status = Pdone;
+ clearwait(job);
+ return 1;
+ default:
+ ;
}
notify(job, msg);