Skip to content

Commit

Permalink
Parameterize test script argument
Browse files Browse the repository at this point in the history
Pass the path to the script file via bootargs. This will make it easier
to add more scripts. Rename "smoke-test" to "test-script" to better
reflect that.

As a side effect, this gets rid of one extra process when running tests
(the "smoke-test" program), which in turn reduces the memory footprint
(2-7 pages, depending on the configuration).

The path to the test script is passed to the shell program via argv.
Shell's stack is used to store the string and the argv array itself,
which consumes some stack (quite significant in case of tiny-stack
test), which required a supporting change in run_shell_script(). We no
longer allocate `pbuf` on the stack, but reserve a bit of the file
buffer for it. This saving is enough to compensate for the expenses for
argv.

The shell now has an optional parameter '-f', which makes it freeze
after executing the script. This is needed to avoid the top level shell
from exiting.
  • Loading branch information
rtfb committed Feb 29, 2024
1 parent 15ba20d commit 316a91e
Show file tree
Hide file tree
Showing 16 changed files with 120 additions and 85 deletions.
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -225,22 +225,22 @@ $(OUT)/test-output-virt.txt: $(OUT)/os_virt
@echo "OK"

$(OUT)/smoke-test-output-u32.txt: $(OUT)/os_sifive_u32
@$(QEMU_LAUNCHER) --bootargs smoke-test --timeout=5s --binary=$< > $@
@$(QEMU_LAUNCHER) --bootargs test-script=/home/smoke-test.sh --timeout=5s --binary=$< > $@
@diff -u testdata/want-smoke-test-output-u32.txt $@
@echo "OK"

$(OUT)/smoke-test-output-u64.txt: $(OUT)/os_sifive_u
@$(QEMU_LAUNCHER) --bootargs smoke-test --timeout=5s --binary=$< > $@
@$(QEMU_LAUNCHER) --bootargs test-script=/home/smoke-test.sh --timeout=5s --binary=$< > $@
@diff -u testdata/want-smoke-test-output-u64.txt $@
@echo "OK"

$(OUT)/smoke-test-output-virt.txt: $(OUT)/os_virt
@$(QEMU_LAUNCHER) --bootargs smoke-test --timeout=5s --binary=$< > $@
@$(QEMU_LAUNCHER) --bootargs test-script=/home/smoke-test.sh --timeout=5s --binary=$< > $@
@diff -u testdata/want-smoke-test-output-virt.txt $@
@echo "OK"

$(OUT)/smoke-test-output-tiny-stack.txt: $(OUT)/os_virt
@$(QEMU_LAUNCHER) --bootargs tiny-stack --timeout=5s --binary=$< > $@
@$(QEMU_LAUNCHER) --bootargs tiny-stack=/home/smoke-test.sh --timeout=5s --binary=$< > $@
@diff -u testdata/want-smoke-test-output-tiny-stack.txt $@
@echo "OK"

Expand Down
2 changes: 1 addition & 1 deletion include/proc.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ void swtch(context_t *old, context_t *new);
// processes that will get executed by default. Kind of like what an initrd
// would do, but a poor man's version until we can do better.
void init_test_processes(uint32_t runflags);
void assign_init_program(char const* prog);

void init_process_table(uint32_t runflags, unsigned int hart_id);
void scheduler();
Expand Down Expand Up @@ -242,5 +241,6 @@ void fd_free(process_t *proc, int32_t fd);
process_t* find_proc_by_pid(uint32_t pid);

regsize_t reoffset_user_stack(process_t *dest, process_t *src, int reg);
void inject_argv(process_t *proc, int argc, char const *argv[]);

#endif // ifndef _PROC_H_
1 change: 1 addition & 0 deletions include/programs.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ extern user_program_t userland_programs[MAX_USERLAND_PROGS];

// defined in proc_test.c:
user_program_t* find_user_program(char const *name);
void assign_init_program(char const* prog, char const *test_script);

