Autor Thema: erik´s IPC Idee ;)  (Gelesen 26508 mal)

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« am: 23. January 2011, 10:10 »
Ich will mein IPC System nun umbauen und einige Ideen von erik nutzen. Im Endeffekt geht es darum Ports einzusparen.

Im Moment ist es noch so das man einen Port braucht um eine Nachricht versenden zu können und auch wenn man eigentlich nur RPC, also send+receive macht, benötigt man den Port.

Ich will das dahingehend ändern, das man ein send+receive auch als Thread machen kann, ohne dass das über einen Port läuft. Das wäre dann auch immer synchron, also blockierend. Damit kann ich auf Clientseite schonmal viele Ports einsparen.

Erik´s Idee ist es ja für jede Nachricht die ankommt einen neuen Thread zu starten und den die Nachricht verarbeiten zu lassen.

Ich möchte dabei dem Programmierer die Wahl lassen, ob er selber die Nachrichten abholt (es werden also keine Threads für eine Nachricht gestartet) oder ob für jede Nachricht ein Thread gestartet wird.

Soweit ist das noch kein Problem. Das Problem sehe ich darin, was ist wenn entweder keine Threads mehr vorhanden sind oder nicht mehr genügend Speicher um einen neuen Thread zu starten? Im Endeffekt geht es um die Frage, was passiert wenn die Nachricht in die Queue gepackt werden kann, aber es kann kein neuer Thread mehr gestartet werden.

Eine Lösung wäre, das jeder Thread der vom IPC System gestartet wird, beim Beenden vorher nochmal in die Queue guckt ob noch eine Nachricht vorhanden ist und diese dann auch noch bearbeitet, weil sonst bleiben die ja da drin.

Dann wollte ich es auch so machen, das die Nachricht erst gar nicht in die Queue kommt, sondern gleich dem neuen Thread zugeteilt wird.

erik.vikinger

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


Ich will mein IPC System nun umbauen und einige Ideen von erik nutzen.
Es zahlt sich wohl nun doch langsam aus das ich immer so sehr von den Vorteilen meiner Idee geschwärmt habe. Vielleicht mag tyndur dann ja auch bald umsteigen. ;)

Im Endeffekt geht es darum Ports einzusparen.
Was, mehr nicht? Der Hauptgrund für mein Konzept war eher maximale Performance!

Im Moment ist es noch so das man einen Port braucht um eine Nachricht versenden zu können und auch wenn man eigentlich nur RPC, also send+receive macht, benötigt man den Port.
Hm, ja das ist doof. In meinen Konzept haben nur die Services einen "Port" (oder auch mehrere wenn ein Service-Prozess mehrere Services anbieten möchte) und der Client benötigt dessen ID um eben an den Service eine RPC-Anfrage zu schicken.

Erik´s Idee ist es ja für jede Nachricht die ankommt einen neuen Thread zu starten und den die Nachricht verarbeiten zu lassen.
Ganz recht, aber das gilt nur für den Service, in diesen wird ein neuer Thread injiziert der dann die Anfrage als Parameter bekommt und mit dem Abliefern der Antwort auch wieder gekillt wird. Der Thread vom Client-Prozess der die Anfrage geschickt hat wird so lange blockiert bis die Antwort da ist und wenn dieser dann aus dem Syscall zurückkommt hat er die Antwort des Service quasi als Return-Wert dabei. Siehe auch http://forum.lowlevel.eu/index.php?topic=2433. Da die 2 Kontext-Wechsel ohne den Scheduler ablaufen geht es quasi nur darum die Anfrage und die Antwort jeweils zu transferieren und damit dürfte die Sache extrem schnell werden. Für den Client-Thread ist es auch völlig unerheblich wie lange der Service-Thread benötigt, der merkt das noch nicht mal direkt.

Ich möchte dabei dem Programmierer die Wahl lassen, ob er selber die Nachrichten abholt (es werden also keine Threads für eine Nachricht gestartet) oder ob für jede Nachricht ein Thread gestartet wird.
Welche Seite meinst Du damit, den Service oder den Client? Beim Client muss kein extra Thread gestartet werden weil ja ein Thread bereits die Anfrage initiiert hat, für den Client soll sich das RPC (synchrones IPC) möglichst genau so anfühlen wie ein ganz normaler lokaler Funktionsaufruf auch. Wenn Du im Service das automatische erzeugen von Thread abschaltbar machen willst dann muss der Service die Anfragen aktiv abholen und das dürfte in vielen Fällen mehr als 2 Kontext-Wechsel pro RPC kosten. Davon würde ich persönlich strickt abraten.

Soweit ist das noch kein Problem. Das Problem sehe ich darin, was ist wenn entweder keine Threads mehr vorhanden sind oder nicht mehr genügend Speicher um einen neuen Thread zu starten? Im Endeffekt geht es um die Frage, was passiert wenn die Nachricht in die Queue gepackt werden kann, aber es kann kein neuer Thread mehr gestartet werden.
Wenn kein neuer Thread in den Service injiziert werden kann weil absolut kein Speicher mehr verfügbar ist dann kommt der IPC-Syscall des Client mit einem passenden Fehlercode zurück. Falls aber z.B. für den gewünschten Service bereits das zugelassene Maximum an Threads aktiv ist muss die Anfrage gequeued werden. Das bedeutet das der Client-Thread blockiert. Irgendwann ist dann mal einer der laufenden IPC-PopUp-Threads im Service fertig und der prüft ob Anfragen gequeued sind (bevor er seine eigenen Antwort an den eigenen Client-Thread zurück gibt, es findet also kein zusätzlicher Kontext-Wechsel statt) und erstellt dann sofort einen neuen PopUp-Thread (er benutzt dazu den eigenen gerade frei gegebenen Thread-Descriptor und User-Mode-Stack) und bereitet diesen mit der Anfrage vor so das der dann demnächst vom Scheduler aktiviert werden kann.

Eine Lösung wäre, das jeder Thread der vom IPC System gestartet wird, beim Beenden vorher nochmal in die Queue guckt ob noch eine Nachricht vorhanden ist und diese dann auch noch bearbeitet, weil sonst bleiben die ja da drin.
Wenn ein IPC-PopUp-Thread fertig ist hat er ja eine Antwort für seinen Client dabei und die muss ja zugestellt werden, er kann also nicht einfach so die nächste Anfrage von einem anderen Client bearbeiten.


Ich hoffe ich konnte etwas helfen. Wenn nicht dann frage Bitte noch mal konkreter nach.
Wenn Du möchtest erstelle ich für die 2 Kontext-Wechsel auch mal ein bisschen Pseudo-Code zur Veranschaulichung.


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: 23. January 2011, 12:03 »
Zitat von: erik
In meinen Konzept haben nur die Services einen "Port"
Naja, aber wenn du bei ner GUI Fenster hast, willst du ja auch Nachrichten an diese Fenster schicken und genau dafür will ich dann auch Ports und das Erstellen von Threads nutzen. Das die Sache dadurch wesentlich komplexer wird ist mir klar.

Zitat von: erik
Welche Seite meinst Du damit, den Service oder den Client?
Also ich beziehe mich weder auf Service noch auf Client, sondern einfach nur auf einen Port, an den Nachrichten geschickt werden können (ein Thread kann immer nur eine Antwort bekommen, da können keine Nachrichten gequeuet werden).

Zitat von: erik
Wenn Du im Service das automatische erzeugen von Thread abschaltbar machen willst dann muss der Service die Anfragen aktiv abholen und das dürfte in vielen Fällen mehr als 2 Kontext-Wechsel pro RPC kosten. Davon würde ich persönlich strickt abraten.
Also um mal zu den Kontext-Wechseln zu kommen. Was meinst du damit genau, nur den Wechsel vom UserMode in den SystemMode oder/und den Wechsel in einen anderen Prozess?

Also bei mir findet ein Wechsel in den SystemMode statt, wenn du send+receive machst, dann ein Wechsel in den neuen Prozess und ein Wechsel wieder in den UserMode (des neuen Prozesses). Die Nachricht wird abgearbeitet und beim Senden der Antwort findet ein Wechsel in den SystemMode, ein Wechsel in den Prozess des Clienten und ein Wechsel zurück in den Userprozess statt. Ich denke das sollte sich nicht weiter optimieren lassen (der Algo an sich, bei mir läuft es ein klein wenig anders ab, da bei dem Wechsel in einen anderen Prozess der Scheduler mit im Spiel ist und es sein kann das der andere Prozess noch nicht an der Reihe ist).

Konkret denke ich an irgendwelche Sachen die sowieso nicht parallelisierbar sind (z.B. Disketten-Treiber), da würde der Service dann ein receive (blockierend) machen und wenn eine Nachricht an den geschickt wird. Dann wird die Nachricht in die Queue gepackt und der Thread wird aufgeweckt und für den Thread ist es so als habe er den receive-Syscall gemacht und hat jetzt seine Nachricht.

Würde ich das jetzt parallelisieren würde das nur mehr Probleme machen als es löst.

Zitat von: erik
Wenn ein IPC-PopUp-Thread fertig ist hat er ja eine Antwort für seinen Client dabei und die muss ja zugestellt werden, er kann also nicht einfach so die nächste Anfrage von einem anderen Client bearbeiten.
Mit beenden meinte ich da schon, er ist fertig mit allem, dass schließt auch das Senden der Antwort mit ein ;)

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 23. January 2011, 13:43 »
Soweit ist das noch kein Problem. Das Problem sehe ich darin, was ist wenn entweder keine Threads mehr vorhanden sind oder nicht mehr genügend Speicher um einen neuen Thread zu starten? Im Endeffekt geht es um die Frage, was passiert wenn die Nachricht in die Queue gepackt werden kann, aber es kann kein neuer Thread mehr gestartet werden.
Dann gibt es einen Fehlercode. Wenn der Speicher so sehr voll ist, dürftest du eh ganz andere Probleme haben.

Ich frage andersrum: Wer initiiert bei dir eine RPC-Anfrage? Immer der Client oder immer der Server oder auch mal beide?

In Eriks Modell hat der Service einen Port, der vom Client angesprochen wird. Die Antwort geht immer an den Fragesteller zurück.

