Lowlevel

Lowlevel => Lowlevel-Coding => Thema gestartet von: FlashBurn am 23. January 2011, 10:10

Titel: erik´s IPC Idee ;)
Beitrag von: FlashBurn 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.
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger 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 (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
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn 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 ;)
Titel: Re:erik´s IPC Idee ;)
Beitrag von: Svenska 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).

;-)
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn 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.
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger 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
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn 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.
Titel: Re:erik´s IPC Idee ;)
Beitrag von: Svenska 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
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn 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.
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger 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
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn 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).
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger 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
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn 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 ;)
Titel: Re:erik´s IPC Idee ;)
Beitrag von: Svenska 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
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn 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.
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger 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 (http://forum.lowlevel.eu/index.php?topic=2433) 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
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn 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).
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger 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
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn 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.
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger 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 (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
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn am 25. January 2011, 21:50
Zitat von: erik
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?
Die eigentliche Idee dahinter war, das ich nicht (am Bsp. SharedMem versenden) so wenig wie möglich Syscalls machen will (nicht die die vorhanden sind, sondern die die gemacht werden müssen damit etwas bestimmt erledigt werden kann).
Im Normalfall wird SharedMem benötigt um Daten per IPC zu versenden. Deswegen wollte/will ich es da gleich mit drin haben und dann wollte ich noch die Anzahl der Syscalls beschränken. Denn den SharedMem musst du so oder so versenden damit dann ein anderer Prozess Zugriff drauf hat. Also kann ich mir einen Syscall um SharedMem zu erstellen auf jeden Fall sparen. Nur einen um SharedMem wieder zu unmappen wäre vllt angebracht.

Zitat von: erik
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.
Diese API wäre ja nur damit der Programmierer ein einfacheres Leben hat. Problem ist es halt eine gewisse Balance zu finden, auf der einen Seite will ich das so wenig wie nötig in den Kernel gewechselt werden muss und auf der anderen Seite will ich die Anzahl der Syscalls begrenzen (warum weiß ich gerade auch nicht  :roll: ).

Zitat von: erik
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.
Also erstmal werde ich an dein IPC System eh nicht rankommen können, weil du ja Segmente nutzt. Das nächste ist, dass du die Richtung verwechselt hast ;) Der Client schickt eine Page mit und der Service kopiert dort die Daten rein. Für solche Sachen kann man auch einfach pro Thread provisorisch schonmal einfach eine Page vorallokieren und die dann immer für sowas nutzen.

Ich habe einfach das Problem das ich mit den dynamic-Size Nachrichten nicht richtig umzugehen wüsste. Kopieren wird in den meisten Fällen dort nicht ausbleiben (erste und letzte Page) und sind die Daten kleiner als eine Page muss ohnehin kopiert werden und dann bekomme ich da ein Problem das ich diese Sachen (Daten < eine Page) ja im Kernel Zwischenspeichern muss und da müsste ich auch erstmal nen Allocator für schreiben und der müsste dann auch noch sehr gut mit parallelen Zugriffen klarkommen. Von daher halte ich meine Idee für effizienter in der Geschwindigkeit, aber dafür ineffizienter was den Speicherverbrauch betrifft.

Ich habe mir nochmal Gedanken wegen synchron und asynchron und sowas gemacht. Also ich will auf jeden Fall Popup-Threads für synchrone=RPC Sachen nehmen und da hat man dann die Wahl wieviele Threads man gleichzeitig zulässt. Sicher bin ich mir jetzt nicht ob ich die Queuetiefe auch noch beschränken sollte (das ist bei meinem momentanen Code noch möglich). Was meinst du dazu?

Was die asynchronen Sachen betrifft, will ich dort die Möglichkeit des aktiven Abholens behalten. Es programmiert sich einfach am einfachsten und wenn man (besser ich ;) ) besser mit den Popup-Threads umgehen kann, finde ich ja vllt einen Weg wie ich das dann auch noch damit hinbekomme. Aber ich denke halt immernoch an GUI-Programmierung und ich sag mal bei einem einfachen Programm würde das mit den Popup-Threads wahrscheinlich noch einfach umzusetzen sein. Wenn ich dann aber mal wieder an ein Spiel denke stelle ich es mir blöd vor alles erstmal nochmal in eine Queue zu packen nur damit es dann ein anderer Thread da wieder rausholen kann, wenn er denn soweit ist (obwohl das vllt auch gar nicht so verkehrt wäre, weil der dann nicht in den Kernel müsste?).
Auch ein Media-Player (besonders Video) wäre vllt auch ganz günstig wenn der Dekoder in einem extra Thread läuft und die GUI in einem anderen.

Es zeigt sich halt das man schlecht Sachen designen kann mit denen man noch keine Erfahrung hat.
Titel: Re:erik´s IPC Idee ;)
Beitrag von: Svenska am 25. January 2011, 22:01
Timeouts sind dafür da, dass Anwendungen (d.h. die Dinge, die in der Regel von Nicht-System-Programmierern programmiert werden!) sich nicht mit Multithreading oder asynchronen Dingen herumplagen müssen, wenn sie es nicht wollen.

Sicherlich ist es für bestimmte Anwendungen sinnvoll, einen eigenen Thread für die Verwaltung von RPC oder Signalen aufzumachen, aber einfache, lineare Anwendungen brauchen auch eine Möglichkeit, aus einer potentiellen Endlosschleife wieder rauszukommen.

Der Wert des Timeouts ist in der Regel anwendungsabhängig. Für einen DNS-Resolver sind das vielleicht 1-2 Sekunden, ehe er auf einen zweiten Server umschwenkt. Und wenn ich ein simples Netcat baue und da gerne mit synchronen APIs arbeite (und weiß, dass die Masse der Daten nach innen geht), dann kann ich einfach etwas in der Art tun:

while(1) {
  result = read_data(network_id, timeout=50ms, &buf);
  if(result) { send_to_screen(buf, length=result); }
  result = read_data(keyboard_id, timeout=50ms, &buf);
  if(result) { send_to_network(buf, length=result); }
}

Das ist sicherlich keine optimale Lösung, aber eine, die recht häufig vorkommt. Außerdem sind Syscalls mit Ablaufzeit immer eine Möglichkeit, einfaches Timeout-Handling zu haben - ohne sich mit Timer-Signalen und Signal-Handling rumschlagen zu müssen.

Ich habe mir nochmal Gedanken wegen synchron und asynchron und sowas gemacht. Also ich will auf jeden Fall Popup-Threads für synchrone=RPC Sachen nehmen und da hat man dann die Wahl wieviele Threads man gleichzeitig zulässt.
Synchron heißt, Client schickt Frage an Server und kriegt direkt eine Antwort (die Frage blockiert, bis die Antwort vorliegt). Da sind Popup-Thread definitiv der falsche Weg, das ist asynchron.

Was die asynchronen Sachen betrifft, will ich dort die Möglichkeit des aktiven Abholens behalten.
Aktives Abholen ist sinnvoll, aber nicht überall - und nicht unbedingt der Königsweg, den man erzwingen muss. Zumal das eher synchron ist, also hast du die Begriffe verwechselt.

Also eher für asynchrone Vorgänge einen Popup-Thread erzeugen, synchrone Vorgänge blockieren. Und es gibt eine Funktion, die auf einen Popup-Thread (also auf asynchrones IPC) aktiv wartet.

Wenn ich dann aber mal wieder an ein Spiel denke stelle ich es mir blöd vor alles erstmal nochmal in eine Queue zu packen nur damit es dann ein anderer Thread da wieder rausholen kann, wenn er denn soweit ist (obwohl das vllt auch gar nicht so verkehrt wäre, weil der dann nicht in den Kernel müsste?).
Ob nun der Kernel drei Dutzend Popup-Threads erzeugt, die alle mangels CPU-Zeit nicht an die Reihe kommen (und die auch in irgendeine bestimmte Reihenfolge gebracht werden müssen), oder ob der Kernel die Events einfach queuet und dann der Hauptschleife schenkt, ist doch egal.

Bei komplexen Spielen mit vielen Threads hast du eh spezielle Threads für Input-Handling, Netzwerk-Handling und so weiter, die sich nur für bestimmte Ereignisse interessieren und von der Hauptschleife unabhängig sind.

Auch ein Media-Player (besonders Video) wäre vllt auch ganz günstig wenn der Dekoder in einem extra Thread läuft und die GUI in einem anderen.
Ja, sicher ist es günstig. Aber willst du es durch dein API-Design erzwingen?

Gruß,
Svenska
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn am 25. January 2011, 22:14
Zitat von: svenska
Synchron heißt, Client schickt Frage an Server und kriegt direkt eine Antwort (die Frage blockiert, bis die Antwort vorliegt). Da sind Popup-Thread definitiv der falsche Weg, das ist asynchron.
Nope ;)

Der Client macht eine RPC-Anfrage an einen Service und blockiert. Beim Service wird ein Thread erzeugt (Popup-Thread) der die Anfrage entgegen nimmt, bearbeitet und die Antwort sendet.

Zitat von: svenska
Aktives Abholen ist sinnvoll, aber nicht überall - und nicht unbedingt der Königsweg, den man erzwingen muss. Zumal das eher synchron ist, also hast du die Begriffe verwechselt.
Also ich will das nicht erzwingen, sondern ich will mir die Möglichkeit offen halten und nicht die Popup-Threads erzwingen. Ich denke eher du hast die Begriffe verwechselt ;)

Beim Empfangen würde ich es synchron nennen, wenn der Empfänger solange blockiert bis eine Nachricht da ist und asynchron wenn er Polling macht (also jedes Mal gleich wieder zurückkehrt wenn keine Nachricht da ist). Beides will ich ermöglichen, aber halt über das aktive Abholen (was ja eigentlich logisch ist).

Zitat von: svenska
Ja, sicher ist es günstig. Aber willst du es durch dein API-Design erzwingen?
Nein, wie oben schon geschrieben will ich gar nichts erzwingen, aber ich will auch nicht das man sich verrenken muss um bestimmte Dinge zu machen. Deswegen will ich beide Wege anbieten (aktives Abholen und Popup-Threads).
Titel: Re:erik´s IPC Idee ;)
Beitrag von: Svenska am 25. January 2011, 23:52
Ich betrachte alles aus der Sicht der Anwendung, die am Ende RPC machen möchte. Wie das intern implementiert ist und wie der Server strukturiert ist, um darauf zu reagieren, ist an der Stelle egal. Von daher ist die Bezeichnung "synchron im Server" nicht unbedingt zielführend. Und weder "Empfangen" noch "Senden" können damit bezeichnet werden, weil die Begriffe "synchron"/"asynchron" gerade das Zusammenspiel zwischen Senden und Empfangen bezeichnen.

Entweder du hast ein synchrones RPC-Spielchen, wo die Anwendung eine Funktion aufruft, solange blockiert, bis die Antwort vorliegt und sie direkt hat, oder du hast asynchrones RPC, wo die Anwendung eine Funktion aufruft, die sofort zurückkehrt und die Antwort per Signal* zugestellt wird (oder nur der Hinweis, dass jetzt etwas angekommen ist und die Anwendung muss sich das Ereignis selbst abholen).

Sinnvoll finde ich an der Stelle eine Funktion "waitfor_event", die blockiert, bis ein asynchrones Ereignis auftritt, aber das Signal* ist meiner Meinung nach notwendig, um vollkommen asynchrone Anwendungen zu ermöglichen.

