Autor Thema: Emulation von fork/exec in der libc  (Gelesen 11690 mal)

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« am: 16. July 2011, 10:25 »
Hallo,


zu dem oben genannten Thema ist mir vor kurzen was gutes eingefallen: Ich kann mir vorstellen das es möglich ist das Pärchen fork/exec in der libc recht brauchbar zu emulieren. Der fork-Stub müsste dafür nur eine Kopie des aktuelles Stacks anfertigen und ein Flag setzen, alle weiteren Aufrufe in die libc welche File-Handels u.ä. betreffen müssten dann mit einem zweiten Datensatz bearbeitet werden (deswegen das Flag) und die exec-Funktion müsste dann einen neuen Prozess erzeugen und den geänderten zweiten Handle-Datensatz dem neuen Prozess geben und als letztes im eigenen Prozess den alten Stack restaurieren um damit wieder aus dem fork-Aufruf zurück zu kommen (mit dem passenden Return-Wert für den Eltern-Prozess). Mir ist klar dass das nicht immer funktioniert, spätestens wenn zwischen fork und exec die beiden Prozesse miteinander kommunizieren wollen geht das mit meiner Idee nicht weil der neue Prozess ja erst bei exec erstellt wird und der Code zwischen fork und exec noch im alten Prozess läuft während der eigentliche Ausführungspfad des alten Prozesses noch nicht ausgeführt wird. Das das nur mit Single-Thread-Programmen funktioniert ist auch klar aber wer Threads benutzt benötigt IMHO auch kein fork.

Es ist offensichtlich das dieser dirty Hack in einigen Situationen nicht das tut was unter POSIX passieren würde und es da eine Menge Risiken gibt, z.B. könnten andere statische Variablen zwischen fork und exec manipuliert werden und diese Manipulation wäre dann im Elternprozess sichtbar (sie passiert ja auch noch im Elternprozess) obwohl das eigentlich nicht sein darf. Trotzdem könnte diese Krücke für viele einfache Programme durchaus brauchbar sein. Es würde einem zumindest ersparen beim Portieren eine Menge Code anzufassen obwohl da nur nach klassischer POSIX-Manier neue Prozesse erstellt werden. Ich hab noch nicht nachgesehen aber ich kann mir vorstellen das damit über 90% aller fork-Aufrufe in den Core-Utils gut abgedeckt wären und man sich so eine Menge Portierungsaufwand erspart. Da man diese Funktionalität nur dann in der libc bräuchte wenn es sich um ein POSIX-Programm handelt sollte das ganze eventuell über ein #define zuschaltbar sein bzw. die libc müsste doppelt vorhanden sein damit dann der Loader die jeweils passende benutzen kann.


Ich hoffe ich habe meine Idee verständlich ausgedrückt ansonsten Bitte nachfragen.

Was haltet Ihr von meiner Idee?
Seht Ihr irgendwelche Probleme oder Lücken (aus Sicht der einfachen Standard-Fälle)?


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

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 16. July 2011, 11:48 »
Könnte so für die einfachen Fällen schon funktionieren.

Aber es gibt zwei Punkte, die mich davon abhalten würden, das umzusetzen: Zum einen die tiefgreifenden Auswirkungen auf die Implementierung der restlichen libc, wenn die überall Spezialfälle berücksichtigen müssen, falls es nach einem fork() war. Und zum anderen, dass du die schwierigen Fälle nicht automatisch erkennst, in denen es schiefgeht. Eine Lösung, die normal das richtige tut, aber in schwierigen Fällen einen Fehler zurückgibt, wäre okay. Aber eine Funktion, die normal das richtige tut, und in schwierigen Fällen den Pseudo-Elternprozess korrumpiert, ist für mich keine Option.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 16. July 2011, 12:25 »
Außerdem wäre das irgendwie... schon vom Design her kaputt.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 16. July 2011, 17:04 »
Hallo,


