Autor Thema: Shared Memory  (Gelesen 36200 mal)

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #80 am: 01. October 2010, 15:30 »
Hallo,

HLT ändert einen internen Zustand der CPU - wie ein CLI auch.
Welchen Zustand ändert HLT? Und wo ist da die Gemeinsamkeit mit CLI?
Welchen, ist egal. CLI sorgt dafür, dass keine Interrupts mehr gemeldet werden und HLT sorgt dafür, dass die CPU nichts mehr tut, bis ein Interrupt auftritt. Das sind zwei Zustände, die dem System obliegen sollten, nicht irgendwelchen Threads.

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.
Eleganter ist es, wenn für diese Zeit die CPU nicht angehalten wird, sondern ein anderer Thread noch die Möglichkeit kriegt, zu arbeiten.

Ü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.
Das entspricht aber deinem SLEEP - ein Prozess kann sagen "hey, ich muss grad mal 10-100 Takte warten" und hält dann die CPU an. Sofern die Endzeit noch in seine Zeitscheibe fällt.

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.)
Nein, wenn ein Userspaceprogramm die CPU anhalten kann, so wird damit potentiell die Möglichkeit verschenkt, den Rest der Zeitscheibe einem bedürftigem Thread zukommen zu lassen.

Bei dir gibst du dem Idle-Thread damit einen Teil der Ring0-Rechte über ein Flag. Userspace darf auch bei dir kein HLT machen.

So, jetzt ist wieder der Punkt, ab dem man Haare spalten kann. ;-)

Gruß,
Sebastian

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #81 am: 01. October 2010, 15:40 »
Zitat von: erik
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).
Jetzt sind wir zwar wirklich beim Haare spalten, aber egal.

Der für mich einzige wirkliche Unterschied zw. Kernel- und User-Threads liegt in der Erstellung, wenn man den Stack aufbauen muss, ansonsten ist es auch meinem Scheduler egal (und er weis es nicht mal direkt) was das für ein Thread ist.

Zitat von: erik
Bis jetzt hab ich noch kein Killer-Argument für Kernel-Mode-Threads bei Micro-Kerneln gesehen.
Wie willst du Threads/Prozesse beenden und ihre Ressourcen freigeben?

Zitat von: erik
Deswegen muss das ja auch freigeschaltet werden damit nur die Threads des idle-Prozess das dürfen.
Darauf möchte ich jetzt mit etwas antworten, was du geschrieben hast:
Zitat von: erik
... als an mehreren Stellen im Kernel-Code extra Spezialfallbehandlungen zu implementieren.

erik.vikinger

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


Eleganter ist es, wenn für diese Zeit die CPU nicht angehalten wird, sondern ein anderer Thread noch die Möglichkeit kriegt, zu arbeiten.
Ich hab doch jetzt nun mehrmals geschrieben das die idle-Threads nur dann dran kommen wenn wirklich niemand sonst will, das wird über die Prioritäten gemanaged.

Das entspricht aber deinem SLEEP - ein Prozess kann sagen "hey, ich muss grad mal 10-100 Takte warten" und hält dann die CPU an. Sofern die Endzeit noch in seine Zeitscheibe fällt.
Du meinst wohl PAUSE (nicht SLEEP, der macht noch ganz andere Sachen). Aber auch PAUSE hat nicht so viel gemeinsam mit HLT. HLT wartet bis zum nächsten Ereignis und PAUSE nur für ein paar Takte.

Nein, wenn ein Userspaceprogramm die CPU anhalten kann, so wird damit potentiell die Möglichkeit verschenkt, den Rest der Zeitscheibe einem bedürftigem Thread zukommen zu lassen.
Darf ich Dich noch mal an die Prioritäten erinnern? Die Threads des idle-Prozess kommen nur dran wenn es wirklichen gar keinen bedürftigen Thread gibt!

