-
Stefan Lankes
-
ca. 20 Jahre an der RWTH Aachen
-
Lehrt und forscht im Bereich der Systemsoftware
-
Insbesondere für das Hochleistungsrechnen
-
Unikernels
-
-
Verwendet hauptsächlich C, C++ und Assembler
-
-
Der Entwicklungsprozess hat sich komplett geändert
-
Versionsverwaltung: git
-
Social Coding: GitHub
-
Continuous Integration: Travis CI
-
Die Art des Testens: Code Coverage
-
Neue Programmiersprachen: Go, Julia, …
-
Linux wurde zum Windows der Akademiker
-
-
Das OS Design hat sich nicht grundlegenden geändert
-
C dominiert weiterhin
-
Noch zeitgemäß?
-
Der Entwicklungsprozess eines OS entfernt sich von einer Anwendung
-
C ist aus der UNIX-Entwicklung entstanden
-
Passt zur OS Entwicklung
-
-
Hoher Freiheitsgrad, kein Overhead
-
Fehler anfällig
-
Keine Laufzeitumgebung direkt im Kernel nutzbar
-
Jeder definiert sich seine eigene
-
z.B. libkern von FreeBSD
-
strcpy, memcpy, qsort, …
-
-
Kein Overhead
-
Einfache Integration von C-Code
-
Vermeidung von Wettlaufsituationen
-
Einfacher und korrekter Umgang mit Zeigern
-
Keine Dangling Pointers, keine Pufferüberläufe
-
Kein Garbage Collection
-
Rust ist eine (relativ) neue Programmiersprache für systemnahe Software
fn main() {
// Die Statements werden ausgeführt sobald
// das compilierte Binary gestartet wird.
// Ausgabe auf stdout
println!("Hello CCCAC!");
}
Bekannt u.a. für den Einsatz in Firefox
⇒ Rust Code läuft somit auf Millionen von Rechnern
Note
|
Frage ans Publikum:
|
-
Rust ist ein open-source (MIT + Apache) Projekt
-
Wird aktuell primär von Mozilla Research gesponsort
-
Die Weiterentwicklung selbst wird allerdings stark durch die Community getrieben
Note
|
-
C/C++ ähnliche Performance
-
Compilerbasierte Überprüfungen welche z.B.
-
Speichersicherheit (ohne Garbage Collection) garantieren
-
Data Races verhindern
-
⇒ Falscher Code compiliert nicht
Note
|
Performance: Keinen Grund wieso es langsamer als C sein sollte Link zu Computer Language Benchmarks Game |
Note
|
Die Sicht auf sich selbst. Allgemein natürlich schwierig. |
std::vector<std::string>* x = nullptr;
{
std::vector<std::string> z;
z.push_back("Hello CCCAC!");
x = &z;
}
std::cout << (*x)[0] << std::endl;
Note
|
|
-
Ist dieses C++-Beispiel problematisch?
let x;
{
let z = vec!("Hello CCCAC!");
x = &z;
}
println!("{}", x[0]);
Note
|
error[E0597]: `z` does not live long enough
--> src/main.rs:9:8
|
9 | x = &z;
| ^ borrowed value does not live long enough
10 | }
| - `z` dropped here while still borrowed
...
13 | }
| - borrowed value needs to live until here
Note
|
-
Variablen werden an einen Besitzer (Owner) gebunden
-
Wird der Scope des Besitzers verlassen, wird die Variable freigeben
-
Yehuda Katz: Ownership is the right to destroy
Note
|
-
Mit Hilfe von Referenzen kann der Besitzt ausgeliehen werden
-
Der Besitz geht automatisch wieder zurück, wenn die Referenz nicht mehr existiert
let mut x = vec!("Hello CCCAC!");
{
let z = &mut x;
// Do something with z...
}
println!("{}", x[0]);
Note
|
Ohne Klammern:
error[E0502]: cannot borrow |
-
-
War mein Startpunkt
-
#![no_std]
use alloc::rc::Rc;
use core::cell::RefCell;
pub struct DoublyLinkedList<T> {
}
-
Erste Schritt: Abhänigkeiten vom OS entfernen
-
Keine Verwendung der Standardlaufzeitumgebung möglich
-
-
Aber die Core Runtime ist verwendbar
-
Cross-Compilierung für das neue OS nötig
-
Verwendung von Xargo um die Kern-Laufzeitumgebung zu bauen
-
Cargo ähnliche Cross-Compilierung
-
$> cat Xargo.toml
[target.x86_64-hermit.dependencies]
alloc = {}
$> xargo build --target x86_64-hermit
{
"llvm-target": "x86_64-unknown-none",
"linker-flavor": "gcc",
"target-endian": "little",
"target-pointer-width": "64",
"target-c-int-width" : "32",
"os": "none",
"arch": "x86_64",
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
"pre-link-args": [ "-m64" ],
"cpu": "x86-64",
"features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float",
"disable-redzone": true,
"eliminate-frame-pointer": true,
"linker-is-gnu": true,
"no-compiler-rt": true,
"archive-format": "gnu",
"code-model": "kernel",
"relocation-model": "static",
"panic-strategy": "abort"
}
println!("HermitCore is running on uhyve!");
-
Rust definiert für die Ein-/Ausgabe Macros
-
Neudefinition erforderlich
-
macro_rules! print {
($($arg:tt)+) => ({
use core::fmt::Write;
#[allow(unused_unsafe)]
unsafe { $crate::console::CONSOLE.write_fmt(format_args!($($arg)+)).unwrap(); }
});
}
/// Print formatted text to our console, followed by a newline.
macro_rules! println {
($($arg:tt)+) => (print!("{}\n", format_args!($($arg)+)));
}
pub struct Console;
/// A collection of methods that are required to format
/// a message to HermitCore's console.
impl fmt::Write for Console {
/// Print a single character.
fn write_char(&mut self, c: char) -> fmt::Result {
COM1.write_byte(c as u8);
Ok(())
}
/// Print a string of characters.
fn write_str(&mut self, s: &str) -> fmt::Result {
...
}
}
pub static mut CONSOLE: Console = Console;
#![feature(allocator_api)] #[global_allocator] static ALLOCATOR: &'static allocator::HermitAllocator = &allocator::HermitAllocator;
-
Registrierung einer eigenen Speicherverwaltung
-
Anschließend läuft alles transparent
-
Verwendung von dynamischen Datenstrukturen über die Core-Runtime möglich