Außerdem wäre das irgendwie... schon vom Design her kaputt.
Full ACK! (übrigens ein Gedanke der mir bei fork/exec schon des öfteren gekommen ist ;) SCNR)
Der Gedanke hinter meiner Idee war auch nicht eine tolle Lösung zu präsentieren sondern eine Art Trade-Off über den Portierungsaufwand. Wenn man mit einer Art libc-Anpassung oder eventuell einem Wrapper (hierüber müsste man mal noch etwas grübeln ob damit taljeth's erster Kritikpunkt abwendbar ist) sich bei 90% aller zu portierenden POSIX-Programme eine große Menge an Aufwand spart dann ist das doch schon mal ein Gewinn. Klar muss man trotzdem noch bei allen Programmen in den Quell-Code schauen ob dieser Dirty-Hack auch anwendbar ist, eine vollautomatische Rundumsorgloslösung kommt da auf jeden Fall nicht bei raus. Ich könnte mir aber vorstellen das man damit bei vielen Programmen, die fork/exec genau so klassisch benutzen, den Quell-Code nur marginal ändern müsste und man so auch von Aktualisierungen im Original-Projekt automatisch profitieren kann ohne jedes mal wieder neu den Portierungsaufwand haben zu müssen.


die tiefgreifenden Auswirkungen auf die Implementierung der restlichen libc, wenn die überall Spezialfälle berücksichtigen müssen, falls es nach einem fork() war
Was schätzt Du denn wie tiefgreifend diese Auswirkungen sind? Eigentlich betrifft das ja nicht so viele der libc-Funktionen, etliche haben keinen dauerhaften Zustand, und für den Rest wäre eventuell ein Wrapper eine gute Idee der eben nur die Zustandsänderungen mit loggt und am Ende von exec wieder alles rückgängig macht (für den Elternprozess). Mir ist klar das das reichlich Dirty ist aber wenn man die "Heilige Kuh der Kompatibilität" nicht schlachten möchte darf man keine Angst vor schmutzigen Händen haben, alles selber neu Schreiben macht auf jeden Fall deutlich mehr Arbeit und mit Sicherheit keine saubereren Hände.

Könnte so für die einfachen Fällen schon funktionieren.
Es geht mir ja vorwiegend um die einfachen Fälle. Solange diese einen erheblichen Anteil darstellen müsste meine Idee tatsächlich die Chance haben eine Reduktion des Portierungsaufwandes bewirken zu können.


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

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 16. July 2011, 20:25 »
Erik, für die "einfachen Fälle" gibt es vfork(). Wenn ein Programm also direkt hintereinander fork()/exec() ausführt, dann kann man das fork() auch immer durch ein vfork() ersetzen und spart sich eine Menge Ärger. Ohne MMU kann man fork() nicht performant machen, vfork() hingegen schon.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 17. July 2011, 11:57 »
Hallo,


Erik, für die "einfachen Fälle" gibt es vfork(). Wenn ein Programm also direkt hintereinander fork()/exec() ausführt, dann kann man das fork() auch immer durch ein vfork() ersetzen und spart sich eine Menge Ärger.
So einfache Fälle habe ich nun auch nicht im Visier. Wenn fork und exec direkt hintereinander stehen dann kann man das einfach mit einem CreateProzess(enableInheritance=true) ersetzen ohne da viel denken zu müssen. Es geht mir um die Fälle wo zwischen fork und exec noch einiges an Code ist der vorwiegend Handels schließt oder öffnet um dem Kindprozess gezielt bestimmte Dinge zu vererben. Ich denke das gerade in den Programmen aus den Core-Utils ne Menge Beispiele für sowas drin sind und gerade um solche klassischen POSIX-Tools geht es mir. Ich würde z.B. gerne einfach eine bash portieren anstatt selber eine Shell schreiben zu müssen (letzteres ist bei weitem keine Kleinigkeit), grundsätzlich sehe ich an der bash auch absolut keine Probleme für meine Plattform von fork/exec mal abgesehen.

Ohne MMU kann man fork() nicht performant machen, vfork() hingegen schon.
Damit willst Du mir doch jetzt hoffentlich nicht empfehlen den gut ausgetrampelten Pfad des Flat-Memory-Konzepts zu gehen? Ich weiß, die dunkle Seite ist einfacher, schneller und verführerischer aber stärker ist sie nicht. Ich persönlich empfinde fork schon vom Design her kaputt aber das ändert nichts an der Tatsache das es in der großen bösen Welt ne Menge Programme gibt die das benutzen. Ich habe also 2 Möglichkeiten: ich kann versuchen diese Programme irgendwie zu Portieren oder ich kann diese Programme für meine Plattform neu schreiben. Letzteres würde ich als Zeitverschwendung betrachten, warum sollte ich das Rad ein weiteres mal neu erfinden? Erstes ist auf eine Plattform die fork grundsätzlich nicht unterstützen kann aber auch nicht einfach also kommt man da schon mal auf, äh, pragmatische Ideen.


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

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 24. July 2011, 13:59 »
Hallo,

naja ich halte Segmentierung jetzt nicht unbedingt für den totalen Grund gegen fork(). Code und RO-Daten lassen sich in jedem Fall als ganzes Segment gemeinsam nutzen und im Notfall kannst du jedes Segment auch wie eine Page behandeln (d.h. Copy-on-Write plus einiges an Buchführung für die Datenstrukturen). Du könntest dich in der Embedded-Welt bedienen (Busybox enthält einen Großteil der Coreutils und funktioniert auch auf NOMMU-Systemen - also exakt deine Zielwelt). Der schnellste Weg, Unix-Programme zum Laufen zu überreden, ist übrigens eine Unix-kompatible Umgebung. Du willst sie nicht, behalte also die Scherben. :P

Effektiv hast du zwei in meinen Augen sinnvolle Möglichkeiten: Du unterstützt in deinem Kernel ein fork() [muss ja nicht performant sein, korrekt reicht aus] oder du unterstützt es halt nicht. Du wirst mit einer unglaublich langsamen fork()-Emulation jedenfalls keinen Spaß haben und dann entweder sowieso um- oder neuschreiben müssen. Bei einer mäßigen/kaputten Implementation passiert das sowieso.

Damit willst Du mir doch jetzt hoffentlich nicht empfehlen den gut ausgetrampelten Pfad des Flat-Memory-Konzepts zu gehen?
Ganz sicher nicht, da ich einerseits weiß, dass du dagegen eine winzigkleine Abneigung hast, andererseits Segmentierung selbst eine nette Sache finde und daher möchte, dass du für deine Probleme auch Lösungen findest. ;)

Ich finde fork() gut, aber wenn es nicht vernünftig implementierbar ist, dann lass es weg und portiere die Software. Wenn du es nebenbei schaffst, die bash gebrauchbar auf NOMMU-Systeme zu portieren, dann freut sich bestimmt auch Upstream.

Gruß,
Svenska

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 24. July 2011, 18:19 »
Hallo,


naja ich halte Segmentierung jetzt nicht unbedingt für den totalen Grund gegen fork(). Code und RO-Daten lassen sich in jedem Fall als ganzes Segment gemeinsam nutzen ...
Da bin ich mir nicht so ganz sicher, der Code und auch die RO-Daten werden beim Laden reloziert (z.B. werden in den Code die richtigen LDT-Selectoren eingebaut, die sollen eigentlich per Zufall vergeben werden) und außerdem landet der Code zur Laufzeit nicht an Offset 0 im Code-Segment sondern an einem zufälligen Offset. Ich habe auch explizit vorgesehen das der Loader in der Lage sein soll in entsprechend markierte Felder in den RO-Daten Zufallswerte einzutragen damit z.B. ein PRNG das als Seed nutzen kann. Es wäre eher ungeschickt (wenn nicht gar ein Sicherheitsrisiko) solche Dinge zu sharen. Ich will bei mir möglichst viele Dinge vom Zufall steuern lassen, in so eine Umgebung passt fork einfach nicht rein (egal ob Flat-Memory oder Segmentierung).

An BusyBox hab ich auch schon gedacht aber ich denke auch das basiert auf fork/exec, auch wenn man dort sicher einiges möglichst einfach gestaltet hat. Ich schätze ich sollte mir dessen Quellcode mal etwas genauer ansehen. Hat damit hier schon jemand Erfahrung?

Der schnellste Weg, Unix-Programme zum Laufen zu überreden, ist übrigens eine Unix-kompatible Umgebung. Du willst sie nicht, behalte also die Scherben. :P
Mein Plan war eigentlich die Kompatibilität auf der libc-Ebene zu erreichen, da ich einen Micro-Kernel realisieren möchte wird dort eh sehr vieles von dem drin sein was bei klassischen POSIX-Systemen im Kernel steckt.

