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

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #20 am: 04. October 2010, 17:40 »
Naja, Pascal hat auch input und output, wenn auch kein stderr, und das ist in Bezug auf Unix unverdächtig, oder? ;)

Was ist genau der Unterschied zwischen einer Pipe deiner Bauart und einer Datei? Im Zweifelsfall müssen sich die Prozesse dann halt eine Pipe statt einer Datei teilen. Und kann man bei dir die Ausgabe überhaupt nicht in eine "richtige" Datei umleiten?
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 #21 am: 04. October 2010, 21:07 »
Hallo,


Problem mit Dateideskriptoren auf POSIX-Art ist, dass du die Dateideskriptoren an neue Prozesse vererbst.
Okay, wobei trotzdem noch die Frage bleibt wo das verwendet wird, von stdin/stdout/stderr mal abgesehen.

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.
Ich wollte das so machen das im erbenden Prozess eben für alles beim vererbenden Prozess nachgefragt wird. Das macht zwar eine Menge Kommunikationsoverhead aber wann wird das schon verwendet (für echte Dateien)? Bei Streams sieht die Sache wieder etwas anders (leichter) aus.
Was mir dann sicher etwas Kopfweh bereitet ist wenn der erbende Prozess seinerseits weiter vererbt, soll dann jeder Prozess direkt mit seinem unmittelbaren Vorfahren kommunizieren oder am besten mit dem Prozess der den original File-Descriptor hat. Was ist wenn ausgerechnet der Prozess mit dem original File-Descriptor diesen schließt nachdem er ihn schon an mehrere Kinder vererbt hat, wer wird dann der Chef über diesen File-Descriptor?

Das in der libc zu verstecken, wird sehr schwer.
Warum? Gehört open/close/read/.... nicht mehr zur libc? Und selbst wenn nicht dann hab ich eben eine libcOS die ein bisschen mehr enthält als nur das was der C-Standard vorgibt.


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 #22 am: 04. October 2010, 22:00 »
Also mit DOS 2.0 wurden Unix-Pipes eingeführt und da kam auch eine Abstraktion von stdin/stdout/stderr mit rein. Sicher hat das Unix-Ursprünge, aber so schlecht kann das Konzept ja nun auch nicht gewesen sein... wenn es bereits damals übernommen wurde.

Übrigens: "Everything is a file" ist ein Unix-Konzept. Windows NT nutzt dieses auch, versteckt es aber vor dem Benutzer. Guck dir mal "dd" für Win32 an und rufe damit "dd --list" auf.

Zitat von: erik
Warum? Gehört open/close/read/.... nicht mehr zur libc?
Bei Minix sind open/close/read Syscalls. Von der libc werden dann Wrapper zur Verfügung gestellt, die diese Syscalls auf POSIX-Standard abbilden.

Je näher du deine Syscalls an dieses Interface annäherst, desto kleiner (und schneller) wird dein Wrapper und desto weniger Aufwand hast du beim Portieren. Und sofern du jemals einen Webbrowser möchtest, wirst du wahrscheinlich lieber WebKit portieren wollen als selbst eine Javascript-Engine zu schreiben... mach dir Portierungen nicht sehr viel schwerer als nötig. Gleiches gilt für FlashBurn.

Grüße,
Sebastian

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #23 am: 04. October 2010, 23:19 »
Problem mit Dateideskriptoren auf POSIX-Art ist, dass du die Dateideskriptoren an neue Prozesse vererbst.
Okay, wobei trotzdem noch die Frage bleibt wo das verwendet wird, von stdin/stdout/stderr mal abgesehen.
Ist stdin/out/err denn nicht schon Beispiel genug?

Aber das ist eigentlich die Methode, wie ein Unix-Prozess mit seinen Kindprozesses kommuniziert: fork(), pipe(), exec(),
das eine Ende selber behalten, das andere Ende ans Kind vererben und dann schließen.

Zitat
Was mir dann sicher etwas Kopfweh bereitet ist wenn der erbende Prozess seinerseits weiter vererbt, soll dann jeder Prozess direkt mit seinem unmittelbaren Vorfahren kommunizieren oder am besten mit dem Prozess der den original File-Descriptor hat. Was ist wenn ausgerechnet der Prozess mit dem original File-Descriptor diesen schließt nachdem er ihn schon an mehrere Kinder vererbt hat, wer wird dann der Chef über diesen File-Descriptor?
Offensichtlich ist das Konzept also nicht ganz optimal. ;)

Ich schätze, um das vernünftig zu implementieren braucht man irgendeine zentrale Stelle.