Wenn du Anwendungen jetzt unaufgefordert Nachrichten schicken möchtest, müssen diese logischerweise einen Service anbieten, der die Nachrichten empfängt. Das halte ich in dem Kontext nicht unbedingt für sinnvoll, da diese Nachrichten von der Anwendung nicht angefragt wurden und sich das nicht so gut in ein RPC-Konzept einfügt.

Für solche Dinge solltest du eher eine eigene API bereitstellen, nach der eine Anwendung sich für bestimmte Ereignisse (Events, d.h. keine RPC-Nachrichten) registriert bzw. registrieren muss, damit dann die Nachrichten zugestellt werden können.

Und nimm bitte Fenster aus der Betrachtung raus. Ich weiß, das magst du nicht, aber ich finde, die Anwendung darf mehrere Fenster haben und sollte sich auch selbst um das Dispatchen von Ereignissen kümmern dürfen, d.h. die Anwendung kriegt Systemereignisse, nicht das Fenster an sich (sofern das Fenster sich nicht explizit dafür registriert).

;-)

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 23. January 2011, 13:59 »
Es gibt nicht nur RPC! Was ist z.B. mit irgendwelchen Update Nachrichten (Maus-Position, Tastendruck, Dateisachen).
Ja dafür registrierst du dich, aber um dann eine Nachricht zu bekommen, brauchst du einen Port (und ein Port heißt nicht das man auch einen Service zur Verfügung stellt!).

Wer Client und wer Server ist, ist doch egal. Als Bsp. der Storage-Server ist für ein normales Programm ein Server, aber wenn der Storage-Server eine Anfrage an einen Treiber macht, ist er Client, also bringt die Unterscheidung erstmal gar nichts.

Deswegen betrachte ich immer Ports, wer die benutzt ist doch egal.

Eine einfache Konsolen-Anwendung, die kein Fenster hat, wird also auch keinen Port brauchen, kann also auch keine unaufgeforderten Nachrichten bekommen.
Hat eine Anwendung aber ein Fenster hat sie auch einen Port an den Nachrichten geschickt werden.
Ein anderes Bsp. wäre, das meine Anwendung darüber informiert werden will, wenn etwas an einer bestimmten Datei etwas ändert. Auch dafür braucht die Anwendung dann wieder einen Port, damit dorthin die Nachricht das sich etwas geändert hat, geschickt werden kann. Man könnte es zwar auch so lösen, dass man eine RPC Anfrage macht und wenn sich etwas ändert bekommt man seine Antwort, aber das geht ja schon wieder Richtung Polling. Zumal es dann auch nur möglich wäre eine Datei pro Thread zu beobachten und nicht mehrere und es macht die Sache auf Seite des Services auch nicht einfacher.

Was die API betrifft, diese soll ja dann einen Port pro Fenster nutzen. Das kann man ja alles vor dem Programmierer verstecken, aber trotzdem muss es erstmal implementiert werden.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 23. January 2011, 15:23 »
Hallo,


Zitat von: erik
In meinen Konzept haben nur die Services einen "Port"
Naja, aber wenn du bei ner GUI Fenster hast, willst du ja auch Nachrichten an diese Fenster schicken und genau dafür will ich dann auch Ports und das Erstellen von Threads nutzen. Das die Sache dadurch wesentlich komplexer wird ist mir klar.
Deswegen habe ich in meinem IPC-Konzept nicht nur synchrones IPC (das dann für RPC genutzt wird) sondern auch asynchrones IPC (das dann für Signale u.ä. genutzt wird) vorgesehen.

Also ich beziehe mich weder auf Service noch auf Client, sondern einfach nur auf einen Port, an den Nachrichten geschickt werden können (ein Thread kann immer nur eine Antwort bekommen, da können keine Nachrichten gequeuet werden).
Also diesen Satz verstehe ich nicht, könntest Du das bitte noch mal deutlich formulieren? Wenn du Dich weder auf den Service noch auf Client beziehst, auf wenn den dann? Es gibt da IMHO keine dritte Partei und der Kernel ist nur der Vermittler (der der Post quasi die Autos, die Postboten und die restliche Infrastruktur anbietet). An einen Thread kann man IMHO keine Messages schicken (weder synchron noch asynchron).

Also um mal zu den Kontext-Wechseln zu kommen. Was meinst du damit genau, nur den Wechsel vom UserMode in den SystemMode oder/und den Wechsel in einen anderen Prozess?
Den Wechsel in einen anderen Prozess. Das erfordert dann pro Kontext-Wechsel 2 CPU-Modus-Wechsel (auf x86 wären das dann 2 Ring-Wechsel).

Also bei mir findet ein Wechsel in den SystemMode statt, wenn du send+receive machst, dann ein Wechsel in den neuen Prozess und ein Wechsel wieder in den UserMode (des neuen Prozesses). Die Nachricht wird abgearbeitet und beim Senden der Antwort findet ein Wechsel in den SystemMode, ein Wechsel in den Prozess des Clienten und ein Wechsel zurück in den Userprozess statt.
Das ist bei mir ähnlich nur das ich für den Wechsel in einen anderen Prozess keine besondere Aktion benötige weil ja eben nicht der Scheduler benutzt wird.

da bei dem Wechsel in einen anderen Prozess der Scheduler mit im Spiel ist und es sein kann das der andere Prozess noch nicht an der Reihe ist).
Wie kann der Ziel-Thread noch nicht an der Reihe sein? Bei der Anfrage wird ja ein neuer Thread erstellt (der kann also nicht blockiert sein) und eine CPU ist ja auch verfügbar (nämlich die auf der gerade gearbeitet wird) und bei der Antwort wartet der Thread des Client ja genau auf eben diese Antwort also kann er ohne Umschweife sofort wieder auf die aktuelle CPU gebracht werden. Ich sehe da kein Problem.

Konkret denke ich an irgendwelche Sachen die sowieso nicht parallelisierbar sind (z.B. Disketten-Treiber), da würde der Service dann ein receive (blockierend) machen und wenn eine Nachricht an den geschickt wird. Dann wird die Nachricht in die Queue gepackt und der Thread wird aufgeweckt und für den Thread ist es so als habe er den receive-Syscall gemacht und hat jetzt seine Nachricht.
Bitte nimm mir das nicht übel aber manchmal schreibst Du echt wirres Zeugs. Ich habe absolut keine Ahnung was Du da eigentlich meinst. Ich vermute mal das das in Deinem Kopf einen Sinn ergibt aber da Du hier wohl nur einen kleinen Teil der Information nieder schreibst kann ich wirklich nicht nachvollziehen was Du eigentlich möchtest.

Zitat von: erik
Wenn ein IPC-PopUp-Thread fertig ist hat er ja eine Antwort für seinen Client dabei und die muss ja zugestellt werden, er kann also nicht einfach so die nächste Anfrage von einem anderen Client bearbeiten.
Mit beenden meinte ich da schon, er ist fertig mit allem, dass schließt auch das Senden der Antwort mit ein ;)
Also wenn mein PopUp-Thread fertig ist dann liegt die Antwort in den Registern der aktuellen CPU und alles was dann passieren muss ist den PopUp-Thread weg zu räumen (also Stack und Thread-Descriptor frei geben) und den Client-Thread wieder auf den Zustand "running" setzen, den Kontext wechseln (was bei mir im wesentlichen das selektieren einer anderen LDT ist) und (mit der aktuellen CPU) ein IRET in eben diesen Client-Thread machen. Der Client-Thread macht dann mit dem Befehl weiter der unmittelbar hinter dem ursprünglichen IPC-Syscall-Befehl folgt und hat seine Antwort in den Registern. So einfach kann das sein. Wenn ich an dieser Stelle die Möglichkeit haben wollte das auf der aktuellen CPU als nächstes ein ganz anderer Thread arbeiten soll müsste ich die Antwort von den Registern in den gespeicherten Zustand des Client-Thread (in dessen Thread-Descriptor) speichern, diesen als "runnable" in die Scheduler-Queue eintragen und dann den Scheduler aufrufen, das wäre alles ein Haufen extra Arbeit die eigentlich nur den RPC-Overhead vergrößert ohne mir irgendeinen Vorteil zu liefern.


Es gibt nicht nur RPC! Was ist z.B. mit irgendwelchen Update Nachrichten (Maus-Position, Tastendruck, Dateisachen).
Deswegen ja parallel zum synchronen IPC auch noch asynchrones IPC.

Ja dafür registrierst du dich, aber um dann eine Nachricht zu bekommen, brauchst du einen Port (und ein Port heißt nicht das man auch einen Service zur Verfügung stellt!).
Dann ist eben ein GUI-Programm auch ein simpler Service (ein Service der vom GUI-System definierte Nachrichten verarbeiten kann). Na und, wo siehst Du da das Problem?

Als Bsp. der Storage-Server ist für ein normales Programm ein Server, aber wenn der Storage-Server eine Anfrage an einen Treiber macht, ist er Client
Ganz genau, so ist es.


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 #6 am: 23. January 2011, 15:46 »
Zitat von: erik
Also diesen Satz verstehe ich nicht, könntest Du das bitte noch mal deutlich formulieren? Wenn du Dich weder auf den Service noch auf Client beziehst, auf wenn den dann?
Ich meine damit, das jemand der einen Port hat um Nachrichten empfangen zu können, keinen Server/Service sein muss. Deswegen rede ich lieber nur von einem Port als Mittel Nachrichten zu empfangen.

Bei meiner Variante macht es für den Server keinen Unterschied ob die Antwort an einen Port oder einen Thread gesendet wird, das wird über die SenderID geregelt und macht dann der Kernel.

Zitat von: erik
Wie kann der Ziel-Thread noch nicht an der Reihe sein?
Weil es einen anderen Thread gibt, der eine höherer Priorität hat? Oder die Zeitscheibe ist abgelaufen?

