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 ... 28 29 [30] 31 32 ... 43
581
Lowlevel-Coding / Re:SMP und die damit verbundenen Probleme
« am: 19. October 2010, 15:18 »
Zitat von: svenska
Bei deinem Mikrokernelsystem ist sicher nicht so schädlich wie bei einem Monolithen.
Ich würde sagen, das nimmt sich nicht so viel. Bei nem Mikrokernel wirst du viele Kernelaufrufe zwecks IPC haben, aber dafür sollte die Zeit im Kernel wirklich nicht lange dauern.

Zitat von: svenska
Für Neuschreiben (wie bei dir) ist diese Vorangehensweise sicherlich die denkbar schlechteste Lösung.
Du weißt doch, es gibt immer jemanden der es trotzdem macht ;)
582
Lowlevel-Coding / Re:Shared Memory
« am: 19. October 2010, 13:45 »
Zitat von: svenska
Wie gesagt, das ist nicht nötig. Du solltest als Maßstab für die Auslagerfähigkeit einer Page den Nutzungsgrad annehmen und nicht den Zustand - eine Page, die in hundert Prozessen gemappt, aber trotzdem ungenutzt ist, kannst du problemlos auslagern.
Ok, wie definierst du Nutzungsgrad und wie würdest du den rausbekommen?

Problem ist hier redet ein Blinder (ich) vom Sehen. Denn ich weiß theoretisch wie das mit dem Auslagern so ungefähr funktioniert, wie das aber implementiert wird da habe ich nicht wirklich eine Ahnung. Aber dafür wird meiner Meinung nach das Dirty-Flag benutzt und das müsstest du dann in allen Prozessen prüfen wo die Page gemappt ist und das finde ich zu aufwendig.

Zitat von: svenska
Sonst kann dir dann jeder das System lahmlegen, indem er einfach den RAM mit shared Pages vollmüllt.
So einfach wird es nicht, dafür würdest du dann schon 2 Programme benötigen, weil so wie ich jetzt mein SharedMemory geplant habe, kann der nur erstellt werden in dem du Speicher verschickst und dann brauchst du noch nen Prozess der den dann auch nicht mehr freigibt.
583
Lowlevel-Coding / Re:SMP und die damit verbundenen Probleme
« am: 19. October 2010, 13:39 »
Zitat von: erik
Das TLB löschen ist ein kleines Assembler-Macro:
Das ist seit dem 486 nicht mehr so bzw. geht viel performanter nämlich mit "invlpg". Mir deiner Variante würde ich ja jedes Mal den ganzen TLB löschen und das ist nicht Sinn der Sache.
Zumal du damit ab PPro richtig Probleme bekommen kannst, denn deine Variante löscht nicht die Einträge die global markiert sind, die musst du alle explizit mit "invlpg" löschen (wimre).

Zitat von: erik
Das diese Annahme falsch ist weißt Du ja nun selber. Zumindest bei einem vmmUnmap() musst Du die vorher gültigen PT-Einträge aus dem TLB entfernen. Andersrum ist das nicht so kritisch.
Wie gesagt, das Löschen im TLB mache ich immer gleich in der vmmMap() und der vmmUnmap() und dann wird einfach nur noch eine IPI-Nachricht verschickt dass das die anderen CPUs (eventuell) auch machen müssen.
Damit ist der TLB auf der aktuellen CPU immer gültig.

Zitat von: erik
Du bist es offensichtlich nicht gewöhnt in parallelen Bahnen zu denken, ich kann Dir da nur empfehlen erst mal mit Multithreading-User-Space-Programmen zu üben. Als ich das erste mal für ein Multi-CPU-PC programmiert habe (damals ein 4 x Pentium-Pro) war das für mich auch eine Art Kulturschock, man wird mit so vielen neuartigen Problemen konfrontiert.
Ich habe von Anfang an so programmiert und meinen Kernel immer für SMP/Multithreading ausgelegt und so programmiert.
Es ist halt ne Tatsache das ein Bug, der nur sporadisch und nach keinem Muster auftritt eher verdammt schwer bis gar nicht zu finden ist.
Gerade bei SMP kann das heißen das dein Kernel mal läuft und mal gibt es nen Deadlock ohne das du weißt warum.

Die ganze Bug Suchgeschichte hatte aber auch seine Vorteile, bei der Suche habe ich mir teile des Codes in Assembler angesehen und da ist mir erstmal aufgefallen wie fehleranfällig mein Lockcode war  :roll: Ein Wunder das da bisher nichts passiert ist.

Zitat von: erik
Nicht so ganz, Du musst Dir mehr Mühe geben keine Henne-Ei-Probleme in Deinem Design zu haben.
Das lässt sich aber eigentlich gerade bei einem OS nie vermeiden, irgendjemand muss halt mal irgendwann initialisieren und da gibt es immer so ein Problem. Bei mir treten die halt auch nach der Initialisierung auf ;)

Nächste Sache ist halt, ich könnte wieder den alten SlabAllocator verwenden, der hat nicht die Probleme, aber der ist nicht mal annähernd so schnell und skaliert auch nicht so schön.