Effektiv hast du zwei in meinen Augen sinnvolle Möglichkeiten: Du unterstützt in deinem Kernel ein fork() [muss ja nicht performant sein, korrekt reicht aus] oder du unterstützt es halt nicht.
Ich denke ich kann fork schon aus technischen Gründen nicht im Kernel unterstützen und eigentlich will ich das auch nicht. In meinen Augen ist fork obsolet. Bei einzelnen Programmen die fork nutzen um mehrere Aufgaben parallel zu erledigen (z.B. ein HTTP-Server der für jede TCP-Connection forkt, ich weiß dass das ein doofes Beispiel ist weil es dafür eigentlich Async-IO gibt) sind Threads aus heutiger Sicht die bessere Wahl (entsprechende Programme muss ich auf jeden Fall portieren aber das sollte selten sein da sich die Benutzung von Threads durchaus langsam verbreitet) und bei den Fällen wo fork benutzt wird um dann mit exec ein neues Programm zu starten wäre CreateProzess und eine konkrete Liste der zu vererbenden Ressourcen die bessere Wahl (schon allein aus sicherheitstechnischer Sicht). Ich möchte in meinem OS nicht nur deswegen kein fork haben weil ich es technisch nicht vernünftig umsetzen kann sondern auch weil ich es als Sicherheitsrisiko einstufe. Nebst dessen das für den ersten Fall Threads billiger sind als fork.

Du wirst mit einer unglaublich langsamen fork()-Emulation jedenfalls keinen Spaß haben
Wieso sollte die Variante in der libc "unglaublich langsam" sein? Klar wird dadurch jeder interessante libc-Aufruf um ein paar CPU-Takte ausgebremst aber das dürfte kaum spürbar sein solange kein fork aktiv ist und wenn fork aktiv ist dann wird zwar stärker gebremst aber es handelt sich ja auch nur um einen relativ kurzen Abschnitt im Programm.

da ich einerseits weiß, dass du dagegen eine winzigkleine Abneigung hast
Aber wirklich nur eine ganz winzig kleine. ;)

andererseits Segmentierung selbst eine nette Sache finde und daher möchte, dass du für deine Probleme auch Lösungen findest. ;)
Das ist toll. Für fork werde ich aber ganz sicher keine wirklich zufriedenstellende Lösung finden, ich kann IMHO nur versuchen für die verschiedenen Anwendungsszenarien jeweils einigermaßen passende Teil-Lösungen zu erarbeiten. In den Fällen wo fork nur zum Parallelisieren benutzt wird oder wo zwischen fork und exec richtig komplexer Code ist und/oder die zwei Prozesse gar miteinander kommunizieren muss ich eh portieren da sich sowas nicht einfach emulieren lässt. Die Fälle wo fork und exec direkt hintereinander stehen lassen sich auch ganz simpel portieren so das dort keine Emulation lohnt. Was übrig bleibt sind die Fälle wo zwischen fork und exec noch Ressourcen geschlossen/geöffnet werden aber sonst nicht allzu komplexe Dinge passieren, ich denke diese Fälle sind auch recht häufig so das sich hier eine Emulation eventuell tatsächlich lohnt, technisch umsetzbar erscheint mir diese zumindest.

In diesem Zusammenhang kann ich mir vorstellen das BusyBox ein schwieriges Programm ist weil es wahrscheinlich recht viele verschiedene Anwendungsszenarien für fork enthält. Bei einem Programm das nur eine Aufgabe erfüllen muss könnte das eventuell einfach werden, man kann dann für jedes Programm individuell entscheiden. Gerade bei der bash sehe ich eigentlich nicht das es dort verschiedene Szenarien für fork gibt, wenn die bash einen neuen Prozess startet dann geht es in erster Linie um das gezielte Vererben von stdin/stdout/stderr und um das Übermitteln von Parametern. Meiner Meinung nach dürfte die bash gerade in die Kategorie fallen die ich mit der libc-Emulation anvisiere.

Ich finde fork() gut
Tja, jeder hat eben seine eigene Meinung. ;) Keine Angst, Meinungsvielfalt empfinde ich als ein sehr wichtiges Gut unserer modernen Zivilisation.

Wenn du es nebenbei schaffst, die bash gebrauchbar auf NOMMU-Systeme zu portieren, dann freut sich bestimmt auch Upstream.
Sicher? Davon bin ich nicht so überzeugt, immerhin würde das bedeuten das die bash von wesentlichen POSIX-Traditionen abweichen würde und damit würde man eventuell riskieren das sie auf anderen Plattformen nicht mehr so toll funktioniert. Ich könnte mir durchaus vorstellen das eine entsprechende Anfrage mit "entweder Du kannst POSIX oder Du lässt es" beantwortet wird. Ich hab mit so einer Antwort auch kein Problem, wenn die bash explizit ein POSIX-Programm sein soll dann ist das Okay für mich.


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

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 24. July 2011, 20:45 »
Hallo,

Es wäre eher ungeschickt (wenn nicht gar ein Sicherheitsrisiko) solche Dinge zu sharen. Ich will bei mir möglichst viele Dinge vom Zufall steuern lassen, in so eine Umgebung passt fork einfach nicht rein (egal ob Flat-Memory oder Segmentierung).
Einverstanden. Ein wirkliches Hindernis ist das also nur, weil du ein paar Designentscheidungen so triffst.

An BusyBox hab ich auch schon gedacht aber ich denke auch das basiert auf fork/exec, auch wenn man dort sicher einiges möglichst einfach gestaltet hat. Ich schätze ich sollte mir dessen Quellcode mal etwas genauer ansehen. Hat damit hier schon jemand Erfahrung?
Als ich mich damit befasst habe, ging es mir um meinen schon damals veralteten Palm IIIx (m68k-Kern), also Linux 2.0. Die NOMMU-Patches unterstützten damals ganz einfach kein fork(), sondern nur vfork(). Entsprechend sollte Busybox - wenn es für NOMMU kompiliert wurde - auch kein fork benutzen können.

Mein Plan war eigentlich die Kompatibilität auf der libc-Ebene zu erreichen, da ich einen Micro-Kernel realisieren möchte wird dort eh sehr vieles von dem drin sein was bei klassischen POSIX-Systemen im Kernel steckt.
Richtig, du kannst aber nicht alles komplett in der libc verstecken (zumindest nicht, wenn es ein bisschen performant sein soll), wenn der Kernel nicht ein paar Grundfunktionen unterstützt. Für fork() wäre das zumindest die Möglichkeit, einen Descriptor zu vererben; dann könnte die libc die Segmente kopieren/sharen und alles wäre gut. Wenn dein Kernel dieses Konzept auch nicht kennen soll, wirst du wohl ganz einfach ohne auskommen müssen.

