Autor Thema: Shared Memory  (Gelesen 36376 mal)

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #60 am: 27. September 2010, 15:09 »
Hallo,


Naja, das ist jetzt Definitionssache, was du als OS bezeichnest
Klar, ich meinte das auch nicht so ganz ernst, ich wollte auf die Tatsache hinaus das ein Micro-Kernel bereits zu 100% einsatzfähig sein muss (also IPC, Timing, Speicherverwaltung und Prozess/Thread-Management) bevor auch nur ein Treiber o.ä. geladen werden kann.

Ich meine aber wenn du einen monolithen mit einem mikro vergleichst, dann kann man sagen dass das OS erst läuft wenn alle Server und Treiber laufen und bis dahin ist es dann doch um einiges komplexer bei einem Mikrokernel.
Damit hast Du natürlich recht aber da das alles im User-Mode abläuft kann man da auch einiges tricksen wie z.B. den Boot-Vorgang von einem Script steuern lassen oder über alle verfügbaren CPUs verteilen.

Ich muss mir bei mir nochwas schönes einfallen lassen, da ich auch Hardware habe (Timer) die ihr Arbeit nicht im UserMode sondern im KernelMode verrichten, aber eigentlich wollte ich das die richtigen Treiber dann wirklich nur ne Nachricht bekommen bzw. aufgeweckt werden.
Die einzigste HW die mir da einfällt ist eben der Timer aber auch der wird bei einem Micro-Kernel nur dazu benutzt irgendwelchen User-Mode-Prozessen eine Message zu schicken bzw. Threads aufzuwecken, sollte also auch ziemlich schnell sein.

Also es war wirklich nicht schwierig ;) (mein Kernel war von Anfang an so geplant und das war mit das erste was ich implementiert habe).
Bist Du sicher? Bitte nicht falsch verstehen aber bist Du wirklich sicher das in Deinem Code keine potentiellen Dead-Locks usw. drin sind oder sind die bis her nur nicht aufgetreten? Auf wie vielen CPUs lief Dein Kernel schon? Was denkst Du eigentlich wie viel Performance dieser zusätzliche Code im Kernel kostet und wie viel Performance ein unterbrechbarer Kernel dafür wieder bringt? Ich weiß es nicht genau aber mein Bauch sagt mir das bei einem Micro-Kernel wohl eher der Verlust überwiegen dürfte. In einem Micro-Kernel gibt es IMHO keine Vorgänge die so lange brauchen das man sie unterbrechbar machen müsste oder für die der Kernel eigene Threads braucht.
Ich hoffe wirklich das Dein Kernel so funktioniert wie Du Dir das vorstellst aber ich weiß auch das es da einige sehr spezielle Stolperfallen gibt. Selbst in Linux gab es deswegen schon den einen oder anderen Bug.

Kann sein das ich da anders ticke, aber die Arbeit etwas Multithreading tauglich zu machen ist im Kernel- und UserMode eigentlich gleich.
Nein, da kann ich Dich beruhigen, diesbezüglich tickst Du ganz normal.

und das geht halt wesentlich effizienter wenn man dann die Ints abschalten kann
Sicher? Das würde ich aber doch bezweifeln. Es ist ein Trade-Off aus dem zusätzlichen Aufwand zum Abschalten und Reaktivieren der IRQs (was wohl in >99% aller Fälle unnötig ist da die CPU ja nicht ständig IRQs bekommt) und dem Verlust wenn ein Thread gerade auf einen anderen wartet weil dieser einen Lock hat aber unterbrochen wurde und den Lock daher nicht freigibt. Sicher wird dieser Trade-Off oft zugunsten der abschaltbaren IRQs aufgehen aber das muss nicht zwangsläufig so sein. Wenn man z.B. die IRQs dynamisch über viele CPUs verteilen kann so das die Wahrscheinlichkeit hoch ist das immer eine CPU Zeit hat oder wenn man Hardware benutzt die möglichst viele Jobs auf ein mal selbstständig erledigt und so nur wenige IRQs generiert kann es durchaus sein das dieser Trade-Off in die andere Richtung aufgeht.

Man sollte nichtmal daran denken, das ein UserMode Programm die Möglichkeit hat die Ints abzuschalten, das wäre genauso "dämlich" wie cooperatives-Multitasking. Sicher kann das auch funktionieren, aber einem warum sollte man es einem Programm so leicht machen den PC unbenutzbar zu machen!?
Wo siehst Du das Problem? Auf meiner CPU soll es möglich sein das ein User-Mode-Thread für eine sehr kurze Zeit, z.B. für die nächsten 32 Assemblerbefehle, das annehmen von IRQs blockieren kann. Wenn man dafür seiner aktuellen Restzeitscheibe immer 1ms als Fairness-Ausgleich abzieht dann kann es keine Gefahr geben das so ein Thread den Computer unbenutzbar macht. Zumal nach Ablauf dieser kurzen Zeitspanne die CPU ja prüfen kann ob IRQs in der Zeit angelaufen sind und diese dann verarbeiten, dadurch erhöht sich höchstens etwas die Latenz. Und da bei mir die IRQs dynamisch, anhand der Prioritäten des gerade ausgeführten Codes, über alle CPUs verteilt werden sollen dürfte es kaum messbar sein wenn ab und an mal eine CPU sich aus diesem Prozess kurz ausklingt, ein Syscall hat die selbe Wirkung weil bei mir ja der Kernel grundsätzlich nicht unterbrechbar ist.

Da mein Kernel schon einige Interfaces hat (weil er aus Modulen besteht die vom Loader zusammengefügt werden), weis ich das ein Interface zwar für einen Programmieren schön ist
Ja ist das denn kein wichtiger Grund? Was macht es schon ob Dein Loader 5 oder 50 Module lädt? Ein sauber programmierter und klar strukturierter Kernel in dem der Programmierer sich gut zurecht findet (der deswegen vielleicht weniger Fehler enthält) ist IMHO sehr viel mehr wert!

wie viele sinnlose Funktionen (z.B. "uint32t foo(void bar) { return 0; }") ich dadurch habe.
Ich weiß ja nicht wie Du Interfaces entwickelst aber solche Funktionen hatte ich noch nie (und wenn doch würde die ein guter Compiler wegoptimieren).

ist eine Regel von mir keine FPU im Kernel
Die armen Kernel-Threads, das empfinde ich schon als erhebliche Einschränkung.

Und genau damit habe ich ein Problem. Wenn man immer darauf bedacht ist kompatibel zu bleiben wird nichts richtiges neues mehr Entwickelt.
Wo wir wieder bei dem Henne-Ei-Problem wären. Wir halten an den ganzen alten Sachen fest und das hindert uns daran was richtig neues zu machen.
Dann kannst Du ja sehr gut nachvollziehen warum ich eine komplett neue Plattform entwickeln möchte. Ich will endlich mal mit ein paar alten Traditionen brechen und beweisen das es auch anders geht.
Wenn Du so denkst, warum programmierst Du dann Dein OS ausgerechnet für x86?

