Autor Thema: IPC - Popup-Threads  (Gelesen 23396 mal)

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« am: 23. November 2011, 16:29 »
Ich will ja die Idee von erik benutzen, wo der IPC-Handler in einem eigenen Thread läuft. Dieser Thread wird auch wirklich erst erstellt wenn eine Nachricht vorhanden ist/empfangen wird.

Dabei ist halt ein Problem bei meinem Kernel-Design aufgetreten. Dort ist es nicht möglich auf den VMM eines anderen Prozesses zu zugreifen, was ja nötig wäre um einen Stack für den Thread erstellen zu können.

Der Grund warum das nicht möglich ist, ist folgender. Auch der VMM braucht ja Speicher um die freien Bereiche verwalten zu können. Allerdings kann er ja schlecht die normalen malloc()/free() Funktionen nutzen, weil die wiederrum auf den VMM aufbauen.
Deswegen habe ich im KernelSpace einen Prozess-lokalen Bereich (der ist immer an der gleichen virtuellen Adresse) wo nur ein "kleiner" Speicher-Manager läuft und auch genau auf den VMM zugeschnitten ist.
Es ist halt einfacher wenn ich nur einen festen Bereich verwalten muss, als wenn ich das ganze von der Größe her dynamisch machen müsste.

Ich habe auch schon eine Idee für eine Lösung.

Wenn ein Client eine RPC-Anfrage macht, muss er in den Kernel. Dort wird dann der fixed-size Anteil der Message in einen Kernel-Buffer kopiert (sind im Mom 32bytes, die man als Metadaten nutzen könnte).
Es wird dann geguckt ob ein neuer Thread beim Empfänger erstellt werden darf (man kann bei der Erstellung der Ports festlegen wieviele Threads max gestartet werden dürfen), ist das der Fall so wird einfach in das PD des Empfängers gewechselt, ein neuer Thread erstellt und dieser wird gleich gestartet ohne das der Scheduler davon wissen muss.

Ist der Handler fertig (die Funktion macht also nen "ret" was wiederrum bewirkt das zurück in den Kernel gesprungen wird) wird überprüft ob eine weitere Nachricht vorliegt oder ob der Thread beendet werden kann.
Liegt eine weitere Nachricht vor, wird diese bearbeitet und der Sender-Thread wird in die Ready-Queue des Schedulers gepackt. Kann der Thread beendet werden, wird danach gleich in das PD des Senders gewechselt und der Sender Thread wird laufen gelassen.

Wird nur eine Nachricht versendet ohne das gewartet werden soll (oder es keine Antwort gibt), so muss trotzdem in das PD des Empfängers gewechselt werden und es wird ein neuer Thread erstellt. Dieser wird dann in die Ready-Queue des Schedulers gepackt und es wird wieder zurück in das PD des Senders gewechselt.

Falls jemand eine gute Idee hat, wie ich das Wechseln der PDs vermeiden kann, also im Endeffekt wie ich den Speicher für den VMM verwalten kann, dann immer her damit.

Fallen euch daran irgendwelche groben Fehler auf oder habt ihr eine bessere Idee (die Popup-Threads bleiben ;))?

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 23. November 2011, 16:42 »
Deine Speicherverwaltung ist komisch.

Warum kann sich der VMM nicht einfach den Speicher nehmen, den er selber braucht? Wie man physischen Speicher holt, dürfte er wissen, und wie man ihn mappt auch.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 23. November 2011, 16:47 »
Ich würde den Stack erst erstellen, wenn der Scheduler zum Thread wechselt. Zum Beispiel durch einen Stub, der vor dem Sprung in den User-Space ausgeführt wird.

Ansonsten der übliche Trick: Wenn du das Page Directory des anderen Prozesses in das Page Directory des aktuellen Prozesses als Page Table einträgst, kannst du darauf als 4 MB kontinuierlichen Speicher zugreifen.
Dieser Text wird unter jedem Beitrag angezeigt.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 23. November 2011, 16:59 »
Zitat von: taljeth
Warum kann sich der VMM nicht einfach den Speicher nehmen, den er selber braucht? Wie man physischen Speicher holt, dürfte er wissen, und wie man ihn mappt auch.
Und wo soll er den hinmappen? Ich hatte es vor langer Zeit auch mal so, dass der VMM ganz normal seine Objekte alloziert hat, aber das führt zu so vielen Problemen und Code der manchmal funktioniert und manchmal nicht.

Es geht doch bei einem VMM darum, das er weiß welche Bereiche im virtuellem Speicher frei sind und welche nicht und dafür braucht er Speicher. Mein VMM besteht im wesentlichen aus 2 AVL-Bäumen, einen der die Bereiche nach der Größe sortiert und einer der die Bereiche nach der Start-Adresse sortiert.

Allerdings kommt mir gerade eine Idee (wo ich mich wieder frage wieso ich die nicht schon eher hatte) und zwar reicht es ja, wenn der Kernel-VMM so gebaut ist. Der User-VMM kann dann die allgemeinen Speicherfunktionen nutzen.
Das würde sogar sehr einfach umzusetzen sein, würde aber zu einem anderen Problem führen (was nicht unbedingt auftreten muss, aber kann). Jetzt ist es so, dass wenn ein Prozess beendet wird, wird auch der gesamte Speicher, den der VMM gebraucht hat, freigegeben. Bei der obigen Variante kann es (und wird es bestimmt auch) aber passieren, das die Objekte so dämlich über viele Objekt-Caches (SlabAllocator) verteilt sind, das man nacher eine Aufteilung, das jeder Objekt-Cache im worst-case genau ein Objekt hat, welches noch in Benutzung ist und es deswegen zu einer tierischen Speicherverschwendung kommt (pro Objekt in dem Fall etwas über 4000bytes, macht bei einem Prozess mit 1024 freien Bereichen schonmal 4MB verschwendet).

Ist halt die Frage, was ist wichtiger Speicherverbrauch oder Performanceeinbußen wegen dem Wechseln des PDs.

Zitat von: jidder
Ich würde den Stack erst erstellen, wenn der Scheduler zum Thread wechselt. Zum Beispiel durch einen Stub, der vor dem Sprung in den User-Space ausgeführt wird.
Finde ich ne ganz schlechte Idee, weil erst dann festgestellt werden kann ob genügend Speicher für den Stack vorhanden ist oder nicht und Fehler, vorallem solche, will ich im Scheduler gar nicht haben.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 23. November 2011, 17:14 »
Und wo soll er den hinmappen? Ich hatte es vor langer Zeit auch mal so, dass der VMM ganz normal seine Objekte alloziert hat, aber das führt zu so vielen Problemen und Code der manchmal funktioniert und manchmal nicht.
Ich dachte, im eigenen Prozess (und vor allem im Kernelspeicher, der ja in allen Prozessen der gleiche ist) kann der VMM allozieren und das Problem ist nur mit anderen Prozessen? Seinen Verwaltungskram braucht der VMM ja nicht im Userspeicher anderer Prozesse, sondern im sowieso aktiven Kontext.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 23. November 2011, 17:17 »
Finde ich ne ganz schlechte Idee, weil erst dann festgestellt werden kann ob genügend Speicher für den Stack vorhanden ist oder nicht und Fehler, vorallem solche, will ich im Scheduler gar nicht haben.