Die libc sollte kein POSIX-Emulator sein. ;-) Allerdings mache ich mir es da einfacher, indem mein gedachter (Mikro)kernel einfach die grundlegenden Unixkonzepte unterstützt (z.B. fork) und die libc das dann nur weitergibt. Der Kernel (und die Treiber, so es die betrifft) kennt also die Konzepte.

Ich denke ich kann fork schon aus technischen Gründen nicht im Kernel unterstützen und eigentlich will ich das auch nicht.
Dann lass es einfach sein und lebe mit den Konsequenzen.

In meinen Augen ist fork obsolet. Bei einzelnen Programmen die fork nutzen um mehrere Aufgaben parallel zu erledigen (z.B. ein HTTP-Server der für jede TCP-Connection forkt, ich weiß dass das ein doofes Beispiel ist weil es dafür eigentlich Async-IO gibt) sind Threads aus heutiger Sicht die bessere Wahl [...]
Ein fork-basierter HTTP-Server lässt sich extrem einfach implementieren, hat gute Performance und skaliert unter Linux recht gut. Laut einer älteren Analyse besser, als wenn man poll() nutzt. Und z.B. Apache nutzt mehrere Mechanismen (Threads, Forks, im Prozess ausgeführte Module) parallel, was sicherlich auch Gründe hat; den würde ich aber nicht als Performancemeister bezeichnen.

Ich möchte in meinem OS nicht nur deswegen kein fork haben weil ich es technisch nicht vernünftig umsetzen kann sondern auch weil ich es als Sicherheitsrisiko einstufe. Nebst dessen das für den ersten Fall Threads billiger sind als fork.
Dann lass auch die Emulation weg...

Du wirst mit einer unglaublich langsamen fork()-Emulation jedenfalls keinen Spaß haben
Wieso sollte die Variante in der libc "unglaublich langsam" sein? Klar wird dadurch jeder interessante libc-Aufruf um ein paar CPU-Takte ausgebremst aber das dürfte kaum spürbar sein solange kein fork aktiv ist und wenn fork aktiv ist dann wird zwar stärker gebremst aber es handelt sich ja auch nur um einen relativ kurzen Abschnitt im Programm.
Ein fork-basierter Webserver wird nicht nur ein paarmal forken, sondern ständig und sehr oft. Dann kommt neben dem ständigen Overhead auch noch der Aufruf von fork() selbst dazu - und der ist ziemlich teuer, besonders wenn du die betroffenen Segmente nicht gemeinsam nutzen möchtest.

In diesem Zusammenhang kann ich mir vorstellen das BusyBox ein schwieriges Programm ist weil es wahrscheinlich recht viele verschiedene Anwendungsszenarien für fork enthält.
Ich vermute, es gibt für die meisten Applets ein paar "#ifdef NOMMU"-Anweisungen und damit zwei verschiedene Implementationen. Ein paar Applets laufen aber nicht (wimre ist die ash nicht NOMMU-tauglich, sondern nur die hush).

Meiner Meinung nach dürfte die bash gerade in die Kategorie fallen die ich mit der libc-Emulation anvisiere.
Dann patche lieber die bash selbst, als ein per Design kaputtes Konzept in die libc zu schreiben (oder nimm eine externe lib_böse_routinen für sowas).

Wenn du es nebenbei schaffst, die bash gebrauchbar auf NOMMU-Systeme zu portieren, dann freut sich bestimmt auch Upstream.
Sicher? Davon bin ich nicht so überzeugt, immerhin würde das bedeuten das die bash von wesentlichen POSIX-Traditionen abweichen würde und damit würde man eventuell riskieren das sie auf anderen Plattformen nicht mehr so toll funktioniert.
Naja, wenn die Bash unter NOMMU-Linux vernünftig funktionieren kann, wäre das schon ne nette Sache. Nutzen wird es wohl eher niemand, weil an Speicherfragmentierung bei der Bash wohl niemand gedacht hat. Ansonsten wirst du sie wohl für deine Verhältnisse forken müssen. ;) Oder du guckst dir die Dash bzw. ähnliche Projekte an. Die sind meist eh schneller, fast komplett kompatibel und vermutlich mit saubereren Sourcen.

Ich könnte mir durchaus vorstellen das eine entsprechende Anfrage mit "entweder Du kannst POSIX oder Du lässt es" beantwortet wird. Ich hab mit so einer Antwort auch kein Problem, wenn die bash explizit ein POSIX-Programm sein soll dann ist das Okay für mich.
Dazu müsstest du erstmal einen minimalinvasiven Patch an die Entwickler schicken. :-)

Gruß,
Svenska

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 24. July 2011, 21:52 »
Hallo,


Einverstanden. Ein wirkliches Hindernis ist das also nur, weil du ein paar Designentscheidungen so triffst.
Naja, so in etwa. Mir ist klar das man auch mit Segmentierung grundsätzlich ein fork implementieren kann. Wenn man immerhin Code und RO-Data shared spart man sich zumindest ein klein wenig Kopierarbeit, trotzdem würde fork ein ziemlich langsames Konstrukt bleiben. Gerade über das Sharen von Code und RO-Data habe ich schon einige male nachgedacht, es gibt ja auch die Situation wo ein Programm mehrere male gestartet wird und da könnte man eventuell etwas Speicher sparen. Aber mir persönlich erscheint die Speicherersparnis gegenüber dem Sicherheitsverlust (weil dann mehrere unabhängige Programme ein paar Dinge wie eben die LDT-Belegung oder das Start-Offset vom Code nicht mehr individuell per Zufall bekommen können, also kein ASLR mehr geht) als zu gering so das ich auf das Sharen lieber verzichte um ein möglichst sicheres System zu bekommen. Ist ganz klar eine willkürliche Designentscheidung aber so ist es eben. Das fork mit Segmenten trotzdem kein Performancewunder wird ist ein weiterer Grund warum ich das erst gar nicht haben will.
Du weißt ja, ich will Sicherheit und Performance haben! ;)

Die NOMMU-Patches unterstützten damals ganz einfach kein fork(), sondern nur vfork(). Entsprechend sollte Busybox - wenn es für NOMMU kompiliert wurde - auch kein fork benutzen können.
Okay, Danke für diesen Hinweis. Ich sollte mir auf jeden Fall noch mal die genauen Unterschiede zwischen fork und vfork ansehen.