Bei dir gibst du dem Idle-Thread damit einen Teil der Ring0-Rechte über ein Flag. Userspace darf auch bei dir kein HLT machen.
Genau so ist es, das ist eben der Preis den ich zahlen muss damit ich keinen unterbrechbaren System-Mode brauche aber ein Bit in irgendeinem Controll-Register in der CPU kostet nun wirklich nicht viel.

So, jetzt ist wieder der Punkt, ab dem man Haare spalten kann. ;-)
Ich liebe es Haare zu spalten! :-D



Der für mich einzige wirkliche Unterschied zw. Kernel- und User-Threads liegt in der Erstellung, wenn man den Stack aufbauen muss, ansonsten ist es auch meinem Scheduler egal (und er weis es nicht mal direkt) was das für ein Thread ist.
Es bleibt eine Sonderbehandlung, egal ob im Scheduler oder in CreateThread().

Wie willst du Threads/Prozesse beenden und ihre Ressourcen freigeben?
Mit einem kfree(), ich verstehe nicht worauf Deine Frage abziehlt.

Zitat von: erik
Deswegen muss das ja auch freigeschaltet werden damit nur die Threads des idle-Prozess das dürfen.
Darauf möchte ich jetzt mit etwas antworten, was du geschrieben hast:
Zitat von: erik
... als an mehreren Stellen im Kernel-Code extra Spezialfallbehandlungen zu implementieren.
Dann antworte ich auch mit etwas das ich selber geschrieben hab:
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.
Ich meine die 3 Worte zwischen den Klammern. Der idle-Prozess wird bei mir ja nicht zur Laufzeit per CreateProcess() gebaut (hab ich auch in dieser Diskussion erklärt) sondern ist schon da wenn der Kernel zum Leben erwacht.


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 #83 am: 01. October 2010, 17:42 »
Zitat von: erik
Mit einem kfree(), ich verstehe nicht worauf Deine Frage abziehlt.
Naja, ich finde/fand es immer nicht wirklich einfach diese ganzen Ressourcen von dem Thread freigeben zu lassen der ja noch läuft (wie gibt man denn Stack und PageTables/Dir frei wenn der Thread noch läuft) und das wäre halt ein guter Grund für mind. einen Kernel-Thread.

Zitat von: erik
Ich meine die 3 Worte zwischen den Klammern. Der idle-Prozess wird bei mir ja nicht zur Laufzeit per CreateProcess() gebaut (hab ich auch in dieser Diskussion erklärt) sondern ist schon da wenn der Kernel zum Leben erwacht.
Ändert ja nichts daran, das du dafür ne Extra-Behandlung, wo auch immer, benötigst und du ja geschrieben hast, dass das nicht so toll ist zwecks Fehler.
Der Punkt ist einfach, der Idle-Thread ist halt was "besonderes" und wo ich den nun mit extra Code besonders behandle ist doch egal (ob Scheduler oder Boot-Code).

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #84 am: 01. October 2010, 17:42 »
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 [...]
Wie gesagt, ich lass es dir als einen Workaround für die Einschränkungen der Hardware durchgehen. Aber erzähl mir nichts von elegant. Auf x86 gibt es jedenfalls keinen Grund, das so zu machen, weil es da diese Einschränkungen der Hardware nicht gibt.

Zitat
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 du dann mal was neues sehen willst, empfehle ich zur Lektüre trap_init() in /usr/src/linux/arch/x86/kernel/traps_32.c - lies und staune. ;)

Zitat
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?
Das mit dem Real Mode ist schon richtig. Da bleibt aber auch nicht viel anderes übrig, wenn man nur eine Art von Interrupthandlern zur Verfügung stellt.

Laut Intel-Manual schaltet sysenter IF aus, während syscall eine vom OS definierten Maske für eflags benutzt.

Zitat
Wimre ist doch der tyndur-Kernel auch nicht unterbrechbar, oder?
Er wird nicht preempted, ja. Aber kooperativ machen wir es an bestimmten Stellen.