Richtig! Und ich schreibe lieber meinen Kernel neu ;)
Ich schreibe zwar definitiv kein portables OS aber wenn ich es tun würde würde ich mich schon bemühen meine Zeit etwas effizienter zu verwalten. Nimm es mir nicht über aber gleich den ganzen Kernel (und sei es nur ein Micro-Kernel) neu zu programmieren halte ich für reichlich ungeschickt, das geht mit einer guten Modularisierung auf Quell-Code-Ebene deutlich besser.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #61 am: 27. September 2010, 15:35 »
Zitat von: erik
Die einzigste HW die mir da einfällt ist eben der Timer aber auch der wird bei einem Micro-Kernel nur dazu benutzt irgendwelchen User-Mode-Prozessen eine Message zu schicken bzw. Threads aufzuwecken, sollte also auch ziemlich schnell sein.
Mir geht es gar nicht darum das es eventuell "länger" dauern könnte, sondern das ich gerne ein einheitliches Interface hätte (das perfekte Interface kann meiner Meinung nach nicht existieren bzw. wäre es mir zu langsam ;) ) was das betrifft.

Zitat von: erik
Bist Du sicher? Bitte nicht falsch verstehen aber bist Du wirklich sicher das in Deinem Code keine potentiellen Dead-Locks usw. drin sind oder sind die bis her nur nicht aufgetreten?
Sicher kann man nur so lange sein, bis einer auftritt ;) Ich hatte erst einen (daher auch der Thread, der war nämlich die Ursache) und der war ziemlich dämlich :(
Ich habe bei einem Read-Write-Lock, als Reader den Lock bekommen und habe ihn als Writer wieder freigegeben (bzw. hat der Code das versucht und hat mein OS festgefahren).

Zitat von: erik
... oder für die der Kernel eigene Threads braucht.
Ich habe z.B. pro CPU 1 Idle-Thread und das ist ein Kernel-Thread und dann kommt noch mein "Thread-Killer" dazu.

Zitat von: erik
Wo siehst Du das Problem?
Wie stellst du sicher dass das Programm die Ints nicht für immer deaktiviert? Das ist der Grund warum man sowas für gewöhnlich nicht zulässt.

Zitat von: erik
Ein sauber programmierter und klar strukturierter Kernel in dem der Programmierer sich gut zurecht findet (der deswegen vielleicht weniger Fehler enthält) ist IMHO sehr viel mehr wert!
Sorry, aber das klingt für mich nach Uni-gelabber ;) Du müsstest es doch besser wissen, das es in der Arbeitswelt sowas nicht gibt, da soll immer alles schneller als möglich gehen und das ist für mich auch ein Grund warum wir zwar immer schneller CPUs haben, aber irgendwie werden viele (bzw. bei nem normalen User fast alle) Programme nicht schneller.

Zitat von: erik
Ich weiß ja nicht wie Du Interfaces entwickelst aber solche Funktionen hatte ich noch nie (und wenn doch würde die ein guter Compiler wegoptimieren).
In dem Fall ging es darum, das die HW nicht dieses Feature unterstützt hat.

Zitat von: erik
Die armen Kernel-Threads, das empfinde ich schon als erhebliche Einschränkung.
Korregiere mich wenn ich falsch liege, aber ersten wozu brauchst du ne FPU im Kernel und welcher Kernel unterstützt das (wimre ist das auch bei Linux ne Regel, das ist aber nur ne wage Erinnerung ;) )?

Zitat von: erik
Wenn Du so denkst, warum programmierst Du dann Dein OS ausgerechnet für x86?
Fast alles bekannt und einfach zugänglich, es gibt genügend Bsp., ich kann es wunderbar einfach testen und ich komme billiger als billig an Hardware.
Wenn ich nicht so knapp bei Kasse wäre, hätte ich schon längst nen BeagleBoard!

Zitat von: erik
Ich schreibe zwar definitiv kein portables OS aber wenn ich es tun würde würde ich mich schon bemühen meine Zeit etwas effizienter zu verwalten. Nimm es mir nicht über aber gleich den ganzen Kernel (und sei es nur ein Micro-Kernel) neu zu programmieren halte ich für reichlich ungeschickt, das geht mit einer guten Modularisierung auf Quell-Code-Ebene deutlich besser.
Ich behaupte das es nicht wirklich lange dauern sollte, meinen Kernel auf ne andere Architektur zu portieren (das weis ich aber auch erst, wenn es denn mal passiert ist).

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #62 am: 27. September 2010, 18:00 »
Hallo,


sondern das ich gerne ein einheitliches Interface hätte (das perfekte Interface kann meiner Meinung nach nicht existieren bzw. wäre es mir zu langsam ;) ) was das betrifft.
Du meinst das jeder Kernel ein Interface bekommt das individuell auf die entsprechende HW angepasst ist?

pro CPU 1 Idle-Thread und das ist ein Kernel-Thread
Bei mir ist idle ein User-Mode-Prozess. Da idle bei mir das Speicherdefragmentieren übernehmen soll hatte ich auch mal überlegt dafür doch Kernel-Mode-Threads zu implementieren aber ich denke es wird auch ohne gehen, der Kernel stellt ein paar spezielle Syscalls zur Verfügung die nur idle benutzen darf.

noch mein "Thread-Killer"
Der klingt aber gefährlich, welche Art von Programmen muss sich den vor dem in Acht nehmen?

Wie stellst du sicher dass das Programm die Ints nicht für immer deaktiviert?
Es soll einen speziellen IRQ-Disable-Befehl geben der die IRQs abschaltet, dieser IRQ-Disable-Befehl hat ein Immediate-Parameter das die Anzahl der Befehle angibt die dann geschützt werden sollen (über den gültigen Wertebereich hab ich noch nicht so genau nachgedacht aber vermutlich was in der Art 4...31, alles andere ist dann ein Illegal-OpCode). Wenn dieser IRQ-Disable-Befehl kommt rechnet die CPU die Strafzeit, z.B. pro Befehl 4 us, aus und verringert die Restzeitscheibe entsprechend, falls die übrige Restzeit <=0 ist gibt es sofort eine Yield-Exception und der IP wird auf diesen IRQ-Disable-Befehl gesetzt (so das wenn dann dieser Thread wieder vom Scheduler dran kommt ein neuer Versuch unternommen wird). Wenn der IRQ-Disable-Befehl erfolgreich verarbeitet wurde (wozu auch das flushen der Pipeline gehört) werden die nächsten Befehle geschützt ausgeführt und der lokale Zeitscheiben-Timer angehalten, wenn innerhalb der erlaubten X Befehle ein spezieller IRQ-React-Befehl (welcher auch die Pipeline flusht) kommt wird der Schutz wieder aufgehoben und die Zeitscheibe läuft wieder weiter. Wenn innerhalb der X Befehle kein solcher IRQ-React-Befehl kommt gibt es ne Exception (und der Prozess wird gekillt). Wenn einer der geschützten Befehle eine Exception verursacht (oder ein Syscall-Befehl dabei ist, was eigentlich nicht sein darf) dann geht die CPU in den Kernel-Mode und dieser Schutz ist vergessen, das heißt das wenn der Exception-Handler zurückkehrt werden die restlichen Befehle ohne diesen Schutz ausgeführt (das ist dann aber auch nicht mehr so schlimm weil der Thread, wohl im Besitz eines Lock, ja eh schon unterbrochen wurde), man tut also gut daran aufzupassen das dieser Code möglichst keine Exception verursacht (ist ja auch nicht so schwer). Mit dem IRQ-React-Befehl werden wieder die IRQs freigeschalten und die CPU prüft auch gleich ob was anliegt. Das die Schutzzeit in Befehlen und nicht in Zeit bemessen wird liegt daran das die Ausführungssgeschwindigkeit ja nicht konstant oder vorhersehbar ist.

