Autor Thema: Neuen Prozess laden/starten (Mikrokernel)  (Gelesen 22610 mal)

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« am: 03. October 2010, 16:46 »
Wie im Titel schon zu sehen, geht es mir darum mal darüber zu diskutieren wie man (am besten) einen neuen Prozess lädt und startet. Das ganze sollte aus Sicht eines Mikrokernel betrachtet werden, wo auch der VFS-Service nicht im Kernel ist.

Im besonderen geht es mir darum, wie man es am besten löst, das ja im Normalfall auch verschiedenste Libraries geladen werden müssen.

Ich habe mir über diesen Libraries-Kram noch gar keine richtigen Gedanken gemacht, aber im Moment kann bei mir nur ein neuer Prozess geladen werden, in dem man eine Funktion/Syscall CreateProcess() aufruft, der man nen Pointer zu der startenden Datei mitgibt, sprich die Datei muss schon im UserSpace geladen sein.

Das ist natürlich beim Booten ganz vorteilhaft, weil ich da alle als Module geladenen Dateien im Kernel eingeblendet habe und so bloß diese Funktion aufrufen muss.
Aber normalerweise übergibt man doch solch einer Funktion einen Dateinamen, oder?

Bei mir sieht es dann auch so aus, das ich einen neuen Prozess erstelle und dort einen neuen Kernelthread, welcher dann die ganze Arbeit übernimmt. Er (der KernelThread) mappt also die Datei rein und parst sie und erstellt dann nen UserModeThread mit der Main-Funktion.

Wie macht ihr das oder wie wird das im Normalfall gemacht?

Ich dachte daran, diese CreateProcess()-Funktion beizubehalten, aber ne Verbindung zum VFS-Service aufzubauen und dann die entsprechende Datei in den neu erstellten Prozess zu laden (vom Kernel aus) und dann erst zu parsen. Wie klingt das?

Wenn ich das so machen würde, dann könnte ich auch einfach über diese Verbindung (zum VFS-Service) die nötigen Libraries laden und einbinden.

So meine letzte Frage bezieht sich dann auf das Henne-Ei-Problem, das ja auch der VFS-Service erstmal gestartet werden muss. Wie macht man das ohne das Dateien geladen werden können (was jetzt nicht so schwierig sein sollte)? Selbst wenn man das geschafft hat, wie würde man dann erreichen das der VFS-Service selbst auch Libraries nutzen kann (im Moment linke ich die einfach mit zu der Executeable dazu)?

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 03. October 2010, 19:23 »
Hallo,


also ich habe vor dafür einen User-Mode-Prozess zu nehmen so das CreateProzess() erstmal auf IPC basiert. Dieser exec-Prozess lädt dann die Datei in den Speicher und macht daraus eine simple Fat-Binary (fürs erste ist sie das bereits), also wenn ich mal Librarys unterstützen sollte dann wird das alles noch vor dem Kernel gemacht. Der Kernel bietet dann einen speziellen Syscall dem die fertig gelinkte Executable in einem simplen Format bereits im Speicher übergeben werden muss. Der Kernel erstellt dann neue Segmente und kopiert den Inhalt der Executable aus dem User-Buffer vom exec-Prozess in die neuen Segmente, anschließend soll dann ein erster Thread erstellt werden der dann den Entry-Point ausführt. Damit ist dieser spezielle Syscall fertig. Diese Variante hat den Vorteil das der Kernel ein Micro bleibt und sich um nichts kümmern muss auch das laden und linken von Librarys wird vorher gemacht.

Der VFS selber gehört bei mir zum Boot-Image, ist also schon im RAM wenn der Kernel zum Leben erwacht. Die ganzen Dateisystemtreiber usw. kommen ebenfalls aus ner ROM-Disk die zusammen mit dem Kernel und den ersten Prozessen in den RAM kommt, auf einem PC würde ich das als Module die von GRUB geladen werden implementieren.


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 #2 am: 03. October 2010, 19:40 »
Zitat von: erik
Der VFS selber gehört bei mir zum Boot-Image, ist also schon im RAM wenn der Kernel zum Leben erwacht. Die ganzen Dateisystemtreiber usw. kommen ebenfalls aus ner ROM-Disk die zusammen mit dem Kernel und den ersten Prozessen in den RAM kommt, auf einem PC würde ich das als Module die von GRUB geladen werden implementieren.
Also wird dein VFS-Service auch alle Libraries die er benötigt schon statisch gelinkt haben.?

Mich hätte halt interessiert ob jemand eine Idee hat wie man das Lösen könnte ohne das man sich alzu sehr verrenken müsste?

