Beiträge anzeigen

Diese Sektion erlaubt es dir alle Beiträge dieses Mitglieds zu sehen. Beachte, dass du nur solche Beiträge sehen kannst, zu denen du auch Zugriffsrechte hast.


Nachrichten - FlashBurn

Seiten: 1 ... 34 35 [36] 37 38 ... 43
701
Lowlevel-Coding / Re:IPC Methoden
« am: 01. September 2010, 20:07 »
Zitat von: erik
So läuft es nur ab wenn der Empfänger die Nachrichten selber aktiv abholen muss (Du also selber zur Post hinlaufen musst), wenn die Nachrichten aber zugestellt werden (also der Postbote zu Dir kommt und auch automagisch das exakt passende Transportbehältnis hat) dann gibt es dieses Problem nicht.
Gut ich will mein IPC darauf aufbauen, das man selber entscheidet wann man eine Nachricht bekommen möchte, sprich das man diese selbst abholt (das ist für mich auch das ganze Konzept des recv Syscall´s).

Ich bin mir eigentlich auch sicher (du kannst mich gerne vom Gegenteil überzeugen) das z.B. Linux auch "nur" die Daten aus seinem VFS/Cache in den Client-Buffer kopiert.

Zitat von: erik
So läuft es nur ab wenn der Empfänger die Nachrichten selber aktiv abholen muss (Du also selber zur Post hinlaufen musst), wenn die Nachrichten aber zugestellt werden (also der Postbote zu Dir kommt und auch automagisch das exakt passende Transportbehältnis hat) dann gibt es dieses Problem nicht.
Ich kann nur Vermutungen anstellen, aber ich denke mal, dass du das IPC an sich überbewertest. Im Fall von z.B. Haiku liegt das komplette VFS-System im Kernel, die werden also auch nur 1x Kopieren oder den Speicher reinmappen.

Man kann natürlich sein IPC System so aufbauen das man praktisch alle Probleme damit lösen kann (wie du es machst). Da muss man dann aber abwägen was leichter ist und für wen es leichter ist. Ich würde mir nämlich nicht noch zusätzliche Komplexität in den Kernel holen wollen (á la ich mappe das dann in den Client-Buffer). Ziel eines Mikrokernels ist es doch so viel wie möglich an Aufgaben (und auch Komplexität) aus dem Kernel zu holen und in den UserSpace zu packen.

Zitat von: erik
Was haben die Messages der User-Mode-Applikationen auf dem Stack vom Kernel zu suchen? Oder überhaupt auf irgendeinem Stack? Okay, tyndur legt die Messages auch auf den User-Mode-Stack und hat daher vermutlich gewisse Größenbeschränkungen, aber das tyndur-Konzept ist für synchrones IPC sicher nicht der Idealfall.
Ich orientiere mich bei schnellem IPC immer am L4-Kernel. Ich habe gerade mal so ein Paper über dessen IPC System überflogen und die haben synchrones IPC mit dynamic-size Msgs. Es wird versucht so viel wie möglich einer Nachricht in den Registern zu "kopieren" (was meiner Meinung nach auf x86 nicht wirklich viel bringt, zwecks verdammt weniger Register), wirds doch mehr wird es in einen Buffer kopiert (im Kernel) und wird es wirklich viel, werden Pages in gemappt.
Soweit ich das verstanden habe, weiß der Sender aber im Prinzip wie die Nachricht versendet wird, da für längere Msgs ein wenig mehr Aufwand auf Seite des Senders betrieben werden muss, aber auch auf Seite des Empfängers.
Auch gibt es da genau das Problem, das die Nachricht nur empfangen werden kann, wenn du damit rechnest bzw. weißt wie groß die Nachricht ist, die du bekommst.
Wie das dann genau mit dem Page mapping funktionier weiß ich nicht, nur das man da eine Nachricht so senden kann, das einem der Speicher praktisch weggenommen wird (wie als wenn man ne SharedMem Region erstellt und diese dann im eigenen Prozess unmappt und an einen anderen weiterschickt).
So einen Syscall könnte ich natürlich auch machen, damit würde ich mir ein paar Kernelaufrufe ersparen, aber mal sehen.

Zitat von: erik
Das ich da anderer Meinung bin dürfte wohl mittlerweile außer Frage stehen. Kopieren ist IMHO ein unnützer Vorgang für synchrones IPC.
Da bin ich wieder anderer Meinung. Gut passt die Nachricht in die Register muss nicht kopiert werden, ist die Nachricht verdammt groß mappst du einfach, aber was ist mit dem was dazwischen liegt, da wo du trotz mapping kopieren musst und was für die Register zu groß ist?
Ich behaupte mal das der Großteil der versendeten Nachricht da reinfällt.

Zitat von: erik
Ganz genau! Der Client (in diesem Fall der aufrufende Code) gibt seinem Buffer dem Service (also fread) damit der Service dort was rein legt. Genau das will ich auf IPC-Ebene nachbauen. Ich würde es mir extrem unhandlich vorstellen wenn fread mir nen Pointer auf die gelesenen Daten zurück geben würde, so müsste ich immer erst noch kopieren wenn ich mehrere Häppchen einer Datei in einem zusammenhängenden Array haben will.
Da komme ich jetzt nicht mit, wenn du mehrere Häppchen einer Datei in einem zusammenhängenden Array haben willst, dann muss doch irgendwo kopiert werden. Ob das nun fread macht oder ob du das erst nach dem fread machst ist dann schon fast egal, es muss gemacht werden.

Ich wage sogar zu behaupten das es bei bestimmten Sachen mehr Sinn macht, eine Datei vollständig in den Prozess einzulesen und aus diesem Buffer dann deine Häppchen rauszuholen, als sehr viele fread Aufrufe zu tätigen und deine Häppchen so zu holen!
702
Lowlevel-Coding / Re:Funktionsaufruf Kernel -> Modul
« am: 01. September 2010, 18:29 »
Zitat von: erik
Ich weiß nicht ob die Default-Mechanismen von Linux usw. so schlecht sind aber aus irgend einem Grund muss es ja die teuren kommerziellen Heap-Librarys geben.
Mir gefällt nicht das der Heap, mehr oder weniger zusammenhängend ist und von oben (wie ein Stack) herunter wächst.

Zitat von: erik
Das ist dann aber ziemlich kurzsichtig. Soll Dein OS nicht mal per LAN kommunizieren oder eine simple serielle Schnittstelle nutzen können?
Da hast du mich in dem Moment falsch verstanden. Ich will nicht die eine Methode für alles finden (sowas wie ne Weltformel), sondern nutze das was ich (also mein Kernel) zur Verfügung habe aus, sprich für verschiedene Probleme, verschiedene Lösungen.

Zitat von: erik
Hier wird dann doch der Speicher vom Client an den Service weitergegeben? Hm, das wird immer komplexer. Also den Mechanismus für beide Richtungen anzubieten scheint zwar verlockend aber ist bestimmt auch komplexer als sich auf eine Richtung zu beschränken. Oder haben Deine Memory-Sharing-Mechanismen nichts direkt mit dem IPC-Mechanismen zu tun? Wenn nicht, dann kosten sie natürlich wieder extra Syscalls.
Also erstmal was hast du immer mit deinen Syscalls ;) Ich weiß nicht wie du dir das vorstellst, aber wenn ich von SharedMem rede, dann läuft das bei mir folgender Maßen ab.
Du machst nen Syscall wo du ne BaseAddr und eine Länge (in Pages) angibst (sowie nen Flag ob der Speicher dann read-only ist oder nicht), der Kernel speichert dann die physischen Adressen der einzelnen Pages in einer Liste und markiert diese als SharedMem (damit sie nicht ausgelagert werden können) und du (der Syscall-Aufrufer) bekommst ne ID zurück. Als nächstes musst du noch einen Syscall machen (ich weiß nicht toll, aber mir ist nichts besseres eingefallen) in dem du sagst das du nem anderen Prozess Zugriff geben willst. Dann kannst du die ID an nen anderen Prozess weitergeben (den Prozess den du gerade Zugriff gegeben hast) und dieser macht dann mit der ID nen Syscall das er den Speicher mappen will, ist genug virtueller Speicher vorhanden wird das gemacht. Bist du (der Client, also der der den Speicher gemappt hat) fertig mit deiner Arbeit, rufst du nen Syscall auf, dass du den Speicher wieder unmappen willst und das wird dann auch gemacht, der Speicher wird aber in dem Sinne nicht freigegeben, sondern ist ja noch beim eigentlichen "Owner" vorhanden.

Das sollte auch ungefähr die Prozedur sein, wie sie auf allen (fast??) OS zur Verfügung gestellt wird.