Mein Bsp. mit dem Diskettentreiber. Es macht in meinen Augen halt keinen Sinn meinetwegen 4 Threads zu haben die alle Daten von einer Diskette holen wollen, aber es kann eh nur einer immer arbeiten und die anderen 3 müssen warten bis der eine fertig ist. Bevor ich da Ressourcen für 4 Threads verschwende und die dann auch noch synchronisieren muss, lasse ich doch lieber nur einen Thread laufen und der arbeitet die Nachrichten eine nach der anderen ab.
Diesen einen Thread würde ich aber den Diskettentreiber erstellen lassen. Das eigentliche Problem ist halt, der Treiber ansich muss ja nicht laufen, also der bräuchte keinen Thread, wenn die immer erstellt werden wenn eine Nachricht kommt, aber wie geht man mit einem Prozess um der keinen Thread hat?

Zitat von: erik
Also wenn mein PopUp-Thread fertig ist dann liegt die Antwort in den Registern der aktuellen CPU
Da x86 nicht so viele Register hat und noch weniger, wenn man Syscall/Sysenter benutzen möchte, geht das leider nicht nur über die Register, sondern es muss halt auch ein wenig Speicher kopiert werden.

Zitat von: erik
Der Client-Thread macht dann mit dem Befehl weiter der unmittelbar hinter dem ursprünglichen IPC-Syscall-Befehl folgt und hat seine Antwort in den Registern. So einfach kann das sein. Wenn ich an dieser Stelle die Möglichkeit haben wollte das auf der aktuellen CPU als nächstes ein ganz anderer Thread arbeiten soll müsste ich die Antwort von den Registern in den gespeicherten Zustand des Client-Thread (in dessen Thread-Descriptor) speichern, diesen als "runnable" in die Scheduler-Queue eintragen und dann den Scheduler aufrufen, das wäre alles ein Haufen extra Arbeit die eigentlich nur den RPC-Overhead vergrößert ohne mir irgendeinen Vorteil zu liefern.
Mein Scheduler weiß aber gerne welcher Thread gerade läuft und da er (der Scheduler) auch noch die Zeitscheiben berechnet und sowas, kann man nicht ohne den Scheduler aufzurufen einen Thread wechseln (das würde nur Probleme verursachen). Auf x86 erfordert ein Thread-wechsel noch ein wenig mehr, bei mir konkret muss man gucken ob das PD gewechselt werden muss, ein Segmentregister das pro Thread verwendet wird muss auch aktualisiert werden und das macht eh alles der Scheduler, also warum nicht gleich den Scheduler aufrufen.

Zitat von: erik
Deswegen ja parallel zum synchronen IPC auch noch asynchrones IPC.
Habe ich ja auch, läuft halt beides über Ports, aber eine send+recv (also RPC) kann auch von einem Thread gemacht werden, der keinen Port hat, aber der Service am anderen Ende des Ports muss davon nichts wissen, für ihn ist es so als wenn er die Antwort an einen Port schickt.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 23. January 2011, 17:36 »
Hallo,

Es gibt nicht nur RPC! Was ist z.B. mit irgendwelchen Update Nachrichten (Maus-Position, Tastendruck, Dateisachen).

Ich zitiere mich eher ungern, dennoch:
Für solche Dinge solltest du eher eine eigene API bereitstellen, nach der eine Anwendung sich für bestimmte Ereignisse (Events, d.h. keine RPC-Nachrichten) registriert bzw. registrieren muss, damit dann die Nachrichten zugestellt werden können.
Oder anders ausgedrückt: RPC-Nachrichten (synchron, Frage-Antwort-Spielchen) werden von Events (asynchron, plötzlich passiert etwas) getrennt. Beide Systeme existieren parallel.

Ja dafür registrierst du dich, aber um dann eine Nachricht zu bekommen, brauchst du einen Port (und ein Port heißt nicht das man auch einen Service zur Verfügung stellt!).
Wenn beide Systeme parallel laufen, gibt es Port für synchrones RPC und asynchrone Events.

Wer Client und wer Server ist, ist doch egal.
Ist es nicht. Der Client (z.B. die Anwendung) fragt den Server (z.B. das Dateisystem) nach etwas (z.B. einer Datei). Dazu benutzt er einen wohlbekannten Port des Servers, der dann das Ergebnis nicht als Nachricht zurückschickt, sondern - da es ein synchrones Verhalten ist - einfach antwortet.

Als Bsp. der Storage-Server ist für ein normales Programm ein Server, aber wenn der Storage-Server eine Anfrage an einen Treiber macht, ist er Client, also bringt die Unterscheidung erstmal gar nichts.
Das ist Blödsinn. Der Storage-Server ist ein Server (darum heißt er so), er stellt für Anwendungen einen RPC-Port zur Verfügung. Dass er dazu auf andere Prozesse zugreift, spielt in der Betrachtung überhaupt keine Rolle! Um ein RPC-Client zu sein, muss man keine Voraussetzungen (mal abgesehen von Permissions) erfüllen!

Deswegen betrachte ich immer Ports, wer die benutzt ist doch egal.
Nein, ist es nicht. Synchrones RPC funktioniert so, dass du weißt, wer den Service anbietet und wer nicht.

Eine einfache Konsolen-Anwendung, die kein Fenster hat, wird also auch keinen Port brauchen, kann also auch keine unaufgeforderten Nachrichten bekommen.
Ebenfalls Blödsinn. Auch eine Konsolenanwendung ohne Fenster wird Ereignisse abkriegen. Die Umgebung kann sich z.B. ändern (du kannst auch im Textmodus die Auflösung ändern, z.B. von 80x25 auf 80x43 oder so), das Programm kann ein Signal bekommen, dass es die Konfiguration neu einlesen soll (SIGHUP) oder sich beenden soll (SIGTERM).

Ich zitiere mich ungern:
Und nimm bitte Fenster aus der Betrachtung raus.
Die haben mit RPC nichts zu tun, sondern sind einzig und allein Aufgabe des GUI-Servers. Der Kernel soll graphische Anwendungen, egal wieviele Fenster sie haben, als Anwendung begreifen, nicht als Ansammlung von Fenstern! Ob die Anwendung dann jedem Fenster einen RPC-Port zuweist oder ob sie einen Dispatcher benutzt, um die Ereignisse auf die Fenster zu verteilen, ist doch total egal.

Nicht jede graphische Anwendung hat ein Fensterkonzept, welches du kennst (Spiele im Vollbildmodus machen das oft selbst). Und wenn du deinen Kernel auf den GUI-Server hin exakt zuschneidest, dann meißelst du dein Fensterkonzept in Stein!

Ein anderes Bsp. wäre, das meine Anwendung darüber informiert werden will, wenn etwas an einer bestimmten Datei etwas ändert. Auch dafür braucht die Anwendung dann wieder einen Port, damit dorthin die Nachricht das sich etwas geändert hat, geschickt werden kann.
Ja. Das ist aber nicht vergleichbar mit den Ports, die du für Anfragen benutzt! Was an diese Adresse geschickt wird, sind asynchrone RPC-Nachrichten, oder von mir als "Events" bezeichnet.
Ich würde das nicht über die gleiche API laufenlassen, siehe oben.

Was die API betrifft, diese soll ja dann einen Port pro Fenster nutzen. Das kann man ja alles vor dem Programmierer verstecken, aber trotzdem muss es erstmal implementiert werden.
Löse dich von Fenstern. Das ist Unfug. Du hast einfach nur Threads.

Und trenne synchrones RPC (Client-Server-Architektur) von asynchronem RPC (Events).

Gruß,
Svenska

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 23. January 2011, 20:40 »
Mein IPC System kann synchron und asynchron, nur läuft halt beides über die selben Ports.

Zitat von: svenska
Der Client (z.B. die Anwendung) fragt den Server (z.B. das Dateisystem) nach etwas (z.B. einer Datei). Dazu benutzt er einen wohlbekannten Port des Servers, der dann das Ergebnis nicht als Nachricht zurückschickt, sondern - da es ein synchrones Verhalten ist - einfach antwortet.
Also erstmal, was macht denn der Treiber, wenn er eine Anfrage vom Server bekommt? Dann unterscheidet sich bei mir das Senden einer Nachricht nicht mit dem Antworten auf eine Nachricht. Als Server versendest du eine Nachricht, die die Antwort auf eine Anfrage ist und der "Anfrager" (der ja wartet) wird aufgeweckt und hat seine Antwort.

Das läuft bei mir alles über die selben Syscalls ab.

Zitat von: svenska
Auch eine Konsolenanwendung ohne Fenster wird Ereignisse abkriegen. Die Umgebung kann sich z.B. ändern (du kannst auch im Textmodus die Auflösung ändern, z.B. von 80x25 auf 80x43 oder so), das Programm kann ein Signal bekommen, dass es die Konfiguration neu einlesen soll (SIGHUP) oder sich beenden soll (SIGTERM).
Mal blöd gefragt wie macht das Windows, denn dort gibt es ja keine Signale? Ich möchte eigentlich auch keine Signale unterstützen.

Ansonsten, wenn man sich an den C-Standard und nicht an den POSIX-Standard (also keine Signale) hält, bekommen Konsolenanwendungen keine Ereignisse ab, sondern die machen alles über Funktionsaufrufe.

Zitat von: svenska
Nicht jede graphische Anwendung hat ein Fensterkonzept, welches du kennst (Spiele im Vollbildmodus machen das oft selbst). Und wenn du deinen Kernel auf den GUI-Server hin exakt zuschneidest, dann meißelst du dein Fensterkonzept in Stein!
Ich versuche im Endeffekt Ports einzusparen und trotzdem eine gewisse Parallelität zu bekommen und das hat nur indirekt mit dem GUI-Server zu tun. Mir ist nur bei der Diskussion wegen eines GUI-Servers aufgefallen, das mit bei meinem Konzept schnell die Ports ausgehen würde und das ich da was ändern muss.

Also mein IPC System sieht folgendes vor:
uint32t sendMsg(uint32t sender, uint32t receiver, void *data, uint32t flags)
uint32t recvMsg(uint32t receiver, void *buffer, uint32t flags)
uint32t sendRecvMsg(uint32t sender, uint32t receiver, void *request, void *response, uint32t flags)
Das sind meine Syscalls dafür und darüber laufen auch alle IPC Sachen.

