When you finished the process system call (e.g., fork, execv) and test your
system call by executing some user program, you'll probably find that the
console input behavior is messed up.
For example, when you executing user shell from OS161 kernel menu, and then
executing /bin/true from the shell, you may see this
OS/161 kernel [? for menu]: s
Operation took 0.000285120 seconds
OS/161 kernel [? for menu]: (program name unknown): Timing enabled.
OS/161$ /bin/true
(program name unknown): bntu: No such file or directory
(program name unknown): subprocess time: 0.063300440 seconds
Exit 1
In this case, the shell program only receive the input "bnut" instead of your
input (/bin/true).
To find out why, we need to dig into how kernel menu ($OS161_SRC/kern/startup/menu.c)
works a little bit. When you hit "s" in the kernel menu. What happens?
-
cmd_dispatchwill look up thecmd_tableand callcmd_shell -
cmd_shelljust callcommon_progwith the shell path argument -
common_progwill first create a child thread with the start functioncmd_progthread, then return -
In the child thread,
cmd_progthreadwill try to run the actual program (in our case, the shell)
Note that the shell program is run in a separate child thread, and the parent thread (i.e., the menu thread) will continue to run after he "forked" the child thread.
So now there are actually two thread that want to read console input, which leads to race condition. This is why the shell program receive corrupted input: the menu thread eaten some of the inputs!
To solve this problem, we need to let the menu thread wait for the child
thread to complete, then return. So what we need to do is in common_prog, we
need to do a waitpid operation after we call thread_fork. And at the end of
cmd_progthread, we need to explicitly call exit with proper exit code in
case the user program doesn't do this.
Also note that waitpid and exit are in fact user land system call, and we can
not directly call them in kernel, so you may need to make some "shortcuts" in
your system call implementation to let the kernel be able to call sys_waitpid
and sys_exit.