Zumal du damit ja indirekt implizierst das man lieber keine komplizierten Sachen/Konzepte nutzen sollte, damit fällt dann auch Multithreading auf mehreren Cores weg. Denn damit holt man sich nen Haufen Probleme und die Komplexität steigt auch nicht ganz unwesentlich.

Zitat von: erik
Hast Du denn vor die IPIs noch für etwas anderes zu benutzen?  Mir fällt da ehrlich gesagt nichts ein.
Ja. Wird für Rendevouz-Funktionen genutzt (z.B. TSCs synchronisieren) und dafür alle außer der sendenden CPUs anzuhalten.

Beide Fälle sollten aber kein Problem darstellen. Jetzt muss ich nur noch rausbekommen wie das mit dem NMI funktioniert und dann habe ich durch meinen ersten Versuch das Problem zu lösen meinen IPI-Code für die sendende CPU sogar wesentlich performanter gemacht.

Zitat von: svenska
Alternativ pinnst du den Kernel auf eine CPU fest und lässt auf den anderen CPUs nur Userspace laufen.
Ersteres habe ich bei mir nicht implementiert und finde ich auch nicht nötig und zweiteres ist, aus meiner Sicht unmöglich.
Denn was willst du machen, wenn schon 2 CPUs im KernelSpace laufen und den Kernel sozusagen sperren willst. Wenn du daran denkst das immer nur eine CPU in den Kernel darf, dann ist das wieder ne GIANT_LOCK und sowas sollte man heutzutage nicht mal mehr in Betracht ziehen. Das ist nur unnötige Ressourcen Verschwendung weil man zu faul war sich nen Kopf zu machen ;)
584
Lowlevel-Coding / Re:Lowlevel außerhalb der OS-Programmierung
« am: 18. October 2010, 21:38 »
Alles was man auf nem Mikrokontroller programmiert ist Lowlevel und stellt meistens auch kein OS dar, sondern "nur" ne Anwendung.

Mit Mikrokontroller meine ich wirklich mikro, also so 8bit Sachen wo man auch nur 2KB Speicher hat und solche Späße.
585
Lowlevel-Coding / Re:SMP und die damit verbundenen Probleme
« am: 18. October 2010, 19:40 »
Zitat von: myself
Ich gehe immernoch davon aus, das auf der aktuellen CPU die TLBs in Ordnung sind und wenn ich die Nachricht gesendet habe, kann mir alles andere egal sein.
Ich kann sagen, dass das so nicht stimmt ;)

Mein Kernel läuft wieder auf mehreren CPUs, mehr oder weniger :(

Also wer sein OS möglichst erstmal "nur" zum Laufen bringen will, sollte von SMP (d.h. nicht das man kein Multithreading machen soll) erstmal Abstand halten!

Es ist einfach eine Qual Code zu debuggen der auf mehreren CPUs gleichzeitig läuft. Ich bin mir nicht sicher ob ich noch irgendwo ein Locking Problem habe (obwohl da wo es zu sein scheint, kann es eigentlich nicht sein) oder ob ich ein Problem mit fehlerhaften bzw. nicht aktuellen TLBs habe.

Die Symptome sind, dass mein Kernel die meiste Zeit, wenn ich ihn in Bochs oder Qemu teste, läuft, aber ab und zu kommt entweder ein Locking Problem oder ein Fehler der nach fehlerhaften bzw. nicht aktuellen TLB aussieht.

Edit::

Ich denke ich kann inzwischen die Probleme mit dem TLB-Shutdown und nicht aktuellen TLBs einschränken.

Mit meiner neuen Variante IPI-Nachrichten zu versenden und zu bearbeiten offenbart sich leider immer mehr ein Problem mit dem Locking.

Um es mal an einem Bsp. zu zeigen. Ich habe ja ne relativ aktuelle Variante des SlabAllocators implementiert und bei dieser ist es so das man sogenannte Magazine (kleine Stacks, die bei mir 4 Objekte beinhalten) pro CPU benutzt. Hat den Vorteil das, solange mind. 1 Objekt in dem Magazin ist, dass allokieren verdammt schnell geht.
Leider hat es den Nachteil, das man während man guckt ob noch Objekte im Magazine sind die Ints ausmachen muss, da das ja alles auf der selben CPU laufen muss. So weit ist da auch noch kein Problem.
Problematisch wird es wenn das Magazin aufgefüllt werden muss. Dazu wird der "alte", "einfache" SlabAllocator aufgerufen. Auch das muss wieder auf der gleichen CPU passieren, weil ansonsten könnte es passieren das man versucht das Magazin einer anderen CPU aufzufüllen, das gar nicht leer ist bzw. sogar voll ist.
Das ist auch immernoch kein Problem. Erst wenn der VMM aufgerufen wird, weil der SlabAllocator ne neue Page braucht tritt ein Problem auf. Solange das alles auf der CPU passiert die ihr Magazin neu befüllen muss funktioniert das auch. Wenn jetzt aber eine andere CPU auch ihr Magazin auffüllen will und dann auf die neue Page zugreift kann das schief gehen.
Denn die Ints sind ja aus, da alles auf der gleichen CPU laufen muss, und damit wird auch nicht der TLB aktualisiert und es wird ein alter Eintrag genutzt.

Ich hoffe ihr konntet das Problem nachvollziehen.

Ich suche jetzt nach einer vernünftigen Lösung dafür, aber bisher ist mir nichts eingefallen. Die einzige Idee die mir kam, war den IPI-Service-Int weg von einem normalen Int hin zu einem NMI zu machen. Damit wird jede CPU immer unterbrochen auch wenn sie eigentlich die Ints aus hat und da ich nur Code ausführe der TLBs aktualisiert sollte das auch kein Problem darstellen.
Was meint ihr?
586
Lowlevel-Coding / Re:Shared Memory
« am: 18. October 2010, 16:51 »
@erik

Siehe anderer Thread. Ich habe eventuell eine Möglichkeit gefunden mein Design, mal wieder, zu fixen ;)
587
Lowlevel-Coding / Re:SMP und die damit verbundenen Probleme
« am: 18. October 2010, 16:50 »
Zitat von: erik
Ich weiß jetzt nur noch deutlicher warum ich keinen unterbrechbaren Kernel will! Das ist ja ein unheimlicher Zusatzaufwand der da getrieben werden muss! Vor allem kann ich für einen Micro-Kernel keinen Vorteil dadurch erkennen.
Du kommst einfach auf x86 um einen unterbrechbaren Kernel nicht herum!

