summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-04-21 16:45:28 -0400
committerFreya Murphy <freya@freyacat.org>2025-04-21 16:45:33 -0400
commitceb9471fed96f907e37a6ba031825c31167a8ff4 (patch)
treed98392e420b4541a6ba926ff4d8b3ebe85734580
parentupdate linker scripts (diff)
downloadcomus-ceb9471fed96f907e37a6ba031825c31167a8ff4.tar.gz
comus-ceb9471fed96f907e37a6ba031825c31167a8ff4.tar.bz2
comus-ceb9471fed96f907e37a6ba031825c31167a8ff4.zip
update userland to compile
Diffstat (limited to '')
-rw-r--r--user/Makefile67
-rw-r--r--user/README25
-rw-r--r--user/compile_flags.txt8
-rw-r--r--user/hello.c7
-rw-r--r--user/idle.c52
l---------[-rw-r--r--]user/include/error.h31
-rw-r--r--user/include/stdio.h45
l---------user/include/syscalls.h1
-rw-r--r--user/include/unistd.h23
-rw-r--r--user/init.c185
-rw-r--r--user/lib/alloc.c15
-rw-r--r--user/lib/entry.S26
-rw-r--r--user/lib/fread.c65
-rw-r--r--user/lib/fwrite.c57
-rw-r--r--user/lib/printf.c40
-rw-r--r--user/lib/spawn.c32
-rw-r--r--user/lib/syscall.S111
-rw-r--r--user/lib/timetostr.c143
-rw-r--r--user/progABC.c71
-rw-r--r--user/progDE.c59
-rw-r--r--user/progFG.c59
-rw-r--r--user/progH.c68
-rw-r--r--user/progI.c107
-rw-r--r--user/progJ.c55
-rw-r--r--user/progKL.c63
-rw-r--r--user/progMN.c76
-rw-r--r--user/progP.c55
-rw-r--r--user/progQ.c45
-rw-r--r--user/progR.c102
-rw-r--r--user/progS.c53
-rw-r--r--user/progTUV.c167
-rw-r--r--user/progW.c61
-rw-r--r--user/progX.c51
-rw-r--r--user/progY.c52
-rw-r--r--user/progZ.c60
-rw-r--r--user/shell.c346
36 files changed, 297 insertions, 2186 deletions
diff --git a/user/Makefile b/user/Makefile
new file mode 100644
index 0000000..a4d089a
--- /dev/null
+++ b/user/Makefile
@@ -0,0 +1,67 @@
+### Copyright (c) 2025 Freya Murphy <freya@freyacat.org>
+
+.PHONY: build clean
+.SILENT:
+
+AS ?= as
+AR ?= ar
+CC ?= cc
+LD ?= ld
+CPP ?= cpp
+
+CPPFLAGS += -Iinclude
+
+CFLAGS += -O2
+CFLAGS += -std=c11
+CFLAGS += -Wall -Wextra -pedantic
+CFLAGS += -fno-pie -fno-stack-protector
+CFLAGS += -fno-omit-frame-pointer -ffreestanding
+CFLAGS += -fno-builtin
+CFLAGS += -D DEBUG -g
+CFLAGS += $(CPPFLAGS)
+
+LDFLAGS += -nmagic -nostdlib
+LDFLAGS += -z noexecstack
+
+USER=*
+LIB=lib
+BIN=../bin/user
+
+H_SRC = $(shell find include -type f -name "*.h")
+LIBA_SRC = $(shell find $(LIB) -type f -name "*.S")
+LIBA_OBJ = $(patsubst %.S,$(BIN)/%.S.o,$(LIBA_SRC))
+LIBC_SRC = $(shell find $(LIB) -type f -name "*.c")
+LIBC_OBJ = $(patsubst %.c,$(BIN)/%.o,$(LIBC_SRC))
+USER_SRC = $(shell find $(USER) -maxdepth 0 -type f -name "*.c")
+USER_OBJ = $(patsubst %.c,$(BIN)/%.o,$(USER_SRC))
+USER_PROJ = $(patsubst %.o,%,$(USER_OBJ))
+
+build: $(USER_PROJ)
+
+clean:
+ rm -fr $(BIN)
+
+$(LIBA_OBJ): $(BIN)/%.S.o : %.S
+ mkdir -p $(@D)
+ printf "\033[33m AS \033[0m%s\n" $<
+ $(CPP) $(CPPFLAGS) -o $@.cpp $<
+ $(AS) -o $@ $@.cpp
+
+$(LIBC_OBJ): $(BIN)/%.o : %.c
+ mkdir -p $(@D)
+ printf "\033[34m CC \033[0m%s\n" $<
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+$(BIN)/libc.a: $(LIBA_OBJ) $(LIBC_OBJ)
+ @mkdir -p $(@D)
+ $(AR) rcs $@ $(LIBA_OBJ) $(LIBC_OBJ)
+
+$(USER_OBJ): $(BIN)/%.o : %.c
+ mkdir -p $(@D)
+ printf "\033[34m CC \033[0m%s\n" $<
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+$(USER_PROJ): % : %.o $(BIN)/libc.a
+ mkdir -p $(@D)
+ printf "\033[32m LD \033[0m%s\n" $@
+ $(LD) $(LDFLAGS) -T ../config/user.ld -o $@ $< $(BIN)/libc.a
diff --git a/user/README b/user/README
deleted file mode 100644
index 548aac4..0000000
--- a/user/README
+++ /dev/null
@@ -1,25 +0,0 @@
-This directory contains the source code for all user-level processes,
-split out by main function.
-
-Naming convention:
-
- idle() classic 'idle' process; ensures there is always a
- runnable process to dispatch (vs., for instance, having
- dispatch() pause when there is nothing to dispatch).
-
- init() classic 'init' process; starts the idle process, and
- starts (and restarts) the user shell program.
-
- shell() "user shell" process, for spawning individual tests
-
- progN() program source code for user process(es) 'N'
-
-All of these expect at least one command-line argument. All are invoked
-with command lines of this form:
-
- name x n
-
-Each of these is designed to be compiled and linked separately, with the
-resulting load modules bundled into a blob for automatic loading by the
-bootstrap. Each will typically use one or more library functions from the
-../lib directory.
diff --git a/user/compile_flags.txt b/user/compile_flags.txt
new file mode 100644
index 0000000..c519df5
--- /dev/null
+++ b/user/compile_flags.txt
@@ -0,0 +1,8 @@
+-c
+-std=c11
+-Iinclude
+-ffreestanding
+-fno-builtin
+-Wall
+-Wextra
+-pedantic
diff --git a/user/hello.c b/user/hello.c
new file mode 100644
index 0000000..5d91d03
--- /dev/null
+++ b/user/hello.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+ printf("Hello World!\n");
+ return 0;
+}
diff --git a/user/idle.c b/user/idle.c
deleted file mode 100644
index c088a3c..0000000
--- a/user/idle.c
+++ /dev/null
@@ -1,52 +0,0 @@
-#include <common.h>
-
-/**
-** Idle process: write, getpid, gettime, exit
-**
-** Reports itself, then loops forever delaying and printing a character.
-** MUST NOT SLEEP, as it must always be available in the ready queue
-** when there is no other process to dispatch.
-**
-** Invoked as: idle
-*/
-
-USERMAIN(main)
-{
- // this is the character we will repeatedly print
- char ch = '.';
-
- // ignore the command-line arguments
- (void)argc;
- (void)argv;
-
- // get some current information
- uint_t pid = getpid();
- uint32_t now = gettime();
- enum priority_e prio = getprio();
-
- char buf[128];
- sprint(buf, "Idle [%d], started @ %u\n", pid, prio, now);
- cwrites(buf);
-
- // report our presence on the console
- cwrites("Idle started\n");
-
- write(CHAN_SIO, &ch, 1);
-
- // idle() should never block - it must always be available
- // for dispatching when we need to pick a new current process
-
- for (;;) {
- DELAY(LONG);
- write(CHAN_SIO, &ch, 1);
- }
-
- // we should never reach this point!
- now = gettime();
- sprint(buf, "Idle [%d] EXITING @ %u!?!?!\n", pid, now);
- cwrites(buf);
-
- exit(1);
-
- return (42);
-}
diff --git a/user/include/error.h b/user/include/error.h
index b9265b4..e62c3b3 100644..120000
--- a/user/include/error.h
+++ b/user/include/error.h
@@ -1,30 +1 @@
-/**
- * @file errno.h
- *
- * @author Freya Murphy <freya@freyacat.org>
- *
- * Error codes.
- */
-
-// public error codes
-#define SUCCESS (0)
-#define E_SUCCESS SUCCESS
-#define E_FAILURE (-1)
-#define E_BAD_PARAM (-2)
-#define E_BAD_FD (-3)
-#define E_NO_CHILDREN (-4)
-#define E_NO_MEMORY (-5)
-#define E_NOT_FOUND (-6)
-#define E_NO_PROCS (-7)
-
-// internal error codes
-#define E_EMPTY_QUEUE (-100)
-#define E_NO_PCBS (-101)
-#define E_NO_PTE (-102)
-#define E_LOAD_LIMIT (-103)
-
-// exit status values
-#define EXIT_SUCCESS (0)
-#define EXIT_FAILURE (-1)
-#define EXIT_KILLED (-101)
-#define EXIT_BAD_SYSCALL (-102)
+../../kernel/include/comus/error.h \ No newline at end of file
diff --git a/user/include/stdio.h b/user/include/stdio.h
index 8a938ab..2e2abf4 100644
--- a/user/include/stdio.h
+++ b/user/include/stdio.h
@@ -27,6 +27,47 @@ extern FILE *stdout;
#define stdout stdout
/**
+ * Get a char from stdin
+ *
+ * @returns the character or EOF on failure
+ */
+extern int getchar(void);
+
+/**
+ * Get a chracter from a stream
+ *
+ * @param stream - the stream to read from
+ * @returns the character or EOF on failure
+ */
+extern int getc(FILE *stream);
+
+/**
+ * Get a chracter from a stream
+ *
+ * @param stream - the stream to read from
+ * @returns the character or EOF on failure
+ */
+extern int fgetc(FILE *stream);
+
+/**
+ * Reads a string from stdin
+ *
+ * @param s - the buffer to read into
+ * @returns s on success, NULL on error or EOF
+ */
+extern char *gets(char *s);
+
+/**
+ * Reads a string from stdin
+ *
+ * @param s - the buffer to read into
+ * @param size - reads at most 1 less then size
+ * @param stream - stream to read from from
+ * @returns s on success, NULL on error or EOF
+ */
+extern char *fgets(char *restrict str, int size, FILE *stream);
+
+/**
* Prints out a char
*
* @param c - the char
@@ -140,7 +181,7 @@ extern int vsnprintf(char *restrict s, size_t maxlen, const char *format,
* @param format - the format string
* @param ... - variable args for the format
*/
-__attribute__((format(printf, 2, 3))) extern void
+__attribute__((format(printf, 2, 3))) extern int
fprintf(FILE *stream, const char *format, ...);
/**
@@ -150,7 +191,7 @@ fprintf(FILE *stream, const char *format, ...);
* @param format - the format string
* @param args - variable arg list for the format
*/
-extern void vfprintf(FILE *stream, const char *format, va_list args);
+extern int vfprintf(FILE *stream, const char *format, va_list args);
/**
* opens a file with a given file name
diff --git a/user/include/syscalls.h b/user/include/syscalls.h
new file mode 120000
index 0000000..0537882
--- /dev/null
+++ b/user/include/syscalls.h
@@ -0,0 +1 @@
+../../kernel/include/comus/syscalls.h \ No newline at end of file
diff --git a/user/include/unistd.h b/user/include/unistd.h
index 1f83abc..a815914 100644
--- a/user/include/unistd.h
+++ b/user/include/unistd.h
@@ -147,33 +147,18 @@ extern int kill(pid_t pid);
extern int sleep(unsigned long ms);
/**
- * Wait for any child to exit
+ * Set the heap break to addr
*
- * @param status - pointer to int32_t into which the child's status is placed,
- * or NULL
- * @return The pid of the terminated child, or an error code
- *
- * Analogous to waitpid(0,status)
- */
-extern int wait(int *status);
-
-/**
- * Spawn a new process running a different program
- *
- * @param prog - program table index of the program to spawn
- * @param args - the command-line argument vector for the process
- * @return the pid of the child, or an error code
- *
- * Analogous to calling fork and exec
+ * @param addr - sets the programs break to addr
+ * @return the previos program break on success, or NULL on failure
*/
-extern int spawn(pid_t prog, char **args);
+extern void *brk(const void *addr);
/**
* Increment the program's data space by increment bytes.
*
* @param increment - the amount in bytes to increment the heap
* @return the previos program break on success, or NULL on failure
- *
*/
extern void *sbrk(intptr_t increment);
diff --git a/user/init.c b/user/init.c
deleted file mode 100644
index be8e393..0000000
--- a/user/init.c
+++ /dev/null
@@ -1,185 +0,0 @@
-#include <common.h>
-
-/**
-** Initial process; it starts the other top-level user processes.
-**
-** Prints a message at startup, '+' after each user process is spawned,
-** and '!' before transitioning to wait() mode to the SIO, and
-** startup and transition messages to the console. It also reports
-** each child process it collects via wait() to the console along
-** with that child's exit status.
-*/
-
-/*
-** "Spawn table" process entry. Similar to the one in shell.c, but
-** this version has a field to hold the PID of the spawned process
-** to allow 'init' to respawn it when it terminates.
-*/
-typedef struct proc_s {
- uint_t index; // process table index
- uint_t pid; // its PID (when spawned)
- uint8_t e_prio; // process priority
- char select[3]; // identifying character, NUL, extra
- char *args[N_ARGS]; // argument vector strings
-} proc_t;
-
-/*
-** Create a spawn table entry for a process with a string literal
-** as its argument buffer. We rely on the fact that the C standard
-** ensures our array of pointers will be filled out with NULLs
-*/
-#define PROCENT(e, p, s, ...) \
- { \
- e, 0, p, s, \
- { \
- __VA_ARGS__, NULL \
- } \
- }
-
-// sentinel value for the end of the table - must be updated
-// if you have more than 90,210 user programs in the table
-#define TBLEND 90210
-
-/*
-** This table contains one entry for each process that should be
-** started by 'init'. Typically, this includes the 'idle' process
-** and a 'shell' process.
-*/
-static proc_t spawn_table[] = {
-
- // the idle process; it runs at Deferred priority,
- // so it will only be dispatched when there is
- // nothing else available to be dispatched
- PROCENT(Idle, PRIO_DEFERRED, "!", "idle", "."),
-
- // the user shell
- PROCENT(Shell, PRIO_STD, "@", "shell"),
-
- // PROCENT( 0, 0, 0, 0 )
- { TBLEND }
-};
-
-// character to be printed by init when it spawns a process
-static char ch = '+';
-
-/**
-** process - spawn all user processes listed in the supplied table
-**
-** @param proc pointer to the spawn table entry to be used
-*/
-
-static void process(proc_t *proc)
-{
- char buf[128];
-
- // kick off the process
- int32_t p = fork();
- if (p < 0) {
- // error!
- sprint(buf, "INIT: fork for #%d failed\n", (uint32_t)(proc->index));
- cwrites(buf);
-
- } else if (p == 0) {
- // change child's priority
- (void)setprio(proc->e_prio);
-
- // now, send it on its way
- exec(proc->index, proc->args);
-
- // uh-oh - should never get here!
- sprint(buf, "INIT: exec(0x%08x) failed\n", (uint32_t)(proc->index));
- cwrites(buf);
-
- } else {
- // parent just reports that another one was started
- swritech(ch);
-
- proc->pid = p;
- }
-}
-
-/*
-** The initial user process. Should be invoked with zero or one
-** argument; if provided, the first argument should be the ASCII
-** character 'init' will print to indicate the spawning of a process.
-*/
-USERMAIN(main)
-{
- char buf[128];
-
- // check to see if we got a non-standard "spawn" character
- if (argc > 1) {
- // maybe - check it to be sure it's printable
- uint_t i = argv[1][0];
- if (i > ' ' && i < 0x7f) {
- ch = argv[1][0];
- }
- }
-
- cwrites("Init started\n");
-
- // home up, clear on a TVI 925
- swritech('\x1a');
-
- // wait a bit
- DELAY(SHORT);
-
- // a bit of Dante to set the mood :-)
- swrites("\n\nSpem relinquunt qui huc intrasti!\n\n\r");
-
- /*
- ** Start all the user processes
- */
-
- cwrites("INIT: starting user processes\n");
-
- proc_t *next;
- for (next = spawn_table; next->index != TBLEND; ++next) {
- process(next);
- }
-
- swrites(" !!!\r\n\n");
-
- /*
- ** At this point, we go into an infinite loop waiting
- ** for our children (direct, or inherited) to exit.
- */
-
- cwrites("INIT: transitioning to wait() mode\n");
-
- for (;;) {
- int32_t status;
- int whom = waitpid(0, &status);
-
- // PIDs must be positive numbers!
- if (whom <= 0) {
- sprint(buf, "INIT: waitpid() returned %d???\n", whom);
- cwrites(buf);
- } else {
- // got one; report it
- sprint(buf, "INIT: pid %d exit(%d)\n", whom, status);
- cwrites(buf);
-
- // figure out if this is one of ours
- for (next = spawn_table; next->index != TBLEND; ++next) {
- if (next->pid == whom) {
- // one of ours - reset the PID field
- // (in case the spawn attempt fails)
- next->pid = 0;
- // and restart it
- process(next);
- break;
- }
- }
- }
- }
-
- /*
- ** SHOULD NEVER REACH HERE
- */
-
- cwrites("*** INIT IS EXITING???\n");
- exit(1);
-
- return (1); // shut the compiler up
-}
diff --git a/user/lib/alloc.c b/user/lib/alloc.c
index 49c762b..3d987d4 100644
--- a/user/lib/alloc.c
+++ b/user/lib/alloc.c
@@ -21,6 +21,19 @@ static const size_t header_len = sizeof(struct page_header);
static struct page_header *start_header = NULL;
static struct page_header *end_header = NULL;
+static void *alloc_pages(size_t pages)
+{
+ (void)pages;
+ // TODO: impl
+ return NULL;
+}
+
+static void free_pages(struct page_header *header)
+{
+ (void)header;
+ // TODO: impl
+}
+
static struct page_header *get_header(void *ptr)
{
struct page_header *header =
@@ -39,7 +52,6 @@ static void *alloc_new(size_t size)
{
size_t pages = ((size + header_len) / PAGE_SIZE) + 1;
- // FIXME: use brk/sbrk
void *addr = alloc_pages(pages);
void *mem = (char *)addr + header_len;
@@ -209,7 +221,6 @@ void free(void *ptr)
header->next->prev = header->prev;
if (header->prev)
header->prev->next = header->next;
- // FIXME: use brk/sbrk
free_pages(header);
}
}
diff --git a/user/lib/entry.S b/user/lib/entry.S
index 87ad9c7..34390a0 100644
--- a/user/lib/entry.S
+++ b/user/lib/entry.S
@@ -1,25 +1,15 @@
-//
-// user-level startup routine
-//
- .text
.globl _start
- .globl main
- .globl exit
+ .extern main
+ .extern exit
-// entry point - this is where the kernel starts us running
+ .section .text
+ .code64
_start:
- // we immediately call main()
call main
- // if we come back from that, it means the user
- // program didn't call exit(), in which case the
- // value returned from main() is the exit status
-
- // push that value onto the stack and call exit()
- subl $12, %esp
- pushl %eax
+ subq $16, %rsp # ???
+ pushq %rax
call exit
- // if we come back from that, something bad has
- // happened, so we just lock up
-1: jmp 1b
+halt:
+ jmp halt
diff --git a/user/lib/fread.c b/user/lib/fread.c
new file mode 100644
index 0000000..f8d0ad8
--- /dev/null
+++ b/user/lib/fread.c
@@ -0,0 +1,65 @@
+#include <stdio.h>
+#include <unistd.h>
+
+FILE *stdin = (void *)0;
+
+int getchar(void)
+{
+ return fgetc(stdin);
+}
+
+int getc(FILE *stream)
+{
+ return fgetc(stream);
+}
+
+int fgetc(FILE *stream)
+{
+ int c;
+ if (fread(&c, 1, 1, stream) < 1)
+ return EOF;
+ return c;
+}
+
+char *gets(char *str)
+{
+ char *s = str;
+ while (1) {
+ char c = fgetc(stdin);
+ if (c == '\n' || c == EOF || c == '\0')
+ break;
+ *(str++) = c;
+ }
+ *str = '\0';
+ return s;
+}
+
+char *fgets(char *restrict str, int size, FILE *stream)
+{
+ if (size < 1)
+ return NULL;
+
+ char *s = str;
+ while (size > 1) {
+ char c = fgetc(stream);
+ if (c == '\n' || c == EOF || c == '\0')
+ break;
+ *(str++) = c;
+ size--;
+ }
+
+ *str = '\0';
+ return s;
+}
+
+size_t fread(void *restrict ptr, size_t size, size_t n, FILE *restrict stream)
+{
+ int fd = (uintptr_t)stream;
+ char *restrict buf = ptr;
+
+ for (size_t i = 0; i < n; i++)
+ if (read(fd, buf + i * size, size) < 1)
+ return i;
+
+ return n;
+}
diff --git a/user/lib/fwrite.c b/user/lib/fwrite.c
new file mode 100644
index 0000000..aa828e0
--- /dev/null
+++ b/user/lib/fwrite.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <unistd.h>
+
+FILE *stdout = (void *)1;
+
+int putchar(int c)
+{
+ return putc(c, stdout);
+}
+
+int putc(int c, FILE *stream)
+{
+ return fputc(c, stream);
+}
+
+int fputc(int c, FILE *stream)
+{
+ if (fwrite(&c, 1, 1, stream) < 1)
+ return EOF;
+ return c;
+}
+
+int puts(const char *str)
+{
+ int res;
+ res = fputs(str, stdout);
+ if (res == EOF)
+ return res;
+ res = fputc('\n', stdout);
+ if (res == EOF)
+ return res;
+ return 0;
+}
+
+int fputs(const char *str, FILE *stream)
+{
+ int res;
+ while (*str) {
+ res = fputc(*str++, stream);
+ if (res == EOF)
+ return res;
+ }
+ return 0;
+}
+
+size_t fwrite(const void *restrict ptr, size_t size, size_t n,
+ FILE *restrict stream)
+{
+ int fd = (uintptr_t)stream;
+ const char *restrict buf = ptr;
+
+ for (size_t i = 0; i < n; i++)
+ if (write(fd, buf + i * size, size) < 1)
+ return i;
+
+ return n;
+}
diff --git a/user/lib/printf.c b/user/lib/printf.c
index 65d7f0f..e6abd09 100644
--- a/user/lib/printf.c
+++ b/user/lib/printf.c
@@ -7,6 +7,7 @@
#include <stdarg.h>
#define PRINTF_NUMERIC_BUF_LEN 50
+#define PRINTF_BUFFER_LEN 256
typedef union {
unsigned long long int u;
@@ -620,42 +621,3 @@ int vfprintf(FILE *stream, const char *format, va_list args)
do_printf(&ctx, args);
return ctx.written_len;
}
-
-int putchar(int c)
-{
- return putc(c, stdout);
-}
-
-int putc(int c, FILE *stream)
-{
- return fputc(c, stream);
-}
-
-int fputc(int c, FILE *stream)
-{
- // TODO: a
- return c;
-}
-
-int puts(const char *str)
-{
- int res;
- res = fputs(str, stdout);
- if (res == EOF)
- return res;
- res = fputc('\n', stdout);
- if (res == EOF)
- return res;
- return 0;
-}
-
-int fputs(const char *str, FILE *stream)
-{
- int res;
- while (*str) {
- res = fputc(*str++, stream);
- if (res == EOF)
- return res;
- }
- return 0;
-}
diff --git a/user/lib/spawn.c b/user/lib/spawn.c
deleted file mode 100644
index 78b1a53..0000000
--- a/user/lib/spawn.c
+++ /dev/null
@@ -1,32 +0,0 @@
-#include <stdio.h>
-#include <error.h>
-#include <unistd.h>
-
-int wait(int32_t *status)
-{
- return (waitpid(0, status));
-}
-
-int spawn(uint_t prog, char **args)
-{
- int32_t pid;
-
- pid = fork();
- if (pid != 0) {
- // failure, or we are the parent
- return (pid);
- }
-
- // we are the child
- pid = getpid();
-
- // child inherits parent's priority level
-
- exec(prog, args);
-
- // uh-oh....
-
- fprintf(stderr, "Child %d exec() #%u failed\n", pid, prog);
-
- exit(EXIT_FAILURE);
-}
diff --git a/user/lib/syscall.S b/user/lib/syscall.S
index 46fcb89..fc1ab93 100644
--- a/user/lib/syscall.S
+++ b/user/lib/syscall.S
@@ -1,93 +1,26 @@
-/**
-** @file ulibs.S
-**
-** @author CSCI-452 class of 20245
-**
-** @brief assembly-language user-level library functions
-*/
-
-#define ASM_SRC
-
-// get the system call codes
-
#include <syscalls.h>
-/**
-** System call stubs
-**
-** All have the same structure:
-**
-** move a code into EAX
-** generate the interrupt
-** return to the caller
-**
-** As these are simple "leaf" routines, we don't use
-** the standard enter/leave method to set up a stack
-** frame - that takes time, and we don't really need it.
-**
-** Could be modified to use the UNIX/Linux convention of
-** having the syscall code set the 'C' flag to indicate that
-** the value being returned in %EAX is an error code:
-**
-** ...
-** int $VEC_SYSCALL
-** jc set_errno
-** ret
-** ...
-**
-** .globl errno
-** set_errno:
-** movl %eax, errno
-** movl $-1, %eax
-** ret
-*/
-
-#define SYSCALL(name) \
- .globl name ; \
-name: ; \
- movl $SYS_##name, %eax ; \
- int $VEC_SYSCALL ; \
+.macro SYSCALL name num
+ .align 8
+ .globl \name
+\name:
+ movq $\num, %rax
+ int $VEC_SYSCALL
ret
+.endm
-/*
-** "real" system calls
-*/
-
-SYSCALL(exit)
-SYSCALL(waitpid)
-SYSCALL(fork)
-SYSCALL(exec)
-SYSCALL(read)
-SYSCALL(write)
-SYSCALL(getpid)
-SYSCALL(getppid)
-SYSCALL(gettime)
-SYSCALL(getprio)
-SYSCALL(setprio)
-SYSCALL(kill)
-SYSCALL(sleep)
-
-/*
-** This is a bogus system call; it's here so that we can test
-** our handling of out-of-range syscall codes in the syscall ISR.
-*/
-SYSCALL(bogus)
-
-/*
-** Other library functions
-*/
-
-/**
-** fake_exit()
-**
-** Dummy "startup" function
-**
-** calls exit(%eax) - serves as the "return to" code for
-** main() functions, in case they don't call exit() themselves
-*/
-
- .globl fake_exit
-fake_exit:
- // alternate: could push a "fake exit" status
- pushl %eax // termination status returned by main()
- call exit // terminate this process
+SYSCALL exit SYS_exit
+SYSCALL waitpid SYS_waitpid
+SYSCALL fork SYS_fork
+SYSCALL exec SYS_exec
+SYSCALL read SYS_read
+SYSCALL write SYS_write
+SYSCALL getpid SYS_getpid
+SYSCALL getppid SYS_getppid
+SYSCALL gettime SYS_gettime
+SYSCALL getprio SYS_getprio
+SYSCALL setprio SYS_setprio
+SYSCALL kill SYS_kill
+SYSCALL sleep SYS_sleep
+SYSCALL brk SYS_brk
+SYSCALL sbrk SYS_sbrk
diff --git a/user/lib/timetostr.c b/user/lib/timetostr.c
deleted file mode 100644
index fa77362..0000000
--- a/user/lib/timetostr.c
+++ /dev/null
@@ -1,143 +0,0 @@
-#include <lib.h>
-#include <time.h>
-
-static char *ABB_WEEKDAY[7] = {
- "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
-};
-
-static char *FULL_WEEKDAY[7] = { "Sunday", "Monday", "Tuesday", "Wednesday",
- "Thursday", "Friday", "Saturady" };
-
-static char *ABB_MONTH[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-
-static char *FULL_MONTH[12] = {
- "January", "Feburary", "March", "April", "May", "June",
- "July", "August", "September", "October", "November", "December"
-};
-
-static char *write_num(unsigned int num, unsigned int pad, char *buf, size_t n)
-{
- size_t digits = 1;
- unsigned int x = num;
-
- while (x /= 10, x > 0)
- digits++;
- if (pad == 0)
- pad = digits;
-
- for (size_t i = 0; i < pad; i++) {
- size_t digit;
- if (i >= digits) {
- digit = 0;
- } else {
- digit = num % 10;
- num /= 10;
- }
-
- if (pad - i - 1 >= n)
- continue;
- buf[pad - i - 1] = '0' + digit;
- }
-
- if (pad > n)
- pad = n;
-
- return buf + pad;
-}
-
-void timetostr(time_t *time, char *format, char *buf, size_t n)
-{
- char *index = buf;
- char c;
- int space;
-
- while (c = *format++, space = (buf + n) - index, c != '\0' && space > 0) {
- if (c != '%') {
- *index++ = c;
- continue;
- } else {
- c = *format++;
- }
-
- switch (c) {
- case '%':
- *index++ = '%';
- break;
- case 'a':
- index = strncpy(index, ABB_WEEKDAY[time->wday], space);
- break;
- case 'A':
- index = strncpy(index, FULL_WEEKDAY[time->wday], space);
- break;
- case 'b':
- case 'h':
- index = strncpy(index, ABB_MONTH[time->mon], space);
- break;
- case 'B':
- index = strncpy(index, FULL_MONTH[time->mon], space);
- break;
- case 'C':
- index = write_num(time->cen, 0, index, space);
- break;
- case 'd':
- index = write_num(time->mday, 2, index, space);
- break;
- case 'H':
- index = write_num(time->hour, 2, index, space);
- break;
- case 'I':
- index = write_num((time->hour + 12) % 12 + 1, 2, index, space);
- break;
- case 'j':
- index = write_num(time->yday, 3, index, space);
- break;
- case 'm':
- index = write_num(time->mon + 1, 2, index, space);
- break;
- case 'M':
- index = write_num(time->min, 2, index, space);
- break;
- case 'n':
- *index++ = '\n';
- break;
- case 'p':
- index = strncpy(index, time->hour > 11 ? "PM" : "AM", space);
- break;
- case 'P':
- index = strncpy(index, time->hour > 11 ? "pm" : "am", space);
- break;
- case 'q':
- index = write_num((time->mon + 3) / 3, 0, index, space);
- break;
- case 'S':
- index = write_num(time->sec, 2, index, space);
- break;
- case 't':
- *index++ = '\t';
- break;
- case 'u':
- index = write_num(((time->wday + 1) % 7) + 1, 0, index, space);
- break;
- case 'w':
- index = write_num(time->wday, 0, index, space);
- break;
- case 'y':
- index = write_num(time->yn, 2, index, space);
- break;
- case 'Y':
- index = write_num(time->year + 1900, 0, index, space);
- break;
- default: {
- char b[3] = { '%', c, '\0' };
- index = strncpy(index, b, space);
- break;
- }
- }
- }
-
- if (space < 1)
- buf[n - 1] = '\0';
- else
- *index = '\0';
-}
diff --git a/user/progABC.c b/user/progABC.c
deleted file mode 100644
index 0a4b299..0000000
--- a/user/progABC.c
+++ /dev/null
@@ -1,71 +0,0 @@
-#include <common.h>
-
-/**
-** User function main #1: exit, write
-**
-** Prints its ID, then loops N times delaying and printing, then exits.
-** Verifies the return byte count from each call to write().
-**
-** Invoked as: main1 x n
-** where x is the ID character
-** n is the iteration count
-*/
-
-USERMAIN(main)
-{
- int count = 30; // default iteration count
- char ch = '1'; // default character to print
- char buf[128]; // local char buffer
-
- // process the command-line arguments
- switch (argc) {
- case 3:
- count = str2int(argv[2], 10);
- // FALL THROUGH
- case 2:
- ch = argv[1][0];
- break;
- default:
- sprint(buf, "%s: argc %d, args: ", argv[0], argc);
- cwrites(buf);
- for (int i = 0; i <= argc; ++i) {
- sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
- cwrites(buf);
- }
- cwrites("\n");
- }
-
- // announce our presence
- int n = swritech(ch);
- if (n != 1) {
- sprint(buf, "== %c, write #1 returned %d\n", ch, n);
- cwrites(buf);
- }
-
- // iterate and print the required number of other characters
- for (int i = 0; i < count; ++i) {
- DELAY(STD);
- n = swritech(ch);
- if (n != 1) {
- sprint(buf, "== %c, write #2 returned %d\n", ch, n);
- cwrites(buf);
- }
- }
-
- // all done!
- exit(0);
-
- // should never reach this code; if we do, something is
- // wrong with exit(), so we'll report it
-
- char msg[] = "*1*";
- msg[1] = ch;
- n = write(CHAN_SIO, msg, 3); /* shouldn't happen! */
- if (n != 3) {
- sprint(buf, "User %c, write #3 returned %d\n", ch, n);
- cwrites(buf);
- }
-
- // this should really get us out of here
- return (42);
-}
diff --git a/user/progDE.c b/user/progDE.c
deleted file mode 100644
index be2dd1b..0000000
--- a/user/progDE.c
+++ /dev/null
@@ -1,59 +0,0 @@
-#include <common.h>
-
-/**
-** User function main #2: write
-**
-** Prints its ID, then loops N times delaying and printing, then returns
-** without calling exit(). Verifies the return byte count from each call
-** to write().
-**
-** Invoked as: main2 x n
-** where x is the ID character
-** n is the iteration count
-*/
-
-USERMAIN(main)
-{
- int n;
- int count = 30; // default iteration count
- char ch = '2'; // default character to print
- char buf[128];
-
- // process the command-line arguments
- switch (argc) {
- case 3:
- count = str2int(argv[2], 10);
- // FALL THROUGH
- case 2:
- ch = argv[1][0];
- break;
- default:
- sprint(buf, "main2: argc %d, args: ", argc);
- cwrites(buf);
- for (int i = 0; i <= argc; ++i) {
- sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
- cwrites(buf);
- }
- cwrites("\n");
- }
-
- // announce our presence
- n = swritech(ch);
- if (n != 1) {
- sprint(buf, "== %c, write #1 returned %d\n", ch, n);
- cwrites(buf);
- }
-
- // iterate and print the required number of other characters
- for (int i = 0; i < count; ++i) {
- DELAY(STD);
- n = swritech(ch);
- if (n != 1) {
- sprint(buf, "== %c, write #2 returned %d\n", ch, n);
- cwrites(buf);
- }
- }
-
- // all done!
- return (0);
-}
diff --git a/user/progFG.c b/user/progFG.c
deleted file mode 100644
index 8dddd56..0000000
--- a/user/progFG.c
+++ /dev/null
@@ -1,59 +0,0 @@
-#include <common.h>
-
-/**
-** User function main #3: exit, sleep, write
-**
-** Prints its ID, then loops N times sleeping and printing, then exits.
-**
-** Invoked as: main3 x n s
-** where x is the ID character
-** n is the iteration count
-** s is the sleep time in seconds
-*/
-
-USERMAIN(main)
-{
- char ch = '3'; // default character to print
- int nap = 10; // default sleep time
- int count = 30; // iteration count
- char buf[128];
-
- // process the command-line arguments
- switch (argc) {
- case 4:
- nap = str2int(argv[3], 10);
- // FALL THROUGH
- case 3:
- count = str2int(argv[2], 10);
- // FALL THROUGH
- case 2:
- ch = argv[1][0];
- break;
- default:
- sprint(buf, "main3: argc %d, args: ", argc);
- cwrites(buf);
- for (int i = 0; i <= argc; ++i) {
- sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
- cwrites(buf);
- }
- cwrites("\n");
- }
-
- // announce our presence
- int n = swritech(ch);
- if (n != 1) {
- sprint(buf, "=== %c, write #1 returned %d\n", ch, n);
- cwrites(buf);
- }
-
- write(CHAN_SIO, &ch, 1);
-
- for (int i = 0; i < count; ++i) {
- sleep(SEC_TO_MS(nap));
- write(CHAN_SIO, &ch, 1);
- }
-
- exit(0);
-
- return (42); // shut the compiler up!
-}
diff --git a/user/progH.c b/user/progH.c
deleted file mode 100644
index 0cef860..0000000
--- a/user/progH.c
+++ /dev/null
@@ -1,68 +0,0 @@
-#include <common.h>
-
-/**
-** User function H: exit, fork, exec, sleep, write
-**
-** Prints its ID, then spawns 'n' children; exits before they terminate.
-**
-** Invoked as: userH x n
-** where x is the ID character
-** n is the number of children to spawn
-*/
-
-USERMAIN(main)
-{
- int32_t ret = 0; // return value
- int count = 5; // child count
- char ch = 'h'; // default character to print
- char buf[128];
- int whom;
-
- // process the argument(s)
- switch (argc) {
- case 3:
- count = str2int(argv[2], 10);
- // FALL THROUGH
- case 2:
- ch = argv[1][0];
- break;
- default:
- sprint(buf, "userH: argc %d, args: ", argc);
- cwrites(buf);
- for (int i = 0; i <= argc; ++i) {
- sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
- cwrites(buf);
- }
- cwrites("\n");
- }
-
- // announce our presence
- swritech(ch);
-
- // we spawn user Z and then exit before it can terminate
- // userZ 'Z' 10
-
- char *argsz[] = { "userZ", "Z", "10", NULL };
-
- for (int i = 0; i < count; ++i) {
- // spawn a child
- whom = spawn(ProgZ, argsz);
-
- // our exit status is the number of failed spawn() calls
- if (whom < 0) {
- sprint(buf, "!! %c spawn() failed, returned %d\n", ch, whom);
- cwrites(buf);
- ret += 1;
- }
- }
-
- // yield the CPU so that our child(ren) can run
- sleep(0);
-
- // announce our departure
- swritech(ch);
-
- exit(ret);
-
- return (42); // shut the compiler up!
-}
diff --git a/user/progI.c b/user/progI.c
deleted file mode 100644
index a1988e3..0000000
--- a/user/progI.c
+++ /dev/null
@@ -1,107 +0,0 @@
-#include <common.h>
-
-#ifndef MAX_CHILDREN
-#define MAX_CHILDREN 50
-#endif
-
-/**
-** User function I: exit, fork, exec, kill, sleep, waitpid, write
-**
-** Reports, then loops spawing userW, sleeps, kills two children, then
-** loops checking the status of all its children
-**
-** Invoked as: userI [ x [ n ] ]
-** where x is the ID character (defaults to 'i')
-** n is the number of children to spawn (defaults to 5)
-*/
-
-USERMAIN(main)
-{
- int count = 5; // default child count
- char ch = 'i'; // default character to print
- int nap = 5; // nap time
- char buf[128];
- char ch2[] = "*?*";
- uint_t children[MAX_CHILDREN];
- int nkids = 0;
-
- // process the command-line arguments
- switch (argc) {
- case 3:
- count = str2int(argv[2], 10);
- // FALL THROUGH
- case 2:
- ch = argv[1][0];
- break;
- case 1: // just use the defaults
- break;
- default:
- sprint(buf, "userI: argc %d, args: ", argc);
- cwrites(buf);
- for (int i = 0; i <= argc; ++i) {
- sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
- cwrites(buf);
- }
- cwrites("\n");
- }
-
- // secondary output (for indicating errors)
- ch2[1] = ch;
-
- // announce our presence
- write(CHAN_SIO, &ch, 1);
-
- // set up the argument vector
- // we run: userW 10 5
-
- char *argsw[] = { "userW", "W", "10", "5", NULL };
-
- for (int i = 0; i < count; ++i) {
- int whom = spawn(ProgW, argsw);
- if (whom < 0) {
- swrites(ch2);
- } else {
- swritech(ch);
- children[nkids++] = whom;
- }
- }
-
- // let the children start
- sleep(SEC_TO_MS(nap));
-
- // kill two of them
- int32_t status = kill(children[1]);
- if (status) {
- sprint(buf, "!! %c: kill(%d) status %d\n", ch, children[1], status);
- cwrites(buf);
- children[1] = -42;
- }
- status = kill(children[3]);
- if (status) {
- sprint(buf, "!! %c: kill(%d) status %d\n", ch, children[3], status);
- cwrites(buf);
- children[3] = -42;
- }
-
- // collect child information
- while (1) {
- int n = waitpid(0, NULL);
- if (n == E_NO_CHILDREN) {
- // all done!
- break;
- }
- for (int i = 0; i < count; ++i) {
- if (children[i] == n) {
- sprint(buf, "== %c: child %d (%d)\n", ch, i, children[i]);
- cwrites(buf);
- }
- }
- sleep(SEC_TO_MS(nap));
- };
-
- // let init() clean up after us!
-
- exit(0);
-
- return (42); // shut the compiler up!
-}
diff --git a/user/progJ.c b/user/progJ.c
deleted file mode 100644
index a1e6310..0000000
--- a/user/progJ.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include <common.h>
-
-/**
-** User function J: exit, fork, exec, write
-**
-** Reports, tries to spawn lots of children, then exits
-**
-** Invoked as: userJ x [ n ]
-** where x is the ID character
-** n is the number of children to spawn (defaults to 2 * N_PROCS)
-*/
-
-USERMAIN(main)
-{
- int count = 2 * N_PROCS; // number of children to spawn
- char ch = 'j'; // default character to print
- char buf[128];
-
- // process the command-line arguments
- switch (argc) {
- case 3:
- count = str2int(argv[2], 10);
- // FALL THROUGH
- case 2:
- ch = argv[1][0];
- break;
- default:
- sprint(buf, "userJ: argc %d, args: ", argc);
- cwrites(buf);
- for (int i = 0; i <= argc; ++i) {
- sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
- cwrites(buf);
- }
- cwrites("\n");
- }
-
- // announce our presence
- write(CHAN_SIO, &ch, 1);
-
- // set up the command-line arguments
- char *argsy[] = { "userY", "Y", "10", NULL };
-
- for (int i = 0; i < count; ++i) {
- int whom = spawn(ProgY, argsy);
- if (whom < 0) {
- write(CHAN_SIO, "!j!", 3);
- } else {
- write(CHAN_SIO, &ch, 1);
- }
- }
-
- exit(0);
-
- return (42); // shut the compiler up!
-}
diff --git a/user/progKL.c b/user/progKL.c
deleted file mode 100644
index aa9f039..0000000
--- a/user/progKL.c
+++ /dev/null
@@ -1,63 +0,0 @@
-#include <common.h>
-
-/**
-** User function main #4: exit, fork, exec, sleep, write
-**
-** Loops, spawning N copies of userX and sleeping between spawns.
-**
-** Invoked as: main4 x n
-** where x is the ID character
-** n is the iteration count (defaults to 5)
-*/
-
-USERMAIN(main)
-{
- int count = 5; // default iteration count
- char ch = '4'; // default character to print
- int nap = 30; // nap time
- char msg2[] = "*4*"; // "error" message to print
- char buf[32];
-
- // process the command-line arguments
- switch (argc) {
- case 3:
- count = str2int(argv[2], 10);
- // FALL THROUGH
- case 2:
- ch = argv[1][0];
- break;
- default:
- sprint(buf, "main4: argc %d, args: ", argc);
- cwrites(buf);
- for (int i = 0; i <= argc; ++i) {
- sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
- cwrites(buf);
- }
- cwrites("\n");
- }
-
- // announce our presence
- write(CHAN_SIO, &ch, 1);
-
- // argument vector for the processes we will spawn
- char *arglist[] = { "userX", "X", buf, NULL };
-
- for (int i = 0; i < count; ++i) {
- write(CHAN_SIO, &ch, 1);
-
- // second argument to X is 100 plus the iteration number
- sprint(buf, "%d", 100 + i);
- int whom = spawn(ProgX, arglist);
- if (whom < 0) {
- swrites(msg2);
- } else {
- write(CHAN_SIO, &ch, 1);
- }
-
- sleep(SEC_TO_MS(nap));
- }
-
- exit(0);
-
- return (42); // shut the compiler up!
-}
diff --git a/user/progMN.c b/user/progMN.c
deleted file mode 100644
index d2dbe9b..0000000
--- a/user/progMN.c
+++ /dev/null
@@ -1,76 +0,0 @@
-#include <common.h>
-
-/**
-** User function main #5: exit, fork, exec, write
-**
-** Iterates spawning copies of userW (and possibly userZ), reporting
-** their PIDs as it goes.
-**
-** Invoked as: main5 x n b
-** where x is the ID character
-** n is the iteration count
-** b is the w&z boolean
-*/
-
-USERMAIN(main)
-{
- int count = 5; // default iteration count
- char ch = '5'; // default character to print
- int alsoZ = 0; // also do userZ?
- char msgw[] = "*5w*";
- char msgz[] = "*5z*";
- char buf[128];
-
- // process the command-line arguments
- switch (argc) {
- case 4:
- alsoZ = argv[3][0] == 't';
- // FALL THROUGH
- case 3:
- count = str2int(argv[2], 10);
- // FALL THROUGH
- case 2:
- ch = argv[1][0];
- break;
- default:
- sprint(buf, "main5: argc %d, args: ", argc);
- cwrites(buf);
- for (int i = 0; i <= argc; ++i) {
- sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
- cwrites(buf);
- }
- cwrites("\n");
- }
-
- // update the extra message strings
- msgw[1] = msgz[1] = ch;
-
- // announce our presence
- write(CHAN_SIO, &ch, 1);
-
- // set up the argument vector(s)
-
- // W: 15 iterations, 5-second sleep
- char *argsw[] = { "userW", "W", "15", "5", NULL };
-
- // Z: 15 iterations
- char *argsz[] = { "userZ", "Z", "15", NULL };
-
- for (int i = 0; i < count; ++i) {
- write(CHAN_SIO, &ch, 1);
- int whom = spawn(ProgW, argsw);
- if (whom < 1) {
- swrites(msgw);
- }
- if (alsoZ) {
- whom = spawn(ProgZ, argsz);
- if (whom < 1) {
- swrites(msgz);
- }
- }
- }
-
- exit(0);
-
- return (42); // shut the compiler up!
-}
diff --git a/user/progP.c b/user/progP.c
deleted file mode 100644
index 8909599..0000000
--- a/user/progP.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include "common.h"
-
-/**
-** User function P: exit, sleep, write, gettime
-**
-** Reports itself, then loops reporting itself
-**
-** Invoked as: userP x [ n [ t ] ]
-** where x is the ID character
-** n is the iteration count (defaults to 3)
-** t is the sleep time (defaults to 2 seconds)
-*/
-
-USERMAIN(main)
-{
- int count = 3; // default iteration count
- char ch = 'p'; // default character to print
- int nap = 2; // nap time
- char buf[128];
-
- // process the command-line arguments
- switch (argc) {
- case 4:
- nap = str2int(argv[3], 10);
- // FALL THROUGH
- case 3:
- count = str2int(argv[2], 10);
- // FALL THROUGH
- case 2:
- ch = argv[1][0];
- break;
- default:
- sprint(buf, "userP: argc %d, args: ", argc);
- cwrites(buf);
- for (int i = 0; i <= argc; ++i) {
- sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
- cwrites(buf);
- }
- cwrites("\n");
- }
-
- // announce our presence
- uint32_t now = gettime();
- sprint(buf, " P@%u", now);
- swrites(buf);
-
- for (int i = 0; i < count; ++i) {
- sleep(SEC_TO_MS(nap));
- write(CHAN_SIO, &ch, 1);
- }
-
- exit(0);
-
- return (42); // shut the compiler up!
-}
diff --git a/user/progQ.c b/user/progQ.c
deleted file mode 100644
index 660c2d6..0000000
--- a/user/progQ.c
+++ /dev/null
@@ -1,45 +0,0 @@
-#include <common.h>
-
-/**
-** User function Q: exit, write, bogus
-**
-** Reports itself, then tries to execute a bogus system call
-**
-** Invoked as: userQ x
-** where x is the ID character
-*/
-
-USERMAIN(main)
-{
- char ch = 'q'; // default character to print
- char buf[128];
-
- // process the command-line arguments
- switch (argc) {
- case 2:
- ch = argv[1][0];
- break;
- default:
- sprint(buf, "userQ: argc %d, args: ", argc);
- cwrites(buf);
- for (int i = 0; i <= argc; ++i) {
- sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
- cwrites(buf);
- }
- cwrites("\n");
- }
-
- // announce our presence
- write(CHAN_SIO, &ch, 1);
-
- // try something weird
- bogus();
-
- // should not have come back here!
- sprint(buf, "!!!!! %c returned from bogus syscall!?!?!\n", ch);
- cwrites(buf);
-
- exit(1);
-
- return (42); // shut the compiler up!
-}
diff --git a/user/progR.c b/user/progR.c
deleted file mode 100644
index 672318b..0000000
--- a/user/progR.c
+++ /dev/null
@@ -1,102 +0,0 @@
-#include <common.h>
-
-/**
-** User function R: exit, sleep, write, fork, getpid, getppid,
-**
-** Reports itself and its sequence number, along with its PID and
-** its parent's PID. It then delays, forks, delays, reports again,
-** and exits.
-**
-** Invoked as: userR x n [ s ]
-** where x is the ID character
-** n is the sequence number of the initial incarnation
-** s is the initial delay time (defaults to 10)
-*/
-
-USERMAIN(main)
-{
- char ch = 'r'; // default character to print
- int delay = 10; // initial delay count
- int seq = 99; // my sequence number
- char buf[128];
-
- // process the command-line arguments
- switch (argc) {
- case 4:
- delay = str2int(argv[3], 10);
- // FALL THROUGH
- case 3:
- seq = str2int(argv[2], 10);
- // FALL THROUGH
- case 2:
- ch = argv[1][0];
- break;
- default:
- sprint(buf, "userR: argc %d, args: ", argc);
- cwrites(buf);
- for (int i = 0; i <= argc; ++i) {
- sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
- cwrites(buf);
- }
- cwrites("\n");
- }
-
- /*
- ** C oddity: a label cannot immediately precede a declaration.
- **
- ** Declarations are not considered "statements" in C. Prior to
- ** C99, all declarations had to precede any statements inside a
- ** block. Labels can only appear before statements. C99 allowed
- ** the mixing of declarations and statements, but did not relax
- ** the requirement that labels precede only statements.
- **
- ** That's why the declarations of these variables occur before the
- ** label, but their initializations occur after the label.
- **
- ** As the PSA says on TV, "The more you know..." :-)
- */
-
- int32_t pid;
- int32_t ppid;
-
-restart:
-
- // announce our presence
- pid = getpid();
- ppid = getppid();
-
- sprint(buf, " %c[%d,%d,%d]", ch, seq, pid, ppid);
- swrites(buf);
-
- sleep(SEC_TO_MS(delay));
-
- // create the next child in sequence
- if (seq < 5) {
- ++seq;
- int32_t n = fork();
- switch (n) {
- case -1:
- // failure?
- sprint(buf, "** R[%d] fork code %d\n", pid, n);
- cwrites(buf);
- break;
- case 0:
- // child
- goto restart;
- default:
- // parent
- --seq;
- sleep(SEC_TO_MS(delay));
- }
- }
-
- // final report - PPID may change, but PID and seq shouldn't
- pid = getpid();
- ppid = getppid();
- sprint(buf, " %c[%d,%d,%d]", ch, seq, pid, ppid);
- swrites(buf);
-
- exit(0);
-
- return (42); // shut the compiler up!
-}
diff --git a/user/progS.c b/user/progS.c
deleted file mode 100644
index c8e0e60..0000000
--- a/user/progS.c
+++ /dev/null
@@ -1,53 +0,0 @@
-#include <common.h>
-
-/**
-** User function S: exit, sleep, write
-**
-** Reports itself, then loops forever, sleeping on each iteration
-**
-** Invoked as: userS x [ s ]
-** where x is the ID character
-** s is the sleep time (defaults to 20)
-*/
-
-USERMAIN(main)
-{
- char ch = 's'; // default character to print
- int nap = 20; // nap time
- char buf[128];
-
- // process the command-line arguments
- switch (argc) {
- case 3:
- nap = str2int(argv[2], 10);
- // FALL THROUGH
- case 2:
- ch = argv[1][0];
- break;
- default:
- sprint(buf, "userS: argc %d, args: ", argc);
- cwrites(buf);
- for (int i = 0; i <= argc; ++i) {
- sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
- cwrites(buf);
- }
- cwrites("\n");
- }
-
- // announce our presence
- write(CHAN_SIO, &ch, 1);
-
- sprint(buf, "userS sleeping %d(%d)\n", nap, SEC_TO_MS(nap));
- cwrites(buf);
-
- for (;;) {
- sleep(SEC_TO_MS(nap));
- write(CHAN_SIO, &ch, 1);
- }
-
- sprint(buf, "!! %c exiting!?!?!?\n", ch);
- cwrites(buf);
- exit(1);
-
- return (42); // shut the compiler up!
-}
diff --git a/user/progTUV.c b/user/progTUV.c
deleted file mode 100644
index 8e69a66..0000000
--- a/user/progTUV.c
+++ /dev/null
@@ -1,167 +0,0 @@
-#include <common.h>
-
-/**
-** User function main #6: exit, fork, exec, kill, waitpid, sleep, write
-**
-** Reports, then loops spawing userW, sleeps, then waits for or kills
-** all its children.
-**
-** Invoked as: main6 x c b
-** where x is the ID character
-** c is the child count
-** b is wait/kill indicator ('w', 'W', or 'k')
-*/
-
-#ifndef MAX_CHILDREN
-#define MAX_CHILDREN 50
-#endif
-
-USERMAIN(main)
-{
- int count = 3; // default child count
- char ch = '6'; // default character to print
- int nap = 8; // nap time
- bool_t waiting = true; // default is waiting by PID
- bool_t bypid = true;
- char buf[128];
- uint_t children[MAX_CHILDREN];
- int nkids = 0;
- char ch2[] = "*?*";
-
- // process the command-line arguments
- switch (argc) {
- case 4:
- waiting = argv[3][0] != 'k'; // 'w'/'W' -> wait, else -> kill
- bypid = argv[3][0] != 'w'; // 'W'/'k' -> by PID
- // FALL THROUGH
- case 3:
- count = str2int(argv[2], 10);
- // FALL THROUGH
- case 2:
- ch = argv[1][0];
- break;
- default:
- sprint(buf, "main6: argc %d, args: ", argc);
- cwrites(buf);
- for (int i = 0; i <= argc; ++i) {
- sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
- cwrites(buf);
- }
- cwrites("\n");
- }
-
- // fix the secondary output message (for indicating errors)
- ch2[1] = ch;
-
- // announce our presence
- write(CHAN_SIO, &ch, 1);
-
- // set up the argument vector
- char *argsw[] = { "userW", "W", "10", "5", NULL };
-
- for (int i = 0; i < count; ++i) {
- int whom = spawn(ProgW, argsw);
- if (whom < 0) {
- swrites(ch2);
- } else {
- children[nkids++] = whom;
- }
- }
-
- // let the children start
- sleep(SEC_TO_MS(nap));
-
- // collect exit status information
-
- // current child index
- int n = 0;
-
- do {
- int this;
- int32_t status;
-
- // are we waiting for or killing it?
- if (waiting) {
- this = waitpid(bypid ? children[n] : 0, &status);
- } else {
- // always by PID
- this = kill(children[n]);
- }
-
- // what was the result?
- if (this < SUCCESS) {
- // uh-oh - something went wrong
-
- // "no children" means we're all done
- if (this != E_NO_CHILDREN) {
- if (waiting) {
- sprint(buf, "!! %c: waitpid(%d) status %d\n", ch,
- bypid ? children[n] : 0, this);
- } else {
- sprint(buf, "!! %c: kill(%d) status %d\n", ch, children[n],
- this);
- }
- } else {
- sprint(buf, "!! %c: no children\n", ch);
- }
-
- // regardless, we're outta here
- break;
-
- } else {
- // locate the child
- int ix = -1;
-
- // were we looking by PID?
- if (bypid) {
- // we should have just gotten the one we were looking for
- if (this != children[n]) {
- // uh-oh
- sprint(buf, "** %c: wait/kill PID %d, got %d\n", ch,
- children[n], this);
- cwrites(buf);
- } else {
- ix = n;
- }
- }
-
- // either not looking by PID, or the lookup failed somehow
- if (ix < 0) {
- int i;
- for (i = 0; i < nkids; ++i) {
- if (children[i] == this) {
- ix = i;
- break;
- }
- }
- }
-
- // if ix == -1, the PID we received isn't in our list of children
-
- if (ix < 0) {
- // didn't find an entry for this PID???
- sprint(buf, "!! %c: child PID %d term, NOT FOUND\n", ch, this);
-
- } else {
- // found this PID in our list of children
- if (ix != n) {
- // ... but it's out of sequence
- sprint(buf, "== %c: child %d (%d,%d) status %d\n", ch, ix,
- n, this, status);
- } else {
- sprint(buf, "== %c: child %d (%d) status %d\n", ch, ix,
- this, status);
- }
- }
- }
-
- cwrites(buf);
-
- ++n;
-
- } while (n < nkids);
-
- exit(0);
-
- return (42); // shut the compiler up!
-}
diff --git a/user/progW.c b/user/progW.c
deleted file mode 100644
index b71ec23..0000000
--- a/user/progW.c
+++ /dev/null
@@ -1,61 +0,0 @@
-#include <common.h>
-
-/**
-** User function W: exit, sleep, write, getpid, gettime
-**
-** Reports its presence, then iterates 'n' times printing identifying
-** information and sleeping, before exiting.
-**
-** Invoked as: userW x [ n [ s ] ]
-** where x is the ID character
-** n is the iteration count (defaults to 20)
-** s is the sleep time (defaults to 3 seconds)
-*/
-
-USERMAIN(main)
-{
- int count = 20; // default iteration count
- char ch = 'w'; // default character to print
- int nap = 3; // nap length
- char buf[128];
-
- // process the command-line arguments
- switch (argc) {
- case 4:
- nap = str2int(argv[3], 10);
- // FALL THROUGH
- case 3:
- count = str2int(argv[2], 10);
- // FALL THROUGH
- case 2:
- ch = argv[1][0];
- break;
- default:
- sprint(buf, "userW: argc %d, args: ", argc);
- cwrites(buf);
- for (int i = 0; i <= argc; ++i) {
- sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
- cwrites(buf);
- }
- cwrites("\n");
- }
-
- // announce our presence
- int pid = getpid();
- uint32_t now = gettime();
- sprint(buf, " %c[%d,%u]", ch, pid, now);
- swrites(buf);
-
- write(CHAN_SIO, &ch, 1);
-
- for (int i = 0; i < count; ++i) {
- now = gettime();
- sprint(buf, " %c[%d,%u] ", ch, pid, now);
- swrites(buf);
- sleep(SEC_TO_MS(nap));
- }
-
- exit(0);
-
- return (42); // shut the compiler up!
-}
diff --git a/user/progX.c b/user/progX.c
deleted file mode 100644
index 782823e..0000000
--- a/user/progX.c
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <common.h>
-
-/**
-** User function X: exit, write, getpid
-**
-** Prints its PID at start and exit, iterates printing its character
-** N times, and exits with a status of 12.
-**
-** Invoked as: userX x n
-** where x is the ID character
-** n is the iteration count
-*/
-
-USERMAIN(main)
-{
- int count = 20; // iteration count
- char ch = 'x'; // default character to print
- char buf[128];
-
- // process the command-line arguments
- switch (argc) {
- case 3:
- count = str2int(argv[2], 10);
- // FALL THROUGH
- case 2:
- ch = argv[1][0];
- break;
- default:
- sprint(buf, "userX: argc %d, args: ", argc);
- cwrites(buf);
- for (int i = 0; i <= argc; ++i) {
- sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
- cwrites(buf);
- }
- cwrites("\n");
- }
-
- // announce our presence
- int pid = getpid();
- sprint(buf, " %c[%d]", ch, pid);
- swrites(buf);
-
- for (int i = 0; i < count; ++i) {
- swrites(buf);
- DELAY(STD);
- }
-
- exit(12);
-
- return (42); // shut the compiler up!
-}
diff --git a/user/progY.c b/user/progY.c
deleted file mode 100644
index 43313bd..0000000
--- a/user/progY.c
+++ /dev/null
@@ -1,52 +0,0 @@
-#include <common.h>
-
-/**
-** User function Y: exit, sleep, write, getpid
-**
-** Reports its PID, then iterates N times printing 'Yx' and
-** sleeping for one second, then exits.
-**
-** Invoked as: userY x [ n ]
-** where x is the ID character
-** n is the iteration count (defaults to 10)
-*/
-
-USERMAIN(main)
-{
- int count = 10; // default iteration count
- char ch = 'y'; // default character to print
- char buf[128];
-
- // process the command-line arguments
- switch (argc) {
- case 3:
- count = str2int(argv[2], 10);
- // FALL THROUGH
- case 2:
- ch = argv[1][0];
- break;
- default:
- sprint(buf, "?: argc %d, args: ", argc);
- cwrites(buf);
- for (int i = 0; i <= argc; ++i) {
- sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
- cwrites(buf);
- }
- cwrites("\n");
- }
-
- // report our presence
- int pid = getpid();
- sprint(buf, " %c[%d]", ch, pid);
- swrites(buf);
-
- for (int i = 0; i < count; ++i) {
- swrites(buf);
- DELAY(STD);
- sleep(SEC_TO_MS(1));
- }
-
- exit(0);
-
- return (42); // shut the compiler up!
-}
diff --git a/user/progZ.c b/user/progZ.c
deleted file mode 100644
index fdeb888..0000000
--- a/user/progZ.c
+++ /dev/null
@@ -1,60 +0,0 @@
-#include <common.h>
-
-/**
-** User function Z: exit, sleep, write, getpid
-**
-** Prints its ID, then records PID and PPID, loops printing its ID,
-** and finally re-gets PPID for comparison. Yields after every second
-** ID print in the loop.
-**
-** This code is used as a handy "spawn me" test routine; it is spawned
-** by several of the standard test processes.
-**
-** Invoked as: userZ x [ n ]
-** where x is the ID character
-** n is the iteration count (defaults to 10)
-*/
-
-USERMAIN(main)
-{
- int count = 10; // default iteration count
- char ch = 'z'; // default character to print
- char buf[128];
-
- // process the command-line arguments
- switch (argc) {
- case 3:
- count = str2int(argv[2], 10);
- // FALL THROUGH
- case 2:
- ch = argv[1][0];
- break;
- default:
- sprint(buf, "?: argc %d, args: ", argc);
- cwrites(buf);
- for (int i = 0; i <= argc; ++i) {
- sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
- cwrites(buf);
- }
- cwrites("\n");
- }
-
- // announce our presence
- int pid = getpid();
- sprint(buf, " %c[%d]", ch, pid);
- swrites(buf);
-
- // iterate for a while; occasionally yield the CPU
- for (int i = 0; i < count; ++i) {
- sprint(buf, " %c[%d]", ch, i);
- swrites(buf);
- DELAY(STD);
- if (i & 1) {
- sleep(0);
- }
- }
-
- exit(0);
-
- return (42); // shut the compiler up!
-}
diff --git a/user/shell.c b/user/shell.c
deleted file mode 100644
index f8c13cd..0000000
--- a/user/shell.c
+++ /dev/null
@@ -1,346 +0,0 @@
-#include <common.h>
-
-// should we keep going?
-static bool_t time_to_stop = false;
-
-// number of spawned but uncollected children
-static int children = 0;
-
-/*
-** For the test programs in the baseline system, command-line arguments
-** follow these rules. The first two entries are as follows:
-**
-** argv[0] the name used to "invoke" this process
-** argv[1] the "character to print" (identifies the process)
-**
-** Most user programs have one or more additional arguments.
-**
-** See the comment at the beginning of each user-code source file for
-** information on the argument list that code expects.
-*/
-
-/*
-** "Spawn table" process entry. Similar to that in init.c,
-** except this one has no place to store the PID of the child.
-*/
-typedef struct proc_s {
- uint_t index; // process table index
- int8_t prio; // process priority
- char select[3]; // identifying character, NUL, extra
- char *args[N_ARGS]; // argument vector strings
-} proc_t;
-
-/*
-** Create a spawn table entry for a process with a string literal
-** as its argument buffer. We rely on the fact that the C standard
-** ensures our array of pointers will be filled out with NULLs
-*/
-#define PROCENT(e, p, s, ...) \
- { \
- e, p, s, \
- { \
- __VA_ARGS__, NULL \
- } \
- }
-
-// sentinel value for the end of the table - must be updated
-// if you have more than 90,210 user programs in the table
-#define TBLEND 90210
-
-/*
-** The spawn table contains entries for processes that are started
-** by the shell.
-*/
-static proc_t spawn_table[] = {
-
-// Users A-C each run ProgABC, which loops printing its character
-#if defined(SPAWN_A)
- PROCENT(ProgABC, PRIO_STD, "A", "userA", "A", "30"),
-#endif
-#if defined(SPAWN_B)
- PROCENT(ProgABC, PRIO_STD, "B", "userB", "B", "30"),
-#endif
-#if defined(SPAWN_C)
- PROCENT(ProgABC, PRIO_STD, "C", "userC", "C", "30"),
-#endif
-
-// Users D and E run ProgDE, which is like ProgABC but doesn't exit()
-#if defined(SPAWN_D)
- PROCENT(ProgDE, PRIO_STD, "D", "userD", "D", "20"),
-#endif
-#if defined(SPAWN_E)
- PROCENT(ProgDE, PRIO_STD, "E", "userE", "E", "20"),
-#endif
-
-// Users F and G run ProgFG, which sleeps between write() calls
-#if defined(SPAWN_F)
- PROCENT(ProgFG, PRIO_STD, "F", "userF", "F", "20"),
-#endif
-#if defined(SPAWN_G)
- PROCENT(ProgFG, PRIO_STD, "G", "userG", "G", "10"),
-#endif
-
-// User H tests reparenting of orphaned children
-#if defined(SPAWN_H)
- PROCENT(ProgH, PRIO_STD, "H", "userH", "H", "4"),
-#endif
-
-// User I spawns several children, kills one, and waits for all
-#if defined(SPAWN_I)
- PROCENT(ProgI, PRIO_STD, "I", "userI", "I"),
-#endif
-
-// User J tries to spawn 2 * N_PROCS children
-#if defined(SPAWN_J)
- PROCENT(ProgJ, PRIO_STD, "J", "userJ", "J"),
-#endif
-
-// Users K and L iterate spawning userX and sleeping
-#if defined(SPAWN_K)
- PROCENT(ProgKL, PRIO_STD, "K", "userK", "K", "8"),
-#endif
-#if defined(SPAWN_L)
- PROCENT(ProgKL, PRIO_STD, "L", "userL", "L", "5"),
-#endif
-
-// Users M and N spawn copies of userW and userZ via ProgMN
-#if defined(SPAWN_M)
- PROCENT(ProgMN, PRIO_STD, "M", "userM", "M", "5", "f"),
-#endif
-#if defined(SPAWN_N)
- PROCENT(ProgMN, PRIO_STD, "N", "userN", "N", "5", "t"),
-#endif
-
-// There is no user O
-
-// User P iterates, reporting system time and stats, and sleeping
-#if defined(SPAWN_P)
- PROCENT(ProgP, PRIO_STD, "P", "userP", "P", "3", "2"),
-#endif
-
-// User Q tries to execute a bad system call
-#if defined(SPAWN_Q)
- PROCENT(ProgQ, PRIO_STD, "Q", "userQ", "Q"),
-#endif
-
-// User R reports its PID, PPID, and sequence number; it
-// calls fork() but not exec(), with each child getting the
-// next sequence number, to a total of five copies
-#if defined(SPAWN_R)
- PROCENT(ProgR, PRIO_STD, "R", "userR", "R", "20", "1"),
-#endif
-
-// User S loops forever, sleeping 13 sec. on each iteration
-#if defined(SPAWN_S)
- PROCENT(ProgS, PRIO_STD, "S", "userS", "S", "13"),
-#endif
-
-// Users T-V run ProgTUV(); they spawn copies of userW
-// User T waits for any child
-// User U waits for each child by PID
-// User V kills each child
-#if defined(SPAWN_T)
- PROCENT(ProgTUV, PRIO_STD, "T", "userT", "T", "6", "w"),
-#endif
-#if defined(SPAWN_U)
- PROCENT(ProgTUV, PRIO_STD, "U", "userU", "U", "6", "W"),
-#endif
-#if defined(SPAWN_V)
- PROCENT(ProgTUV, PRIO_STD, "V", "userV", "V", "6", "k"),
-#endif
-
- // a dummy entry to use as a sentinel
- { TBLEND }
-
- // these processes are spawned by the ones above, and are never
- // spawned directly.
-
- // PROCENT( ProgW, PRIO_STD, "?", "userW", "W", "20", "3" ),
- // PROCENT( ProgX, PRIO_STD, "?", "userX", "X", "20" ),
- // PROCENT( ProgY, PRIO_STD, "?", "userY", "Y", "10" ),
- // PROCENT( ProgZ, PRIO_STD, "?", "userZ", "Z", "10" )
-};
-
-/*
-** usage function
-*/
-static void usage(void)
-{
- swrites("\nTests - run with '@x', where 'x' is one or more of:\n ");
- proc_t *p = spawn_table;
- while (p->index != TBLEND) {
- swritech(' ');
- swritech(p->select[0]);
- }
- swrites("\nOther commands: @* (all), @h (help), @x (exit)\n");
-}
-
-/*
-** run a program from the program table, or a builtin command
-*/
-static int run(char which)
-{
- char buf[128];
- register proc_t *p;
-
- if (which == 'h') {
- // builtin "help" command
- usage();
-
- } else if (which == 'x') {
- // builtin "exit" command
- time_to_stop = true;
-
- } else if (which == '*') {
- // torture test! run everything!
- for (p = spawn_table; p->index != TBLEND; ++p) {
- int status = spawn(p->index, p->args);
- if (status > 0) {
- ++children;
- }
- }
-
- } else {
- // must be a single test; find and run it
- for (p = spawn_table; p->index != TBLEND; ++p) {
- if (p->select[0] == which) {
- // found it!
- int status = spawn(p->index, p->args);
- if (status > 0) {
- ++children;
- }
- return status;
- }
- }
-
- // uh-oh, made it through the table without finding the program
- sprint(buf, "shell: unknown cmd '%c'\n", which);
- swrites(buf);
- usage();
- }
-
- return 0;
-}
-
-/**
-** edit - perform any command-line editing we need to do
-**
-** @param line Input line buffer
-** @param n Number of valid bytes in the buffer
-*/
-static int edit(char line[], int n)
-{
- char *ptr = line + n - 1; // last char in buffer
-
- // strip the EOLN sequence
- while (n > 0) {
- if (*ptr == '\n' || *ptr == '\r') {
- --n;
- } else {
- break;
- }
- }
-
- // add a trailing NUL byte
- if (n > 0) {
- line[n] = '\0';
- }
-
- return n;
-}
-
-/**
-** shell - extremely simple shell for spawning test programs
-**
-** Scheduled by _kshell() when the character 'u' is typed on
-** the console keyboard.
-*/
-USERMAIN(main)
-{
- // keep the compiler happy
- (void)argc;
- (void)argv;
-
- // report that we're up and running
- swrites("Shell is ready\n");
-
- // print a summary of the commands we'll accept
- usage();
-
- // loop forever
- while (!time_to_stop) {
- char line[128];
- char *ptr;
-
- // the shell reads one line from the keyboard, parses it,
- // and performs whatever command it requests.
-
- swrites("\n> ");
- int n = read(CHAN_SIO, line, sizeof(line));
-
- // shortest valid command is "@?", so must have 3+ chars here
- if (n < 3) {
- // ignore it
- continue;
- }
-
- // edit it as needed; new shortest command is 2+ chars
- if ((n = edit(line, n)) < 2) {
- continue;
- }
-
- // find the '@'
- int i = 0;
- for (ptr = line; i < n; ++i, ++ptr) {
- if (*ptr == '@') {
- break;
- }
- }
-
- // did we find an '@'?
- if (i < n) {
- // yes; process any commands that follow it
- ++ptr;
-
- for (; *ptr != '\0'; ++ptr) {
- char buf[128];
- int pid = run(*ptr);
-
- if (pid < 0) {
- // spawn() failed
- sprint(buf, "+++ Shell spawn %c failed, code %d\n", *ptr,
- pid);
- cwrites(buf);
- }
-
- // should we end it all?
- if (time_to_stop) {
- break;
- }
- } // for
-
- // now, wait for all the spawned children
- while (children > 0) {
- // wait for the child
- int32_t status;
- char buf[128];
- int whom = waitpid(0, &status);
-
- // figure out the result
- if (whom == E_NO_CHILDREN) {
- break;
- } else if (whom < 1) {
- sprint(buf, "shell: waitpid() returned %d\n", whom);
- } else {
- --children;
- sprint(buf, "shell: PID %d exit status %d\n", whom, status);
- }
- // report it
- swrites(buf);
- }
- } // if i < n
- } // while
-
- cwrites("!!! shell exited loop???\n");
- exit(1);
-}