Zitat von: erik
Verstehe ich das richtig das der HDD-Treiber den Speicher der Applikation oder des VFS frei gibt? Oh man, das klingt ganz schön schräg.
Siehe oben, wird nicht freigegeben, sondern ge-unmappet (scheiß denglisch ;) ).

Zitat von: erik
Falls Du dieses mal mit "Ports" die I/O-Ports meinst dann muss ich Dich enttäuschen es gibt auch HW die nur mit Memory-Mapped-I/O arbeitet und keine Ports hat.
Schitt erwischt :( Da muss ich mir auch nochmal Gedanken machen, wie ich einem Prozess (Treiber) erlauben darf nen bestimmten physikalischen Speicherbereich in seinen Adressraum zu mappen.

Zitat von: erik
Das ist einfach, der Kernel-Code schaut halt einfach selber ins Paging-Directory und schon hat er die physische Adresse. Das ist ein recht kurzer Syscall.
Das ist klar, aber das will ich nicht jedem X-beliebigen Prozess erlauben, sondern nur Treibern!

Zitat von: erik
Obwohl es ne Menge OSe gibt die auf den unterschiedlichsten CPU-Architekturen laufen und nur sehr kleine Teile davon spezifisch sind, die überlassen dem Compiler die Anpassungsarbeit.
Ja, aber zu welchem Preis? Ich meine das Linux auf allen Architekturen die selben Page-Tables nutzt, aber je nach dem wie das Paging dann auf der Architektur Hardware mäßig implementiert ist, sehen die dann in der Hardware ganz anders aus.
Außerdem gefällt mir diese ganze bedingte Kompilieren nicht, der Source sieht nicht mehr wirklich "schön" aus und ich habe auch oft Probleme den richtigen Code zu finden und zu lesen.
Außerdem wäre mir das viel zu viel Arbeit, denn du musst ja höllisch aufpassen, was du dann alles auf ner neuen Architektur implementieren musst, welche Funktionen eigentlich gar nichts machen usw.
703
Lowlevel-Coding / Re:IPC Methoden
« am: 01. September 2010, 18:12 »
Zitat von: erik
Aus meiner Sicht würde ich das anders formulieren: Im Average-Case ist Dein System X-fach langsamer als andere weil Du die Daten (mehrfach sogar, falls ich Dich richtig verstanden habe) kopierst und im Best-Case kommst Du immer noch nicht ganz an die Konkurrenz ran (selbst die nicht Zero-Copy-Konkurrenz dürfte kaum einholbar sein).
Wie kommst du darauf das mein System X-fach langsamer sei? Ich meine wir gehen einfach mal davon aus, dass alle Daten in die Pipe passen ohne das der Writer warten muss, das die Daten wieder daraus gelesen werden.

Im normal Fall läuft es doch so ab, du allokierst einen Speicherbereich für deinen Buffer für eine Nachricht, kopierst die erforderlichen Sachen in den Buffer rein und machst einen Syscall das du eine Nachricht versenden willst. Die Nachricht wird dann in einen Buffer im Kernel kopiert (dieser muss auch vorher allokiert werden, was bei dynamic-size Msgs unter Umständen ne "Weile" dauern kann).
Wenn der Empfänger dann die Nachricht abholt gibt es 2 Möglichkeiten, entweder sein Empfangsbuffer ist für die Nachricht groß genug oder er muss erstmal einen Syscall machen um zu wissen wie groß die Nachricht ist. Dann allokiert er einen Buffer und ruft nen Syscall auf, das er die Nachricht haben will. Die Nachricht wird dann aus dem Kernelbuffer in den Buffer des Clienten kopiert.

So ungefähr sollte das auf allen Systemen aussehen die asynchrones IPC zur Verfügung stellen. Die Nachricht muss in einem Buffer im Kernel zwischengespeichert werden und den Speicher, wo der Buffer drin liegt, kannst du dem Sender auch nicht einfach wegnehmen. Genauso ist es normal das du mit dem Speicher wo du die Nachricht hast reinkopieren lassen, machen kannst was du willst.

Ich bin mir ziemlich sicher dass das IPC von Haiku so aussieht, wie die aber das mit fread und solchen Konsorten gelöst haben, weiß ich nicht, müsste ich mal nachgucken. Die nutzen dynamic-size Msgs.

Ich weiß das man beim synchronen IPC versucht das Kopieren zu vermeiden, aber wie will man das mit sehr großen Nachrichten anstellen? Weil die Nachricht müsste ja in den Kernelstack des Senders passen, damit du ihn einfach vom Kernelstack in den Userstack des Empfängers kopieren kannst.

Zitat von: erik
Aha, deswegen ein Haufen extra Syscalls für das Memory-Sharing usw?
Ich verstehe nicht was du mit den extra Syscalls meinst. Weil SharedMem habe ich sowieso (wie jedes andere OS auch haben sollte) und das nutze ich halt dafür.

Zitat von: erik
Was ist bei Dir der "Treiber"? Der Dateisystem-Treiber (z.B. für ext2) oder der Block-Device-Treiber (z.B. für SATA)? Falls ersteres, warum sollte der VFS die Anfragen zerstückeln? Der weiß doch gar nicht das die Datei fragmentiert auf der Platte liegt (der VFS hat noch nicht mal ne Ahnung das man Dateien fragmentieren müsste/könnte). Falls letzteres, wo wird das Dateisystem verwaltet? Doch hoffentlich nicht im VFS, dann könnte man nicht mal einfach so ein NFS o.ä. einbinden.
Also ich gehe im Moment schon davon aus, dass das (z.B.) ext2 Modul dafür verantworlich ist, die einzelnen Blöcke (LBAs) von der Platte (oder woher auch immer) zu laden.

Ich stelle mir das so vor, das du als Modul (z.B. ext2) dem VFS verschiedene Funktionen zur Verfügung stellst (z.B. open, close, read, write, ...) und dich (damit meine ich das Modul) sehr wohl darum kümmerst welche LBAs zu der Datei gehören.

NFS ist ein Netzwerkfilesystem, oder? Sehe ich jetzt spontan kein Problem, anstatt nen Blockdevice Treiber nach den Daten zu fragen, fragt er (NFS-Modul) einfach den Netzwerk-Treiber nach den Daten.

Es kann sein das ich mir das jetzt zu einfach mache, aber das liegt daran, dass ich bei dem Thema null-Ahnung habe.

Zitat von: erik
Okay, ich denke das hab ich verstanden, aber das erscheint mir irgendwie unnötig umständlich.
Aus meiner Sicht ist das schneller/besser als wenn ich sage, das er die Daten per Msg verschickt.

Zitat von: erik
Wer ist "er" und "ihn"? Falls beides der Block-Device-Treiber ist, warum wird der Speicher nicht erst mal vom Dateisystem-Treiber analysiert/ausgelesen?
Der Blockdevice-Treiber. Was meinst du mit deiner letzten Frage?

Zitat von: erik
Ich denke das hab ich ebenfalls verstanden, auch wenn ich das immer noch ziemlich umständlich finde.
Wieso? kommt dem Zero-copy ziemlich nahe, bzw. ist es sogar. Das dürfte so ähnlich wie dein Konzept aussehen.

Zitat von: erik
Hier kommen wir meiner Meinung nach zum Problem in Deinem Konzept. Warum "willst" Du nicht auf das kopieren verzichten?
Problem ist (in meinem Kopf) das Paging, ich will nicht ohne das es der Prozess weiß, in den Pagingtabellen rumfummeln. Denn das müsste ich machen damit ich anstatt seines (der Empfänger/Client) Buffers, meinen eigenen nehmen kann.

Man könnte jetzt streng genommen sogar sagen, dass fread daran Schuld ist. Denn fread sagt das du den Buffer übergibst wo die Daten rein sollen und nicht das du nen Buffer zurück bekommst wo die Daten drin sind.

Zitat von: erik
Sorry, für dieses vernichtende Urteil aber dieses Konzept wirkt auf mich irgendwie extrem umständlich und von der verkehrten Seite angegangen.
Du hast mich erst überzeugt das mein Konzept richtiger Mist ist, wenn ich ein besser (eventuell mit deiner Hilft ;) ) habe. Aber es sollte auch vernünftig für Paging umzusetzen sein.
704
Lowlevel-Coding / Re:Funktionsaufruf Kernel -> Modul
« am: 01. September 2010, 10:42 »
Ich denke mal beim Heap sprichst du vom User-Heap? Da ist natürlich ein anderer Ansatz wesentlich besser geeignet. Obwohl die (z.B. Linux, Solaris) auch den SlabAllocator dafür nutzen und es scheint zu funktionieren.

Was den Heap allgemein betrifft, ist das so eine der Sachen die ich nie richtig verstanden habe und ich habe auch das Gefühl das viele sich da an Linux/Unix orientieren, aber ich bin der Meinung das deren Heap-Prinzip nicht so toll für Multithreading geeignet ist.