Zitat von: erik
Warum, einen TLB-Flush wirst Du doch überall mal kurz ausführen können.
Mir geht es in dem Fall eigentlich darum, das ich keinen doppelten Code habe, weil ich müsste die Nachrichten Behandlung ja einmal im Handler haben und einmal im Sende-Code was natürlich quatsch ist.

Zitat von: erik
Das klingt irgendwie kompliziert. Kann man an diese Sache nicht anders ran gehen?
Bin ich gerade dabei ;) Wenn ich fertig bin und es funktioniert so wie ich es mir vorstelle, dann muss man nur noch einen Lock haben, damit man eine neue Nachricht in die Liste packen kann. Man muss dann auch nicht mehr warten bis alle anderen CPUs die Nachricht bearbeitet haben.
Allerdings muss der Sendevorgang an sich (das Schreiben, genauer 2 32bit Werte, in ein 64bit APIC Register) durch deaktivierte Ints geschützt werden.

Zitat von: erik
Nach einem vmmUnmap() solltest Du aber schon warten bis wirklich alle CPUs ihren TLB gelöscht haben.
;)

Ich gehe immernoch davon aus, das auf der aktuellen CPU die TLBs in Ordnung sind und wenn ich die Nachricht gesendet habe, kann mir alles andere egal sein.

Was ich machen könnte, ist am Ende von vmmMap() und vmmUnmap() nachzusehen ob nicht irgendwelche IPI Nachrichten da sind und diese dann bearbeiten oder noch besser bevor ich eine neue Nachricht sende, wird nachgeguckt ob ich nicht erstmal alte bearbeiten sollte.
Ich denke ich werde letzteres umsetzen.

Zitat von: erik
Nach einem vmmUnmapp() muss man tatsächlich warten bis alle CPUs ihren TLB aktualisiert haben aber dort gibt es ja auch keine neuen Pages die man gleich benutzen will und es sollte auch kein Problem sein nach einem vmmUnmap() mal die INTs an zuschalten.
Nein und nein ;)

Also das Problem was ich meine ist, das CPU A nen Unmap macht (und die Ints aus sind) und auf CPU B macht jemand danach nen Map (mit Ints aus und der gleichen virtuellen Adresse).
Jetzt steht in den PageTables schon ein korrekter neuer Wert drin, aber da nicht alle CPUs aktuelle TLBs hat, kann es passieren das einer auf ne alte Page zugreift.

Die Ints kann ich deswegen nicht mal eben wieder anmachen, weil es bei mir Code gibt, der auf der selben CPU beendet werden muss, auf der er auch begonnen wurde und dann kann man nicht mal eben die Ints anmachen.
588
Lowlevel-Coding / Re:Shared Memory
« am: 18. October 2010, 16:13 »
Zitat von: erik
Irgendetwas scheinst Du anders zu machen.
Ja definitiv  :-D

Zitat von: erik
Eine andere Lösung wäre die Verwaltungsstrukturen im voraus zu allozieren (schließlich weiß man ja das man welche benötigt) bevor der Heap in einen unsicheren Zustand gebracht wird und dann könnten sich die verschiedenen Allocatoren gegenseitig beliebig verschachtelt aufrufen.
Das war meine erste Lösung die leider die Anzahl der CPUs nicht in betracht gezogen hatte und daher ab einer bestimmten Anzahl auch nicht mehr funktioniert hat.