*Das Signal kann dein Popup-Thread sein.

Im Server selbst kannst du einen Popup-Threads erzeugen, wenn eine RPC-Anfrage eingeht, aber das halte ich nicht für zielführend. Ich weiß, du stehst auf viele Threads, aber wenn jede RPC-Anfrage einen Thread erzeugt, kannst du den Server ganz schnell DoSen.
Um das zu verhindern, erzeugt dein Service einfach einen Thread für jede CPU (oder weniger), die in einer Endlosschleife jeweils auf ein Ereignis warten und es dann abarbeiten. Das heißt, es gibt maximal CPUZAHL gleichzeitige Ereignisse je Server, alle weiteren werden gequeued. Das erspart dem Scheduler viel Arbeit, spart bei vielen RPC-Anfragen eine Menge Speicher und macht die Services einfacher.

Gruß,
Svenska
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn am 26. January 2011, 07:41
Zitat von: svenska
Entweder du hast ein synchrones RPC-Spielchen, wo die Anwendung eine Funktion aufruft, solange blockiert, bis die Antwort vorliegt und sie direkt hat
Genauso läuft es auf der Client Seite ab.

Zitat von: svenska
Ich weiß, du stehst auf viele Threads, aber wenn jede RPC-Anfrage einen Thread erzeugt, kannst du den Server ganz schnell DoSen.
Um das zu verhindern, erzeugt dein Service einfach einen Thread für jede CPU (oder weniger), die in einer Endlosschleife jeweils auf ein Ereignis warten und es dann abarbeiten. Das heißt, es gibt maximal CPUZAHL gleichzeitige Ereignisse je Server, alle weiteren werden gequeued. Das erspart dem Scheduler viel Arbeit, spart bei vielen RPC-Anfragen eine Menge Speicher und macht die Services einfacher.
Und ich weiß du magst Multithreading nicht so ;) Ich bin davon seit BeOS überzeugt. Das Problem mit einem Thread pro CPU ist das, wie du schon richtig in einem anderen Thread festgestellt hast, oft ein Warten von I/O Ereignisse stattfindet und da wäre es wesentlich besser wenn man so viele Threads wie halt gehen hat und nicht so viele wie CPUs dasind. Denn das würde nicht den maximalen Durchsatz bringen.
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger am 26. January 2011, 11:17
Hallo,


Die eigentliche Idee dahinter war, das ich nicht (am Bsp. SharedMem versenden) so wenig wie möglich Syscalls machen will (nicht die die vorhanden sind, sondern die die gemacht werden müssen damit etwas bestimmt erledigt werden kann).
Ich verstehe was Du meinst aber normalerweise sind richtiges Shared-Memory und IPC (das nur temporäres Shared-Memory benutzt um eben Parameter und Rückgabewerte zu übertragen) zwei völlig verschiedene Dinge. Das IPC überhaupt Shared-Memory benutzt liegt einfach daran das Kopieren zu langsam/umständlich ist aber eben nicht daran das Shared-Memory konzeptioneller Bestandteil von IPC wäre. Richtiges Shared-Memory wird normalerweise für längere Zeit eingerichtet so das mehrere Prozesse gemeinsam/parallel an einem Datenbestand arbeiten können und das wiederum hat nichts mit IPC zu tun. Das der Kernel intern für das ummappen der Pages auf die selben internen Funktionen zu greift ist klar, es steckt ja auch der selbe Paging-Mechanismus dahinter, aber gerade deswegen bin ich der Meinung das ein paar zusätzliche dedizierte Shared-Memory-Syscalls Deinen Kernel kaum vergrößern werden.

Im Normalfall wird SharedMem benötigt um Daten per IPC zu versenden.
Nein, wir verwenden Shared-Memory für IPC um das teure Kopieren zu umgehen. Wenn das Kopieren nichts kosten würde würde keiner von uns auf die Idee kommen Shared-Memory für die Übermittlung der Parameter/Rückgabewerte bei IPC einzusetzen.

Das nächste ist, dass du die Richtung verwechselt hast ;) Der Client schickt eine Page mit und der Service kopiert dort die Daten rein.
Ich habe die Richtung nicht gewechselt, so war das von Anfang an in meinem Konzept vorgesehen, eben weil es sich genau so für synchrones IPC (also RPC mit Anfrage und zugehöriger Antwort) am besten anbietet.

Für solche Sachen kann man auch einfach pro Thread provisorisch schonmal einfach eine Page vorallokieren und die dann immer für sowas nutzen.
Wer soll schon mal Pages provisorisch vorallozieren? Der Client oder der Service? Nur weil Du etwas im voraus machst reduziert sich dadurch nicht der Gesamtaufwand. Wenn ein Client permanent RPC ausführt (z.B. ls) dann gibt es kein provisorisch sondern dieses vorgelagerte Allozieren ist einfach Bestandteil des vollständigen RPC-Vorgangs. Wenn ein Service vor jedem Abholen einer Anfrage erst mal eine Page allozieren muss (eventuell bräuchte der Service für die nächste Anfrage aber auch 1000 Pages aber er kann ja nicht in die Zukunft schauen) dann ist das einfach ein Teil-Vorgang der immer etwas Zeit kostet und bei permanenten ununterbrochenen Anfragen (wie mehrere parallel laufende ls sie für den VFS-Service generieren würden) eben doch wieder den Durchsatz drosselt.

Ich habe einfach das Problem das ich mit den dynamic-Size Nachrichten nicht richtig umzugehen wüsste.
Deswegen ja nicht aktives Abholen sondern zustellen lassen. Der Postbote bringt das Paket immer in einem passenden Karton (wurde vom Absender passend verpackt) wogegen der Abholer ja nie weiß was er denn nun als nächstes bekommt. Und auch für die Rückgabewerte beim RPC ist es besser wenn der Client schon einen leeren Karton mitliefert denn er weiß ja normalerweise wie viele Daten er will (und bei den meisten libc-Funktionen wird auch bei Lese-Funktionen einen Pointer für die gewünschte Datenablage mitgegeben). Klar gibt es bei den Lese-Funktionen ein paar Ausnahmen die nicht im voraus wissen wie groß die Antwort denn werden wird aber das sind eben Ausnahmen und dafür gibt es dann auch in der API bereits passende Auswege.

Kopieren wird in den meisten Fällen dort nicht ausbleiben (erste und letzte Page) und sind die Daten kleiner als eine Page muss ohnehin kopiert werden
Okay, das ist ein Nachteil des Pagings aber das trifft IMHO auch nur die oberste Ebene, wenn eine Applikation den VFS-Service ancallt das 5 Bytes aus einer Datei gelesen werden soll dann wirst Du dort für den VFS ne neue Page nehmen und kopieren aber wenn der VFS diese Page dann an den Dateisystemtreiber weiterreicht dann ist das nicht mehr nötig (ebenso wenn der Dateisystemtreiber diese Page an den SATA-Treiber weiterreicht), einmal Kopieren ist genug.

ja im Kernel Zwischenspeichern muss
Also im Kernel zwischenspeichern solltest Du nicht müssen und wenn doch würde es bei einem nicht unterbrechbaren Kernel reichen jeder CPU einen festen Buffer zuzuordnen (mehr als 2 Pages müssen da ja nicht rein).

Sicher bin ich mir jetzt nicht ob ich die Queuetiefe auch noch beschränken sollte (das ist bei meinem momentanen Code noch möglich). Was meinst du dazu?
Die Queue muss ja nicht die Daten enthalten (die können ja noch beim Client-Thread liegen, ummappen/rauskopieren sollte erst gemacht werden wenn der IPC-Vorgang auch wirklich gestartet werden kann) sondern nur eine Thread-ID o.ä. und daher bin ich der Meinung das man die Queue nicht extra begrenzen muss (vorausgesetzt Du hast ein gutes kmalloc im Kernel).

Was die asynchronen Sachen betrifft, will ich dort die Möglichkeit des aktiven Abholens behalten.
Auch hier sehe ich darin keinen Sinn, muss aber auch sagen das ich mit Spielen und Mediaplayern noch keine Erfahrung hab. Ich vergleiche asynchrone IPC-Messages gerne mit Signalen und die werden ja auch nicht abgeholt.


Synchron heißt, Client schickt Frage an Server und kriegt direkt eine Antwort (die Frage blockiert, bis die Antwort vorliegt). Da sind Popup-Thread definitiv der falsche Weg, das ist asynchron.
Wie kommst du denn auf die blöde Idee das PopUp-Threads für synchrones IPC keinen Sinn ergeben? Ich finde gerade bei synchronem IPC machen die PopUp-Thread sehr viel Sinn weil so der Service in der Lange ist jede Anfrage sofort zu bearbeiten und das nicht davon abhängt ob der Service gerade selber auf eine Anfrage wartet. Und im Client braucht es sowas gar nicht, der blockiert ja bis die Antwort kommt so das der blockierte Thread genau dann aufgeweckt werden kann wenn die Antwort da ist.

Ob nun der Kernel drei Dutzend Popup-Threads erzeugt, die alle mangels CPU-Zeit nicht an die Reihe kommen (und die auch in irgendeine bestimmte Reihenfolge gebracht werden müssen), oder ob der Kernel die Events einfach queuet und dann der Hauptschleife schenkt, ist doch egal.
Ich denke das die meisten Sachen nicht CPU-Limitiert sind sondern selber wieder auf (externe) Ereignisse warten müssen, in sofern wäre es mir persönlich lieber wenn ein paar kB mehr RAM verbraucht werden (für die vielen PopUp-Thread-Stacks) anstatt das z.B. der IP-Stack auf 4 gleichzeitig aktive TCP-Streams begrenzt wird nur weil der PC nur 4 CPUs hat.


Im Server selbst kannst du einen Popup-Threads erzeugen, wenn eine RPC-Anfrage eingeht, aber das halte ich nicht für zielführend. Ich weiß, du stehst auf viele Threads, aber wenn jede RPC-Anfrage einen Thread erzeugt, kannst du den Server ganz schnell DoSen.
Wenn ein Schadprogramm erst mal auf dem System läuft und beliebige Syscalls/RPCs machen kann dann ist eh schon vieles zu spät. Wichtig ist dann nur noch das es sich nicht noch zusätzliche Rechte holen kann damit z.B. der Schaden auf den User begrenzt bleibt in dessen Kontext das Schadprogramm läuft. Auch wäre es gut wenn root-Prozesse gewisse Vorrechte hätten damit root wenigstens die Möglichkeit hat dieses Schadprogramm zu killen. Aber viel mehr kann ein OS in der Situation nicht mehr leisten und auch keines der üblichen OSe tut das.