Zitat von: erik
Du meinst der HDD-Treiber alloziert Speicher (um dort Daten rein zu legen), gibt diesen Speicher weiter (an seinen Client, einen Dateisystem-Treiber) und damit ist der Speicher vom HDD-Treiber wieder entzogen (so als hätte er free benutzt)? Das ist ein sehr merkwürdiges Konzept, das mag zwischen VFS, Dateisystem-Treibern und Block-Device-Treiber noch funktionieren
Das ist doch erstmal das einzige was mich interessiert ;)

Zitat von: erik
Außerdem wie geht das beim Schreiben auf eine HDD? Muss da der HDD-Treiber erst Speicher allozieren damit das VFS da was rein legen (kopieren) kann und der HDD-Treiber (nachdem die Daten auf die HDD geschrieben wurden) diesen Speicher wieder freigeben muss?
Nein, der User hat ja seinen Buffer aus dem die Daten kommen, die (Daten) werden dann in neuen Speicher kopiert welcher an den VFS-Service weitergegeben wird (bzw. wenn nicht die ganze Datei geändert wird, werden die neuen Daten einfach über die alten Daten geschrieben) und dieser gibt den Speicher dann wiederrum an den HDD-Treiber weiter.
Der Treiber schreibt das ganze dann auf die HDD und gibt den Speicher wieder frei (das muss er auch beim Lesen machen, das habe ich glaub ich nicht so deutlich gesagt).

Das größte Problem was ich bisher nicht gelöst habe (aber ich habe schon eine Idee dafür) ist, dass ich nicht weiß wie ich es einem Treiber ermögliche das er rausbekommt, welche physikalische Adresse hinter einer virtuellen Steckt. Ich dachte mir das ich dafür nen Syscall mache und bei jedem Aufruf wird überprüft ob es ein Treiber ist (das ist bei mir immer dann der Fall wenn der Prozess auf Ports zugreifen darf).
Genauso müsste ein Prozess dann auch Speicher als nicht auslagerbar markieren dürfen (was dann halt schon bei der Allokierung passieren muss).
Obwohl ich mit dem Auslagern wohl die größten Probleme bekommen werde, da ich dafür noch gar keine Idee habe, wie das zu lösen ist, deswegen ignorier ich das im Moment auch fleissig ;)

Zitat von: erik
Ja, bei ARM hat man den Anbruch der 64 Bit-Epoche dem Anschein nach noch völlig verschlafen und das wo doch auch bereits Handys mal 1 GByte RAM haben können.
Dem würde ich jetzt entgegenhalten naund ;) Ich meine nur weil die schon bei 1GB RAM angekommen sind, heißt das ja noch lange nicht das denen der virtuelle Speicher ausgeht.
Ich denke mal Handys brauchen nicht unbedingt ne 64bit Architektur, aber schaden kann es natürlich nicht (mal von den Transistoren abgesehen, die du dann mehr bräuchtest).

Zitat von: erik
Versuch doch Dein OS so zu programmieren das es sich für beide Welten eignet.
Gerade das werde ich nicht tun! Ich bin der Meinung wer einen Mikrokernel (und nicht einen Mix aus Mikro und Monolith) schreibt, der sollte für jede Architektur einen extra Mikrokernel schreiben. Ist der Kernel wirklich klein, würde ich sogar sagen, das es sich lohnen würde diesen in Assembler zu schreiben.

Der Punkt ist, ich optimiere viele Sachen für die x86 Architektur und möchte nicht noch mehr Abstraktionsebenen einbauen, nur damit der Kernel leichter auf eine neue Architektur portiert werden kann. Gerade bei nem Mikrokernel ist doch der Aufwand den Kernel für ne andere Architektur (wo dann auch deren Besonderheiten beachtet werden, bzw. ausgenutzt werden) neu zu schreiben nicht sonderlich groß!
Wenn du die Interfaces gleicht behälst solltest du die meisten Sachen einfach nur neu kompilieren brauchen. Ich plane im Moment sogar wie ich meinen Device-Server portabel gestalte, da ja auf der ARM Architektur sowas wie ein BIOS nicht existiert. Da würde ich dem Device-Server wahrscheinlich als Startmodul auf jeder Architektur nen angepasstest Skript mitgeben, welches dann bestimme Module in einer bestimmten Reihenfolge lädt.
Damit wäre es dann einfach zu sagen, das dieses und jenes Gerät diesen und jenen Speicher/IO-Ports benutzt ohne das ich dafür Code ändern müsste (ziel wäre es nur die Adresse und IO-Ports in einem Skript zu ändern und schon hat man die Unterstützung für ein anderes Board ohne das man irgendwelchen Code neukompiliert hat).
705
Lowlevel-Coding / Re:Funktionsaufruf Kernel -> Modul
« am: 31. August 2010, 21:04 »
Zitat von: erik
Ich wollte den Heap über mehrere Segmente verteilen, eventuell sogar für jede angefragte Objekt-Größe ein eigenes Segment oder zumindest etwas in dieser Richtung. Genau weiß ich das noch nicht. Es wird auf jeden Fall nicht für jeden Aufruf von malloc ein neues Segment erstellt, da wären die Segmente ziemlich schnell alle und der Verschnitt wäre riesig (weil ein Segment immer ganze Pages belegt). Vielmehr möchte ich das gleichgroße Objekte alle im selben Segment drin sind und wie ein Array verwaltet werden. Der Vorteil meiner Segmente ist das ich die einzelnen Segmente unabhängig voneinander Vergrößern und auch wieder Verkleinern kann, ich hab nicht nur einen virtuellen Adressraum, wo man schon mal mit Konflikten rechnen muss, sondern ziemlich viele die eben völlig unabhängig voneinander sind.
Klingt wieder verdächtig nach dem SlabAllocator ;) So schlecht scheint das Konzept also nicht zu sein.

Zitat von: erik
Wenn der Service immer seinen Speicher an den Client weitergibt damit sich dieser daran bedienen kann dann gibt es bei Dir prinzipiell kein Zero-Copy. Überlege Dir mal wie damit ein HDD-Treiber arbeiten müsste, der müsste die gewünschten Sektoren erst mal in eigenen Speicher holen um dann diesen Speicher seinem Client zu zeigen damit dieser sich die Daten dort raus kopiert. Daran gefallen mir persönlich 2 Dinge nicht: zum einen der Zwang zum teuren und unsinnigen Kopieren und zum anderen das für das Memory-Sharing usw. ne ganze Menge Syscalls erforderlich sein dürften. Ein ls über ein Verzeichnis mit 10000 Dateien möchte ich damit nicht machen müssen.
Also den HDD-Treiber interessiert es prinzipiell schon mal gar nicht was mit den Daten passiert, der läd sie nur und gibt sie einfach an den VFS-Service weiter (da findet kein kopieren statt) und damit ist der Speicher für ihn auch weg.
Ich weiß nun nicht wie "ls" genau funktioniert, aber ich stelle mir das schon so vor, das er für jede einzelne Datei in dem Verzeichnis mind. 1 Syscall machen muss (müsste die Datei nicht sogar vorher geöffnet werden nur um an die Infos zu kommen, dann wären da ja sogar noch mehr Syscalls nötig).
Die Daten über die Dateien liegen im VFS-Service und dieser macht in dem Fall kein Memory-Sharing mit dem Clienten!
Der Client würde seine Anfrage per Pipe stellen und wenn er das geschickt macht, kann er sogar mehrere Anfragen mit einmal in die Pipe schreiben (so könnte ich sogar einige Syscalls vermeiden, wo auch mal ein Vorteil meiner UserSpace Pipe´s zum Tragen kommt).

Zitat von: erik
Das ist ungeschickt, der kommende Mainstream ist 64 Bit.
Ja, aber nicht überall ist die Situation mit den PCs so wie hier bei uns in Deutschland, ich möchte sogar behaupten die ist nirgends so wie hier. Damit meine ich das die Mehrheit der Leute relativ neue PCs haben.
Meistens ist es eher so das noch viele auf dem Stand von z.B. Athlon XP und sowas sind.
Was du eher meinst sind Spiele-PCs, aber das sollte weltweit gesehen, wohl eher die Minderheit sein.
Dann kommt noch hinzu das ich gerne auf realer Hardware teste und das auf so viel wie möglich und da sind viele 64bit Systeme nicht gerade günstig. Wenn ich mir da überlege wie viele 32bit Systeme ich mehr als günsitg erstanden habe.
Auch ist z.B. ARM (meines Wissens nach) noch nicht bei 64bit angekommen (um mal ne andere Platform zu nennen).
Also ich will erstmal ein halbwegs brauchbares System in 32bit haben. Dann habe ich vor ein neues für 64bit zu schreiben.
706
Lowlevel-Coding / Re:IPC Methoden
« am: 31. August 2010, 20:52 »
Zitat von: erik
Das ist, äh, ziemlich spartanisch. Damit kann man ja nichts weiter machen als Kommandos zu erteilen.
Naja, die Planung sieht auch so aus, das es für viel mehr nicht genutzt werden soll, aber wie groß würdest du ihn denn machen? Aber bitte davon ausgehen, das ich fixed-size benutze und er nicht zu groß werden soll.