Der Server macht also nach dem Initialisieren einen Syscall recvMsg(serverPortID,&request,RECV_WAIT) und bekommt vom Clienten eine Anfrage indem der einfach sendRecvMsg(serverPortID,0,&request,&response,SEND_RECV_THREAD) macht (die 0 habe ich einfach so dahin geschrieben, im Endeffekt ist der Wert bei dem Flag SEND_RECV_THREAD egal, da vom Kernel die ThreadID eingetragen wird).
Der Server bearbeitet die Anfrage und sendet dann die Antwort mit sendRecvMsg(serverPortID,request->sender,&response,&request,0). Der Client der ja blockiert hat, wird aufgeweckt und hat seine Antwort.

Wie soll eigentlich ein Antwort bei so einem synchronen IPC eurer Meinung nach aussehen? Weil eigentlich ist es auch nur das Versenden einer Nachricht an jemanden der "zufällig" gerade auf eine Antwort wartet.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 24. January 2011, 12:47 »
Hallo,


Ich meine damit, das jemand der einen Port hat um Nachrichten empfangen zu können, keinen Server/Service sein muss. Deswegen rede ich lieber nur von einem Port als Mittel Nachrichten zu empfangen.
Das hängt sicher davon ab wie die Worte Server und Service definiert werden aber grundsätzlich hast Du schon recht. Ob jetzt ein Message-Hander, der sich am GUI-Server anmeldet um Event an seinen Port geschickt zu bekommen, gleich als Service zu betrachten ist wird man wohl eher verneinen können.

Bei meiner Variante macht es für den Server keinen Unterschied ob die Antwort an einen Port oder einen Thread gesendet wird, das wird über die SenderID geregelt und macht dann der Kernel.
Bei meinem Konzept kann eine Antwort, die der PopUp-Thread als Handler einer synchronen IPC-Anfrage generiert und als letzte Handlung abliefert, niemals in irgendeiner Weise adressiert werden. Der Kernel weiß für welche Anfrage der PopUp-Thread gearbeitet hat und weckt selbstständig den richtigen (wartenden) Client-Thread auf um ihn eben diese Antwort zu geben. Der PopUp-Thread kann ja als letztes kein RET machen da der Handler ja quasi die main-Funktion ist und deswegen habe ich für das Zurückliefern von Antworten einen extra Syscall vorgesehen der auch nur von PopUp-Threads benutzt werden darf. Sieh Dir bitte noch mal meinen Link (vom Anfang dieses Threads) an, da gibt es auch ein minimales Beispiel. Dieser Antwort-Syscall hat kein Parameter mit dem das Ziel der Antwort bestimmt werden könnte (wozu auch). Bei Handlern für asynchrone Events wird ein anderer PopUp-Thread-Ende-Syscall aufgerufen der gar keine Antwort nimmt.

Zitat von: erik
Wie kann der Ziel-Thread noch nicht an der Reihe sein?
Weil es einen anderen Thread gibt, der eine höherer Priorität hat? Oder die Zeitscheibe ist abgelaufen?
Aber das sind doch Dinge nicht nicht unbedingt während des IPC-Syscalls behandelt werden müssen, wenn die Zeitscheibe noch innerhalb des PopUp-Thread ablauft dann hat der den Ende-Syscall noch nicht aufgerufen und wenn nur noch 1µs übrig ist dann kommt die Unterbrechung eben erst nachdem der Kernel sein IRET in den Client-Thread getan hat. Ich nehme an das dieses Problem bei Dir dadurch entsteht weil Du einen unterbrechbaren Kernel hast, aufgrund dessen das ich das nicht habe habe ich damit auch kein Problem.

Mein Bsp. mit dem Diskettentreiber. ....
Deswegen hab ich in meiner IPC-Syscall-API auch extra ein Parameter vorgesehen mit dem der Service beim einrichten seines Ports festlegen kann wie viele PopUp-Threads der Kernel für diesen Port maximal parallel laufen lassen darf, dieses Limit darf auch 1 sein so das der Programmierer sich unnötige Synchronisationsdinge sparen kann. Für Deinen Disketten-Treiber wäre das eine gute Entscheidung um den Code so einfach wie möglich zu halten. Für einen AHCI-SATA-Treiber wäre 32 ein gutes Limit weil die AHCI-Spec eben genau so viele gleichzeitige Anfragen an eine HDD zulässt. Was das richtige Limit für das VFS ist muss man aber selber überlegen.

... aber wie geht man mit einem Prozess um der keinen Thread hat?
Das ist eine gute Frage auf die ich so schnell auch keine gute Antwort habe. Ich würde sagen das einfachste wäre es den main-Thread in ein endloses Sleep zu schicken, so könnte man ihn auch wieder aufwecken wenn der Prozess z.B. ein SIGTERM bekommt. So ein schlafender Thread kostet zwar etwas Speicher (Stack und Thread-Descriptor) aber wenigstens keine CPU-Takte weil er ja nie in der Scheduler-Liste auftaucht.

geht das leider nicht nur über die Register, sondern es muss halt auch ein wenig Speicher kopiert werden.
Also Speicher möchte ich auch per IPC übermitteln (darüber hatten wir doch schon lang und ausführlich diskutiert) aber den will ich eigentlich niemals kopieren sondern nur vererben (was Dank meiner Segmente auch recht einfach geht).

Mein Scheduler weiß aber gerne welcher Thread gerade läuft
Wozu? Ich sehe in dieser Information keinen Nutzwert, das wäre höchstens eine Info die der Task-Manager anzeigen könnte (für neugierige User).

Auf x86 erfordert ein Thread-wechsel noch ein wenig mehr, bei mir konkret muss man gucken ob das PD gewechselt werden muss, ein Segmentregister das pro Thread verwendet wird muss auch aktualisiert werden und das macht eh alles der Scheduler, also warum nicht gleich den Scheduler aufrufen.
Ja, bei mir müssen auch einige der Register wieder geladen werden (also das was der Client-Thread über den Syscall als Callee-Save erwartet) aber das sind vielleicht 10 Assemblerbefehle und dafür den Scheduler aufzurufen, der eigentlich noch sehr viel mehr macht, erscheint mir auf meiner Plattform eher ungeeignet. Wenn Du das auf x86 anders lösen möchtest dann steht Dir das natürlich frei.


Mein IPC System kann synchron und asynchron, nur läuft halt beides über die selben Ports.
Also das finde ich sehr ungeschickt, in meinem Konzept sind synchrones und asynchrones IPC 2 völlig verschiedene Dinge die auch verschiedene Syscalls nutzen. Das im Kernel selber aber wohl einiges an Code geteilt wird (z.B. für das Speicherummappen) ist nur ein internes Implementierungsdetail.

Dann unterscheidet sich bei mir das Senden einer Nachricht nicht mit dem Antworten auf eine Nachricht.
Das ist wieder so ein Problem. In meinem Konzept ist eine Antwort keine eigenständige IPC-Message sondern integraler Bestandteil eines synchronen IPC-Vorgangs. Antworten können niemals an ein bestimmtes Ziel geschickt werden (sonst bräuchte der Client ja am Ende doch wieder einen eigenen Port) sondern der Kernel weiß was er mit der Antwort zu tun hat.

uint32t sendMsg(uint32t sender, uint32t receiver, void *data, uint32t flags)
uint32t recvMsg(uint32t receiver, void *buffer, uint32t flags)
uint32t sendRecvMsg(uint32t sender, uint32t receiver, void *request, void *response, uint32t flags)
Das sind meine Syscalls dafür und darüber laufen auch alle IPC Sachen.
Neben den bereits erwähnten Problemen mit der Antwort fällt mir spontan auf das es nirgends ein Parameter für die Größe der übergebenden Daten gibt. Woher soll der Kernel wissen wie viel Platz vom Client für die Antwort vorgesehen ist damit er nicht eventuell zu viel da rein legt?
Das mir persönlich das aktive Abholen von Anfragen nicht gefällt haben wir ja auch schon öfters diskutiert. ;)


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

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 24. January 2011, 13:21 »
Zitat von: erik
Der Kernel weiß für welche Anfrage der PopUp-Thread gearbeitet hat und weckt selbstständig den richtigen (wartenden) Client-Thread auf um ihn eben diese Antwort zu geben.
Das wollte ich vermeiden, das der Kernel sich auch noch darum kümmern muss bzw. da bei mir ja synchron und asynchron über die selben Ports läuft.

Zitat von: erik
Der PopUp-Thread kann ja als letztes kein RET machen da der Handler ja quasi die main-Funktion ist und deswegen habe ich für das Zurückliefern von Antworten einen extra Syscall vorgesehen der auch nur von PopUp-Threads benutzt werden darf.
Da überlege ich noch ob ich das nicht so einrichte das der Thread bei einem RET einen bestimmten Syscall macht der dann die Antwort sendet (bei meinen bisherigen Threads springt ein RET auch zu einem Stub der den Thread_End Syscall aufruft). Allerdings dürfte das schwierig werden, da ich ja immer eine Nachricht zurückliefern müsste, da ist ein Aufrufen eines Syscalls einfacher.

Zitat von: erik
Aber das sind doch Dinge nicht nicht unbedingt während des IPC-Syscalls behandelt werden müssen, wenn die Zeitscheibe noch innerhalb des PopUp-Thread ablauft dann hat der den Ende-Syscall noch nicht aufgerufen und wenn nur noch 1µs übrig ist dann kommt die Unterbrechung eben erst nachdem der Kernel sein IRET in den Client-Thread getan hat. Ich nehme an das dieses Problem bei Dir dadurch entsteht weil Du einen unterbrechbaren Kernel hast, aufgrund dessen das ich das nicht habe habe ich damit auch kein Problem.
Jein. Das Problem ist halt das in der Thread-Struc ein paar Daten aktualisiert werden und vorallem das der Kernel-Stack einen bestimmten Aufbau haben muss um beim nächsten Thread-Wechsel wieder richtig zu funktionieren (das ist ein Problem wegen des unterbrechbaren Kernels).

