Autor Thema: Kooperatives Multitasking  (Gelesen 11295 mal)

MasterQ32

  • Beiträge: 10
    • Profil anzeigen
    • MasterQ32.de
Gespeichert
« am: 13. September 2013, 16:55 »
Hey!

Ich plane gerade, mir einen kleinen Kernel zu schreiben. Da meine Planung eigentlich nur einen Task vorsieht, dachte ich daran, kooperatives Multitasking einzubauen. Ich weiß, dass es nicht immer die beste Wahl ist, aber für den Anfang reicht mir das voll und ganz aus.

Mein Vorgehen wäre nun folgendes:
struct task
    void *
    void *stack
    uint32_t stackpointer
task_wechseln
    task-stackpointer sichern
    nächsten task auswählen
    task-stackpointer wiederherstellen
Die Funktion darf halt keine lokalen variablen (außer static) enthalten, da ich so keine sonstigen änderungen am stackpointer vornehmen.

Das sollet doch eigentlich keine Probleme machen oder habe ich irgendetwas grundlegendes vergessen?

Gruß
Felix
"Wenn ich Populist wäre, müsste ich mich jetzt sofort hinsetzen und das Feature programmieren. Gut, dass ich kein Populist bin." - JCL

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 13. September 2013, 17:12 »
Das klingt so, als ob du versuchst den Stackpointer im C-Code zu wechseln. Davon würde ich abraten, weil die Compiler auch ohne lokale Variablen den Stack nicht unbedingt auf die offensichtliche Art auslegen (und z.B. Platz für Zwischenergebnisse reservieren). Außerdem musst du vermutlich Register sichern, was allerdings nicht möglich ist, wenn du (verschachtelte) Funktionsaufrufe hast. Wenn du zwischen User Modus und Kernel Modus unterscheiden willst (d.h. Kernel vom User Space schützen willst), dann kriegst du außerdem Probleme, weil du ja im Prinzip zweimal den Kontext wechseln musst. Du könntest diese Probleme vermutlich lösen, wenn du alles (Interrupthandler, Tasksicherung und Taskwiederherstellung) in Assembler schreibst, aber davon rate ich ab. Mein Vorschlag wäre, dass du unser Tutorial (zumindest Interrupts und Multitasking) befolgst, und das anschließend deinen Wünschen entsprechend umbaust. Basierend auf den Code könntest du dann den schedule-Aufruf aus handle_interrupt von Interrupt 0x20 in den Interrupt verschieben, der bei dir für Syscalls zuständig ist, und schon hast du kooperatives Multitasking.
Dieser Text wird unter jedem Beitrag angezeigt.

MasterQ32

  • Beiträge: 10
    • Profil anzeigen
    • MasterQ32.de
Gespeichert
« Antwort #2 am: 13. September 2013, 22:05 »
Okay, das wollte ich wissen. Mal schauen ob das was wird, aber ich gehe zuversichtlich an die Arbeit. Kooperatives Multitasking würde mir auf jeden Fall bei Atomics helfen, da man keine speziellen Locking-Mechanismen braucht. Ein bisschen muss ich mein Konzept zwar anpassen, aber das wird schon klappen. Danke!
"Wenn ich Populist wäre, müsste ich mich jetzt sofort hinsetzen und das Feature programmieren. Gut, dass ich kein Populist bin." - JCL

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 13. September 2013, 22:37 »
Effektiv unterscheidet sich kooperatives Multitasking von präemptivem Multitasking nur dadurch, dass Tasks nicht in einem Timer-Interrupt gewechselt werden, sondern mit einem Syscall. Die eigentliche Implementation des Taskwechsels bleibt also die gleiche.

Dein Ansatz klingt für mich eher wie "ein Prozess, mehrere Threads" und wäre da eher mit einer Userspace-Threading-Bibliothek vergleichbar. Was du vorhast, müsste tatsächlich komplett in C machbar sein, wenn du setjmp()/longjmp() benutzt. Allerdings verlierst du dann auch den Speicherschutz.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 13. September 2013, 22:45 »
An setjmp/longjmp hab ich gar nicht gedacht. Allerdings ist bei denen zu beachten, dass der Stack nicht gewechselt wird, und das deswegen ziemlich eingeschränkt ist.
Dieser Text wird unter jedem Beitrag angezeigt.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 14. September 2013, 09:55 »
Also zumindest in der Praxis wechseln setjmp/longjmp sehr wohl den Stack, auch wenn ich mir grad nicht sicher bin, ob die Spec das vorschreibt oder ob es nur ein Nebeneffekt dessen ist, wie man es eben implementiert. Das einzige Problem, das du hast, ist zum allerersten Mal auf einen neuen Stack zu wechseln. Das geht nicht mit Standard-C. Mit POSIX gibt es Möglichkeiten dafür, qemu benutzt für seine Coroutinen-Implementierung zum Beispiel standardmäßig ucontext.h und alternativ sigaltstack() für den ersten Stackwechsel und anschließend immer setjmp/longjmp.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

 

Einloggen