Wie ist das eigentlich dann bei dir, wenn im Kernel eine Exception passiert? Ist die dann grundsätzlich nicht behebbar? Ansonsten müsstest du ja quasi nach einem Interrupt in einen Ring-0-Task zurückkehren und hättest damit schon alles wesentliche, was auch einen unterbrechbaren Kernel erlaubt, oder?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #85 am: 01. October 2010, 17:46 »
Zitat von: erik
Mit einem kfree(), ich verstehe nicht worauf Deine Frage abziehlt.
Naja, ich finde/fand es immer nicht wirklich einfach diese ganzen Ressourcen von dem Thread freigeben zu lassen der ja noch läuft (wie gibt man denn Stack und PageTables/Dir frei wenn der Thread noch läuft) und das wäre halt ein guter Grund für mind. einen Kernel-Thread.
Naja, dafür würde ich nicht groß mit einem Thread anfangen. Das freizugebende Zeug in irgendeine Queue stecken und beim nächstbesten Interrupt (dann in anderem Kontext) kann man freigeben.
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 #86 am: 01. October 2010, 18:09 »
Hallo,


Naja, ich finde/fand es immer nicht wirklich einfach diese ganzen Ressourcen von dem Thread freigeben zu lassen der ja noch läuft (wie gibt man denn Stack und PageTables/Dir frei wenn der Thread noch läuft) und das wäre halt ein guter Grund für mind. einen Kernel-Thread.
Dafür könnte ich ja meinen DoIdle-Syscall benutzen. Aber ich glaube nicht dass das nötig ist, ich sehe einfach kein Problem darin das ein Thread seine eigenen Ressourcen wegräumt.

der Idle-Thread ist halt was "besonderes" und wo ich den nun mit extra Code besonders behandle ist doch egal (ob Scheduler oder Boot-Code).
Den Boot-Code muss ich eh extra schreiben und der kostet zur OS-Laufzeit auch keinen einzigen Takt extra.


Wie gesagt, ich lass es dir als einen Workaround für die Einschränkungen der Hardware durchgehen. Aber erzähl mir nichts von elegant. Auf x86 gibt es jedenfalls keinen Grund, das so zu machen, weil es da diese Einschränkungen der Hardware nicht gibt.
Ja Okay, besonders elegant ist der HLT im User-Mode nicht aber ich sehe darin keine Einschränkung oder irgendwelche Nachteile (bist Du da anderer Meinung?) sondern einfach nur eine kleine Abweichung vom üblichen Weg.

Wenn du dann mal was neues sehen willst, ....
Offensichtlich ist meine Kenntnis von dieser Welt nicht absolut vollständig. ;)

Laut Intel-Manual schaltet sysenter IF aus, während syscall eine vom OS definierten Maske für eflags benutzt.
Aha, sagen wir es gibt eine leichte Präferenz dafür mit ausgeschalteten IRQs in einen System-Mode zu wechseln, sieh Dir dazu auch mal andere CPUs an bei den meisten dürfte das der Normalfall sein. Es ist eben in den meisten (wenn auch nicht allen) Situationen von Vorteil wenn die IRQs erst mal aus sind und der Kernel dann selber entscheiden darf. Für meine Plattform (da zähle ich das OS mal mit) sehe ich einfach nur keine Notwendigkeit für einen unterbrechbaren System-Mode also wird es keine Möglichkeit geben IRQs im System-Mode anzuschalten.

Zitat
Wimre ist doch der tyndur-Kernel auch nicht unterbrechbar, oder?
Er wird nicht preempted, ja. Aber kooperativ machen wir es an bestimmten Stellen.
:-D