Zitat von: erik
Deswegen hab ich in meiner IPC-Syscall-API auch extra ein Parameter vorgesehen mit dem der Service beim einrichten seines Ports festlegen kann wie viele PopUp-Threads der Kernel für diesen Port maximal parallel laufen lassen darf, dieses Limit darf auch 1 sein so das der Programmierer sich unnötige Synchronisationsdinge sparen kann.
Du hast ja eh kein aktives abholen, aber ich würde das schon ganz gerne zur Verfügung stellen. Außerdem werde ich so planen das man auswählen kann das immer ein neuer Thread erstellt wird oder das nie ein neuer Thread erstellt wird. Das Problem mit dem Limit ist, wie findet man heraus was ein gutes Limit ist? Ich meine woher willst du wissen das 2 Threads zu wenig sind, aber 6 schon zu viele?

Zitat von: erik
Ich würde sagen das einfachste wäre es den main-Thread in ein endloses Sleep zu schicken, so könnte man ihn auch wieder aufwecken wenn der Prozess z.B. ein SIGTERM bekommt. So ein schlafender Thread kostet zwar etwas Speicher (Stack und Thread-Descriptor) aber wenigstens keine CPU-Takte weil er ja nie in der Scheduler-Liste auftaucht.
Daran dachte ich auch schon, das man den main-Thread auf ein Event warten lässt und dieses Event kann durch eine Nachricht eintreten (z.B. das der Treiber beendet werden soll).

So könnte ich auch Signale emulieren, indem man dafür einen Port hat an den Nachrichten (Signale) geschickt werden können und wenn es ein Signal ist, bräuchte ich einen Syscall das alle Threads des eigenen Prozesses erstmal suspended werden. Dann wird das Signal abgearbeitet und falls es nicht gerade sowas wie ein beenden-Signal war, werden die Threads dann wieder losgelassen.

Ob das so machbar ist oder wird es da Probleme geben bzw. Signale die sich nicht so umsetzen lassen?

Zitat von: erik
Also Speicher möchte ich auch per IPC übermitteln (darüber hatten wir doch schon lang und ausführlich diskutiert) aber den will ich eigentlich niemals kopieren sondern nur vererben (was Dank meiner Segmente auch recht einfach geht).
Das meinte ich noch nichtmal. Ich habe ja fixed-Size Nachrichten und normalerweise könnte man die auch in die Register kopieren und dann nen Syscall machen, so würde man sich das Kopieren der Daten vom UserStack zum KernelStack vermeiden, aber auf Grund der wenigen Register ist das leider nicht möglich. Das dürfte unter x64 besser werden und auch sehr viel schneller (auch andere Architekturen die wesentlich mehr Register bieten).

Zitat von: erik
Das ist wieder so ein Problem. In meinem Konzept ist eine Antwort keine eigenständige IPC-Message sondern integraler Bestandteil eines synchronen IPC-Vorgangs. Antworten können niemals an ein bestimmtes Ziel geschickt werden (sonst bräuchte der Client ja am Ende doch wieder einen eigenen Port) sondern der Kernel weiß was er mit der Antwort zu tun hat.
Wo siehst du da das Problem?

Was die Antwort betrifft, hatte ich doch schon erklärt, das wenn ein Thread RPC macht, man ein spezielles Flag nutzt und der Sender eine ID bekommt die kein Port sein kann. Wenn der Service dann die Antwort schickt, macht er das als wenn es ein Port wäre, aber der Kernel weiß das es kein Port ist, sondern ein Thread und von daher braucht man für sowas keinen eigenen Port.

Zitat von: erik
Neben den bereits erwähnten Problemen mit der Antwort fällt mir spontan auf das es nirgends ein Parameter für die Größe der übergebenden Daten gibt. Woher soll der Kernel wissen wie viel Platz vom Client für die Antwort vorgesehen ist damit er nicht eventuell zu viel da rein legt?
Wie gesagt, fixed-Size ;) Meine Nachrichten sind immer 32byte groß und zusätzlich kann mit den Syscall noch ein SharedMem-Bereich (der dann auch jedes Mal extra erstellt wird) versendet werden. Das ist bei meinen Bsp. Syscalls noch nicht drin, aber dafür werde ich keine Syscalls haben die sich nur um SharedMem kümmern.

Was mir noch eingefallen ist, der Grund warum sowas noch nicht umgesetzt wurde, dürfte daran liegen das die meisten Systeme dynamic-Size Nachrichten haben und wie willst du die in den Adressraum bekommen ohne das der Thread noch einen Syscall machen muss. Man könnte natürlich dem Thread einen Parameter mitgeben der die Größe der Daten enthält und der Thread kann dann den Speicher holen und dann würde er den Syscall für das Abholen der Nachricht machen (was dir ja nicht gefällt, aber nicht aktives Abholen wird ohne Segmente sehr schwierig umzusetzen sein).

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 24. January 2011, 17:35 »
Hallo,


Das wollte ich vermeiden, das der Kernel sich auch noch darum kümmern muss bzw. da bei mir ja synchron und asynchron über die selben Ports läuft.
Genau da sehe ich das Problem in Deinem derzeitigem Konzept. Das der Kernel anhand der aktuellen PopUp-Thread-ID den richtigen synchronen IPC-Vorgang findet, um eben zu wissen wo die Antwort hin gehört, sehe ich nun wirklich nicht als das große Problem an. Du möchtest mit wenigen aber mächtigen Syscalls auskommen wogegen ich vorschlage lieber ein paar mehr Syscalls zu nehmen von denen aber jeder nur eine bestimme Aufgabe erledigt (für Gemeinsamkeiten kann man ja im Kernel auch den selben Code benutzen). Meiner persönlichen Meinung nach sind die kleinen spezialisierten Syscalls schneller, schon weil keine Fallunterscheidungen drin sind, und vielleicht auch leichter zu entwickeln.
Ein anderes Problem sind Fehler in den Applikationen bzw. gezielt böswillige Aktionen derer. Was ist wenn ein Client eine synchrone Anfrage an einen Service stellt und während der Service arbeitet ein dritter Prozess einfach eine Message an den schlafenden Client schickt. So wie ich Deine Syscalls verstanden habe würde dann einfach der Client aufwachen und mit der gefackten Message als Antwort weiterarbeiten. Klar kannst Du das wieder mit Filtern usw. im Kernel unterbinden (was immer zusätzliche CPU-Takte kostet) aber wäre es nicht besser wenn das Konzept solche Angriffe erst gar nicht zulässt?

Da überlege ich noch ob ich das nicht so einrichte das der Thread bei einem RET einen bestimmten Syscall macht der dann die Antwort sendet (bei meinen bisherigen Threads springt ein RET auch zu einem Stub der den Thread_End Syscall aufruft).
Das muss dann aber in der User-Mode-Application (bzw. in Deiner zuständigen IPC-Library) selber eingerichtet werden und ich persönlich finde es nicht toll wenn Kernel-Funktionalitäten vom User-Mode abhängen. Bei mir würde ein RET auf oberster Ebene des PopUp-Thread einfach einen Segmentation-Error ergeben und fertig.

Du hast ja eh kein aktives abholen, aber ich würde das schon ganz gerne zur Verfügung stellen.
Für was? Welchen Vorteil erhoffst Du Dir dadurch?
Ich persönlich sehe da eigentlich nur den Nachteil von potentiell mehr Syscalls pro IPC-Vorgang und längeren Latenzen weil der Service gerade nicht in der Abhole-Warte-Position ist (dann muss nämlich gequeued werden). Außerdem muss Du ja die gewünschte Anzahl an Threads bereits da haben um dann (falls mal genügend Clients parallel Wünsche haben) auch entsprechend bedienen zu können. Diese Threads liegen aber mit hoher Wahrscheinlichkeit die meiste Zeit nur faul rum und kosten Speicher.
Dir ging es doch eigentlich um das Sparen von Ressourcen oder?

Das Problem mit dem Limit ist, wie findet man heraus was ein gutes Limit ist? Ich meine woher willst du wissen das 2 Threads zu wenig sind, aber 6 schon zu viele?
Man kann ja erst mal ein möglichst großes Limit benutzen, es werden ja nie mehr PopUp-Threads injiziert als auch tatsächlich parallele Anfragen kommen so das da erstmal keine Speicherverschwendung entsteht, und dann mal schauen ob es zu Problemen kommt. ;)

So könnte ich auch Signale emulieren, indem man dafür einen Port hat an den Nachrichten (Signale) geschickt werden können
Dafür habe ich extra die Möglichkeit vorgesehen das man auch zu einer Prozess-ID einen Port für asynchrone Messages aktivieren kann aber das muss der Prozess schon selber aktiv einrichten so das es nie zu unerwarteten Messages kommt.

und wenn es ein Signal ist, bräuchte ich einen Syscall das alle Threads des eigenen Prozesses erstmal suspended werden. Dann wird das Signal abgearbeitet und falls es nicht gerade sowas wie ein beenden-Signal war, werden die Threads dann wieder losgelassen.
Du willst alle Threads eines Prozesses einfrieren? Hm, das erscheint mir dann doch etwas zu drastisch, das macht ja noch nicht einmal POSIX.

Was die Antwort betrifft, hatte ich doch schon erklärt, das wenn ein Thread RPC macht, man ein spezielles Flag nutzt und der Sender eine ID bekommt die kein Port sein kann. Wenn der Service dann die Antwort schickt, macht er das als wenn es ein Port wäre, aber der Kernel weiß das es kein Port ist, sondern ein Thread und von daher braucht man für sowas keinen eigenen Port.
Da müssen aber eine ganze Menge Dinge auf der User-Mode-Seite sauber mitspielen damit das ordentlich funktioniert, das wäre mir zu heikel, ich möchte lieber das mein IPC-System so einfach wie möglich zu benutzen ist und eben eine möglichst kleine Angriffsfläche gegen (un)beabsichtigte SW-Fehler bietet.

Was mir noch eingefallen ist, der Grund warum sowas noch nicht umgesetzt wurde, dürfte daran liegen das die meisten Systeme dynamic-Size Nachrichten haben
Dynamic-Size macht ja auch irgendwie Sinn. Eine fest vorgegebene Nachrichtengröße ist immer entweder zu groß (Verschwendung) oder zu klein (Zusatzaufwand).

