Currently your operating system has only been able to run one process,
probably sosh
. In this milestone you will implement the
process related system calls: process_create
,
process_delete
, my_id
,
process_status
and process_wait
. Obviously
each new process should run in its own address space. This will
require you to carefully manage seL4 address spaces.
Whilst the SOS apps will be included in the provided cpio
file, you should instead ensure that your programs are loaded from the
NFS directory when implementing process_create
.
All the functionality for process creation can be found in the
start_first_process()
in main.c
. You can use
this as a guide to create a clean internal SOS interface to process
creation and destruction.
sosh has an exec
command. This command provides a simple
interface to the process_create
system call. In a similar
style to UNIX shells, if the third argument to exec
is an
'&' then it will run the process in the
background. Otherwise sosh will use process_wait
to wait
until the child process has finished executing.
By this final milestone you should ensure that all I/O is asynchronous. This means that your system must not block waiting for completion of file system or paging I/O, but should be able to run any process that is ready while other processes are blocked on I/O completion.
Note: the difficult part of this milestone is not process creation, it is process deletion. Now you will discover whether the data structures you have chosen have kept enough information for you to clean up a process and return the resource to the various allocators.
Adding new applications
-
Create the following folder structure for your new app, replacing
<NEWAPP>
with the name of your app (drop the angle brackets):mkdir -p projects/aos/apps/<NEWAPP>/src
-
Use the following
CMakeLists.txt
forprojects/aos/apps/<NEWAPP>/CMakeLists.txt
:cmake_minimum_required(VERSION 3.7.2) project(<NEWAPP> C) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -u __vsyscall_ptr") # list all source files here add_executable(<NEWAPP> EXCLUDE_FROM_ALL src/<NEWAPP>.c) # list libraries to link binary against target_link_libraries(<NEWAPP> muslc sel4 sosapi) # warn about everything add_compile_options(-Wall -Werror -W -Wextra) add_app(<NEWAPP>)
-
Modify
projects/aos/CMakeLists.txt
, adding the following line:add_subdirectory(apps/sosh) +add_subdirectory(apps/<NEWAPP>) # add any additional apps here
All application files are automatically copied to the apps directory within the build directory.
Code
The libelf
library has been provided for you in your
source tree. You may use this library to handle the parsing of ELF
format files. You will need to modify apps/sos/src/elf.c
to load executables from the network file system instead of the cpio
image linked with SOS.
Note: you initially only need to read the ELF header of an executable file, in order to parse it and subsequently load it for execution. You can assume the header is less than the page size (4 KiB). You should only read in the file as needed when loading the executable, or completely lazily when the application faults on it.
Design issues
As with most milestones, a lot of the design work will be working out suitable data structures to hold process information. You may also need to extend other data structures in your operating system to handle multiple processes.
You must read the ELF files from the NFS filesystem and not the CPIO file. You will need to think about how your process loader will handle the asynchronous operations involved with reading files from the NFS.
You must set up the stack properly for every process for the process
startup routine from muslc to work. The existing
init_process_stack
function already does this, use if for
all processes.
Processes require some kind of ID. IDs should eventually be re-used, but they should not be re-used to soon to avoid race conditions.
New processes should have stdout
and stderr
already opened on file descriptors 1 and 2, respectively; this is
assumed by muslc. For apps that require stdin
, it must be
explicitly opened before performing any I/O and must be allocated to
file descriptor 0. If you implemented the lowest-available policy,
simply open console
as the first file syscall in your
app. Since SOS implements a single-reader console policy, you must be
prepared for this to fail.
Remember, anything allocated while a process runs should be de-allocated when it exits or is killed (e.g. in-kernel TCB, frames, paging file space, etc..).
You may wish to load the whole executable image on process creation, or instead load page-wise on demand at page-fault time.
Assessment
Demonstration
You should show sosh
executing a sub-process and show
that the ps
and kill
commands work. Hint:
exec
ing and kill
ing multiple instances of
sosh
is a good test.
You will also demonstrate (by running a sosh
) that your
system works even with repeated and concurrent executions, and that
you can execute every file (of the right content) from your NFS
directory.
As always you should be able to explain the data structures and algorithms used.
Show Stoppers
- Leaking process IDs (e.g. a monotonically increasing counter with no strategy for wrap around).
- Recycling process IDs immediately.
- Only supporting < 16 processes.
- More than constant time lookup from process ID to the PCB.
- Not handling or cleaning up outstanding async requests when a process exists (or after it exits).
- Failing to free paging file space on process destruction.
- Running programs from the CPIO archive. (It's okay to load the initial sosh from the CPIO archive.)
- Crash when attempting to load a non-executable or corrupt file.
- Assuming ELF files only have two sections.
Better Solutions
- A sound strategy for handling waiting on a process that exited quickly (before the call to wait).
- Lazy load the executable or data from the file.
- Mapping read-only ELF segments read-only, and not paging them, but re-reading them from the ELF file