Sorry, aber das klingt für mich nach Uni-gelabber ;) Du müsstest es doch besser wissen, das es in der Arbeitswelt sowas nicht gibt, da soll immer alles schneller als möglich gehen
Gerade weil ich im Berufsleben und auch privat schon mit Projekten sehr unterschiedlicher Quell-Code-Qualität zu tun hatte weiß ich ganz genau wie wichtig eine möglichst hohe Quell-Code-Qualität ist. Wobei ich auch sagen muss das die Projekte mit denen ich privat in Kontakt komme tendenziell eine höhere Quell-Code-Qualität haben, ist auch logisch weil ein Open-Source-Programmierer von seinen Mitstreitern anhand seiner Arbeit beurteilt wird und ein angestellter Programmierer wird von seinem Chef oft danach beurteilt wie gut er ihm in den Ar*** kriecht. Sauberer Quell-Code trägt erheblich zu einer fehlerarmen Software bei und lohnt sich daher immer (ich hatte auch schon Chefs die das genau so sahen und der Erfolg der Projekte hat ihnen Recht gegeben). Ich bin mir sicher dass das hier einige Leute bestätigen können.

In dem Fall ging es darum, das die HW nicht dieses Feature unterstützt hat.
Dann sollte der Compiler sich darum kümmern und die Funktion inlinen.

Korregiere mich wenn ich falsch liege, aber ersten wozu brauchst du ne FPU im Kernel und welcher Kernel unterstützt das (wimre ist das auch bei Linux ne Regel, das ist aber nur ne wage Erinnerung ;) )?
Also ich hab die FPU schon mal in einem Kernel benutzt, war aber auch ein ziemlich irrer Mechanismus für den ich die FPU brauchte. In Linux gibt es wimre Regeln in was für Code-Bereichen wie viel (von FPU/SSE/....) benutzt werden darf, aber komplett verboten ist das wimre nicht.

Fast alles bekannt und einfach zugänglich, es gibt genügend Bsp., ich kann es wunderbar einfach testen und ich komme billiger als billig an Hardware.
Das sind doch nur Ausreden und zum Großteil glatt falsch. ;)
ARM ist auch recht gut Dokumentiert (vor allem zu diesen voll integrierten SoC-Chips gibt es oft downloadbare Manuals mit über 1000 Seiten) und hinter dem genannten Board steht eine Community die sicher auch noch die restlichen Fragen beantworten kann. Für entsprechende SoCs auf MIPS- oder PowerPC-Basis sieht die Sache nicht anders aus.
Alle 3 Architekturen sind deutlich frischer, schlanker und vor allem konsistenter als es x86 ist.
(das sollte jetzt kein Flame gegen x86 sein, nur eine kurze Tatsachenbeschreibung)

Ich behaupte das es nicht wirklich lange dauern sollte, meinen Kernel auf ne andere Architektur zu portieren (das weis ich aber auch erst, wenn es denn mal passiert ist).
Da gibt es wirklich nur eine Methode das heraus zu finden. Mach das einfach mal und Du wirst sehen wie viel leichter das gehen kann wenn man ordentlich abstrahiert und strukturiert. ;)


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #63 am: 27. September 2010, 18:13 »
Zitat von: erik
Du meinst das jeder Kernel ein Interface bekommt das individuell auf die entsprechende HW angepasst ist?
Selbstverständlich nicht, jeder Kernel muss die selben Syscalls zur Verfügung stellen (da frag ich mich gerade was meinst du eigentlich genau mit "jeder Kernel"?), aber ich wäre halt froh wenn man nur einmal abstrahieren müsste. Da ich aber verschiedene Module habe, müssen diese alles das selbe Interface implementieren damit keine "Symbol nicht gefunden" Fehler passieren können.

Zitat von: erik
Bei mir ist idle ein User-Mode-Prozess. Da idle bei mir das Speicherdefragmentieren übernehmen soll hatte ich auch mal überlegt dafür doch Kernel-Mode-Threads zu implementieren aber ich denke es wird auch ohne gehen, der Kernel stellt ein paar spezielle Syscalls zur Verfügung die nur idle benutzen darf.
Naja, ich unterscheide zw dem Idle-Thread (der wirklick nur "hlt" ausführt und im Kernel laufen muss) und anderen Idle-Threads, die immer dann laufen wenn nichts ansteht.

Zitat von: erik
Der klingt aber gefährlich, welche Art von Programmen muss sich den vor dem in Acht nehmen?
Jeder ;) Das ist mein Thread der Prozesse/Threads vollständig beendet (also deren ganze Ressourcen freigibt und sowas).

Zitat von: erik
Wenn dieser IRQ-Disable-Befehl kommt rechnet die CPU die Strafzeit, z.B. pro Befehl 4 us, aus und verringert die Restzeitscheibe entsprechend, falls die übrige Restzeit <=0 ist gibt es sofort eine Yield-Exception und der IP wird auf diesen IRQ-Disable-Befehl gesetzt (so das wenn dann dieser Thread wieder vom Scheduler dran kommt ein neuer Versuch unternommen wird).
Sicher das du das meinst was du geschrieben hast? Weil das hört sich danach an, das deine CPU deine Datenstrukturen kennt.

Ansonsten ist sowas natürlich zu begrüßen.

Zitat von: erik
Dann sollte der Compiler sich darum kümmern und die Funktion inlinen.
Das geht nicht, da diese Symbole ja erst beim Booten aufgelöst werden.

Zitat von: erik
ARM ist auch recht gut Dokumentiert (vor allem zu diesen voll integrierten SoC-Chips gibt es oft downloadbare Manuals mit über 1000 Seiten) und hinter dem genannten Board steht eine Community die sicher auch noch die restlichen Fragen beantworten kann.
Gut dann das Argument das ich ein Consumer-OS schreibe und nicht eins für nen Mikrokontroller. Das BeagleBoard kommt dem schon am nächsten, aber ich hab halt nicht einfach mal so 150€ rumliegen :(

Ich sags mal so, wenn ich einen rein finanziellen Grund hätte, würde ich mir irgendein Nischen-Produkt suchen und dafür ein OS schreiben, da das bestimmt mehr Erfolg hätte, aber so nehme ich die Arch die am weitverbreitesten ist (unter normalen PCs) ergo x86. Ob die Arch toll ist seih mal dahingestellt.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #64 am: 27. September 2010, 20:08 »
Hallo,


Selbstverständlich nicht, jeder Kernel muss die selben Syscalls zur Verfügung stellen (da frag ich mich gerade was meinst du eigentlich genau mit "jeder Kernel"?), aber ich wäre halt froh wenn man nur einmal abstrahieren müsste.
Mit jeder Kernel meinte ich jeden Kernel der auf eine neue HW-Plattform (wobei jetzt mal PC mit nur PIC und PC mit HPET schon zwei verschiedene Plattformen sind) kommt bekommt zu seinem Unterbau (also die fest eingebauten Treibern) ein angepasstes API was es ihm ermöglicht die spezielle HW auch so gut als möglich auszureizen. Das API zu den Applikationen (die Syscalls) bleibt natürlich immer gleich. Ich hoffe jetzt hab ich genau das getroffen was Du meinst.

ich unterscheide zw dem Idle-Thread (der wirklick nur "hlt" ausführt und im Kernel laufen muss) und anderen Idle-Threads, die immer dann laufen wenn nichts ansteht.
Jetzt bin ich aber neugierig, worin unterscheiden sich diese beiden Dinge? Wie entscheidet der Kernel oder jemand anderes darüber welche dieser Möglichkeiten gewählt wird? Gibt es von beiden Sorten so viele Threads wie es CPUs gibt? Warum muss der HLT im Kernel ausgeführt werden?

Das ist mein Thread der Prozesse/Threads vollständig beendet (also deren ganze Ressourcen freigibt und sowas).
Also eine Art Garbage-Collector, interessant das Du so eine Idee umsetzen willst. ;)

