Lowlevel

Lowlevel => OS-Design => Thema gestartet von: FlashBurn am 09. October 2011, 23:35

Titel: Nicht unterbrechbarer Kernel
Beitrag von: FlashBurn am 09. October 2011, 23:35
Jetzt habe ich mich gerade damit angefreundet (und angefangen entsprechenden Code zu schreiben) das ich einen nicht unterbrechbaren MikroKernel schreibe und schon fallen mir die ersten Probleme auf (Designphase mal wieder übersprungen -> erik ;)).

Also erstmal sollte man sich darüber im Klaren sein, das es auf x86 keinen 100%ig nicht unterbrechbaren Kernel gibt. Zumindest nicht wenn man nicht auf "hlt" oder andere Stromsparmechanismen verzichten möchte.

Ein anderes Problem ist mir erst jetzt bewusst geworden. Die Zeit die im Kernel verbracht wird, kann schonmal verdammt lange werden, nämlich dann wenn der User Speicher haben möchte.
Stellen wir uns einfach vor, wir sind auf einem Single-Core System (funktioniert auch auf nem Dual-Core System, wo alle CPUs gleichzeitig in den Kernel gehen und Speicher wollen, desto mehr CPUs desto unwahrscheinlicher wird es) und der User will z.B. 1GB Speicher haben.
Das Nachgucken und Besorgen eines Bereiches vom UserSpace der groß genug ist, sollte relativ schnell gehen (kann also vernachlässigt werden), aber das Besorgen der nötigen Pages ist ein Teil des Problems. Wir reden also von 1048576 4kb Pages und weil es mir um den worst-case geht, kann ich auch keine 4mb Pages nehmen. Da für jede Page der PMM aufgerufen werden muss und dieser mit einem Lock geschützt ist, rechnen wir mal so über den Daum gepeilt mit 20 Instruktionen (das ist schon wenig) pro Page, macht schonmal 20971520 Instruktionen und ich bin großzügig und rechne mal mit nur 2 Takten pro Instruktion, macht 41943040 Takte.

Jetzt gehe ich mal von 100MHz aus, ein Takt entspricht also 10ns und für obige Takte entspricht das dann 419430400ns was 419,4304ms macht und das nur um die Pages zu holen, da sind die noch nicht mal gemappt. Auch bei 1000MHz wird es nicht besser mit 41,94304ms, die dafür gebraucht werden.

Wie soll man sowas also lösen?

Ja man könnte für sowas (bzw. ist es der einzige Fall der mir einfällt, der so lange dauern könnte und natürlich der entgegengesetzte Fall, das Freigeben) Punkte einrichten, wo der Kernel dann unterbrechbar ist, aber wo würde man diese Punkte hinpacken? Weil ich will den Kernel dann z.B. nicht bei 4 Pages unterbrechen.

Ein weiteres Problem (was relativ einfach zu lösen ist) ist, dass ein Thread ja seine Zeitscheibe abgeben kann und dazu geht er per Syscall in den Kernel. Dort wird dann der Scheduler aufgerufen und der wählt einen neuen Thread aus. Problem ist hier nun, das der Scheduler immer aus dem Kernel springt, als wenn es ein IRQ wäre, aber in diesem Fall darf kein EOI gesendet werden. Das lässt sich lösen, dass man einfach jedes Mal wenn man in den Kernel springt, ein Flag setzt ob der Grund ein IRQ war oder nicht, aber das müsste man auch noch für jeden Thread speichern (wie er in den Kernel gekommen ist). Denn wenn der Thread per Syscall reingekommen ist, will man natürlich auch wieder auf dem Weg heraus (Sysret oder Sysexit).

Kleine Idee am Rande, ist es möglich, wenn ich weiß das der Thread zurück in den UserSpace geht, dass ich jedes Mal mit Sysret/Sysexit aus dem Kernel gehe (ich kann ja vorher nen EOI senden und das Page Directory wechseln, sowie andere nötige Sachen machen)? Damit könnte ich sogar ISRs ein wenig beschleunigen. Denn die sollten schneller sein als ein iret.

Auch müssen jedes Mal die Register, die beim Eintritt in den Kernel auf dem per CPU Kernel-Stack gespeichert werden, in der Thread-Struktur gespeichert werden, was auch nochmal ein paar Takte kostet.

Ein anderes Problem, welches aber auch für einen unterbrechbaren Kernel zutrifft, ist halt das Abgeben der Zeitscheibe. Denn dazu wird in den Kernel gesprungen und der Scheduler wird aufgerufen, dort (im Scheduler) müssen die Ints aus sein und genau in der Zeit kann es passieren das der Timer-IRQ feuert und dann gequeuet wird. Es wird ein neuer Thread ausgesucht und der Scheduler springt zurück in den UserSpace und was wird als erstes gemacht? Es wird wieder in den KernelSpace gesprungen, weil ja der IRQ abgearbeitet werden muss.

Kann man dagegen irgendetwas machen oder muss man damit leben? Auch das Abschalten oder maskieren hilft ja nicht, weil ja Zeit bis dahin vergeht wo ja ein IRQ auftreten kann.
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: Svenska am 09. October 2011, 23:47
Ich sehe da kein Problem. Optimiere für den Average Case, wenn du keine harten Echtzeitbedingungen einhalten musst und mache den Worst Case entweder selten oder unattraktiv.

Mir fällt kein sinnvoller Einsatzzweck für deinen geschilderten Fall ein.
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: erik.vikinger am 10. October 2011, 00:30
Hallo,


Designphase mal wieder übersprungen
Du kennst Deine Fehler ganz genau und machst diese trotzdem. Mal so unter uns zwei, ist das Deiner Meinung nach intelligentes verhalten? SCNR :evil:

Also erstmal sollte man sich darüber im Klaren sein, das es auf x86 keinen 100%ig nicht unterbrechbaren Kernel gibt. Zumindest nicht wenn man nicht auf "hlt" oder andere Stromsparmechanismen verzichten möchte.
Dann leg doch das HLT in den User-Mode, ach Mist, geht ja auf x86 nicht, sorry für die blöde Idee.

Wir reden also von 1048576 4kb Pages
Das sind aber schon 4 GB Speicher und nicht bloß 1 GB! :?

ich bin großzügig und rechne mal mit nur 2 Takten pro Instruktion
Das ist nicht großzügig sondern naiv, vor allem weil ja einige Speicherzugriffe dabei sind.

Wie soll man sowas also lösen?
Ich war jetzt echt versucht da Segmente vorzuschlagen aber ich weiß ja dass das hier keiner hören will.

Punkte einrichten, wo der Kernel dann unterbrechbar ist
Dann kannst du auch gleich direkt den Scheduler aufrufen. Prinzipiell eine interessante Idee aber wenn man eine zeitaufwendige Aktion ausführt dann dauert die eben etwas, dort auch noch ständig zu unterbrechen kostet unterm Strich nur noch mehr Zeit (Cache-Trashing usw.), ich persönlich halte davon nix.

Ein weiteres Problem (was relativ einfach zu lösen ist) ist, dass ein Thread ja seine Zeitscheibe abgeben kann und dazu geht er per Syscall in den Kernel....
Warum geht der Thread zum Abgeben der Zeitscheibe per Syscall in den Kernel? Der kann doch auch INT 0x?? benutzen (0x?? durch den IRQ-Vector des Timer-IRQs ersetzen). In meinem System ist es auch nicht vorgesehen das zum aktiven Abgeben der Zeitscheibe der normale Syscall benutzt wird, ich habe extra einen Befehl vorgesehen der das selbe macht wie der abgelaufene Zeitscheiben-Counter. Außerdem willst Du doch bei Multi-Core bestimmt den Local-APIC-Timer für die Zeitscheiben benutzen.

dort (im Scheduler) müssen die Ints aus sein und genau in der Zeit kann es passieren das der Timer-IRQ feuert und dann gequeuet wird. Es wird ein neuer Thread ausgesucht und der Scheduler springt zurück in den UserSpace und was wird als erstes gemacht? Es wird wieder in den KernelSpace gesprungen, weil ja der IRQ abgearbeitet werden muss.
Und dieser Zeitscheibe-Abgelaufen-IRQ (falls es den einer ist) schmeißt den frischen Thread auch gleich wieder von der CPU runter. So ein Pech aber auch. Ich fürchte damit wirst Du leben müssen oder Du baust etwas ein das der Scheduler am Ende prüft ob der Zeitscheiben-Timer gerade einen IRQ auslösen möchte und quittiert das einfach so das wenn dann die CPU die INTs wieder enabled eben kein Timer-IRQ mehr ansteht. Bei Level-Triggered-IRQs gibt es ja nichts persistentes im IRQ-Controller, bei Edge-Triggered-IRQs hast Du da schon eher ein Problem. Aber wenn Du für die Zeitscheiben den Local-APIC-Timer benutzt musst Du den am Ende des Schedulers eh frisch aufziehen und damit hat sich doch hoffentlich auch dessen IRQ erledigt.


Grüße
Erik
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: FlashBurn am 10. October 2011, 10:43
Zitat von: svenska
Mir fällt kein sinnvoller Einsatzzweck für deinen geschilderten Fall ein.
Naja, wie erik schon richtig erkannt hatte, habe ich mich bei der Anzahl der Pages schonmal vermacht, aber das ein Programm, meinetwegen 64MB Speicher haben will und dann der PC für die gesamt Zeitspanne blockiert ist (da ja auch keine IRQs mehr angenommen werden) und das vielleicht noch von einem Task mit niedriger Priorität, kann doch schonmal vorkommen.
Und selbst bei 64MB reden wir hier von mehreren ms (schon bei meiner naiven Rechnung) und ich denke das macht sich sehr wohl für den User bemerkbar.

Zitat von: erik
Du kennst Deine Fehler ganz genau und machst diese trotzdem. Mal so unter uns zwei, ist das Deiner Meinung nach intelligentes verhalten?
Nennen wir es faules Verhalten ;)