Achso jetzt verstehe ich. Es geht eigentlich gar nicht um das Page Directory, sondern darum, dass du auf den virtuellen Adressraum des anderen Prozesses zugreifen willst.

Da du vor nichts zurückschreckst, will ich dann mal noch eine abenteuerliche Lösung vorschlagen. Du könntest ausnutzen, dass dein VMM für jeden Prozess in einem begrenzten Bereich liegt. Dann kannst du einfach die dazugehörigen Einträge im PD des Sender mit den Werten aus dem PD des Empfängers überschreiben, den Speicher normal reservieren, und anschließend die alten Werte wiederherstellen. Mit etwas Glück gibt es nicht mal unnötige TLB-Misses, falls das die einzigen Zugriffe auf den VMM sind.
Dieser Text wird unter jedem Beitrag angezeigt.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 23. November 2011, 17:31 »
Zitat von: taljeth
Ich dachte, im eigenen Prozess (und vor allem im Kernelspeicher, der ja in allen Prozessen der gleiche ist) kann der VMM allozieren und das Problem ist nur mit anderen Prozessen?
Jap, es geht darum, das ich aus einem Prozess heraus nicht auf den VMM eines anderes Prozesses zugreifen kann. Der Kernel hat aber auch nen VMM der irgendwo her seinen Speicher bekommen muss und der ist auch in alle Prozesse gemappt.

Zitat von: jidder
Achso jetzt verstehe ich. Es geht eigentlich gar nicht um das Page Directory, sondern darum, dass du auf den virtuellen Adressraum des anderen Prozesses zugreifen willst.
Auch darum geht es nicht ganz ;) Ich müsste auf den VMM eines anderen Prozesses zugreifen und der VMM für jeden Prozess holt sich den Speicher für seine Objekte immer aus dem selben virtuellen Bereich.

Zitat von: jidder
Du könntest ausnutzen, dass dein VMM für jeden Prozess in einem begrenzten Bereich liegt. Dann kannst du einfach die dazugehörigen Einträge im PD des Sender mit den Werten aus dem PD des Empfängers überschreiben, den Speicher normal reservieren, und anschließend die alten Werte wiederherstellen. Mit etwas Glück gibt es nicht mal unnötige TLB-Misses, falls das die einzigen Zugriffe auf den VMM sind.
Ansich gar keine schlechte Idee, aber ... ;)

Was machst du bei Multithreading? Thread A mappt also den VMM raus und den von einem anderen Prozess rein und Thread B will jetzt, auf einer anderen CPU, gleichzeitig Speicher anfordern!

Also mein VMM besteht aus 2 AVL-Bäumen, dort werden Nodes gespeichert (erster Objekttyp) und dann gibt es die Bereiche (zweiter Objekttyp). Für diese beiden Objekttypen muss ich ja irgendwo her Speicher bekommen.
Wenn der VMM also nen neuen freien Bereich eintragen will, muss er eventuell zwei neue Nodes und einen neuen Bereich allozieren. Wenn er dabei ganz normal ein malloc() aufrufen würde, würde das malloc() feststellen das es neuen Speicher braucht und den VMM aufrufen ...

Ich hoffe das Problem ist klar.

Ich habe das ganze so gelöst das ich einen festen virtuellen Bereich habe wo ein "einfacher" Allocator Speicher für diese beiden Objekttypen herholt (er braucht keinen dynamischen Speicher dafür, weil die Größe und Position des Bereichs ja statisch schon zur Compilezeit bekannt ist). Das ganze habe ich einmal für den Kernel-VMM (und dieser Bereich ist in jedem Adressraum der gleiche) und einmal für den User-VMM (dieser Bereich ist in jedem Adressraum mit anderen Daten/Pages gemappt).

Ich kann also für einen Prozess der gerade die CPU hat, ganz einfach Speicher über den VMM allozieren, aber wenn ich aus einem Prozess A heraus Speicher in einem Prozess B allozieren will, muss ich auf dessen VMM zugreifen. Das bringt Probleme, weil der VMM von Prozess B Objekte benutzt die an der selben Adresse liegen wie Objekte vom Prozess A. Dadurch kann ich den VMM des Prozesses B auch nicht einfach in Prozess A mappen (zumal das eh Probleme bei vielen CPUs gibt, da irgendwann auch der virtuelle Speicher ausgeht).

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 23. November 2011, 17:40 »
Hallo,


@FlashBurn: was genau versuchst Du mit Deiner komplizierten VMM-Architektur eigentlich zu erreichen? Der Vorteil den Du momentan hast ist wohl der das Deine beiden Bäume immer an der selben virtuellen Adresse anfangen können (da sie ja im privaten Adressraum der entsprechenden Prozesse liegen, auch wenn dieser Bereich nicht mit Ring 3 ansprechbar ist) wohingegen wenn alle Bäume ganz normal im Kernel-Kontext liegen hat jeder Prozess individuelle virtuelle Baum-Adressen. Zwei zusätzliche Pointer in der Prozess-Descriptor-Struktur machen aber IMHO keine ernsten Probleme so das ich trotz allem dafür bin das die Prozess-spezifischen VMM-Daten im normalen Kernel-Speicher liegen und der VMM eben immer als zusätzliches Parameter den Pointer für den gewünschten Prozess bekommt damit der VMM auch immer für den richtigen Prozess arbeitet. Der VMM benötigt dann für sich selber (neben dem PMM für den eigentlichen Speicher der in den Prozess gemappt werden soll) wieder den Allocator des Kernels (der nur für den Kernel-Speicher zuständig ist und welcher für sich ebenfalls den PMM benötigt).

Da diese IPC-Idee ursprünglich für meine segmentierte Speicherverwaltung erdacht wurde, in der der Kernel immer alles sieht (es gibt ja auch nur maximal ein PD), hab ich damit bis jetzt kein Problem gesehen wenn der Kernel für einen beliebigen Prozess Threads in einem anderen beliebigen Prozess erstellt. Ich bin auch der Meinung das selbst bei Flat-Memory keine grundsätzlichen Probleme im Weg stehen.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 23. November 2011, 18:00 »
Zitat von: erik
was genau versuchst Du mit Deiner komplizierten VMM-Architektur eigentlich zu erreichen?
Ich habe doch das Problem beschrieben das der Kernel-VMM auch Speicher für seine eigenen Objekte braucht und normalerweise malloc() dafür aufrufen würde. Malloc() wiederrum ruft dann den Kernel-VMM zwecks neuem Speicher auf. Das kann nicht funktionieren und man muss also nen "einfachen" Speichermanager zumindest für die Objekte des VMM haben.

Ich nutze halt den selben Code für den Kernel- und die User-VMMs.