Wie ist das eigentlich dann bei dir, wenn im Kernel eine Exception passiert? Ist die dann grundsätzlich nicht behebbar?
Ja, dann soll die CPU in einen Double-Fault-Shut-Down-Mode gehen und eine Nachricht an einen dafür zuständigen Controller im Chipsatz schicken. Dieser Controller löst dann einen normalen IRQ (mit hoher Priorität) aus welcher von irgend einer der anderen CPUs verarbeitet wird, der IRQ-Handler muss dann sehen was los war und diese Infos ins System-HW-Log schreiben um danach eine Kernel-Panic auszulösen. Exceptions im Kernel sind bei mir schwere Fehler und bedeuten das im Kernel-Code Fehler drin sind. Da ich keine Kernel-Mode-Threads o.ä. hab sehe ich auch darin keine Einschränkung oder irgendwelche Nachteile.


mir ist da noch was eingefallen:

es dürfte verdammt schwierig werden andere OS auf deine Platform zu portieren, wenn dein System-Mode Grundsätzlich nicht unterbrechbar ist.
Schon allein die Segmentierung wird das Portieren anderer OSe sehr zuverlässig verhindern. Ich will eben mal ganz andere Wege gehen was Speichermanagement und solche Dinge anbelangt. Normale Programme hingegen möchte ich schon gerne Portieren und da sehe ich auch keine unüberwindbaren Probleme sobald ich es schaffe einen vernünftigen Compiler und gescheite Librarys anzubieten.

das meine Idle-Threads auch Kernel-Threads und keine kompletten Prozesse sind.
Das bedeutet aber das mindestens CreateThread() und KillThread() doppelt oder zumindest mit verschiedenen Ausführungspfaden da sein müssen.


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 #87 am: 01. October 2010, 18:24 »
Dafür könnte ich ja meinen DoIdle-Syscall benutzen. Aber ich glaube nicht dass das nötig ist, ich sehe einfach kein Problem darin das ein Thread seine eigenen Ressourcen wegräumt.
Naja, den Stack, auf dem man grad läuft, sollte man vielleicht nicht sofort freigeben (vorausgesetzt man benutzt einen Kernelstack pro Thread, ansonsten stellt sich das Problem natürlich nicht).

Zitat
Ja, dann soll die CPU in einen Double-Fault-Shut-Down-Mode gehen und eine Nachricht an einen dafür zuständigen Controller im Chipsatz schicken. Dieser Controller löst dann einen normalen IRQ (mit hoher Priorität) aus welcher von irgend einer der anderen CPUs verarbeitet wird, der IRQ-Handler muss dann sehen was los war und diese Infos ins System-HW-Log schreiben um danach eine Kernel-Panic auszulösen. Exceptions im Kernel sind bei mir schwere Fehler und bedeuten das im Kernel-Code Fehler drin sind. Da ich keine Kernel-Mode-Threads o.ä. hab sehe ich auch darin keine Einschränkung oder irgendwelche Nachteile.
Ja, solange du dein OS als untrennbaren Bestandteil der Plattform siehst, lässt sich das alles rechtfertigen. Es ist halt alles recht starr, so dass du die Hardware gleich mitändern musst, wenn dir das OS nicht mehr gefällt.

Zitat
Schon allein die Segmentierung wird das Portieren anderer OSe sehr zuverlässig verhindern. Ich will eben mal ganz andere Wege gehen was Speichermanagement und solche Dinge anbelangt.
Och, beim i386 hat man es auch sehr erfolgreich geschafft, die Segmentierung zu ignorieren. Warum sollte das bei deiner Architektur nicht klappen?

Deine anderen Entscheidungen, die praktisch nur einen Mikrokernel zulassen, blockieren das ganze wohl effektiver.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #88 am: 01. October 2010, 19:11 »
Zitat von: erik
Das bedeutet aber das mindestens CreateThread() und KillThread() doppelt oder zumindest mit verschiedenen Ausführungspfaden da sein müssen.
Nope, nur CreateThread() (und selbst das könnte ich verhindern, denn der Unterschied ist wirklich minimal bzw. werde ich das bald über ein Flag machen => läuft auf eine if-Schleife hinaus mit einmal 5 Zeilen und einmal 3 Zeilen Code) und KillThread interessiert es wieder gar nicht was für ein Thread das ist, da man eh auf ungültige Werte prüfen sollte.