Zitat von: erik
Du versuchst immer das Kopieren beim Kernel zu vermeiden aber das Kopieren im User-Space scheint Dich nicht zu kümmern. So weit mir bekannt ist ist das Kopieren im User-Space nicht schneller also wo ist das Problem?
1. ist der KernelSpace begrenzt (was aber nicht wirklich ein Problem sein sollte) und 2. ist im schlimmsten Fall das Kopieren im UserSpace genauso langsam wie das Kopieren im KernelSpace.
Worauf ich hinaus möchte, im schlimmsten Fall bringt mir mein System gar nichts, aber im besten Fall hoffe ich (und viel mehr ist es leider im Moment auch nicht ;) ) das es auf SMP System schneller ist als das Kopieren im KernelSpace (da es gleichzeitig stattfinden könnte).
Genauso versuche ich so viele Kernelaufrufe wie möglich zu vermeiden und da fällt mir dann doch ein dass das Kopieren im Kernel teurer ist als im UserSpace.
Denn im Kernel muss ich immer vorher gucken, ob der User überhaupt die Zugriffsrechte hat und ob der Speicher gemappt ist, aus dem kopiert werden soll. Wozu? Damit ich ja keine Exception im Kernel bekomme. Im UserSpace ist mir das egal, dann wird das Programm halt beendet.

Zitat von: erik
Falls wir uns auf ein Beispiel-Szenario einigen konnten wäre es nicht schlecht wenn Du Dein Konzept daran mal Schritt für Schritt ganz detailliert erklärst, sicher können wir das dann auch besser einschätzen. Ich persönlich habe wohl noch nicht alles da dran verstanden.
Bleiben wir doch bei der 300MB Datei. Das ich immer nur eine 4kb Page mappe, habe ich schon verworfen, da würden die ständigen Requests an den Service mir ne neue Page zu geben, die Performance auffressen.

Also ich sage dem VFS-Service (über ne Pipe) das ich eine Datei öffnen will und gebe noch den Pfad+Namen an. Hat das geklappt sage ich das ich halt die ganzen 300MB lesen will.
Der VFS-Service weist also den Treiber an die Datei zu laden (das VFS muss dazu im schlimmsten Fall sehr viele Anfragen machen, weil die Datei nicht zusammenhängend ist). Der Treiber macht das halt und erstellt nen SharedMem Bereich, setzt den VFS-Service auf die "allow"-Liste und gibt ihm die ID des SharedMem zurück. Dann "unmapped" er den SharedMem wieder und für ihn ist die Sache dann gegessen.
Der VFS-Service wiederrum setzt dann den Clienten auf die "allow"-Liste und gibt ihm die ID des SharedMem. Der Client kann den Speicher dann mappen (vorrausgesetzt er hat genug virtuellen Speicher frei) und dann werden die Daten in den Buffer des Clienten kopiert (ich kann und will dieses Kopieren nicht vermeiden).

Als ein potentielles Problem sehe ich, dass der Client den SharedMem nicht wieder freigibt. Denn so könnte es passieren, das der VFS-Service den Speicher gerne freigeben würde (ich meine wir reden hier von 300MB), aber das geht nicht (das weiß der Service aber nicht, für ihn funktioniert das ganze) da er ja noch beim Clienten gemappt ist.

Was ich gerade beim Schreiben schon optimiert habe, der VFS-Service muss die Datei noch nicht mal in seinen eigenen virtuellen Speicher mappen, es reicht ja vollkommen aus das er die ID des SharedMem speichert.

Falls du grobe Fehler siehst, dann immer raus damit!
707
Lowlevel-Coding / Re:Funktionsaufruf Kernel -> Modul
« am: 30. August 2010, 21:39 »
Zitat von: erik
Achte nicht zu sehr auf meine Segmente, die machen zwar ein paar Dinge ganz einfach aber sind keine zwingende Voraussetzung für mein IPC-Konzept.
Und genau da muss ich dir wiedersprechen (bzw. habe bestimmt noch nicht alles verstanden) ;)

Wie funktioniert denn dein malloc? Das Problem was ich habe, wenn wir die 300MB Datei nehmen, dann wäre es ja möglich das dir malloc nen Speicherbereich zurückgibt der nicht an 4kb ausgerichtet ist (sehr unwahrscheinlich, aber möglich). Wie würdest du das dann mit deinen Segmenten lösen? Und mit reinem Paging kannst du dann nicht einfach sagen, ich blende dann mal in den 300MB Buffer meinen (den vom Service) Speicher ein!

Zitat von: erik
Pro LDT sind 32768 Segmente möglich (jeder Prozess hat seine eigene LDT), das sollte für ne Weile reichen und wenn die doch mal knapp werden dann geht eben der IPC-Vorgang gerade nicht und wird gequeued (also der Client blockiert).
Dazu wäre es auch gut, wenn du mal erklärst wie dein malloc funktionieren soll oder besser wann ein neues Segment erstellt wird und wann nicht.

Zitat von: erik
Hä, wer gibt hier an wen Speicher weiter?
Also fread würde einfach zum Service sagen, gib mir mal den Speicher von da bis da (den Bereich wo die zu lesenden Daten drin sind) und der Service gibt dann als Antwort ne ID für SharedMem zurück die in den Clienten eingeblendet wird und fread kann aus diesem "Cache" dann in den Buffer des Clienten kopieren.

Zitat von: erik
Spätestens auf einer 64 Bit-Plattform ist dieses Problem erst mal für absehbare Zeit in weiter Ferne.
Ich habe mir schon überlegt immer nur 4kb einzublenden, zu kopieren und die nächsten 4kn einblenden zu lassen.
Einziges Problem mit dem Caching ist, was passiert wenn dem Storage-Server der virtuelle Speicher ausgeht und noch eine Datei geöffnet werden soll?

Leider habe ich nicht vor so schnell mein OS auf eine 64bit Architektur zu portieren bzw. neuzuschreiben.

Zitat von: erik
Wenn wir da Probleme finden sollen dann musst Du Dein Konzept schon mal konkret vorstellen. Wink
Ich hoffe die obige Beschreibung reicht?!
708
Lowlevel-Coding / Re:Funktionsaufruf Kernel -> Modul
« am: 30. August 2010, 20:53 »
Zitat von: erik
Das kann ich wirklich nicht beurteilen weil ich echte keine Ahnung hab was Du eigentlich meinst.
Das könnte daran liegen das ich noch immer nicht dein Konzept mit den Segmenten vollständig verstanden habe, bzw. mir nicht klar ist wie du bestimmte Probleme lösen willst. Aber so langsam (hoffe ich) verstehe ich es.

Was machst du eigentlich wenn dir die Segmente ausgehen und du aber noch freien virtuellen Speicher hast? Was ich mir auch nicht so richtig vorstellen kann, wie löst du das mit dem Auslagern der Daten?

Ich sage mal (vielleicht auch aus Gewohnheit) das wenn du die Segmente auch auf 4kb Einheiten festlegen würdest, dass dann viele Sachen einfacher werden, aber dann wären sie natürlich auch wieder sinnlos ;)

Im Endeffekt, habe ich bei mir schon Caching drin (da die Daten immer vom VFS Service in den Clienten kopiert werden) und du müsstest da halt genauso kopieren. Du würdest dir also einmal kopieren (bei mir aus der Pipe in den Buffer des Clienten) ersparen.
Aber wenn ich dein Konzept so übernehmen würde, dann bräuchte ich einfach zu sagen, dass ich in dem Fall was ähnliches mache und einfach den Bereich der zu lesen ist (bzw. halt die 4kb Pages wo der Bereich drin liegt) einblendet (natürlich read-only) und dann die Daten von da aus in den Buffer des Clienten kopiere, so würde ich auch auf einmal kopieren kommen.
Die Idee ansich ist zwar gut, hat aber das Problem (was eher selten bis gar nicht auftauchen sollte) wenn mir der virtuelle Speicher ausgeht, funktioniert das ganze nicht mehr, da sind dann meine 4kb Pipe´s wieder von Vorteil.

Edit::

Für das Problem das mir der virtuelle Speicher ausgehen sollte, werden halt immer nur 4kb eingeblendet und ich kopiere die Daten dann von da aus in den Buffer.