Sicher das du das meinst was du geschrieben hast? Weil das hört sich danach an, das deine CPU deine Datenstrukturen kennt.
Ja ich meine wirklich genau das was ich geschrieben hab. Welche Daten-Strukturen sollte meine CPU denn dafür kennen? Ich bin mir nicht bewusst irgendwelche Dinge vom Speicher genannt zu haben, meine CPU soll, mit Ausnahme der Descriptoren für Segmente und Pages, überhaupt nicht selbstständig auf den Speicher zugreifen. Der Zeitscheiben-Counter ist eh in HW implementiert (ein simpler Downcounter in den der Scheduler immer die Länge der Zeitscheibe des nächsten Thread reinlegt und der bei 0 aufhört zu zählen und eine Yield-Exception generiert also einen Kontext-Switch auslöst durch den dann der Scheduler aktiv wird) und kann daher auch dort manipuliert werden und Exceptions muss die CPU auch so auslösen können. Ein kleiner zusätzlicher Downcounter der die Befehle zählt und bei != 0 die IRQ-Annahme + Zeitscheiben-Counting sperrt ist IMHO keine so große Erweiterung mehr.

Ansonsten ist sowas natürlich zu begrüßen.
Genau deswegen will ich sowas ja implementieren, ich betrachte meine Plattform auch als Spielwiese um mal gänzlich neue Dinge auszuprobieren.

Gut dann das Argument das ich ein Consumer-OS schreibe und nicht eins für nen Mikrokontroller.
Weder ARM noch MIPS oder PowerPC sind nur Mikrocontroller! Die beiden letzten sind sogar in 64 Bit verfügbar und wurden schon in sehr großen Super-Computern eingesetzt! Was ist eigentlich an Mikrocontrollern so schlimm?


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #65 am: 28. September 2010, 09:46 »
Zitat von: erik
Mit jeder Kernel meinte ich jeden Kernel der auf eine neue HW-Plattform (wobei jetzt mal PC mit nur PIC und PC mit HPET schon zwei verschiedene Plattformen sind) kommt bekommt zu seinem Unterbau (also die fest eingebauten Treibern) ein angepasstes API was es ihm ermöglicht die spezielle HW auch so gut als möglich auszureizen. Das API zu den Applikationen (die Syscalls) bleibt natürlich immer gleich. Ich hoffe jetzt hab ich genau das getroffen was Du meinst.
Das ist so ungefähr das was ich geplant hatte.

Zitat von: erik
Jetzt bin ich aber neugierig, worin unterscheiden sich diese beiden Dinge? Wie entscheidet der Kernel oder jemand anderes darüber welche dieser Möglichkeiten gewählt wird? Gibt es von beiden Sorten so viele Threads wie es CPUs gibt? Warum muss der HLT im Kernel ausgeführt werden?
Sie unterscheiden sich dahingehend, das so Programme immer nur dann ausgeführt werden wenn die CPU nichts zu tun hat, dann wird aber kein Strom gespart. Die Wahl ist ganz einfach, Idle-Threads (ohne "hlt") sind bei mir Priorität 0 und laufen, wie gesagt, nur wenn keine anderen Threads laufen und wenn gar keine Threads in der ready-Queue sind, läuft der richtige Idle-Thread der dann ein "hlt" ausführt.
Ich bin der Meinung das "hlt" nur im Ring0 ausgeführt werden darf, deswegen sind das Kernel-Threads.

Zitat von: erik
Also eine Art Garbage-Collector, interessant das Du so eine Idee umsetzen willst.
Nicht wirklich, denn nen Garbage-Collector rufst du ja nicht auf und dieser Thread ist aus der Not geboren, weil ich keine bessere Idee hatte.
So ist es halt einfacher, sowas wie Stack, Thread-Discriptor und solche Sachen freizugeben.
Der Thread wird per Semaphore aufgeweckt.

Zitat von: erik
Ja ich meine wirklich genau das was ich geschrieben hab. Welche Daten-Strukturen sollte meine CPU denn dafür kennen? Ich bin mir nicht bewusst irgendwelche Dinge vom Speicher genannt zu haben, meine CPU soll, mit Ausnahme der Descriptoren für Segmente und Pages, überhaupt nicht selbstständig auf den Speicher zugreifen. Der Zeitscheiben-Counter ist eh in HW implementiert (ein simpler Downcounter in den der Scheduler immer die Länge der Zeitscheibe des nächsten Thread reinlegt und der bei 0 aufhört zu zählen und eine Yield-Exception generiert also einen Kontext-Switch auslöst durch den dann der Scheduler aktiv wird) und kann daher auch dort manipuliert werden und Exceptions muss die CPU auch so auslösen können. Ein kleiner zusätzlicher Downcounter der die Befehle zählt und bei != 0 die IRQ-Annahme + Zeitscheiben-Counting sperrt ist IMHO keine so große Erweiterung mehr.
Also sowas wie nen APIC, denn was du beschreibst ist kein extra Timer-Chip, der muss in der CPU sitzen.

Zitat von: erik
Weder ARM noch MIPS oder PowerPC sind nur Mikrocontroller! Die beiden letzten sind sogar in 64 Bit verfügbar und wurden schon in sehr großen Super-Computern eingesetzt! Was ist eigentlich an Mikrocontrollern so schlimm?
Naja nen Mikrokontroller der genug Leistung und die Möglichkeit zur Eingabe und zur Bildschirmausgabe hat, ist einfach zu teuer. Ich weiß das es da genügend von gibt, aber das finanzielle spielt da halt auch ne Rolle und nur im Emulator testen wollte ich dann auch nicht. Das ist ein weiterer Grund ich habe schon Schwierigkeiten nen vernünftigen Emulator für ARM zu finden, der unter Windows läuft und nicht alzu schwer zu bedienen ist (da wäre nur Qemu aber selbst kompiliert bekomme ich es nicht und richtig zum Laufen hab ich den ARM Emulator auch noch nicht bekommen).

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #66 am: 28. September 2010, 12:21 »
Hallo,