Um das zu verhindern, erzeugt dein Service einfach einen Thread für jede CPU (oder weniger), die in einer Endlosschleife jeweils auf ein Ereignis warten und es dann abarbeiten. Das heißt, es gibt maximal CPUZAHL gleichzeitige Ereignisse je Server, alle weiteren werden gequeued. Das erspart dem Scheduler viel Arbeit, spart bei vielen RPC-Anfragen eine Menge Speicher und macht die Services einfacher.
Und das drosselt bei eher I/O-Lastigen Services erheblich den Durchsatz weil nur wenige Anfragen parallel bearbeitet werden können. Außerdem belasten die vielen blockierten (weil gerade auf I/O wartenden) PopUp-Threads nicht den Scheduler (und wenn doch dann ist Dein Scheduler Mist). Und ob durch künstliche Begrenzung der Anzahl der PopUp-Threads die Services wirklich einfacher werden wage ich zu bezweifeln, sobald Du mehr als einen PopUp-Thread gleichzeitig zu lässt muss der Code passend ausgelegt sein (mit Locks/Semaphoren/usw. an allen relevanten Stellen). Ich meinem Konzept möchte ich es der Services schon ermöglichen die Anzahl paralleler PopUp-Threads zu begrenzen aber da bin ich mir auch noch nicht sicher welcher konkrete Wert da den angebracht wäre (es ist mir erst mal wichtig das der Kernel überhaupt eine Begrenzung anbietet). Ob für den VFS-Service 256 PopUp-Threads schon zu viele oder doch noch zu wenige sind hängt sicher auch von der CPU/RAM-Ausstattung des betreffenden Computers ab.


Grüße
Erik
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn am 26. January 2011, 11:44
Also nochmal zum SharedMem. Mir geht es darum das du nach deiner Variante einen Syscall machst um einen SharedMem-Bereich zu erstellen und dann eventuell noch einen zweiten um einem anderen Prozess die Rechte zu geben diesen nutzen zu dürfen und dann auf jeden Fall noch einen dritten (oder zweiten) um dem anderen Prozess die ID (oder soetwas in der Art) zukommen zu lassen. Der Empfänger hat dann die ID und muss auch noch mal nen Syscall machen um den SharedMem zu mappen.

Das ist doch alles viel zu viel Aufwand. Da benutze ich doch lieber das was ich schon habe und erledige das alles in einem Syscall.

Zitat von: erik
Wenn das Kopieren nichts kosten würde würde keiner von uns auf die Idee kommen Shared-Memory für die Übermittlung der Parameter/Rückgabewerte bei IPC einzusetzen.
Selbst dann würdest du es wahrscheinlich auf einer 32bit Architektur nicht unbedingt machen wollen, weil das Problem bleibt immernoch die Daten von einem Adressraum in einen anderen zu bekommen und da der Kernel das einzige ist was alle Adressräume gemeinsam haben wirst du die Daten dort zwischen speichern und ohne SharedMem (wo du ja nur ne Liste mit den Pages speichern musst) könnte dir da schnell der virtuelle Speicher ausgehen.

Zitat von: erik
Nur weil Du etwas im voraus machst reduziert sich dadurch nicht der Gesamtaufwand.
Von daher und wie du ja später schreibst (weil man nicht immer weiß wieviele Daten es nun werden), wäre es halt nicht schlecht wenn nicht der Client das Behältnis mitschickt, sondern er bekommt es.

Irgendwo muss so oder so Speicher allokiert werden. Eine andere Möglichkeit wäre noch (ich spezialisiere meinen Syscall noch weiter ;) ) dem Syscall die Anzahl der Pages die benötigt werden zu sagen und im Kernel wird dann ein Bereich im Adressraum genommen und mit Pages hinterlegt und als SharedMem mitgesendet (so spart man sich wieder einen Syscall ;) ).
Was wäre mit der Idee?

Die funktioniert natürlich nur, wenn du Daten haben möchtest, wenn du welche senden willst, muss der Client weiterhin den Speicher selbst allokieren. Aber auch das lässt sich leicht lösen. Man muss ja einen Pointer und eine Länge mitgeben (damit der Kernel weiß wo und wieviele Pages als SharedMem mitgesendet werden sollen) und wenn man als Pointer "0" angibt, heißt das für den Kernel das er den Speicher allokieren soll und wenn der Pointer != "0" ist, dann ist der Speicher schon vorhanden.

Ich denke mal das wäre dir wider zu umständlich/Fehler anfällig oder?

Zitat von: erik
Deswegen ja nicht aktives Abholen sondern zustellen lassen. Der Postbote bringt das Paket immer in einem passenden Karton (wurde vom Absender passend verpackt) wogegen der Abholer ja nie weiß was er denn nun als nächstes bekommt. Und auch für die Rückgabewerte beim RPC ist es besser wenn der Client schon einen leeren Karton mitliefert denn er weiß ja normalerweise wie viele Daten er will (und bei den meisten libc-Funktionen wird auch bei Lese-Funktionen einen Pointer für die gewünschte Datenablage mitgegeben).
Seien wir mal ehrlich, das einzige was aktives Abholen von deinen Popup-Threads unterscheidet ist der Zeitpunkt wann es geschieht und wo. Denn den Rest kann ich auch analog machen, sprich auch beim aktiven Abholen kann ich dem Empfänger einfach nen Pointer übergeben wo die Nachricht dann ist (so muss der Empfänger nicht mehr wissen wie groß die Nachricht ist), aber ich habe den Vorteil das ich weiß wann die Nachricht kommt, nämlich dann wenn ich sie abholen möchte und nicht irgendwann. Das ist im Endeffekt wie ein Signal, da muss ich soviele Dinge beachten damit ich Signale nutzen kann.
Am Bsp. deiner Popup-Threads müsste ich auf jeden Fall viel Code haben der Threadsafe ist, was z.B. beim aktiven Abholen nicht der Fall wäre.

Zitat von: erik
Okay, das ist ein Nachteil des Pagings aber das trifft IMHO auch nur die oberste Ebene, wenn eine Applikation den VFS-Service ancallt das 5 Bytes aus einer Datei gelesen werden soll dann wirst Du dort für den VFS ne neue Page nehmen und kopieren aber wenn der VFS diese Page dann an den Dateisystemtreiber weiterreicht dann ist das nicht mehr nötig (ebenso wenn der Dateisystemtreiber diese Page an den SATA-Treiber weiterreicht), einmal Kopieren ist genug.
Das Problem ist, dass ich alle Nachrichten < einer Page im Kernel zwischen speichern würde und wenn ich mir nicht gerade nen sehr effizienten Allocator schreibe oder portiere, müsste ich dafür dann auch jedes Mal eine Page allokieren und das im Kernel, wo der virtuelle Speicher ja begrenzt ist. Ich sehe es halt als effizienter an, wenn man nur Pages und fixed-Size Objekte durch die Gegend schiebt als wenn erstnoch ein Allocator einen Bereich suchen muss der dann passt.

Edit::

Was ich bei meinem SharedMem Bsp. noch vergessen habe, du brauchst auch nochmal mind. einen Syscall um herauszufinden welche Prozess hinter einem Port steckt. Denn die Prozess ID brauchst du um dem Prozess zu erlauben einen bestimmten SharedMem Bereich nutzen zu dürfen und mit anderen Prozessen wirst du nur über Ports kommunizieren.
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger am 26. January 2011, 16:32
Hallo,


Also nochmal zum SharedMem. Mir geht es darum das du nach deiner Variante einen Syscall machst um einen SharedMem-Bereich zu erstellen und dann ....
Das ist doch alles viel zu viel Aufwand. Da benutze ich doch lieber das was ich schon habe und erledige das alles in einem Syscall.
Ich denke das ich mit einem Syscall pro Teilnehmer auskomme, zuzüglich der Übermittlung der Zugangsdaten, aber das ist gar nicht der Punkt. Richtiges Shared-Memory wird für längerfristige Sachen benutzt und da spielen 2 oder 3 Syscalls zum Erstellen absolut keine Rolle. Das Problem was ich sehe ist das Du den Shared-Memory für eigenes IPC Zweckentfremden möchtest (wahrscheinlich weil Du Dir davon eine Beschleunigung erhoffst). Dein derzeitiges IPC-Konzept bereitet Dir offenbar Kopfzerbrechen wegen dem Übertragen der Parameter/Rückgabewerte und da versuchst Du das mit erweiterten Shared-Memory-Funktionalitäten zu kompensieren. Möglicherweise gelangst du damit auch ganz gut zum Ziel aber ein vernünftiges Design kommt da IMHO nicht bei raus. Auch diese fürchterlich überladenen Alles-in-Einem-Syscalls empfinde ich als extrem ungeschickt. Schon allein die vielen Verzweigungen kosten Dich bei jedem Aufruf dieser Syscalls etwas an Performance.

weil das Problem bleibt immernoch die Daten von einem Adressraum in einen anderen zu bekommen und da der Kernel das einzige ist was alle Adressräume gemeinsam haben wirst du die Daten dort zwischen speichern
Nein, dafür mappt man die Quelle temporär in den Ziel-Adressraum (oder anders herum) und kopiert nur einmal. Was bleibt ist das IPC/RPC konzeptionell nichts mit Shared-Memory zu tun haben sondern das die gegebene Computer-Architektur Mapping (ob nun Pages oder Segmente ist ja egal) eben als geeignetes Werkzeug anbietet um damit IPC/RPC hochperformant zu unterstützen.

Von daher und wie du ja später schreibst (weil man nicht immer weiß wieviele Daten es nun werden), wäre es halt nicht schlecht wenn nicht der Client das Behältnis mitschickt, sondern er bekommt es.
Hä, wie kommst Du denn jetzt plötzlich da drauf? Der Client weiß doch wie viele Daten er lesen/empfangen oder schreiben/senden möchte und der Service weiß das erst nachdem er die Anfrage empfangen hat insofern ist es IMHO absolut logisch das der Client die Behälter bei der Anfrage bereits alle mitschickt (nebst dessen das sich das so auch mit der Semantik der libc-Funktionen deckt).

Irgendwo muss so oder so Speicher allokiert werden.
Nein, der Client hat den Speicher bereits, siehe fread da muss der Applications-Code ja auch schon den Speicher haben wo dann die Daten hin sollen. Gerade deswegen empfinde ich mein IPC-Konzept ja als so schnell weil da eigentlich nie extra Speicher alloziert werden muss sondern es wird immer der Speicher benutzt der schon da ist (was dann noch den zusätzlichen Performance-Vorteil des Zero-Copy mit sich bringt).

das einzige was aktives Abholen von deinen Popup-Threads unterscheidet ist der Zeitpunkt wann es geschieht und wo.
Richtig! Während bei mir der Kernel dann einen PopUp-Thread erzeugt (und diesen sofort auf der CPU die gerade noch der Client-Thread belegt hat los laufen lässt) wenn die Anfrage gestellt wird muss bei Dir der Kernel eventuell warten (bzw. unterbrechen und was anderes tun) bis der Service bereit ist die Anfrage entgegen zu nehmen. Ich habe also in vielen Fällen eine deutlich kürzere Latenz.

aber ich habe den Vorteil das ich weiß wann die Nachricht kommt
Wo ist da ein Vorteil? Was hat der VFS-Service davon wenn er weiß wann die Anfragen der vielen Clients rein kommen? Wichtig ist doch das die Anfragen möglichst zügig bearbeitet werden, zumindest meiner persönlichen Meinung nach.

Das ist im Endeffekt wie ein Signal, da muss ich soviele Dinge beachten damit ich Signale nutzen kann.
Hä, was ist denn an Signalen bitte so kompliziert? Aber die Analogie zwischen einem Signal und dem Eintreffen einer RPC-Anfrage stimmt ganz gut.

