Safe System Programming
This is the home page for the "Safe System Programming" course.
Here, you will find (in a badly-organised form) all the
material, slides, and information needed to attend the course
Lessons:
- First lesson: 2020/02/17, 9:30 -> 12:00
- Second lesson: 2020/02/24, 9:30 -> 12:00
- Third lesson: 2020/03/02, 9:30 -> 12:00
- Fourth lesson: 2020/03/06, 9:30 -> 12:00, lesson via hangouts
- Rust advanced data types
- Videos (in Italian): first part and second part. Unfortunately, there have been some issues with the streaming platform during the lesson, so the recording might miss some parts.
- Fift lesson: 2020/03/13, 9:30 -> 12:00
- Sixth lesson: 2020/03/20, 9:30 -> 12:00
- Seventh lesson: 2020/03/27, 9:30 -> 12:00
- Eighth lesson: 2020/04/03, 9:30 -> 12:00
Ideas about Possible Projects for the Exam
Some projects are simpler than others; if you decide to work on a project, please
contact me first.
- Try to convert some simple C or C++ application (example: a scheduling simulator) to Rust, and compare size/performance/memory footprint
- Implement some kind of simple real-time application using Rust. For example, a simplified
version of rt-app, or a multi-threaded
application simulating a physical system (such as an inverted pendolum) and controlling it
(for example, using some kind of PID controller)
- Implement some kind of simplified kernel (for x86_64 or ARM) in Rust. See links below for
some references
- Students also attending the
Virtualization Technologies
course can develop a single project for the two courses. For example:
- Use Rust to implement some kind of minimalistic hypervisor for x86_64 or ARM,
based on trap'n'emulate, or hardware-supported virtualization
- Implement in Rust a simple and minimalistic VM based on KVM
- Implement a simple container runtime using Rust
- Use Rust to implement some kind of application at your choice, showing if and how
the Rust features helped in making it safer without compromising performance.
Links and other teaching material:
Here is a paper
comparing the performance of user-space device drivers written in different languages.
In order to better understand Rust and some aspects of
its design, it is important to know some concepts about
programming languages (not directly related to Rust or
to safe programming languages, but applicable to many
different programming languages).
Here is a simple document (in Italian) defining some
of these important
concepts.
On the internet it is possible to find a huge amount of tutorial showing
how to write kernels, hypervisors or bare-metal applications in Rust.
For example, look at
Philipp Oppermann's blog (note:
in the example showed during the course, Rust is used to code a library
that is linked to some startup code written in Assembly; in the current
version of the blog, Rust is used to write the main application, using
a "bootloader" crate. The blog uses cargo --- in particular,
cargo xbuild --- to cross-compile bare-metal Rust applications).
Other useful links can be toyos-rs and eduOS-rs.
Interesting news: QEMU developers are thinking about
moving QEMU to Rust.
Code examples:
Some examples about ownership and move semantics in Rust (do not care about syntax, Box, and new yet):
An example about a simple function
in Rust (notice how the return value is passed).
An example about using boolean predicates (in an "if" expression).
Some examples about the Rust predefined data types, in particular compound types:
An example about parsing a string,
showing that the type inference mechanism here needs some help...
Some examples about Rust data types that can be accessed through pattern matching:
- A simple example with tuples,
showing how to match the elements of a tuple. Notice that in this case
pattern matching is done using a "let" variable declaration
- A Similar example using a
function. Notice how to declare a function that receives a tuple as an argument
- A more complex example using an enumeration
(custom data type). This is the "sum type" in algebraic data types.
Notice that in this case pattern matching uses a "if let" construct.
- Same example, but
using a C-like structure in the enum type, instead of a tuple-like structure.
Some examples about methods:
Some examples about traits and generics:
And, last but not least, some examples about smart pointers:
- Example of usage of a box to dynamically allocate memory. Memory is managed according to the RAII paradigm (a box can be used as a reference to the allocated memory; the memory is freed when the reference goes out of scope; assignment has a move semantic)
- Similar example with a box showing that even if the memory is dynamically allocated, a mutable reference cannot be taken if other reference to the variable already exist
- Example with a reference counter (Rc): in this case, the allocated data can have multiple owners (for every new owner, a reference counter is increaded; when an owner is destroyed, the reference counter is drecreased; when the reference counter is 0, the data is deallocated)
- Similar example showing that the clone() method of a reference counted smart pointer returns immutable references to the allocated data
- Example showing how to use a RefCell smart pointer to move borrow checking at runtime. The example compiles and runs without issues because "r1" and "r2" are immutable references... Hence, something like "r2.v = 0" will not compile. To make it compile, the "
let r2 = cell.borrow();
" must be changed to "let mut r2 = cell.borrow_mut();
". With this change, the code will compile but will generate an exception at runtime (it is still illegal to borrow a mutable reference when other references are already been borrowed)
- Example showing how to use a RefCell smart pointer to borrow mutable and immutable references (at different times!)
- Another example about RefCell
- Yet another RefCell example showing runtime borrow checking (compiles, but generates an exception at runtime)
- Example showing different kinds of references and smart pointers
- Examples about using RefCell (combined with Rc) to have multiple references or owners, with one mutable. This does not work (runtime exception), because a RefCell cannot be borrowed mutably when it has been already borrowed, but this does work, because Rc allows to have multiple owners, and RefCell allows a single owner to be mutable
Very simple kernel written in Rust
Examples about functions and closures:
Some other examples, about threads:
Coding exercizes:
- Write a function that computes the greatest common divisor between two integers, and a main function invoking it
- Write a generic
max()
function
- Exercises introducing lifetimes
- Implement a recursive data type in rust (for example, natural numbers according to Peano)