Sie unterscheiden sich dahingehend, das so Programme immer nur dann ausgeführt werden wenn die CPU nichts zu tun hat, dann wird aber kein Strom gespart.
Definiere mal Bitte "die CPU nichts zu tun hat". Das einzigste Kriterium ist doch das wenn es gar keine "runnable" Threads gibt und da es noch die Threads vom idle-Prozess gibt (die eigentlich niemals blockieren) wird diese Bedingung nie erfüllt.

Die Wahl ist ganz einfach, Idle-Threads (ohne "hlt") sind bei mir Priorität 0 und laufen, wie gesagt, nur wenn keine anderen Threads laufen und wenn gar keine Threads in der ready-Queue sind, läuft der richtige Idle-Thread der dann ein "hlt" ausführt.
Wie kommt es zur zweiten Situation? Warum wird nicht auch in der ersten Situation Energie gespart?
In meinem OS wollte ich das so machen das die idle-Threads immer eine Schleife mit einem HLT-Befehl ausführen also die CPU für ihre Zeitscheibe schlafen lassen (IRQs werden aber weiterhin angenommen). Wenn die Zeitscheibe abgelaufen ist versucht der Scheduler wieder andere Threads laufen zu lassen und wenn es keine anderen gibt dann eben wieder einen idle-Thread. Als Verbesserung könnte der idle-Thread die System-Auslastung erfragen und dann die CPU länger und tiefer schlafen lassen aber diesmal per Syscall so das der Kernel über das aufwecken bestimmen kann aber auch keine IRQs von der CPU akzeptiert werden. Ich könnte aber auch ein DoIdle-Syscall implementieren der vom idle-Thread immer in der Schleife aufgerufen wird und dessen Rückgabewert bestimmt ob der idle-Thread diesen Syscall in der nächsten Zeitscheibe noch mal aufrufen soll (weil es was zu tun gab) oder ob jetzt doch eher HLT dran ist (weil es nichts zu tun gab). In diesem Syscall könnte dann der Kernel entscheiden ob er die aktuelle CPU dazu benutzen möchte um etwas Speicher zu defragmentieren oder ob die CPU besser im Tiefschlaf aufgehoben ist oder ob sie lieber in Bereitschaft (HLT-Befehl im User-Mode) bleiben soll.

Ich bin der Meinung das "hlt" nur im Ring0 ausgeführt werden darf, deswegen sind das Kernel-Threads.
Da bin ich mir jetzt auch nicht sicher, was sagt den das Intel-Manual dazu?

Nicht wirklich, denn nen Garbage-Collector rufst du ja nicht auf und dieser Thread ist aus der Not geboren, weil ich keine bessere Idee hatte.
So ist es halt einfacher, sowas wie Stack, Thread-Discriptor und solche Sachen freizugeben.
Das heißt Du gibst den Speicher erst später frei weil es schwierig ist einen Thread-Descriptor wegzuräumen wenn man das im Kontext eben dieses Threads macht (weil der Thread sich selber gekillt hat).

Also sowas wie nen APIC, denn was du beschreibst ist kein extra Timer-Chip, der muss in der CPU sitzen.
Der Zeitscheiben-Timer ist ein simpler Down-Counter (der Scheduler legt die Zeit rein und der Counter zählt bis 0) und jede CPU hat natürlich einen eigenen. Dieser Counter ist für nichts anderes zu gebrauchen außer die Zeitscheibe eines User-Mode-Threads zu verwalten. Ich bemühe mich meinen CPUs genau die Fähigkeiten zu geben die ich auch in der Praxis benötige, nicht mehr und nicht weniger, für einen vollwertigen x86-Local-APIC hab ich einfach keine Verwendung und über den normalen HW-Timer (der im Chipsatz sitzt und einem HPET sehr ähnlich wird) kann ich keine IRQs an eine bestimme CPU schicken um eben einen bestimmten Thread am Ende seiner Zeitscheibe zu unterbrechen.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #67 am: 29. September 2010, 14:44 »
Zitat von: erik
Definiere mal Bitte "die CPU nichts zu tun hat". Das einzigste Kriterium ist doch das wenn es gar keine "runnable" Threads gibt und da es noch die Threads vom idle-Prozess gibt (die eigentlich niemals blockieren) wird diese Bedingung nie erfüllt.
Mein Idle-Threads tauchen nicht in der Liste auf, von daher kann das funktionieren.

Zitat von: erik
Wie kommt es zur zweiten Situation? Warum wird nicht auch in der ersten Situation Energie gespart?
Die zweite Situation hab ich dir ja oben erklärt. Naja, ich dachte mir halt das es auch Threads geben muss die nur Laufen wenn wirklich kein anderer die CPU braucht und dann muss ja auch nicht unbedingt Energie gespart werden.

Zitat von: erik
Da bin ich mir jetzt auch nicht sicher, was sagt den das Intel-Manual dazu?
Sagt Ring0.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #68 am: 29. September 2010, 17:56 »
Hallo,


Mein Idle-Threads tauchen nicht in der Liste auf
Das macht aber den Scheduler komplizierter als nötig, der muss dan ja normale User-Mode-Threads, User-Mode-Threads die nicht auf der Runnable-Liste stehen und Kernel-Threads (eventuell auch mit und ohne Runnable-Liste) unterstützen. Das wäre mir zu aufwendig, mein Scheduler soll genau eine Art von Threads kennen und die auch immer auf die selbe Art an die CPU lassen. Bei mir dient der idle-Prozess auch dazu das der Scheduler niemals auf eine komplett leere Runnable-Liste stößt (wie ich mehrere Teillisten für die unterschiedlichen Prioritäten verwalte weiß ich noch nicht genau).

Naja, ich dachte mir halt das es auch Threads geben muss die nur Laufen wenn wirklich kein anderer die CPU braucht und dann muss ja auch nicht unbedingt Energie gespart werden.
Schon klar, aber diese Threads (die nicht zum idle-Prozess gehören und echte Arbeit leisten) hätten dann eben nur die zweit niedrigste Priorität, bei mir soll es unmöglich sein das ein Thread auf normalem Weg auf die unterste idle-Priorität konfiguriert werden kann das wird nur beim Kernel-Boot gehen wenn der idle-Prozess vom Boot-Code gebaut wird. Wenn wirklich ein echter idle-Thread dran kommt dann kann auch immer Energie gespart werden.

Sagt Ring0.
Aha, dann würde ich den HLT-Befehl als Syscall anbieten den nur der idle-Prozess benutzen darf.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #69 am: 29. September 2010, 18:40 »
Zitat von: erik
Das macht aber den Scheduler komplizierter als nötig, der muss dan ja normale User-Mode-Threads, User-Mode-Threads die nicht auf der Runnable-Liste stehen und Kernel-Threads (eventuell auch mit und ohne Runnable-Liste) unterstützen. Das wäre mir zu aufwendig, mein Scheduler soll genau eine Art von Threads kennen und die auch immer auf die selbe Art an die CPU lassen. Bei mir dient der idle-Prozess auch dazu das der Scheduler niemals auf eine komplett leere Runnable-Liste stößt (wie ich mehrere Teillisten für die unterschiedlichen Prioritäten verwalte weiß ich noch nicht genau).
So kompliziert ist das gar nicht. Ich habe eine Datenstruktur wo Sachen drin stehen die pro CPU gelten und da ist auch ein Pointer zum entsprechenden Idle-Thread drin.
Ich rufe ne Funktion auf, die mir den Thread mit der höchsten Priorität aus der Ready-Queue holt, gibt die Funktion 0 zurück, wird der Idle-Thread ausgeführt.