du kannst aber nicht alles komplett in der libc verstecken (zumindest nicht, wenn es ein bisschen performant sein soll)
Ich sehe da momentan keine Performance-Probleme. Solange der Kernel schnelles IPC/RPC mit Zero-Copy-Datentransfer unterstützt ist doch egal ob ein bestimmter Service vom Kernel oder von einem User-Mode-Prozess (also der Personality) erbracht wird.

wenn der Kernel nicht ein paar Grundfunktionen unterstützt. Für fork() wäre das zumindest die Möglichkeit, einen Descriptor zu vererben; dann könnte die libc die Segmente kopieren/sharen und alles wäre gut. Wenn dein Kernel dieses Konzept auch nicht kennen soll, wirst du wohl ganz einfach ohne auskommen müssen.
Aber gerade bei einem Micro-Kernel ist es doch Teil des Konzeptes das diser nicht weiß was ein Datei-Descriptor (diese Descriptoren meintest Du doch?) ist, das soll ein vfs-Prozess managen. Für das Vererben von Datei-Descriptoren hab ich ein halbwegs anständiges Konzept mal irgendwo aufgeschrieben (und auch hier kurz diskutiert), wimre war das auch einigermaßen performant. Die libc kann bei mir keine ganzen Segmente kopieren oder sharen (und schon gar nicht alle), das ist für meine Idee zur fork-Emulation auch überhaupt nicht erforderlich. Die libc im Elternprozess macht bloß beim exec-Aufruf eine Bestandsaufnahme über alle geöffneten Ressourcen und gibt beim CreateProzess eine Liste mit die dann von der libc im Kindprozess verarbeitet wird (bevor main aufgerufen wird, damit dann dort diese Ressourcen auch verfügbar sind), anschließend wird im Elternprozess, nach dem CreateProzess-Aufruf innerhalb von exec, alle Änderungen seit dem zugehörigen/vorangegangenen fork-Aufruf wieder rückgängig gemacht und anschließend noch der Stack auf den Zeitpunkt des fork-Aufrufs restauriert damit dann ein zweites mal aus dem fork zurückgekehrt werden kann (diesmal als Elternprozess). Es wird also nie wirklich ein echtes fork ausgeführt, sondern das ganze über die Zeit hinweg emuliert.

Die libc sollte kein POSIX-Emulator sein. ;-)
Schon klar, aber irgendwie muss man dieses Problem ja lösen und da helfen ideologische Scheuklappen auch nicht weiter. Grundsätzlich gebe ich Dir ja Recht und diese Spezial-Version der libc soll auch nur in den Programmen benutzt werden die eben fork enthalten und wo ich mir den Aufwand des Portierens ersparen möchte (okay das könnten tendenziell schon einige sein da ich ja mit möglichst wenig Aufwand möglichst viele Programme portieren möchte).

Ein fork-basierter HTTP-Server lässt sich extrem einfach implementieren, hat gute Performance und skaliert unter Linux recht gut.
Sicher richtig, aber den selben HTTP-Server mit Threads zu realisieren ist noch deutlich performanter (so den die Zielplattform Threads ordentlich unterstützt), fork kostet in jedem Fall das Anlegen eines neuen Paging-Directorys und später etliche Paging-Exceptions (für COW) und ein Haufen Verwaltung im Kernel wogegen Threads nur einen neuen Stack und ein wenig Verwaltung im Kernel kosten.

Ich möchte in meinem OS nicht nur deswegen kein fork haben weil ich es technisch nicht vernünftig umsetzen kann sondern auch weil ich es als Sicherheitsrisiko einstufe. Nebst dessen das für den ersten Fall Threads billiger sind als fork.
Dann lass auch die Emulation weg...
Gerade diese Emulation wird nur recht wenig Performance kosten und eigentlich kein Sicherheitsrisiko darstellen, der Kernel kann ja trotzdem beim CreateProzess einen neuen Prozess mit neuen Zufallswerten fürs ASLR anlegen. In meiner Emulation gibt es kein Sharing.

Ein fork-basierter Webserver wird nicht nur ein paarmal forken, sondern ständig und sehr oft.
Ein solcher HTTP-Server ist definitiv nicht Ziel meiner Emulation, die funktioniert nur wenn nach dem fork auch exec aufgerufen wird. Alles was nur fork benutzt muss von mir auf jeden Fall auf die Benutzung von Threads umgebaut werden. Aber zumindest hier könnte der Upstream durchaus profitieren da ich dafür auf pthread setzen möchte.

Dann patche lieber die bash selbst, als ein per Design kaputtes Konzept in die libc zu schreiben (oder nimm eine externe lib_böse_routinen für sowas).
Ich wollte eine BAD-POSIX-Version der libc erstellen oder eventuell einen Warpper der die interessanten Funktionen der libc passend kapselt und zusätzlich fork/exec anbietet.

Oder du guckst dir die Dash bzw. ähnliche Projekte an. Die sind meist eh schneller, fast komplett kompatibel und vermutlich mit saubereren Sourcen.
Okay, ich werde mich dann mal bei Gelegenheit umsehen.

Ich könnte mir durchaus vorstellen das eine entsprechende Anfrage mit "entweder Du kannst POSIX oder Du lässt es" beantwortet wird. Ich hab mit so einer Antwort auch kein Problem, wenn die bash explizit ein POSIX-Programm sein soll dann ist das Okay für mich.
Dazu müsstest du erstmal einen minimalinvasiven Patch an die Entwickler schicken. :-)
Ich hatte eher gehofft mit meiner Emulation ganz ohne Patch auszukommen, oder mit so minimalen Änderungen das es keine große Mühe ist diese in die nächste Version zu holen (ich würde nur sehr ungern auf eine bestimmte Version festgenagelt sein und bei eventuellen Sicherheitsfixes im Original-Projekt vor erheblichen Aufwand stehen).
Die bash NOMMU-tauglich zu machen dürfte über "minimalinvasiv" deutlich hinaus gehen, genau deswegen betrachte ich das Patchen solcher Programme nicht wirklich als Option.


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

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 24. July 2011, 22:53 »
Wenn man immerhin Code und RO-Data shared spart man sich zumindest ein klein wenig Kopierarbeit, trotzdem würde fork ein ziemlich langsames Konstrukt bleiben.
Beim Start ja, im Betrieb nicht. Solaris hat so betrachtet auch ein langsames Fork. ;)