Am Bsp. deiner Popup-Threads müsste ich auf jeden Fall viel Code haben der Threadsafe ist, was z.B. beim aktiven Abholen nicht der Fall wäre.
Wenn Du Deinem Service erlauben möchtest mehr als eine Anfrage parallel zu bearbeiten (also z.B. mit mehreren Threads aktiv abholst) benötigst Du das doch eh alles. Wo ist da das Problem? Bei meinen PopUp-Threads kann ich das auch auf 1 begrenzen wenn ein Service eh keinen Vorteil daraus zieht wenn er mehrere Anfragen parallel bearbeiten kann (z.B. Dein Diskettentreiber).

Das Problem ist, dass ich alle Nachrichten < einer Page im Kernel zwischen speichern würde
Du musst gar nichts im Kernel zwischen Speichern sondern kopierst immer direkt von der Quelle zum Ziel.

du brauchst auch nochmal mind. einen Syscall um herauszufinden welche Prozess hinter einem Port steckt.
So einen Syscall wird es bei mir gar nicht geben. Dem Client geht die Prozess-ID des Service nichts an.

Denn die Prozess ID brauchst du um dem Prozess zu erlauben einen bestimmten SharedMem Bereich nutzen zu dürfen
Nein, das geht über Zugriffs-Keys die beim Erstellen des Shared-Memorys angelegt werden und die ich nur den Prozessen gebe die ich dazu einladen möchte beim Sharen mit zu machen. Sieht Dir mal die PSOX-Funktionen für Shared-Memory an, ungefähr das ist es auch was die Programme typischerweise erwarten (unter Windows funktioniert das wimre sehr ähnlich).


Grüße
Erik
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn am 26. January 2011, 16:59
Zitat von: erik
Auch diese fürchterlich überladenen Alles-in-Einem-Syscalls empfinde ich als extrem ungeschickt. Schon allein die vielen Verzweigungen kosten Dich bei jedem Aufruf dieser Syscalls etwas an Performance.
Da bin ich halt anderer Meinung bzw. will ich ja die Möglichkeit haben mehr als nur die 32byte Daten als Nachricht zu versenden (bei mir dann halt immer vielfaches der Pagegröße) und das ist im Endeffekt ja SharedMem.
Warum sollte ich dann nicht schon das vorhandene nutzen? Die Performance die durch die Überprüfung der Flags verloren geht dürfte wesentlich geringer sein, als die die verloren gehen würde, wenn ich dafür mehrere Syscalls aufrufen müsste.

Zitat von: erik
Nein, der Client hat den Speicher bereits, siehe fread da muss der Applications-Code ja auch schon den Speicher haben wo dann die Daten hin sollen.
Und wo kommt dieser Speicher her ;) Der muss doch erst allokiert werden und das erfordert irgendwann auch mal nen Syscall. Wo du recht hast ist, dass ich im Clienten wahrscheinlich nochmal allokieren müsste (damit ich 4KB alignment habe) und auch kopieren (aus der Page in den User-Buffer).
Aber soweit wie ich mir die libc angeguckt habe, ist das ganze fread/fwrite eh gepuffert und wenn ich da dann nen 4KB Buffer nehme sehe ich da kein Problem.

Zitat von: erik
Ich habe also in vielen Fällen eine deutlich kürzere Latenz.
Jein ;) Ich denke mal was hier untergegangen ist, das ich beim aktiven Abholen dann davon ausgehe dass das Senden asynchron war (ich rede also nur von irgendwelchen Events und sowas) und dass das nichts mit dem Service zutun hat, sondern es geht mir dabei um den Clienten, der die Nachrichten abholt. Die Latenz ist dabei egal, weil ob die Nachricht nun im UserSpace in eine Queue kommt oder im KernelSpace hat mit der Latenz erstmal nichts zu tun.

Ich kann dann aber als Programmierer entscheiden wann ich die Nachricht haben möchte und bearbeite sie dann und hole auch die nächste Nachricht erst wenn ich wieder soweit bin und kann mir, wenn es sein muss den ganzen Multithread-Kram sparen (sollte das Portieren erleichtern). Sobald ich Popup-Threads für den Empfang von irgendwelchen Events nutze, muss das gesamte Programm Threadsafe sein und wenn ich eh ein Programm habe wo die GUI vom restlichen Programm getrennt ist (also in einem anderen Thread) werde ich bestimmt auch einen Popup-Thread nutzen, aber alle anderen Programme sollen halt auch die Möglichkeit haben es anders zu lösen.

Zitat von: erik
Hä, was ist denn an Signalen bitte so kompliziert?
Du hattest doch mal selber gebracht das es eher ungünstig ist, wenn man ein Signal bekommt und der Thread war gerade mitten in einem malloc() und das Signal will jetzt ebenfalls malloc() benutzen. Im Endeffekt läuft es darauf hinaus dass das gesamte Programm Threadsafe sein muss und seien wir mal ehrlich Linux bzw die ganzen "alten" Programme hat damit noch so seine Probleme.

Zitat von: erik
Du musst gar nichts im Kernel zwischen Speichern sondern kopierst immer direkt von der Quelle zum Ziel.
Und wie bekomme ich die Daten aus dem einem Adressraum in den anderen, wenn ich nicht einfach nur eine Page ummappen kann (bei Daten < einer Page)? Ich muss doch die Daten aus dem einem Adressraum in eine temporäre Page kopieren um diese dann beim Empfänger reinzumappen und um dann beim Beenden des RPC wieder die Daten aus der temporären Page in den Clienten zu kopieren (was alles im Endeffekt das selbe ist, was ich mit meinem IPC System machen will, nur das mehr im UserSpace stattfindet).

Zitat von: erik
Nein, das geht über Zugriffs-Keys die beim Erstellen des Shared-Memorys angelegt werden und die ich nur den Prozessen gebe die ich dazu einladen möchte beim Sharen mit zu machen. Sieht Dir mal die PSOX-Funktionen für Shared-Memory an, ungefähr das ist es auch was die Programme typischerweise erwarten (unter Windows funktioniert das wimre sehr ähnlich).
Theoretisch wäre es also möglich per Zufall genau den richtigen Key zu erraten und man kann einfach SharedMem benutzen für den man gar nicht gedacht war? Das finde ich aber sehr zweifelhaft. Ich dachte eigentlich immer das läuft alles über Dateien und die Diskriptoren und das die dann an einen anderen Prozess weitergegeben werden (wofür man wieder die ID des Prozesses bräuchte).
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger am 27. January 2011, 12:45
Hallo,


Da bin ich halt anderer Meinung bzw. will ich ja die Möglichkeit haben mehr als nur die 32byte Daten als Nachricht zu versenden (bei mir dann halt immer vielfaches der Pagegröße) und das ist im Endeffekt ja SharedMem.
Nein!  IPC != Shared-Memory
Beides basiert zwar auf dem Konzept des Ummappen von Speicher (weil beides mit der gegebenen CPU-Architektur eben so am besten zu lösen ist) aber es sind 2 verschiedene Mechanismen. Den einen (Shared-Memory) benötigst Du um auf einem Datenbestand von mehreren Prozessen aus gleichzeitig zu zugreifen und den anderen (IPC/RPC) um von einem Prozess aus eine Funktion in einem anderen Prozess aufzurufen. Das sich für die Realisierung beider Mechanismen Mapping (egal ob Pages oder Segmente) anbietet liegt eben in der Natur der CPU. Du darfst gerne beide Mechanismen in einen Syscall zusammen murkseln aber ich persönlich rate davon dringend ab.

Warum sollte ich dann nicht schon das vorhandene nutzen? Die Performance die durch die Überprüfung der Flags verloren geht dürfte wesentlich geringer sein, als die die verloren gehen würde, wenn ich dafür mehrere Syscalls aufrufen müsste.
Für was benötigt man mehrere Syscalls? Entweder Du möchtest RPC machen (dann braucht der Client einen Syscall um seine Anfrage los zu schicken und um die Antwort zu erhalten und der Service braucht auch nur einen Syscall um die Antwort zurück zu schicken) oder Du möchtest richtiges Shared-Memory machen und dann wirst Du pro Teilnehmer auch einen Syscall benötigen zuzüglich dem Übertragen der Zugangsdaten (oder wie auch immer Du das realisieren möchtest). Aber wenn Du Shared-Memory von IPC abhängig machst dann bedeutet dass das nie zwei Prozesse Speicher teilen können ohne das zumindest einer davon einen IPC-Port einrichten muss und das finde ich doof.

Zitat von: erik
Nein, der Client hat den Speicher bereits, siehe fread da muss der Applications-Code ja auch schon den Speicher haben wo dann die Daten hin sollen.
Und wo kommt dieser Speicher her ;) Der muss doch erst allokiert werden und das erfordert irgendwann auch mal nen Syscall.
Das könnte aber auch ein statisches Array sein oder auf dem Stack liegen, nebst dessen das nicht jeder Aufruf von malloc auch zwangsläufig einen Syscall benötigt (falls Du ne anständige libc hast)

Ich denke mal was hier untergegangen ist, das ich beim aktiven Abholen dann davon ausgehe dass das Senden asynchron war (ich rede also nur von irgendwelchen Events und sowas) und dass das nichts mit dem Service zutun hat, sondern es geht mir dabei um den Clienten, der die Nachrichten abholt. Die Latenz ist dabei egal, weil ob die Nachricht nun im UserSpace in eine Queue kommt oder im KernelSpace hat mit der Latenz erstmal nichts zu tun.
Also langsam weiß ich echt nicht mehr wovon Du eigentlich so schreibst! Wenn wir über RPC (also synchrones IPC mit Anfrage und zugehöriger Antwort) schreiben dann gibt es da in meinem Konzept nur in so fern aktives Abholen weil der Client ja so lange blockiert bis seine Antwort vom Service eintrifft, der Client benutzt quasi einen send+recv-Syscall der eben so lange blockiert bis die zugehörige Antwort kommt (alle anderen Messages die sonst noch durchs System geistern können diesen wartenden Client nicht erreichen und er ist auch nicht adressierbar sondern wartet nur genau auf seine Antwort). Auch sonst kann dieser wartende Client-Thread nicht von außen beeinflusst werden (man kann ihn auch nicht einfach aufwecken o.ä.).

es geht mir dabei um den Clienten, der die Nachrichten abholt
Also Clienten (im Zusammenhang von RPC, bei asynchronem IPC gibt es ja nur Sender und Empfänger) holen ihre Antwort nie selber aktiv ab, das erledigt der RPC-send+recv-Syscall automagisch mit.

Ich kann dann aber als Programmierer entscheiden wann ich die Nachricht haben möchte und bearbeite sie dann und hole auch die nächste Nachricht erst wenn ich wieder soweit bin und kann mir, wenn es sein muss den ganzen Multithread-Kram sparen (sollte das Portieren erleichtern).
Also ich als Programmierer möchte das alle meine Services alle Anfragen so schnell als möglich bearbeiten. Außerdem wüsste ich gar nicht wie ich es umsetzen sollte das meine Services zur Laufzeit entscheiden wann sie eine Anfrage erhalten möchten und wann nicht. In den Services werde ich eh alles Thread-Save machen müssen schließlich fällt mir kein Service ein bei dem ich alle Anfragen nur rein seriell verarbeiten möchte (außer vielleicht der für den Diskettencontroller aber sowas hab ich nicht). Also sehe ich keinen Vorteil darin mir bei Services das Multithreading ersparen zu können, ich will es doch eh haben damit ich auf vernünftige Performance komme. Die Clients könnten trotzdem Singlethreaded sein, der RPC-send+recv-Syscall macht da keine Einschränkungen.
Meine libc wird es auch nur ein einer Thread-Save-Version geben, bei Locks die sicher frei sind dürfte der Performanceverlust nur ziemlich minimal sein.