Ich versuche schon die ganze Zeit meine jetzige Lösung so zu gestalten, das ich den Lock irgendwie ändern könnte.
Allerdings bin ich so langsam an einem Punkt angekommen wo ich nicht mehr glaube dass das möglich ist :( Habe nämlich gerade festgestellt, das mein SlabAllocator Memory leakt und um das Leak zu schließen, müsste ich die Ints ausmachen und meine vmmAlloc() aufrufen welche ja die vmmMap() aufruft und das auch irgendwann zu einem Problem wird :(
589
Lowlevel-Coding / Re:SMP und die damit verbundenen Probleme
« am: 18. October 2010, 15:57 »
Zitat von: erik
In der eigentlichen IPI-Sende-Funktion, welche für jede Ziel-CPU einzeln aufgerufen wird und internen einen Lock benutzt, muss natürlich die aktuelle CPU als Ziel ausgefiltert werden (die gewünschte Aktion muss dann direkt ausgeführt werden).
Sorry, wenn ich das mal so sage, aber das ist sehr unvorteilhaft ;)

Wie lange soll das dauern, wenn du die Sende-Funktion für jede CPU einzeln aufrufst (max. 255 mal)? Dann kommt noch hinzu das der Vorteil, der gleichzeitigen Bearbeitung auch flöten geht.
Viel einfacher ist es, wenn ich eine Nachricht schicke und die geht entweder an alle oder an alle außer der sendenden.

Das die aktuelle CPU den Code direkt ausführen soll, ist auch eher unvorteilhaft (zwecks extra Behandlung).

Zitat von: erik
Also ich sehe nicht wo mein Vorschlag bedingt das die INTs vorher an sind.
Das Senden ist durch einen Lock geschützt und als sendende CPU (A) wartest du (und behälst damit den Lock) bis alle CPUs die Nachricht bearbeitet haben und genau das ist der springende Punkt. Jemand kommt mit Ints aus bei der IPI-Sende-Funktion an und möchte den Lock (CPU B).
Den wird er nur nie bekommen, denn es hat gerade eine CPU (A) den Lock und die wartet auf genau die CPU (B) die gerade versucht den Lock zu bekommen und mit Ints aus da rein ist. Da sie (CPU B) schon die Ints aus hatte als sie rein kam, wird sie die Nachricht nicht (bzw. sogar nie) bekommen.

Eine andere Idee die ich noch hatte, ist es das man mehrere Msgs senden kann. Das sollte dann so aussehen, das die Msgs in einer Queue sind und jede CPU die Msgs der Queue durchgeht und guckt ob sie sie bearbeiten muss. Hat die CPU die Msg bearbeitet setzt es das Bit in einer Bitmap und erhöht nen Counter, ist der Counter gleich der Anzahl der CPUs wird die Nachricht "gelöscht".
So kann ich einfach mehrere Msgs senden und muss auch nicht mehr darauf warten das eine Nachricht bearbeitet wurde.

Alles gut und schön, aber da habe ich dann immernoch eine "Bedingung", nämlich das wenn man vmmMap() aufgerufen hat, man die Page(s) die man gemappt hat erst benutzen darf, wenn man die Ints an hatte. Denn ansonsten nutzt du die Page und hast den TLB noch gar nicht aktualisiert (was ich natürlich mache in meinen Problemfunktionen :( ).

Allerdings sollte das Problem des nicht aktualisierten TLBs eigentlich gar keins sein. Denn was kann schon passieren? Wurde die Page neu gemappt, ist (eigentlich) eh kein Eintrag vorhanden und es muss in die PageTables geschaut werden.
Blöd wird es erst wenn da vorher ne andere Page stand und ein vmmUnmap() mit einem vmmMap() (auf einer anderen CPU) mit der selben virtuellen Adresse kollidiert (was eigentlich nicht passieren darf).

Jetzt weißt du hoffentlich warum man einen unterbrechbaren Kernel haben sollte!?
590
Lowlevel-Coding / Re:SMP und die damit verbundenen Probleme
« am: 18. October 2010, 12:25 »
Zitat von: erik
ich würde sagen Du sollst nicht jede Page einzeln mappen und immer sofort alle TLBs invalidieren sondern erst alle Pages mappen und erst am Schluss alle TLBs invalidieren. Zu häufiges TLB invalidieren kosten nur unnötig Performance (das solltest Du nicht unterschätzen). Das einzigste was Du sicherstellen musst ist das bevor die Pages das erste mal benutzt werden es keine Altlasten in den TLBs gibt. Von welcher CPU das Invalidieren der TLBs dann ausgeht ist doch völlig egal solange Du keine CPU vergisst.
So schlimm ist es bei mir auch nicht.

Also:
vmmMap(void *virt, void *phys, uint32t count, struct addrSpace_t *addrSpace) {
spinAcquire(&addrSpace->lock);

for(uint32t x= 0; x < count; x++, virt+= PG_SIZE, phys+= PG_SIZE) {
 //hier packt er jetzt die phys in die PageTables
 invalidTLB(virt);
}

smpSendBroadcastMsg(SMP_CODE_INVALIDPG,virt,count,getPD());

spinRelease(&addrSpace->lock);
}
Das wäre mal ne sehr stark vereinfachte Variante der vmmMap().

Dein Vorschlag heißt also das ich das invalidieren nicht in der Schleife mache, sondern das ich ne Nachricht sende und die geht an alle einschließlich der CPU die die Nachricht gesendet hat.
Wäre ne Möglichkeit. Schwierigkeit sehe ich halt dann darin, das ich auch das Senden der Nachricht in einen Lock packe und da ja wieder keine Ints an sind und somit die sendende CPU wieder die Nachricht nicht bekommen würde.
Ich muss das Senden mit nem Lock schützen, da ich immer nur eine Nachricht zur selben Zeit senden und bearbeiten lassen kann.

Edit::

Was mir noch einfällt. Deine Lösung das ich den Lock freigeben und erst später an alle CPUs die Nachricht sende, kann auch deswegen nicht funktionieren, weil es wieder einen Deadlock (obwohl ich inzwischen glaube, dass das das falsche Wort dafür ist) gibt.
Denn Problem an deinem Vorschlag und meinem momentanen Code ist, dass beide davon ausgehen (müssen) das die Ints vorher an waren und genau das ist das Problem.

Edit::

Zitat von: erik
Auf meiner Plattform trifft dieses TLB-Problem grundsätzlich nicht auf, bei mir soll es möglich sein das eine CPU über ein spezielles Controll-Register (sowas wie die MSR bei x86) einen globalen TLB-Flush für eine bestimmte Page auslösen kann.
Wenn ich dich hier richtig verstehe dann willst du nen TLB-Flush mit der physikalischen und nicht der virtuellen Adresse machen?
Das würde so bei mir gar nicht funktionieren, weil es durchaus sein kann, das ein und die selbe physikalische Page an mehreren virtuellen Adressen gemappt ist.
591
Lowlevel-Coding / Re:Shared Memory
« am: 18. October 2010, 12:11 »
Zitat von: erik
Dann ist Dein Design fehlerhaft!
Naja, so schlimm ist es auch nicht. Nur habe ich bei meinem Design halt viele Henne-Ei-Probleme und die zu lösen ist nicht immer schön.

Mein Lieblingsbeispiel ist das Allokieren von Speicher. Während des Vorgangs passiert es das der SlabAllocator aufgerufen wird damit du Speicher für eine Verwaltungsstruktur bekommst. Dieser wiederrum könnte den Allocator aufrufen, weil er mehr Speicher benötigt.

Dass das so nicht funktionieren kann ist klar, aber solche ähnlichen Probleme müssten eigentlich bei anderen auch auftreten, wenn man denn nicht alles statisch macht.

Das "lustige" an dem Bsp. ist, das ich also nicht mehr den SlabAllocator aufrufe, sondern nen speziellen Allocator, der nur Speicher aus nem vorher festgelegten Bereich holt (ansonsten funktioniert er genauso wie ein SlabAllocator) und genau dieser Allocator macht mir jetzt gerade die Probleme mit meiner vmmMap() ;)
592
Lowlevel-Coding / Re:SMP und die damit verbundenen Probleme
« am: 18. October 2010, 12:05 »
Zitat von: erik
wenn Dein Problem so ist dann empfehle ich Dir das man bei verschachtelten Locks immer  in der selben Reihenfolge locken muss. Klingt vielleicht doof und lässt sich wohl nicht so ganz mit Deiner Zielvorstellung in Einklang bringen aber schlussendlich wirst du da kaum drumherum kommen.
Das ist klar und wird auch so gemacht, aber (um bei meinem Bsp. zu bleiben) die vmmMap() wird ja nicht nur von einer anderen Funktion aus aufgerufen und d.h. dann auch das da noch andere Locks mit im Spiel sind.

Zitat von: erik
Wenn die CPU A mit ihren Modifikationen am Page-Directory fertig ist und anschließend alle anderen CPUs nur noch darüber informieren möchte, ist da der Lock wirklich noch erforderlich? Wäre es nicht möglich den Lock freizugeben nachdem alle Änderungen erledigt sind aber bevor die anderen CPUs informiert werden? Ich weiß ja nicht genau wie Deine Speicherverwaltung arbeitet aber ich sehe da eigentlich kein Erfordernis den Lock zu behalten.
Praktisch ist der Lock erforderlich.

Stell dir einfach vor du möchtest mehr als eine Page mit einem Aufruf von vmmMap() mappen und jetzt stell dir mal vor die Funktion wird nach jeder Page unterbrochen und läuft dann jedesmal auf ner anderen CPU. Unschön, aber noch zu handeln. Denn jetzt könntest du sagen, ok machen wir einfach so, beim TLB-Shutdown wird einfach jede CPU (auch die die die IPI versendet) angeschrieben und invalidet den TLB. Die Variante ist aus Performance sicht natürlich absolute scheiße (zumal ich bei meiner Variante noch ein wenig optimieren kann).

Das Problem ist, halt, dass das Versenden der IPI Nachricht auf der selben CPU (A) stattfinden muss, weil es sonst passiert das dieser Teil auf ner anderen CPU B stattfindet und die ihren TLB also nicht aktualisiert, aber die andere CPU A invalidet ihren TLB nochmal.

Lange Rede kurzer Sinn, ich behalte den Lock, damit ich davon ausgehen kann dass das Senden der IPI Nachricht auf der selben CPU stattfindet wie das mappen. Den Lock zu behalten hat den Sinn, die Ints auszulassen.
593
Lowlevel-Coding / Re:SMP und die damit verbundenen Probleme
« am: 18. October 2010, 10:24 »
Zitat von: erik
Wenn ich Dein Problem falsch verstanden habe dann erkläre es bitte noch mal etwas deutlicher (und benutze A und B für die CPUs damit man nicht durcheinander kommt).
Ich würde nicht sagen das du es falsch verstanden hast, sondern nicht komplett.

Dein Vorschlag hatte ich schon vor Ewigkeiten (wegen solcher Probleme) umgesetzt.

Man hat ne vmmMap()-Funktion und um sich die Arbeit zu erleichtern darf immer nur einer gleichzeitig in den PageTables eines Prozesses (und der KernelSpace ist für ich in dem Fall ein extra Prozess) rumwerkeln. Also sichere ich den Code durch einen Lock und wenn man das Lock hat dann sind die Ints aus. Soweit kein Problem. Mein Problem ist nun das ich eigentlich sagen muss, dass diese vmmMap() nur mit eingeschalteten Ints aufgerufen werden darf, aber genau das bekomme ich ohne viele neue Probleme an anderen Stellen nicht hin.

Dadurch kann es jetzt halt passieren, das jemand auf CPU A im KernelSpace was gemappt hat und nen TLB-Shutdown macht, aber auf CPU B ist jemand in einem kritischen Bereich und hat seine Ints aus und ruft jetzt dummerweise vmmMap() auf und will eine Page im KernelSpace mappen. Den Lock kann er natürlich nicht bekommen, weil CPU A den hat und ihn erst freigibt, wenn der TLB-Shutdown abgeschlossen. Dies wiederrum kann nicht geschehen, weil CPU B die Ints nicht an hat und so nie die IPI-Nachricht bearbeitet.

Um es einfacher zu machen, was wird wohl einfacher sein, mir alle Funktionen angucken die die Ints aus haben und vmmMap() angucken oder versuchen vmmMap() und den TLB-Shutdown anders zu gestalten?

Meine Vermutung ist, das ich mir alle Funktionen angucken muss die die vmmMap mit ausgeschalteten Ints aufrufen und zusehen muss das ich das nicht mehr mache.

Ich werde nachher mal eins der Probleme posten, die anderen sehen ähnlich aus.
594
Lowlevel-Coding / Re:Shared Memory
« am: 18. October 2010, 10:14 »
Zitat von: svenska
Naja, den Fakt, dass eine Page "shared" ist, kannst du im Swapping komplett ignorieren.

Du speicherst halt pro Page irgendwelche Informationen zur Nutzung, um deinen welche-page-auslagern-Algorithmus betreiben zu können und ignorierst den Zustand des Sharings komplett. Wird eine solche, von mehreren Programmen genutzte, Page ausgelagert, bricht natürlich die Systemperformance ein - unter der Voraussetzung, dass du aber genug RAM hast, spielt das keine Rolle.
Naja, ignorieren würde ich das nicht unbedingt. Ich würde sogar sagen, das wenn eine Page bei mehr als 2 Prozessen gemappt ist, dann lohnt sich das Auslagern schon gar nicht mehr.

Bei mir ist es halt so das du von einem Prozess nicht in den anderen reingucken kannst (auch nicht vom Kernel aus und erst recht nicht auf die PageTables) und von daher kannst du ja nicht wissen ob die Page die du gerade in dem Prozess ausgewählt hast, in dem anderen Prozess auch nicht benötigt wird. Da müsstest du also erst mal das PD von dem anderen Prozess mappen, dann die PageTable um dann nachzusehen ob die Page eventuell ausgelagert werden kann.
Das ganze temporäre mappen in den KernelSpace dauert wahrscheinlich auch ein wenig und ich denke mal da lohnt es sich dann nicht mehr die Page noch auszulagern. Bei mehr als zwei Prozessen wird das noch aufwendiger und wenn man dann noch SMP dazunimmt kann man sich solche SharedPages wahrscheinlich ganz sparen.

Zitat von: svenska
Den Rest deines Problems kann ich nicht so recht nachvollziehen, wahrscheinlich auch, da ich weder das Zusammenspiel deiner Verwaltung zueinander noch das Paging im x86-speziellen kenne, daher kann ich dazu nichts sagen. Ich bezog mich also nur auf identische, in mehreren Prozessen gemappte, Pages.
Naja, die Deadlock lässt sich leider aufgrund meines Designs nicht vermeiden und das eigentliche Problem habe ich inzwischen auch gefunden (habe ja nen neuen Thread aufgemacht).
595
Lowlevel-Coding / SMP und die damit verbundenen Probleme
« am: 17. October 2010, 20:16 »
Ich mache diesmal ein seht weitreichendes Thema auf, da ich genau deswegen gerade Probleme habe, meinen Kernel wieder (vorher ist das Problem einfach nur noch nicht aufgetreten) zum Laufen zu bekommen.

Im speziellen geht es darum, wie man einen sogenannten TLB-Shutdown macht. Also der TLB auf allen CPUs synchronisiert werden muss.

Ich habe das bei mir so gelöst, das man Nachrichten an andere CPUs verschicken kann (per IPI) und man selbst dann wartet bis alle anderen CPUs die Nachricht abgearbeitet haben.

Mein Problem ist nun, das eine CPU die Ints aus hat, weil sie sich in einem kritischen Bereich befindet und versucht einen Lock zu bekommen. Diesen Lock hat nun aber die CPU die gerade eine Nachricht an alle anderen CPUs schickt. Der Deadlock entsteht dadurch das die eine CPU darauf wartet einen Lock zu bekommen und die Ints aus sind und die andere wartet darauf das die gesendete Nachricht bearbeitet wird und auch bei ihr sind die Ints aus.

Wenn ihr jetzt meint "dann mach doch einfach die Ints an", das ist leider nicht so einfach. Dieses spezielle Lock schützt die PagingTables eines Prozesses vor dem gleichzeitigen Zugriff (und außerdem ist es einfacher wenn ich davon ausgehen kann dass das Ändern alles auf ein und der selben CPU passiert) und ich muss auch von genau dieser CPU aus die IPI versenden.

Eine andere (vermeintliche) Lösung wäre einfach das Lock freizugeben, die Ints auszulassen und die andere CPU bekommt den Lock.
Dann habe ich trotzdem nen Deadlock, weil dann beide (immernoch) die Ints aus haben und beide jetzt versuchen ne Msg zu senden.

Einzige Lösung, die mir eingefallen ist, wäre das diese spezielle Funktion nur mit angeschalteten Ints aufgerufen werden darf, aber das ist leider nicht wirklich möglich.

Hat wer schon seinen Kernel so weit und SMP Unterstützung und hat das Problem gelöst?

@erik

Wie willst du solch ein Problem lösen? Denn dein Kernel ist ja grundsätzlich nicht unterbrechbar.
596
Lowlevel-Coding / Re:Shared Memory
« am: 15. October 2010, 22:02 »
Das mit dem refCount für jede Page ist zwar ganz nett, aber zeigt leider, wieder einmal, große Design Probleme meines VMMs.

Ich überlege im Moment ob ich wirklich wissen muss in welchen Prozessen eine Page gemappt ist oder ob es nicht einfach reicht nen refCount zu haben?!

Problem ist mal wieder eine Henne-Ei-Geschichte. Jedes Mal wenn eine Page gemappt wird, wird halt eine Funktion aufgerufen, die den refCount erhöht und den laufenden Prozess in die Liste der Prozesse, die die Page gemappt haben, reinpackt. Soweit so gut, aber um den Prozess in die Liste zu packen oder um eine neue Page in meine Tabelle zu packen muss Speicher allokiert werden. Jetzt kann natürlich das Problem auftreten dass das in einer endlos Kette endet. Denn jedes mal wenn Speicher gebraucht wird, kann es ja sein, das eine neue Page gemappt werden muss damit ich neuen Speicher bekomme, aber wenn jetzt die neue Page gemappt werden soll, brauche ich ja wieder Speicher und da wird wieder festgestellt das ne neue Page benötigt wird und die muss wieder gemappt werden ... ne klassische Endlosschleife halt.

Mir ist leider noch kein Weg eingefallen (außer halt keine Liste mit Prozessen, sondern nur nen RefCount zu haben) das Problem zu lösen (bisher tritt es nur auf mehreren CPUs auf, nicht aber auf einer).

Habt ihr auch solche Henne-Ei-Probleme in eurem VMM und wenn ja, wie habt ihr sie gelöst?
597
Lowlevel-Coding / Re:Shared Memory
« am: 14. October 2010, 21:41 »
Zitat von: svenska
Meine Vermutung ist, dass die Zahl der mehrfach gemappten Pages verschwindend klein ist gegenüber der Menge an Pages, die jedes Programm für sich hat.
Unter der Annahme das der Speicher den ein Programm erst zur Laufzeit allokiert größer ist als das Image der Executeable.
Denn bei mir ist jedes Executeable (wenn die physikalischen Sektionen 4KB aligned sind) gemappt (so ist es effizienter wenn man das gleiche Executeable mehrmals ausführt).

Zitat von: svenska
Oder du ignorierst den Fakt komplett und lagerst einfach "Pages" aus und speicherst pro Page, ob sie alt/ungenutzt ist oder nicht. Wobei ich nicht weiß, wie sich das in deinem Mikrokernel implementieren ließe.
Das verstehe ich jetzt nicht. Denn du kannst den Fakt das eine Page gemappt ist, nicht einfach ignorieren. Ich meine stell dir mal vor, du lagerst eine solche Page aus und dort kommen jetzt andere Daten rein, dann sind diese Daten jetzt in allen Prozessen die diese Page auch gemappt hatten und wenn das dann noch Code war, wird es interessant ;)