Ich denke ich werde das Konzept so nehmen, es sein denn ihr findet Probleme damit.
709
Lowlevel-Coding / Re:IPC Methoden
« am: 30. August 2010, 13:03 »
Zitat von: erik
Ich finde "fixed size Msgs" klingt nach wenigen kBytes, von da bis zu den 4MBytes ist ein weites Feld, was machst Du mit Datensätzen in diesem Größen-Bereich? Das Shared-Memory muss aber auch wieder erst initiiert werden und damit bekommst Du dann für eine einzelne Funktionalität (in diesem Fall fread) mehrere verschiedene Wege und damit mehr Komplexität (im fread genauso wie in Deinem Storage-Server).
Da ich mein Msg-System noch nicht wirklich nutzen muss, bin ich mir mit der Größe noch nicht sicher, aber im Moment sind es gerade mal 32bytes ;)
Ich bin wie gesagt, sowieso eher ein Fan von SharedMem (was auch meine Pipe´s mit einschließt) und die Kommunikation welcher SharedMem wofür genutzt wird, das soll dann über Msgs laufen und alles andere halt über SharedMem (Pipe´s).
Ich denke ab 4kb kann man durchaus SharedMem nutzen, bzw sollte es auch. Sicher für einmalige Sachen ist das zwar scheiße, aber bevor ich das ganze in den Kernel kopiere und von dort aus dann wieder zum Clienten kopiere, finde ich SharedMem schneller (was ich aber nicht bzw. noch nicht beweisen kann) und angenehmer.
710
Lowlevel-Coding / Re:Funktionsaufruf Kernel -> Modul
« am: 30. August 2010, 12:55 »
Zitat von: erik
Auf welches IPC-Konzept bezieht sich diese Frage? Ich gehe nicht davon aus das Du mein IPC-Konzept meinst denn bei mir wird nichts "abgeholt"!
Gut dann bekommst du halt eine Nachricht, aber das was ich meine bleibt gleich.

Zitat von: erik
Wovon schreibst Du da? Lesen und Schreiben (also fread und fwrite) sind bei mir 2 verschiedene/unabhängige IPC-Vorgänge.
Mir geht es darum, dass du die Daten ja anforderst, weil du damit arbeiten willst und wenn wir bei unserem Bsp bleiben, dann hast du die ganze 300MB Datei geladen (bzw. als Segment in deinem Prozess) und willst jetzt die Datei anbestimmten Stellen bearbeiten (das können viele, aber auch nur ein paar sein) und dann stehst du vor der Wahl, machst du für jede kleine Änderung einen neuen IPC Aufruf oder änderst du alles mit einmal und sagst dann das du die Datei speichern willst.
In dem Fall müsstest du die ganzen 300MB in deinen eigenen (ich meine mit deinen, den vom Clienten) Speicher kopieren und dann ändern.
Den Speicher (mit den geänderten Daten) willst du (als Client) jetzt aber auch behalten, weil du damit noch weiter arbeiten willst.

Zitat von: erik
Beim Paging sind diese Randbereiche aber deutlich größer und damit wirklich ein ernsthaftes Risiko.
Der Punkt ist aber, dass das nur "halbherzig" ist. Wirklich sicher ist es nicht.
Wer sagt, dass nicht genau diese 16bytes den Server (Service) abstürzen lassen bzw. das dieser dann mit falschen Daten arbeitet?! Ist dann ähnlich einem Bufferoverflow.
711
Lowlevel-Coding / Re:Funktionsaufruf Kernel -> Modul
« am: 30. August 2010, 10:42 »
Zitat von: erik
Wie seht ihr das Risiko mit diesen kleinen Rand-Bereichen?
Naja, ist halt so ne Sache ;) Ich sag mal wenn du sowas zulässt, dann kannst du auch sagen, das du die Segmente gar nicht brauchst und kannst alles über Paging machen (weil da hast du ja auch nur "kleine" Randbereiche).
Ich würde halt sagen, wenn dann richtig. Obwohl das mit den Segmenten natürlich auch nur Sinn macht, wenn kein Paging dahinter steckt, weil ansonsten könntest du ja auch fast alles übers Paging machen, bzw. könntest du auf x86 theoretisch auch solche Einblendungen per Paging machen und dann ein Segment drüber legen, damit nicht auf die Randbereiche zugegriffen werden kann. Dies heißt dann aber auch, das der ganze restliche Speicher auch über Segmente gemacht werden muss und genau da sehe ich halt auch das Problem.
Der Aufwand dafür wäre (mir) zu groß. Weil du speicherst dann neben dem Pointer auch noch das Segment wo der Poiter drin liegt.

Zitat von: erik
Ich verstehe nicht was Du meinst! Du scheinst das Wort "er" in verschiedenen Bedeutungen zu nutzen.
Der Client kann beim Service weder etwas verändern noch etwas lesen, er gibt ja seine Speicher-Bereiche für den Service frei und nicht umgekehrt. (Ich hoffe das war es was Du wissen wolltest, wenn nicht dann formuliere Deine Frage Bitte noch mal neu)
Ich seh gerade, dass ich mich da wirklich sehr dumm ausgedrückt habe.

Also was ich meine ist, das man ja im Normalfall eine Nachricht abholt und dieser Speicher wo die Nachricht drin ist, ist dann meiner und ich kann machen was ich will. Mir fällt gerade kein Bsp dafür ein, aber was ist wenn du die Nachricht nicht nur liest, sondern vielleicht auch noch ein wenig veränderst um dann damit zu arbeiten?
Das würde bei dir dann heißen, dass du die Daten doch wieder kopieren musst und um mal bei dem Bsp mit der 300MB Datei zu bleiben, könnte das im Extrem Fall heißen, dass du die 300MB zum Lesen und nochmal 300MB zum Schreiben brauchst.
Wo sich mir dann auch die Frage stellt, wie lange ist das Segment gültig oder musst du es als Empfänger dann wieder selbst freigeben? Oder was passiert wenn der Sender das Segment freigibt, aber der Empfänger noch damit arbeiten will?

Zitat von: erik
Also hier verstehe ich gar nichts mehr. Sorry, aber Bitte formuliere Deine Frage noch mal neu.
Ein Lesezugriff auf den Cache im VFS läuft immer auf einen Kopiervorgang hinaus (vom Cache in den Buffer der Applikation), weil der Service (in diesem Fall das VFS) ja keine Speicherbereiche an den Client geben kann (wäre auch irgendwie doof).
Du hast mir die Frage schon beantwortet (man darf in die erhaltenen Daten nicht schreiben).
712
Lowlevel-Coding / Re:Funktionsaufruf Kernel -> Modul
« am: 29. August 2010, 20:22 »
Zitat von: erik
Bei einem Monolithischen Kernel sieht der Kernel alles von der Applikation da ist mein Konzept schon mal ein echter Fortschritt.
Ähm, der Kernel sieht immer alles von der Applikation. Was genau meinst du in dem Fall?

Zitat von: erik
Beim Service ist einfach ein bischen mehr Speicher vom Client zu sehen als tatsächlich benötigt wird. Ich muss zwar meine Segmente auf 4kBytes (oder auf der 64Bit-Plattform auf 64kBytes), also kleinste Page-Größe, ausrichten (weil in einer Page niemals mehrere Segmente drin sein dürfen, wegen Defragmentieren und Swappen) aber wo die zugreifbaren Daten Anfangen und Enden kann ich jeweils auf 256 Bytes genau festlegen (theoretisch sogar noch genauer). Das bedeutet das im Worst-Case der Service vom Client pro Buffer bis zu 510 Bytes (2 * 255) Speicher sieht in dem er eigentlich nichts zu suchen hat, das ist zwar ein gewisses Risiko aber ich denke das ist verschmerzbar.
Was ist wenn der Empfänger jetzt in den Buffer schreiben will? Muss er dann kopieren oder darf er in das Segment schreiben?
Damit (wenn er in das Segment schreiben darf) gibt es dann 2 Probleme, 1. kann er dann im ungünstigsten Fall Daten beim Empfänger ändern und der Sender kann mit den Daten in dem Segment praktisch nichts mehr anfangen, da sie ja nicht mehr dem entsprechen was er mal gesendet hat.
Das letzte Problem ist besonders fürs VFS entscheidend. Denn du willst ja das Kopieren vermeiden, wenn der Empfänger aber die Daten ändern darf, dann kannst du sie nicht mehr einfach an jeden Clienten senden (der die Datei lesen möchte), da sie nicht unbedingt dem entsprechen muss was eigentlich in der Datei steht.
Darf der Empfänger nicht in das Segment schreiben, musst du ja doch wieder kopieren, damit er das machen kann.

Also sparst du im Endeffekt 1 Kopiervorgang (aber auch das wären im "schlimmsten" Fall 50% Ersparnis).
713
Lowlevel-Coding / Re:IPC Methoden
« am: 29. August 2010, 12:08 »
Zitat von: taljeth
Dann gibt es halt einen Fehler zurück. Dasselbe wie wenn der Empfänger weggesegfaultet ist oder anderweitig nicht in der Lage ist, Nachrichten zu verarbeiten.
Das war mir klar, aber was passiert mit der Nachricht, bleibt die in der Queue und muss durch einen extra Syscall gelöscht werden oder passiert das gleich?