Ich könnte, wie oben schon geschrieben, auch einfach nur den Kernel-VMM diesen "einfachen" Speichermanager nutzen lassen und die User-VMMs nutzen dann ganz normal Kernel-Speicher. Das wiederrum hätte aber einen Nachteil was den eventuellen Speicheroverhead betrifft, wäre aber performanter.

Nur bin ich mir halt nicht sicher, ob der Performanceunterschied wirklich relevant ist. Denn die einzige Situation (die mir im Moment einfällt), wo ich auf den VMM eines anderen Prozesses zugreifen muss, ist IPC.
Wenn ich jetzt davon ausgehe, dass nur beim RPC auch auf den VMM eines anderen Prozesses zugegriffen werden muss (und das nur beim Senden, für die Antwort ja nicht) und ich dann auch gleich in dem anderen Prozess bleibe, habe ich eigentlichen keinen Performance-Vor- oder -Nachteil.

Ausnahme wäre da jetzt nur asynchrones-IPC, aber da fallen mir im Moment auch nur Notify-Nachrichten ein und dafür würden meine fixed-size-Nachrichten eigentlich ausreichen und da würde dann also auch nicht auf den VMM eines anderen Prozesses zugegriffen.

Meine Frage wäre dann, wie löst ihr das, dass der Kernel-VMM ja auch irgendwo Speicher herbekommen muss?

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 23. November 2011, 20:09 »
Hallo,


@FlashBurn: ich schätze Du hast ein paar ungünstige Abhängigkeiten in den Schichten Deiner Speicherverwaltung drin.

Für ein Flat-Memory-System würde ich das etwa so konstruieren:

User-Mode-Library (libc) bietet malloc()/free() für beliebig große Speicherblöcke für den User-Mode-Code und benutzt dazu den virtuellen Adressraum das Prozess
wenn da neue Pages her müssen oder welche frei gegeben werden können dann wird der Prozess-spezifische VMM im Kernel per Syscall aufgerufen
    |
   V
der Prozess-spezifische VMM wird vom User-Mode oder von verschiedenen Kernel-internen Funktionen aufgerufen wenn in den virtuellen Adressraum eines Prozess (also das was pro Prozess individuell ist) etwas gemacht werden soll
er holt sich die eigentlichen Speicherseiten direkt beim PMM und seine Verwaltungsstrukturen beim Kernel-VMM
    |
   V
der Kernel-VMM bietet quasi das malloc()/free() für alles innerhalb des Kernels (bei einem Micro-Kernel wo nur wenige Objekt-Größen erforderlich sind kann das direkt von einem optimierten SLAB-Allocator erledigt werden und bei einem Monolithen wird man wohl eher was generisches benötigen das der libc-Variante im User-Mode recht ähnlich ist) und ist nur für den virtuellen Adressraum des Kernel zuständig (also den Teil des virtuellen Adressraum der in allen PDs identisch ist, ein vom Kernel-VMM gelieferter Pointer ist demzufolge in allen Kontexten gültig)
der Kernel-VMM greift für alles was er braucht auf den PMM zurück
    |
   V
der PMM ist die unterste Stufe und sollte im Idealfall keine Abhängigkeiten zu was anderem haben dafür kann er nur ganze Pages verwalten
theoretisch könnte der PMM für seine Verwaltungsstrukturen wieder auf den Kernel-VMM zurückgreifen aber das ist dann eine Kreisabhängigkeit die man nicht so ohne weiteres problemfrei bekommt und sollte fürs erste vermieden werden

Ich hoffe das hilft etwas und ist nicht zu arg falsch.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 23. November 2011, 20:27 »
@erik

Das ist mir auch alles klar und sieht auch so ähnlich bei mir aus. Ich habe nur noch eine Schicht zw. SlabAllocator und PMM, nämlich den VMM.

Auch dein Bsp. sagt mir nicht woher der SlabAllocator weiß welche virtuellen Adressen frei und welche belegt sind. Das muss du doch irgendwie verwalten und dafür brauchst du Speicher.

Der SlabAllocator funktioniert doch so, das er guckt ob er einen komplett freien ObjectCache oder einen ObjectCache mit mind. einem freien Objekt hat. Ist das nicht der Fall fragt er den VMM nach sovielen Pages wie man pro ObjectCache für den entsprechenden Objekttypen braucht.
Der VMM benutzt nun praktisch den SlabAllocator für die Objekte die er zur Verwaltung des virtuellen Speichers braucht. Da haben wir dann wieder diese Abhängigkeit die sich nicht so einfach auflösen lässt. Dafür brauchst du einen Allocator der keinen dynamischen Speicher braucht bzw. diesen irgendwo herbekommt ohne einen anderen Speichermanager aufzurufen.

Um es kurz zu machen, woher weiß, in deinem Bsp., der SlabAllocator wo noch freie Bereiche im Adressraum des Kernels sind? Das steht in einer Datenstruktur und wo kommt der Speicher (der ja auch dynamisch verwaltet werden soll) für diesen Speicher her?

Ich möchte meinen aus diesem Grund nutzt man unter Linux nen BuddyAllocator und hat das Prinzip des HighMem. Man nutzt also im Kernel ein 1:1 Mapping der physischen und virtuellen Adressen. Das ist aber mMn totaler Müll, ist zwar einfach aber du bekommst dadurch Probleme wo ich ehrlich gesagt nur drüber lachen kann ;) Aber du kannst dir den VMM für den Kernel sparen.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 23. November 2011, 21:23 »
Hallo,


die libc holt sich den Speicher für die eigenen Verwaltungsstrukturen natürlich auch vom Prozess-spezifischen VMM aus dem Kernel, diese Verwaltungsstrukturen beschreiben nicht nur den virtuellen Adressraum (des Prozesses) aus Sicht der libc sondern auch sich selber. Genauso machen das auch die beiden VMMs im Kernel, die Verwaltungsstrukturen beschrieben nicht nur den Speicher der eigentlich verwaltet werden soll sondern auch immer sich selber. Die SLAB-Blöcke enthalten im jeweiligen Header immer Pointer auf andere SLAB-Blöcke (so das daraus eine Liste aus SLAB-Blöcken entsteht, diese Liste könnte z.B. nach der Anzahl der verfügbaren/freien Objekte im entsprechenden Block sortiert sein). Der SLAB-Allocator muss auch nicht wissen wo noch freie virtuelle Pages vorhanden sind, wenn er ein neues Objekt liefern soll aber in seiner SLAB-Block-Liste keines mehr zu finden ist dann fordert er einfach eine/mehrere neue Seite(n) (dazu muss er natürlich in dem selber verwalteten virtuellen Adressraum ein freies Plätzchen suchen) vom PMM an und baut daraus einen neuen SLAB-Block für die gewünschte Objekt-Größe und bindet diesen neuen Block in die entsprechende Liste mit ein. Die einzigste Speicherverwaltung die wirklich nicht auf anderes angewiesen sein sollte ist der PMM und da die Menge des physischen Speichers ja zur Kernel-Lade-Zeit bekannt ist (und sich auch nur selten zur Laufzeit ändert, zumindest ist das noch kein Aspekt für die erste OS-Version) kann hier auch mit einer statischen Methode (z.B. simple Bit-Map) gearbeitet werden.