Ich bin halt spontan und merke dann später erst was ich mir da aufgehalst habe.

Zitat von: erik
Das sind aber schon 4 GB Speicher und nicht bloß 1 GB!
Wenigstens einer der aufpasst ;) Jap, aber auch mit 1GB wird es nicht schöner.

Zitat von: erik
Das ist nicht großzügig sondern naiv, vor allem weil ja einige Speicherzugriffe dabei sind.
Ich weiß, ich wollte auch nur zeigen, dass man sich das nicht mal schön rechnen kann.

Zitat von: erik
Dann kannst du auch gleich direkt den Scheduler aufrufen. Prinzipiell eine interessante Idee aber wenn man eine zeitaufwendige Aktion ausführt dann dauert die eben etwas, dort auch noch ständig zu unterbrechen kostet unterm Strich nur noch mehr Zeit (Cache-Trashing usw.), ich persönlich halte davon nix.
Da ich gestern eh nicht richtig schlafen konnte, habe ich mir darüber nochmal ein paar Gedanken gemacht.

Meine Idee dafür ist, da ich eh Kernel-Threads haben will, brauche ich auch die Möglichkeit zw. Kernel-Threads und User-Threads zu unterscheiden (Kernel-Threads haben ihren eigenen Stack und User-Threads benutzen den per CPU Kernel-Stack) und beim Allozieren und Deallozieren lege ich ein Anzahl von Schleifendurchläufen fest (vllt 512) und wenn mehr als 512 4kb Pages benötigt werden, wird der Thread zu einem Kernel-Thread und bekommt seinen eigenen Stack. Es werden dann die 512 Schleifendurchläufe gemacht (wobei eine 4mb Page als nur ein Schleifendurchlauf zählt) und danach werden die Ints angemacht und es wird "pause" ausgeführt. Damit hat die CPU zeit, eventuell gequeuete IRQs abzuarbeiten.
Die Ints werden dann wieder ausgemacht und es werden bis zu weitere 512 durchläufe gemacht.

Das sollte Performancemäßig ein guter Kompromiss sein und ich sollte damit die meisten Speicheranforderungen ohne extra Kernel-Stack ausführen können.

Zitat von: erik
Warum geht der Thread zum Abgeben der Zeitscheibe per Syscall in den Kernel? Der kann doch auch INT 0x?? benutzen (0x?? durch den IRQ-Vector des Timer-IRQs ersetzen).
Hmm, den Fall habe ich noch gar nicht betrachtet, weil das auch nen potentieller Angriffspunkt ist. Denn ein Programm könnte dann ja munter einfach irgendwelche IRQs auslösen und das wäre ja sehr unschön.
Konnte man das nicht irgendwie begrenzen welche Ints aus dem UserSpace aufgerufen werden können?

Zumal direkt den IRQ des Timer´s aufzurufen auch unschön wäre, weil ich so nicht einfach feststellen kann, ob nun der Timer oder der User den IRQ ausgelöst haben (gut da ich eh immer den Timer-Counter auslöse kann ich das).

Zitat von: erik
Und dieser Zeitscheibe-Abgelaufen-IRQ (falls es den einer ist) schmeißt den frischen Thread auch gleich wieder von der CPU runter.
Nope, das fange ich ganz geschickt ab, entweder es ist wirklich mit einmal ein Thread verfügbar der ne höhere Priorität hat oder aber der Thread wird weiter ausgeführt da seine Zeitscheibe ja noch nicht aufgebraucht ist.

Zitat von: erik
oder Du baust etwas ein das der Scheduler am Ende prüft ob der Zeitscheiben-Timer gerade einen IRQ auslösen möchte und quittiert das einfach so das wenn dann die CPU die INTs wieder enabled eben kein Timer-IRQ mehr ansteht. Bei Level-Triggered-IRQs gibt es ja nichts persistentes im IRQ-Controller, bei Edge-Triggered-IRQs hast Du da schon eher ein Problem.
Ich wüsste nicht wie ich das so ohne weiteres feststellen sollte, ob der Timer noch nen IRQ ausgelöst hat (während ich den Counter lese und wieder neu schreibe) und ein fach per gut Glück nen EOI zu senden ist auch keine gute Idee, dann kann es ja passieren, das ich vllt den falschen IRQ "wegwerfe" (was so oder so ein Problem ist).

Was ist mit meiner Idee, dass ich mir immer merke wie ich in den Kernel gekommen bin (also ob es nen Syscall oder nen IRQ war) und dann bei nem IRQ nen EOI sende, aber immer mit der optimalen Methode aus dem Kernel gehe (also nicht iret, sondern Sysret/Sysexit)? Das sollte doch eigentlich keine Probleme geben?
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: Svenska am 10. October 2011, 14:31
[dass] aber das ein Programm, meinetwegen 64MB Speicher haben will und dann der PC für die gesamt Zeitspanne blockiert ist (da ja auch keine IRQs mehr angenommen werden) und das vielleicht noch von einem Task mit niedriger Priorität, kann doch schonmal vorkommen.
Willst du harte Echtzeitbedingungen erfüllen oder nicht? Und wenn ja, in welcher Größenordnung?

Und selbst bei 64MB reden wir hier von mehreren ms (schon bei meiner naiven Rechnung) und ich denke das macht sich sehr wohl für den User bemerkbar.
Darum macht man ja auch Copy on Write... dann verteilt sich das Problem von "ich will jetzt aber ganz viel RAM" in eine Reihe von Pagefaults.

In Summe ist das natürlich langsamer, aber auf Latenzen hin betrachtet besser. Das ist der Kompromiss, den du finden musst. Du kannst ja auch beides machen: COW für Allokationen größer 16 MB, direktes Bereitstellen sonst.

Gruß,
Svenska
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: FlashBurn am 10. October 2011, 15:37
Zitat von: svenska
Willst du harte Echtzeitbedingungen erfüllen oder nicht? Und wenn ja, in welcher Größenordnung?
Nein will ich nicht, aber es wäre mehr als nur unschön, wenn das System gerade hängt nur weil Speicher angefordert wird.

Zitat von: svenska
Darum macht man ja auch Copy on Write... dann verteilt sich das Problem von "ich will jetzt aber ganz viel RAM" in eine Reihe von Pagefaults.
Ich glaube das hatten wir schonmal und es lief darauf hinaus, dass das Programm es am besten wissen sollte und man es nicht im OS so festschreiben sollte bzw. halt normal COW und wenn das Programm besondere Wünsche hat, dann muss es das angeben.

Du kennst dich ja auch ein wenig mit Linux aus, wie war das eigentlich damals mit dem Big-Kernel-Lock, theoretisch würde man ja die Ints ausmachen, aber bei nem Monolithen geht das nicht, also konnte es passieren, dass ein Thread der den Lock hält alle andere die in den Kernel wollten blockiert oder? Dann sollte das doch am besten als Mutex implementiert gewesen sein?!
Denn dort könnte ja rein theoretisch das selbe Problem bestehen.
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: erik.vikinger am 10. October 2011, 17:42
Hallo,


aber das ein Programm, meinetwegen 64MB Speicher haben will und dann der PC für die gesamt Zeitspanne blockiert ist (da ja auch keine IRQs mehr angenommen werden) und das vielleicht noch von einem Task mit niedriger Priorität, kann doch schonmal vorkommen.
Und selbst bei 64MB reden wir hier von mehreren ms (schon bei meiner naiven Rechnung) und ich denke das macht sich sehr wohl für den User bemerkbar.
Um ehrlich zu sein denke ich das Du dieses Problem etwas überschätzt. Klar kann der PC mal für ein paar Millisekunden "einfrieren" wenn ein Task echt mal eine große Menge Speicher am Stück anfordert aber wie oft kommt das vor? Ich behaupte mal die überwiegend meisten Speicheranforderungen die der OS-Kernel für die Applikationen durchführen muss liegen im einstelligen MByte Bereich. Ein Programm das einen wirklich großen Puffer anfordert kann dabei oft auch mit MAP-Lazy leben.

Und noch ne andere Idee: was ist wenn Deine Kernel-API gar keine größeren Speicheranforderungen mit MAP-Now akzeptiert? Das kannst Du doch als Kernel-Programmierer durchaus so festlegen und Du als libc-Programmierer baust bei größeren Speicheranforderungen etwas ein das dann immer nur einen entsprechend großen virtuellen Speicherbereich mit MAP-Lazy alloziert und wenn der User-Code trotzdem MAP-Now will dann gibt es in der libc (also noch im User-Mode) eine kleine Schleife die diesen Speicher, nachdem er mit MAP-Lazy alloziert wurde, in passenden Stückchen vom Kernel auch mit echten Pages hinterlegen lässt. Auf diese Weise kannst Du den nichtunterbrechbaren Worst-Case recht zuverlässig auf ein vertretbares Maß beschränken, einzigster Nachteil ist das Du bei richtig großen Speicheranforderungen mehrere Syscalls brauchst aber das sollte eigentlich nur sehr selten sein. Ansonsten sehe ich das so wie Svenska das bei derartig riesigen Buffern durchaus auch MAP-Lazy angebracht ist wobei eine Automatik natürlich auch immer ihre Nachteile hat.

Meine Idee dafür ist, da ich eh Kernel-Threads haben will, brauche ich auch die Möglichkeit zw. Kernel-Threads und User-Threads zu unterscheiden (Kernel-Threads haben ihren eigenen Stack und User-Threads benutzen den per CPU Kernel-Stack) und beim Allozieren und Deallozieren lege ich ein Anzahl von Schleifendurchläufen fest (vllt 512) und wenn mehr als 512 4kb Pages benötigt werden, wird der Thread zu einem Kernel-Thread und bekommt seinen eigenen Stack. Es werden dann die 512 Schleifendurchläufe gemacht (wobei eine 4mb Page als nur ein Schleifendurchlauf zählt) und danach werden die Ints angemacht und es wird "pause" ausgeführt. Damit hat die CPU zeit, eventuell gequeuete IRQs abzuarbeiten.
Die Ints werden dann wieder ausgemacht und es werden bis zu weitere 512 durchläufe gemacht.
Ich hab echt den Eindruck das Du Dir immer die maximal umständlichsten Lösungen ausdenkst. Willst Du ernsthaft die Thread-Art zur Laufzeit ändern? Ich kann nur wiederholen das Simplizität ein essentiell wichtiges Design-Paradigma ist.