und wie willst du die in den Adressraum bekommen ohne das der Thread noch einen Syscall machen muss.
Na per Paging, meine Segmente machen das zwar einfacher weil es egal ist wie groß die Nachricht ist (es kostet immer den selben kleinen Aufwand) aber es geht auch prinzipiell mit Paging. Wenn Du per IPC Speicher vom Client an den Service mitgeben möchtest dann bekommt der Kernel beim Syscall einen Pointer und eine Größenangabe, dann sucht er sich einen passenden Platz im virtuellen Adressraum des Service und mappt alle Pages auch dort hinein. Das muss der Kernel sich natürlich merken damit er das beim Ende des PopUp-Thread auch wieder rückgängig machen kann. Klar gibt es da bei der ersten und letzten Page eventuell ein kleines Sicherheitsproblem aber da könnte man ja dann doch kopieren. Der Handler (die main-Funktion des PopUp-Thread) bekommt dann vom Kernel einen neuen Pointer in seinen virtuellen Adressraum und die korrekte Größenangabe als Parameter übergeben. Ich sehe da absolut keine Schwierigkeit, es kostet mit Paging einfach nur ein bisschen mehr CPU-Zeit (die leider auch noch von der Menge der zu übergebenden Daten abhängt) aber für viele kleine PRC-Sachen (die meistens mit nur einer Page auskommt) dürfte das extrem schnell sein und Du hast trotzdem den Vorteil von dynamic-size Messages.


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

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 24. January 2011, 19:02 »
Zitat von: erik
Was ist wenn ein Client eine synchrone Anfrage an einen Service stellt und während der Service arbeitet ein dritter Prozess einfach eine Message an den schlafenden Client schickt. So wie ich Deine Syscalls verstanden habe würde dann einfach der Client aufwachen und mit der gefackten Message als Antwort weiterarbeiten.
Das habe ich bedacht und der Client kann nur von dem "Port" (weil da kommt ja im Endeffekt die Antwort her) aufgeweckt werden, an den die Anfrage gesendet wurde. Wenn ein anderer "Port" versucht eine Nachricht an den Thread zu schicken, bekommt der ne Fehlermeldung zurück.

Zitat von: erik
Für was? Welchen Vorteil erhoffst Du Dir dadurch?
Um mir die Arbeit zu erleichtern und auch das Portieren dürfte dadurch einfacher werden. Ich werde nochmal darüber nachdenken ob es wirklich nötig ist. Eigentlich hast du ja Recht ;)

Zitat von: erik
Ich persönlich sehe da eigentlich nur den Nachteil von potentiell mehr Syscalls pro IPC-Vorgang und längeren Latenzen weil der Service gerade nicht in der Abhole-Warte-Position ist (dann muss nämlich gequeued werden).
Also wenn du nur einen Thread pro Port erstellen kannst, läuft es auch darauf hinaus, das gequeuet wird. Also schonmal kein Unterschied. Was du mit den mehr Syscalls pro IPC-Vorgang meinst weiß ich allerdings nicht.

Zitat von: erik
Außerdem muss Du ja die gewünschte Anzahl an Threads bereits da haben um dann (falls mal genügend Clients parallel Wünsche haben) auch entsprechend bedienen zu können.
Dazu fällt mir dann doch was ein. Als Bsp. für aktives Abholen würde ich Spiele sehen. Du hast eine GameLoop und rufst einmal die Nachrichten ab und berechnest darauf hin einen neuen Frame. Allerdings lässt es sich bestimmt auch ohne aktives Abholen lösen.

Zitat von: erik
Man kann ja erst mal ein möglichst großes Limit benutzen, es werden ja nie mehr PopUp-Threads injiziert als auch tatsächlich parallele Anfragen kommen so das da erstmal keine Speicherverschwendung entsteht, und dann mal schauen ob es zu Problemen kommt.
Das sehe ich als potentielles Sicherheits Problem, bei mir nochmehr als bei dir (da ich ja entweder keinen bzw. vllt bald einen oder unendliche viele Threads zulasse). Denn sowas öffnet DoS Attacken Tür und Tor.

Zitat von: erik
Da müssen aber eine ganze Menge Dinge auf der User-Mode-Seite sauber mitspielen damit das ordentlich funktioniert, das wäre mir zu heikel, ich möchte lieber das mein IPC-System so einfach wie möglich zu benutzen ist und eben eine möglichst kleine Angriffsfläche gegen (un)beabsichtigte SW-Fehler bietet.
Das lässt sich doch ganz einfach in einer Library (oder auch API) kapseln. Da sehe ich jetzt nicht das Problem.

Zitat von: erik
Du willst alle Threads eines Prozesses einfrieren? Hm, das erscheint mir dann doch etwas zu drastisch, das macht ja noch nicht einmal POSIX.
Das könnte deswegen so drastisch sein, weil ich von Signalen überhaupt keine Ahnung habe ;)

Zitat von: erik
Wenn Du per IPC Speicher vom Client an den Service mitgeben möchtest dann bekommt der Kernel beim Syscall einen Pointer und eine Größenangabe, dann sucht er sich einen passenden Platz im virtuellen Adressraum des Service und mappt alle Pages auch dort hinein.
Also da muss ich dann doch mal stänkern. Du und taljeth hattet mir mal gesagt ein read Syscall der mir den Speicher zurück liefert wäre blödsinnig und eher abnormal, aber genau das was du ja vorschlägst ist ja nichts anderes ;)

Ich mache das im Endeffekt ja auch, nur bei mir gibt es halt nur Nachrichten mit 32byte oder mit den 32byte und Speicher mit dem vielfachen von der Page-Größe. Ist auch irgendwo dynamisch, aber es ist halt weniger aufwendig, was die Verwaltung und das Kopieren betrifft. Das ist doch im Endeffekt das was du auch willst. gibt es halt Verschnitt, besser als kopieren ;)

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 24. January 2011, 21:03 »
Zitat von: erik
Außerdem muss Du ja die gewünschte Anzahl an Threads bereits da haben um dann (falls mal genügend Clients parallel Wünsche haben) auch entsprechend bedienen zu können.
Dazu fällt mir dann doch was ein. Als Bsp. für aktives Abholen würde ich Spiele sehen. Du hast eine GameLoop und rufst einmal die Nachrichten ab und berechnest darauf hin einen neuen Frame. Allerdings lässt es sich bestimmt auch ohne aktives Abholen lösen.
Du brauchst bloß eine globale Variable (geschützt durch eine Semaphore) benutzen, in die das RPC per Extra-Thread die Daten injiziert. Deine Hauptschleife fragt dann nicht den Kernel (der dadurch u.U. Performanceprobleme kriegt, weil das RPC überlastet ist), sondern eine Variable, die schon im eigenen Adressraum liegt. Und wenn diese gerade nicht geschrieben werden kann, dann muss der RPC-Thread halt warten.

Zitat von: erik
Man kann ja erst mal ein möglichst großes Limit benutzen, es werden ja nie mehr PopUp-Threads injiziert als auch tatsächlich parallele Anfragen kommen so das da erstmal keine Speicherverschwendung entsteht, und dann mal schauen ob es zu Problemen kommt.
Das sehe ich als potentielles Sicherheits Problem, bei mir nochmehr als bei dir (da ich ja entweder keinen bzw. vllt bald einen oder unendliche viele Threads zulasse). Denn sowas öffnet DoS Attacken Tür und Tor.
Darum ein Limit.
Es gibt Fälle, wo das Limit offensichtlich ist (zumindest der Maximalwert). Grundsätzlich ist so ein Limit ein "tuneable", also eine Stellschraube, die man immer mal wieder anpassen muss. Ganz ohne wirst du in deinem OS nie auskommen. Es gibt definitiv Konstanten, die nicht 0, 1 oder INT_MAX-1 sind. :-)

Das lässt sich doch ganz einfach in einer Library (oder auch API) kapseln. Da sehe ich jetzt nicht das Problem.
Wenn du schon eine Library brauchst, um deine Anwendungen auch nur überhaupt mit dem Kernel zu verbinden, dann viel Spaß beim Portieren. Du solltest das Programmieren "ohne Lib" nicht unnötig erschweren.

In die API kapseln heißt wieder zusätzlichen Aufwand in Kauf nehmen.

Ich mache das im Endeffekt ja auch, nur bei mir gibt es halt nur Nachrichten mit 32byte oder mit den 32byte und Speicher mit dem vielfachen von der Page-Größe. Ist auch irgendwo dynamisch, aber es ist halt weniger aufwendig, was die Verwaltung und das Kopieren betrifft. Das ist doch im Endeffekt das was du auch willst. gibt es halt Verschnitt, besser als kopieren ;)
Statische Größen haben auch Vorteile. Sie vereinfachen die Implementierung und, wenn die Nachrichten klein genug (aber nicht zu klein) sind, dann kann man das auch schön effizient bauen. Und es gibt weniger Angriffsfläche.

Gruß,
Svenska

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 24. January 2011, 21:19 »
Zitat von: svenska
Du brauchst bloß eine globale Variable (geschützt durch eine Semaphore) benutzen, in die das RPC per Extra-Thread die Daten injiziert. Deine Hauptschleife fragt dann nicht den Kernel (der dadurch u.U. Performanceprobleme kriegt, weil das RPC überlastet ist), sondern eine Variable, die schon im eigenen Adressraum liegt. Und wenn diese gerade nicht geschrieben werden kann, dann muss der RPC-Thread halt warten.
Naja, es wäre doch aber besser z.B. Tasten-Events in eine Queue zu packen als entwender einen Thread warten zu lassen oder viele Threads warten zu lassen.

Zitat von: svenska
Es gibt Fälle, wo das Limit offensichtlich ist (zumindest der Maximalwert). Grundsätzlich ist so ein Limit ein "tuneable", also eine Stellschraube, die man immer mal wieder anpassen muss. Ganz ohne wirst du in deinem OS nie auskommen. Es gibt definitiv Konstanten, die nicht 0, 1 oder INT_MAX-1 sind.
Das stimmt soweit, aber ;) Es gibt ja auch bei anderen OS die Möglichkeit auf eine Nachricht zu warten und dort kann man einstellen ob man gar nicht warten will, ob man solange warten will bis eine Nachricht da ist oder man gibt eine Zeit vor. Die Erfahrungen hatten damals gezeigt das entweder kein Timeout genutzt wird oder solange gewartet wird bis eine Nachricht vorhanden ist.