@FlashBurn: Ich kann ehrlich gesagt nicht erkennen wo Du genau das Problem siehst. Vielleicht sollte ich wirklich mal ein Flat-Memory-OS bauen um zu verstehen wo da noch versteckte Probleme sein könnten. ;)
So ähnlich wie ich das vorhin skizziert habe möchte ich das auch für meine segmentierte Speicherverwaltung bauen, nur eben mit der Kreisabhängigkeit zwischen PMM und Kernel-VMM.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 23. November 2011, 21:36 »
Zitat von: erik
Der SLAB-Allocator muss auch nicht wissen wo noch freie virtuelle Pages vorhanden sind, wenn er ein neues Objekt liefern soll aber in seiner SLAB-Block-Liste keines mehr zu finden ist dann fordert er einfach eine/mehrere neue Seite(n) (dazu muss er natürlich in dem selber verwalteten virtuellen Adressraum ein freies Plätzchen suchen) vom PMM an und baut daraus einen neuen SLAB-Block für die gewünschte Objekt-Größe und bindet diesen neuen Block in die entsprechende Liste mit ein.
Wenn der SlabAllocator nicht weiß wo nach freie virtuelle Pages/Adressen sind, woher weiß er dann wo er die physischen Pages hinmappen soll?

Also ich holle mir ne Page vom PMM (Pmm::alloc4kb()) und dann muss ich diese mappen (Vmm::map(virt,phys,count,flags)), aber woher weiß ich wo noch ne freie virtuelle Adresse ist?

Du sprichst von einem selber verwalteten virtuellem Adressraum. Wie willst du den verwalten? Ich mache das, wie schon öfter geschrieben, mit 2 AVL Bäumen und für die Nodes und die eigentlichen Objekte die die Bereiche beschreiben, brauche ich Speicher und auch der wird ja dynamisch verwaltet.

Einfach mal als Bsp., folgende Adressen sind noch frei 0xC4000000 bis 0xC5000000 und 0xD0000000 bis 0xE0000000. Woher weißt du das die noch frei sind und wo speicherst du diese Information?

Ich weiß das du die Infos direkt in deinen Segmenten speichern kannst und daraus ne Liste machen kannst, das geht hier aber nicht. Vorallem weil ich kein 1:1 Mapping will und weil der KernelSpace "nur" 1GB groß ist und damit kann ich nicht einfach auf die vollen 4GB zugreifen.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 24. November 2011, 15:44 »
Hallo,


schau Dir mal an wie verschiedene libc-Implementierungen das lösen. Das malloc()/free() kann ja auch nicht für jede Page den Kernel fragen ob es die benutzen kann oder nicht. Dort werden ein paar statische Variablen (Pointer und Größenangaben) benötigt die quasi den Einstiegspunkt die die Heap-Verwaltung ermöglichen und alles andere ist weitgehendst dynamisch. Mit den statischen Variablen wird z.B. beschrieben in welchem Teil des linearen Adressraums der Heap liegt (falls das mehrere sein können wird es natürlich etwas komplexer) und die Pointer zeigen dann auf die Verwaltungsstrukturen die zwischen den User-Blöcken ebenfalls im Heap liegen. Diese Verwaltungsstrukturen beschreiben welche Bereiche im Heap benutzt und welche frei sind, dabei zählen die Verwaltungsstrukturen selber ebenfalls als benutzter Speicher. Das bedeutet das in dem Moment wo die Heap-Verwaltung initialisiert wird (und der erste Bereich im virtuellen Adressraum mit Hilfe des Kernels für den Heap reserviert wird) das dann ein kleiner Teil dieses ersten Bereiches sofort mit den ersten paar Elementen der Verwaltungsstrukturen belegt wird (diese ersten Verwaltungsstrukturen beschreiben sich selber und auch den noch freien Rest).
Es ist sogar möglich mehrere unabhängige Heap-Verwaltungen parallel in einem Prozess zu betreiben (es muss nur jede einen eigenen Satz an statischen Variablen haben), die kommen sich auch nie in die Quere weil ja jede Heap-Verwaltung individuelle Bereiche des virtuellen Adressraums vom Kernel bekommt. Es sieht auch keine dieser Heap-Verwaltungen den Speicher der anderen Heaps. Theoretisch können diese Heap-Verwaltungen sich sogar gegenseitig benutzen, das würde z.B. dann Sinn ergeben wenn eine Heap-Verwaltung eine andere Benutzt um mit deren Hilfe ihre eigenen Verwaltungsstrukturen zu verwalten (in dem Fall würden im ersten Heap tatsächlich nur die User-Blöcke liegen und die zugehörigen Verwaltungsstrukturen in einem anderen Heap).
Damit die Verwaltungsstrukturen zusätzlich zu den User-Blöcken auch sich selber beschreiben können müssen die eine hohe Effizienz haben (es müssen also als Anzahl weniger Verwaltungsstrukturen benötigt werden als User-Blöcke und Verwaltungsstrukturen vorhanden sind). Wenn man die Verwaltungsstrukturen immer als Header vor jeden User-Block legt ergibt sich ein 1:1-Verhältnis und wenn man die Verwaltungsstrukturen als eigenständigen Baum verwalten will ist man fast zwangsläufig auf einen SLAB-Allocator angewiesen (die Verwaltungsstrukturen beschreiben dann nur die User-Blöcke (pro User-Block eine Verwaltungsstruktur bzw. Baum-Node) und die Slab-Blöcke (pro SLAB-Block eine Verwaltungsstruktur aber jeder SLAB-Block bietet ja Platz für mehrere Verwaltungsstrukturen)).