Warum einen extra Prozess für das Idlen erstellen?

Zitat von: erik
Aha, dann würde ich den HLT-Befehl als Syscall anbieten den nur der idle-Prozess benutzen darf.
Da hätte ich dann aber ein Problem, wenn ich deine Ideen umsetzen würde. Denn mit deaktivierten Ints (zwecks nicht unterbrechbar) macht der "hlt" nicht viel Sinn.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #70 am: 30. September 2010, 13:06 »
Hallo,


Ich rufe ne Funktion auf, die mir den Thread mit der höchsten Priorität aus der Ready-Queue holt, gibt die Funktion 0 zurück, wird der Idle-Thread ausgeführt.
Dieses prüfen auf 0 ist ein Spezialfall der extra behandelt werden muss (macht den Code größer und tendenziell unübersichtlicher), nebst dessen das der Vergleich auf 0 extra CPU-Zeit kostet. Ich bemühe mich in meiner SW möglichst alles was grundlegend gleich ist auch gleich zu behandeln, das ist IMHO eine wichtige SW-Design-Regel. Sonderfälle kosten nur zusätzlichen Code und jeder zusätzliche Code kann wiederum Fehler enthalten, gerade bei einem Micro-Kernel sollte man bemüht sein die Code-Basis so klein wie möglich zu halten. Dazu kommt das sich in einfachen Code auch nur mit geringerer Wahrscheinlichkeit Fehler einschleichen können wie in komplexen Code.

Warum einen extra Prozess für das Idlen erstellen?
Um eben keinen Sonderfall zu haben. Da ich nur User-Mode-Threads habe müssen auch alle Threads zu einem Prozess gehören. Ich finde die minimale Platzverschwendung für die Prozess-Descriptor-Struktur ist harmloser als an mehreren Stellen im Kernel-Code extra Spezialfallbehandlungen zu implementieren.

Da hätte ich dann aber ein Problem, wenn ich deine Ideen umsetzen würde. Denn mit deaktivierten Ints (zwecks nicht unterbrechbar) macht der "hlt" nicht viel Sinn.
Tja, das ist eben eine Designschwäche von x86. ;)
Für diesen speziellen Syscall sollte man natürlich die IRQs freischalten, das würde auch nicht mit CPU-lokalen Kernel-Mode-Stacks kollidieren da die CPU ja für die gesamte Dauer von HLT im Besitzt bleibt.

Auf meiner CPU soll es 3 Arten solcher Befehle geben PAUSE, HLT und SLEEP. Der PAUSE-Befehl dient dazu die CPU kurz, etwa 10 bis 100 Takte, nichts tun zu lassen (das spart nur wenig Energie da ja alles aktiv bleibt) und dient dazu z.B. in einer Schleife auf einen Lock zu warten ohne das man gleich die ganze Zeitscheibe abgeben möchte, dieser Befehl funktioniert in allen CPU-Modi. Der HLT-Befehl darf nur im User-Mode benutzt werden und lässt die CPU tiefer schlafen aber noch auf externe IRQs reagieren (dabei wird diese CPU sogar bevorzugt weil sie mit HLT auch die niedrigste Priorität meldet), auch der Zeitscheibencounter läuft weiter und löst am Ende auch ne Yield-Exception aus so das ein HLT niemals die CPU ganz blockiert. Der SLEEP-Befehl darf nur im System-Mode benutzt werden und damit wird die CPU in einen sehr tiefen Schlaf versetzt, wo z.B. auch der Takt ganz abgeschaltet wird, um möglichst viel Energie zu sparen. Aufwecken funktioniert beim SLEEP aber nur wenn diese CPU von einer anderen CPU speziell angetriggert wird, der Kernel entscheidet also darüber welche CPUs sich wie lange im Tiefschlaf befinden sollen.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #71 am: 30. September 2010, 13:21 »
Ich glaube, du hast bisher vergessen zu erwähnen, warum du Ring-0-Tasks für böse hältst. Das ist nämliche eine einfache Lösung für den Idle-Task, und die korrekte noch dazu. ;)

hlt im Userspace halte ich für Blödsinn. Wie soll denn der Userspace sagen können, ob es auf dieser CPU gerade nichts sinnvolles zu tun gibt? Ein Syscall "Hey Kernel, ich hab grad nichts zu tun" halte ich für sinnvoller. Und dann kann der Kernel entscheiden, ob man die CPU wirklich schlafen schicken sollte oder ob einfach erstmal eine anderer Task drankommt. Andere Tasks warten zu lassen, weil ein Thread meint, die CPU bis zum nächsten Timerinterrupt mit Nichtstun beschäftigen zu müssen, klingt jedenfalls nicht besonders hilfreich.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #72 am: 30. September 2010, 19:56 »
Hallo,


Ich glaube, du hast bisher vergessen zu erwähnen, warum du Ring-0-Tasks für böse hältst.
Stimmt, das habe ich noch nicht.
Ich halte System-Mode/Ring-0-Threads/Tasks nicht grundsätzlich für böse, ich betrachte es nur als Design-Ziel das mein Kernel keinerlei eigene Aktivitäten entfaltet. Außerdem würde ein unterbrechbarer System-Mode meine CPU komplizierter machen: ich habe nur ein einziges Set an Schattenregistern wogegen z.B. ARM für jeden der verschiedenen System-Modi ein eigenes Set hat aber dafür hab ich einfach zu viele Register und den x86-Weg das die CPU eigenständig in den Speicher/Stack schreibt möchte ich nicht gehen. Daraus ergibt sich das HLT ein User-Mode-Befehl ist und SLEEP ein System-Mode-Befehl. Und weil ich der Meinung bin keinen unterbrechbaren System-Mode zu brauchen (mit den sich daraus ergebenen Rahmenbedingungen komme ich IMHO sehr gut zurecht) erkläre ich das einfach zur Plattform-Eigenschaft. ;)

Das ist nämliche eine einfache Lösung für den Idle-Task, und die korrekte noch dazu.
Dass das eine einfache Lösung ist stimmt natürlich (zumindest für x86) aber warum das die korrekte Lösung ist musst Du mir mal erklären.

hlt im Userspace halte ich für Blödsinn. Wie soll denn der Userspace sagen können, ob es auf dieser CPU gerade nichts sinnvolles zu tun gibt? ....
Du hast wahrscheinlich nicht 5 Artikel davor geschaut (soll kein Vorwurf sein) :
Ich könnte aber auch ein DoIdle-Syscall implementieren der vom idle-Thread immer in der Schleife aufgerufen wird und dessen Rückgabewert bestimmt ob der idle-Thread diesen Syscall in der nächsten Zeitscheibe noch mal aufrufen soll (weil es was zu tun gab) oder ob jetzt doch eher HLT dran ist (weil es nichts zu tun gab). In diesem Syscall könnte dann der Kernel entscheiden ob er die aktuelle CPU dazu benutzen möchte um etwas Speicher zu defragmentieren oder ob die CPU besser im Tiefschlaf aufgehoben ist oder ob sie lieber in Bereitschaft (HLT-Befehl im User-Mode) bleiben soll.
Zusätzlich möchte ich ein Flag implementieren das den HLT-Befehl freischaltet und dieses wird der Kernel (bzw. der Boot-Code) nur für den idle-Prozess setzen.