Auch wäre dann interessant woher man weiß das der Sender auf eine Antwort wartet, denn man muss ihm ja bescheid geben, das der Empfänger die Nachricht nicht entgegen nehmen konnte (da ist dann synchron wieder im Vorteil). Bei mir ist das wieder durch ein Flag gekennzeichnet, das der Sender auf eine Antwort wartet.

Zitat von: taljeth
Vermutlich schon, ja. Aber wenn wir mal kurz von den 300 MB Abstand nehmen, die sicher nicht der Durchschnittsfall sind, dann machen die erste und die letzte Page wahrscheinlich häufig den Großteil oder sogar den ganzen Request aus.
Da wäre dann das optimalste, wenn du alles in eine oder zwei neue Pages kopierst und diese dann mappst. Dann ersparst du dir zumindest den 2. Kopiervorgang.
714
Lowlevel-Coding / Re:IPC Methoden
« am: 29. August 2010, 11:45 »
Zitat von: taljeth
Solange das Szenario fread ist, musst du mindestens einmal kopieren, um das nötige Alignment zu bekommen, damit du einfach Pages mappen kannst. Wenn ich es richtig verstanden habe, haben deine Segmente auch gewisse Alignmentvorgaben, insofern hast du dann genau dasselbe Problem.
Wenn ich dich jetzt richtig verstanden habe, dann würdest du halt aus der 1. Page alles in eine neue Page kopieren und diese dann anstatt der originalen mappen und das selbe eventuell mit der letzten Page nochmal?

Da wären wir dann wieder da, das ich sage, nur fixed size Msgs und alles andere über meine Pipe´s bzw. wenn es z.B. mehr als 4MB sind, dann macht man das per SharedMemory.

Ich würde dann sozusagen die Komplexität an die User Programme (bzw. die Bibliotheken) weiterreichen.

Was ich in dem Sinne auch noch nicht habe, was passiert eigentlich wenn der empfangende Prozess nicht genug freien virtuellen Speicher hat um die Nachricht zu mappen?
715
Lowlevel-Coding / Re:Funktionsaufruf Kernel -> Modul
« am: 29. August 2010, 09:48 »
Also gut folgender Code irritiert mich ein wenig:
  File_Read_Responce_t responce;
  ulong responce_length = ~0;

  //ein blockierender Syscall (synchrones IPC) :
  const long retval = syscall_msg_sync_send(vfs_msg_id,&request,sizeof(request),NULL,0,&responce,&responce_length,sizeof(responce),data,&fread_length,length);
Die erstellst auf deinem Stack den Speicher für "response", der hat ne bestimmte Größe (entspricht der Struktur die hinter "File_Read_Response_t" steckt) die du ja auch dem Syscall mitgibts.
Ich habe das jetzt so verstanden das er also die Nachricht dort in den Speicher von "responce" und nur der Länge "sizeof(responce)" reinkopiert.

Zitat von: erik
Der Client erstellt gar kein Segment für IPC, er nimmt den Speicher den er schon hat und interessiert sich nicht dafür in welchem seiner Segmente dieser Speicher liegt.
Das Problem was ich hier nicht ganz verstehe ist, er muss also sehr wohl irgendwann mal ein Segment mit der Größe der Nachricht erstellt haben oder er nimmt einfach einen Buffer der irgendwo in irgendeinem Segment liegt.
Ist letzteres der Fall hast du doch aber ein Problem, da du entweder das ganze Segment mit dem Buffer einblenden musst (was dann wieder nicht sicher ist, da da ja auch andere Daten drin stehen können) oder du musst aus diesem Buffer ein neues Segment machen, was halt nicht immer geht, da du ja deine Segmente an 4kb ausrichtest/ausrichten musst.
Also entweder fordert der Sender vorher ein Segment entsprechend seines benötigten Buffers vom Kernel an oder er muss sich darum kümmern das der Buffer auch an 4kb ausgerichtet wird.

Das selbe Problem hast du wenn du es auf nem Flat-Memory-System umsetzen willst. Der Server muss dann dafür sorgen das der Buffer für die Nachricht an 4kb (Pagegröße) ausgerichtet ist und das nichts anderes in dieser Page steht, dann kannst du das mit dem einblenden machen, aber ansonsten nicht.

Wenn ich mir jetzt mal vorstelle, das der Sender die Nachricht selbst noch für was benutzen will und der Empfänger auch ganz gerne mit der Nachricht arbeiten will, dann muss einer von beiden die Nachricht doch in einen Buffer kopieren, dieser Schritt entfällt bei mir natürlich.

Zitat von: erik
Es ist Aufgabe des Kernels sich um diese Details zu kümmern und Aufgabe des CPU-Entwicklers dem Kernel das passende Werkzeug zu geben.
Wie gesagt ist meine Frage dann, was macht der Kernel wenn die Nachricht nicht an 4kb ausgerichtet ist?

Zitat von: erik
Ja, das stimmt und war auch einer der Gründe warum ich diese Idee tatsächlich umsetzen will. Ich möchte beweisen das man mit Segmentierung ein sehr sicheres und gleichzeitig schnelles System erstellen kann, Segmente also kein überholtes Relikt vergangener Zeiten sind.
Ich weiß jetzt nicht was dafür alles in Hardware getan werden muss, könnte mir aber vorstellen, dass wenn du komfortabel mit Segmenten arbeiten willst, der Hardwareoverhead in keinem Verhältnis dazu steht. Bzw. müssten dann auch noch alle Compiler neu geschrieben werden und auch diese Arbeit ist nicht zu unterschätzen. Denn ansich sind alle Compiler auf Flat-Memory ausgelegt (inzwischen, denn früher mussten sie ja auch mit Segmenten klarkommen).
716
Lowlevel-Coding / Re:IPC Methoden
« am: 29. August 2010, 09:29 »
Auf Grund von erik´s Fragen, habe ich das mit der Pipe nochmal durchdacht und habe den Code von oben wieder verworfen (zumindest größtenteils). Was ich übernommen habe, ist das man immer in "Wörtern" (auf einer 32bit CPU also 4byte) in die Pipe schreibt und auch aus ihr liest.

Das Problem mit dem Code war, das es nicht möglich war eine Nachricht mit mehreren Aufrufen an "pipeLightRead" zu holen, das habe ich mit meinem aktuellem Code gelöst.

Wäre toll wenn ihr den mal kommentieren könnte, sprich ob das ne gute Idee oder eher ne schlechte ist!

#define PIPELIGHT_STATUS_READER_WAITING 0x1
#define PIPELIGHT_STATUS_WRITER_WAITING 0x2

struct pipeLightKernel_t {
uint32t numPages;
struct list_t *pages;
struct sem_t reader;
struct sem_t writer;
};

struct pipeLight_t {
uint32t size;
uint32t volatile numWords2Read;
uint32t volatile flags;
uint32t volatile ptrRead;
uint32t volatile ptrWrite;
uint32t data[];
}

void pipeLightReaderWait(struct pipeLightKernel_t *pipe, struct pipeLight_t *pipeUser) {
if(pipeUser->numWords2Read == 0) {
if(pipe->writer.count < 0)
semRelease(&pipe->writer);

pipe->flags|= PIPELIGHT_STATUS_READER_WAITING;

semAcquire(&pipe->reader);

pipe->flags&= ~PIPELIGHT_STATUS_READER_WAITING;
}
}

void pipeLightReaderFlush(struct pipe_t *pipe) {
if(pipe->flags & PIPELIGHT_STATUS_WRITER_WAITING)
pipeLightWriterWakeup(pipe);
}

void pipeLightReaderWakeup(struct pipeLightKernel_t *pipe) {
semRelease(&pipe->reader);
}

void pipeLightWriterWait(struct pipeLightKernel_t *pipe, struct pipeLight_t *pipeUser) {
if(pipeUser->numWords2Read == pipeUser->size) {
if(pipe->reader.count < 0)
semRelease(&pipe->reader);

pipe->flags|= PIPELIGHT_STATUS_WRITER_WAITING;

semAcquire(&pipe->writer);

pipe->flags&= PIPELIGHT_STATUS_WRITER_WAITING;
}
}

void pipeLightWriterFlush(struct pipeLightKernel_t *pipe) {
if(pipe->flags & PIPELIGHT_STATUS_READER_WAITING)
pipeLightReaderWakeup(pipe);
}

void pipeLightWriterWakeup(struct pipeLightKernel_t *pipe) {
semRelease(&pipe->writer);
}