Der Prozess-spezifische VMM im Kernel verwaltet den jeweiligen virtuellen Adressraum der Prozesse aber die dafür benötigten Verwaltungsstrukturen (Deine Baum-Nodes) holt er sich per kmalloc()/kfree() vom Kernel-VMM (so das diese nicht innerhalb des Prozess-privaten Teils des virtuellen Adressraum liegen). Wenn der Prozess-spezifische VMM vom Prozess (oder auch von innerhalb des Kernels z.B. bei einem ThreadCreate()) aufgefordert wird neuen virtuellen Speicher innerhalb des Prozesses bereit zu stellen dann sucht dieser in den zugehörigen Verwaltungsstrukturen (die ja im Kernel-Teil des virtuellen Adressraum liegen und somit aus jedem beliebigen Kontext heraus nutzbar sind) ein freies Plätzchen und modifiziert dazu diese Prozess-spezifischen Verwaltungsstrukturen (wozu er den Kernel-VMM benutzt wenn z.B. neue Nodes für den Baum benötigt werden), anschließend hold er neue Pages direkt beim PMM und trägt für diese ein passendes Mapping (die virtuelle Adresse hat der Prozess-spezifische VMM ja selber bestimmt und die physische Adresse kommt vom PMM) in das PD des betreffenden Prozesses ein (die virtuelle Adresse innerhalb des Kernel-Teils an der das PD des Ziel-Prozesses ansprechbar ist steht ja im Prozess-Descriptor, somit ist auch jedes PD aus jedem beliebigen Kontext heraus ansprechbar). Damit das sauber funktioniert muss eben für jeden Prozess ein (möglichst zusammenhängender) Teil im virtuellen Adressraum des Kernels reserviert werden (physischer Speicher wird nur in dem Umfang benötigt wie das PD eben braucht), wenn der Teil des virtuellen Adressraum für den Prozess genau 3GB beträgt dann werden pro PD 3MB+4kB benötigt, das klingt zwar erst mal viel aber wer hat schon mehr als 50 parallele Prozesse am laufen (wenn man eh kein fork() hat). Irgendwelche physischen Speicherbereiche benötigt man dazu nicht im Kernel (erst recht nicht 1:1), auch werden bei einem Micro-Kernel keine HW-Geräte-Speicher im Kernel benötigt, die müssen in den Prozess-Teil des virtuellen Speichers von den Treiber-Prozessen gemappt werden. Bei einem PC der 2GB physischen Speicher hat kann das dann mit nur einem GB Kernel-Adressraum bald eng werden aber da dürfte sich dann der Umstieg auf 64Bit lohnen und wenn Du eh nur 2GB pro Prozess gewähren möchtest hast Du ja genug Reserve im virtuellen Teil für den Kernel.

Der Kernel-VMM funktioniert wieder so ähnlich wie die Heap-Verwaltung im User-Space (ist ja auch der Kernel-Heap) und managed seine eigenen Verwaltungsstrukturen selber. Der Kernel-VMM ist für den Kernel-Teil des virtuellen Adressraum zuständig und weiß auch immer welche Teile da noch frei sind und welche bereits vergeben wurden.


Grüße
Erik (der wirklich hofft das er sich jetzt verständlich ausdrücken konnte)
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 24. November 2011, 16:18 »
Also erstmal, ab User-VMM sagen wir einfach mal, das ist kein Problem.

Meine Aufteilung ist 3/1, sprich 3GB für den Prozess und 1GB für den Kernel. Das alle PDs immer in den Kernel gemappt sind, will ich einfach nicht, finde ich unschön und unnötig.

Zitat von: erik
Das malloc()/free() kann ja auch nicht für jede Page den Kernel fragen ob es die benutzen kann oder nicht.
Da muss ich dir wiedersprechen, genau das muss es machen. Nicht malloc() bestimmt was es nutzen darf, sondern es fragt beim Kernel nach neuem Speicher. Sonst ist sowas wie ASLR gar nicht möglich. Denn woher soll malloc() wisse wie der Adressraum aussieht?
Dann kommt noch hinzu, das der Kernel den Stack für UserThreads alloziert, wie soll das gehen, wenn der Kernel nicht weiß was malloc() alles für sich beansprucht?
Selbst unter Linux wird doch sbrk() aufgerufen wenn neuer Speicher benltigt wird, das ist doch nix anderes als das Fragen welchen Speicher man nutzen darf!?

Der Kernel-VMM kann also auch nicht so funktionieren wie das User malloc(). Es ist ja schließlich auch ohne weiteres möglich ein User malloc() im Kernel zu nutzen, genau aus dem Grund, weil malloc() halt eine Funktion aufruft um sich neuen Speicher zu holen und dann kommt noch hinzu, dass malloc() für alle Größen "zuständig" ist. Damit meine ich das man malloc() nicht dafür nutzt (nutzen kann) einfach mal ein paar Pages zu allozieren, weil halt gewisse Informationen mit gespeichert werden, sprich wenn du von malloc() 4096 bytes allozierst, dann verbaucht malloc() mind. 4100bytes (4byte um die Größe des Blocks zu wissen).

Ein VMM hingegen gibt grundsätzlich nur vielfaches der Pagegröße raus und das muss auch so sein, z.B. für Shared-Memory oder halt um Pages zu mappen.

Deswegen kommst du auch nicht mit ein oder zwei statischen Pointer weg. Es gibt einen Weg, wie man sich eine "zusätzliche" Datenstruktur sparen kann und das ist indem man jedes Mal das PD (und alle PageTables) auf freie Einträge untersucht und guckt ob man einen Bereich findet der groß genug ist. Dass das aber nicht wirklich das wahre ist, sollte klar sein.

Also muss man irgendwie darüber Buch führen welche Bereiche noch frei sind. Um einfach mal den worst-case zu nehmen, eine Page benutzt, eine Page frei ... und das für den "ganzen" (weil ja in die letzten 4MB das PD gemappt ist) KernelSpace. Wo und wie willst du dir merken welche Pages frei sind und welche nicht? Immerhin sind das 130560 Bereiche und den Speicher wollte ich eigentlich nicht statisch vorreservieren. Dann kommt noch hinzu das man natürlich die Bereiche noch sortiert haben will, um schnell einen Bereich nach der Größe oder der Startadresse zu finden.

Um es ganz einfach zu machen, du sagst ja auch, dass der User-VMM seine Datenstruktur im KernelSpace speichert und dafür den Kernel-VMM nutzt. Nun unterscheide ich aber nicht wirklich zw. Kernel- und User-VMM (wieso auch?). Beide verwalten einfach einen Adressraum einer gewissen Größe und mit einer gewissen Startadresse. Problem beim Kernel-VMM ist halt nur, dass es darunter keinen VMM gibt der genutzt werden kann (Kreisabhängigkeit).

Ich hatte, wie gesagt, am Anfang mal nen VMM der einfach geguckt hat, ich brauche jetzt z.B. ne neue Node und es sind beim SlabAllocator keine mehr vorrätig, also packe ich einfach mal nen neuen ObjectCache in den SlabAllocator für die Nodes. Das ist ersten ein riesiger Hack und zweitens gab das bei mir doch einige Probleme bei vielen CPUs und halt das typische Multithreading Problem, mal funktions mal nicht.

Also habe ich das jetzt alles schön voneinander getrennt und habe für den Kernel-VMM nen "einfachen" Allocator geschrieben, der statisch nen kleinen Bereich (der groß genug ist, um auch den worst-case im Kernel bewältigen zu können) verwaltet.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 24. November 2011, 19:21 »
Hallo,