Zitat
Warum? Gehört open/close/read/.... nicht mehr zur libc? Und selbst wenn nicht dann hab ich eben eine libcOS die ein bisschen mehr enthält als nur das was der C-Standard vorgibt.
Ich meinte, komplett innerhalb der libc des Prozesses, ohne dass irgendein Service die ganze Sache verwaltet. Die libc kennt eben nur den Zustand eines Prozesses und ist wahrscheinlich nur bedingt geeignet, alles zu synchronisieren.
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 #24 am: 05. October 2010, 11:12 »
Hallo,


Ist stdin/out/err denn nicht schon Beispiel genug?
Jein, es sind eben keine echten Dateien. Ich wüste gerne ob sowas auch wirklich für richtige Dateien gemacht wird. Bei Output-Streams ist ein write eher ein append und die verschiedenen Zugriffe der Clients müssen zwar serialisiert werden aber die exakte Reihenfolge ist IMHO eher nachrangig. Über Input-Streams muss ich aber auch noch mal nachdenken.

Aber das ist eigentlich die Methode, wie ein Unix-Prozess mit seinen Kindprozesses kommuniziert: fork(), pipe(), exec(), das eine Ende selber behalten, das andere Ende ans Kind vererben und dann schließen.
Da ich weder fork noch exec habe muss ich dieses Code-Stückchen eh neu schreiben und ein Ende einer Pipe zu vererben ohne es selber zu behalten erschient mir jetzt nicht so extrem schwierig zu sein. Die größte Schwierigkeit sehe ich bei gemeinsam benutzten Ressourcen wo wirklich Kollisionen auftreten können (eben Dateien wegen dem File-Pointer).

Offensichtlich ist das Konzept also nicht ganz optimal. ;)
Ja, offensichtlich, aber das ist nicht mein dringendstes Problem

Ich schätze, um das vernünftig zu implementieren braucht man irgendeine zentrale Stelle.
Um die würde ich gerne rum kommen, vor allem weil Dein Beispiel mit der Pipe ja eher nur genau 2 Prozesse trifft. Ich hoffe das es reicht wenn die libc's der beteiligten Prozesse es schaffen sich zu einigen.

Die libc kennt eben nur den Zustand eines Prozesses und ist wahrscheinlich nur bedingt geeignet, alles zu synchronisieren.
Hm, weis nicht aber die embedded Variante von Qt macht das wimre auch so. Da ist jeder prinzipiell geeignet der Master zu sein aber nur einer wird es.


Übrigens: "Everything is a file" ist ein Unix-Konzept. Windows NT nutzt dieses auch, versteckt es aber vor dem Benutzer.
Ich weiß, aber so toll finde ich das ehrlich gesagt nicht. Das klingt für mich irgendwie danach unterschiedliche Dinge über einen Kamm zu scheren.

Von der libc werden dann Wrapper zur Verfügung gestellt, die diese Syscalls auf POSIX-Standard abbilden.
Bei mir wird das eben auf was anderes abgebildet.

Und sofern du jemals einen Webbrowser möchtest, wirst du wahrscheinlich lieber WebKit portieren wollen als selbst eine Javascript-Engine zu schreiben... mach dir Portierungen nicht sehr viel schwerer als nötig.
Davon träume ich noch nicht einmal. In meiner derzeitigen Planung hat meine Plattform nur RS232 als Verbindung zur Außenwelt, als nächstes sollen dann SATA (dafür wollte ich auf handlesübliche AHCI-basierte Controller zurückgreifen) und Ethernet (das würde ich gerne selber im FPGA implementieren) kommen. Danach kommt USB (auch gekaufte Controller) damit dann auch Tastatur und Maus möglich werden und danach kommt dann vielleicht mal ne Grafikkarte (wobei ich noch keine Vorstellung habe ob ich da was eigenes möchte oder was fertiges, PC kompatibel wird jedenfalls nichts nützen da ich keine I/O-Ports habe).


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 #25 am: 05. October 2010, 11:36 »
Ist stdin/out/err denn nicht schon Beispiel genug?
Jein, es sind eben keine echten Dateien. Ich wüste gerne ob sowas auch wirklich für richtige Dateien gemacht wird.
Was macht eine "echte" Datei denn bei dir aus? Das einzige besondere an stdin/out/err ist, dass man rein sequenziell Zugriffe hat. Der Dateideskriptor dafür kann auf ein Terminal zeigen, aber auch auf eine Pipe oder eine Datei auf einem Dateisystem.