void pipeLightReader(struct pipeLight_t *pipe, uint32t *buffer, uint32t count) {
while(true) {
if(!count)
break;

//if there is no data, go into the kernel and wait for the writer to wake us up
while(pipe->numWords2Read == 0)
pipeLightReaderWait(pipe);

*buffer= pipe->data[ptrRead];

atomicSub(&pipe->numWords2Read,1);
buffer++;
count--;

if(++ptrRead == pipe->size)
ptrRead= 0;
}

pipeLightReaderFlush(pipe);
}

void pipeLightWriter(struct pipeLight_t *pipe, uint32t *buffer, uint32t count) {
while(true) {
if(!count)
break;

//if there is no free mem to write to, go into the kernel and wait for the reader to wake us up
while(pipe->numWords2Read == pipe->size)
pipeLightWriterWait(pipe->data);

pipe->data[ptrWrite]= *buffer;

atomicAdd(&pipe->numWords2Read,1);
buffer++;
count--;

if(++ptrWrite == pipe->size)
ptrWrite= 0;
}

pipeLightWriterFlush(pipe->data);
}
717
Lowlevel-Coding / Re:IPC Methoden
« am: 28. August 2010, 22:33 »
Zitat von: erik
Nein, man kann auch in MMU-basierten Falt-Memory-Systemen einfach mal eine größere Menge an Daten von einem Prozess in einen anderen mappen. Man sucht sich dazu einfach in dem Ziel-Prozess einen passenden freien Block im virtuellen Adressraum und mappt dort die selben Pages des physischen Speichers rein wie in dem Quell-Prozess.
Wo wir schon bei einem interessantem Punkt wären. Wenn man Nachrichten mit dynamischer Länge hat, könnte man sagen, das man ab 4kb nicht mehr die Daten kopiert, sondern Pages einblendet.
Die Frage wäre jetzt nur was passiert mit den Pages beim Sender? Ich meine normalerweise werden die Daten ja kopiert oder besser gesagt kannst du als Sender davon ausgehen, wenn du zurück vom Syscall kommst, dass du mit den Daten machen kannst was du willst. Wenn man aber die Pages in einem anderen Prozess einblendet, dann kannst du das nicht mehr einfach so machen.
Eine Lösung wäre COW (copy-on-write).

Zitat von: erik
Naja, man muss eben auf beiden Seiten aufpassen das man keine Message fehlerhaft dekodiert ansonsten verliert man die Synchronisation. Wenn man da z.B. ein fehlertolerantes Protokoll benutzen möchte bringt das eben wieder etwas zusätzliche Komplexität ins Spiel.
Die würde ich halt in den Bibliotheken verstecken.

Zitat von: erik
Wieso, was ist daran schlechter Programmierstiel dem OS klar zu sagen das ich viele Daten lesen will anstatt dem OS etliche male zu sagen (lügen) das ich nur wenige Daten lesen will? Mal vom zusätzlichen Kommunikationsoverhead vieler Anfragen abgesehen.
Ich würde sowas nicht per fread machen sondern die Datei direkt in meinen Prozess mappen lassen (was wohl daran liegt, dass das wohl wesentlich effizienter und schneller sein sollte, auf allen Betriebssystemen).

Wie wäre es denn wenn mal jemand sagen würde wie das unter Windows oder Linux (oder sonst einem OS) gemacht wird?

Zitat von: erik
Benötigt man dieses Pipe-Paar ein mal pro Prozess oder ein mal pro Thread? Kann man über ein Pipe-Paar verschiedene Dinge parallel/verschachtelt erledigen?
Ich bin im Moment für pro Thread, weil du meine Pipe´s nicht wie klassische Pipe´s benutzen kannst. Betrachte sie eher wie eine definierte Kommunikation über SharedMem.

Was meinst du mit dem parallel/verschachtelt erledigen? Also wie gesagt, meine Pipe ist keine Pipe im klassischen Sinne.

Zitat von: erik
Okay, hab ich verstanden. Das bedeutet das Du in jedem Prozess je einen Thread benötigs um die Kommunikation aufrecht zu erhalten auch wenn mal gerade nichts kommuniziert wird. Wenn sehr viele Programme auf Deinem OS laufen die alle mal auf Dateien zugegriffen haben würde das auch bedeuten das in Deinem "Storage-Server" eine ziemlich große Anzahl an Threads nutzlos schläft und Speicher verbraucht.
It´s not a bug, it´s a feature ;)

Ich bin mir gerade nicht sicher was du damit meinst das ich in jedem (User-) Prozess einen Thread brauche um die Kommunikation aufrecht zu erhalten.
Was die Threads in den Servern betrifft, ja.

Aber wenn viele Programme laufen können, die viele Dateien öffnen, dann hat der PC auch genug Power und RAM um das bewältigen zu können.

Zitat von: erik
Das heißt Du möchtest für einen Vorgang gleich 2 CPUs belegen?
So wie du das "sagst" klingt das so negativ ;) Ich will darauf hinaus, das die Daten, in meinem Fall, ja in eine Pipe kopiert werden und daraus auch wieder rauskopiert werden müssen. Am optimalsten wäre es halt wenn das ganze Gleichzeitig stattfinde würde. Dann müssten auch keine Kontextwechsel stattfinden, sondern der Storage-Server kann immer schön in die Pipe kopieren und der Client kann zur gleichen Zeit schön aus der Pipe kopieren, so werden die Daten ohne Kontextwechsel in den Client kopiert.

Ein weiterer Vorteil ist, das meine Methode auch bei knappen virtuellem Speicher funktionieren.

Ich wäre dann auch mal an einer Lösung interessiert wie man die Daten aus dem Server in den Clienten (über IPC) bekommt bzw. wie du/andere es halt besser machen würden.

Anders gefragt, wie machen es denn bekannte/weniger bekannte Mikrokernel?

Edit::

Was mir gerade so durch den Kopf geht. Wenn ich es richtig verstanden habe, dann soll ja beim synchronen Msg-Handling an sich nichts kopiert werden (oder besser im Kernel zwischengespeichert werden), aber wo sind die Daten denn? Wenn sie auf dem Stack sind, auf welchem User oder Kernel? Falls auf dem Userstack, wie bekommt ihr sie da von einem Prozess zum nächsten? Denn normalerweise kann man den Userspace von einem anderen Prozess ja nicht "sehen".
718
Lowlevel-Coding / Re:IPC Methoden
« am: 28. August 2010, 16:56 »
Zitat von: erik
Bezüglich Deiner Definition von synchronem Message-Handling fehlt dann noch (als Steigerung) richtiges Message-basiertes RPC, also wo der Client nicht nur wartet bis der Service seine Anfrage bearbeitet sondern solange wartet bis er auch seine Antwort vom Service bekommt.
Ähm, das habe ich bei mir mit dem Syscall "send+recv" und nem Flag das man auf die Antwort des Empfängers warten will.

Zitat von: erik
Wieso sollte das nicht ohne kopieren gehen? Ich hab doch nebenan genau erläutert wie es auch komplett ohne kopieren geht.
Um das Thema auch für weniger wissende interessant zu machen, würde ich sagen das wir deine Hardware-Architektur mal außen vor lassen ;) Die Mehrheit der heute vorhandenen Architekturen kennt keine richtigen Segmente mehr.
Und wenn du keine Segmente hast, dann musst du ja in irgendeiner Form kopieren. Einzige Möglichkeit ohne kopieren auszukommen, wäre auf einer Architektur ohne MMU (auch das dürfte für uns nicht so interessant sein).

Zitat von: erik
Aber bei Byte-orientierten Pipes muss man gut aufpassen das Sender und Empfänger nie uneins werden wo Nachrichten anfangen und aufhören, man benötigt also ein gutes (komplexes) Kommunikations-Protokoll.
Bitte genauer erklären was du meinst, da ich dir nicht genau folgen kann, am besten an einem Bsp.

Zu dem Bsp. möchte ich mal noch meinen, das es ziemlich schlechter Programmierstil wäre eine 300MB Datei per fread in einem Ritt zu laden. Zumal du dir ja ein schönes Bsp ausgesucht hast, was deine Architektur ja bevorzugt (da es keinen Unterschied für dich macht ob du 3MB oder 300MB per Segment einblendest) ;)

Also ich sage jetzt mal das ich das alles über Pipe´s löse (da bin ich mir aber noch nicht 100% sicher). Bei der Initialisierung der libc (oder dem 1. benutzen von Dateifunktionen) macht man sich mit dem Storage-Server 2 Pipe´s aus, eine zum Senden und eine zum Empfangen.

