• Navigation überspringen
  • Zur Navigation
  • Zum Seitenende
Organisationsmenü öffnen Organisationsmenü schließen
Friedrich-Alexander-Universität Lehrstuhl für Informatik 4 (Systemsoftware)
  • FAUZur zentralen FAU Website
  1. Friedrich-Alexander-Universität
  2. Technische Fakultät
  3. Department Informatik
Suche öffnen
  • English
  • Campo
  • StudOn
  • FAUdir
  • Stellenangebote
  • Lageplan
  • Hilfe im Notfall
  1. Friedrich-Alexander-Universität
  2. Technische Fakultät
  3. Department Informatik
Friedrich-Alexander-Universität Lehrstuhl für Informatik 4 (Systemsoftware)
Menu Menu schließen
  • Lehrstuhl
    • Team
    • Aktuelles
    • Kontakt und Anfahrt
    • Leitbild
    • 50-jähriges Jubiläum
    Portal Lehrstuhl
  • Forschung
    • Forschungsbereiche
      • Betriebssysteme
      • Confidential Computing
      • Embedded Systems Software
      • Verteilte Systeme
    • Projekte
      • AIMBOS
      • BALu
      • BFT2Chain
      • DOSS
      • Mirador
      • NEON
      • PAVE
      • ResPECT
      • Watwa
    • Projektkampagnen
      • maRE
    • Seminar
      • Systemsoftware
    Portal Forschung
  • Publikationen
  • Lehre
    • Sommersemester 2025
      • Applied Software Architecture
      • Ausgewählte Kapitel der Systemsoftware
      • Betriebssystemtechnik
      • Projekt angewandte Systemsoftwaretechnik
      • System-Level Programming
      • Systemnahe Programmierung in C
      • Systemprogrammierung 1
      • Verteilte Systeme
    • Wintersemester 2024/25
      • Betriebssysteme
      • Middleware – Cloud Computing
      • Systemprogrammierung 2
      • Verlässliche Echtzeitsysteme
      • Virtuelle Maschinen
      • Web-basierte Systeme
    Portal Lehre
  • Examensarbeiten
  1. Startseite
  2. Extern

Extern

Bereichsnavigation: Lehre
  • Betriebssystemtechnik
    • Vorlesung
      • Folien
      • Glossar
    • Übung
      • Aufgaben
      • Dokumentation
        • Blog
          • Entwicklungsumgebung
            • Assembler Crashkurs
              • C++ Crashkurs
                • 🔗 Testrechnerverwaltung
                • 🔗 Adora-Belle (Helpdesk)
                • Kontakt
              • Evaluation

              Blog

              Implementierungshinweise zum PID Lookup

              Bernhard Heinloth

              2022-07-07

              PID-Thread Lookup

              Für IPC muss irgendwie die PID zum Prozess (Thread-Pointer) aufgelöst werden. Es ist in unserem Fall vollkommen in Ordnung, da einfach eine Liste zu verwenden und die durchzulaufen.

              Aber Achtung:

              • die ready-Queue des Schedulers ist nicht ausreichend – denn nicht jeder Thread ist da drin, sondern könnte ja gerade in einem Waitingroom sein (sogar ziemlich wahrscheinlich, wenn ihr euch die IPC-Implementierung anschaut)

              • ein Queue<Thread> processlist könnt ihr nicht verwenden – denn Thread erbt von Queue::Node, was lediglich einen next-Zeiger als Attribut anfügt. Und dieser eine Zeiger würde dann gleichzeitig von der ready-Queue UND der processlist-Queue verwendet werden, was natürlich zu Fehlern führt.

                Siehe dazu auch die Warnung in der Dokumentation:

                One instance of a class inheriting from Queue::Node can be at most in one Queue

              • kommt besser nicht auf die Idee, die PID gleich der Threadadresse zu setzen (und wild zu casten). Da kann viel schief gehen, u.a. nicht vertrauenswürdige Zeiger aus dem Userspace und sehr schnelle erneute PID Belegung (bei delete und new)!

              • man kann vector verwenden, aber schaut euch dazu die Implementierung an, sie ist momentan etwas von der STL inspiriert und sehr stark vereinfacht (z.B. bzgl Iteratoren). Je nachdem wie ihr das verwenden wollt müsst ihr vielleicht die Methoden anpassen – z.B. um beliebige pos auch jenseits der aktuellen Kapazität (_capacity) einfügen zu können, empfiehlt sich eine Erweiterung um

                 inline void insert(size_t pos, const T& value) {
                  if (pos == _capacity) {
                      expand();
                  } else if (pos > _capacity) {
                      // Reserve capacity is the next power of 2
                      size_t r = pos;
                      for (size_t p = 1; p < sizeof(uintptr_t) * 8; p *= 2) {
                          r |= r >> p;
                      }
                      reserve(r + 1);
                  }
                  // ...

                (man könnte alternativ auch schlicht reserve(pos + 1) machen, was aber zu vielen Speicherkopien bei subsequenten inserts führen kann – deshalb wird im Beispiel immer die nächste Zweierpotenz verwendet)

              Map Systemaufruf (Nachtrag)

              In der Aufgabenstellung wird der map-Systemaufruf zusammen mit dem Allokator für den Userspace als Beispiel gezeigt. Der Allokator verwendet intern (versteckt hinter einer Templatevariable) beim ersten Aufruf map(nullptr, ...), lässt sich also vom Kernel eine Adresse geben. Und fordert bei Bedarf dann weiteren Speicher an – braucht aber unbedingt einen zusammenhängenden Speicherbereich (und verwendet deshalb in den folgenden map-Aufrufen auch explizite Adressen).

              Das bedeutet unter Umständen, dass ihr, wenn ihr den Allokator so wie in der Vorgabe verwendet, aber auch noch zusätzlich in eurer Anwendung map(nullptr, ...) aufrufen wollt, der Allokator keinen weiteren Speicher mehr rausgeben wird.

              Mögliche Workarounds:

              • entweder einfach map mit expliziten Zieladressen (jenseits von 0x5000000 [Userspace + App + Allokator]) in eurer Anwendung aufrufen

              • oder alloc_buddy.h im Userspace (jedoch nicht im Kernel) patchen, zum Beispiel den Code in Zeile 355

                if ((base_ptr = reinterpret_cast<uintptr_t>(RESERVE(nullptr, size))) == NULL) {
                  return NULL;
                }

                zu etwas wie

                if ((base_ptr = reinterpret_cast<uintptr_t>(RESERVE(reinterpret_cast<void*>(0x1000000000), size))) == NULL) {
                  return NULL;
                }

                zu ändern, um den Heap ab 0x1000000000 starten zu lassen.

              • oder beim Aufruf mit Parameter nullptr schlicht ganz zufällige (noch unbelegte) Adressen rauszugeben. Grundlegende Idee:

                void* map(void* addr, size_t size) {
                  if (addr == nullptr) {
                      static uintptr_t nextPtr = 88172645463325252ull;  // TODO: Eigener Wert
                      do {
                          nextPtr ^= nextPtr << 13;
                          nextPtr ^= nextPtr >> 7;
                          nextPtr ^= nextPtr << 17;
                          addr = reinterpret_cast<void*>(nextPtr);
                      } while (addr < USER_SPACE || mapping->in_use(addr, size));
                  }
                  // ...
                }

              Zurück zur Übersicht

              Friedrich-Alexander-Universität
              Erlangen-Nürnberg

              Schlossplatz 4
              91054 Erlangen
              • Impressum
              • Datenschutz
              • Barrierefreiheit
              • Facebook
              • RSS Feed
              • Xing
              Nach oben