den Fall habe ich noch gar nicht betrachtet, weil das auch nen potentieller Angriffspunkt ist.
Welche INTs eine User-Mode-SW alles nutzen kann kann man in der IDT individuell festlegen, von daher sehe ich da kein Sicherheitsrisiko wenn man gezielt den INT-Vector freigibt auf den der Timer-IRQ gemappt ist (solange dieser IRQ nicht geshared ist). Und das feststellen ob das ein echter IRQ oder ein SW-INT war ist ganz einfach:if ( *((short*)(thread_state.saved_ip - 2)) == ((short)0x??CD) )

Grüße
Erik
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: FlashBurn am 10. October 2011, 18:07
Zitat von: erik
Um ehrlich zu sein denke ich das Du dieses Problem etwas überschätzt.
Kann gut sein, passiert mit oft.

Zitat von: erik
Klar kann der PC mal für ein paar Millisekunden "einfrieren" wenn ein Task echt mal eine große Menge Speicher am Stück anfordert aber wie oft kommt das vor?
Das hat auf nem halbwegs modernen System nicht einmal vorzukommen, egal was für ne Situation es gibt!

Zitat von: erik
Und noch ne andere Idee: was ist wenn Deine Kernel-API gar keine größeren Speicheranforderungen mit MAP-Now akzeptiert?
Ich kann jetzt nicht sagen, wie sehr die Performance einbrechen würde wenn bei z.B. einem 64mb Buffer, ab z.B. 4mb für jede Page eine Exception geworfen wird, aber das dürfte nicht zu verachten sein.
Warst du nicht eh ein Verfechter davon, dass das viel zu viel Zeit braucht und das man den Programmierer wählen lässt?

Zumal wieso ist hier die Methode, die Anwendung wie ein Baby zu behandeln gut?

Zitat von: erik
Ich hab echt den Eindruck das Du Dir immer die maximal umständlichsten Lösungen ausdenkst.
Auch das ist eine Lösung. Ich versuche halt oft nicht die Bedingungen zu ändern (bei deinem Bsp. Map-Lazy ab einer bestimmten Speichermenge), sondern den Weg.

Zitat von: erik
Willst Du ernsthaft die Thread-Art zur Laufzeit ändern?
Du stellst dir das komplexer vor als es ist. Ich würde einfach nur nen neuen Stack allozieren und den als per CPU-Stack eintragen und den aktuellen Stack in der Thread-Struktur speichern. Mehr wäre das nicht und da meine Kernel-Stacks 4kb groß sind, ist das auch nicht Zeitaufwendig.
Wenn man dann noch ein wenig Caching betreibt, dass man z.B. die Stacks danach nicht freigibt, sondern in eine Liste packt, ist nur das erste Mal "teuer".

Zitat von: erik
Ich kann nur wiederholen das Simplizität ein essentiell wichtiges Design-Paradigma ist.
Darüber lässt sich jetzt streiten. Es kommt halt drauf an was man erreichen will. Ne Liste ist immer einfacher als z.B. nen Baum und trotzdem wirst du bei den entsprechenden Fällen nen Baum wählen. Ist das dann deswegen ein schlechtes Design?

Zitat von: erik
von daher sehe ich da kein Sicherheitsrisiko wenn man gezielt den INT-Vector freigibt auf den der Timer-IRQ gemappt ist (solange dieser IRQ nicht geshared ist).
Das stimmt, dann müsste ich das nur in meiner libos einbauen, weil der Timer-IRQ ja nicht immer auf den selben Int gemappt ist (PIT und lokaler-APIC). Da muss ich nochmal genauer drüber nachdenken. Wieso haben das andere OS nicht? Soweit ich weiß ist yield() immer ein Syscall.
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: Svenska am 10. October 2011, 20:20
Zitat von: erik
Klar kann der PC mal für ein paar Millisekunden "einfrieren" wenn ein Task echt mal eine große Menge Speicher am Stück anfordert aber wie oft kommt das vor?
Das hat auf nem halbwegs modernen System nicht einmal vorzukommen, egal was für ne Situation es gibt!
Das nennt man dann aber harte Echtzeitanforderungen... die willst du ja auch nicht.

Ich kann jetzt nicht sagen, wie sehr die Performance einbrechen würde wenn bei z.B. einem 64mb Buffer, ab z.B. 4mb für jede Page eine Exception geworfen wird, aber das dürfte nicht zu verachten sein.
Was willst du jetzt - höchsten Durchsatz oder geringste Latenz? Beides geht nicht. Definiere "Performance" und was du erreichen willst.

Warst du nicht eh ein Verfechter davon, dass das viel zu viel Zeit braucht und das man den Programmierer wählen lässt?
Du erfindest doch hier die Probleme. :-P

Zitat von: erik
Ich hab echt den Eindruck das Du Dir immer die maximal umständlichsten Lösungen ausdenkst.
Ich ebenfalls.

Ich versuche halt oft nicht die Bedingungen zu ändern (bei deinem Bsp. Map-Lazy ab einer bestimmten Speichermenge), sondern den Weg.
Äh, ...hä? Ein anderer Codepfad bei anderen Anforderungen ist für mich ein anderer "Weg".

Es kommt halt drauf an was man erreichen will. Ne Liste ist immer einfacher als z.B. nen Baum und trotzdem wirst du bei den entsprechenden Fällen nen Baum wählen.
Und am Ende des Tages möchtest du dann doch ein Array benutzen, weil es den Cache besser ausnutzt und daher im Normalfall doch schneller ist.

Ist das dann deswegen ein schlechtes Design?
Wenn du Dinge kompliziert machst, die nicht kompliziert sein müssen - ja.

Wie das Big Kernel Lock im Detail implementiert wurde, ist mir egal. Aber ja, wenn ein Thread das Lock hält, darf kein anderer Thread in den Kernel bzw. wird dort blockiert. Diese Locks kann sich eine normale Anwendung allerdings nicht holen, also auch nicht das System blockieren.

Gruß,
Svenska
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: FlashBurn am 10. October 2011, 20:31
Zitat von: svenska
Das nennt man dann aber harte Echtzeitanforderungen... die willst du ja auch nicht.
Ich kenne jetzt nicht die genau Definition von harten Echtzeitanforderungen, aber so wie ich das interpretiere, haben die dann nicht alle OS? Weil es lässt sich bestimmt ne Obergenze finden, in der alle Aktionen fertig werden und das ist dann die Anforderung ;)

Zitat von: svenska
Was willst du jetzt - höchsten Durchsatz oder geringste Latenz? Beides geht nicht. Definiere "Performance" und was du erreichen willst.
Ich würde gerne einen guten Kompromiss eingehen ;)

Sprich wenn ich die Speicheranforderung unterbrechbar mache, dann kostet das im best-case unwesentlich mehr Zeit, aber der Zugriff auf den Speicher im Programm ist auf jeden Fall wesentlich schneller. Dabei muss ich dann halt den Kompromiss im Kernel eingehen.

Zitat von: svenska
Und am Ende des Tages möchtest du dann doch ein Array benutzen, weil es den Cache besser ausnutzt und daher im Normalfall doch schneller ist.
Kann durchaus passieren ;) Kommt halt auf den Fall an.

Zitat von: svenska
Diese Locks kann sich eine normale Anwendung allerdings nicht holen, also auch nicht das System blockieren.
Diese Aussage verstehe ich nicht. Jede Anwendung kann bzw. muss doch in den Kernel und kann sich damit sehr wohl den Lock holen oder was meinst du?

Edit::

Ich habe mir nochmal meine Mapping-Funktion angeguckt und mind. nochmal der selbe Aufwand kommt fürs Mapping dazu. Also ist auch COW keine Lösung weil ja die Flags gesetzt und die TLB Einträge gelöscht werden müssen. MAP_LAZY wäre auch nicht viel besser, es müssen ja auch Flags gesetzt und die TLB Einträge gelöscht werden.

Dann kommt noch hinzu, dass ein Prozess entweder seinen Speicher nicht Stück für Stück freigibt oder beendet werden muss. Das Freigeben ist auch wieder teuer und kann unter Umständen richtig lange dauern. Selbst wenn die Anwendung nicht viel Speicher angefordert haben sollte, so nutzt sie vllt viele Libs und die müssen auch alle erstmal wieder geunmappt werden und wenn da dann ein paar 100MB zusammenkommen und überprüft werden muss ob der Speicher freigegeben werden kann oder ob er zum SharedMemory (z.B. Libs) gehört, könnte es schonmal passieren dass das gesamte System für eine Sekunde oder sogar länger hängt.

Ich denke das Problem ist nicht zu unterschätzen. Denn wie erik schon sagte, meine Rechnung ist naiv.
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: Svenska am 11. October 2011, 00:50
Hallo,

Zitat von: svenska
Das nennt man dann aber harte Echtzeitanforderungen... die willst du ja auch nicht.
Ich kenne jetzt nicht die genau Definition von harten Echtzeitanforderungen, aber so wie ich das interpretiere, haben die dann nicht alle OS? Weil es lässt sich bestimmt ne Obergenze finden, in der alle Aktionen fertig werden und das ist dann die Anforderung ;)
Nein, weil kein OS eine solche Zeit garantiert. Kannst du auch garnicht, weil z.B. jeder einzelne Festplattenzugriff sich mehrere Minuten hinziehen kann (wenn der Sektor kaputt ist und die Software versucht, da noch Daten runterzukratzen) oder das OS komplett abstürzt/panict. Harte Echtzeit gibt es daher meist nur auf Controllern mit einem RTOS drauf (und einem sehr kleinem, vollständig verstandenem System außenrum) , die dann in ein "normales" PC-gestütztes System eingekoppelt sind.