Zitat von: erik
Dafür könnte ich ja meinen DoIdle-Syscall benutzen. Aber ich glaube nicht dass das nötig ist, ich sehe einfach kein Problem darin das ein Thread seine eigenen Ressourcen wegräumt.
Da brauchst du dann aber ein wirklich gutes kfree(). Denn wenn auf allen CPUs zur gleichen Zeit Threads beendet werden und diese ihre Ressourcen (je nach dem wie viele das sind, könnte das auch mal dauern) freigeben, müsstest du ja irgendwo einen Lock (mind.) haben und da sind wir dann wieder da was man als lange empfindet. Denn in der Zeit kann ja nichts anderes gemacht werden, da ja dein Kernel nicht unterbrechbar ist.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #89 am: 01. October 2010, 19:55 »
Hallo,


Naja, den Stack, auf dem man grad läuft, sollte man vielleicht nicht sofort freigeben (vorausgesetzt man benutzt einen Kernelstack pro Thread, ansonsten stellt sich das Problem natürlich nicht).
Das ist einer der Gründe warum ich im System-Mode einen CPU-verwalteten Stack haben möchte.

Ja, solange du dein OS als untrennbaren Bestandteil der Plattform siehst, lässt sich das alles rechtfertigen. Es ist halt alles recht starr, so dass du die Hardware gleich mitändern musst, wenn dir das OS nicht mehr gefällt.
Es geht mir weniger ums rechtfertigen, es geht mir darum das ich im VHDL-Code für die CPU nichts implementieren möchte was ich im Assembler/C-Code für das OS nicht auch benutze. Mir ist klar das dadurch meine Plattform nicht sonderlich flexibel sein wird aber schlussendlich brauche ich auch nur einen Weg um mein Ziel zu erreichen. Solange dieser Weg ein guter Weg ist bin ich damit zufrieden. dieser Weg wird mir wohl sehr schnelles IPC und durchgehendes Zero-Copy ermöglichen so das ich pro CPU-Takt sicher eine recht hohe Performance erreichen werde. Sollte ich tatsächlich konzeptionelle Probleme im OS oder in der Plattform finden bedeutet das natürlich das mit hoher Wahrscheinlichkeit das andere auch geändert werden muss.

Och, beim i386 hat man es auch sehr erfolgreich geschafft, die Segmentierung zu ignorieren. Warum sollte das bei deiner Architektur nicht klappen?
Dann wirst Du auch auf das Paging verzichten müssen (zumindest zum Speicherschutz), auf meiner Plattform gibt es nur ein Paging-Directory auf das alle CPUs zugreifen und zum wechseln muss man vielleicht sogar das Paging kurz abschalten (macht sich wahrscheinlich im VHDL-Code leichter wenn man nicht in ein aktives System eingreifen muss). Meine Segmente wird man wohl auch nicht so ohne weiteres auf Flat-Memory-Simulation umstellen können, nebst dessen das im System-Mode erstmal direkt mit den physischen Adressen gearbeitet wird (außer für den System-Mode-Stack der liegt in einem CPU-spezifischen Segment). Es ist sicher nicht gänzlich unmöglich auf meiner Plattform ein OS ohne Segmentierung laufen zu lassen aber dafür ist meine Plattform einfach nicht konzipiert und dementsprechend umständlich wird dieses Unterfangen werden. Es ist sicher auch extrem schwierig mein OS auf ner anderen Plattform laufen zu lassen (selbst i386 könnte schwierig werden), es wird einfach zu anhängig von den speziellen Features meiner Plattform sein.
Du nimmst ja auch keinen Schraubendreher um einen Nagel in die Wand zu klopfen obwohl man das damit schon irgendwie hinbekommen kann. Oder doch? ;)