Du hattest doch mal selber gebracht das es eher ungünstig ist, wenn man ein Signal bekommt und der Thread war gerade mitten in einem malloc() und das Signal will jetzt ebenfalls malloc() benutzen.
Das hängt davon ab wie Signale implementiert sind. Wenn ein Signal die Ausführung eines Threads wirklich unterbricht, so wie z.B. tyndur das macht, dann muss malloc nicht nur Thread-Save sein sondern auch temporär das Zustellen von Signalen unterbinden (kostet jeweils 2 Syscalls, ausschalten+einschalten). Wenn Signale aber einen neuen Thread erzeugen (ich möchte PopUp-Threads auch für asynchrones IPC benutzen) dann reicht normales Thread-Save völlig aus.

seien wir mal ehrlich Linux bzw die ganzen "alten" Programme hat damit noch so seine Probleme.
Dem werde ich sicher nicht widersprechen aber solche "alten" Programme muss man ja nicht unbedingt portieren. Und mit Linux sollen doch unser beider OSe nicht viel gemein haben.

Zitat von: erik
Du musst gar nichts im Kernel zwischen Speichern sondern kopierst immer direkt von der Quelle zum Ziel.
Und wie bekomme ich die Daten aus dem einem Adressraum in den anderen
Der Kernel macht für den kurzen Zeitraum des Kopierens beide Adressräume gleichzeitig zugänglich, zumindest jeweils den Teil der benötigt wird (also wo die Daten liegen bzw. hin sollen). Sobald das Kopieren fertig ist werden die beiden Adressräume wieder sauber getrennt und da das Kopieren ja im Kernel statt findet gibt es da auch keine Sicherheitslecks.

Theoretisch wäre es also möglich per Zufall genau den richtigen Key zu erraten und man kann einfach SharedMem benutzen für den man gar nicht gedacht war? Das finde ich aber sehr zweifelhaft.
Man wird auf jeden Fall noch eine gültige Shared-Memory-ID brauchen und ansonsten kannst Du ja den Key 128 Bit groß machen so das raten wirklich keinen Sinn mehr ergibt.

Ich dachte eigentlich immer das läuft alles über Dateien und die Diskriptoren und das die dann an einen anderen Prozess weitergegeben werden (wofür man wieder die ID des Prozesses bräuchte).
Das kann man auch so machen, ich hab gestern einfach nur mal kurz nach Beispiel-Code gesucht und eben die Variante mit dem Key gefunden und das war in irgendwelchen Linux-Man-Pages drin.


Grüße
Erik
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn am 27. January 2011, 13:21
Also wenn ich jetzt von asynchronen IPC rede und von einem Clienten dann geht es nicht um RPC! Ich bin da wieder bei meinem lieblings Bsp. GUI-Anwendung. Diese GUI-Anwendung bekommt eine Nachricht, in der Nachricht steht dass das Fenster vergrößert wurde und neugezeichnet werden muss. Der Service sendet die Nachricht asynchron, weil warum sollte der Service darauf warten das die Nachricht auch bearbeitet wurde?
Der Client wartet entweder auf eine Nachricht oder er macht gerade etwas, die Nachricht kommt in die Queue des Ports und wenn er Client fertig ist macht er seinen Syscall um die Nachricht abzuholen.
Der Client kann also jedes Mal die Nachricht ganz einfach verarbeiten, bei meinem Bsp., wird er also seinen Fensterinhalt neu zeichnen und erst wenn er fertig ist, guckt er nach ob eine neue Nachricht vorhanden ist.

Würde ich das jetzt über Popup-Threads machen, würde ich einfach die Queue, für Nachrichten, in den UserSpace packen und wahrscheinlich mit einer Semaphore arbeiten. So dass der Popup-Thread die Semaphore inkrementiert wenn er die Nachricht in die Queue gepackt hat und damit den eventuell wartenden Worker-Thread startet (was wieder einen Syscall kostet) und der Worker-Thread dekrementiert die Semaphore und wenn noch mind. eine Nachricht vorhanden ist bearbeitet er die nächste.

So könnte ich das Problem welches mit dem Multi-Threading kommen würde auch noch umgehen, aber ich würde die Popup-Threads nutzen.

Was ich momentan noch gar nicht sehe ist, dass mehrere Nachrichten gleichzeitig=parallel bearbeitet werden. Kann sein das ich das irgendwann auch hinbekomme (gedanklich), aber im Moment einfach noch nicht.

So ich hoffe jetzt du weißt was ich mit aktiven Abholen und asynchronen IPC meine!

Dann nochmal zum SharedMem  :-D

Ich sehe da wie gesagt keinen Unterschied, bei beiden Sachen (Nachricht und "richtiger" SharedMem) wird der Speicher in beiden Prozessen gemappt sein und theoretisch können in dem Moment beide darauf zugreifen (theoretisch deswegen, weil ja ein anderer Thread des Clienten auf die dumme Idee kommen könnte, in dem Speicher der als Nachricht verschickt wurde, herumzufrickeln). Der einzige Unterschied wäre, dass der SharedMem beim RPC zeitlich für das Antworten begrenzt ist und ansonsten solange bleibt bis ihn der Empfänger unmappt.

Was den IPC Port betrifft, den man dann zum Übertragen von SharedMem bräuchte, wie willst du denn dem anderen Prozess den SharedMem zukommen lassen und wie willst du rausfinden welchem Prozess du den Speicher zukommen lassen willst?
Was mir im Moment fehlt, wäre mal ein konkretes Bsp. wo SharedMem verwendet wird.

Zitat von: erik
Der Kernel macht für den kurzen Zeitraum des Kopierens beide Adressräume gleichzeitig zugänglich
Das geht bei mir halt nicht, ich kann von einem Prozess aus nicht auf den Adressraum eines anderen Prozess zugreifen (weil die Daten welche Bereiche frei und welche nicht frei sind, werden im Kernel immer an der selben Stelle gespeichert und sind Prozessbezogen).

Zitat von: erik
Man wird auf jeden Fall noch eine gültige Shared-Memory-ID brauchen und ansonsten kannst Du ja den Key 128 Bit groß machen so das raten wirklich keinen Sinn mehr ergibt.
Wieso so umständlich?! Zumal du den immer noch durch einen dummen Zufall bekommen könntest. Bei mir ist das Unmöglich! Wenn ein Prozess einen Speicher-Bereich an einen anderen sendet, gibt es für alle anderen Prozesse keine Möglichkeit da ran zukommen, nicht mal per Zufall (und es braucht wie gesagt auch noch weniger Syscalls).

Was die Anzahl der Syscalls betrifft, das möchte inzwischen nicht mehr so schlimm sein, aber da ich immernoch für Pentium Systeme programmiere (und da nutzt man nen Interrupt und das kostet richtig) lege ich Wert darauf das man nur so wenig wie nötig machen muss.
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger am 27. January 2011, 15:12
Hallo,


Also wenn ich jetzt von asynchronen IPC rede
Das es Dir um asynchrones IPC ging war im Deinem letzten Post nicht ersichtlich!

von einem Clienten dann geht es nicht um RPC!
Bei asynchronem IPC gibt es keinen Client! Da gibt es nur Sender und Empfänger. Mit ganz viel Fantasie könnte man den Empfänger noch als Service betrachten weil er ja einen öffentlich erreichbaren Port hat (es gibt bestimmt auch richtige Services die man nur asynchron antriggern braucht) aber der Begriff Client ist da definitiv fehl am Platz.

So ich hoffe jetzt du weißt was ich mit aktiven Abholen und asynchronen IPC meine!
Jetzt ergeben für mich ein paar Deiner vergangenen Beiträge etwas mehr Sinn aber warum Du unbedingt aktiv abholen möchtest leuchtet mir trotzdem nicht ein. Ist multithreading-taugliche SW denn wirklich so furchtbar das man das unbedingt vermeiden muss?

Dann nochmal zum SharedMem  :-D
Ich sehe da wie gesagt keinen Unterschied, bei beiden Sachen (Nachricht und "richtiger" SharedMem) wird der Speicher in beiden Prozessen gemappt sein
Naja, richtiges Shared-Memory macht man für einen erstmal unbestimmt langen Zeitraum weil man ja Daten sharen möchte und das Mapping beim RPC ist nur so lange wie eben der RPC dauert und auch nur Mittel zu Zweck (weil man könnte ja auch immer kopieren und da bräuchte man gar kein Mapping für RPC).
Aber lass Dich nicht von mir aufhalten, mach das so wie Du es für richtig hältst. Meine Meinung kennst Du jetzt und darum ging es Dir doch, oder?
Wenn Du Shared-Memory zwangsweise per IPC machst, wie möchtest Du dann mehr als 2 Prozesse teil nehmen lassen?

Was den IPC Port betrifft, den man dann zum Übertragen von SharedMem bräuchte, wie willst du denn dem anderen Prozess den SharedMem zukommen lassen und wie willst du rausfinden welchem Prozess du den Speicher zukommen lassen willst?
Ich könnte auch einfach die Shared-Memory-ID zusammen mit dem ReadOnly-Key in globalen Umgebungsvariablen o.ä. veröffentlichen um so zu ermöglichen das beliebige Prozesse auf meine allgemein nützlichen Daten zugreifen können (keine Ahnung ob es für so ein Szenario eine ernsthafte Anwendung gibt).

Was mir im Moment fehlt, wäre mal ein konkretes Bsp. wo SharedMem verwendet wird.
Ich hab zwar ein paar Beispiele gefunden wie man Shared-Memory benutzt aber leider keine Beispiele wofür man Shared-Memory ernsthaft braucht.

Zitat von: erik
Der Kernel macht für den kurzen Zeitraum des Kopierens beide Adressräume gleichzeitig zugänglich
Das geht bei mir halt nicht
Das ist doof! Sogar der L4 kann das.

gibt es für alle anderen Prozesse keine Möglichkeit da ran zukommen, nicht mal per Zufall (und es braucht wie gesagt auch noch weniger Syscalls).
Wenn man wirklich richtigen Shared-Memory machen möchte dann ist IMHO die Anzahl der Syscalls zum Einrichten nicht so das Kriterium, ich denke wenn man sowas macht dann nicht bloß kurz um mal schnell ne Hand voll Bytes zu kopieren sondern weil man wirklich mit mehreren Prozessen an einem Datensatz ernsthaft (länger) arbeiten möchte.


Grüße
Erik
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn am 27. January 2011, 17:14
Ist multithreading-taugliche SW denn wirklich so furchtbar das man das unbedingt vermeiden muss?
Manchmal ist es halt einfacher ohne Multithreading und Multithreading wird bestimmt auch nicht überall mehr Performance bringen oder anders gesagt es wird manchmal mehr Probleme schaffen als es lösen wird.

Wenn Du Shared-Memory zwangsweise per IPC machst, wie möchtest Du dann mehr als 2 Prozesse teil nehmen lassen?
Ganz einfach, ich sende den Speicher an alle Prozesse die teilnehmen dürfen.