Zitat
Bei Output-Streams ist ein write eher ein append und die verschiedenen Zugriffe der Clients müssen zwar serialisiert werden aber die exakte Reihenfolge ist IMHO eher nachrangig. Über Input-Streams muss ich aber auch noch mal nachdenken.
Zumindest brauchst du dann ein paar Synchronisationspunkte, z.B. das Beenden eines Prozesses. Wenn ein Prozess auf das Ende eines Kindprozesses wartet und danach eine Meldung ausgibt, erwartet jeder, dass diese Meldung selbstverständlich nach allen Meldungen des Kinds kommt.

Bei Ausgaben kannst du dich vermutlich noch irgendwie darum herummogeln, indem du die unterschiedlichen Ausgaben erst im Dateisystem-Server in irgendeiner Reihenfolge zusammenbastelst - die Clients interessieren sich dafür nicht. Aber wenn du eine Eingabeumleitung benutzt und alle Eingaben aus einer Datei liest, dann müssen Vater- und Kindprozess zwingend denselben Dateizeiger benutzen, sonst werden Dinge zweimal gelesen.
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 #26 am: 05. October 2010, 14:05 »
Hallo,


Was macht eine "echte" Datei denn bei dir aus?
Ich denke es ist gerade der File-Pointer, der bei allen Clients synchron sein muss, der ein Problem darstellt. Zumindest fällt mir da auf die schnelle keine elegante Lösung ein. Streams/Pipes (egal ob Input oder Output) haben das nicht in der Form.

Der Dateideskriptor dafür kann auf ein Terminal zeigen, aber auch auf eine Pipe oder eine Datei auf einem Dateisystem.
Ich denke selbst wenn stdout auf ne Datei zeigt muss das erst den Prozess interessieren der den original-Descriptor hat (für alle anderen bleibt das ein simpler Output-Stream).

Zumindest brauchst du dann ein paar Synchronisationspunkte, ...
Ja, es ist sicher nötig an ein paar Punkten ein flush zu benutzen.

Aber wenn du eine Eingabeumleitung benutzt und alle Eingaben aus einer Datei liest, dann müssen Vater- und Kindprozess zwingend denselben Dateizeiger benutzen, sonst werden Dinge zweimal gelesen.
Stimmt, hier muss man gut aufpassen. Bei Input-Streams werde ich wohl auf jeden Fall besser fahren wenn der erbende Prozess immer bei seinem direkten Vorfahren nachfragt, so das nichts was die libc im Elternprozess zwar schon eingelesen hat (in nen Buffer o.ä.) aber noch nicht verwendet wurde verloren geht.

Was ich mich aber noch frage ist: Was ist wenn in einer langen Kette an Vererbungen mittendrin ein Prozess gekillt wird?


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 #27 am: 05. October 2010, 14:22 »
Damit bist du wieder bei deinem "nicht so dringenden" Problem, das ich oben schon angesprochen hatte. ;)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #28 am: 05. October 2010, 15:47 »
Das eigentliche Problem ist doch, das diese "alles ist eine Datei" Geschichte vorallem auf monolithische Kernel zugeschnitten ist und man so bei einem Mikrokernel einen IPC Overhead hat den man nicht haben müsste.

Das nächste Problem sehe ich darin wie man z.B. den Stdout implementiert. Ich meine wie soll ich mir das am lesenden Ende vorstellen und wo werden die Daten wie gespeichert?
Würde man das ganze als Pipe implementieren ist das schon wesentlich einfacher.

Eine Sache habe ich aber noch nicht ganz verstanden, File-Handles werden doch pro Prozess und nicht global rausgegeben, oder? Wie stellt man dann sicher das 2 Handles auch ein und die selbe Datei ansprechen?

Weil ansonsten könnte ich die Stout/-err/-in Geschichte einfach per Pipe lösen.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #29 am: 05. October 2010, 16:27 »
Hallo,

Das eigentliche Problem ist doch, das diese "alles ist eine Datei" Geschichte vorallem auf monolithische Kernel zugeschnitten ist und man so bei einem Mikrokernel einen IPC Overhead hat den man nicht haben müsste.
Das mag sein, aber es vereinfacht vor allem den Userspace extrem und stelle eine einheitliche, flexible Schnittstelle zur Verfügung. Alternativ musst du dir halt etwas ähnliches einfallen lassen oder aber für jedes Subsystem eine eigene Schnittstelle definieren, die du dann exportierst.

Der Vorteil ist, dass du die Schnittstelle zwischen Kernel und Treiber komplett ändern kannst und trotzdem irgendwie (read/write) kompatibel zum Userspace bleibst - es ändern sich nur ein paar Dateinamen - was du mit den reinen exportierten APIs nicht kannst. Die APIs kannst du natürlich direkt exportieren (z.B. DOS-basierte Windowse). Die Darstellung als Datei ist nur der nullte Wrapper.