Dabei geht es um Garantien, auch im allerschlimmerschlimmsten worst case.

Sprich wenn ich die Speicheranforderung unterbrechbar mache, dann kostet das im best-case unwesentlich mehr Zeit, aber der Zugriff auf den Speicher im Programm ist auf jeden Fall wesentlich schneller.
Sprich, wenn ein malloc() nicht am Stück, sondern mit zig Kontextwechseln zwischendurch stattfinden kann, beeinträchtigt das die Performance nicht, wenn aber erst bei Benutzung alloziiert wird, dann schon? Komische Milchmädchenrechnungen machst du da...

Zitat von: svenska
Diese Locks kann sich eine normale Anwendung allerdings nicht holen, also auch nicht das System blockieren.
Diese Aussage verstehe ich nicht. Jede Anwendung kann bzw. muss doch in den Kernel und kann sich damit sehr wohl den Lock holen oder was meinst du?
Das Lock gibt es nur, während ein Syscall ausgeführt wird. Syscalls terminieren aber üblicherweise irgendwann, auch bei kaputten Eingaben, und das Lock wird auch nur genommen, wenn es notwendig ist.

Irgendwann werden wir mal Benchmarks mit deinem Betriebssystem machen und schauen, ob all deine Probleme wirklich relevant und gut gelöst sind. 8-) Ich vermute ja, dass die Probleme zwar existieren, aber real fast keine Rolle spielen - und wenn doch, dann in Spezialfällen, für die es gutes Werkzeug gibt.

Gruß,
Svenska
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: FlashBurn am 11. October 2011, 11:17
Zitat von: svenska
Sprich, wenn ein malloc() nicht am Stück, sondern mit zig Kontextwechseln zwischendurch stattfinden kann, beeinträchtigt das die Performance nicht, wenn aber erst bei Benutzung alloziiert wird, dann schon? Komische Milchmädchenrechnungen machst du da...
Also, erstmal reden wir besser nicht vom malloc(), sondern von vmmAlloc() (was im Kernel stattfindet, ansonsten könnte ein falscher Eindruck entstehen) und dann wäre bei meinem altem Design (und ich gehe mal von aus, bei jedem anderen Monolithen und nicht unterbrechbaren MikroKernel auch) genau das passiert. Es hätten theoretisch zig Kontextwechsel stattfinden können, entweder weil die Zeitscheibe abgelaufen ist oder weil ein IRQ gefeuert hat. Solange getade kein Lock gehalten wurde, war mein letztes Design unterbrechbar (und ne Lock wurde immer nur sehr kurz gehalten).
Sprich schlechter ist es nicht geworden und einen Kontextwechsel pro 4kb Page ist wesentlich mehr als max. ein Kontextwechsel pro 512 4kb Pages! Also ich finde das keine Milchmädchenrechnung.

Ich habe einfach im Hinterkopf, dass ich auf meinem Desktop unter Windows ein Treiberproblem habe und da sind die Ints einfach zu lange aus und deswegen habe ich Soundprobleme (knarksen und sowas). Das scheint immer nur aufzutreten, wenn auf die HDDs zugegriffen wird und manchmal auch wenn auf ein ODD zugegriffen wird.

Genau solche Probleme möchte ich vermeiden und deswegen will ich es auf gar keinen Fall das die Ints alzu lange aus sind.

Zitat von: svenska
Irgendwann werden wir mal Benchmarks mit deinem Betriebssystem machen und schauen, ob all deine Probleme wirklich relevant und gut gelöst sind.
Sehr gerne und ich weiß schon jetzt das es besser geht, ich es nur nicht besser weiß.
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: erik.vikinger am 11. October 2011, 14:54
Hallo,


Das hat auf nem halbwegs modernen System nicht einmal vorzukommen, egal was für ne Situation es gibt!
Ich würde wetten das jeder von uns dieses "einfrieren" mehrmals pro Tag an seinem PC erlebt (egal ob da Windows oder Linux drauf läuft), diese Situationen sind nur normalerweise kurz genug das wir sie nicht bewusst wahrnehmen können. Schau doch einfach mal in den Linux-Kernel (der Windows-Kernel ist uns ja leider verschlossen) rein ob da die Speicherverwaltung unterbrechbar ist. Wirklich harte Echtzeitbedingungen werden, wie Svenska schon korrekt schrieb, nur in kleinen und 100% perfekt überschaubaren System erreicht, alles andere ist viel zu komplex (was auf Desktop-PCs ganz besonders zutrifft) um sowas auch nur annähernd gewährleisten zu können.

Wenn Du Dir bei der Speicherverwaltung auf Deinem 32 Bit-System, wo es nur um GBs und ein paar Hunderttausend Pages geht, schon solche Sorgen machst was denkst Du was uns auf fetten 64 Bit-System, wo es um TBs und ein paar Hundertmillionen Pages geht, erst erwartet? Eigentlich müsste bei diesem Gedanken doch jeder intelligente Mensch auf die Idee kommen das Paging als alleiniges Werkzeug zur Speicherverwaltung eine technologische Sackgasse darstellt, weil es einfach irgendwann nicht mehr benutzbar ist.

Warst du nicht eh ein Verfechter davon, dass das viel zu viel Zeit braucht und das man den Programmierer wählen lässt?
Ja, stimt, ich habe doch auch nur vorgeschlagen dieses Problem in die libOS zu verlagern indem der Kernel zu große Speicheranforderungen mit MAP-Now ablehnt. Damit hast Du in der libOS 5 bis 10 Zeilen C-Code (also eine kleine Schleife die den Mapping-Syscall in mehreren Häppchen aufruft) mehr aber dafür keine Probleme im Kernel und das Interface zum normalen User-Code (z.B. mmap) bleibt trotzdem gleich.

Wieso haben das andere OS nicht? Soweit ich weiß ist yield() immer ein Syscall.
Mein System wird yield() definitiv nicht als Syscall haben sondern als Inline-Assembler-Macro, also Bitte nicht solche Verallgemeinerungen. ;)
Das viele andere OS das per Syscall machen liegt eventuell daran das diese nicht gut designt sind, oder? Vermutlich hat die anständige Planungsphase gefehlt. ;)


Grüße
Erik
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: FlashBurn am 11. October 2011, 16:28
Zitat von: erik
Ich würde wetten das jeder von uns dieses "einfrieren" mehrmals pro Tag an seinem PC erlebt (egal ob da Windows oder Linux drauf läuft), diese Situationen sind nur normalerweise kurz genug das wir sie nicht bewusst wahrnehmen können.
Wenn diese Situationen kurz genug sind, dass man sie nicht wahrnimmt ist das ja in Ordnung, aber wenn der Sound schon aussetzt, dann ist das nicht mehr in Ordnung (ich rede hier von mehreren ms bis zu theoretisch Sekunden).

Zitat von: erik
Wenn Du Dir bei der Speicherverwaltung auf Deinem 32 Bit-System, wo es nur um GBs und ein paar Hunderttausend Pages geht, schon solche Sorgen machst was denkst Du was uns auf fetten 64 Bit-System, wo es um TBs und ein paar Hundertmillionen Pages geht, erst erwartet?
Wenn man mal von meiner alten Mapping-Funktion absieht (meine aktuelle Funktion braucht keinen Lock), war meine Speichervaltung unterbrechbar.

Allerdings werde ich das mit dem Mapping dann auch so lösen, dass das in mehreren Schritten passieren wird (wie beim Allozieren der Pages).

Zitat von: erik
ich habe doch auch nur vorgeschlagen dieses Problem in die libOS zu verlagern indem der Kernel zu große Speicheranforderungen mit MAP-Now ablehnt. Damit hast Du in der libOS 5 bis 10 Zeilen C-Code (also eine kleine Schleife die den Mapping-Syscall in mehreren Häppchen aufruft) mehr aber dafür keine Probleme im Kernel und das Interface zum normalen User-Code (z.B. mmap) bleibt trotzdem gleich.
Aber ob ich die Schleife nun im Kernel oder UserSpace habe ist doch erstmal egal, aber die Kontextwechsel sind verdammt teuer.

Um auch nochmal auf das MAP_NOW zurück zu kommen. Ist es nicht schon aus Effizienz-Sicht besser alles gleich zu mappen, als die teuren Exceptions das machen zu lassen?
Das wird doch nur zwecks Swapping und overcommitment gemacht (??).

Zitat von: erik
Das viele andere OS das per Syscall machen liegt eventuell daran das diese nicht gut designt sind, oder? Vermutlich hat die anständige Planungsphase gefehlt.
Kommt drauf an was alles gemacht wird und welchen Zustand der Scheduler erwartet. Bei mir ging es nur darum, dass ich den IRQ direkt im Handler hatte und daher konnte ich den nicht nochmal dafür nutzen, aber eigentlich hätte ich das auch machen können. Nur war es bei mir einfacher, weil ich so ne Funktion (vorallem für die Kernel-Threads) hatte und nicht nen Int (was im Kernel eh über ne Funktion gelöst werden muss, da ich den Int ja erst zu Laufzeit kenne).
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: Svenska am 11. October 2011, 16:39
MAP_NOW: Der Speicher wird schneller alloziiert, steht direkt zur Verfügung und blockiert während der Alloziierung Teile des Systems.
MAP_LAZY: Der Speicher wird erst auf Anfrage alloziiert und blockiert das System nicht, dafür ist es Langsamer.
Wieder der Kompromiss zwischen Performance (MAP_NOW) und Latenz (MAP_LAZY).