Deine anderen Entscheidungen, die praktisch nur einen Mikrokernel zulassen, blockieren das ganze wohl effektiver.
Ich habe mich vor etwa 2 Jahren ganz klar für Micro-Kernel entschieden und genau darauf wird meine Plattform optimiert. Meine Plattform soll nicht viel können aber das was sie kann soll sie überragend gut machen.


Zitat von: erik
Das bedeutet aber das mindestens CreateThread() und KillThread() doppelt oder zumindest mit verschiedenen Ausführungspfaden da sein müssen.
Nope, nur CreateThread() (und selbst das könnte ich verhindern, denn der Unterschied ist wirklich minimal bzw. werde ich das bald über ein Flag machen => läuft auf eine if-Schleife hinaus mit einmal 5 Zeilen und einmal 3 Zeilen Code) und KillThread interessiert es wieder gar nicht was für ein Thread das ist, da man eh auf ungültige Werte prüfen sollte.
Sicher? Für einen User-Mode-Thread musst Du auch einen User-Mode-Stack anlegen und wieder löschen, für einen Kernel-Mode-Thread nicht. Auch muss ein User-Mode-Thread zu einem Prozess gehören im Gegensatz zu einem Kernel-Mode-Thread. Ich denke diese kleinen Fallunterscheidungen werden noch an einigen anderen Stellen erforderlich sein.

Da brauchst du dann aber ein wirklich gutes kfree(). Denn wenn auf allen CPUs zur gleichen Zeit Threads beendet werden und diese ihre Ressourcen (je nach dem wie viele das sind, könnte das auch mal dauern) freigeben, müsstest du ja irgendwo einen Lock (mind.) haben und da sind wir dann wieder da was man als lange empfindet. Denn in der Zeit kann ja nichts anderes gemacht werden, da ja dein Kernel nicht unterbrechbar ist.
Der kritische Abschnitt in dem kfree wird wohl auf wenigen dutzend Assemblerbefehlen mit vielleicht 6 Speicherzugriffen hinauslaufen, klar wäre es unschön wenn da wirklich 8 CPUs zur exakt gleichen Zeit durch wollen aber wie wahrscheinlich ist das? Es geht darum das auf mehreren CPUs mit einem zeitlichen Abstand von deutlich unter einer µs gleichzeitig Speicher freigeräumt werden muss, das passiert nicht gerade nennenswert häufig. Mit einem geschickten (hierarchischen) Aufbau der Kernel-Heap-Verwaltung muss es vielleicht noch nicht mal zwangsläufig zu einer Kollision kommen.


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

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #90 am: 01. October 2010, 20:02 »
Es gibt keine if-Schleifen! If ist eine Verzweigung!

Eventuell lässt sich beim Thread-Killen ein Zeiger auf eine "Datenbank" zurückgeben, in der alle Ressourcen dieses Threads aufgeführt werden. Dann braucht man nicht ewig lange Listen traversieren. Kostet dafür etwas Speicher.

Was mich an den Idle-Threads irgendwie interessiert ist, warum man nicht einfach den Kernel selbst dafür missbrauchen kann. Im Endeffekt läuft das ja ungefähr so ab:

-alles Benötigte laden (Bootloader)
-Datenstrukturen vorbereiten
-diverse Tasks/Threads erzeugen (z.B. init)
-Ende: kann man da nicht einfach ein >> while(true) asm("HLT"); << hinsetzen?

Wenn der Scheduler nichts mehr zu verteilen hat, so führt der Kernel halt sich selbst aus - und das ist dann diese Idle-Endlosschleife. Damit wäre der Idle-Thread auch kein eigener Thread mehr und man muss CreateProcess() / CreateThread() nicht anpassen.

Ich behaupte, ich habe einen Denkfehler da drin. Welcher ist es nur?