Zitat von: erik
also ich habe vor dafür einen User-Mode-Prozess zu nehmen so das CreateProzess() erstmal auf IPC basiert. Dieser exec-Prozess lädt dann die Datei in den Speicher und macht daraus eine simple Fat-Binary (fürs erste ist sie das bereits), also wenn ich mal Librarys unterstützen sollte dann wird das alles noch vor dem Kernel gemacht. Der Kernel bietet dann einen speziellen Syscall dem die fertig gelinkte Executable in einem simplen Format bereits im Speicher übergeben werden muss.
Das hätte natürlich den Vorteil das man sich nicht auf ein Dateiformat festlegen muss und es wäre die perfekte Anwendung für fork().

Also wenn ich es richtig verstanden habe, willst du per IPC nen Art runtimeloader aufrufen. Dieser läd die Datei erstellt nen Prozess-Image und könnte nen Fork machen. So umgeht man den Kernel fast ganz und macht das meiste im UserSpace.

Ist ne Variante, aber da müsste man dann sehen, wie man es macht das man warten kann bis der Prozess zu Ende ist und sowas.

Ich würde halt das Laden und das Parsen im Kernel machen, in einem neuen Prozess und KernelThread.

Edit::

Was ich noch vergessen habe, wie bekommt ihr die Parameter die dem Programm übergeben werden in das Programm?
« Letzte Änderung: 03. October 2010, 19:58 von FlashBurn »

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 03. October 2010, 21:40 »
Hallo,

dein VFS muss unabhängig von allem sein, was es zum Zeitpunkt des Starts deines VFS nicht gibt.

Konkret: Wenn du das VFS startest, dann darf es auf keinen nicht geladenen Libraries basieren, sofern du keine andere Möglichkeit hast, Libraries nachzuladen. Die könntest du vom Bootloader als Module laden lassen, müsstest sie halt nur entsprechend mit dem System verknüpfen. Ob das lohnt - keine Ahnung. Welche Libraries willst du denn deinem VFS anhängen?

Erik nimmt eine Lebendgeburt des Systems vor, d.h. der Bootloader lädt als freistehender Prozess die Libraries und baut die benötigten Datenstrukturen auf, ehe der Kernel läuft.

Unter Linux gibt es "binfmt" (man definiert vorher eine Liste mit Magic Numbers oder andere Kriterien) werden Dateien beim Versuch, sie auszuführen, an einen entsprechenden (ebenfalls definierten) Interpreter übergeben. Ist einsetzbar für Shellscripte, Java-Anwendungen und architekturfremde Dateien via Qemu, wurde aber auch für DOS-Anwendungen (via dosemu) verwendet. ELF-Dateien erhalten eine Sonderbehandlung, der ELF-Loader ist /lib/ld-linux.so.2 und wird immer (oder nur bei dynamischen ELFs?) mitgeladen.

Gruß,
Svenska

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 04. October 2010, 10:20 »
Hallo,


Also wird dein VFS-Service auch alle Libraries die er benötigt schon statisch gelinkt haben.?
Ja, in VFS ist ja nun auch wirklich nicht viel Library-Zeugs drin (der dürfte noch nicht mal ne halbwegs vollständige libc brauchen).

Mich hätte halt interessiert ob jemand eine Idee hat wie man das Lösen könnte ohne das man sich alzu sehr verrenken müsste?
Für die ersten paar Prozesse sollte man lieber auf solche Spielchen verzichten. Wie viel HDD-Platz kann man dadurch schon gewinnen? Sicher nicht so viel das sich dieser Aufwand lohnt.

Das hätte natürlich den Vorteil das man sich nicht auf ein Dateiformat festlegen muss
Der Kernel muss nur ein einziges und ganz simples Executable-Format unterstützen, alles andere bleibt im User-Mode. Bei mir werde ich aber erstmal dieses simple Format immer benutzen so das mein exec-Prozess nichts weiter machen muss außer die Datei in den Speicher zu laden.

und es wäre die perfekte Anwendung für fork().
Also fork() kann und will ich nicht unterstützen. Ich möchte schon dass das eigentliche Anlegen eines neuen Prozesses vom Kernel gemacht wird und dort auch ein neues Executable reingeladen wird.

Also wenn ich es richtig verstanden habe, willst du per IPC nen Art runtimeloader aufrufen. Dieser läd die Datei erstellt nen Prozess-Image und könnte nen Fork machen. So umgeht man den Kernel fast ganz und macht das meiste im UserSpace.
Ja, bis auf das fork hast Du mich richtig verstanden.