Das nächste Problem sehe ich darin wie man z.B. den Stdout implementiert. Ich meine wie soll ich mir das am lesenden Ende vorstellen und wo werden die Daten wie gespeichert?
Würde man das ganze als Pipe implementieren ist das schon wesentlich einfacher.
Also DOS nutzt für seine Pipes temporäre Dateien. Daher auch die Begrenzung, dass maximal 2KB in einer Pipe sein können

Weil ansonsten könnte ich die Stout/-err/-in Geschichte einfach per Pipe lösen.
Kannst du, oder andersrum. Beispiel wieder DOS: Pipes sind Dateien.

Gruß

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #30 am: 05. October 2010, 16:40 »
Zitat von: svenska
Kannst du, oder andersrum. Beispiel wieder DOS: Pipes sind Dateien.
Aber nur wenn du nach der "alles ist eine Datei" Philosophie handelst. Zumal das immernoch nicht meine Frage beantwortet wie das auf der lesenden Seite aussieht.

Was ich halt nicht ganz verstehe ist, man liest bis zum EOF, soweit so gut, aber was passiert wenn man ftell() aufrufen würde und liest man dann das nächste mal einfach wieder bis zum EOF und wie wird man benachrichtig das neue Daten vorhanden sind?

Im Endeffekt ist zwar nach außen alles eine Datei, aber dahinter muss man sich immer was spezielles einfallen lassen, damit es funktioniert. Warum dann nicht den Layer der Datei weglassen?

Zitat von: svenska
Der Vorteil ist, dass du die Schnittstelle zwischen Kernel und Treiber komplett ändern kannst und trotzdem irgendwie (read/write) kompatibel zum Userspace bleibst - es ändern sich nur ein paar Dateinamen - was du mit den reinen exportierten APIs nicht kannst. Die APIs kannst du natürlich direkt exportieren (z.B. DOS-basierte Windowse). Die Darstellung als Datei ist nur der nullte Wrapper.
Ich sehe da keinen Vorteil. Entweder es ändert sich die exportierte API und beide Seiten (Kernel und Treiber) müssen geändert werden oder es ändert sich das Protokoll welches hinter read/write kommt, dann muss genauso neugeschrieben werden.

Aber mal zum Punkt fexible API. Ich habe in letzter Zeit oft mit dem Gedanken gespielt das ne Text-API (nach XML Art) ziemlich flexible wäre.?

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #31 am: 05. October 2010, 18:12 »
Hallo,


Damit bist du wieder bei deinem "nicht so dringenden" Problem, das ich oben schon angesprochen hatte. ;)
Allerdings, ich schreibe dann mal meine Gedanken dazu auf meine (bereits ziemlich große) ToDo-Liste.


Das eigentliche Problem ist doch, das diese "alles ist eine Datei" Geschichte vorallem auf monolithische Kernel zugeschnitten ist und man so bei einem Mikrokernel einen IPC Overhead hat den man nicht haben müsste.
Genau so sehe ich das auch.

Das nächste Problem sehe ich darin wie man z.B. den Stdout implementiert. Ich meine wie soll ich mir das am lesenden Ende vorstellen und wo werden die Daten wie gespeichert?
Würde man das ganze als Pipe implementieren ist das schon wesentlich einfacher.
stdout usw. müssen ja irgendwo enden und an dieser Stelle (also normalerweise im Shell-Prozess) muss eben etwas sitzen das diese Pipe abfragt und die gelesenen Daten in eine Datei schreibt oder auf ein anderes Stream-Device weiterleitet.


Alternativ musst du dir halt etwas ähnliches einfallen lassen oder aber für jedes Subsystem eine eigene Schnittstelle definieren, die du dann exportierst.
Ich hab mir vorgestellt das in der libc zu kapseln. Die libc bietet eine API für Dateien, eine API für Streams usw. und das normale open/read/write/... setzen da oben drauf auf (ich denke dieser Layer dürfte recht dünn sein). Die Datei-API benutzt ihrerseits den VFS als Back-End und für die Pipes kommunizieren die libc's in den beteiligten Prozessen direkt miteinander.

Die Darstellung als Datei ist nur der nullte Wrapper.
Das sehe ich anders. Wenn wir mal ein einfaches VFS betrachten wohinter sich verschiedene Dinge verbergen können dann muss eben hinter dem VFS die Logik stecken die aus den read/write/.... das macht was eigentlich gemeint ist (also Wrapper -1). Ich sehe da das Potential für Konvertierungsverluste und Zeitverschwendung. Bei einem Monolithen kann man das machen/rechtfertigen um das Syscall-API klein zu halten aber bei einem Micro-Kernel ist das IMHO der falsche Ansatz. Ich persönlich finde z.B. toll wie in Java die Streams für alles mögliche benutzt werden können (in/out/err oder TPC-Streams oder Pipes). Streams auf Dateien abbilden zu wollen halte ich für Quatsch.