Deswegen würde ich halt sagen, lege ich einfach die zwei Limits fest (1 oder unendlich viele Threads) und hoffe auf das beste ;)

Zitat von: svenska
Wenn du schon eine Library brauchst, um deine Anwendungen auch nur überhaupt mit dem Kernel zu verbinden, dann viel Spaß beim Portieren. Du solltest das Programmieren "ohne Lib" nicht unnötig erschweren.

In die API kapseln heißt wieder zusätzlichen Aufwand in Kauf nehmen.
Den Aufwand nehme ich gerne in Kauf. Denn was das betrifft handhabe ich es wie unter Windows, alles lieber über eine API/Libraries kapseln und nicht direkt mit dem Kernel kommunizieren. Welches Programm kommuniziert schon direkt mit dem Kernel? Die meisten werden zumindest die libc voraussetzen und auf meinem OS kommt dann halt noch eine Library (libos) dazu. Sehe ich jetzt nicht so das Problem. Macht auch eventuelle Änderungen am Kernel einfacher.

erik.vikinger

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


der Client kann nur von dem "Port" (weil da kommt ja im Endeffekt die Antwort her) aufgeweckt werden, an den die Anfrage gesendet wurde. Wenn ein anderer "Port" versucht eine Nachricht an den Thread zu schicken, bekommt der ne Fehlermeldung zurück.
Aber für diese Überprüfung benötigst Du einen extra Vergleich im Kernel und der kostet nen halben Takt, und zwar bei jedem IPC-Vorgang. Bei meinen Konzept benötige ich diesen Vergleich nicht weil der Syscall für das zurückschicken der Antwort sein Ziel ja gerade aus einer kernelinternen Struktur (die den IPC-Vorgang beschreibt) geholt hat.

Um mir die Arbeit zu erleichtern und auch das Portieren dürfte dadurch einfacher werden.
Ich glaube das beides mit Deinem Konzept eher schwieriger ist als mit einem echt synchronen IPC-Konzept. Im Prinzip simulierst Du ja einen synchronen IPC-Vorgang mit 2 asynchronen IPC-Vorgängen.

Eigentlich hast du ja Recht ;)
Das hattest Du doch hoffentlich nie bezweifelt, oder etwa doch? ;)

Also wenn du nur einen Thread pro Port erstellen kannst, läuft es auch darauf hinaus, das gequeuet wird. Also schonmal kein Unterschied.
Ich habe ein einstellbares Limit vorgeschlagen (das auch auf 1 stehen darf aber eben nicht muss) und somit dürfte bei mir fast nie gequeued werden.

Was du mit den mehr Syscalls pro IPC-Vorgang meinst weiß ich allerdings nicht.
Ich könnte mir Vorstellen das so ein "gib mir die nächste Anfrage"-Syscall eventuell ein Timeout hat oder das der Service erst noch fragen muss wie viel Speicher er denn nun bekommen hat. Des weiteren könnte der Service es als nötig erachten zusätzliche Threads zu erstellen was auch wieder Syscalls kostet. Ich bin mir nicht ganz sicher ob Dein Konzept wirklich zwangsläufig zu mehr Syscalls führt aber ausschließen kann ich das auch nicht.

Das sehe ich als potentielles Sicherheits Problem, bei mir nochmehr als bei dir (da ich ja entweder keinen bzw. vllt bald einen oder unendliche viele Threads zulasse). Denn sowas öffnet DoS Attacken Tür und Tor.
Deswegen ja ein vom Service einstellbares Limit, das dürfte den meisten Kram ganz gut abfangen. Aber grundsätzlich ist es immer möglich das ein Programm, das die Möglichkeit hat beliebige Syscalls zu machen, ein System in die Knie zwingen kann. Nur instabil darf das System dadurch nicht werden. Da ich vor habe den Speicherverbrauch der PopUp-Threads dem Client zu zu rechnen dürfte das zumindest zu exzessive DoS-Angriffe auch etwas limitieren. Ein weiterer Punkt wäre das vererben der Priorität des Clients an den PopUp-Thread, in der Hoffnung dass das Schadprogramm zumindest noch nicht die Rechtevergabe geknackt hat und daher nicht die Möglichkeit hat mit hoher Priorität zu arbeiten, so würden wenigstens die wichtigen Programme noch einigermaßen laufen können.

Zitat von: erik
Wenn Du per IPC Speicher vom Client an den Service mitgeben möchtest dann bekommt der Kernel beim Syscall einen Pointer und eine Größenangabe, dann sucht er sich einen passenden Platz im virtuellen Adressraum des Service und mappt alle Pages auch dort hinein.
Also da muss ich dann doch mal stänkern. Du und taljeth hattet mir mal gesagt ein read Syscall der mir den Speicher zurück liefert wäre blödsinnig und eher abnormal, aber genau das was du ja vorschlägst ist ja nichts anderes ;)
Sorry, ich hatte vergessen zu erklären dass das nur die Richtung vom Client zum Service betrifft in der anderen Richtung wird kein Speicher weitergegeben sondern eben das Mapping beim Service wieder entfernt. Auch deswegen ist es gut wenn man eine Antwort anders behandelt als eine Anfrage. In meinem IPC-Vorschlag kann der Client bei jeder synchronen Anfrage bis zu 4 Speicherbereiche dem Service (für die Dauer der Bearbeitung) zur Verfügung stellen, bis zu 2 Bereiche aus denen der Service nur lesen kann und bis zu 2 Bereiche in die der Service nur schreiben kann.


.... Die Erfahrungen hatten damals gezeigt das entweder kein Timeout genutzt wird oder solange gewartet wird bis eine Nachricht vorhanden ist.
Und was denkst du woran das liegt? Wenn ich jetzt einfach mal behaupte das es an unfähigen Programmierern liegt dann dürfte diese Behauptung in gar nicht so wenigen Fällen zumindest etwas zutreffen. Der Programmierer muss sich mit diesem Thema auch mal richtig auseinander setzen um überhaupt zu verstehen worum es bei dem TimeOut eigentlich geht und welche Auswirkungen (auf die Funktionalität aber auch auf die Stabilität) dieses hat.

.... und hoffe auf das beste ;)
Nunja, die Hoffnung stirbt zuletzt. ;) Viel Glück!


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

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 24. January 2011, 22:04 »
Zitat von: erik
Aber für diese Überprüfung benötigst Du einen extra Vergleich im Kernel und der kostet nen halben Takt, und zwar bei jedem IPC-Vorgang. Bei meinen Konzept benötige ich diesen Vergleich nicht weil der Syscall für das zurückschicken der Antwort sein Ziel ja gerade aus einer kernelinternen Struktur (die den IPC-Vorgang beschreibt) geholt hat.
Meinst du wirklich es macht einen Unterschied ob ich halt eine Überprüfung durchführe und dafür nen Wert zwischen speicherst?

Zitat von: erik
Ich glaube das beides mit Deinem Konzept eher schwieriger ist als mit einem echt synchronen IPC-Konzept. Im Prinzip simulierst Du ja einen synchronen IPC-Vorgang mit 2 asynchronen IPC-Vorgängen.
Naja, der Punkt ist doch das es nach Außen synchron ist und damit sollte es keine Probleme geben.

Zitat von: erik
Ich könnte mir Vorstellen das so ein "gib mir die nächste Anfrage"-Syscall eventuell ein Timeout hat oder das der Service erst noch fragen muss wie viel Speicher er denn nun bekommen hat. Des weiteren könnte der Service es als nötig erachten zusätzliche Threads zu erstellen was auch wieder Syscalls kostet.
Also wiegesagt Timeouts habe ich nicht (ich sehe auch keinen Sinn darin, weil wie willst du wissen was ein guter Timeout-Wert ist?) und nach der Speichergröße musst du auf Grund von fixed-Size Nachrichten auch nicht fragen.
Was die weiteren Threads betrifft, trifft das auch auf dein System zu, das macht eigentlich keinen Unterschied.

Zitat von: erik
Sorry, ich hatte vergessen zu erklären dass das nur die Richtung vom Client zum Service betrifft in der anderen Richtung wird kein Speicher weitergegeben sondern eben das Mapping beim Service wieder entfernt. Auch deswegen ist es gut wenn man eine Antwort anders behandelt als eine Anfrage.
Im Endeffekt meinst du also das ich einen reply-Syscall haben sollte, der dann nur noch eine fixed-Size Nachricht beinhaltet und keinen SharedMem mehr mitsenden kann? Ist eine Idee, muss ich mir nochmal durch den Kopf gehen lassen.

Zitat von: erik
Und was denkst du woran das liegt? Wenn ich jetzt einfach mal behaupte das es an unfähigen Programmierern liegt dann dürfte diese Behauptung in gar nicht so wenigen Fällen zumindest etwas zutreffen. Der Programmierer muss sich mit diesem Thema auch mal richtig auseinander setzen um überhaupt zu verstehen worum es bei dem TimeOut eigentlich geht und welche Auswirkungen (auf die Funktionalität aber auch auf die Stabilität) dieses hat.
Also ich zähle mich dann zu den unfähigen Programmierern. Denn mir erschließt sich solch ein Timeout auch nicht ganz, weil ich einfach der Meinung bin entweder es ist zu groß gewählt oder es ist zu klein gewählt.

Außerdem macht es ein Timeout nicht wirklich leichter (also im Kernel und auch sonst).

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 24. January 2011, 22:50 »
Hallo,


Meinst du wirklich es macht einen Unterschied ob ich halt eine Überprüfung durchführe und dafür nen Wert zwischen speicherst?
Ich meine der wesentliche Unterschied ist das Du in Deinen mächtigen IPC-Syscalls überhaupt ne Menge an Fallunterscheidungen drin hast.

Was die weiteren Threads betrifft, trifft das auch auf dein System zu, das macht eigentlich keinen Unterschied.
Das stimmt nicht ganz, wenn bei mir mehr Threads für das behandeln der IPC-Anfragen nötig sind dann erstellt der Kernel selber welche und nicht der Service.