MAP_LAZY erspart u.U. das Swapping und macht Overcommitment erst möglich.
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: FlashBurn am 11. October 2011, 17:35
Zitat von: svenska
Wieder der Kompromiss zwischen Performance (MAP_NOW) und Latenz (MAP_LAZY).
Nur das man das mit der Latenz ja lösen kann, nur ist es halt dann nicht mehr ganz so simpel (aber nicht viel komplexer, ist ja nur ne Schleife mehr, die man eh im UserSpace dann spätestens haben müsste).
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: erik.vikinger am 11. October 2011, 17:40
Hallo,


Wenn diese Situationen kurz genug sind, dass man sie nicht wahrnimmt ist das ja in Ordnung, aber wenn der Sound schon aussetzt, dann ist das nicht mehr in Ordnung (ich rede hier von mehreren ms bis zu theoretisch Sekunden).
In meiner (sicherlich naiven) Welt ist die Soundkarte ein busmasterfähiges Gerät das man problemlos mit Sounddaten für die nächsten 500 ms beschicken kann, ich sehe da eigentlich gar kein Problem. Auf einem typischen Desktop-PC ist es IMHO nicht so extrem ungewöhnlich das die CPU mal für ne halbe Sekunde nicht zur Verfügung steht so dass das restliche System eigentlich damit umgehen können sollte.

Aber ob ich die Schleife nun im Kernel oder UserSpace habe ist doch erstmal egal, aber die Kontextwechsel sind verdammt teuer.
Ich wollte Dir damit auch keine Alternative zu den vielen Kontextwechseln anbieten (wenn die Speicheroperation unterbrechbar sein soll dann gibt es eben teure Kontextwechsel) sondern Dir zeigen das man mit wenigen Zeilen im User-Mode ein Problem lösen kann für das man im Kernel-Mode deutlich mehr Zeilen benötigt. Einen konzeptionell nichtunterbrechbaren Kernel dann doch wieder unterbrechbar zu machen und Thread-Arten ändern (inklusive zusätzlichen Stack allozieren) usw. ist mMn ein riesiger Haufen Code der vor allem jede Menge potentielle Bugs in Deinen Kernel holt. Du kennst doch sicher das KISS-Prinzip.

da ich den Int ja erst zu Laufzeit kenne).
Das Du die INT-Nummer erst zur Laufzeit kennst ist doch gar kein Problem, zumindest für die User-Mode-Programme. Da bastelst Du ein kleines Assembler-Modul für die yield()-Funktion :.public  yield
.extern  SYSTEM_YIELD_INT_NUMBER
.align 4
yield:
    db    0xCD
    db    SYSTEM_YIELD_INT_NUMBER
    ret
Dann muss der Linker nur noch für SYSTEM_YIELD_INT_NUMBER einen Relocations-Eintrag ins Executable packen (ELF sollte sowas können) und Dein Kernel erkennt beim Laden dieses Label und reloziert die richtige Nummer rein, voilà und fertig ist Dein flexibler yield-Mechanismus.


Grüße
Erik
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: FlashBurn am 11. October 2011, 18:18
Zitat von: erik
Auf einem typischen Desktop-PC ist es IMHO nicht so extrem ungewöhnlich das die CPU mal für ne halbe Sekunde nicht zur Verfügung steht so dass das restliche System eigentlich damit umgehen können sollte.
Also erstmal was ist denn für dich ein typischer Desktop-PC?

Ich erinnere mich daran, dass das Video oft am Audio synchronisiert wird und da weiß ich nicht wie das im Detail passiert und wieviel da gebuffert wird. Auch weiß ich nicht in wie weit man die Soundkarte Anweisungen mitteilen kann, hole in der und der Zeit von da und da Daten ab und spiele es dann ab (oder die Daten vorher schicken und sagen zu welchem Zeitpunkt es abgespielt werden soll).

Zitat von: erik
Ich wollte Dir damit auch keine Alternative zu den vielen Kontextwechseln anbieten (wenn die Speicheroperation unterbrechbar sein soll dann gibt es eben teure Kontextwechsel)
Wie kommt ihr eigentlich darauf, dass da immer teuere Kontextwechsel passieren. Die können passieren, müssen aber nicht. Genauso wie die innerhalb eines Monolithen passieren können (wenn man keinen Spinlock hält und die Ints an sind).

Nur habe ich so den Vorteil das ich das viele Interrupt an und ausmachen (was auf älteren CPUs nämlich verdammt teuer ist und das bei meinem alten Spinlock-Code richtig oft passiert ist) auf einmal an und wieder ausmachen alle 512 Schleifendurchläufe reduziere.

Zitat von: erik
Einen konzeptionell nichtunterbrechbaren Kernel dann doch wieder unterbrechbar zu machen und Thread-Arten ändern (inklusive zusätzlichen Stack allozieren) usw. ist mMn ein riesiger Haufen Code der vor allem jede Menge potentielle Bugs in Deinen Kernel holt.
Ich brauche eh Kernel-Threads, also sind die schonmal vorhanden und wie gesagt, das Thread-Art ändern besteht nur aus einem Pointer der entweder vorhanden ist oder nicht, mehr ist das nicht (so ist es jedenfalls geplant, ob da nicht doch noch Schwierigkeiten auftauchen weiß ich nicht).

Davon ausgehend das die Codezeilen-Anzahl bei beiden Varianten (einmal Schleife im Kernel und einmal im UserSpace) gleich sind, sind die Bugs doch eh statistisch gleich vorhanden ;) Gut einmal werden sie dann im UserSpace sein, was die Sache aber nicht besser macht, weil es trotzdem ein wichtiger Systemteil bleibt.

Zitat von: erik
Du kennst doch sicher das KISS-Prinzip.
Ja, aber ... ;)

Wie man das nun interpretiert ist so eine Sache, es liegt auch immer im Auge des Betrachters. Das hatten wir doch erst, wozu dann nen Baum nehmen, der ist nun wirklich nicht mehr KISS, sondern die Liste oder das Array.

Die ganzen technischen Sachen sind nicht mehr KISS. Wenn man mehr Effizienz will, muss man leider oft auf KISS verzichten. Denn KISS wäre bei einem OS mMn ganz eindeutig ein nicht unterbrechbarer Monolith, aber wirklich effizient und praktikabel ist das nicht.

Zitat von: erik
Das Du die INT-Nummer erst zur Laufzeit kennst ist doch gar kein Problem, zumindest für die User-Mode-Programme. Da bastelst Du ein kleines Assembler-Modul für die yield()-Funktion :
So ähnlich habe ich das schon gemacht, dass wäre nicht das Problem.

Edit::

Nicht das ich irgendwie eine schlechte Meinung vom Linux-Kernel hätte ;) aber folgendes ist nicht in Ordnung:

freier RAM: 39mb= "8619*4kB 127*8kB 59*16kB 41*32kB 15*64kB 7*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 39604kB"

Sobald man jetzt zusammenhängende >128kb braucht startet der OOM Killer. Wenn ich mich recht entsinne liegt es daran, das im Kernel nur identity gemappt wird (??). Gut das ist jetzt wahrscheinlich KISS, aber das soll gut sein? Sorry, aber dann doch lieber komplexer und nicht solche Probleme.
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: kevin am 11. October 2011, 21:19
Mein System wird yield() definitiv nicht als Syscall haben sondern als Inline-Assembler-Macro, also Bitte nicht solche Verallgemeinerungen. ;)
Ist das ein Widerspruch? Syscalls laufen doch in der Regel auch durch ein bisschen Assemblercode?

Zitat
Das viele andere OS das per Syscall machen liegt eventuell daran das diese nicht gut designt sind, oder? Vermutlich hat die anständige Planungsphase gefehlt. ;)
Was macht denn dein Assemblercode, wenn nicht in irgendeinem Sinn einen Syscall? Das einzige, was ohne Zusammenarbeit mit dem OS ginge wäre wohl irgendein Äquivalent zu hlt - aber das ist ja nicht wirklich ein yield? Oder anders gesagt: Was designst du anders und wieso ist ein Syscall falsch/nicht designt?
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: FlashBurn am 11. October 2011, 21:30
Wobei mir gerade auffällt, das ein Syscall auf neueren (und auch einigen älteren) CPUs wesentlich schneller als ein "int TIMER_IRQ" ist.
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: erik.vikinger am 11. October 2011, 22:12
Hallo,


Ist das ein Widerspruch? Syscalls laufen doch in der Regel auch durch ein bisschen Assemblercode?
Ja, natürlich, der Compiler erzeugt ja nicht direkt den Syscall-Befehl. Warum eigentlich nicht? Das wäre doch mal ne colle Sache.
In meinem Fall ist bei allen normalen Syscall-Funktionen (in der libOS) ein Stück Inline-Assembler drin das eben den SYSCALL-Befehl enthält und dafür sorgt das die Aufrufkonvention passt, in der Yield-Funktion ist dagegen ein Stück Inline-Assembler drin das den YIELD-Befehl enthält. Ich hatte irgendwann mal die tolle Idee das wenn ich eh einen CPU-lokalen Timer habe der einen eigenen Exception-Vector hat und auch nicht über den IRQ-Controller o.ä. geht (also auch kein EOI o.ä. benötigt) dann kann ich diesen Mechanismus auch gleich mit einen extra Befehl verfügbar machen, wimre hab ich mich dabei von irgendeiner anderen CPU inspirieren lassen aber ich weiß nicht mehr von welcher CPU-Architektur (diese Idee ist also nicht ganz von mir aber ich finde die trotzdem toll und sehr zweckdienlich). Für meine CPU und auch den Scheduler macht es absolut keinen Unterschied ob die spezielle Yiel-Exception gekommen ist weil der Zeitscheiben-Counter abgelaufen ist oder ob ein YIELD-Befehl kam (das könnte der Kernel auch nur feststellen indem er sich den als letztes im User-Mode ausgeführten Befehl anschaut) so das ich damit auch nicht solche Probleme haben kann wie FlashBurn mit kämpft. Den richtigen Timer im Chipsatz (eine Art HPET, der auch über den IRQ-Controller läuft) wird nicht für die Zeitscheiben verwendet. Nebst dessen das es bei mir auch nur einen einzigen Befehl gibt der den Wechsel vom System-Mode in den User-Mode ermöglicht so das ich da auch keine Unterscheidung benötige (wie auf x86 mit SYSRET vs. IRET).