Wie soll denn der Userspace sagen können, ob es auf dieser CPU gerade nichts sinnvolles zu tun gibt? ....
Das entscheidet nicht der User-Mode-Code selber sondern dessen idle-Priorität, die idle-Threads kommen eben nur dran wenn es nichts zu tun gibt.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #73 am: 30. September 2010, 22:18 »
Naja, elegant ist imho was anderes, aber wenn es ein Workaround für Einschränkungen der Hardware ist, lass ich's dir mal durchgehen. ;)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #74 am: 01. October 2010, 01:24 »
Das ist nämliche eine einfache Lösung für den Idle-Task, und die korrekte noch dazu.
Dass das eine einfache Lösung ist stimmt natürlich (zumindest für x86) aber warum das die korrekte Lösung ist musst Du mir mal erklären.
Auf x86 ist ein HLT ein Ring0-Befehl und kann daher nur von einem Ring0-Thread ausgeführt werden. ;-)

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #75 am: 01. October 2010, 09:10 »
Hallo,


Naja, elegant ist imho was anderes, aber wenn es ein Workaround für Einschränkungen der Hardware ist, lass ich's dir mal durchgehen.
Was genau meinst Du damit? Ich finde meine Lösung schon recht elegant.


Auf x86 ist ein HLT ein Ring0-Befehl und kann daher nur von einem Ring0-Thread ausgeführt werden.
Das ist mir bewusst aber warum ist es korrekt das ein HLT-Befehl im Ring-0/System-Mode ausgeführt werden soll? Gerade weil doch der HLT-Befehl von externen Interrupts u.ä. unterbrochen werden können muss (im Gegensatz zu irgendwelchen Schlaf-Modi die es bei x86 ja auch gibt) ist es meiner Meinung nach nicht logisch das nur ein Kernel diesen Befehl ausführen können soll (natürlich sollte der Kernel die Ausführung dieses Befehls reglementieren können). Alle üblichen Wechsel in den Ring-0 (INT-Befehle, IRQs und Exceptions) deaktivieren auf x86 immer das IE-Flag womit zumindest suggeriert wird das der Ring-0 nicht per Default unterbrechbar ist. Es ist aus meiner persönlichen Sicht ein kleines x86-Design-Mysterium das der HLT-Befehl zwar in einem unterbrechbaren Umfeld sein muss (sonst käme die CPU da ja nicht mehr raus) aber nur in einem Umfeld benutzt werden kann das per Default nicht unterbrechbar ist.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #76 am: 01. October 2010, 12:20 »
Naja, elegant ist imho was anderes, aber wenn es ein Workaround für Einschränkungen der Hardware ist, lass ich's dir mal durchgehen.
Was genau meinst Du damit? Ich finde meine Lösung schon recht elegant.
Du hast also einen Befehl, der nur im Userspace geht. Deswegen fragt der entsprechende Userspace-Prozess erstmal beim Kernel nach, ob er diesen Befehl benutzen soll. Damit das kein Userspaceprozess macht, der es nicht machen sollte, baust du ein Flag ein, mit dem der Kernel dem Userspaceprozess explizit erlauben muss, den Befehl auch auszuführen, nachdem er den Kernel gefragt hat, ob er es tun soll.

Ist das nicht ein bisschen von hinten durch die Brust ins Auge?

Zitat
Gerade weil doch der HLT-Befehl von externen Interrupts u.ä. unterbrochen werden können muss (im Gegensatz zu irgendwelchen Schlaf-Modi die es bei x86 ja auch gibt) ist es meiner Meinung nach nicht logisch das nur ein Kernel diesen Befehl ausführen können soll (natürlich sollte der Kernel die Ausführung dieses Befehls reglementieren können). Alle üblichen Wechsel in den Ring-0 (INT-Befehle, IRQs und Exceptions) deaktivieren auf x86 immer das IE-Flag womit zumindest suggeriert wird das der Ring-0 nicht per Default unterbrechbar ist. Es ist aus meiner persönlichen Sicht ein kleines x86-Design-Mysterium das der HLT-Befehl zwar in einem unterbrechbaren Umfeld sein muss (sonst käme die CPU da ja nicht mehr raus) aber nur in einem Umfeld benutzt werden kann das per Default nicht unterbrechbar ist.
Ich weiß nicht wo du diesen Default hernimmst, aber ich sehe in der Architektur keine besondere Bevorzugung von Interrupt Gates gegenüber Trap Gates (wobei der Unterschied ja bekanntlich der Wert von IF ist). Wenn du Interrupt Gates benutzt, aber eigentlich Trap Gates haben willst, bist du vollkommen selber schuld.

Ach, und ein iret nach Ring 0, also in einen Kernel-Task, ist so unüblich auch wieder nicht... Nicht jeder Kernel läuft komplett in Interrupthandlern ab.
« Letzte Änderung: 01. October 2010, 12:23 von taljeth »
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #77 am: 01. October 2010, 14:51 »
Nun, HLT ändert einen internen Zustand der CPU - wie ein CLI auch. Außerdem hält HLT die CPU solange an, bis ein externes, nicht vom Kernel ausgehendes(!) Ereignis auftritt.

Nur weil mein VLC in der Lage ist, die Videoframes schneller zu dekodieren als nötig, hat er noch lange nicht das Recht, meine CPU für unbekannt lange Zeit anzuhalten. Das soll mal schön der Kernel machen, wenn er der Meinung ist, dass wirklich nichts weiter auf dieser CPU ansteht.

Beachte: Der wichtige Punkt ist das unbekannt. Das kann auch unendlich sein (für Interrupts abgeschaltet, aus welchem Grund auch immer). Überhaupt sollte ein Userspace-Task die CPU nicht anhalten können, auch nicht für einen Zeitraum innerhalb der eigenen Zeitscheibe. Das ist genauso elegant wie busy waiting, nur energieeffizienter. ("Wenn ich schon nichts tun kann, soll es bitte auch kein anderer können.") Der Task sollte die Zeitscheibe lieber dem System zur Verfügung stellen, was dann irgendetwas damit anstellen kann, wie z.B. die CPU anhalten, wenn kein anderer möchte.

Für den Standardfall (d.h. größtenteils Leerlauf im System) spielt das keine Rolle, ob die CPU nun vom (einzigen) Programm oder vom Kernel angehalten wird, aber unter Last verschenkst du damit einiges an CPU-Zyklen.