Was zur Sicherheit noch. Geht es wenn Prozess B von Prozess A Speicher bekommen hat, den dann weiter an Prozess C zu geben ohne dass das Prozess A will?

Zitat von: erik
Der Kernel macht für den kurzen Zeitraum des Kopierens beide Adressräume gleichzeitig zugänglich
Das geht bei mir halt nicht
Das ist doof! Sogar der L4 kann das.
Bei mir sind die Prozesse halt so richtig von einander getrennt (unter anderem um virtuellen Speicher zu sparen. Ich würde wahrscheinlich sogar sehr gut mit nur 512MB KernelSpace auskommen.

Wenn man wirklich richtigen Shared-Memory machen möchte dann ist IMHO die Anzahl der Syscalls zum Einrichten nicht so das Kriterium, ich denke wenn man sowas macht dann nicht bloß kurz um mal schnell ne Hand voll Bytes zu kopieren sondern weil man wirklich mit mehreren Prozessen an einem Datensatz ernsthaft (länger) arbeiten möchte.
Naja, so ähnlich könnte man mit einem langsamen IPC System argumentieren (z.B. bei meinem ;) ). Wenn es so viele Daten sind das die Übertragung lange dauert. Dann sollte das nicht so ins Gewicht fallen, weil die Bearbeitung der Daten viel länger dauern wird. Bestes Bsp. ist die Festplatte, da das Laden so lange dauert, fällt ein langsamerer "Datenverkehr" zum Clienten auch nicht mehr auf.
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger am 27. January 2011, 19:27
Hallo,


.... anders gesagt es wird manchmal mehr Probleme schaffen als es lösen wird.
Solche Situationen gibt es ganz bestimmt aber das trifft wohl kaum auf Services zu die einen hohen Durchsatz und geringe Latenz aufweisen sollen. Bei einfachen Client-Programmen wird man sicher gerne auf Multithreading verzichten aber bei einem High-Performance-Service wird man eher alle Tricks aus dem Ärmel ziehen die nur irgendwie gehen. Im Rahmen der Personality Deines OS wirst Du sicher kaum irgendwelche Dinge portieren sondern die lieber selber und für Dein OS optimal passend implementieren, bei normalen User-Space-Programmen wirst Du sicher eher aufs Portieren zurückgreifen anstatt für alles mögliche das Rad neu zu erfinden. Deswegen bin ich ja der Meinung das man zumindest auf libc-Ebene eine gute Kompatibilität erreichen sollte.

Wenn Du Shared-Memory zwangsweise per IPC machst, wie möchtest Du dann mehr als 2 Prozesse teil nehmen lassen?
Ganz einfach, ich sende den Speicher an alle Prozesse die teilnehmen dürfen.
Und wenn die den Speicher gar nicht wollen? So könnte ja schnell ein DoS-Angriff auf den virtuellen Adressraum von anderen Prozessen möglich sein. Ich bin schon der Meinung das alle teilnehmenden Prozesse sich den Shared-Memory immer aktiv holen sollten.

Was zur Sicherheit noch. Geht es wenn Prozess B von Prozess A Speicher bekommen hat, den dann weiter an Prozess C zu geben ohne dass das Prozess A will?
Das hängt sehr von der zu Grunde liegenden Shared-Memory-Implementierung ab. Was ich da beschrieben hab ist ja nur ein Beispiel und Shared-Memory kann man sicher auf sehr viele verschiedene Arten implementieren. Ich persönlich hab noch nie etwas mit richtigem Shared-Memory programmiert und werde dafür wohl auch kaum gleich in meinen ersten Kernel alles nötige einbauen. Wenn ich irgendwann mal ein Programm portieren möchte das Shared-Memory benötigt kann ich immer noch schauen wie dieses Programm das erwartet und was es sonst noch so für Möglichkeiten gibt und mir dann ein passendes Syscall-API ausdenken das meinen persönlichen Wünschen entspricht und natürlich mit den Möglichkeiten meines Kernels und meiner Plattform harmoniert. Ich könnte mir z.B. vorstellen das ich dafür grundsätzlich ein eigenes Segment erstelle das sich dann auch vergrößern/verkleinern lässt und das für alle Teilnehmer synchron. Vielleicht entschließe ich mich auch dazu da eine etwas komplexere Rechteverwaltung ein zu bauen damit der Initiator des Shared-Memory genau bestimmen kann wer was darf. Aber egal wie das auch werden wird es wird mit Sicherheit völlig unabhängig vom IPC-System in den Kernel integriert (zumindest auf Syscall-Ebene, das ich intern im Kernel für das Mappen der Segmente sicher auf die gleichen Funktionen zurückgreife ist wohl logisch).

Bei mir sind die Prozesse halt so richtig von einander getrennt
Tja, das ist halt doof. So musst Du wohl immer gleich doppelt Kopieren wenn Du doch mal Kopieren musst.


Grüße
Erik
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn am 27. January 2011, 19:47
Zitat von: erik
Bei einfachen Client-Programmen wird man sicher gerne auf Multithreading verzichten aber bei einem High-Performance-Service wird man eher alle Tricks aus dem Ärmel ziehen die nur irgendwie gehen.
Mein reden ;) Das ich den Service mit Hilfe von Multithreading schneller machen will sollte ja inzwischen klar sein, aber ich möchte halt die User-Programme nicht unnötig kompliziert machen (und des wegen das ganze aktive Abholen).

Zitat von: erik
Und wenn die den Speicher gar nicht wollen? So könnte ja schnell ein DoS-Angriff auf den virtuellen Adressraum von anderen Prozessen möglich sein.
Das ist eine gute Frage, aber genauso kann man einen DoS-Angriff per RPC auf einen Service durchführen!

Zitat von: erik
Tja, das ist halt doof. So musst Du wohl immer gleich doppelt Kopieren wenn Du doch mal Kopieren musst.
Naja, das perfekte Design wird es wohl nicht geben, es gibt immer etwas was man anders machen könnte, aber das wird dann auch wieder Nachteile haben.
Und bisher brauche ich es halt nicht wirklich.
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger am 27. January 2011, 20:23
Hallo,


aber ich möchte halt die User-Programme nicht unnötig kompliziert machen (und des wegen das ganze aktive Abholen).
Aber für RPC benötigt der Client doch gar keine Threads oder andere komplizierte Sachen, genauso wie der Sender bei asynchronen Messages, und abgeholt werden (egal ob aktiv oder per PopUp-Thread) muss da auch nichts. Erst wenn das Programm selber einen Port aufmacht um einen Service anzubieten oder um asynchrone Messages zu empfangen wird es komplizierter, aber das benötigen einfache Programme ja gar nicht.


Grüße
Erik
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn am 27. January 2011, 20:31
Es gibt durchaus einfache GUI-Programme und die sind nicht Multithreaded und es würde auch keinen Sinn machen sie Multithreaded zu machen. Trotzdem werden diese Programme einen Port haben weil sie Events empfangen wollen/müssen.

Deswegen meinte ich ja auch am Anfang das ich Port nicht mit Service gleichsetze auch ein normales Programm kann einen Port haben ohne das es einen Service anbietet.

Edit::

So langsam wird mir klar warum noch niemand so ein IPC System wie du es vorhast implementiert hat. Ich meine das mit den DoS Attacken ist nicht ohne und ein wirkliches Problem (zumindest auf Architekturen die keine Segmente habe). Umgehen kann man das nur in dem der Client eben nicht das Gefäß mitbringt (was ja das eigentliche Problem ist) oder man muss es so machen das der Popup-Thread einen Wert (nämlich die Größe des Gefäßes) mitbekommt und der Popzp-Thread dann entscheiden kann ob er die Nachricht annehmen will oder nicht.

Ein anderes Problem ist auch was passiert wenn das Gefäß zu groß ist und nicht mehr in den virtuellen Adressraum passt?
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger am 27. January 2011, 21:15
Hallo,


Es gibt durchaus einfache GUI-Programme ....
Wenn diese Programme wirklich so einfach sind dann wird es wohl kaum auf Performance ankommen. Bastle doch eine Library die den Port und den PopUp-Thread intern managed und die Messages in eine User-Mode-Queue stellt (sowas hattest Du doch vor ein paar Posts schon mal beschrieben) und schon ist alles komplizierte wieder gut versteckt. Ob der Mode-Wechsel nun vor dem reinpacken in die Queue (mit PopUp-Thread) oder nach dem rausholen aus der Queue (mit Aktiv-Abhol-Syscall) steckt ist doch nun wirklich egal, letzteres erspart Dir zumindest die entsprechende Speicherverwaltung im Kernel.


Grüße
Erik
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn am 27. January 2011, 21:21
Zitat von: erik
Wenn diese Programme wirklich so einfach sind dann wird es wohl kaum auf Performance ankommen. Bastle doch eine Library die den Port und den PopUp-Thread intern managed und die Messages in eine User-Mode-Queue stellt (sowas hattest Du doch vor ein paar Posts schon mal beschrieben) und schon ist alles komplizierte wieder gut versteckt. Ob der Mode-Wechsel nun vor dem reinpacken in die Queue (mit PopUp-Thread) oder nach dem rausholen aus der Queue (mit Aktiv-Abhol-Syscall) steckt ist doch nun wirklich egal, letzteres erspart Dir zumindest die entsprechende Speicherverwaltung im Kernel.
Naja, die Performance ist da wirklich nicht so wichtig, aber die Library muss auch erstmal geschrieben werden ;) Das eigentliche Problem wird dann sein wie man die Library so hinbekommt das man einerseits solch einfachen Programme unterstützt andererseits aber auch Programme die kein Problem mit dem Multithreading haben und das ohne das der Programmierer alles selbst machen muss.

Wäre auch schön wenn du auf die Sache mit der DoS-Attacke eingehen würdest!
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger am 28. January 2011, 07:41
Hallo,


Naja, die Performance ist da wirklich nicht so wichtig, aber die Library muss auch erstmal geschrieben werden ;)
Na also ne simple FIFO-Queue mit nem einfachen aber wirkungsvollen Lock sollte doch jemanden der ein OS baut nicht überfordern. ;)
Das kannst Du dann auch für andere Dinge außer nur GUI einsetzen wo es darauf ankommt externe Signale/Messages zu empfangen aber das Programm ein simples Singlethreading-Konzept einhalten soll und das dann lieber aktiv abholt. Ich denke das ist in wenigen Tagen komplett programmiert.

Das eigentliche Problem wird dann sein wie man die Library so hinbekommt das man einerseits solch einfachen Programme unterstützt andererseits aber auch Programme die kein Problem mit dem Multithreading haben und das ohne das der Programmierer alles selbst machen muss.
Also für den besseren/komplexeren Programme würde ich ne andere Library schreiben die eher den Fähigkeiten Deines GUI-Systems entspricht, ich denke diese 2 extremen Gegensätze sollte man nicht versuchen in eine einzige Library zu packen.