#endif // ifndef _PROGRAMS_H_
3 changes: 3 additions & 0 deletions include/runflags.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
#define RUNFLAGS_SMOKE_TEST ((1 << 2) | RUNFLAGS_TESTS)
#define RUNFLAGS_TINY_STACK ((1 << 3) | RUNFLAGS_TESTS)

// defined in runflags.c
extern char const *test_script;

uint32_t parse_runflags();

#endif // ifndef _RUNFLAGS_H_
1 change: 1 addition & 0 deletions include/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define _STRING_H_

int strncmp(char const *a, char const *b, unsigned int num);
int has_prefix(char const *str, char const *prefix, int *end_of_prefix);
char* strncpy(char *dest, char const *src, unsigned int num);
int kstrlen(char const *s);

Expand Down
18 changes: 14 additions & 4 deletions scripts/qemu-launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,19 @@ def make_docker_cmd(is_32bit, is_interactive):
return cmd


def is_interactive(args):
if 'test' in args.binary:
return False
if args.bootargs == 'dry-run':
return False
ba = args.bootargs
if not ba:
return True
if ba.startswith('test-script') or ba.startswith('tiny-stack'):
return False
return True


def make_qemu_command(args):
binary = args.binary

Expand All @@ -156,10 +169,7 @@ def make_qemu_command(args):
else:
machine = 'sifive_e'

is_interactive = ('test' not in binary) and (
args.bootargs not in ['dry-run', 'smoke-test', 'tiny-stack']
)
cmd = make_docker_cmd(is_32bit, is_interactive)
cmd = make_docker_cmd(is_32bit, is_interactive(args))

# Override our guesses if args were passed explicitly:
if args.qemu is not None:
Expand Down
21 changes: 21 additions & 0 deletions src/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,27 @@ sp_argv_t copy_argv(process_t *proc, uintptr_t *sp, regsize_t argc, char const*
};
}

// inject_argv assigns a given argc and argv to a given process. It stores the
// values at the end of the page allocated for stack, pushing the stack pointer
// (and thus, the bottom of the stack) below them. That should only ever be
// done to a freshly initialized process, otherwise the bottom of the stack
// would be ruined. Intended for use in the code path for automated tests.
void inject_argv(process_t *proc, int argc, char const *argv[]) {
void *stack_bottom = proc->perrno - argc - 1;
char const **new_argv = stack_bottom;
for (int i = 0; i < argc; i++) {
int len = kstrlen(argv[i]);
stack_bottom -= len + 1;
strncpy(stack_bottom, argv[i], len + 1);
*new_argv = (char const*)USR_STK_VIRT(stack_bottom);
new_argv++;
}
*new_argv = 0;
proc->trap.regs[REG_SP] = STK_ROUND(USR_STK_VIRT(stack_bottom));
proc->trap.regs[REG_A0] = argc;
proc->trap.regs[REG_A1] = USR_STK_VIRT(new_argv - argc);
}

uintptr_t* _set_perrno(void *sp) {
return (uintptr_t*)(sp + user_stack_size) - 1;
}
Expand Down
15 changes: 7 additions & 8 deletions src/proc_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ extern int u_main_hello1();
extern int u_main_hello2();
extern int u_main_sysinfo();
extern int u_main_fmt();
extern int u_main_smoke_test();
extern int u_main_hanger();
extern int u_main_ps();
extern int u_main_cat();
Expand Down Expand Up @@ -46,10 +45,6 @@ user_program_t userland_programs[MAX_USERLAND_PROGS] _rodata = {
.entry_point = &u_main_fmt,
.name = "fmt",
},
(user_program_t){
.entry_point = &u_main_smoke_test,
.name = "smoke-test",
},
(user_program_t){
.entry_point = &u_main_hanger,
.name = "hang",
Expand Down Expand Up @@ -110,13 +105,13 @@ void init_test_processes(uint32_t runflags) {
return;
}
if (runflags == RUNFLAGS_SMOKE_TEST || runflags == RUNFLAGS_TINY_STACK) {
assign_init_program("smoke-test");
assign_init_program("sh", test_script);
} else {
assign_init_program("sh");
assign_init_program("sh", 0);
}
}