Dann "stellst" du eine Nachricht zusammen, die halt aus dem MsgCode für OPEN besteht und dem String für den Dateinamen.
Als Rückgabewerte bekommst du dann den ErrorCode (0 falls alles in Ordnung war) sowie den Dateihandle (ne einfache Nummer),
Für GET_SIZE dann wieder das gleiche Spiel, MsgCode halt für GET_SIZE und noch den Dateihandle.
Als Rückgabewerte halt wieder ErrorCode und die Size.
READ wird dann schon interessanter. Man stellt halt wieder eine Nachricht zusammen, MsgCode von READ und dann noch den Dateihandle und halt wieviel man von wo an lesen möchte. (An dieser stelle möchte ich mal anmerken, das es sinnvoller wäre von fread hier zu entscheiden, die Datei irgendwie per SharedMem zu lesen, bzw. einzublenden)
Die Daten kommen dann halt per Pipe und müssen in den von malloc allokierten Bereich kopiert werden. Wenn alles optimal läuft (auf einem SMP System) dann kann das sogar halbwegs gleichzeitit ablaufen (sprich der Storage-Server schreibt in die Pipe und auf der anderen CPU kann fread gleichzeitig aus der Pipe lesen).

Da ich aber ja gerade versuche ne neue Pipe (siehe früherer Post) zu implementieren, würde ich die "kleinen" Sachen (wie MsgCode, Dateihandle, Errorcode) per Msg verschicken und nur sowas wie Dateinamen und die Daten die zu lesen sind per Pipe.
719
Lowlevel-Coding / Re:Funktionsaufruf Kernel -> Modul
« am: 28. August 2010, 16:02 »
Zitat von: erik
Ich dachte das hätte ich bereits deutlich genug erklärt. Hast Du meine letzten Beiträge wirklich gelesen? (Bitte nimm mir diese Frage nicht übel aber irgendwie bin ich verwundert)
Nein, die Frage war berechtigt ;) Ich vergesse immer das du Segmente nutzt! Bzw. dein Bsp.code vom fread irritiert mich da ein wenig. Wenn du Segmente benutzt dann macht es natürlich Sinn, das du ein Segment zurück bekommst und die Nachricht nicht erst in einen Buffer kopieren musst, aber bei deinem Bsp. übergibst du einen Pointer auf einen Buffer und die Länge des Buffers, das hat mich total durcheinander gebracht.

Was passiert eigentlich mit dem Segment auf der Senderseite? Kann der noch schreibend auf das Segment zugreifen? Und wie bekommt/erstellt er das Segment? Weil du ja auf 4kb aligned Segmente haben willst, muss sich der Sender darum kümmern dass der Speicher das ist oder fragt er nach einem passendem Segment?

Ich sag mal Segmente sind für sowas natürlich ganz praktische, es geht schneller (da kein kopieren) und du hast wesentlich besseren Schutz (weil man nicht außerhalb des Segments lesen/schreiben kann), nur die Verwaltung dürfte ziemlich anstrengend werden.

Zitat von: erik
Wenn die Applikationen mit hoher Priorität den kompletten Computer beanspruchen um ihre Arbeiten zu erledigen dann verhungern natürlich die Applikationen mit niederer Priorität aber das ist ja gewollt, genau deswegen gibt es ja extra die Prioritäten damit das OS weiß welche Dinge dem User wichtig sind (also mit Vorrang bearbeitet werden müssen) und welche nicht (also warten dürfen). Bei dem Scheduler könnte man natürlich eine Art Fairness-Regel einbauen damit auch Applikationen mit niedrigerer Priorität nicht komplett verhungern, Windows kann das angeblich, aber davon ob das wirklich sinnvoll ist bin ich nicht überzeugt. Prioritäten sind ein Werkzeug um dem Computer zu sagen welche Wichtigkeit eine Aufgabe hat, es liegt am User dieses Werkzeug richtig zu nutzen. Wenn Du möchtest das ein Audio-Player im Hintergrund Musik spielt und diese nicht ins stocken geraten darf dann gibst Du dem Audio-Player eine hohe Priorität, wenn dadurch die Applikation im Vordergrund spürbar beeinträchtigt wird brauchst Du entweder einen schnelleren Computer oder Du musst Deine Ansprüche ändern so das die Musik auch mal stocken darf (der Audio-Player also keine hohe Priorität bekommt). Prioritäten machen Deinen Computer nicht schneller sie sorgen nur dafür das die vorhandene Performance gemäß Deiner Präferenzen genutzt wird.
Also bei deinem Bsp gibt es aber einen Fehler (wie ich finde, du kannst da natürlich anderer Meinung sein), das Programm im Vordergrund sollte immer bevorzeugt werden und nicht irgendein Programm im Hintergrund.

Ansich sieht man eigentlich schon zu das es sowas wie verhungern nicht gibt bzw. das es nicht passiert. Also bei meinem momentanen Scheduler passiert das auch nicht (aber was noch nicht ist kann noch werden ;) ).
720
Lowlevel-Coding / Re:IPC Methoden
« am: 28. August 2010, 14:19 »
Ich habe gerade das Prinzip aus folgendem Artikel übernommen (pipe-light):
http://www.ddj.com/showArticle.jhtml?articleID=189401457

Erstmal der Code:
static const int cachelineInWords= 32 / sizeof(uint32t);

struct pipeLightKernel_t {
uint32t id;
uint32t numPages;
struct list_t *pages;
struct sem_t reader;
struct sem_t writer;
};

struct pipeLight_t {
uint32t id;
uint32t size;
uint32t * volatile data;
};

static uint32t pipeLightNextNull(uint32t *ptrData, uint32t max);

void pipeLightReaderWait(struct pipeLightKernel_t *pipe) {
semRelease(&pipe->writer);
semAcquire(&pipe->reader);
}

void pipeLightReaderFlush(struct pipeLightKernel_t *pipe) {

}

void pipeLightWriterWait(struct pipeLightKernel_t *pipe) {
semRelease(&pipe->reader);
semAcquire(&pipe->writer);
}

void pipeLightWriterFlush(struct pipeLightKernel_t *pipe) {

}

void pipeLightReader(struct pipeLight_t *pipe, void *buffer, uint32t count) {
uint32t i= 0, *ptrData= (uint32t *)buffer, pos= 0, nextNull= 0;

while((nextNull= pipe->data[i]) == 0)
pipeLightReaderWait(pipe->id);

i++; pos++;

while(true) {
if(!count)
break;

uint32t data;
//if there is no data, go into the kernel and wait for the writer to wake us up
while((data= pipe->data[i]) == 0)
pipeLightReaderWait(pipe->id);

if((i + 1) % cachelineInWords == 0) {
uint32t j;

for(j= 0; j < cachelineInWords; j++)
pipe->data[i - j]= 0;
}

if(pos == nextNull) {
nextNull= data;
data= 0;
}
if(count >= 4) {
*ptrData= data;
count-= 4;
ptrData++;
} else {
memcpy(ptrData,&data,count);
count= 0;
}

pos++;
i= (i + 1) % pipe->size;
}

if(i % cachelineInWords != 0) {
uint32t j;

for(j= 0; j < i % cachelineInWords; j++)
pipe->data[i - j]= 0;
}

pipeLightReaderFlush(pipe->id);
}

void pipeLightWriter(struct pipeLight_t *pipe, void *buffer, uint32t count) {
uint32t i= 0; *ptrData= (uint32t *)buffer, pos= 0, nextNull= 0;

while(true) {
if(!count)
break;

uint32t data= 0;
//if there is no free mem to write to, go into the kernel and wait for the reader to wake us up
while(pipe->data[i] != 0)
pipeLightWriterWait(pipe->id);

if(pos == nextNull) {
nextNull= pipeLightNextNull(ptrData++,(count / 4) + 1) + pos + 1;
data= nextNull
} else {
if(count >= 4)
data= *ptrData;
count-= 4;
ptrData++;
} else {
memcpy(&data,ptrData,count);
count= 0;
}
}

pipe->data[i]= data;

pos++;
i= (i + 1) % pipe->size;
}

pipeLightWriterFlush(pipe->id);
}

uint32t pipeLightNextNull(uint32t *ptrData, uint32t max) {
uint32t x;

for(x= 0; x < max; x++) {
if(ptrData[x] == 0)
break;
}

return x;
}

Mein Problem sind die beiden "Flush"-Funktionen. Genauer ist das Problem zu vermeiden, das der Reader in den Kernel geht um auf Daten zu warten, bevor er das aber fertigstellen kann, kommt der Scheduler dazwischen und der Writer kann sein Flush ausführen (Problem: der Reader hat sich noch nicht in die Semaphore gepackt).
Nächste Situation wäre, wenn der Writer einen Flush ausführt und im Kernel unterbrochen wird und der Reader alle Daten fertig gelesen hat und auch seinen Flush fertig ausführt und dann kommt der Writer zurück und will (eventuell) einen nicht vorhandenen Reader aufwecken.

Ich hoffe ihr versteht was ich meine und könnt mir helfen wie man das lösen könnte.
Seiten: 1 ... 34 35 [36] 37 38 ... 43

Einloggen