Oder anders gesagt: Was designst du anders und wieso ist ein Syscall falsch/nicht designt?
Naja, mein Vorteil ist das ich mir anschaue welche Probleme ich in der SW eventuell haben könnte und dann überlege ob es da nicht eine elegante Möglichkeit gibt das gleich in HW zu umgehen, das geht natürlich nicht wenn man für eine fest vorgegebene Architektur ein OS entwickelt. Mein RFS-Befehl (mit dem man vom System-Mode in den User-Mode kommt) ist auch absolut unabhängig vom Stack so das der auch innerhalb einer beliebig tiefen Unterfunktion funktioniert (der aktuelle System-Mode-Stack wird dann einfach verworfen) so das ich auch nicht diese typischen Assembler-Stubs, wie die 256 bei x86, benötige.
Meine Bemerkung mit dem "nicht gut designt" war auch nicht so ganz ernst gemeint, mir ist schon klar das keiner von Euch um die Probleme und Altlasten bei x86 einfach so drumherum designen kann. ;)


Grüße
Erik
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: Svenska am 12. October 2011, 02:28
Zitat von: erik
Du kennst doch sicher das KISS-Prinzip.
Ja, aber ... ;)

Wie man das nun interpretiert ist so eine Sache, es liegt auch immer im Auge des Betrachters. Das hatten wir doch erst, wozu dann nen Baum nehmen, der ist nun wirklich nicht mehr KISS, sondern die Liste oder das Array.

Die ganzen technischen Sachen sind nicht mehr KISS. Wenn man mehr Effizienz will, muss man leider oft auf KISS verzichten. Denn KISS wäre bei einem OS mMn ganz eindeutig ein nicht unterbrechbarer Monolith, aber wirklich effizient und praktikabel ist das nicht.

Das ist, mit Verlaub, Blödsinn. Weiter sage ich dazu nichts.
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: FlashBurn am 12. October 2011, 09:00
Zitat von: svenska
Das ist, mit Verlaub, Blödsinn. Weiter sage ich dazu nichts.
Wieso ;)

Für mich ist alles was irgendwie komplex ist nicht mehr KISS, also eigentlich fast alles moderne (vorallem technische). Es würde alles auch einfacher gehen, aber es wäre halt nicht so effizient (dazu sage ich nur Locking und lock-free Algos).

Zitat von: erik
Ja, natürlich, der Compiler erzeugt ja nicht direkt den Syscall-Befehl. Warum eigentlich nicht? Das wäre doch mal ne colle Sache.
Würde gehen, wenn man nicht erst noch bestimmt Dinge machen müsste (was ansich auch kein Problem ist), aber du würdest dich damit auf bestimmte CPUs festlegen (auch erstmal kein Problem), könntest dann eventuelle neue Opodes auf neueren CPUs nicht mehr nutzen und müsstest, zumindest unter 32bit 2 Varianten, einmal für Intel und einmal für AMD zur Verfügung stellen und wozu den Aufwand, wenn man auch ne mini-Funktion vom OS nutzen kann?
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: erik.vikinger am 12. October 2011, 10:18
Hallo


Wieso ;)
Du scheinst Simplizität immer als absolute Simplizität anzunehmen und nie in Relation zur Problemstellung zu setzen.
Wer einfach nur ein klein wenig elektrische Energie benötigt kommt mit einem Wasserrad (mit Generator) oder gar mit 2 unterschiedlichen Metaldräten (als Thermoelement) und etwas Feuer aus. Wer aber eine größere Menge an elektrischer Energie haben will und dazu noch unabhängig von der Umwelt sein muss und dazu auch noch eine hohe Effizienz benötigt der muss sich schon ein komplexes Kraftwerk zulegen. Absolut gesehen ist das Kraftwerk natürlich ungleich komplexer als das Wasserrad oder gar das Thermoelement aber in Relation zum Schwierigkeitsgrad der Aufgabenstellung kann das Kraftwerk immer noch im Rahmen von KISS sein.
Auch beim Vergleich zwischen Micro-Kernel und Monolith ist meiner persönlichen Meinung nach im Punkt Simplizität eher der Micro-Kernel der Gewinner, da wird die Komplexität aufgebrochen und auf mehrere unabhängige User-Mode-Prozesse verteilt, getreu dem Motto "Teile und Herrsche".

Wenn Du jede Form von Komplexität grundsätzlich ablehnen möchtest dann solltest Du Dir lieber ein schöne Hölle suchen und auf so komplexe Dinge wie Elektrizität verzichten. ;)
Auf der anderen Seite sind die Lösungen die Du hier propagierst oft reichlich komplex, vor allem deutlich komplexer als die Aufgabenstellung eigentlich erfordert. Ich verstehe z.B. nicht wozu Du verschiedene Arten von Threads mit unterschiedlichen Speicheranforderungen haben möchtest. Bei mir werden Threads nur Attribute haben, z.B. Dämon-Thread (die den Prozess-Tod nicht blockieren) oder PopUp-Thread (vom IPC-System), aber diese Attribute spielen nur in einer eng begrenzten Anzahl an Situationen eine Rolle (z.B. ein PopUp-Thread darf sich nicht einfach selbst killen, was sollte in so einer Situation das IPC-System dem Caller als Antwort geben?) und werden ansonsten ignoriert (weder der Scheduler noch die Exceptionhander oder der generische IRQ-Handler interessieren sich für die Thread-Attribute wenn sie einen Thread von der CPU schmeißen u.ä.).

Würde gehen, wenn man nicht erst noch bestimmt Dinge machen müsste (was ansich auch kein Problem ist), aber du würdest dich damit auf bestimmte CPUs festlegen (auch erstmal kein Problem), könntest dann eventuelle neue Opodes auf neueren CPUs nicht mehr nutzen und müsstest, zumindest unter 32bit 2 Varianten, einmal für Intel und einmal für AMD zur Verfügung stellen
Der Compiler weiß ganz genau für welche CPU er compiliert und optimiert, der gcc unterscheidet auch zwischen AMD und Intel. Solche Dinge wie ein SYSCALL-Befehl gehören natürlich in den CPU-spezifischen Teil des Compilers. Aber da der Syscall auch vom OS (eventuell sogar von der konkreten Version des OS) abhängig ist ist es natürlich Blödsinn sowas in den Compiler fest einzubauen.

wenn man auch ne mini-Funktion vom OS nutzen kann?
Hä? Du meinst ne Minifunktion aus der libOS? Also die die das kleine Stück Inline-Assembler enthält.


Grüße
Erik
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: kevin am 12. October 2011, 10:19
Erik: Als was würdest du denn den YIELD-Befehl bezeichnen, wenn nicht als eine Art Sonder-Syscall? Für mich macht das die Sache nur uneinheitlicher, weil du nur noch fast alle Syscalls über dieselbe Instruktion abwickelst.

Wobei mir gerade auffällt, das ein Syscall auf neueren (und auch einigen älteren) CPUs wesentlich schneller als ein "int TIMER_IRQ" ist.
Falls dein OS den Timer benutzt, um seine Uhr zu aktualisieren, wäre ein manueller Aufruf des Timerinterrupts sowieso nicht so geschickt... (Auf Eriks Architektur geht das dann grundsätzlich nicht)

Zitat
Würde gehen, wenn man nicht erst noch bestimmt Dinge machen müsste (was ansich auch kein Problem ist), aber du würdest dich damit auf bestimmte CPUs festlegen (auch erstmal kein Problem), könntest dann eventuelle neue Opodes auf neueren CPUs nicht mehr nutzen und müsstest, zumindest unter 32bit 2 Varianten, einmal für Intel und einmal für AMD zur Verfügung stellen und wozu den Aufwand, wenn man auch ne mini-Funktion vom OS nutzen kann?
Blödsinn. Erstens ist es sowieso immer Aufgabe des Compilers, die passenden Opcodes rauszusuchen. Wenn du die benutzen willst, brauchst du halt einen aktuellen Compiler. Wo ist das Problem?

Und du brauchst auf x86 auch im PM keine zwei Varianten.
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: erik.vikinger am 12. October 2011, 12:18
Hallo,


Als was würdest du denn den YIELD-Befehl bezeichnen, wenn nicht als eine Art Sonder-Syscall? Für mich macht das die Sache nur uneinheitlicher, weil du nur noch fast alle Syscalls über dieselbe Instruktion abwickelst.
Meiner persönlichen Meinung nach ist die Funktionalität von Yield etwas anderes als ein typischer Syscall, es wird ja kein Service o.ä. angeboten, außerdem wird Yield üblicherweise von einer Hardware-Komponente angetriggert und hat daher eher den Charakter eines IRQs. Für mich ist der YIELD-Befehl eher sowas wie UD2 bei x86, eine Art Sonder-Weg für eine normale Exception. Bei mir haben die verschiedenen Eintrittsmöglichkeiten in den Kernel jeweils individuelle (konfigurierbare) Einsprungspunkte (ein paar für die Exceptions, einen für Yield, einen (eigentlich zwei aber das ist hier jetzt mal uninteressant) für den Syscall und dann kann der IRQ-Controller noch den Einsprungspunkt für den aktuell gelieferten IRQ vorgeben (was üblicherweise immer der selbe ist)), bei dem Einsprungspunkt für Yield gibt es zwei Möglichkeiten wie der angetriggert werden kann, einmal per Hardware wenn der Zeitscheiben-Counter bei 0 angekommen ist und zum zweiten mit dem YIELD-Befehl. Mir ist klar das der YIELD-Befehl eine Art Außname darstellt weil er so einen zusätzlichen Sonderweg in den Kernel bietet aber für diesen speziellen Zweck ist das IMHO gerechtfertigt, mit dem YIELD-Befehl kommt die CPU direkt im Scheduler-Code an und spart sich so unnötige Befehle. Darüber hinaus ist der Code am Einsprungspunkt für Yield ein anderer als für den Syscall, bei ersterem geht es darum möglichst schnell den aktuellen Thread-Zustand von der CPU runter zu holen und im Thread-Descriptor zu sichern wogegen es bei letzterem darum geht nur ein paar Register auf dem Kernel-Stack zu sichern damit die Syscall-Services ein paar freie Register zum arbeiten haben. Die zusätzliche Komplexität (in der Hardware) für diesen Schnell-Weg ist IMHO minimal da ich den Yield-Mechanismus für den Zeitscheiben-Counter ja eh benötige, wenn ich das über den Syscall machen würde würde das in Software wohl mehr Aufwand bedeuten als so.