Aber mal zum Punkt fexible API. Ich habe in letzter Zeit oft mit dem Gedanken gespielt das ne Text-API (nach XML Art) ziemlich flexible wäre.?
Das stelle ich mir sehr langsam vor. Die Prüfung auf Wohlgeformtheit ist bei XML nicht ohne und eine XML-Anfrage ist x-fach größer als ein Binär-Äquivalent.


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 #32 am: 05. October 2010, 18:15 »
Zitat von: erik
Das stelle ich mir sehr langsam vor. Die Prüfung auf Wohlgeformtheit ist bei XML nicht ohne und eine XML-Anfrage ist x-fach größer als ein Binär-Äquivalent.
Das wird auch der Grund sein, warum es noch nicht wirklich versucht wurde, aber wenn man den Overhead mal beiseite lässt wäre ne Text-API nicht schlecht.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #33 am: 05. October 2010, 20:37 »
Hallo,

Was ich halt nicht ganz verstehe ist, man liest bis zum EOF, soweit so gut, aber was passiert wenn man ftell() aufrufen würde und liest man dann das nächste mal einfach wieder bis zum EOF und wie wird man benachrichtig das neue Daten vorhanden sind?
Wie wäre es mit einer File Notification API?

Für solche Fälle kann man auch select() oder poll() oder epoll() oder kqueue nutzen. Du kannst ja nicht nur auf zu schreibende, sondern auch auf zu lesende Daten warten. Ursprünglich funktionierte das nur mit Sockets, inzwischen kannst du diese libc-Funktionen auch auf Dateihandles anwenden. Es sei denn, ich irre mich gerade gewaltig.

Im Endeffekt ist zwar nach außen alles eine Datei, aber dahinter muss man sich immer was spezielles einfallen lassen, damit es funktioniert. Warum dann nicht den Layer der Datei weglassen?
Wie gesagt, es vereinfacht den Userspace ungemein, wenn du nicht irgendwelche API-spezifischen Headerdateien einbinden musst, sondern es mit der Standard-libc erschlagen kannst.

Zitat von: svenska
Der Vorteil ist, dass du die Schnittstelle zwischen Kernel und Treiber komplett ändern kannst und trotzdem irgendwie (read/write) kompatibel zum Userspace bleibst - es ändern sich nur ein paar Dateinamen - was du mit den reinen exportierten APIs nicht kannst. Die APIs kannst du natürlich direkt exportieren (z.B. DOS-basierte Windowse). Die Darstellung als Datei ist nur der nullte Wrapper.
Ich sehe da keinen Vorteil. Entweder es ändert sich die exportierte API und beide Seiten (Kernel und Treiber) müssen geändert werden oder es ändert sich das Protokoll welches hinter read/write kommt, dann muss genauso neugeschrieben werden.
Falscher Ansatz. Kernel und Treiber musst du ohnehin komplett anpassen, aber die Anwendungsprogramme nicht. Für viele Fälle reicht da eine simple Implementation.

Beispielsweise muss ein MP3-Player einfach nur open() auf die Soundkarte und write() für die Daten machen; solange du keine optimale Latenz brauchst oder irgendwelche Kanäle aus einem Programm mixen willst, reicht das aus. Für Spezialfälle (Latenz, Mixing, Resampling, ...) stellst du dann z.B. deine interne, evtl. sogar instabile oder hardwareabhängige API bereit. Zugriffspunkt für die Kommunikation ist dann eleganterweise auch diese Datei, da eh vorhanden.

Gleiches gilt für die grafische Oberfläche, wenn du den Grafikspeicher einfach als Datei zur Verfügung stellst. Sonderfälle (wie 2D-Beschleunigung) kannst du nachträglich da einbauen, ohne die Kompatiblität zu gefährden und Anwendungen haben immer die Möglichkeit einer Rückfallstrategie.

Deine interne API den Treibern zur Verfügung zu stellen ist in Ordnung. Die Anwendungsprogramme sollten davon allerdings nichts mitkriegen und bestenfalls ein sauberes, schlankes Interface zur Verfügung haben.

Aber mal zum Punkt fexible API. Ich habe in letzter Zeit oft mit dem Gedanken gespielt das ne Text-API (nach XML Art) ziemlich flexible wäre.?
XML ist ein Gerüst der Hölle. So ziemlich jede XML-Implementation ist kaputt, anfällig für buffer overflows usw. Wer auf Anhieb eine XML-Implementation fehlerfrei hinkriegt, der ist entweder ein Genie oder ein Lügner.