Im Endeffekt meinst du also das ich einen reply-Syscall haben sollte, der dann nur noch eine fixed-Size Nachricht beinhaltet und keinen SharedMem mehr mitsenden kann?
Fast, ich meine das Du einen reply-Syscall haben solltest der nur noch das für die Anfrage eingerichtete Memory-Sharing wieder beendet (so das der Speicher den der Client seiner Anfrage beigefügt hat damit der Service darauf zugreifen kann nun wieder dem Client ganz allein gehört). Die Antwort liegt ja bereits im Speicher des Clients, der Service hat die Antwort ja direkt in den geshareten Speicher geschrieben und damit auch unmittelbar in den Speicher des Client.

Da fällt mir ein das ich bei Deinen Syscalls keine Möglichkeit gesehen habe das Memory-Sharing wieder zu beenden. Woher weiß der Kernel dann das der synchrone IPC-Vorgang abgeschlossen ist und das Sharing nicht mehr benötigt wird?

Also ich zähle mich dann zu den unfähigen Programmierern.
Diese Beurteilung kann und will ich nicht für Dich übernehmen. ;)
Fakt ist das es solche TimeOuts bei allen relevanten OSen gibt und dort auch sinnvoll eingesetzt werden (können).


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 #18 am: 25. January 2011, 12:40 »
Zitat von: erik
Das stimmt nicht ganz, wenn bei mir mehr Threads für das behandeln der IPC-Anfragen nötig sind dann erstellt der Kernel selber welche und nicht der Service.
Das meintest du also. Ich dachte du meinst, wenn beim Bearbeiten der Nachricht festgestellt wird, dass noch mehr Threads benötigt werden.
Also bei meinem momentanen Code wäre es theoretisch möglich das mehrere Threads von einem Port lesen, aber praktisch hätte ich das nicht gemacht.

Zitat von: erik
Fast, ich meine das Du einen reply-Syscall haben solltest der nur noch das für die Anfrage eingerichtete Memory-Sharing wieder beendet (so das der Speicher den der Client seiner Anfrage beigefügt hat damit der Service darauf zugreifen kann nun wieder dem Client ganz allein gehört). Die Antwort liegt ja bereits im Speicher des Clients, der Service hat die Antwort ja direkt in den geshareten Speicher geschrieben und damit auch unmittelbar in den Speicher des Client.
Ich will aber auch die Möglichkeit haben, das ein Prozess einem anderen Speicher schicken kann, worüber die beiden dann kommunizieren können, klassischer SharedMem halt und da müsste ich dann wiederrum ein Flag anbieten welches dafür sorgt, das beim Antworten halt nicht der Speicher wieder entfernt wird. Auch stelle ich mir RPC wie einen Funktionsaufruf vor und in die 32byte sollen halt die Parameter rein und in den mitgeschickten SharedMem sind alle Daten die du normalerweise als Pointer übergeben würdes. Eine Funktion hat ja dann noch einen Rückgabewert und diesen würde ich wieder in die 32byte packen.

Zitat von: erik
Da fällt mir ein das ich bei Deinen Syscalls keine Möglichkeit gesehen habe das Memory-Sharing wieder zu beenden. Woher weiß der Kernel dann das der synchrone IPC-Vorgang abgeschlossen ist und das Sharing nicht mehr benötigt wird?
Das liegt daran, das ich es zwr geplant, aber noch nicht implementiert habe. Ansonsten hätte ich es dem Service überlassen ob er den Speicher wieder unmappt oder nicht (ich weiß großes Sicherheitsloch).

Zitat von: erik
Fakt ist das es solche TimeOuts bei allen relevanten OSen gibt und dort auch sinnvoll eingesetzt werden (können).
Ich habe halt das Problem wie soll ich einen vernünftigen Wert auswählen? Habe ich dann einen Wert wird dieser für bestimmte Situationen einfach zu kurz sein (z.B. hohe CPU-Auslastung und der Thread der gerne antworten möchte kommt einfach nicht an die Reihe) oder er ist so lang das der Timeout schonwieder keinen Sinn mehr macht.

Es wäre aber mal interessant zu wissen wie du (oder auch man im allgemeinen) solch einen Timeout einsetzen würdest bzw. wofür sowas eingesetzt wird.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #19 am: 25. January 2011, 20:50 »
Hallo,


Ich will aber auch die Möglichkeit haben, das ein Prozess einem anderen Speicher schicken kann, worüber die beiden dann kommunizieren können, klassischer SharedMem halt
Dann mach doch über 2 oder 3 weitere Syscalls klassisches SharedMem. Warum versuchst Du in die IPC-Syscalls so viele verschiedene Funktionalitäten rein zu packen?
Das wird doch dann nur ein riesiger Code-Blob der um so schwerer zu warten ist um so größer er wird. Versuche lieber für jede klar definierte Aufgabe einen kleinen aber exakt passenden Syscall zu machen, das soll nicht heißen das man allen möglichen Kram in X Varianten anbieten soll aber synchrones IP + asynchrones IPC + Shared-Memory über jeweils ein paar eigene Syscalls empfinde ich persönlich als eine gute Lösung. Wenn bei der Implementierung dann gewisse algorithmische Gemeinsamkeiten vorkommen dann kannst Du das immer noch in eigene Unterfunktionen packen die dann von mehreren Syscalls benutzt werden.

und da müsste ich dann wiederrum ein Flag anbieten welches dafür sorgt, das beim Antworten halt nicht der Speicher wieder entfernt wird.
Hm, an was bei Dir der Programmierer dann alles Denken muss? Im Endeffekt wird es darauf hinauslaufen das Du dann in der OS-Library versuchst für jeden üblichen Verwendungszweck ein eigenes kleines API zu bauen wo die Funktionen dann nichts weiter machen als die richtigen Flags für ihre spezielle Verwendung der Alles-in-Eins Syscalls anzuhängen. Das ist doch doof wenn Du versucht im User-Mode alles zusammenzufassen nur damit Du das im Kernel wieder auseinander pflückst. Nebst dessen das Deinen generischen Syscalls auch ziemlich schnell die Register für die Parameter ausgehen dürften.

Auch stelle ich mir RPC wie einen Funktionsaufruf vor und in die 32byte sollen halt die Parameter rein und in den mitgeschickten SharedMem sind alle Daten die du normalerweise als Pointer übergeben würdes. Eine Funktion hat ja dann noch einen Rückgabewert und diesen würde ich wieder in die 32byte packen.
Deswegen hab ich in meinem Konzept ja 2 Speicherbereiche pro Richtung vorgesehen damit die Befehle von den Nutzdaten getrennt bleiben können. Wenn nicht alle 4 Speicherbereiche für einen bestimmten RPC benötigt werden kann der Client da einfach einen NULL-Pointer (und die Länge 0) mitgeben. Aber ich würde trotzdem nicht auf dynamic-size verzichten weder bei den Parametern/Rückgabewerten und erst recht nicht bei den eigentlichen Nutzdaten. 32 Byte für die Rückgabewerte könnten z.B. für ein fstat-RPC zu wenig sein wenn da die Datei-Größe (8 Bytes), die Zugriffsrechte, die Daten für letzte Änderung, letzten Zugriff und Erstellung, ..... drin sein sollen. Aber dafür gleich ne ganze Page zu verschicken ist IMHO auch nicht sehr effizient. Wenn Du da http://codewiki.wikidot.com/c:system-calls:fstat mal im Beispiel-Code schaust wirst Du sehen dass das Struct als lokale Variable auf dem Stack liegt. In meiner Idee kann der fstat-Stub in der libc einfach das struct (in welches der Applications-Code die Infos rein haben will) beim fstat-RPC als Shared-Memory mit geben und der Service befüllt das dann direkt ohne das irgendetwas noch zusätzlich kopiert werden müsste. In Deiner Idee müsste der VFS-Service eine Page allozieren und diese in der RPC-Antwort dem fstat-Stub übermitteln welcher dann die Infos dort raus kopiert und die Page wieder frei gibt, das sind 2 zusätzliche Syscalls (für allozieren und freigeben der Page) und einmal Kopieren als zusätzlicher Aufwand ohne das Du da etwas gewinnst (die eigentliche Nutzarbeit des Service, das befüllen der Struktur, ist dagegen kaum relevant). Genau deswegen bin ich der Meinung das mein IPC-Konzept um viele Größenordnungen schneller ist.

Aus diesem Grund wird bei tyndur momentan versucht das VFS mit in den Kernel2 zu nehmen damit man sich da einiges an IPC-(Kopier-)Arbeit sparen kann. Das IPC-Konzept von tnydur ist nämlich noch ineffizienter als Deine Idee, aber zumindest hat tyndur Dynamic-Size-Messages.

Ansonsten hätte ich es dem Service überlassen ob er den Speicher wieder unmappt oder nicht (ich weiß großes Sicherheitsloch).
Gut das Du das selber weißt sonst hätte ich Dir das jetzt um die Ohren gehauen. ;) Sowas ist mehr als nur grob fahrlässig!

Es wäre aber mal interessant zu wissen wie du (oder auch man im allgemeinen) solch einen Timeout einsetzen würdest bzw. wofür sowas eingesetzt wird.
Das hängt sehr von der Situation ab, das kann man nicht pauschal beantworten. Für das aktive IPC-Abholen würde ich gar kein Timeout implementieren, entweder man schaut nur kurz und kommt gleich wieder zurück oder man wartet ewig (wenn ein Service momentan nicht benutzt wird ist es ja auch Quatsch wenn der recv-Syscall alle Nase lang nen Timeout-Error-Code zurückmeldet, was soll der Service damit anfangen). Beim Client sieht die Sache schon wieder ganz anders aus. Wenn ein Browser eine TCP-Conection auf machen möchte dann sollte es da ganz klar ein vernünftiges Timeout geben, was da als vernünftig gilt hängt davon ab wie lange ein funktionierender Server im Worst-Case so braucht und wie lange der User bereit ist zu warten. Die Länge von Timeouts sind kein programmiertechnisches Problem sondern gehört eher in die Kategorien Sicherheit und Usability, der Programmierer muss das Timeout nur auch wirklich benutzen.


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

 

Einloggen