Wäre auch schön wenn du auf die Sache mit der DoS-Attacke eingehen würdest!
Also rein aus Speichersicht ist bei mir so ein DoS-Angriff auf den Service gar nicht direkt möglich da der Verbrauch der PopUp-Threads (also Stack- und TLS-Segment) ja logisch dem Client-Prozess zugeordnet wird und der Service ja nicht nur einen virtuellen Adressraum hat der voll werden könnte, nur das was der Code den der PopUp-Thread ausführt an Speicher anfordert (z.B. per malloc) muss sich der Service auch selber anschreiben lassen aber es ist ja auch sein Code der das verursacht. Ob das auch über mehrere Ebenen hinweg funktioniert muss ich dann mal sehen. Wie ich das konkret umsetze weiß ich allerdings noch überhaupt nicht, so weit bin ich auch noch gar nicht.
Bei der CPU-Belastung möchte ich das ähnlich machen. Wenn ich irgendwann einmal einen besseren Scheduler habe der Gruppen unterstützt dann sollen die PopUp-Threads immer den ursprünglichen Client-Prozess logisch zugeordnet werden so das sie z.B. der PopUp-Thread im SATA-Treiber seine CPU-Zeit immer noch von dem Prozess holen muss der ursprünglich das fread an den VFS-Service geschickt hat.
Mit dieser Vorgehensweise dürfte sich der böse Schadprozess nur selber schaden aber nicht das gesamte System komplett lahm legen können. Auf der anderen Seite muss man auch ganz ehrlich sagen das wenn ein Schadprozess erst mal richtig läuft das dann unter jedem normalen OS ein ernstes Problem darstellt. Die eigentliche Verteidigungslinie ist damit bereits durchbrochen und es geht hier nur noch darum das wenigstens root noch die Chance bekommt den Prozess zu killen ohne das ganze System herunterfahren zu müssen oder gar direkt den Stecker ziehen zu müssen nur weil er es nicht mal mehr bis an eine Konsole schafft. Wenn dieser Schadprozess aber auch noch an root-Rechte kommt und sich damit z.B. eine extrem hohe Priorität geben kann dann ist eh alles zu spät.


Grüße
Erik
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn am 28. January 2011, 09:55
Ich habe mir überlegt um dem etwas vorzubeugen könnte ich dem Popup-Thread meine fixed-Size Nachricht und die Größe des zusätzlichen Speichers mitgeben und der Code kann dann entscheiden ob die Größe für diesen Nachrichtentyp in Ordnung geht (was ja auch relativ ist).

Nur kostet das halt wieder Performance (es muss, wenn noch Speicher mitgeschickt wurde, noch ein Syscall gemacht werden um diesen auch mappen zu lassen), aber ich habe die Möglichkeit zu sagen, das diese Nachricht nicht weiter bearbeitet werden soll.

Was ich noch nicht weiß wie ich es löse ist, was passiert wenn der virtuelle Speicher des Services zu voll ist um eine Nachricht (also den zusätzlichen Speicher) empfangen zu können. Sollte ich dann warten bis genug Speicher frei ist (wie sollte man das lösen) oder sollte ich einfach dem Clienten eine Nachricht schicken das der Service nicht genügend Speicher hat um die Nachricht zu empfangen?

Rein theoretisch wäre es möglich das ein Client 256MB mit sinnlosen Daten hat und 12 Threads und alle Threads machen eine RPC Anfrage an den Storage-Server mit den 256MB. Dann ist der Storage-Server erstmal beschäftigt und kann keine weiteren Anfragen mehr annehmen, weil er keinen freien virtuellen Speicher mehr hat. Das ist zwar nur kurzzeitig, aber es ist halt möglich.

Ich weiß auch nicht wieviel Sinn es macht ein gewisses Limit einzuführen (z.B. 32MB). Eigentlich sollte es nicht so schlimm sein, wenn ein Client mehrere Anfragen machen müsste um mehr Daten zu bekommen oder? Weil dann bräuchte es schon 96 Threads/Clients für eine DoS-Attacke (sind zwar auch nicht zu viele, aber immerhin ;) ).

Was die FIFO-Queue betrifft mache ich mir da mehr sorgen um das malloc() was ich da bräuchte (Thread-safe).
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger am 28. January 2011, 12:25
Hallo,


Ich habe mir überlegt um dem etwas vorzubeugen könnte ich dem Popup-Thread meine fixed-Size Nachricht und die Größe des zusätzlichen Speichers mitgeben und der Code kann dann entscheiden ob die Größe für diesen Nachrichtentyp in Ordnung geht (was ja auch relativ ist).
Das köntest Du eventuell auch nur für große Nachrichten (> 4 MByte) machen. Der PopUp-Thread bekommt ja immer einen Pointer und eine Größenangabe und wenn der Pointer NULL ist obwohl die Größenangabe größer 0 ist (wenn die Größenangabe gleich 0 ist dann muss auch immer der Pointer NULL sein weil dann gar keine Zusatzdaten mitkommen, das ist auch ein gültiger Zustand, ungültig ist nur wenn Pointer != NULL aber Größenangabe == 0 ist) dann muss der PopUp-Thread das Mappen explizit anfordern wenn er es denn für angebracht hält. Das Problem ist IMHO das der Client seine Anfragen immer so formulieren kann das der Service sie für angebracht hält, ein fwrite(file, pointer, 256MByte) ist grundsätzlich erstmal immer eine gültige Aktion. Ich denke das Problem mit Deinem einem virtuellen Adressraum wirst Du so oder so haben, außer Du begrenzt die maximale RPC-Datenmenge grundsätzlich im Kernel immer auf einen festen Wert von z.B. 16 MByte (wenn diese Grenze groß genug ist stellt die auch kein Performance-Problem dar) aber dann braucht man für den DoS-Angriff einfach nur mehr Threads. Bei meinem Konzept hab ich vorgesehen das der Service beim Einrichten eines Ports immer auch Maximal-Größen angeben muss, genauso wie die maximale Anzahl an PopUp-Threads, z.B. der UDP-Service könnte da 64 kBytes angeben weil UDP eh nicht mehr Daten pro Paket aufnimmt.
Auf der anderen Seite muss man auch ehrlich sagen das wenn ein Schadprogramm einmal richtig läuft dann ist es eh schon fast zu spät. Die eigentliche Verteidigungslinie (Browser oder auch die Ausführungsverhinderung von nicht vertrauenswürdigen Programmen) muss schon davor ansetzen. Ich denke wenn wir zu sehr versuchen möglichst viel Sicherheit in IPC zu bauen dann arbeiten wir da wohl an der falschen Stelle (was nicht heißen soll dass das Thema Sicherheit bei IPC ignoriert werden soll), es kommt IMHO auf einen guten Kompromiss an.

Was ich noch nicht weiß wie ich es löse ist, was passiert wenn der virtuelle Speicher des Services zu voll ist um eine Nachricht (also den zusätzlichen Speicher) empfangen zu können. Sollte ich dann warten bis genug Speicher frei ist (wie sollte man das lösen) oder sollte ich einfach dem Clienten eine Nachricht schicken das der Service nicht genügend Speicher hat um die Nachricht zu empfangen?
Bei asynchronen Messages/Signalen würde ich von vornherein eine sehr konservative maximale Datengröße vorgeben, ich denke 64 kBytes sollten für alle möglichen Anwendungsfälle mehr als ausreichend sein (zumindest für ne Mausposition/Fenstergröße bei GUI-Nachrichten oder ein Exception-Descriptor bei Page-Fault-Signalen o.ä. sollte das immer bequem reichen).
Bei synchronen RPC-Dingen blockiert doch der RPC-send+recv-Syscall den Client eh bis alles fertig ist und bei mir liefert der auch 2 getrennte Rückgabewerte zurück, einmal vom Kernel der über den Erfolg/Misserfolg (bei Misserfolg mit nem richtigen Error-Code) des eigentlichen RPC-Vorgangs informiert und einen anderen der vom Service kommt und über den Status der eigentlichen Service-Routine Auskunft gibt. Wenn der erste Rückgabewert (vom Kernel) schon angibt das der RPC-Vorgang fehl schlug (egal ob nun kein virtueller Speicher mehr beim Service vorhanden war oder der Service nur Speicherbereiche bis x MByte akzeptiert aber der Client mehr übergeben wollte oder was anderes) dann braucht der Client die eigentliche Antwort nicht weiter analysieren sondern kann entscheiden ob er es noch mal probiert oder ob er auf gibt und dem User ne Fehlermeldung präsentiert.

Was die FIFO-Queue betrifft mache ich mir da mehr sorgen um das malloc() was ich da bräuchte (Thread-safe).
Du benötigst doch eh eine multithreading-taugliche libc, dann nimm die doch auch für Singlethreaded-Programme. Ein einfaches Lock wie das http://forum.lowlevel.eu/index.php?topic=2468.msg27659#msg27659 (http://forum.lowlevel.eu/index.php?topic=2468.msg27659#msg27659) sollte für Dinge wie malloc völlig reichen da malloc ja üblicherweise schneller fertig ist als ein einfacher Kontext-Switch dauert so das es eher kontraproduktiv wäre die Zeitscheibe frei zu geben (aber darüber haben wir ja in dem zitierten Thread bereits ausführlich gestritten).


Grüße
Erik
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn am 28. January 2011, 12:35
Zitat von: erik
Das köntest Du eventuell auch nur für große Nachrichten (> 4 MByte) machen. Der PopUp-Thread bekommt ja immer einen Pointer und eine Größenangabe und wenn der Pointer NULL ist obwohl die Größenangabe größer 0 ist (wenn die Größenangabe gleich 0 ist dann muss auch immer der Pointer NULL sein weil dann gar keine Zusatzdaten mitkommen, das ist auch ein gültiger Zustand, ungültig ist nur wenn Pointer != NULL aber Größenangabe == 0 ist) dann muss der PopUp-Thread das Mappen explizit anfordern wenn er es denn für angebracht hält.
Die Idee gefällt mir, vllt könnte man das sogar dynamisch machen, sprich bei der Port-Erstellung entscheidet das der Service (vorteilhaft z.B. für dein UDP-Bsp.) ab welcher Größe der Speicher explizit gemappt werden muss und was die maximale Größe überhaupt ist.

Wenn ich meine libc schreibe, will ich eigentlich versuchen lock-free Algos zu verwenden. Denn die erreichen ja einen höheren Durchsatz bei mehreren Threads und das kann vollständig im UserSpace laufen und die Performance auf ein-CPU Systemen sollte nicht viel schlechter sein als ganz ohne Lock.
Titel: Re:erik´s IPC Idee ;)
Beitrag von: Svenska am 28. January 2011, 20:43
Wenn ich irgendwann einmal einen besseren Scheduler habe der Gruppen unterstützt dann sollen die PopUp-Threads immer den ursprünglichen Client-Prozess logisch zugeordnet werden so das sie z.B. der PopUp-Thread im SATA-Treiber seine CPU-Zeit immer noch von dem Prozess holen muss der ursprünglich das fread an den VFS-Service geschickt hat.
Das kann böse nach hinten losgehen, wenn ein niedrigpriorisierter Prozess deinen SATA-Treiber (der ja begrenzt seriell arbeiten muss) blockieren kann, während gleichzeitig höherpriorisierte Prozesse dafür sorgen, dass CPU-Zeit knapp ist.
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger am 28. January 2011, 21:44
Hallo,