Gerade über das Sharen von Code und RO-Data habe ich schon einige male nachgedacht, es gibt ja auch die Situation wo ein Programm mehrere male gestartet wird und da könnte man eventuell etwas Speicher sparen.
Das allein ist für mich ein wichtiger Grund, sowas zu tun (insbesondere bei Shared Libraries wird das wichtig, wenn du sowas komplexes wie KDE haben möchtest - wo jeder Popel eine riesige Umgebung mitzieht). Ob man da nun das Codesegment der Lib shared oder das Codesegment einer Anwendung ist egal.

Aber mir persönlich erscheint die Speicherersparnis gegenüber dem Sicherheitsverlust (weil dann mehrere unabhängige Programme ein paar Dinge wie eben die LDT-Belegung oder das Start-Offset vom Code nicht mehr individuell per Zufall bekommen können, also kein ASLR mehr geht) als zu gering so das ich auf das Sharen lieber verzichte um ein möglichst sicheres System zu bekommen.
Zwei Programme, die sich ein Segment teilen, können doch trotzdem verschiedene LDTs haben (nur die betroffenen Segmente müssen die gleichen Indizes haben) und der Offset ist dann für gemeinsame Segmente gleich. Um ein Programm so zu exploiten, müsstest du es also ein zweites Mal exploitet haben, um an den Offset zu kommen... außerdem kannst du das Sharing ja für bestimmte kritische Anwendungen deaktivieren.

Aber gerade bei einem Micro-Kernel ist es doch Teil des Konzeptes das diser nicht weiß was ein Datei-Descriptor (diese Descriptoren meintest Du doch?) ist, das soll ein vfs-Prozess managen.
Naja, das seh ich für mich persönlich etwas anders. Ich betrachte einen Kernel, der Speicher- und Prozess-/Threadverwaltung macht und das VFS enthält durchaus noch als Mikrokernel. Treiber (inkl. Dateisystem) sind ja schließlich trotzdem noch Userspace. Aber der Kernel muss nichts von Dateidescriptoren wissen, sondern höchstens von "Ressourcen" (und das Sharing würde dann trotzdem über die VFS-Anwendung laufen).

Grundsätzlich gebe ich Dir ja Recht und diese Spezial-Version der libc soll auch nur in den Programmen benutzt werden die eben fork enthalten und wo ich mir den Aufwand des Portierens ersparen möchte (okay das könnten tendenziell schon einige sein da ich ja mit möglichst wenig Aufwand möglichst viele Programme portieren möchte).
Wenn du die Programme nicht auf Forkfreiheit hin umbauen möchtest, dann solltest du ein voll funktionsfähiges und relativ schnelles (im Rahmen der Möglichkeiten) fork bauen. Ansonsten wäre der richtige Weg, darauf zu verzichten und die Programme zu portieren.

Ich wollte eine BAD-POSIX-Version der libc erstellen oder eventuell einen Warpper der die interessanten Funktionen der libc passend kapselt und zusätzlich fork/exec anbietet.
Achso, deine "normale" libc soll also kein POSIX anbieten? Ansonsten würde ich vorschlagen, in der libc nur die gewöhnlichen und gewollten Teile anzubieten und eine zusätzliche bad_libc bereitstellen, die sowas wie fork wrappt.

Die bash NOMMU-tauglich zu machen dürfte über "minimalinvasiv" deutlich hinaus gehen, genau deswegen betrachte ich das Patchen solcher Programme nicht wirklich als Option.

Meine Meinung ist, dass du entweder richtiges POSIX anbieten solltest (und zwar ohne größere Verrenkungen wie eine fork-Emulation) oder eben kein richtiges POSIX hast. Im letzteren Fall kannst du dich einerseits bei einer großen Menge NOMMU-fähiger (Linux-)Software bedienen oder sie recht einfach anpassen (wenn sie schon Threads oder asynchrones I/O benutzen). Teilweise wirst du halt Programme nicht sinnvoll portieren können, dann solltest du es meiner Meinung nach aber auch eher lassen.

Du hast eine MMU, die du nicht benutzen willst - also simuliere sie bitte auch nicht in Software. :P

Am Ende landest du dann bei den gleichen Problemen wie Intel mit dem Pentium Pro, der zwar wirklich schnell war, aber eben nicht für 16-Bit-Code (Win95)... wenn Programm X nicht läuft, dann ist das blöde - wenn aber Programm X nur sehr langsam ist, dann fällt das direkt auf deine Plattform und dein OS zurück und hinterlässt einen schlechten Eindruck. Unabhängig davon, ob Programm X nun irgendwelche Kompatiblitätslayer benutzt oder nicht.

Gruß,
Svenska

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 25. July 2011, 09:44 »
Hallo,


Okay, das selbst ein fork das kopiert zur eigentlichen Laufzeit keine Bremse darstellt ist mir klar aber das Kopieren kann bei größeren Programmen schon ein ziemlich extremer Overhead sein (da müsste ja der gesamte Heap usw. mitkopiert werden). Vor allem wäre dieser Overhead kompletter Unsinn wenn kurz nach den fork ein exec kommt und dann eh ein neuer Prozess erstellt wird. Gerade für diese Szenarien ist ein echtes fork im Kernel IMHO völliger Unsinn auf meiner Plattform.

Das allein ist für mich ein wichtiger Grund, sowas zu tun (insbesondere bei Shared Libraries wird das wichtig, wenn du sowas komplexes wie KDE haben möchtest - wo jeder Popel eine riesige Umgebung mitzieht). Ob man da nun das Codesegment der Lib shared oder das Codesegment einer Anwendung ist egal.
An Dinge wie KDE denke ich noch nicht wirklich aber grundsätzlich hast Du schon recht. Wenn ich wirklich irgendwann mal Shared Libraries haben möchte dann wird das wohl über die GDT gehen (dafür ist diese ja vorgesehen, in meiner derzeitigen System-Struktur benötige ich gar keine GDT so das ich mich entschlossen habe in den ersten CPU-Versionen auch noch keine GDT zu unterstützen, das wird also ein optionales Feature) so das die Prozesse trotzdem noch ein individuelles ASLR haben. Auf jeden Fall ist dieses Thema in meinem Projekt noch in weiter Ferne.