Gruß,
Sebastian

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #78 am: 01. October 2010, 15:17 »
Zitat von: erik
Alle üblichen Wechsel in den Ring-0 (INT-Befehle, IRQs und Exceptions) deaktivieren auf x86 immer das IE-Flag womit zumindest suggeriert wird das der Ring-0 nicht per Default unterbrechbar ist. Es ist aus meiner persönlichen Sicht ein kleines x86-Design-Mysterium das der HLT-Befehl zwar in einem unterbrechbaren Umfeld sein muss (sonst käme die CPU da ja nicht mehr raus) aber nur in einem Umfeld benutzt werden kann das per Default nicht unterbrechbar ist.
Das ist, wie dir taljeth ja schon gesagt hat, nicht korrekt.

Was mir noch aufgefallen ist, es dürfte verdammt schwierig werden andere OS auf deine Platform zu portieren, wenn dein System-Mode Grundsätzlich nicht unterbrechbar ist.

Ansonsten seh ich immernoch kein Problem damit das "hlt" nur im Ring0 ausgeführt werden kann, genauso wenig damit, das meine Idle-Threads auch Kernel-Threads und keine kompletten Prozesse sind.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #79 am: 01. October 2010, 15:21 »
Hallo,


Ist das nicht ein bisschen von hinten durch die Brust ins Auge?
Ein bisschen hast Du schon recht aber ich habe eben die Plattform-Eigenschaft das der System-Mode grundsätzlich nicht unterbrechbar ist (damit ich die CPU möglichst einfach halten kann) und von daher muss der HLT-Befehl zwangsläufig in den User-Mode. Mag sein das dies eine Stelle ist wo mir mein Konzept eine winzige Unannehmlichkeit aufzwingt aber als so schlimm empfinde ich das an dieser Stelle gar nicht, der DoIdle-Syscall macht ja schließlich noch andere Sachen (den hätte ich sowieso). Ein unterbrechbarer System-Mode würde mir auf jeden Fall deutlich mehr Unannehmlichkeiten aufzwingen (komplexeres Register-File in der CPU und einen komplexeren Scheduler wenn er verschiedene Arten von Threads können soll usw.) und ich kann da einfach keinen Vorteil erkennen. Bis jetzt hab ich noch kein Killer-Argument für Kernel-Mode-Threads bei Micro-Kerneln gesehen.

Zu den Freischalt-Flags muss ich sagen das ich eh ein Controll-Register (in jedem CPU-Kern) dafür benötige, viele Arten von Befehlen müssen erst Freigeschalten werden (aus recht unterschiedlichen Gründen) und von daher macht dort ein Bit mehr auch nichts mehr aus. Außerdem werden diese Bits bereits im Decoder verarbeitet und kosten so im eigentlichen CPU-Kern keine zusätzliche Logik, nicht freigeschaltete Befehle werden vom Deocer einfach als Illegal-OpCode decodiert.

Ich weiß nicht wo du diesen Default hernimmst, aber ich sehe in der Architektur keine besondere Bevorzugung von Interrupt Gates gegenüber Trap Gates (wobei der Unterschied ja bekanntlich der Wert von IF ist). Wenn du Interrupt Gates benutzt, aber eigentlich Trap Gates haben willst, bist du vollkommen selber schuld.
Ich schätze die Zeit hat dann doch bereits ein paar Lücken in meine x86-Kenntnisse gefressen.
Normalerweise ist es aber schon besser wenn beim Einsprung in den Kernel erst mal die IRQs aus sind und der Kernel dann die IRQs wieder freischaltet wenn es sicher ist (anders habe ich das auch noch nie gesehen). Wenn wir an den Real-Mode denken dann ist das IE-Flag auch per Default gelöscht wenn in einen Interrupt/IRQ/Exception-Handler gesprungen wird. Wie sieht das eigentlich im Long-Mode oder bei den SYSCALL/SYSENTER-Befehlen aus?

Ach, und ein iret nach Ring 0, also in einen Kernel-Task, ist so unüblich auch wieder nicht... Nicht jeder Kernel läuft komplett in Interrupthandlern ab.
Das ist mir vollkommen klar, ich weiß das es viele Kernel dieser Art gibt. Für mein OS möchte ich das aber nicht, ich sehe bei einem Micro-Kernel dafür einfach keine Notwendigkeit. Und wie gesagt, ich möchte meine CPU so einfach wie möglich halten und da ist ein IRET in den System-Mode nicht gerade förderlich.

Wimre ist doch der tyndur-Kernel auch nicht unterbrechbar, oder?


HLT ändert einen internen Zustand der CPU - wie ein CLI auch.
Welchen Zustand ändert HLT? Und wo ist da die Gemeinsamkeit mit CLI?

Außerdem hält HLT die CPU solange an, bis ein externes, nicht vom Kernel ausgehendes(!) Ereignis auftritt.
Ganz recht, aber wenn das im User-Mode gemacht wird dann kommt dieses Ereignis spätestens mit dem Ablaufen der Zeitscheibe.

Nur weil mein VLC in der Lage ist, die Videoframes schneller zu dekodieren als nötig, hat er noch lange nicht das Recht, meine CPU für unbekannt lange Zeit anzuhalten. Das soll mal schön der Kernel machen, wenn er der Meinung ist, dass wirklich nichts weiter auf dieser CPU ansteht.
Ich bin völlig Deiner Meinung, hab ich das irgendwo mal anders dargelegt?

Beachte: Der wichtige Punkt ist das unbekannt. Das kann auch unendlich sein (für Interrupts abgeschaltet, aus welchem Grund auch immer).
Das kann bei mir deswegen nicht unendlich sein weil es auf meiner CPU keinen Weg gibt die IRQs im User-Mode dauerhaft abzuschalten (selbst der Kernel kann da nichts drehen). Ein User-Mode-Thread ist spätestens mit Ablauf seiner Zeitscheibe die CPU wieder los!

Überhaupt sollte ein Userspace-Task die CPU nicht anhalten können, auch nicht für einen Zeitraum innerhalb der eigenen Zeitscheibe. Das ist genauso elegant wie busy waiting, nur energieeffizienter.
Deswegen muss das ja auch freigeschaltet werden damit nur die Threads des idle-Prozess das dürfen.

Für den Standardfall (d.h. größtenteils Leerlauf im System) spielt das keine Rolle, ob die CPU nun vom (einzigen) Programm oder vom Kernel angehalten wird, aber unter Last verschenkst du damit einiges an CPU-Zyklen.
Wo bitte werden da CPU-Zyklen verschenkt? Der HLT-Befehl ist doch nicht ineffizienter nur weil er im User-Mode arbeitet. Außerdem werden die Threads des idle-Prozess unter Last gar nicht erst aufgerufen (wegen deren niedrigerer Priorität.)


Was mir noch aufgefallen ist, es dürfte verdammt schwierig werden andere OS auf deine Platform zu portieren, wenn dein System-Mode Grundsätzlich nicht unterbrechbar ist.
Das ist auch nicht mein Ziel, ich betrachte Plattform und OS als eine Einheit.

Ansonsten seh ich immernoch kein Problem damit das "hlt" nur im Ring0 ausgeführt werden kann, genauso wenig damit, das meine Idle-Threads auch Kernel-Threads und keine kompletten Prozesse sind.
Ich sehe eben 2 verschiedene Arten von Threads und um diese auf die CPU zu bringen benötigst Du 2 verschiedene Mechanismen (auch wenn die Unterschiede nur marginal sind).


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

 

Einloggen