Ist ne Variante, aber da müsste man dann sehen, wie man es macht das man warten kann bis der Prozess zu Ende ist und sowas.
Mein exec-Prozess soll die PID an seinen (IPC-basierenden) Auftraggeber zurückmelden und was der mit der PID macht ist dann seine Angelegenheit.

Ich würde halt das Laden und das Parsen im Kernel machen, in einem neuen Prozess und KernelThread.
Ich las das laden lieber im User-Mode so das der Kernel nur das (simple) parsen machen muss.

Was ich noch vergessen habe, wie bekommt ihr die Parameter die dem Programm übergeben werden in das Programm?
Ich möchte das über einen Parameterblock machen der dem exec-Prozess gegeben wird. Dieser Block stamt von der CreateProzess()-Implementierung in der libc und der exec-Prozess gibt das dann dem Kernel mit welcher diesen Block hinten an die const-Section anhängt. Ein Pointer darauf ist dann das einzigste Parameter das der Entry-Point bekommt, dieser Code (auch aus der libc) zerlegt dann diesen Block in Umgebungsvariablen, geerbte Handles und die Parameter. Auf diese Weise bleibt das alles in der libc.


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 #5 am: 04. October 2010, 12:25 »
Wenn du was POSIX-artiges machst, musst du übrigens noch viel mehr an den neuen Prozess weitergeben als nur Parameter. Beispielsweise Umgebungsvariablen oder Dateideskriptoren (wie auch immer die bei dir intern funktionieren).
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 04. October 2010, 13:09 »
Zitat von: taljeth
Wenn du was POSIX-artiges machst, musst du übrigens noch viel mehr an den neuen Prozess weitergeben als nur Parameter. Beispielsweise Umgebungsvariablen oder Dateideskriptoren (wie auch immer die bei dir intern funktionieren).
Das wäre meine nächste Frage gewesen. Wie man z.B. das mit den Dateidiskriptoren lösen könnte.

Ich dachte daran, dass das der erzeugende Prozess selber machen sollte, so würde kein Sicherheitsproblem entstehen.
Er (der Prozess der einen neuen gestartet hat) schickt dem VFS-Service eine Nachricht das alle seine Dateidiskriptoren an einen bestimmten Prozess kopiert werden (oder was genau muss mit den Dateidiskriptoren gemacht werden, bei POSIX?).

Die Umgebungsvariablen würde ich im App-Server verwalten, aber auch da habe ich noch gar keine Vorstellung was das genau bedeutet, wozu die verwendet werden usw.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 04. October 2010, 13:28 »
POSIX kopiert beim fork alle Deskriptoren, ja. Und beim exec schließt es wieder alle, die FD_CLOEXEC gesetzt haben. Kopieren heißt dabei das, was dup() macht. Es sind also zwei Deskriptoren, die sich aber beispielsweise einen gemeinsamen Zeiger für die Position in der Datei teilen. Lies dir am besten mal ein paar Manpages durch, vor allem von dup und fork.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 04. October 2010, 13:38 »
Zitat von: taljeth
Es sind also zwei Deskriptoren, die sich aber beispielsweise einen gemeinsamen Zeiger für die Position in der Datei teilen.
Du solltest mir eventuell erläutern was ein Dateidiskriptor ist, ich glaube ich habe das mit dem Dateihandle (einfach ne ID) verwechselt. Denn der Diksriptor ist doch der Client-Teil des Handles oder?

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 04. October 2010, 13:52 »
Also ein Dateideskriptor ist eigentlich schon das, was du wohl mit einem Handle meinst. Einfach ein Integer, den du z.B. von open() zurückkriegst. Ich bin mir jetzt nicht ganz sicher, was die Deskriptoren im Kernel adressieren. Ich glaube, es gibt ein paar lokale Eigenschaften, die jeder Deskriptor für sich hat (z.B. die Flags), und ein paar, die sie sich teilen (in der open file description).

Aber so ganz blicke ich da auch noch nicht durch. ;)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 04. October 2010, 14:10 »
Zitat von: taljeht
Also ein Dateideskriptor ist eigentlich schon das, was du wohl mit einem Handle meinst. Einfach ein Integer, den du z.B. von open() zurückkriegst.
Was mich verwirrt hat, war das du davon gesprochen hast das ein solcher Diskriptor die Position in der Datei speichert.

So wie ich mir das vorgestellt habe, wird das alles in der libc gemacht, sprich du sagst dem VFS-Service immer welchen 4kb Block du gerade brauchst und den Rest macht der libc Code.

Der VFS-Service soll bei mir eigentlich wirklich nur minimale Sachen machen und der Rest wird von den Libraries gemacht.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 04. October 2010, 14:58 »
Hallo,