Falls dein OS den Timer benutzt, um seine Uhr zu aktualisieren, wäre ein manueller Aufruf des Timerinterrupts sowieso nicht so geschickt... (Auf Eriks Architektur geht das dann grundsätzlich nicht)
Ich hatte FlashBurn so verstanden das er diesen Timer exklusiv für die Zeitscheibe benutzt, wenn er den selben Timer auch für andere Dinge nutzt kann er sowieso nicht einfach blind bei jedem IRQ den Thread wechseln. Obwohl ich da auch bei SMP eindeutig die Notwendigkeit sehe dafür den Timer im Local-APIC zu nutzen und der hätte dann sowieso einen eigenen INT-Vector (unabhängig von allen anderen IRQs). Das man auf meiner Architektur, so wie auf den meisten anderen auch, nicht per Software einfach einen IRQ-Vector aufrufen kann ist natürlich richtig und auch gewollt (wegen der Sicherheit usw.), deswegen benötige ich ja auch extra den YIELD-Befehl um da gezielt eine klar definierte Ausnahme machen zu können.


Grüße
Erik
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: kevin am 12. October 2011, 12:36
Meiner persönlichen Meinung nach ist die Funktionalität von Yield etwas anderes als ein typischer Syscall, es wird ja kein Service o.ä. angeboten
Es ist eine Funktion aus der API des Schedulers. Also ist es ein Syscall.

Zitat
außerdem wird Yield üblicherweise von einer Hardware-Komponente angetriggert und hat daher eher den Charakter eines IRQs. Für mich ist der YIELD-Befehl eher sowas wie UD2 bei x86, eine Art Sonder-Weg für eine normale Exception.
Nur dass ud2 nicht in normalen Codepfaden vorkommt (sondern eben nur, wo man sicherstellen will, dass eine (Nicht-)Instruktion nicht ausgeführt wird) und dass ein per Software getriggerter IRQ wesentlich krimineller als eine per Software getriggerte Exception ist.

Zitat
Bei mir haben die verschiedenen Eintrittsmöglichkeiten in den Kernel jeweils individuelle (konfigurierbare) Einsprungspunkte (ein paar für die Exceptions, einen für Yield, einen (eigentlich zwei aber das ist hier jetzt mal uninteressant) für den Syscall und dann kann der IRQ-Controller noch den Einsprungspunkt für den aktuell gelieferten IRQ vorgeben (was üblicherweise immer der selbe ist))
Es tut mir ja wirklich leid, aber an dieser Stelle muss ich dann auch dein Design mal kritisieren. ;)

Drei grundsätzlich verschiedene Möglichkeiten, einen Syscall zu machen, spricht dafür, dass dein Design nicht durchdacht genug ist, dass es eine einheitliche Lösung bieten kann. Wenn du mit Ausnahmen anfangen musst, ist die Basis nicht generisch genug. Wer sagt dir, dass Yield der einzige Syscall ist, der ein bisschen anders ist? Solltest du dann nicht Möglichkeiten bieten, ein paar verschiedene, frei definierbare Gruppen von Syscalls anzubieten? Ich weiß, dann landest du bald wieder bei der x86-IDT, aber vielleicht ist das ja doch alles nicht ganz so blöd (und Exceptions und IRQs kannst du ja nach wie vor zwingend separat halten).
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: kevin am 12. October 2011, 13:06
Ah, und noch eine Anmerkung, die ich machen wollte, dann aber beim Schreiben vergessen habe: Dass der Interrupt-Controller den Einsprungspunkt vorgibt, fühlt sich irgendwie komisch an und ich bin mir nicht sicher, ob das so eine tolle Idee ist. Aber was es auf jeden Fall ist, ist ein weiterer Fall, wo du nicht einheitlich arbeitest. Der Einsprungspunkt kommt einmal vom Interrupt-Controller, das nächste Mal von jeweils (im Speicher oder Registern konfigurierten?) unterschiedlichen Einsprungpunkten für die Exceptions, und genau drei Einsprungspunkte für n Syscalls (Wo sind die konfiguriert? Ist wenigstens das gleiche wie die Exceptions?), die dann im Kernel gemultiplext werden.
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: erik.vikinger am 12. October 2011, 14:04
Hallo,


Es ist eine Funktion aus der API des Schedulers. Also ist es ein Syscall.
Hm, Ansichtssache. Der Punkt ist das ich für Yield trotzdem einen eigenen Einsprungspunkt in den Kernel benötige da der Zeitscheiben-Counter mit Sicherheit keinen Syscall initiieren wird. Wenn dieser dedizierte Einsprungspunkt dann eh vorhanden ist ist eine Zweitnutzung zur Steigerung der Effizienz zwar immer noch ein (kleiner) Konzept-Bruch aber in diesem konkreten Fall meiner Meinung nach absolut okay. Ich bleibe auch der Meinung das Yield, im Gegensatz zu allen anderen Syscalls, keinen Service anbietet.

dass ein per Software getriggerter IRQ wesentlich krimineller als eine per Software getriggerte Exception ist.
Dem kann und werde ich nicht widersprechen, das wäre ein billiger Trick für ein klein wenig mehr Effizienz (und im Fall das Syscalls über spezielle Befehle gehen auch etwas Code-Ersparnis für eine zusätzliche Return-Methode). Auf x86 gibt es noch genug andere Dinge die man durchaus als kriminell betrachten kann, da wäre dieser Trick zumindest in guter Gesellschaft.

Es tut mir ja wirklich leid, aber an dieser Stelle muss ich dann auch dein Design mal kritisieren. ;)
Nur zu.

Drei grundsätzlich verschiedene Möglichkeiten, einen Syscall zu machen, spricht dafür, dass dein Design nicht durchdacht genug ist, dass es eine einheitliche Lösung bieten kann.
Der Weg wie meine CPU in den Kernel-Modus wechselt ist immer der selbe (da hat x86 mit mit und ohne Error-Code schon mehr Vielfalt zu bieten), nur der Vector ist jedes mal ein anderer. Auch der Code der am jeweiligen Vector steht ist je nach Aufgabenstellung ein anderer, hier ist mir Effizienz eindeutig wichtiger als Einheitlichkeit (vor allem weil Einheitlichkeit ja nicht zwangsläufig Simplizität ergibt). Nebst dessen das ich immer noch bestreite das Yield ein echter Syscall ist (eine Hardware würde schließlich nie einen Syscall aufrufen). Yield ist IMHO ein Zwischending aus Exception und IRQ, stellt also gegenüber diesen 2 Basis-Konzepten eh schon eine Ausnahme dar.

Wer sagt dir, dass Yield der einzige Syscall ist, der ein bisschen anders ist?
Also mir fällt da nichts weiter ein. Wenn Du da eine Idee haben solltest dann ruhig raus damit. Eine einzige Ausnahme rechtfertigt auf jeden Fall noch nicht ein (deutlich) komplexeres Basis-System.

Solltest du dann nicht Möglichkeiten bieten, ein paar verschiedene, frei definierbare Gruppen von Syscalls anzubieten?
Da hätte ich dann aber immer noch das Problem das ich damit ja nicht den Yield-Exception-Vector erreiche aber das ist ja genau der Grund warum ich einen extra YIELD-Befehl haben will damit der in der CPU genau das selbe auslöst wie eine bestimmte HW-Komponente aber ohne eine HW-Komponente sein zu müssen. Ich könnte auch eine bestimmte Port-Adresse freigeben wo dann bei einem Schreibzugriff der Zeitscheiben-Counter auf 0 gesetzt wird und damit eine Yield-Exception auslöst aber auch das ist ein Sonderweg nur das der nicht primär das CPU-Design betrifft.

Ich weiß, dann landest du bald wieder bei der x86-IDT, aber vielleicht ist das ja doch alles nicht ganz so blöd
Mein Syscall-Befehl ist recht flexibel und es ist auch sehr Effizient möglich im Kernel direkt die richtige Funktion anzuspringen (dazu benötige ich nur 2 Assemblerbefehle). Ich hab sogar vorgesehen das die Syscall-Nummer nicht nur als Immed angegeben werden kann sondern auch aus einem Register kommen darf (quasi eine Art "INT AL").

und Exceptions und IRQs kannst du ja nach wie vor zwingend separat halten
Das sowieso, alles andere wäre ein pures Sicherheitsrisiko.

