Autor Thema: Ordentliche ms genaue Sleep Funktion (Delay)  (Gelesen 5361 mal)

wissenshunger

  • Beiträge: 49
    • Profil anzeigen
Gespeichert
« am: 13. March 2014, 19:23 »
Hallo liebe Community,

ich habe mir schon einige Beispiele an Sleep Funktionen angeschaut und einiges getestet.
Von asm("nop"); Schleifen bis hin zu komplizierten Timer.

Bisher an mich nichts richtig zufrieden gestellt, aber ich bin im Moment an diesem Modell hängen geblieben:
void sleep(uint32_t ms)
{
    SLEEP_ACTIV_STATE = 1;
    uint64_t cur = tick_counter;
while((cur+ms) >= tick_counter);
SLEEP_ACTIV_STATE = 0;
return;
}

Am Timer 1, der eigentlich das Multitasking steuert steht folgendes:
if (cpu->intr == 0x20) {  //TIMER
        TIMER_ITR();
new_cpu = schedule(cpu);
tss[1] = (uint32_t) (new_cpu + 1);
new_cpu = cpu; 
}

TIMER_ITR():
void TIMER_ITR(void)
{
tick_counter += 10;
}

Wie man sieht ist diese Sleep-Funktion nur 10ms "genau". Sprich der Timer wird jede 10ms ausgelöst. (100Hz) Ich benötige allerdings für das Multitasking eine niedrige Frequenz, vielleicht 10Hz, also jede 100ms. Dann würde meine Sleepfunktion allerdings um 100ms ungenau gehen.

Das Ziel ist es aber meine Task mit 10Hz zu wechseln und meine Sleepfunktion auch nur 1ms warten zu lassen.
Ist den mein jetziges Model dafür überhaupt geeignet? Sollte ich etwas ganz anderes Verfolgen?

Wie habt ihr dieses Funktion gelöst?

Seltsam ist bei meiner Varriante von Sleep-Funktion auch, dass vor dem Multitasking (aber schon aktivem Timer IRQ) meine Sleep-Funktion die Zeit abwartet und es danach weiter im Kernel geht. Sobald das Multitasking aktiv ist, sprich auch Task laufen & ich dann z.B. mein Floppy-Laufwerk ansteuer und die Sleepfunktion aufgerufen wird kommt er nicht mehr aus der while Schleife herraus.

Ich freue mich auf eure Idee, Vorschläge und Anregungen...
L.G.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 13. March 2014, 20:21 »
Deine Sleep-Funktion führt ja busy waiting durch, und ist deswegen für ein Multitaskingsystem nicht geeignet. Besser ist es, wenn ein Task/Prozess/Thread den Sleep-Systemaufruf durchführt, diesen in den Blockieren zu lassen und während des Wartens einen anderen Task (sofern einer existiert) laufen zu lassen. Auch falls du diese Funktion nur im Kernel (beispielsweise ein Floppy-Treiber im Kernel) nutzt, verlierst du damit die Vorteile eines Multitaskingssystems (während ein Task auf I/O wartet, kann ein anderer die CPU nutzen).

Viele Systeme haben deswegen für Prozesse Zustände wie Running, Blocked, ... (viele bunte Bilder) eingeführt. Ein Prozess der auf I/O wartet (beispielsweise bei einem Sleep auf einen Timer-IRQ oder bei einem Floppy-Treiber auf den Floppy-IRQ), wird blockiert und beim Scheduling so lange übersprungen, bis der IRQ-Handler, auf den der Prozess wartet, den Prozess wieder laufen lässt (natürlich mit deiner bevorzugten Anzahl Abstraktionsschichten dazwischen).

Wenn du das Multitasking mit 10 Hz laufen lassen willst, aber sleep() mit einer Auflösung von 1 ms haben willst, kannst du beispielsweise den Timer auf 1 ms stellen und nur bei jedem 100sten Interrupt schedule() aufrufen.

Seltsam ist bei meiner Varriante von Sleep-Funktion auch, dass vor dem Multitasking (aber schon aktivem Timer IRQ) meine Sleep-Funktion die Zeit abwartet und es danach weiter im Kernel geht. Sobald das Multitasking aktiv ist, sprich auch Task laufen & ich dann z.B. mein Floppy-Laufwerk ansteuer und die Sleepfunktion aufgerufen wird kommt er nicht mehr aus der while Schleife herraus.
Deaktivierst du Interrupts in den Funktionen, die das Diskettenlaufwerk ansteuern?
« Letzte Änderung: 13. March 2014, 21:21 von Jidder »
Dieser Text wird unter jedem Beitrag angezeigt.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 14. March 2014, 03:12 »
Der übliche Weg ist es, im Betriebssystem eine Art "Uhrzeit" zu definieren, z.B. in "Millisekunden seit Systemstart". Damit kannst du dann nicht nur relative Wartezeiten (1 Sekunde ab jetzt), sondern auch absolute Wartezeiten (alle fünf Minuten) sinnvoll abbilden. Wenn du nämlich immer nur 1 Sekunde wartest, hast du jedesmal eine Ungenauigkeit von ein paar ms, und der Fehler wird immer größer.

Um eine Sekunde zu warten, wartest du dann nicht eine Sekunde, sondern du stellst dir einen Wecker auf "in einer Sekunde" und legst dich schlafen, bis der Wecker klingelt. Ganz wie im realen Leben.

 

Einloggen