Das kann böse nach hinten losgehen, wenn ein niedrigpriorisierter Prozess deinen SATA-Treiber (der ja begrenzt seriell arbeiten muss) blockieren kann, während gleichzeitig höherpriorisierte Prozesse dafür sorgen, dass CPU-Zeit knapp ist.
Ja, das ist mir auch schon aufgefallen. Ich möchte ja in meine CPUs die Fähigkeit einbauen das der User-Mode-Code für kurze/begrenzte Zeit die Annahme von IRQs und anderen Unterbrechungen unterbinden kann (was ja eigentlich gar nicht erlaubt ist), das würde es ermöglichen dafür zu sorgen das der Code wenigstens nicht während einer Critical-Section unterbrochen wird. Da die Datenstrukturen in einem SATA-AHCI-Treiber noch recht harmlos sind (es geht ja nur um das Management von Jobs) sollte das dort klappen aber bei einem richtigen Dateisystem-Treiber ist das schon wieder was anderes, da könnten die kritischen Code-Abschnitte durchaus länger sein. Das Problem entsteht eben dann wenn ein Thread mit niedriger Priorität unterbrochen wird während er einen Lock hält und dann eventuell für sehr lange Zeit nicht mehr dran kommt um diesen Lock wieder frei zu geben. Hier wäre es besser wenn der PopUp-Thread immer eine für den Service ausreichend hohe Priorität hat (eventuell gibt man allen Threads in einem Service die selbe Priorität und der Service muss das Aufteilen von Bandbreite o.ä. selber managen) aber die CPU-Zeit trotzdem dem Prozess geklaut wird (dann würden die restlichen Threads in einem Prozess eventuell verhungern während einer davon einen Service in Anspruch nimmt).

Hm, alles irgendwie doof, die optimale Lösung wird mir da ganz gewiss nicht mehr Heute einfallen. Was ich auch nicht möchte ist das ich versuche jedes blöde SW-Design-Problem wieder mit HW zu kompensieren, das geht nur bis zu einem gewissen Grad. Das vorübergehende Abschalten der Unterbrechbarkeit ist zwar eine tolle Idee (und soll auch umgesetzt werden) aber das als Ausrede zu benutzen um nen blöden Scheduler zu programmieren ist wieder nicht so klug.

Werden den bei den aktuellen OSen eigentlich die I/O-Anfragen u.ä. mit der Priorität des Initiator-Prozesses gewichtet? (ich tippe mal auf nein oder nur sehr begrenzt)
Lohnt es sich eigentlich im IPC-System zu versuchen Anti-DoS-Techniken einzubauen oder sollte man lieber versuchen dafür zu sorgen das böse Prozesse erst gar nicht gestartet werden? (ich tippe mal auf letzteres)


Grüße
Erik
Titel: Re:erik´s IPC Idee ;)
Beitrag von: Svenska am 28. January 2011, 22:20
Du möchtest die Priorität von Treibern während des Syscalls auf die Priorität des aufrufenden Prozesses herabstufen. Die übliche Lösung ist es, die Priorität der Anwendungen während des Syscalls auf die Priorität des Treibers hochzustufen. Damit verhinderst du Prioritätsinversion.

Jemand, der ein Lock hat, muss temporär höher priorisiert sein, als jemand, der kein Lock hat. Und das kannst du auch mit Hardware nicht umkehren.

Die Antwort lautet nein, aber der CFS unter Linux kann Control Groups auch für I/O machen, soweit ich weiß. Allerdings ist das auf einem Desktop-System, naja, nur begrenzt wichtig. (Wenn du aber eine VServer-Umgebung aufbaust, ist das wieder unglaublich praktisch.)

Ich glaube, dein bester Schutz gegen ein DoS des IPC ist es, das IPC so schnell (und skalierend) zu bauen, dass die Flaschenhälse woanders auflaufen. Und der allerbeste Schutz gegen einen DoS ist natürlich, wenn das System die Last einfach schluckt und nicht umfällt. ;-)

Notfalls hast du halt eine DoS-Heuristik, die die Priorität von übermäßig IPC-produzierenden herabsetzt, auch auf Kosten von Locks. (Wird dann allerdings böse, wenn jemand einen I²C oder SPI mit Bitbanging implementieren möchte...)

Gruß
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn am 28. January 2011, 22:25
Zitat von: erik
Werden den bei den aktuellen OSen eigentlich die I/O-Anfragen u.ä. mit der Priorität des Initiator-Prozesses gewichtet? (ich tippe mal auf nein oder nur sehr begrenzt)
Irgendwer hatte es mal getestet das man einen kurzen "boost" (höhere Priorität) bekommt wenn man eine kritische Sektion "betritt". Soll aber nicht wirklich was gebracht haben (so das es spürbar war) und hängt auch sehr davon ab wie dein Scheduler funktioniert.

Eine Lösung um das Verhungern zu lösen sind lock-free Algos und lass dir gesagt sein, das ist ein schei*** Thema ;) (ich habe heute den ganzen Tag versucht ne Queue lock-free zu implementieren und ich habe es noch immer nicht geschafft, bin nun aber soweit das ich vllt meinen Kernel in C++ neu schreibe ;) )

Zitat von: erik
Lohnt es sich eigentlich im IPC-System zu versuchen Anti-DoS-Techniken einzubauen oder sollte man lieber versuchen dafür zu sorgen das böse Prozesse erst gar nicht gestartet werden? (ich tippe mal auf letzteres)
Wenn du dein IPC-System DoS sicher machen würdest, würdest du damit Symptombekämpfung betreiben. versuchst du das böse Prozesse erst gar nicht gestartet werden, wäre das eine Ursachenbekämpfung. Was wird wohl besser (aber nicht unbedingt einfacher) sein ;)
Titel: Re:erik´s IPC Idee ;)
Beitrag von: erik.vikinger am 29. January 2011, 09:17
Hallo,


Du möchtest die Priorität von Treibern während des Syscalls auf die Priorität des aufrufenden Prozesses herabstufen.
Nein, ich dachte daran das die Priorität des einzelnen PopUp-Threads dem Client-Thread (der den RPC initiiert hat) entspricht aber das ist ja Mist wegen den Locks. Eine andere Idee wäre es das alle PopUp-Threads automatisch mit der Default-Priorität des Treiber laufen (also die Priorität des Clients ignoriert wird), das tät zumindest die wenigsten Probleme mit Locking, Scheduler usw. verursachen aber es verhindert auch das eben die Jobs eines Clients mit niedriger Priorität auch im Service nur mit niedriger Priorität behandelt werden (der würde alle Jobs gleich behandeln und damit den DoS-Angriffen die Tür weit öffnen).

Die übliche Lösung ist es, die Priorität der Anwendungen während des Syscalls auf die Priorität des Treibers hochzustufen. Damit verhinderst du Prioritätsinversion.
Das finde ich irgendwie doof (täte dann ja auch die restlichen Threads im Client-Prozess betreffen), und für mein RPC-System völlig unnötig. Die Priorität des Clients ist für den Service absolut ohne Belang, nur die Priorität des entsprechenden PopUp-Threads kann den Service beeinflussen.

Jemand, der ein Lock hat, muss temporär höher priorisiert sein, als jemand, der kein Lock hat. Und das kannst du auch mit Hardware nicht umkehren.
Ich will das auch nicht mit Hardware umkehren sondern vereinfachen. Wenn ein Stück User-Mode-Code für kurze Zeit (so lange er den Lock hält) nicht unterbrechbar ist hat er quasi die höchste Priorität (er wäre damit auf Kernel-Niveau). Ich muss nur sicherstellen das die CPU dafür sorgt dass das von keinem User-Mode-Code irgendwie bösartig ausgenutzt werden kann, also der Zeitraum muss definitiv eng begrenzt sein und es sollte von der Restzeitscheibe immer eine kleine Strafe abgezogen werden (der Zeitscheiben-Counter zählt in der kurzen Zeit nicht aber es wird am Beginn immer gleich X Mikrosekunden abgezogen).

Die Antwort lautet nein, ....
Dachte ich mir doch.

Ich glaube, dein bester Schutz gegen ein DoS des IPC ist es, das IPC so schnell (und skalierend) zu bauen, dass die Flaschenhälse woanders auflaufen. Und der allerbeste Schutz gegen einen DoS ist natürlich, wenn das System die Last einfach schluckt und nicht umfällt. ;-)
Sehe ich ähnlich. Wichtig ist das ein Angriff nicht zu Instabilitäten oder zu Lecks in der Rechteverwaltung bzw. Rechtedurchsetzung führt.

Notfalls hast du halt eine DoS-Heuristik, die die Priorität von übermäßig IPC-produzierenden herabsetzt, auch auf Kosten von Locks. (Wird dann allerdings böse, wenn jemand einen I²C oder SPI mit Bitbanging implementieren möchte...)
ls wäre auch so ein Prozess der quasi nur RPC macht. Ich denke mit solch einer Beschränkung muss man nur anfangen wenn man merkt dass das System überlastet ist. Wenn ich 4 CPUs hab und eine davon mit ls oder Bitbanging ausgelastet ist kann mir das doch völlig egal sein.


Wenn du dein IPC-System DoS sicher machen würdest, würdest du damit Symptombekämpfung betreiben. versuchst du das böse Prozesse erst gar nicht gestartet werden, wäre das eine Ursachenbekämpfung. Was wird wohl besser (aber nicht unbedingt einfacher) sein ;)
Dann sind wir uns ja einig.
Wir versuchen DoS-Angriffe auf RPC zwar zu verhindern bzw. abzumildern aber wenn wir uns zwischen einem anständigen Design und einer Krückenlösung die aber weniger DoS-empfindlich ist entscheiden müssen nehmen wir auf jeden Fall das anständige Design. Ich denke bei RPC geht die Schönwetter-Performance vor, den Regenschirm sollen andere Stellen halten.


Grüße
Erik
Titel: Re:erik´s IPC Idee ;)
Beitrag von: kevin am 31. January 2011, 09:26
(ich habe heute den ganzen Tag versucht ne Queue lock-free zu implementieren und ich habe es noch immer nicht geschafft, bin nun aber soweit das ich vllt meinen Kernel in C++ neu schreibe ;) )
Hm? Für eine einfach verkettete Queue ist das doch trivial?
Titel: Re:erik´s IPC Idee ;)
Beitrag von: FlashBurn am 31. January 2011, 11:56
Zitat von: taljeth
Hm? Für eine einfach verkettete Queue ist das doch trivial?
Na dann mal her damit, aber für C++ ohne das man nen GC benutzen muss ;)
Titel: Re:erik´s IPC Idee ;)
Beitrag von: Svenska am 31. January 2011, 16:45
Die übliche Lösung ist es, die Priorität der Anwendungen während des Syscalls auf die Priorität des Treibers hochzustufen. Damit verhinderst du Prioritätsinversion.
Das finde ich irgendwie doof (täte dann ja auch die restlichen Threads im Client-Prozess betreffen), und für mein RPC-System völlig unnötig. Die Priorität des Clients ist für den Service absolut ohne Belang, nur die Priorität des entsprechenden PopUp-Threads kann den Service beeinflussen.
Mein Fehler, ich meinte natürlich nur den Thread selbst.

Wir versuchen DoS-Angriffe auf RPC zwar zu verhindern bzw. abzumildern aber wenn wir uns zwischen einem anständigen Design und einer Krückenlösung die aber weniger DoS-empfindlich ist entscheiden müssen nehmen wir auf jeden Fall das anständige Design. Ich denke bei RPC geht die Schönwetter-Performance vor, den Regenschirm sollen andere Stellen halten.
Schönwetter-Performance ja, aber bitte Schlechtwetter-Robustheit. :-P