das mit den File-Descriptors finde ich auch etwas verwirrend. Ich möchte das auch gerne in der libc verbergen, z.B. die Verwaltung des aktuellen Datei-Pointers. Der Integerrückgabewert von open wäre dann einfach nur ein Index in eine Liste von FILE* und fopen liefert eben direkt diesen Pointer. Bei geerbten File-Descirptors hätte ich mir vorgestellt das der Eltern-Prozess als eine Art Vermittler fungiert und alles über ihn läuft. Auf diese Weise würde der VFS nicht mit solchen Dingen belästigt werden.
Für den VFS stelle ich mir vor das dieser nur create/delete/open/close/read/write/resize/rename anbietet und sonst nichts.

Bei den Umgebungsvariablen bin ich mir ebenfalls etwas unschlüssig. Die werden doch auch vererbt? Sonst ginge es ja nicht das 2 verschiedene Instanzen einer Shell unterschiedliche Umgebungsvariablen haben. Wimre wurden bereits unter DOS die Umgebungsvariablen vererbt.


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: 04. October 2010, 16:19 »
Problem mit Dateideskriptoren auf POSIX-Art ist, dass du die Dateideskriptoren an neue Prozesse vererbst. Du hast also hinterher zwei Deskriptoren in zwei unterschiedlichen Prozessen, die aber auf dieselbe open file description zeigen und sich damit z.B. den Dateizeiger teilen. Das in der libc zu verstecken, wird sehr schwer.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 04. October 2010, 16:27 »
Sowas müsste man dann in einer "libposix" verstecken und die müssten beide miteinander kommunizieren.

Wozu braucht man sowas bzw. wo wird es angewendet?

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 04. October 2010, 16:30 »
Das merkst du dann, wenn du es nicht implementierst und ein Programm fällt auf die Schnauze. ;)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 04. October 2010, 16:37 »
Das war nicht wirklich hilfreich ;)

Nee, aber mal ehrlich, in welcher Situation braucht man sowas? Ich meine das bedeutet ja auch, das wenn ein Prozess die Datei liest und der Pointer verändert wird, das dann der andere Prozess an der neuen Stelle liest oder?

Das klingt so als wenn man sich das hat einfallen lassen um Multithreading per Multitasking zu simulieren. Klingt also nach Unix ;)

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 04. October 2010, 16:43 »
Mag schon sein. Aber du machst POSIX, um Unix-Programme laufen zu lassen.

Dafür, dieselbe Datei in vielen Prozessen gleichzeitig offen zu haben, gibt es natürlich ein sehr einfaches Beispiel: Standardein- und -ausgabe. Jeder Prozess vererbt den Deskriptor für das Terminal einfach weiter. Das ist natürlich ein Character Device und insofern ein bisschen anders.

Aber jetzt denk mal weiter und leite die Standardausgabe in eine Datei um. Du willst, dass auch die Ausgabe der Kindprogramme mitgeloggt wird, und du willst nicht, dass sich die Ausgaben der verschiedenen Prozesse gegenseitig überschreiben, weil ihr Dateizeiger unabhängig ist.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 04. October 2010, 16:48 »
Zitat von: taljeth
Aber jetzt denk mal weiter und leite die Standardausgabe in eine Datei um. Du willst, dass auch die Ausgabe der Kindprogramme mitgeloggt wird, und du willst nicht, dass sich die Ausgaben der verschiedenen Prozesse gegenseitig überschreiben, weil ihr Dateizeiger unabhängig ist.
Wo wir wieder bei so einer Unix-Sache wären, ich hatte nämlich nicht vor die Standardausgabe als Datei anzulegen, sondern das muss ich emulieren. Na mal sehen wie ich das alles hinbekomme.

Die Kinderprozesse würden bei mir ihr eigenes "Fenster" bekommen.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #18 am: 04. October 2010, 16:52 »
Wie läuft das denn bei dir, wenn es keine Datei ist? Das ist übrigens keine Unix-Spezialität, sondern der C-Standard sieht so Sachen wie FILE* stdout vor...
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #19 am: 04. October 2010, 16:58 »
Warum wurde C "erfunden" und woran hat sich der C-Standard orientiert? Unix, richtig ;)

Ich wollte das in eine Pipe schreiben (ist keine Datei) und es dann in einem "Konsolen"-Fenster ausgeben.

Musst du eigentlich irgendwo festlegen, das du willst, das alle Diskriptoren kopiert werden bzw. nicht kopiert werden? Oder musst du dann jedes Mal ne neue Standardausgabe öffnen wenn du nicht die alte nutzen willst?

 

Einloggen