Außerdem müsstest du deine XML-Strukturen ohnehin inkompatibel zum Rest der Welt standardisieren, da kannst du ein (wesentlich einfacher zu parsendes) binäres Format nutzen. Das ist zudem noch kleiner. Bleib mir bloß mit XML vom Leibe.

Gruß,
Sebastian
« Letzte Änderung: 05. October 2010, 20:46 von Svenska »

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #34 am: 05. October 2010, 20:50 »
Zitat von: svenska
Für solche Fälle kann man auch select() oder poll() oder epoll() oder kqueue nutzen. Du kannst ja nicht nur auf zu schreibende, sondern auch auf zu lesende Daten warten. Ursprünglich funktionierte das nur mit Sockets, inzwischen kannst du diese libc-Funktionen auch auf Dateihandles anwenden. Es sei denn, ich irre mich gerade gewaltig.
Gut, das klingt so als wenn das nicht immer so war? Mir geht es darum, das diese "Dateien" im Kernel also speziell behandelt werden, das aber hinter einer Datei versteckt wird.

Zitat von: svenska
XML ist ein Gerüst der Hölle. So ziemlich jede XML-Implementation ist kaputt, anfällig für buffer overflows usw. Wer auf Anhieb eine XML-Implementation fehlerfrei hinkriegt, der ist entweder ein Genie oder ein Lügner.

Außerdem müsstest du deine XML-Strukturen ohnehin inkompatibel zum Rest der Welt standardisieren, da kannst du ein (wesentlich einfacher zu parsendes) binäres Format nutzen. Das ist zudem noch kleiner. Bleib mir bloß mit XML vom Leibe.
Ok, XML ist schlecht, aber ich meine sowas das man eine Anfrage in der Art macht:
OPEN name="foo.bar" flags="rb"
So wäre es z.B. egal in welcher Reihenfolge du Parameter übergibst und damit lassen sich dann bestimmt auch andere schöne Sachen machen.

Du könntest z.B. mehrere verschiedene Versionen dieses "call´s" haben mit verschiedenen Parametern und wenn ein altes Programm nicht alle Parameter übergibt, dann werden in die restlichen Standardwerte reingeschrieben.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #35 am: 05. October 2010, 21:07 »
Hallo,


Was leider immer noch keiner erklärt hat ist ob es tatsächlich Anwendungsfälle gibt in denen 2 Prozesse auf die selbe Datei über den selben File-Descriptor zugreifen. Das stelle ich mir immer ziemlich tricky vor.


Wie gesagt, es vereinfacht den Userspace ungemein, wenn du nicht irgendwelche API-spezifischen Headerdateien einbinden musst, sondern es mit der Standard-libc erschlagen kannst.
Das ist aber genauso gut möglich wenn die Verzweigung in die einzelnen APIs noch in der libc drin ist, solange die allgemeinen Headerdateien erstmal reichen sehe ich da keine Probleme.

XML ist ein Gerüst der Hölle.
Aha, dafür schwören aber ne Menge Leute auf XML.

Wer auf Anhieb eine XML-Implementation fehlerfrei hinkriegt, der ist entweder ein Genie oder ein Lügner.
oder er hat sich auf das wirklich benötigte beschränkt.


aber ich meine sowas das man eine Anfrage in der Art macht:OPEN name="foo.bar" flags="rb"So wäre es z.B. egal in welcher Reihenfolge du Parameter übergibst und damit lassen sich dann bestimmt auch andere schöne Sachen machen.
Das geht binär genau so gut und ist leichter zu parsen/interpretieren.


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 #36 am: 05. October 2010, 21:16 »
Zitat von: erik
Was leider immer noch keiner erklärt hat ist ob es tatsächlich Anwendungsfälle gibt in denen 2 Prozesse auf die selbe Datei über den selben File-Descriptor zugreifen. Das stelle ich mir immer ziemlich tricky vor.
Wäre ich auch dran interessiert.