Ganz ehrlich FlashBurn, manchmal habe ich so den subjektiven Eindruck das Du mich gar nicht verstehen willst. Ich hatte doch eindeutig geschrieben das die User-Space-Heap-Verwaltung sich bei der Initialisierung den ersten Bereich virtuellen Adressraumes für den Heap beim Kernel holt. Weitere Bereiche (falls mit mehreren unabhängigen Bereichen gearbeitet wird) kommen natürlich auch vom Kernel. Außer einer wirklich kleinen Hand voll Pointer und Größenangaben benötigt die Heap-Verwaltung nichts statisches, es geht darum das die Heap-Verwaltung einen Einstieg in die Verwaltungsstrukturen hat (z.B. einen Pointer auf das Root-Element eines Baums). Ob dieser erste Bereich durch sbrk() ermittelt wird oder als neuer unabhängiger Bereich im virtuellen Adressraum des Prozess alloziert wird (z.B. mit mmap()) spielt für das Prinzip keine Rolle (ist nur ein Implementierungsdetail).


Zitat von: erik
Das malloc()/free() kann ja auch nicht für jede Page den Kernel fragen ob es die benutzen kann oder nicht.
Da muss ich dir wiedersprechen, genau das muss es machen. Nicht malloc() bestimmt was es nutzen darf, sondern es fragt beim Kernel nach neuem Speicher.
Aber nicht bei jedem Aufruf von malloc() sondern immer nur dann wenn der Platz im Heap nicht mehr reicht, dann wird auch gleich eine größere Menge an Speicher (und auch immer in ganzen Pages) beim Kernel beantragt damit dieser teure Vorgang möglichst selten ist. Dieser neue Bereich wird dann als leerer Bereich in die Verwaltungsstrukturen mit eingetragen. Falls mit sbrk() einfach nur der eine Bereich vergrößert wird dann muss das natürlich auch in den Verwaltungsstrukturen passend vermerkt werden.

Das alles gilt auch für die Heap-Verwaltung im Kernel, nur das diese sich beim PMM um neue Pages bemüht. Der Speicher der vom Kernel-Heap kommt wird auch nicht in den User-Mode weitergereicht (geht ja auch nicht weil er im Kernel-Teil des virtuellen Adressraums liegt) und hat auch (üblicherweise) kein Page-Alignment, der Kernel-Heap dient dazu um z.B. die Baum-Elemente (für beide VMMs) oder die Prozess-Descriptoren unterzubringen (also alles Dinge die der Kernel nur intern benötigt).


Das alle PDs immer in den Kernel gemappt sind, will ich einfach nicht, finde ich unschön und unnötig.
Dann hast Du aber ein grundsätzliches Problem beim Allozieren von Speicher für andere Prozesse als den aktuellen, ist natürlich Deine freie Designentscheidung, aber das macht sich bei der Idee mit den PopUp-Threads eher ungünstig (auch wenn es kein absolutes Ausschlusskriterium ist).


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 24. November 2011, 19:44 »
Zitat von: erik
Ganz ehrlich FlashBurn, manchmal habe ich so den subjektiven Eindruck das Du mich gar nicht verstehen willst.
Sorry, wenn das so rüber kommt. Aber ich hatte deine Erklärung für malloc() halt so verstanden das malloc() den gesamten virtuellen Adressraum selbst verwaltet.

Zitat von: erik
Das alles gilt auch für die Heap-Verwaltung im Kernel, nur das diese sich beim PMM um neue Pages bemüht. Der Speicher der vom Kernel-Heap kommt wird auch nicht in den User-Mode weitergereicht (geht ja auch nicht weil er im Kernel-Teil des virtuellen Adressraums liegt) und hat auch (üblicherweise) kein Page-Alignment, der Kernel-Heap dient dazu um z.B. die Baum-Elemente (für beide VMMs) oder die Prozess-Descriptoren unterzubringen (also alles Dinge die der Kernel nur intern benötigt).
Hmm, das klingt so ähnlich wie ich es vorher hatte und damit hatte ich nur Probleme und empfinde es mehr als Hack als elegant.

Nur um nochmal sicher zu gehen das wir die selbe Sprache sprechen ;) Der VMM verwaltet einfach nen Bereich, der aus einer Startadresse und einer Größe besteht und dabei geht es immer um vielfaches der Pagegröße. Er hat erstmal nix mit dem PMM zu tun.
Man macht beim VMM eine Anfrage nach einem Bereich (in meinem Fall z.B. Vmm::allocZoneKernel(numPages)). Diese Funktion geht durch den Baum und sucht einen Bereich der groß genug ist (best-fit) und wenn er ne neue Node oder nen neuen Bereich erstellen will ruft er einen Allocator auf, um Speicher für die Objekte zu bekommen.

Wie würdest du das lösen? Du redest ja immer davon das der VMM den Speicher seiner Objekte selbst verwaltet. Also würde der VMM wieder durch den Baum gehen um sich eine virtuelle Page zu holen und dorthin Speicher zu mappen, damit er den dann für das Objekt nutzen kann. Diese Page beinhaltet ja mehrere Objekte und auch das musst du ja irgendwie managen. Sprich du hättest dort einen Allocator im Allocator. Finde ich zu ungeschickt und deswegen habe ich da nen "einfachen" Allocator für geschrieben (ist ne Art SlabAllocator nur einfacher).

Mir geht es wirklich nur darum die virtuellen Adressen zu managen, da soll noch gar kein Heap dran hängen, sondern du sollst den VMM nur nach virtuellen freien Adressen fragen, nicht mehr und nicht weniger. Man könnte jetzt wirklich sagen, ich kenne die max. Speichergröße des worst-case, reserviere dafür statisch einen Speicherbereich im KernelSpace und lasse auf diesem Speicherbereich nen ganz normales malloc() arbeiten (ist ja ungefähr das was ich mache).

Mich hätte halt interessiert wie andere das Problem lösen.

Es kann natürlich sein, dass ich immernoch nicht erfasst habe was du meinst. Das einzige was mir noch einfällt ist, dass du sagst, dass ich meinem Kernel malloc() zur Initialisierung ja einfach einen großen Bereich übergeben könnte (was er dann erstmal mit seinen statischen 2 Pointer managen könnte) und dann läuft das schon und malloc() mappt sich den Speicher selbst rein.

So einfach geht das leider auch nicht. Problem an der Stelle ist einfach, das ich die Möglichkeit brauche einfach nur virtuelle Adresse zu bekommen, damit ich da ganz bestimmt Pages hinmappen kann (ohne den PMM danach zu fragen) und da kann ich dann wieder kein malloc() verwenden.

Zumal ich so den Vorteil habe, dass alles schön voneinander getrennt ist und einfach ausgetauscht werden kann.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 24. November 2011, 21:28 »
Hallo,


Sorry, wenn das so rüber kommt.
Mach Dir nichts draus, jeder hat so seine ganz speziellen Eigenheiten mit denen er mache andere manchmal glatt in den Wahnsinn treiben könnte, das muss die Welt auch mal aushalten. Deine spezielle Eigenheit ist es gerne mal den Wald vor lauter Bäumen zu übersehen. ;)

