Skip to content

Latest commit

 

History

History
executable file
·
430 lines (331 loc) · 8.75 KB

slides.adoc

File metadata and controls

executable file
·
430 lines (331 loc) · 8.75 KB

The day after C

Persönlicher Hintergrund

  • 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

    • github.com/stlankes

Im Wandel der Zeit

  • 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

Never change a running system

  • Das OS Design hat sich nicht grundlegenden geändert

  • C dominiert weiterhin

  • Der Entwicklungsprozess eines OS entfernt sich von einer Anwendung

Wie sieht eine ideale Sprache für die OS-Entwicklung aus?

Vor-/Nachteile von C

  • C ist aus der UNIX-Entwicklung entstanden

    • Passt zur OS Entwicklung

  • Hoher Freiheitsgrad, kein Overhead

  • Fehler anfällig

  • Keine Laufzeitumgebung direkt im Kernel nutzbar

Wünsche an einer OS-Sprache

  • 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

Wiederverwendung von Rust-Code

$> cat Cargo.toml
[dependencies.raw-cpuid]
version = "3.1.0"
features = ["nightly"]

[dependencies.x86]
path = "../crates/x86"
default-features = false
extern crate raw_cpuid;
extern crate spin;
extern crate x86;

Was ist Rust?

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:

  • Wer kennt Rust?

  • Wer hat schonmal Code in Rust geschrieben?

  • Wessen Code hat auch compiliert? C-Ähnliche Syntax Nicht nur Einsatz in Firefox:

  • game engines

  • operating systems

  • file systems

Woher kommt Rust?

rust
  • 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

Vorteile von Rust

  • 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

Safety vs Speed

Note

Die Sicht auf sich selbst. Allgemein natürlich schwierig.

Einfache Integration von C

#[repr(C)]
struct RustObject {
    number: c_int
}

#[link(name = "libprinto")]
extern {
    fn c_print_object(object: *mut RustObject) -> c_int;
}

fn main() {
    let mut rust_object = /* TODO */;

    unsafe { c_print_object(&mut *rust_object); }
}
Note

Ownership & Borrowing

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
  • wechsel zu Stefan

  • z wird am Ende vom Scope zerstört

  • In der Realität verteilt über viele Files

  • Ist dieses C++-Beispiel problematisch?

Erlaubt Rust solche Referenzen?

let x;

{
	let z = vec!("Hello CCCAC!");

	x = &z;
}

println!("{}", x[0]);
Note

Was sagt der Compiler?

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

Ownership

  • 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

Borrowing

  • Mit Hilfe von Referenzen kann der Besitzt ausgeliehen werden

  • Der Besitz geht automatisch wieder zurück, wenn die Referenz nicht mehr existiert

Sind die geschweiften Klammern nötig?
let mut x = vec!("Hello CCCAC!");

{
	let z = &mut x;
	// Do something with z...
}

println!("{}", x[0]);
Note

Ohne Klammern: error[E0502]: cannot borrow v as immutable because it is also borrowed as mutable -→ src/main.rs:94:20 | 90 | let x = &mut v; | - mutable borrow occurs here …​ 94 | println!("{}", v[0]); | ^ immutable borrow occurs here

Ein OS mit Rust entwickeln

Existierende Projekte

Laufzeitumgebung

#![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

Kern-Laufzeitumgebung

  • 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

Target definieren

{
    "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"
}

Ein-/Ausgaben

println!("HermitCore is running on uhyve!");
  • Rust definiert für die Ein-/Ausgabe Macros

    • Neudefinition erforderlich

Ein-/Ausgabe

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)+)));
}

Console

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;

Speicherverwaltung

#![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

Zusammenfassung

  • Rust lässt sich einfach für die OS-Entwicklung verwenden

    • Nicht alle Features konnte beschrieben werden

    • Benötigt ein nightly Compiler

  • Ownership / Borrowing ist für einen old school Entwickler gewönnungsbedürftig

  • Performance?

Note