void assign_init_program(char const* prog) {
void assign_init_program(char const* prog, char const *test_script) {
user_program_t *program = find_user_program(prog);
if (!program) {
panic("no init program");
Expand All @@ -128,6 +123,10 @@ void assign_init_program(char const* prog) {
return;
}
uintptr_t status = init_proc(p0, USR_VIRT(program->entry_point), program->name);
if (test_script != 0) {
char const *args[] = {program->name, "-f", test_script};
inject_argv(p0, 3, args);
}
release(&p0->lock);
if (status != 0) {
panic("init p0 process");
Expand Down
10 changes: 8 additions & 2 deletions src/runflags.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@
#include "runflags.h"
#include "string.h"

char const *test_script = 0;

uint32_t parse_runflags() {
if (!strncmp(fdt_get_bootargs(), "dry-run", ARRAY_LENGTH("dry-run"))) {
return RUNFLAGS_DRY_RUN;
}
if (!strncmp(fdt_get_bootargs(), "smoke-test", ARRAY_LENGTH("smoke-test"))) {
char const *bootargs = fdt_get_bootargs();
int end_of_prefix = 0;
if (has_prefix(bootargs, "test-script", &end_of_prefix)) {
test_script = bootargs + end_of_prefix + 1;
return RUNFLAGS_SMOKE_TEST;
}
if (!strncmp(fdt_get_bootargs(), "tiny-stack", ARRAY_LENGTH("tiny-stack"))) {
if (has_prefix(bootargs, "tiny-stack", &end_of_prefix)) {
test_script = bootargs + end_of_prefix + 1;
return RUNFLAGS_TINY_STACK;
}
return 0;
Expand Down
15 changes: 15 additions & 0 deletions src/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,21 @@ int strncmp(char const *a, char const *b, unsigned int num) {
return *a - *b;
}

// has_prefix checks whether str has a given prefix. Returns 0 if at least one
// character of str is different than the corresponding character in prefix. If
// end_of_prefix is not null, it will be set to the index of the first
// character within str after the prefix.
int has_prefix(char const *str, char const *prefix, int *end_of_prefix) {
int prefix_len = kstrlen(prefix);
if (strncmp(str, prefix, prefix_len)) {
return 0;
}
if (end_of_prefix != 0) {
*end_of_prefix = prefix_len;
}
return 1;
}

char* strncpy(char *dest, char const *src, unsigned int num) {
char *orig_dest = dest;
for (unsigned int i = 0; i < num - 1 && *src; i++) {
Expand Down
18 changes: 8 additions & 10 deletions testdata/want-smoke-test-output-tiny-stack.txt
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
kinit: cpu 0
Reading FDT...
FDT ok
bootargs: tiny-stack
bootargs: tiny-stack=/home/smoke-test.sh
kprintf test: str=foo, ptr=0xabcdf10a, pos int=1337, neg int=-9223372036854775807
Init userland smoke test!
Total RAM: 48
Free RAM: 17
Num procs: 3
Free RAM: 24
Num procs: 2
formatted string: num=387, zero=0, char=X, hex=0xaddbeef, str=foo
only groks 7 args: 11 12 13 14 15 16 17 %d %d
I will hang now, bye
Total RAM: 48
Free RAM: 10
Num procs: 4
Free RAM: 17
Num procs: 3
PID STATE NAME
0 S smoke-test
1 S sh
4 S hang
6 R ps
0 S sh
3 S hang
5 R ps
23
formatted string: num=387, zero=0, char=X, hex=0xaddbeef, str=foo

Expand Down
18 changes: 8 additions & 10 deletions testdata/want-smoke-test-output-u32.txt
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
kinit: cpu 0
Reading FDT...
FDT ok
bootargs: smoke-test
bootargs: test-script=/home/smoke-test.sh
kprintf test: str=foo, ptr=0xabcdf10a, pos int=1337, neg int=-2147483647
Init userland smoke test!
Total RAM: 32
Free RAM: 23
Num procs: 3
Free RAM: 25
Num procs: 2
formatted string: num=387, zero=0, char=X, hex=0xaddbeef, str=foo
only groks 7 args: 11 12 13 14 15 16 17 %d %d
I will hang now, bye
Total RAM: 32
Free RAM: 21
Num procs: 4
Free RAM: 23
Num procs: 3
PID STATE NAME
0 S smoke-test
1 S sh
4 S hang
6 R ps
0 S sh
3 S hang
5 R ps
23
formatted string: num=387, zero=0, char=X, hex=0xaddbeef, str=foo

Expand Down
18 changes: 8 additions & 10 deletions testdata/want-smoke-test-output-u64.txt
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
kinit: cpu 0
Reading FDT...
FDT ok
bootargs: smoke-test
bootargs: test-script=/home/smoke-test.sh
kprintf test: str=foo, ptr=0xabcdf10a, pos int=1337, neg int=-9223372036854775807
Init userland smoke test!
Total RAM: 32
Free RAM: 23
Num procs: 3
Free RAM: 25
Num procs: 2
formatted string: num=387, zero=0, char=X, hex=0xaddbeef, str=foo
only groks 7 args: 11 12 13 14 15 16 17 %d %d
I will hang now, bye
Total RAM: 32
Free RAM: 21
Num procs: 4
Free RAM: 23
Num procs: 3
PID STATE NAME
0 S smoke-test
1 S sh
4 S hang
6 R ps
0 S sh
3 S hang
5 R ps
23
formatted string: num=387, zero=0, char=X, hex=0xaddbeef, str=foo

Expand Down
18 changes: 8 additions & 10 deletions testdata/want-smoke-test-output-virt.txt
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
kinit: cpu 0
Reading FDT...
FDT ok
bootargs: smoke-test
bootargs: test-script=/home/smoke-test.sh
kprintf test: str=foo, ptr=0xabcdf10a, pos int=1337, neg int=-9223372036854775807
Init userland smoke test!
Total RAM: 48
Free RAM: 17
Num procs: 3
Free RAM: 24
Num procs: 2
formatted string: num=387, zero=0, char=X, hex=0xaddbeef, str=foo
only groks 7 args: 11 12 13 14 15 16 17 %d %d
I will hang now, bye
Total RAM: 48
Free RAM: 10
Num procs: 4
Free RAM: 17
Num procs: 3
PID STATE NAME
0 S smoke-test
1 S sh
4 S hang
6 R ps
0 S sh
3 S hang
5 R ps
23
formatted string: num=387, zero=0, char=X, hex=0xaddbeef, str=foo

Expand Down
16 changes: 13 additions & 3 deletions user/src/shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ int _userland run_shell_script(char const *filepath, cmdbuf_t cmdpool) {
return -1;
}
char *fbuf = (char*)pgalloc();
int32_t nread = read(fd, fbuf, PAGE_SIZE);
int32_t nread = read(fd, fbuf, PAGE_SIZE - 32); // reserve 32 bytes for pbuf
if (nread == -1) {
pgfree(fbuf);
prints("ERROR: read=-1\n");
Expand All @@ -87,7 +87,7 @@ int _userland run_shell_script(char const *filepath, cmdbuf_t cmdpool) {
fbuf[nread] = 0;
int start = 0;
int end = 0;
char pbuf[32];
char *pbuf = fbuf + PAGE_SIZE - 32;
while (fbuf[end] != 0) {
pbuf[0] = 0;
int i = 0;
Expand Down Expand Up @@ -225,7 +225,17 @@ int _userland u_main_shell(int argc, char* argv[]) {
cmdbuf_t cmdpool = sh_init_cmd_slots(cmd_slots, num_slots);

if (argc > 1) {
int code = run_shell_script(argv[1], cmdpool);
int freeze = 0;
int script_i = 1;
if (argv[1][0] == '-' && argv[1][1] == 'f') {
freeze = 1;
script_i = 2;
}
int code = run_shell_script(argv[script_i], cmdpool);
if (freeze) {
for (;;)
sleep(1000);
}
exit(code);
return code;
}
Expand Down
Loading

0 comments on commit 316a91e

Please sign in to comment.