Nur um nochmal sicher zu gehen das wir die selbe Sprache sprechen ;) Der VMM verwaltet einfach nen Bereich, der aus einer Startadresse und einer Größe besteht und dabei geht es immer um vielfaches der Pagegröße. Er hat erstmal nix mit dem PMM zu tun.
Da möchte ich noch mal explizit auf meinen Beitrag von gestern Abend um 20:09 verweisen. Dort hatte ich doch 4 Ebenen beschrieben und zwei davon mit VMM benahmst (was sicher nicht besonders geschickt ist aber was besseres fällt mir nicht so wirklich ein außer für den Kernel-VMM eben Kernel-Heap). Der VMM der für jeden Prozess den individuellen Teil des virtuellen Adressraums verwaltet (Manager 2 in meiner Auflistung von gestern Abend) benutzt dazu Deine zwei Bäume um eben die freien und belegten Abschnitte im virtuellen Prozess-Adressraum zu verwalten. Diese zwei Bäume gibt es für jeden Prozess individuell so das dieser Prozess-spezifische VMM immer wissen muss für welchen Prozess er gerade arbeitet (außer Du speicherst diese beiden Bäume immer in einem Prozess-privaten Bereich des virtuellen Adressraums, dann ergibt es sich automagisch für welchen Prozess dieser VMM arbeitet anhand des gerade aktiven PD's aber genau das macht Dir ja Probleme weil Du dann öfters das PD wechseln musst).

Man macht beim VMM eine Anfrage nach einem Bereich (in meinem Fall z.B. Vmm::allocZoneKernel(numPages)). Diese Funktion geht durch den Baum und sucht einen Bereich der groß genug ist (best-fit) und wenn er ne neue Node oder nen neuen Bereich erstellen will ruft er einen Allocator auf, um Speicher für die Objekte zu bekommen.
Ja, da ist die Aufgabe des Prozess-spezifischen VMMs. Den Speicher für die Baum-Elemente holt er sich aber vom Kernel-Heap (was Du hier als Allocator bezeichnet hast) und managed die nicht selber (im Gegensatz zum Heap im User-Mode oder auch im Kernel). Wenn der Prozess-spezifische VMM dann in den virtuellen Adressraum für den Prozess echte Pages legen muss holt er diese direkt beim PMM (Manager 4 in meiner Auflistung von gestern Abend) und wenn bestimmte Pages rein sollen dann kommen die eben wo anders her.

Du redest ja immer davon das der VMM den Speicher seiner Objekte selbst verwaltet. Also würde der VMM wieder durch den Baum gehen um sich eine virtuelle Page zu holen und dorthin Speicher zu mappen, damit er den dann für das Objekt nutzen kann.
Das ist nicht die Funktionsweise die ich für den VMM vorsehen würde sondern so arbeitet die Heap-Verwaltung (im User-Space und im Kernel-Space, Manager 1 und 3 in meiner Auflistung von gestern Abend 20:09).

Diese Page beinhaltet ja mehrere Objekte und auch das musst du ja irgendwie managen. Sprich du hättest dort einen Allocator im Allocator.
Jain, und wir reden hier jetzt über den Kernel-Heap (Manager 3 in meiner Auflistung von gestern Abend). Ja, jede Page die zu einem SLAB-Block wird enthält natürlich mehrere der Elemente die der Heap nach draußen (an den restlichen Kernel) gibt (also der Rückgabewert von kmalloc()). Der Kernel-Heap hat also zwei Gründe warum er den PMM nach echten Pages fragen muss: einmal weil er ein paar Pages benötigt um einen neuen SLAB-Block für eine der Objekt-Größen zu bauen (weil für diese Objekt-Größe keine SLABs mehr frei sind) und zum anderen für den Speicher den kmalloc() liefern soll (falls in den Bereichen die bereits zum Kernel-Heap gehören nichts passendes mehr frei ist). Wenn der Kernel-Heap als reiner SLAB-Allocator implementiert ist (was sich bei einem Micro-Kernel ja gerade anbieten würde da dort nur eine sehr überschaubare Menge an unterschiedlichen Objekt-Größen benötigt wird) dann fällt natürlich der zweite Grund weg. Zur Verwaltung der SLAB-Blöcke selber benötigt der Kernel-Heap für jede Objekt-Größe einen statischen Pointer als Einspungspunkt in die verkettete Liste aus SLAB-Blöcken (im Header eines jeden SLAB-Block ist immer mindestens ein Pointer auf den nächsten SLAB-Block drin, besser zwei damit es eine doppelt verkettete Liste wird die sich dann leichter sortieren lässt). Falls dieser Kernel-Heap-SLAB-Allocator noch CPU-lokale Magazine unterstützt benötigt man natürlich noch für jede CPU mal jede Objekt-Größe einen statischen Pointer (hier würde sich ein Array of Structs anbieten, da die Anzahl der CPUs ja nicht schon zur Compile-Zeit bekannt ist) um eben für jede Objekt-Größe auf jeder CPU einen Magazin-Mechanismus verwalten zu können.

Mich hätte halt interessiert wie andere das Problem lösen.
Also dafür bin ich der falsche Ansprechpartner, bei mir werden die meisten Dinge zwar sehr ähnlich werden aber einige Details werden wegen meinen Segmenten auch ganz anders ausfallen.

Problem an der Stelle ist einfach, das ich die Möglichkeit brauche einfach nur virtuelle Adresse zu bekommen, damit ich da ganz bestimmt Pages hinmappen kann
Das trifft auf den Prozess-spezifischen VMM (Manager 2 in meiner Auflistung von gestern Abend) selbstverständlich zu aber nicht auf den Kernel-Heap (Manager 3 in meiner Auflistung von gestern Abend) da es Dir innerhalb des Kernels für all Deine Verwaltungsstrukturen (egal ob Bäume oder Prozess/Thread-Descriptoren oder sonstwas) egal sein kann in was für Pages die liegen. Was der Kernel-Heap liefert hat auch keinen Bezug zur Page-Größe und kein besonderes Alignment (egal ob der Kernel-Heap als reiner SLAB-Allocator oder als generische Variante oder als Kombination aus beidem realisiert ist).

Zumal ich so den Vorteil habe, dass alles schön voneinander getrennt ist und einfach ausgetauscht werden kann.
Das bleibt ja auch bei meinem Vorschlag erhalten (nur mit dem Unterschied das meine 4 Ebenen jeweils etwas weniger komplex sind ;)).


Grüße
Erik


PS.: FlashBurn, Bitte verliere den Wald nicht aus den Augen, ließ lieber mehrmals. Ich weiß das ich kein toller Erklärer bin, auch weil ich oft versuche möglichst viele Details mit rein zu bringen (um eben ein möglichst vollständiges Bild zu liefern) und andere so sicher Probleme haben dem Wesentlichen zu folgen.
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #18 am: 24. November 2011, 21:48 »
Zitat von: erik
Ja, da ist die Aufgabe des Prozess-spezifischen VMMs. Den Speicher für die Baum-Elemente holt er sich aber vom Kernel-Heap (was Du hier als Allocator bezeichnet hast) und managed die nicht selber (im Gegensatz zum Heap im User-Mode oder auch im Kernel). Wenn der Prozess-spezifische VMM dann in den virtuellen Adressraum für den Prozess echte Pages legen muss holt er diese direkt beim PMM (Manager 4 in meiner Auflistung von gestern Abend) und wenn bestimmte Pages rein sollen dann kommen die eben wo anders her.
So, ich unterscheide aber nicht zw. Kernel- und User-VMM. Ist eigentlich genau das gleiche (theoretisch könnte ich den Code sogar fürs ID-Management einsetzen), hat nur nen unterschiedlichen Startwert und ne unterschiedliche Größe.