Dass der Interrupt-Controller den Einsprungspunkt vorgibt, fühlt sich irgendwie komisch an und ich bin mir nicht sicher, ob das so eine tolle Idee ist.
Dann schau Dich mal auf anderen Plattformen um, z.B. bei ARM gibt es auch einen Vectored-IRQ-Controller (VIC) der für jeden seiner IRQs einen individuellen Vector direkt an den CPU-Kern liefern kann, damit werden (gegenüber älteren ARM-CPUs ohne VIC) bei jedem IRQ gleich mal ein paar CPU-Takte eingespart weil die CPU nicht erst den IRQ-Controller befragen muss um welchen IRQ es sich handelt und dann aus einer Tabelle den Funktions-Vector holen muss (man spart also einen Peripherie-Zugriff und einen Speicherzugriff ein). Diese Idee ist nicht nur toll sondern auch flexibel, weil ich als IRQ-Controller-Designer dann immer noch entscheiden kann ob ich so viel Speicherkapazität vorsehe das jeder IRQ einen eigenen Vector bekommen kann (was für einen Monolithen ein echter Vorteil wäre weil man sich dort dann jegliche Form von Dispatcher-Code sparen kann) oder ob der immer den selben Vector liefern soll (was für einen Micro-Kernel keine Einschränkung darstellt weil dieser ja eh IPC-Messages verschickt und damit auch nur einen einzigen generischen IRQ-Handler hat). Das tollste ist aber das diese Flexibilität keine Änderung in der CPU erfordert, man kann also immer die selbe CPU mit verschiedenen IRQ-Controllern kombinieren um je nach Anwendung das Optimum aus Hardware-Kosten und Performance zu gewinnen.

Aber was es auf jeden Fall ist, ist ein weiterer Fall, wo du nicht einheitlich arbeitest.
Ja, das stimmt, zumindest etwas. Meine CPU hat grundsätzlich zwei Möglichkeiten den Einsprungspunkt in den Kernel zu bekommen, einmal aus globalen Controll-Registern (das wird für alle Exceptions und Syscall und Yield so gemacht, sind genau 11 Stück) und dann von Außen als Teil der Antwort des IRQ-Controllers (zusammen mit der IRQ-Nummer und der Anzahl der angelaufenen IRQs) wenn die CPU den IRQ vom IRQ-Controller abholt. Das hat aber nur Auswirkungen auf den Wert in R63 (meinem IP) wenn die CPU vom User-Mode in den Kernel-Mode wechselt, der restliche Zustand (wie z.B. der frische Kernel-Mode-Stack) ist immer identisch.

und genau drei Einsprungspunkte für n Syscalls
Wie kommst du auf 3? Für meinen einen Syscall-Mechanismus hab ich 2 Einsprungspunkte vorgesehen, eigentlich würde das auch mit einem gehen aber bei den zwein macht einer von beiden bestimmte Zusicherungen so das der Code da nichts prüfen muss und schneller zu den eigentlichen Service-Funktionen springen kann (mit nur 2 Assemblerbefehlen, wie oben schon erwähnt). Dieser Zusatz ist natürlich genau auf mein OS abgestimmt und ist im wesentlichen nur eine Hardwarebeschleunigung für etwas das man auch genauso (nur nicht so schnell) in Software machen kann.

die dann im Kernel gemultiplext werden.
Gemultiplext wird bei mir gar nichts im Kernel. Die verschiedenen Einsprungspunkte haben eigenständige Code-Pfade. Die CPU landet bei mir z.B. beim Yield direkt im Code des Schedulers der dann auch sofort seine Arbeit erledigt, es gibt da keine gemeinsame Basis wo alle Mode-Wechsel durch müssen.
Ich habe den subjektiven Eindruck das Du zu x86-lastig denkst. ;)


Grüße
Erik
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: FlashBurn am 12. October 2011, 14:18
Zitat von: erik
Du scheinst Simplizität immer als absolute Simplizität anzunehmen und nie in Relation zur Problemstellung zu setzen.
Ah, also subjektiv. Denn wer legt fest was relativ ist?

Dann zur Problemstellung, in meinem Fall heißt das, der Kernel soll MAP_NOW anbieten (es soll nicht irgendwie über den UserSpace gelöst werden) und der Kernel soll eine gewisse maximale Zeitspanne nicht mit Ints aus laufen.

Also entweder man nimmt KISS wörtlich und dann braucht man mMn auch nix besseres als ne Liste (lasse mich gerne eines besseren belehren) oder es ist abhängig von den Anforderungen.

Um mal wieder nen Autovergleich zu bringen. Willst du nen Auto das fährt brauchst du keine hoch-komplexen Motoren, wie wir sie heute haben. Willst du aber nen Auto das auch noch wenig Verbraucht, also effizient ist, brauchst du nen komplexen modernen Motor.
Selbst wenn es vllt einfache Grundprinzipien gibt, ist die Umsetzung dann meistens komplex.

Zitat von: erik
Ich verstehe z.B. nicht wozu Du verschiedene Arten von Threads mit unterschiedlichen Speicheranforderungen haben möchtest.
Anforderung -> max. Zeitspanne mit Int aus => der Code muss im Kernel unterbrechbar gemacht werden, wenn er Gefahr läuft zu lange zu brauchen.

Ich habe in dem Sinne auch nicht verschiedene Arten von Threads. Ich setze da nirgends ein Flag was sagt, du bist jetzt ein Kernel-Thread und du ein User-Thread (gut man könnte argumentieren, dass ich das indirekt mache).

Zitat von: erik
Bei mir werden Threads nur Attribute haben, z.B. Dämon-Thread (die den Prozess-Tod nicht blockieren) oder PopUp-Thread (vom IPC-System), aber diese Attribute spielen nur in einer eng begrenzten Anzahl an Situationen eine Rolle (z.B. ein PopUp-Thread darf sich nicht einfach selbst killen, was sollte in so einer Situation das IPC-System dem Caller als Antwort geben?) und werden ansonsten ignoriert (weder der Scheduler noch die Exceptionhander oder der generische IRQ-Handler interessieren sich für die Thread-Attribute wenn sie einen Thread von der CPU schmeißen u.ä.).
Das finde ich komplex. Wieso kannst du nicht nur eine Art von Thread haben :P

Zitat von: erik
Hä? Du meinst ne Minifunktion aus der libOS? Also die die das kleine Stück Inline-Assembler enthält.
Jap. Mir fällt auf, das immer nur von Open-Source ausgegangen wird. Wenn das Programm aber nur in binärer Form vorliegt (und man nicht den DAU entscheiden lassen möchte welche Version er braucht, ob Intel oder AMD), dann macht genau solch eine Funktion (wie es in Windows und ich möchte meinen auch in Linux verwendet wird) Sinn.

Auch möchte ich nicht mehrere Einsprungspunkte haben (einmal für Int, Syscall und Sysenter).

Zitat von: taljeth
Blödsinn. Erstens ist es sowieso immer Aufgabe des Compilers, die passenden Opcodes rauszusuchen. Wenn du die benutzen willst, brauchst du halt einen aktuellen Compiler. Wo ist das Problem?
Wie oben schon beschrieben, die Situation Programm liegt nur in binärer Form vor.

Zitat von: taljeht
Und du brauchst auf x86 auch im PM keine zwei Varianten.
Einmal Int, einmal Sysenter und einmal Syscall, macht schon 3 Varianten und alle im PM!

Zitat von: erik
Ich hatte FlashBurn so verstanden das er diesen Timer exklusiv für die Zeitscheibe benutzt, wenn er den selben Timer auch für andere Dinge nutzt kann er sowieso nicht einfach blind bei jedem IRQ den Thread wechseln.
Richtig, ich benutze den IRQ nur für die Zeitscheiben. Zumal ich ja nen One-Shot-Timer nutze und keinen monotonen.

Edit::

Ich habe ganz vergessen, es gibt sogar noch eine 4. Methode nen Syscall zu machen, call-gates. Die sollen wohl auch schneller sein als Ints, nur halt mehr Speicher als Opcode verbrauchen.
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: Svenska am 12. October 2011, 16:27
FlashBurn ist ein typischer Vertreter des deutschen Over-Engineerings. :roll: Muss man mit leben.
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: FlashBurn am 12. October 2011, 16:39
Zitat von: svenska
FlashBurn ist ein typischer Vertreter des deutschen Over-Engineerings.
Also erstmal danke für das Kompliment :P

OT:
Sind wir deutschen wirklich dafür bekannt?
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: Svenska am 12. October 2011, 17:27
Ja.
PS: Für solche Dinge solltest du ins IRC kommen, dafür muss man das Forum nicht zuspammen. :-)
Titel: Re: Nicht unterbrechbarer Kernel
Beitrag von: Sannaj am 09. December 2011, 20:06
Also es gibt unterbrechbare Kernel, Linux kann das zum Beispiel. Allerdings macht so etwas nur bei Monolithischen Kernels Sinn. Hierbei werden die ehr unwichtigen Kernelmoduel (sprich Hardwaretreiber), als Task mit Ring 0 Rechten behandelt. Die Idee, das du ein Kernel internes cooperatives MT, über ein externes präemeratives Multitasking legen willst, macht die Sache natürlich komplizierter. Eine Interessante Idee ist es aber trozdem. Du musst dir auch im klaren sein, das Funktionen wie vmm_alloc immer atomar ausgeführt werden sollten, weil es sonst zu bösen Überraschungen kommst. Wenn du meinst, das es sich lohnt den Aufwand trotzdem zu betreiben würde ich eine Funktion einbauen, die dem Schedule sagt, das er eine bestimmte Aktion atomar ausführen werden muss. Der Schedule sollte in diesem Fall nur eine Markierung setzten, die Uhr aktualisieren und dann weitermachen. In die entsprechenden Kernelfunktionen müsste dann so etwas wie eine "atomar Anfang"/"atomar Ende" Algorithmus eingebaut werden. Die "atomar Anfang"-Funktion setzt eine dafür markierte Flag auf den "no shedule interrupts - time out not reached mode". Wird nun der Shedule aufgerufen setzt er " den "no shedule interrupts - time out reached mode". Die "atomar Ende" - Funktion setzt den Wert auf den Standart zurück und führt den Rest des Shedules aus, wenn "time out reached mode" da war. (Aufpassen, das nicht zusätzlich auf noch der PIT gleichzeitig den Shedule starten kann.)

Das ein Programm, das auf einen Schlag einen ganzen Gigabyte Speicher haben will, halte ich für relativ unwahrscheinlich. Ausführbare Dateien und dylib's selbst sind in der Regel wesentlich kleiner und auf solch große Dateien sollte man nur noch partiell zugreifen.