Zitat von: erik
Das geht binär genau so gut und ist leichter zu parsen/interpretieren.
Aber, binär legst du auch die Reihenfolge fest und wie willst du es machen einen neuen Parameter hinzuzufügen ohne das es Probleme mit alten Programmen gibt. Auch wäre es so kein Problem wenn sich irgendwelche IDs ändern würden (z.B. bei Syscalls) weil man ja den direkten Namen nimmt.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #37 am: 05. October 2010, 21:32 »
Zitat von: svenska
Für solche Fälle kann man auch select() oder poll() oder epoll() oder kqueue nutzen. Du kannst ja nicht nur auf zu schreibende, sondern auch auf zu lesende Daten warten. Ursprünglich funktionierte das nur mit Sockets, inzwischen kannst du diese libc-Funktionen auch auf Dateihandles anwenden. Es sei denn, ich irre mich gerade gewaltig.
Gut, das klingt so als wenn das nicht immer so war? Mir geht es darum, das diese "Dateien" im Kernel also speziell behandelt werden, das aber hinter einer Datei versteckt wird.
Sockets sind keine Dateien. Diese API wurde anfangs nur für Sockets zugelassen, weil sie Teil des Netzwerklayers war. Inzwischen ist es möglich, diese API auch auf Dateien anzuwenden (select(2) gibt als Beispiel stdin an), einfach weil sie deinen Anwendungsfall (der recht häufig ist), gut lösen kann, gut getestet ist und vor allem für beides funktioniert.

Ansonsten müsstest du eine File Notification API erfinden und nutzen, was auch geht - und wenn ich mich recht entsinne, gibt es sowas unter POSIX zusätzlich auch. Die WinSock erlaubt select()/poll() nur für Sockets, nicht für Dateien.

Du könntest z.B. mehrere verschiedene Versionen dieses "call´s" haben mit verschiedenen Parametern und wenn ein altes Programm nicht alle Parameter übergibt, dann werden in die restlichen Standardwerte reingeschrieben.
Warum nicht einfach alle Felder "mandatory" machen und die Anwendung mit Standardwerten operieren lassen? :-)

Wie gesagt, es vereinfacht den Userspace ungemein, wenn du nicht irgendwelche API-spezifischen Headerdateien einbinden musst, sondern es mit der Standard-libc erschlagen kannst.
Das ist aber genauso gut möglich wenn die Verzweigung in die einzelnen APIs noch in der libc drin ist, solange die allgemeinen Headerdateien erstmal reichen sehe ich da keine Probleme.
Ich meinte ja auch die Schnittstelle zwischen Anwendungen und Kernel, wo diese Philosophie halt echt gut funktioniert, einfach und gleichzeitig mächtig ist.

Wie du die Schnittstelle zwischen Kernel und Treiber gestaltest, spielt (für mich) an der Stelle garkeine Rolle. Genausowenig, ob du diesen Wrapper (Kernel und Anwendung kommunizieren über Dateien) nun im Kernel/VFS oder in der libc versteckst.

XML ist ein Gerüst der Hölle.
Aha, dafür schwören aber ne Menge Leute auf XML.
Guck dir mal übliche, auf XML aufsetzende Netzwerkprotokolle an (MSN Messenger, ...). Da werden teilweise Binärdaten roh mitgeschickt, teilweise mit Base64 encodiert und dann hat man XML mit Base64 ENcodiert. Das sind grausame Protokolle, die da unterwegs sind. XML ist nur solange gut, wie man ein gut durchdachtes Protokoll dahinter ansetzt, wo man sich vorher Gedanken gemacht hat.

Und genau dann braucht man kein extensibles Textprotokoll wie XML mehr.

Wer auf Anhieb eine XML-Implementation fehlerfrei hinkriegt, der ist entweder ein Genie oder ein Lügner.
oder er hat sich auf das wirklich benötigte beschränkt.
Da hab ich aber schon andere Sachen gehört und gelesen...

Zitat von: erik
Das geht binär genau so gut und ist leichter zu parsen/interpretieren.
Aber, binär legst du auch die Reihenfolge fest und wie willst du es machen einen neuen Parameter hinzuzufügen ohne das es Probleme mit alten Programmen gibt. Auch wäre es so kein Problem wenn sich irgendwelche IDs ändern würden (z.B. bei Syscalls) weil man ja den direkten Namen nimmt.
Ob dein Service nun "VFS_Handle_File_Open" oder "142" heißt, spielt keine Rolle. IDs ändern sich übrigens auch nicht von alleine, wenn du die vorher festlegst - genausowenig wie Namen.

Der Unterschied ist, dass dir bei Zahlen niemand den Text-Parser kaputtmachen muss - und dass ein Cast auf int einfach schneller ist, als ein Textparser, der am Ende eh nur ein Handle hinten rauswirft...

Gruß,
Svenska

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #38 am: 05. October 2010, 22:17 »
Was leider immer noch keiner erklärt hat ist ob es tatsächlich Anwendungsfälle gibt in denen 2 Prozesse auf die selbe Datei über den selben File-Descriptor zugreifen. Das stelle ich mir immer ziemlich tricky vor.
Ich habe noch nicht genau verstanden, was dir am stdio-Beispiel nicht zusagt. Es ist kein Spezialfall und vermutlich der Haupteinsatzzweck der Deskriptorvererbung. Ein viel schöneres und praktischeres Beispiel kannst du doch gar nicht mehr bekommen?
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 #39 am: 06. October 2010, 08:44 »
Hallo,


