aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2021-10-18 17:51:11 -0700
committerNicholas Noll <nbnoll@eml.cc>2021-10-18 17:51:11 -0700
commitead340a66039096c7b4bf12dcd65e189769c6653 (patch)
tree732594824f3e7951eecf0180792db2d24ff6d13e
parentbf03074e346b004659196b6c17eee04dbffd3ac2 (diff)
feat(rc): job control prototype working for basic commands
-rw-r--r--sys/cmd/dwm/config.h1
-rw-r--r--sys/cmd/rc/code.c16
-rw-r--r--sys/cmd/rc/exec.c244
-rw-r--r--sys/cmd/rc/exec.h11
-rw-r--r--sys/cmd/rc/input.c14
-rw-r--r--sys/cmd/rc/lex.c6
-rw-r--r--sys/cmd/rc/main.c74
-rw-r--r--sys/cmd/rc/prompt.c4
-rw-r--r--sys/cmd/rc/rc.h65
-rw-r--r--sys/cmd/rc/rules.mk2
-rw-r--r--sys/cmd/rc/sys.c47
-rw-r--r--sys/cmd/rc/var.c8
-rw-r--r--sys/cmd/rc/wait.c210
13 files changed, 507 insertions, 195 deletions
diff --git a/sys/cmd/dwm/config.h b/sys/cmd/dwm/config.h
index ebf7b89..a24bcc7 100644
--- a/sys/cmd/dwm/config.h
+++ b/sys/cmd/dwm/config.h
@@ -32,6 +32,7 @@ static Rule rules[] = {
/* class instance title tags mask isfloating isterminal noswallow monitor */
{ "Gimp", nil, nil, 0, 1, 0, 0, -1 },
{ "Inkscape", nil, nil, 0, 1, 0, 0, -1 },
+ { "zoom", nil, nil, 0, 1, 0, 0, -1 },
{ "qutebrowser", nil, nil, 0, 0, 0, 0, -1 },
{ "term-256color", nil, nil, 0, 0, 1, -1, -1 },
};
diff --git a/sys/cmd/rc/code.c b/sys/cmd/rc/code.c
index 6deed89..8dec021 100644
--- a/sys/cmd/rc/code.c
+++ b/sys/cmd/rc/code.c
@@ -13,9 +13,9 @@ struct Interpreter
Code *compiled = nil;
static struct Interpreter interpreter;
-#define emiti(x) ((void)(interpreter.i != interpreter.cap || grow()), interpreter.code[interpreter.i].i = (x), interpreter.i++)
-#define emitf(x) ((void)(interpreter.i != interpreter.cap || grow()), interpreter.code[interpreter.i].f = (x), interpreter.i++)
-#define emits(x) ((void)(interpreter.i != interpreter.cap || grow()), interpreter.code[interpreter.i].s = (x), interpreter.i++)
+#define emiti(x) ((void)(interpreter.i != interpreter.cap || grow()), interpreter.code[interpreter.i].i = (x), interpreter.i++)
+#define emitf(x) ((void)(interpreter.i != interpreter.cap || grow()), interpreter.code[interpreter.i].f = (x), interpreter.i++)
+#define emits(x) ((void)(interpreter.i != interpreter.cap || grow()), interpreter.code[interpreter.i].s = (x), interpreter.i++)
static
int
@@ -59,18 +59,21 @@ walk(Tree *node)
emitf(Xdollar);
break;
+#if 0
case '&':
emitf(Xasync);
p = emiti(0);
emitf(Xexit);
stashaddr(p);
break;
+#endif
case ';':
walk(node->child[0]);
walk(node->child[1]);
break;
+#if 0
case '^':
emitf(Xmark);
walk(node->child[1]);
@@ -78,6 +81,7 @@ walk(Tree *node)
walk(node->child[0]);
emitf(Xconcatenate);
break;
+#endif
case Targs:
walk(node->child[1]);
@@ -149,9 +153,11 @@ int
compile(Tree *node)
{
flush(errio);
- print(errio, "%t\n", node);
+ //print(errio, "%t\n", node);
+
+ interpreter.i = 0;
+ interpreter.code = emalloc(100*sizeof(*interpreter.code));
- interpreter.i = 0;
emiti(1); // reference count
walk(node);
diff --git a/sys/cmd/rc/exec.c b/sys/cmd/rc/exec.c
index 868b1dc..80cd645 100644
--- a/sys/cmd/rc/exec.c
+++ b/sys/cmd/rc/exec.c
@@ -16,21 +16,12 @@ struct Builtin{
static Word nullpath = { .str="", .link=nil };
struct Builtin builtin[]={
- {".", xdot},
+ {".", xdot},
+ {"fg", xfg},
+ {"jobs", xjob},
0,
};
-/* stub out until we need */
-void Xasync(void){}
-void Xconcatenate(void){}
-void Xexit(void){}
-void Xfunc(void){}
-void Xfor(void){}
-void Xglob(void){}
-void Xjump(void){}
-void Xmatch(void){}
-void Xpipe(void){}
-void Xread(void){}
// -----------------------------------------------------------------------
// internal
@@ -40,10 +31,10 @@ static
void
pushword(char *str)
{
- if(!shell->args)
- fatal("attempt to push on empty argument stack");
+ if(!proc->args)
+ fatal("attempt to push on empty argument stack\n");
- shell->args->word = makeword(str, shell->args->word);
+ proc->args->word = makeword(str, proc->args->word);
}
static
@@ -51,14 +42,14 @@ void
popword(void)
{
Word *w;
- if(!shell->args)
- fatal("tried to pop word on empty argument stack");
+ if(!proc->args)
+ fatal("tried to pop word on empty argument stack\n");
- w = shell->args->word;
+ w = proc->args->word;
if(!w)
- fatal("tried to pop word but nothing there");
+ fatal("tried to pop word but nothing there\n");
- shell->args->word = w->link;
+ proc->args->word = w->link;
efree(w->str);
efree(w);
}
@@ -110,21 +101,21 @@ pushlist(void)
List *stack = emalloc(sizeof(*stack));
stack->word = nil;
- stack->link = shell->args;
+ stack->link = proc->args;
- shell->args = stack;
+ proc->args = stack;
}
static
void
poplist(void)
{
- List *stack = shell->args;
+ List *stack = proc->args;
if(!stack)
- fatal("attempted to pop an empty argument stack");
+ fatal("attempted to pop an empty argument stack\n");
freelist(stack->word);
- shell->args = stack->link;
+ proc->args = stack->link;
efree(stack);
}
@@ -149,12 +140,12 @@ void
xx(void)
{
popword(); // "exec"
- if(!shell->args->word){
+ if(!proc->args->word){
Xerror("empty argument list");
return;
}
- execute(shell->args->word, path(shell->args->word->str));
+ execute(proc->args->word, path(proc->args->word->str));
poplist();
}
@@ -169,13 +160,38 @@ xforkx(void)
case -1:
return -1;
case 0: // child
- clearwait();
+ clearwait(proc);
+
+ if(shell.interactive){
+ proc->pid = getpid();
+ if(proc->pgid <= 0)
+ proc->pgid = proc->pid;
+
+ setpgid(pid, proc->pgid);
+ tcsetpgrp(0, proc->pgid);
+
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ signal(SIGTSTP, SIG_DFL);
+ signal(SIGTTIN, SIG_DFL);
+ signal(SIGTTOU, SIG_DFL);
+ signal(SIGCHLD, SIG_DFL);
+ }
+
pushword("exec");
xx();
- exit(1);
+
+ exit(1); // NOTE: xx does not return!
/*unreachable*/
- default:
- addwait(pid);
+ default: // parent
+ addwait(proc, pid);
+
+ /* ensure the state matches for parent and child */
+ proc->pid = pid;
+ if(proc->pgid <= 0)
+ proc->pgid = pid;
+ setpgid(pid, proc->pgid);
+
return pid;
}
}
@@ -189,9 +205,9 @@ pushredir(int type, int from, int to)
r->type = type;
r->from = from;
r->to = to;
- r->link = shell->redir;
+ r->link = proc->redir;
- shell->redir = r;
+ proc->redir = r;
}
/* byte code */
@@ -209,9 +225,11 @@ run(Code *c, int pc, Var *local)
new->cmd.io = nil;
new->flag.eof = 0;
new->line = 1;
- new->link = shell;
+ new->link = proc;
+
+ new->pgid = new->pid = -1;
- shell = new;
+ proc = new;
}
// -----------------------------------------------------------------------
@@ -281,23 +299,22 @@ xdot(void)
Thread *old;
char file[512];
- old = shell;
popword();
#if 0
- if(old->args->word && strcmp(old->args->word->str, "-i")==0){
+ if(proc->args->word && strcmp(proc->args->word->str, "-i")==0){
iflag = 1;
popword();
}
#endif
/* get input file */
- if(!old->args->word){
+ if(!proc->args->word){
Xerror("usage: . [-i] file [arg ...]\n");
return;
}
- base = strdup(old->args->word->str);
+ base = strdup(proc->args->word->str);
popword();
- for(fd=-1, p=path(base); p ; p = p->link){
+ for(fd=-1, p=path(base); p; p = p->link){
strcpy(file, p->str);
if(file[0])
@@ -315,15 +332,17 @@ xdot(void)
return;
}
/* set up for a new command loop */
+ old = proc; // store pointer to old code
run(dotcmd, 1, nil);
- pushredir(Rclose, fd, 0);
- shell->cmd.path = base;
- shell->cmd.io = openfd(fd);
+ /* operations on new command stack */
+ pushredir(Rclose, fd, 0);
+ proc->cmd.path = base;
+ proc->cmd.io = openfd(fd);
/* push $* value */
pushlist();
- shell->args->word = old->args->word;
+ proc->args->word = old->args->word;
/* free caller's copy of $* */
argv = old->args;
@@ -337,6 +356,50 @@ xdot(void)
}
void
+xjob(void)
+{
+ int i;
+ Thread *job;
+
+ for(i = 0, job = shell.jobs; job; job = job->next)
+ report(job,i);
+
+ poplist();
+}
+
+void
+xfg(void)
+{
+ int i;
+ Thread *job, *old;
+
+ popword(); // fg
+
+ /* get input job id */
+ if(!proc->args->word){
+ print(errio, "usage: fg [pid|\%num]\n");
+ poplist();
+ return;
+ }
+
+ i = atoi(proc->args->word->str);
+ popword(); // [jobid]
+
+ for(job=shell.jobs; i > 0; job=job->next, --i)
+ ;
+ assert(!job->flag.done);
+
+ addwait(job, job->pid);
+ job->flag.stop = 0;
+
+ poplist(); // this goes here?
+
+ job->link = proc, proc = job; // XXX: can this leave orphans?
+ foreground(job, 1);
+ printf("hi\n");
+}
+
+void
xboot(int argc, char *argv[])
{
int i;
@@ -369,10 +432,10 @@ xboot(int argc, char *argv[])
for(i = argc-1; i > 0; --i)
pushword(argv[i]);
- /* interpreter loop */
+ /* main interpreter loop */
for(;;){
- shell->code.i++;
- (*shell->code.exe[shell->code.i-1].f)();
+ proc->code.i++;
+ (*proc->code.exe[proc->code.i-1].f)();
}
}
@@ -390,31 +453,50 @@ Xerror(char *msg)
{
print(errio, "rc: %s", msg);
flush(errio);
- while(!shell->flag.i)
+ while(!proc->flag.i)
Xreturn();
}
void
Xreturn(void)
{
- Thread *run = shell;
+ Thread *run = proc;
+
+ /*
+ * If our job is still running we must:
+ * 1. move program one step back to rerun Xreturn upon recall
+ * 2. return to our calling thread
+ * 3. don't free!
+ */
+ if(run->flag.stop){
+ run->code.i--;
+ proc = run->link;
+ return;
+ }
- printf("returning\n");
+ /*
+ * If our job has finished:
+ * 1. remove from our list
+ * 2. clean up its memory!
+ */
+ if(run->flag.done)
+ deljob(run);
while(run->args)
poplist();
freecode(run->code.exe);
+ efree(run->wait.pid);
- shell = run->link;
+ proc = run->link;
efree(run);
- if(!shell)
+ if(!proc)
exit(0);
}
void
Xword(void)
{
- pushword(shell->code.exe[shell->code.i++].s);
+ pushword(proc->code.exe[proc->code.i++].s);
}
void
@@ -424,18 +506,18 @@ Xdollar(void)
char *s, *t;
Word *a, *star;
- if(count(shell->args->word)!=1){
+ if(count(proc->args->word)!=1){
Xerror("variable name not singleton!\n");
return;
}
- s = shell->args->word->str;
+ s = proc->args->word->str;
// deglob(s);
n = 0;
for(t = s;'0'<=*t && *t<='9';t++)
n = n*10+*t-'0';
- a = shell->args->link->word;
+ a = proc->args->link->word;
if(n==0 || *t)
a = copywords(var(s)->val, a);
@@ -450,7 +532,7 @@ Xdollar(void)
}
poplist();
- shell->args->word = a;
+ proc->args->word = a;
}
void
@@ -458,22 +540,22 @@ Xassign(void)
{
Var *v;
- if(count(shell->args->word)!=1){
+ if(count(proc->args->word)!=1){
Xerror("variable name not singleton!\n");
return;
}
//deglob(runq->argv->words->word);
- v = var(shell->args->word->str);
+ v = var(proc->args->word->str);
poplist();
//globlist();
freewords(v->val);
- v->val = shell->args->word;
+ v->val = proc->args->word;
v->new = 1;
if(v->update)
v->update(v);
- shell->args->word = nil;
+ proc->args->word = nil;
poplist();
}
@@ -485,7 +567,7 @@ Xreadcmd(void)
Word *prompt;
flush(errio);
- root = shell;
+ root = proc;
if(yyparse()){
exit(1);
@@ -494,21 +576,22 @@ Xreadcmd(void)
run(compiled, 1, root->local);
}
+ // killzombies();
freeparsetree();
}
void
Xlocal(void)
{
- if(count(shell->args->word)!=1){
+ if(count(proc->args->word)!=1){
Xerror("variable name must be singleton\n");
return;
}
//deglob(shell->args->word->str);
- shell->local = makevar(strdup(shell->args->word->str), shell->local);
- shell->local->val = copywords(shell->args->link->word, nil);
- shell->local->new = 1;
+ proc->local = makevar(strdup(proc->args->word->str), proc->local);
+ proc->local->val = copywords(proc->args->link->word, nil);
+ proc->local->new = 1;
poplist();
poplist();
@@ -517,13 +600,13 @@ Xlocal(void)
void
Xunlocal(void)
{
- Var *v = shell->local, *hide;
+ Var *v = proc->local, *hide;
if(!v)
- fatal("Xunlocal: no locals!", 0);
+ fatal("Xunlocal: no locals!\n", 0);
printf("unlocal\n");
- shell->local = v->link;
+ proc->local = v->link;
hide = var(v->name);
hide->new = 1;
@@ -540,12 +623,12 @@ Xbasic(void)
int pid, status;
struct Builtin *b;
- arg = shell->args->word;
+ arg = proc->args->word;
if(!arg){
Xerror("empty argument list\n");
return;
}
- print(errio, "recieved arg: %v\n", arg); // for debugging
+ /* print(errio, "recieved arg: %v\n", arg); // for debugging */
flush(errio);
v = var(arg->str);
@@ -561,6 +644,10 @@ Xbasic(void)
}
}
+ /* if we are here then it's an external command */
+ killzombies();
+ addjob(proc);
+
// run the external command
if((pid = xforkx()) < 0) {
Xerror("try again");
@@ -568,9 +655,16 @@ Xbasic(void)
}
poplist();
- do{
- waitpid(pid, &status, 0);
- } while(!WIFEXITED(status) && !WIFSIGNALED(status));
- printf("done waiting\n");
+ if(!shell.interactive)
+ waitall(proc);
+
+ foreground(proc, 0); // waits for child
}
+
+void
+Xexit(void)
+{
+ exit(shell.status);
+}
+
diff --git a/sys/cmd/rc/exec.h b/sys/cmd/rc/exec.h
index ef826fb..ad53365 100644
--- a/sys/cmd/rc/exec.h
+++ b/sys/cmd/rc/exec.h
@@ -7,18 +7,9 @@
* Code in line with jump around {...}
*/
-void Xasync(void);
-void Xconcatenate(void);
void Xdollar(void);
void Xexit(void);
-void Xfunc(void);
-void Xfor(void);
-void Xglob(void);
-void Xjump(void);
void Xmark(void);
-void Xmatch(void);
-void Xpipe(void);
-void Xread(void);
void Xreturn(void);
void Xlocal(void);
void Xreadcmd(void);
@@ -29,5 +20,7 @@ void Xerror(char*);
void Xword(void);
/* builtin commands */
+void xfg(void);
void xdot(void);
+void xjob(void);
void xboot(int argc, char *argv[]);
diff --git a/sys/cmd/rc/input.c b/sys/cmd/rc/input.c
index cf05382..4c6b37f 100644
--- a/sys/cmd/rc/input.c
+++ b/sys/cmd/rc/input.c
@@ -85,7 +85,7 @@ enterraw(int fd)
{
struct termios raw;
- if(!isatty(0))
+ if(!shell.interactive)
goto fatal;
if(!mode.defer) {
@@ -995,7 +995,7 @@ notty(void)
for(;;){
c = fgetc(stdin);
- put(&shell->cmd.io, c);
+ put(&proc->cmd.io, c);
}
}
@@ -1019,17 +1019,17 @@ readline(char *prompt)
int n;
// reset the command buffer
- shell->cmd.io->e = shell->cmd.io->b = shell->cmd.io->buf;
+ proc->cmd.io->e = proc->cmd.io->b = proc->cmd.io->buf;
- if(!isatty(0))
+ if(!shell.interactive)
return notty();
- if((n = raw(shell->cmd.io->e, shell->cmd.io->cap-1, prompt)) == -1)
+ if((n = raw(proc->cmd.io->e, proc->cmd.io->cap-1, prompt)) == -1)
return 0;
- shell->cmd.io->e += n;
+ proc->cmd.io->e += n;
/* insert a newline character at the end */
- put(&shell->cmd.io, '\n');
+ put(&proc->cmd.io, '\n');
printf("\n");
return 1;
diff --git a/sys/cmd/rc/lex.c b/sys/cmd/rc/lex.c
index ec9e94d..e7c7d7d 100644
--- a/sys/cmd/rc/lex.c
+++ b/sys/cmd/rc/lex.c
@@ -40,18 +40,18 @@ readc(void)
peek = EOF;
return c;
}
- if(shell->flag.eof)
+ if(proc->flag.eof)
return EOF;
if(!prompt(&lexer.doprompt))
exit(1); // XXX: hack for signal handling right now...
- c = get(shell->cmd.io);
+ c = get(proc->cmd.io);
lexer.doprompt = lexer.doprompt || c=='\n' || c==EOF;
if(c==EOF)
- shell->flag.eof = 1;
+ proc->flag.eof = 1;
return c;
}
diff --git a/sys/cmd/rc/main.c b/sys/cmd/rc/main.c
index 46a4e0f..d1bbd06 100644
--- a/sys/cmd/rc/main.c
+++ b/sys/cmd/rc/main.c
@@ -2,9 +2,53 @@
#include "parse.h"
#include "exec.h"
-int rcpid;
+#include <signal.h>
+#include <termios.h>
+
+// -----------------------------------------------------------------------
+// globals
+
Io *errio = nil;
-Thread *shell = nil;
+Thread *proc = nil;
+Shell shell = { 0 };
+
+// -----------------------------------------------------------------------
+// functions
+
+void
+initshell(void)
+{
+ if((shell.interactive=isatty(0))){
+ while(tcgetpgrp(0) != (shell.pid = getpgrp()))
+ kill(-shell.pid, SIGTTIN);
+
+ /* ignore job control signals */
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGTTIN, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ /*
+ * NOTE: if SIGCHLD is set to SIG_IGN then
+ * 1. children that terminate do not become zombies
+ * 2. call a to wait() will block until all children have terminated
+ * 3. the call to wait will fail with errno == ECHILD
+ * see for discussion:
+ * https://stackoverflow.com/questions/1608017/no-child-process-error-from-waitpid-when-waiting-for-process-group
+ */
+ // signal(SIGCHLD, SIG_IGN);
+
+ /* take control */
+ shell.pid = getpid();
+ if(setpgid(shell.pid, shell.pid)<0)
+ fatal("could not put shell in its own process group");
+
+ tcsetpgrp(0, shell.pid);
+ }
+}
+
+// -----------------------------------------------------------------------
+// main point of entry
int
main(int argc, char *argv[])
@@ -17,31 +61,7 @@ main(int argc, char *argv[])
initenv();
initpath();
-
- itoa(num, rcpid = getpid());
- setvar("pid", makeword(num, nil));
+ initshell();
xboot(argc, argv);
-#if 0
- Thread root = {
- .cmd = {
- .path = "<nil>",
- .io = openfd(0),
- },
- .line = 0,
- .flag = {
- .i = 1,
- .eof = 0,
- },
- };
-
- shell = &root;
- errio = openfd(2);
-#if 1
- while(!yyparse())
- ;
-#else
- printkeycode()
-#endif
-#endif
}
diff --git a/sys/cmd/rc/prompt.c b/sys/cmd/rc/prompt.c
index b4b1d96..21078e8 100644
--- a/sys/cmd/rc/prompt.c
+++ b/sys/cmd/rc/prompt.c
@@ -6,11 +6,11 @@ prompt(ushort *flag)
int f = *flag;
if(f){
if(!readline("> ")){
- shell->flag.eof = 1;
+ proc->flag.eof = 1;
return 0;
}
- shell->line++;
+ proc->line++;
*flag = 0;
}
return 1;
diff --git a/sys/cmd/rc/rc.h b/sys/cmd/rc/rc.h
index 1c2aa6b..9c6307f 100644
--- a/sys/cmd/rc/rc.h
+++ b/sys/cmd/rc/rc.h
@@ -3,6 +3,19 @@
#include <u.h>
#include <libn.h>
+/*
+ * A thread functions much like a GNU job -> it's just a simple execution stack
+ * We just need to modify the following datastructures:
+ *
+ * 1. Need to store the list of all "active" and "foreground" threads
+ * - Right now we just have Thread *proc which is the running process.
+ * - Need to move this to a linked list (how does this interact with the link?)
+ * - Linked list stores the independent roots of each individual process tree
+ * 2. Child pids are stored inside waitpid right now. Need to associate this more explictly with a thread.
+ * 3. Wait needs to be generalized to act on threads.
+ * 4. our "start" function is equivalent to the launch_job function
+ * 5. running the interpreter runs the launch_process implicitly (with forks called as interpreter functions)
+ */
// -----------------------------------------------------------------------
// types
@@ -14,8 +27,7 @@ typedef struct Tree Tree;
typedef struct Redir Redir;
typedef union Code Code;
typedef struct Thread Thread;
-
-typedef struct WaitMsg WaitMsg;
+typedef struct Shell Shell;
struct Io
{
@@ -86,7 +98,7 @@ struct Thread
struct {
int i;
Code *exe;
- } code; // execution stack
+ } code; // execution stack
struct {
Io *io;
char *path;
@@ -97,29 +109,39 @@ struct Thread
Redir *redir; // list of redirections
struct {
- ushort i : 1;
- ushort eof : 1;
+ ushort i : 1;
+ ushort eof : 1;
+ ushort stop : 1;
+ ushort done : 1;
+ ushort again : 1;
} flag; // flags for process
- int pid;
+ struct {
+ int len, cap, *pid;
+ } wait;
+
+ int pid, pgid, status;
long line;
Tree *nodes; // memory allocation
Thread *link; // process we return to
+ Thread *next; // next job
};
-struct WaitMsg
+struct Shell
{
- int pid; // of loved one
- ulong time[3]; // of loved one & descendants
- char *msg;
+ int pid;
+ int status;
+ int interactive;
+ Thread *jobs;
};
// -----------------------------------------------------------------------
// globals
-extern int rcpid;
-extern Thread *shell;
+extern Shell shell;
+
+extern Thread *proc;
extern Io *errio;
extern Code *compiled;
@@ -168,12 +190,23 @@ void freeparsetree(void);
/* sys.c */
void initenv(void);
+void execute(Word *, Word*);
-void addwait(int);
-void clearwait(void);
-int waitfor(int);
+/* wait.c */
+void addwait(Thread *, int);
+void clearwait(Thread*);
+int waitall(Thread *);
-void execute(Word *, Word*);
+void killzombies(void);
+
+/* job.c */
+Thread *getjob(int, int*);
+void addjob(Thread *);
+void deljob(Thread *);
+void report(Thread *, int);
+
+void foreground(Thread *, int);
+void background(Thread *, int);
/* exec.c */
// XXX: odd place for this
diff --git a/sys/cmd/rc/rules.mk b/sys/cmd/rc/rules.mk
index 44c9b7a..dcddcce 100644
--- a/sys/cmd/rc/rules.mk
+++ b/sys/cmd/rc/rules.mk
@@ -13,6 +13,8 @@ SRCS_$(d) :=\
$(d)/code.c\
$(d)/var.c\
$(d)/sys.c\
+ $(d)/wait.c\
+ $(d)/job.c\
$(d)/exec.c\
$(d)/main.c
diff --git a/sys/cmd/rc/sys.c b/sys/cmd/rc/sys.c
index 2c6a19d..643f327 100644
--- a/sys/cmd/rc/sys.c
+++ b/sys/cmd/rc/sys.c
@@ -1,12 +1,5 @@
#include "rc.h"
-struct Wait
-{
- int len, cap, *pid;
-};
-
-static struct Wait wait;
-
// -----------------------------------------------------------------------
// internal
@@ -72,46 +65,6 @@ initenv(void)
}
void
-clearwait(void)
-{
- wait.len = 0;
-}
-
-int
-havewait(int pid)
-{
- int i;
-
- for(i=0; i<wait.len; i++)
- if(wait.pid[i] == pid)
- return 1;
- return 0;
-}
-
-void
-addwait(int pid)
-{
- if(wait.len == wait.cap){
- wait.cap = wait.cap + 2;
- wait.pid = erealloc(wait.pid, wait.cap*sizeof(*wait.pid));
- }
- wait.pid[wait.len++] = pid;
-}
-
-/*
-int
-waitfor(int pid)
-{
- Thread *p;
- struct WaitMsg *w;
- char errbuf[ERRMAX];
-
- if(pid >= 0 && !havewait(pid))
- return 0;
-}
-*/
-
-void
execute(Word *cmd, Word *path)
{
int nc;
diff --git a/sys/cmd/rc/var.c b/sys/cmd/rc/var.c
index f0e5f5b..7b5d75a 100644
--- a/sys/cmd/rc/var.c
+++ b/sys/cmd/rc/var.c
@@ -175,8 +175,8 @@ Var*
var(char *name)
{
Var *v;
- if(shell){
- for(v = shell->local; v; v=v->link)
+ if(proc){
+ for(v = proc->local; v; v=v->link)
if(strcmp(v->name, name) == 0)
return v;
}
@@ -206,7 +206,7 @@ mkenv(void)
nchr+=strlen(a->str)+1; \
}
- for(v= shell->local; v; v=v->link){
+ for(v= proc->local; v; v=v->link){
BODY
}
for(h=globals; h!=arrend(globals); h++){
@@ -238,7 +238,7 @@ mkenv(void)
*p++='\0'; \
}
- for(v=shell->local; v; v=v->link){
+ for(v=proc->local; v; v=v->link){
BODY
}
for(h=globals; h!=arrend(globals); h++){
diff --git a/sys/cmd/rc/wait.c b/sys/cmd/rc/wait.c
index 06f9614..db586cb 100644
--- a/sys/cmd/rc/wait.c
+++ b/sys/cmd/rc/wait.c
@@ -1,3 +1,213 @@
#include "rc.h"
+
#include <sys/wait.h>
+// -----------------------------------------------------------------------
+// globals
+
+struct WaitMsg
+{
+ int pid;
+ ulong time[3];
+ int status;
+ int signal;
+ int suspend;
+};
+
+
+// -----------------------------------------------------------------------
+// internal
+
+static
+int
+await(int pid4, int opt, struct WaitMsg *msg)
+{
+ int pid, status, core;
+ struct rusage ru;
+ ulong u, s;
+
+ /* event loop */
+ for(;;){
+ if((pid = wait4(pid4, &status, opt, &ru)) <= 0){
+ msg->pid = 0;
+ perror("failed wait");
+ return 0;
+ }
+
+ u = ru.ru_utime.tv_sec*1000+((ru.ru_utime.tv_usec+500)/1000);
+ s = ru.ru_stime.tv_sec*1000+((ru.ru_stime.tv_usec+500)/1000);
+
+ if(WIFEXITED(status)){
+ msg->pid = pid;
+ msg->time[0] = u;
+ msg->time[1] = s;
+ msg->time[2] = u+s;
+ msg->status = WEXITSTATUS(status);
+ msg->signal = 0;
+ msg->suspend = 0;
+
+ return 1;
+ }
+
+ if(WIFSIGNALED(status)){
+ msg->pid = pid;
+ msg->time[0] = u;
+ msg->time[1] = s;
+ msg->time[2] = u+s;
+ msg->status = WCOREDUMP(status);
+ msg->signal = 1;
+ msg->suspend = 0;
+
+ return 1;
+ }
+
+ if(WIFSTOPPED(status)){
+ msg->pid = pid;
+ msg->time[0] = u;
+ msg->time[1] = s;
+ msg->time[2] = u+s;
+ msg->status = WSTOPSIG(status);
+ msg->signal = 0;
+ msg->suspend = 1;
+
+ return 1;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+// exported
+
+void
+clearwait(Thread *job)
+{
+ job->wait.len = 0;
+}
+
+int
+havewait(Thread *job, int pid)
+{
+ int i;
+
+ for(i=0; i<job->wait.len; i++)
+ if(job->wait.pid[i] == pid)
+ return 1;
+ return 0;
+}
+
+void
+addwait(Thread *job, int pid)
+{
+ if(job->wait.len == job->wait.cap){
+ job->wait.cap = job->wait.cap + 2;
+ job->wait.pid = erealloc(job->wait.pid, job->wait.cap*sizeof(*job->wait.pid));
+ }
+ job->wait.pid[job->wait.len++] = pid;
+}
+
+void
+delwait(Thread *job, int pid)
+{
+ int r, w;
+
+ for(r=w=0; r < job->wait.len; r++){
+ if(job->wait.pid[r] != pid)
+ job->wait.pid[w++] = job->wait.pid[r];
+ }
+ job->wait.len = w;
+}
+
+int
+waitall(Thread *job)
+{
+ Thread *t;
+ struct WaitMsg msg;
+
+ while(job->wait.len && await(-job->pgid, WUNTRACED, &msg)){
+ if(msg.pid == 0 && errno == ECHILD){
+ perror("wait job");
+ return 0;
+ }
+
+ for(t=job; t; t=t->link){
+ if(t->pid == msg.pid){
+ t->status = msg.status;
+ t->flag.stop = t->flag.done = t->flag.again = 0;
+ if(msg.suspend){
+ t->flag.stop = 1;
+ }else{
+ t->flag.done = 1;
+ if(msg.signal){
+ print(errio, "%d: terminated by signal %d\n", msg.pid, msg.status);
+ }
+ }
+ delwait(t, msg.pid);
+ goto outer;
+ }
+ }
+
+ perror("waitpid");
+ return 0;
+ outer:;
+ }
+
+ return 1;
+}
+
+void
+killzombies(void)
+{
+ Thread *job;
+ int index, status, pid;
+
+ while((pid=waitpid(-1, &status, WNOHANG))>0){
+ print(errio, "pid %d\n", pid);
+ flush(errio);
+
+ job = getjob(pid, &index);
+ if(!job){
+ perror("invalid pid");
+ }
+
+ job->flag.done = job->flag.stop = job->flag.again = 0;
+
+ if(WIFEXITED(status))
+ job->flag.done = 1;
+ if(WIFSTOPPED(status))
+ job->flag.stop = 1;
+ if(WIFCONTINUED(status))
+ job->flag.again = 1;
+
+ if(job->flag.done){
+ report(job,index);
+ deljob(job);
+ }
+ }
+}
+
+#if 0
+int
+waitfor(int pid)
+{
+ Thread *t;
+ struct WaitMsg w;
+
+ if(pid >= 0 && !havewait(pid))
+ return 0;
+
+ while(await(-proc->pgid, WUNTRACED, &w)){
+ delwait(w.pid);
+ if(w.pid == pid){
+ if(w.signal)
+ print(errio, "pid[%d]: signal: %d\n", w.pid, w.status);
+ return 1;
+ }
+ for(t=proc->link; t; t=t->link){
+ if(t->pid == w.pid)
+ t->pid = -1;
+ }
+ }
+
+ return 0;
+}
+#endif