Gruß,
Sebastian

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #91 am: 01. October 2010, 20:48 »
Dann hast du halt einen Kernelthread, der in einer etwas exotischen Weise erstellt wurde. Kann man natürlich machen, ich seh nur nicht den Vorteil...
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 #92 am: 01. October 2010, 20:58 »
Hallo,


Ich behaupte, ich habe einen Denkfehler da drin. Welcher ist es nur?
Du hast vergessen das es SMP 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 #93 am: 01. October 2010, 21:21 »
Ein Task, der while(1) asm("hlt"); macht könnte sogar auf mehreren CPUs gleichzeitig laufen, ohne dass was böses passiert. ;)
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 #94 am: 02. October 2010, 05:39 »
Eben.
Natürlich läuft der Kernel auf jeder CPU, die er verwaltet (wobei es natürlich Gründe gibt, Kernel auf einer CPU und Userspace auf den restlichen CPUs zu verteilen - insbesondere Hartechtzeitsysteme), also führt er diese Schleife auch auf jeder CPU aus.
Also eher kein Denkfehler, nur ein 80er-Jahre-Ansatz...

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #95 am: 02. October 2010, 08:55 »
@svenska

Das ist genau das was ich in meinem Kernel mache. Da sind wir uns als mal so richtig einig ;)

Zitat von: erik
Sicher? Für einen User-Mode-Thread musst Du auch einen User-Mode-Stack anlegen und wieder löschen, für einen Kernel-Mode-Thread nicht. Auch muss ein User-Mode-Thread zu einem Prozess gehören im Gegensatz zu einem Kernel-Mode-Thread. Ich denke diese kleinen Fallunterscheidungen werden noch an einigen anderen Stellen erforderlich sein.
Was das wieder freigeben betrifft, da ich eh auf "0" überprüfe bevor ich freigebe, ist es egal ob ein Stack vorhanden ist oder nicht.
Auch ein KernelThread kann bei mir zu einem Prozess gehören (wird sogar bei jeder Prozesserstellung genutzt).
Zumal auch der Kernel ein Prozess ist (um viele Sachen einfacher zu machen hat bei mir der Kernel auch die selben Prozessstruturen wie alle anderen auch und ist der Prozess mit der ID 1 oder 0 da bin ich mir grad nicht sicher).

@erik

Da du ja nen MikroKernel haben willst und deine Msgs über Segmente erstellt werden, solltest du eventuell überlegen nur nen SlabAllocator zu benutzen. Denn im Endeffekt allokierst du ja nur Objekte bekannter Größe und da ist der dann schneller (und an sich auch Speicher schonender).

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #96 am: 02. October 2010, 09:27 »
Hallo,


Ein Task, der while(1) asm("hlt"); macht könnte sogar auf mehreren CPUs gleichzeitig laufen, ohne dass was böses passiert.
Der Code ja, aber Du brauchst für jede CPU einen individuellen Stack. Aus meiner persönlichen Sicht wird ein Thread über seinen Stack definiert (Call-Chain und die lokalen Variablen in den Stack-Frames sind die wesentlichen Merkmale eines Thread-Kontextes) und nicht über den Code den er gerade ausführt (der Code ist nur das Werkzeug das diesen Kontext bearbeitet).


Was das wieder freigeben betrifft, da ich eh auf "0" überprüfe bevor ich freigebe, ist es egal ob ein Stack vorhanden ist oder nicht.
Also ich will auch auf "ungültig" Prüfen (nur eben einen Selector) aber wenn dort nichts gültiges ist dann ist das ein fataler Fehler (Thread ohne Stack geht nicht). Du opferst da IMHO etwas Fehlererkennung. Wie ist das bei CreateThread(), da musst Du doch schon genau wissen wie viele Stacks erstellt werden müssen?

Zumal auch der Kernel ein Prozess ist (um viele Sachen einfacher zu machen hat bei mir der Kernel auch die selben Prozessstruturen wie alle anderen auch und ist der Prozess mit der ID 1 oder 0 da bin ich mir grad nicht sicher).
Das ist vernünftig. Du versuchst also auch Sonderfälle zu vermeiden. ;)