Zum Thema wie man Paging in einem MikroKernel macht (der vorallem den VFS-Service nicht im Kernel hat) sollte es fast genauso funktionieren wie bei allen anderen auch (sag ich mal einfach so, da ich noch keine Ahnung davon habe ;) ). Nur das du halt den Inhalt der Pages erst an den VFS-Service schickst und dieser den dann in die Swap-Datei schreibt.
598
Lowlevel-Coding / Re:Shared Memory
« am: 14. October 2010, 20:51 »
Zitat von: erik
So hätte ich das nicht gemacht. Ich würde die Seite in allen Prozessen als COW markieren. Dann tritt dein Problem nicht auf. Keine Sonderbehandlung für den ersten Prozess.
Hast recht, ich hatte mir sorgen gemacht, wenn ich das im ersten Prozess auch mache, dass ich dann wieder das Problem habe, das ich eine Page leake, aber das ist ja nicht der Fall, weil ja alle anderen Prozesse die ursprüngliche Page haben und die darf ja nicht verändert werden.

Jetzt bin ich gerade dabei meine Henne-Ei-Problem zu lösen, das ich ohne einen funktionierenden VMM keine Pages mappen kann, weil dann auch immer die Struktur allokiert werden muss, für den refCount und den Prozess in welche die Page gemappt ist.

