This is the whole user-side write function, generated by user/usys.pl. How do
the descriptor, buffer address and byte count reach the kernel?
Test yourself · category 20 of 20
User space: ulib, usys and the shell
How a user program starts, calls the kernel through the usys stubs and the small ulib/printf/malloc library, and how the shell parses a command line and wires pipes and redirections with fork, close, dup and exec.
When cat calls write(1, buf, n), what number is in register a7 at the ecall?
True or false: if a user program’s main returns 3 without calling exit, the
process crashes, because main returns to an invalid address.
Why?
user/user.ld has no ENTRY line, and the Makefile passes no -e option when it
links _cat. Where does cat start executing after kexec?
init executes printf("init: starting sh\n"). How many write system calls does
that one call make?
The shell handles cd itself instead of forking a child to run it like every other
command. Why?
Match each piece of shell syntax with the node that the parser in user/sh.c
builds for it.
Every user program except forktest is linked with ULIB = ulib.o usys.o printf.o umalloc.o. Which of these are therefore part of _cat?
For ls | wc, click the line that makes ls’s standard output (descriptor 1) refer
to the pipe.
Your pick: none yet (click a line in the code)
You type ls and press Enter. Put these steps in the order they happen in the shell
and its child.
- The child’s parsecmd builds the tree, and nulterminate writes
\0s into its copy of buf - fork1 creates a child; the shell goes on to wait
- gets reads the line one byte per
read, stopping at the newline - main checks whether the line starts with
cd - runcmd reaches the EXEC case and calls exec
- getcmd writes
$to descriptor 2
In the right child (the future wc) someone deletes line 116, close(p[1]). You run
ls | wc. What happens?
While parsing echo hi > out, parseredirs builds a redircmd whose mode
field is 0x601. Decode it with kernel/fcntl.h.
Value: 0x601
True or false: in the REDIR case, runcmd tells open which descriptor
number the file should get (rcmd->fd).
Why?
Why does the shell parse the command line in the child after fork1(), rather
than parsing first and forking afterwards?
After parsing ls | wc, where do the strings ecmd->argv[0] of the two exec nodes
point?
A freshly exec’d program’s first malloc call is malloc(100). How many
bytes does malloc (through morecore) ask the kernel for with sbrk? A
Header is 16 bytes.
cat is in its write stub (user/usys.S:31) and is about to execute ecall;
the trap has not happened yet. What is the state of the hart running it?
Which of these user library functions can make a system call?
For echo a ; echo b, click the line that guarantees a is printed before echo b
even starts.
Your pick: none yet (click a line in the code)
You type a | b | c (three programs). Counting the shell’s own fork1 in main and
every fork1 in runcmd, how many times is fork called to run this line?
You type echo hi &. The shell prints the next prompt without waiting for echo.
Which process eventually calls wait and frees echo’s process slot?
The file out contains 50 bytes. You type cat < nosuchfile > out, and nosuchfile
does not exist. What happens?
char buf[] = "abcde"; then memmove(buf + 1, buf, 4);. Which branch of
memmove runs, and what does buf hold afterwards?
The shell’s child calls exec("echo", argv) for the line echo hi there. When
echo’s start executes its first instruction, which statements are true?
user/user.ld places .text at address 0, and kexec maps it with PTE_R,
PTE_X and PTE_U. A buggy user program executes int x = *(int *)0;. What happens?