Wenn du die Programme nicht auf Forkfreiheit hin umbauen möchtest, dann solltest du ein voll funktionsfähiges und relativ schnelles (im Rahmen der Möglichkeiten) fork bauen. Ansonsten wäre der richtige Weg, darauf zu verzichten und die Programme zu portieren.
Das erscheint mir ein wenig zu sehr in Schwarz-Weiß. Ich würde es bevorzugen zumindest für die Programme wo es geht auch einen Mittelweg zu haben. So eine BAD-POSIX-libc-Version ist sicher mit einigem Aufwand verbunden aber wenn ich dafür etliche Programme fast gratis portieren kann dürfte sich das wieder rechnen.

Achso, deine "normale" libc soll also kein POSIX anbieten?
Nein, also zumindest keine problematischen POSIX-Teile. Sowas wie pthread möchte ich schon immer anbieten. Ob der fork-Zusatz nun per Compilerschalter und #define kommt oder als zusätzlicher Wrapper drum herum gelegt wird spielt denke ich auch keine konzeptionelle Rolle, das kann ich immer noch später nach Lust und Laune entscheiden.

... kannst du dich einerseits bei einer großen Menge NOMMU-fähiger (Linux-)Software bedienen oder sie recht einfach anpassen (wenn sie schon Threads oder asynchrones I/O benutzen).
Da werde ich mich auf jeden Fall noch mal gründlich umsehen müssen. Es ist von mir aber schon beabsichtigt das sich das System für den User einem normalen Linux zumindest ähnlich anfühlt. Wenn sich das nicht vernünftig umsetzen lässt muss ich mich eben anderweitig umsehen, trotzdem möchte ich in den normalen User-Space möglichst wenig Aufwand investieren müssen.

Teilweise wirst du halt Programme nicht sinnvoll portieren können, dann solltest du es meiner Meinung nach aber auch eher lassen.
Klar, wenn es nicht wirklich geht dann muss ich eben einen anderen Weg finden eine benötigte Funktionalität anzubieten.

Du hast eine MMU, die du nicht benutzen willst - also simuliere sie bitte auch nicht in Software. :P
Ich hab keine MMU, zumindest nicht im herkömmlichen Sinne. Ich hab zwar Paging aber ich kann nicht so ohne weiteres das Paging-Directory wechseln, nebst dessen das im gesamten System immer nur ein Paging-Directory benutzt werden kann egal wie viele CPUs vorhanden sind (das Paging wird an einer Stelle systemweit/global verwaltet, selbst der Chip-Satz wird darauf zugreifen).

Am Ende landest du dann bei den gleichen Problemen wie Intel mit dem Pentium Pro, der zwar wirklich schnell war, aber eben nicht für 16-Bit-Code (Win95)... wenn Programm X nicht läuft, dann ist das blöde - wenn aber Programm X nur sehr langsam ist, dann fällt das direkt auf deine Plattform und dein OS zurück und hinterlässt einen schlechten Eindruck. Unabhängig davon, ob Programm X nun irgendwelche Kompatiblitätslayer benutzt oder nicht.
Das ist ein berechtigter Einwand. Aber gerade die von mir erdachte fork-Emulation dürfte deutlich schneller sein als wenn ich das mit Kopieren im Kernel erledigen tät, zumindest in den Fällen wo nach dem fork auch ein exec kommt (Programme die nur fork allein benutzen muss ich eh richtig portieren). Ich denke mit meiner fork-Emulation dürfte ich fast eine Geschwindigkeit erreichen wie sie Flat-Memory-Systeme mit richtigen fork schaffen (und zwar was das fork selber anbelangt aber auch die restliche Laufzeit), dafür verhält sich mein fork nicht ganz so wie POSIX es vorsieht. In all jenen Fällen wo diese Verhaltensabweichung akzeptabel ist, und ich hoffe dieser Anteil ist hoch, könnte ich somit mit insgesamt wenig Aufwand ein recht passables Ergebnis erzielen.


Zu Deinen Micro-Kernel-Gedanken dürfte Dir taljeth sicher recht geben, aber wir wollen uns nicht streiten wie Micro ein Kernel sein muss um als Micro-Kernel zu gelten. ;)


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

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 25. July 2011, 11:27 »
Zu Deinen Micro-Kernel-Gedanken dürfte Dir taljeth sicher recht geben, aber wir wollen uns nicht streiten wie Micro ein Kernel sein muss um als Micro-Kernel zu gelten. ;)
Nein, sobald LIOv2 drin ist, würde ich tyndur als Hybriden bezeichnen (wenn auch stark mikrokernellastig).
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 25. July 2011, 12:01 »
Hallo,


Ich hab mir mal den Unterschied zwischen fork und vfork genauer angesehen, im Prinzip ist meine Emulation eine Art Umwandlung von fork nach vfork in der nur ein paar mehr Möglichkeiten funktionieren als mit purem vfork. Der Vorteil meiner Idee wäre das alle Aspekte die von dem BAD-POSIX-Wrapper berücksichtigt werden für den Elternprozess nicht vom Kindprozess manipuliert werden können wogegen bei vfork nur die Dinge getrennt bleiben die der Kernel verwaltet. Also bevor ich überhaupt anfangen würde diese Idee zu realisieren muss ich erst einmal genau prüfen ob es in diesem Band an Möglichkeiten genug Programme gibt damit sich das ganze wirklich lohnt. Wenn ich hingegen gute Alternativen zu den üblichen User-Space-Programmen (Core-Utils, bash usw.) finde kann diese Idee natürlich komplett entfallen, das wäre mir eigentlich auch ganz recht.


Nein, sobald LIOv2 drin ist, würde ich tyndur als Hybriden bezeichnen (wenn auch stark mikrokernellastig).
Aha, dann hatte ich Dich wohl irgendwann einmal missverstanden, sorry.


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

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 25. July 2011, 15:23 »
Hallo,

Vor allem wäre dieser Overhead kompletter Unsinn wenn kurz nach den fork ein exec kommt und dann eh ein neuer Prozess erstellt wird. Gerade für diese Szenarien ist ein echtes fork im Kernel IMHO völliger Unsinn auf meiner Plattform.
Eben dafür gibt es ja vfork. Der Elternprozess bleibt so lange stehen, bis das Kind ein exec ausführt (und damit einen neuen Prozess erzeugt), außerdem kann das Kind auf den Elternprozess rückwirken.

Ich hab keine MMU, zumindest nicht im herkömmlichen Sinne. Ich hab zwar Paging aber [...]
Also doch eine MMU, denn die stellt Paging bereit. Deine ist nur etwas dümmer als alle anderen.

