diff options
Diffstat (limited to 'c')
| -rw-r--r-- | c/gbos.h | 1 | ||||
| -rw-r--r-- | c/libc.s | 8 | ||||
| -rw-r--r-- | c/ptest.c | 19 | ||||
| -rw-r--r-- | c/sh.c | 68 |
4 files changed, 84 insertions, 12 deletions
@@ -12,6 +12,7 @@ char *getargs(void); /* this program's argument string */ char readc(void); /* one input byte, EOF at end */ void sexit(unsigned char code); unsigned char getpid(void); +unsigned char pipe(void); /* -> read fd; write end is read+1 */ /* helpers (c/libc.c) */ void putu(unsigned int n); /* print decimal */ @@ -1,6 +1,6 @@ .module libc .globl _writes, _putc, _puts, _nl, _strlen, _readc, _sexit, _getpid, _getargs - .globl _open, _close, _fgetc, _fputc, _flist, _fremove + .globl _open, _close, _fgetc, _fputc, _flist, _fremove, _pipe ;; SDCC sm83 sdcccall(1): 1st arg -> A (byte) or DE (pointer); ret A / BC. ;; rst $30 (the trap) clobbers BC/DE/HL; SDCC treats them caller-saved, so ;; wrappers need not preserve them - but we compute cleanly regardless. @@ -86,6 +86,12 @@ _getpid: rst #0x30 ret + ;; unsigned char pipe(void) -> A (read fd; write end is read+1) +_pipe: + ld c, #28 ; SYS_PIPE + rst #0x30 + ret + ;; unsigned char open(const char *name /*DE*/, unsigned char mode /*A*/) -> A(fd) _open: ld b, a ; B = mode diff --git a/c/ptest.c b/c/ptest.c new file mode 100644 index 0000000..88b7d30 --- /dev/null +++ b/c/ptest.c @@ -0,0 +1,19 @@ +#include "gbos.h" +/* ptest: exercise the kernel pipe in one process - write some bytes, read them + back, then close the write end and confirm the reader sees EOF. */ +void main(void) { + unsigned char pr = pipe(); + unsigned char pw = pr + 1; + int c; + if (pr == NOFD) { puts("pipe: none free"); nl(); return; } + fputc(pw, 'H'); fputc(pw, 'i'); fputc(pw, '!'); + c = fgetc(pr); putc(c); + c = fgetc(pr); putc(c); + c = fgetc(pr); putc(c); + nl(); + close(pw); /* last writer gone */ + c = fgetc(pr); + if (c < 0) puts("EOF"); else { puts("got "); putc(c); } + nl(); + close(pr); +} @@ -95,6 +95,61 @@ done: if (myout != NOFD) close(myout); } +/* run a multi-stage pipeline (a | b | c): wire stages together with real + kernel pipes, launch them ALL concurrently, then wait for them. */ +static void run_pipeline(char **tok, unsigned char nt) { + unsigned char pids[8], npid = 0; + unsigned char cfd[8], ncfd = 0; /* file-redirect fds; closed after all exit */ + unsigned char start = 0, prev_r = NOFD; + for (;;) { + unsigned char end = start, last, i, cmdend, fin = NOFD, fout = NOFD; + unsigned char my_out = NOFD, next_r = NOFD, id, pid; + while (end < nt && !isop(tok[end], '|')) end++; + last = (end >= nt); + if (!last) { /* pipe from this stage to the next */ + unsigned char pr = pipe(); + if (pr != NOFD) { next_r = pr; my_out = pr + 1; } + } + cmdend = end; /* this stage's own >/< redirects */ + for (i = start; i < end; i++) { + if (isop(tok[i], '>')) { if (i + 1 < end) fout = open(tok[i+1], O_WRITE); if (i < cmdend) cmdend = i; } + else if (isop(tok[i], '<')) { if (i + 1 < end) fin = open(tok[i+1], O_READ); if (i < cmdend) cmdend = i; } + } + id = lookup(tok[start]); + if (id == NOFD) { + puts(tok[start]); puts(": not found"); nl(); + if (prev_r != NOFD) close(prev_r); /* orphaned pipe ends -> EOF/EPIPE */ + if (my_out != NOFD) close(my_out); + if (fin != NOFD) close(fin); + if (fout != NOFD) close(fout); + } else { + set_cmdline(tok, start, cmdend); + pid = fork(); + if (pid == 0) { + if (fin != NOFD) setin(fin); else if (prev_r != NOFD) setin(prev_r); + if (fout != NOFD) setout(fout); else if (my_out != NOFD) setout(my_out); + exec(id); + } + if (npid < 8) pids[npid++] = pid; + if (fin != NOFD && ncfd < 8) cfd[ncfd++] = fin; + if (fout != NOFD && ncfd < 8) cfd[ncfd++] = fout; + } + prev_r = next_r; + if (last) break; + start = end + 1; + } + { unsigned char got = 0; /* wait for all stages */ + while (got < npid) { + unsigned char r = wait(), j, mine = 0; + if (r == NOFD) break; + for (j = 0; j < npid; j++) if (pids[j] == r) { mine = 1; break; } + if (mine) got++; + else { putc('['); putu(r); puts(" done]"); nl(); } + } + } + { unsigned char k; for (k = 0; k < ncfd; k++) close(cfd[k]); } +} + void main(void) { char line[80]; char *tok[16]; @@ -133,16 +188,7 @@ void main(void) { pipepos = 0; for (i = 1; i < nt; i++) if (isop(tok[i], '|')) { pipepos = i; break; } - if (pipepos) { - unsigned char pw = open("__pipe", O_WRITE); - run(tok, 0, pipepos, NOFD, pw, 0); - close(pw); - { unsigned char pr = open("__pipe", O_READ); - run(tok, pipepos + 1, nt, pr, NOFD, 0); - close(pr); } - fremove("__pipe"); - } else { - run(tok, 0, nt, NOFD, NOFD, bg); - } + if (pipepos) run_pipeline(tok, nt); + else run(tok, 0, nt, NOFD, NOFD, bg); } } |
