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.