Eine Frage hätte ich noch. Ich will die Prozesse in denen eine Page gemappt ist speicher, um später auch eine Page die in mehreren Prozessen gemappt ist, auslagern zu können. Macht man sowas überhaupt, weil ich es mir auch schwer vorstelle überhaupt rauszubekommen, das die Page eigentlich in allen Prozessen lange nicht genutzt wurde?
599
Lowlevel-Coding / Re:Shared Memory
« am: 14. October 2010, 20:18 »
Ich habe mal wieder ein wenig an meinem VMM gearbeitet und SharedMemory macht mir noch immer sorgen :(

Ich bin jetzt soweit das ich für jede physikalische Page die gemappt ist einen refCount führe und in welchen Prozess sie gemappt ist (kann sogar mehrmals der selbe sein).

Ich überlege halt gerade ob es überhaupt Sinn macht zu wissen ob eine Page als SharedRead oder SharedWrite gemappt ist? Denn die einzige Info die ich mal irgendwann bräuchte wäre ob eine Page COW ist, damit ich dann entsprechend reagieren kann.
Ich wüsste halt nicht wozu ich wissen müsste das eine Page irgendwie geshared wird (also mehrmals gemappt ist) wenn ich eh nen refCount habe. Oder fällt euch ein Grund ein? (Es geht darum, das ich nen Flag mit in den PTE packe, ob eine Page SharedRead oder -Write ist)

Noch eine Frage zu COW. Ansich ist das ja ne klare Sache, man markiert eine Page in allen Prozessen, bis auf dem ersten Prozess, als COW und wenn dann geschrieben werden soll, dann wird ne neue Page allokiert und der Inhalt wird kopiert. Soweit so klar. Was ist aber wenn der erste Prozess beendet wurde und die Page nur noch in einem anderen Prozess gemappt ist, das Flag für COW steht da ja weiterhin drin, dann würde die Page kopiert werden obwohl das gar nicht nötig ist!?

Meine Lösung wäre halt, dass jedes Mal bevor eine neue Page allokiert und kopiert wird, nachgeguckt wird ob dies auch wirklich noch nötig ist.

Wie habt ihr das gelöst?
600
Lowlevel-Coding / Re:Neuen Prozess laden/starten (Mikrokernel)
« am: 10. October 2010, 21:55 »
Zitat von: svenska
POSIX ist ein Standard, der (u.a.) ein Interface beschreibt. Implementierst du dieses Interface in deiner libc, dann stellt deine libc eine POSIX-Implementation bereit. Andernfalls stellt deine libc eine native API (oder sogar ABI) bereit, und deine POSIX-Implementation liegt in einer libposix, die als Wrapper eingesetzt wird. Dann musst du zwei APIs pflegen.
Für mich ist beides ein Standard der bestimmte Sachen vorgibt (z.B. für C printf() und für POSIX ein fork()).

Zitat von: svenska
Bei Sachen wie CGI/FastCGI mit Gefolge wie AJAX stelle ich mir das schon etwas schwierig vor, wenn die Kinder voneinander  abhängen. Sie haben nämlich prinzipiell die gleichen Eltern, aber kennen sich nicht. In dem Fall kann ich es mir schon vorstellen, dass ein Kindprozess sagt "ich will nicht mehr", das Socket schließt und an den Elternprozess "zurückgibt". Letzterer kann das Socket ja auch solange offenlassen, bis das betreffende Kind gestorben ist...
Also entweder nutzt der Elternprozess die "Datei" nicht während das Kind läuft oder es schließt sie sobald geforkt wurde. Wie soll das "zurückgeben" funktionieren?

Ich hatte die verrückte Idee (nur mal als Grobkonzept) fork() als threadCreate() und exec() als processCreate() umzusetzen.

Bei exec() sehe ich die wenigsten Probleme, da ich einfach bei meiner processCreate() eine Möglichkeit vorsehen kann, das man Dateidiskriptoren an den neuen Process weitergibt und dann wird einfach der laufende Thread beendet.

Bei fork() ist es etwas schwieriger. Erstmal müsste man für alle Dateidiskriptoren einen RefCount haben (wenn der ElternThread die Datei schließt, das der KindThread noch damit arbeiten kann) und ansonsten müsste die Implementation der C-Library ThreadSafe sein.

Welche Probleme würden euch sonst noch einfallen (was fork() als neuen Thread betrifft)?
Seiten: 1 ... 28 29 [30] 31 32 ... 43

Einloggen