Zitat von: erik
Jain, und wir reden hier jetzt über den Kernel-Heap (Manager 3 in meiner Auflistung von gestern Abend). Ja, jede Page die zu einem SLAB-Block wird enthält natürlich mehrere der Elemente die der Heap nach draußen (an den restlichen Kernel) gibt (also der Rückgabewert von kmalloc()). Der Kernel-Heap hat also zwei Gründe warum er den PMM nach echten Pages fragen muss: einmal weil er ein paar Pages benötigt um einen neuen SLAB-Block für eine der Objekt-Größen zu bauen (weil für diese Objekt-Größe keine SLABs mehr frei sind) und zum anderen für den Speicher den kmalloc() liefern soll (falls in den Bereichen die bereits zum Kernel-Heap gehören nichts passendes mehr frei ist).
Auch wenn das Wort Heap gerne dafür verwendet wird, mag ich es nicht. Denn die meisten assozieren damit einfach einen bereich im virtuellen Adressraum der dem Stack entgegenwächst und das trifft für meinen VMM einfach nicht zu.

Zitat von: erik
Das trifft auf den Prozess-spezifischen VMM (Manager 2 in meiner Auflistung von gestern Abend) selbstverständlich zu aber nicht auf den Kernel-Heap (Manager 3 in meiner Auflistung von gestern Abend) da es Dir innerhalb des Kernels für all Deine Verwaltungsstrukturen (egal ob Bäume oder Prozess/Thread-Descriptoren oder sonstwas) egal sein kann in was für Pages die liegen.
Das trifft bei mir auf den Kernel- und User-VMM zu. Ich brauche das, da ich auch Pages mappen möchte und die müssen wirklich an der Pagegröße alignt sein. Frag mich nicht warum, aber ich trenne das gerne so gut es geht (und ich weiß dass das eigentlich gar kein OO Konzept ist, durfte ich mir schon oft von meinem Prof anhören) und deswegen habe ich einmal den VMM und einmal den SlabAllocator.

Zitat von: erik
Das bleibt ja auch bei meinem Vorschlag erhalten (nur mit dem Unterschied das meine 4 Ebenen jeweils etwas weniger komplex sind ;)).
Eben nicht, bei deinem Vorschlag (wenn ich ihn denn richtig verstanden habe) hätte der SlabAllocator auch noch die Funktion des VMMs und ich könnte keine Bereiche mehr allozieren (wo ich dann irgendwelche Pages reinmappen kann).

Ich kann dir als Bsp. die IO-Permission-Bitmap nennen, die IO-APICs, Stacks und es gibt bestimmt noch ein paar Sachen, die mir jetzt nicht einfallen. Wo ich einen VMM im Kernel brauche der mir virtuelle Bereiche ohne physischen Speicher liefert.

Und was ich als sehr großen Vorteil erachte, ich kann alle Ebenen ganz leicht austauschen ohne an einer anderen etwas ändern zu müssen. Bei deiner Variante wäre es ja nicht so einfach mal den "Kernel-Heap" auszutauschen. Ich kann theoretisch einfach nen allgemeinen malloc() nehmen und muss nur den Code zum alllozieren und freigeben für Speicher anpassen (was genau 2 Funktionsaufrufe sind).

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #19 am: 26. November 2011, 19:06 »
Hallo,


Ich brauche das, da ich auch Pages mappen möchte und die müssen wirklich an der Pagegröße alignt sein.
Hm, stimmt, hatte ich vergessen. Also der Kernel-Heap muss nicht nur in der Lage sein Objekte zu liefern sondern auch ganze virtuelle Pages (ohne gleich zwangsläufig physischen Speicher dahinter zu legen, sondern nur optional). Diese Fähigkeit muss er doch eigentlich sowieso haben da er ja auch ganze Pages benutzen muss um daraus SLAB-Blöcke zu bauen (und was anderes als ganze Pages können auch nicht mit Hilfe des PMM mit echtem physischen Speicher hinterlegt werden). Dann musst Du diese interne Fähigkeit des Kernel-Heap als zusätzliches Interface verfügbar machen. Der Kernel-Heap muss doch eh intern einen Baum pflegen um den virtuellen Kernel-Speicher zu managen (so wie der Prozess-VMM den virtuellen Speicher der Prozesse managed, nur mit dem Unterschied das der Prozess-VMM für seine Baum-Objekte einfach den Kernel-Heap benutzt und der Kernel-Heap dafür sich selbst benutzen muss).

Ich sehe da noch immer kein schwerwiegendes Problem.

Ist eigentlich genau das gleiche (theoretisch könnte ich den Code sogar fürs ID-Management einsetzen), hat nur nen unterschiedlichen Startwert und ne unterschiedliche Größe.
So wie ich das sehe können auch in meiner Idee sich Prozess-VMM und Kernel-Heap eine erhebliche Menge Code teilen (das mit dem Baum zur Verwaltung des jeweiligen virtuellen Adressraums ist ja eigentlich das Gleiche), nur die jeweiligen Pointer auf die Baum-Wurzel sind verschieden.

Und was ich als sehr großen Vorteil erachte, ich kann alle Ebenen ganz leicht austauschen ohne an einer anderen etwas ändern zu müssen. Bei deiner Variante wäre es ja nicht so einfach mal den "Kernel-Heap" auszutauschen.
Warum soll das bei meinem Vorschlag nicht gehen? Solange man jeder Ebene ein sauberes Interface verpasst und die anderen Ebenen dieses Interface korrekt benutzen kann man auch jede Ebene individuell beliebig austauschen.

So, ich unterscheide aber nicht zw. Kernel- und User-VMM.
Dann eben nicht, sorry, aber das ist Deine Designentscheidung. Ich versuche Dir nur einen Weg zu zeigen von dem ich glaube (nicht wissen) das er Deine Probleme löst. Ideologische Scheuklappen sind da nicht immer angebracht.

Auch wenn das Wort Heap gerne dafür verwendet wird, mag ich es nicht.
Namen sind nicht so arg wichtig, klar sollte man immer etwas darauf achten was andere jeweils damit assoziieren aber auch der Heap im User-Mode wächst schon sehr lange nicht mehr einfach nur dem Stack entgegen (schon allein deswegen weil heutige Prozesse überwiegend mehrere Stacks für mehrere Threads haben). Ich persönlich empfinde den Begriff Heap für den Kernel-VMM eigentlich als ganz angemessen, es ist ja im Endeffekt ein Heap.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

 

Einloggen