Da du ja nen MikroKernel haben willst und deine Msgs über Segmente erstellt werden, solltest du eventuell überlegen nur nen SlabAllocator zu benutzen. Denn im Endeffekt allokierst du ja nur Objekte bekannter Größe und da ist der dann schneller (und an sich auch Speicher schonender).
Auf was willst Du hinaus? Für meine Messages wird kein neuer Speicher alloziert sondern über bereits vorhandenen Speicher (in irgendeinem bereits bestehenden Segment) ein neues Segment gelegt das nur Zugriffe auf genau den von der Message darin belegten Teilabschnitt zulässt (aus Byte genau). Das Original-Segment (beim Client) bekommt also ein Alias-Segment in der LDT eines anderen Prozesses (dem Service), es wird quasi beerbt (wenn auch nur ein bestimmter Abschnitt daraus). Wenn eine Applikation aber z.B. ein komplette Datei mit etlichen MB einlesen möchte und dafür extra ein Segment mit passender Größe erstellt dann ist das erbende Alias-Segment beim Service natürlich genau so groß (also zeigt auf komplett den selben linearen Speicherbereich) wie das Original-Segment. Für einen richtigen Slab-Allocator sehe ich da nirgends eine Verwendungsmöglichkeit oder meinst Du etwas anderes in meinem OS?


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 #97 am: 02. October 2010, 09:38 »
Zitat von: erik
Wie ist das bei CreateThread(), da musst Du doch schon genau wissen wie viele Stacks erstellt werden müssen?
Jap, richtig. Ich habe im Moment noch 2 Funktionen (die auch noch fast genauso aussehen) und will die mal in eine vereinen.

Zitat von: erik
Für einen richtigen Slab-Allocator sehe ich da nirgends eine Verwendungsmöglichkeit oder meinst Du etwas anderes in meinem OS?
Naja, alles wofür du ein kmalloc/kfree einsetzen würdest.

Ich habe kein kmalloc/kfree in meinem Kernel, da wird alles über den SlabAllocator gemacht, weil ich ja nur Objekte bekannter Größer allokieren möchte und das halt mit dem SlabAllocator wesentlich schneller geht.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #98 am: 02. October 2010, 09:54 »
Hallo,


Naja, alles wofür du ein kmalloc/kfree einsetzen würdest.
Das sind in erster Linie die Strukturen für Prozesse, Threads, Message-Targets und Events, dazu kommen noch kleine Elemente für verkette Listen. Auf dem eigentlichen Kernel-Heap liegen also Objekte mit maximal 5 verschiedenen Größen. Alle Segmente (für die User-Mode-Prozesse) werden über die normale Speicherverwaltung für den linearen Speicher gehen. Wie ich die Kernel-Heap-Verwaltung genau aufbauen möchte weiß ich noch nicht aber ich denke ein generischer Slab-Allocator ist dafür etwas zu umfangreich. Darüber mache ich mir genauere Gedanken wenn ich meinen Kernel auch tatsächlich Assemblieren und Ausführen kann.


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 #99 am: 02. October 2010, 13:23 »
Ein Task, der while(1) asm("hlt"); macht könnte sogar auf mehreren CPUs gleichzeitig laufen, ohne dass was böses passiert.
Der Code ja, aber Du brauchst für jede CPU einen individuellen Stack. Aus meiner persönlichen Sicht wird ein Thread über seinen Stack definiert (Call-Chain und die lokalen Variablen in den Stack-Frames sind die wesentlichen Merkmale eines Thread-Kontextes) und nicht über den Code den er gerade ausführt (der Code ist nur das Werkzeug das diesen Kontext bearbeitet).
while(1) asm("hlt") interessiert sich für den Stack herzlich wenig. Du kannst denselben Code also mit demselben Stack auf mehreren CPUs ausführen und es passiert immer noch nichts böses.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

 

Einloggen