Ich denke mit meiner fork-Emulation dürfte ich fast eine Geschwindigkeit erreichen wie sie Flat-Memory-Systeme mit richtigen fork schaffen (und zwar was das fork selber anbelangt aber auch die restliche Laufzeit), dafür verhält sich mein fork nicht ganz so wie POSIX es vorsieht.
Damit ist es aber kein richtiges fork mehr und sollte auch nicht so bezeichnet werden. Ein richtiges fork kannst du nicht wirklich performant machen.

In all jenen Fällen wo diese Verhaltensabweichung akzeptabel ist, und ich hoffe dieser Anteil ist hoch, könnte ich somit mit insgesamt wenig Aufwand ein recht passables Ergebnis erzielen.
Das ist sicher. Aber du solltest dann nicht behaupten, dein System könne fork (wenn die Semantik aber größtenteils stimmt, ist der Patch für die Anwendungen aber ein sed-Befehl...).

Gruß,
Svenska

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 25. July 2011, 16:31 »
Hallo,


ich hab mal im Source-Code der bash 4.2 nach fork gesucht (vfork gab es nicht) und das gibt es nur in einer Funktion make_child(), diese gibt es aber 2 mal (in jobs.c und nojobs.c) und ist noch recht übersichtlich (200 bzw. 50 Zeilen lang mit vielen Kommentaren). Ich denke zumindest für die bash ist damit die Idee der Emulation erledigt da sich das dort wohl einfach nicht lohnt.


Vor allem wäre dieser Overhead kompletter Unsinn wenn kurz nach den fork ein exec kommt und dann eh ein neuer Prozess erstellt wird. Gerade für diese Szenarien ist ein echtes fork im Kernel IMHO völliger Unsinn auf meiner Plattform.
Eben dafür gibt es ja vfork. Der Elternprozess bleibt so lange stehen, bis das Kind ein exec ausführt (und damit einen neuen Prozess erzeugt), außerdem kann das Kind auf den Elternprozess rückwirken.
Meine Emulation würde aber mehr erhalten als vfork das tut und bei Programmen die fork benutzen (die dürften das üblicherweise aus einem triftigen Grund tun) ist das sicher relevant. Auch das Rückwirken auf den Elternprozess ist ja oft gerade nicht gewollt.

Damit ist es aber kein richtiges fork mehr und sollte auch nicht so bezeichnet werden.
Okay, es ist dann kein richtiges fork mehr aber da ich den Original-Source der zu portierenden Programme möglichst wenig anfassen möchte lass ich den Namen einfach so wie er ist. Ich werde auch nicht behaupten das mein System fork kann sondern höchstens das ich eine Library habe die fork für gewisse Fälle einigermaßen brauchbar emulieren kann.

Ein richtiges fork kannst du nicht wirklich performant machen.
Exakt, u.a. deswegen will ich sowas erst gar nicht im Kernel haben, das wäre wirklich "schon vom Design her kaputt".

Eine fork-Emulation in der Art von Cygwin möchte ich auch nicht ohne echte Not realisieren, Performance ist mir schon wichtig, auch bei nicht-nativen Programmen (den Grund hast Du ja gestern Abend ausführlich erläutert).


Also doch eine MMU, denn die stellt Paging bereit.
Aber mein Paging dient nicht dem Memory-Management in dem Sinne wie das bei Flat-Memory-Systemen benutzt wird (also ist es keine MMU!), nebst dessen das mein Paging das auch gar nicht könnte (ich beschränke die HW-Realisierung ganz bewusst auf das was ich auch wirklich benötige oder mir Performance bringt).

Deine ist nur etwas dümmer als alle anderen.
Du scheinst mein Paging-Konzept noch nicht zu kennen ansonsten würdest Du nicht solchen Quatsch schreiben. Schau Dir mal die MMU-Realisierung im MicroBlaze (Soft-CPU von Xilinx, auf dem wimre richtiges Linux läuft) an und dann reden wir noch mal über dumme MMUs. ;)


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

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 25. July 2011, 20:47 »
Hallo,

Eine fork-Emulation in der Art von Cygwin möchte ich auch nicht ohne echte Not realisieren
Die Idee sieht sogar verdammt gebrauchbar aus. Langsam, aber korrekt. ;-)

Deine ist nur etwas dümmer als alle anderen.
Du scheinst mein Paging-Konzept noch nicht zu kennen ansonsten würdest Du nicht solchen Quatsch schreiben. Schau Dir mal die MMU-Realisierung im MicroBlaze (Soft-CPU von Xilinx, auf dem wimre richtiges Linux läuft) an und dann reden wir noch mal über dumme MMUs. ;)
Würde mich mal interessieren. Kannst du das bei Langeweile (Wetter ist eh schlecht) mal in einem neuen Thread näher ausführen? ;-)

Gruß,
Svenska

erik.vikinger

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


Die Idee sieht sogar verdammt gebrauchbar aus. Langsam, aber korrekt. ;-)
Hm, korrekt vermutlich schon, langsam aber mit absoluter Sicherheit.
Ob ich das auch auf meiner Plattform hinbekomme kann ich gar nicht so einfach sagen, dazu müsste die fork-Implementierung die gesamte LDT analysieren und da es auch Segmente geben kann die Write-Only sind dürfte das Auslesen schwer werden, spätestens bei Code-Segmenten ist dann der Kernel gefragt weil die im User-Mode weder lesbar noch beschreibbar sind (aber das lässt Cygwin ja auch von Windows erledigen). Was bleibt ist das es sich um Kopieren handelt und das möchte ich möglichst vermeiden. Kopieren finde ich grundsätzlich doof!

Würde mich mal interessieren. Kannst du das bei Langeweile (Wetter ist eh schlecht) mal in einem neuen Thread näher ausführen? ;-)
Okay, aber dafür musst Du mir helfen für das zweite M eine passende Alternative zu finden. ;)


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

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #18 am: 25. July 2011, 21:36 »
Würde mich mal interessieren. Kannst du das bei Langeweile (Wetter ist eh schlecht) mal in einem neuen Thread näher ausführen? ;-)
Okay, aber dafür musst Du mir helfen für das zweite M eine passende Alternative zu finden. ;)
Erst danach. Und wenn ich dann immernoch der Meinung bin, dass ein M da passend wäre, dann ist das eben so. ;-)

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #19 am: 25. July 2011, 21:49 »
Das zweite M heißt Mapping, hab ich dir doch schonmal gesagt. ;)

Abgesehen davon hat Svenska recht, dass du auch Memory Management damit machst, auch wenn du es noch so sehr leugnest.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

 

Einloggen