Ich habe noch nicht genau verstanden, was dir am stdio-Beispiel nicht zusagt. Es ist kein Spezialfall und vermutlich der Haupteinsatzzweck der Deskriptorvererbung. Ein viel schöneres und praktischeres Beispiel kannst du doch gar nicht mehr bekommen?
Mir gefällt nicht das es ein Spezialfall ist, es geht dabei um das weitervererben eines Endes einer Pipe also um das weitervererben eines Input-Streams oder Output-Streams. Streams sind was völlig anderes als Dateien (ich denke für Streams hab ich ein funktionsfähiges Konzept in meine ToDo-Liste geschrieben). Wenn Descriptorvererbung nur für Streams/Pipes gemacht wird (was zweifelsohne der Haupteinsatzzweck ist) dann muss ich erst gar keine Vererbung von Dateien implementieren. Es geht mir darum ob es für diesen Nebeneinsatzzweck (vererben von Dateidescriptoren) auch reale Beispiele gibt an denen man sich orientieren könnte wie das ungefähr umzusetzen ist.


Ich meinte ja auch die Schnittstelle zwischen Anwendungen und Kernel, wo diese Philosophie halt echt gut funktioniert, einfach und gleichzeitig mächtig ist.
Aber gerade diese Schnittstelle wird doch von der libc repräsentiert (zumindest wenn wir Open-Source-SW betrachten und was anderes kann ich eh nicht auf meine Plattform portieren). Dass das üblicherweise zwischen Applikation und Kernel kommt liegt doch daran das übliche OSe Monolithen sind, bei einem Micro-Kernel-OS hat der Kernel überhaupt gar nichts damit zu tun da trifft das eher die Personality und die libc muss das passend verbergen so das auch dieses Konglomerat von Services wie ein OS aussieht.

Guck dir mal übliche, auf XML aufsetzende Netzwerkprotokolle an
Keine Angst, das schaue mich mir lieber erst gar nicht an. Ich bin nicht der Meinung das man XML für alles und jedes benutzen muss aber XML hat durchaus seine Stärken, ich möchte XML z.B. für mein linkbares Objekt-Datei-Format benutzen.

Wer auf Anhieb eine XML-Implementation fehlerfrei hinkriegt, der ist entweder ein Genie oder ein Lügner.
oder er hat sich auf das wirklich benötigte beschränkt.
Da hab ich aber schon andere Sachen gehört und gelesen...
Ich hab XML mal für eine ganz simple Konfigurationsdatei benutzt und ich bin mir sicher das dort kaum Fehler drin waren. Der Quell-Code fürs speichern und wieder einlesen war kaum über 20 kBytes und basierte im wesentlichen auf fprintf und strcmp (beim einlesen hab ich erst die komplette Datei in einen Puffer geladen und diesen dann durchgearbeitet).


Aber, binär legst du auch die Reihenfolge fest und wie willst du es machen einen neuen Parameter hinzuzufügen ohne das es Probleme mit alten Programmen gibt. Auch wäre es so kein Problem wenn sich irgendwelche IDs ändern würden (z.B. bei Syscalls) weil man ja den direkten Namen nimmt.
Ach was, das funktioniert wunderbar in Binär!
Du hast einen Header in Deiner Anfrage:uint   commando_code;  //Funktionsnummer für Deine Kommandos (2^32 sind erstmal genug)
uint   data_length;    //Anzahl der folgenden Bytes für dieses Kommando
Und danach kommen null, einer oder mehrere Parameter-Blöcke, jeder Parameterblock hat folgenden Aufbau:uint   parameter_code;    //hier kannst Du für jedes Kommando wieder bis zu 2^32 unterschiedliche Parameter definieren
uint   parameter_length;  //Anzahl der folgenden Bytes für diesen Parameter-Block
                          // (mit dieser Info kann Dein Service auch Parameter überspringen die er nicht kennt weil die libc neuer ist als der Service)
.....  //Nutzdaten für dieses Parameter, hier könnte ein Dateiname mit variabler Länge stehen oder einfach nur ein einzelner Integer mit Flags
Diese Parameter-Blöcke müssen in keiner bestimmten Reihenfolge kommen und sind extrem flexibel. Der wichtigste Vorteil ist jedoch das Du keinen Text-Parser brauchst. (falls ich das jetzt nicht genau genug beschrieben hab dann frage ruhig noch mal)


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

 

Einloggen