Autor Thema: Timer für meine Tasks  (Gelesen 7684 mal)

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« am: 23. February 2007, 14:01 »
Wie kann ich meinen Tasks im OS am besten,elgantesten,sichersten und codeschlankesten einen Timer anbieten?


(1)Ist es möglich einen Timer-Dienst zu implementieren und als Taks laufen zu lassen oder ist es notwendig das im Kernel zu haben.

(2)Welchen Timer(-Chip) nehm ich? (Wenn ich den vom Multitasking nehm, dann können die Tasks die den Timer-Dienst benutzen wollen nur solche Werte nehmen, die teilbar durch die Einstellung des IRQ 0 sind)

(3)Gibt es Anwendungen wo das nicht verschmerzbar ist? (TCP/IP, bst. Treiber, Audio + Video)

(4)Muss ich solche getimeten Prozesse den anderen im Multitasking vorziehen, was wenn zwei Prozesse vorgezogen werden wollen? Was ist, wenn ein Prozess die ganze Zeit einen Timer on hat, nur um länger ausgeführt zu werden?


Gruss
Nooooooooooos

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 23. February 2007, 14:40 »
Wie kann ich meinen Tasks im OS am besten,elgantesten,sichersten und codeschlankesten einen Timer anbieten?
Wie so oft: Das hängt davon ab, in welcher Auflösung und Reaktionszeit du sein möchtest.


Zitat
(1)Ist es möglich einen Timer-Dienst zu implementieren und als Taks laufen zu lassen oder ist es notwendig das im Kernel zu haben.
Es ist notwendig, wenn du kurze Timerlaufzeiten haben möchtest. Da der Timer über Interrupts arbeitet, müsstest du für jeden Timerinterrupt eh in den Kernel schalten und wenn du sowieso schon dort bist, kannst du auch die Schedule-Anweisungen und Tabellen mitverarbeiten.

Zitat
(2)Welchen Timer(-Chip) nehm ich? (Wenn ich den vom Multitasking nehm, dann können die Tasks die den Timer-Dienst benutzen wollen nur solche Werte nehmen, die teilbar durch die Einstellung des IRQ 0 sind)
Du hast mehrere zur Auswahl; Minix benutzt einen der drei Timer und lässt diesen in einer Auflösung von 60 Hz arbeiten (d.h. alle 16,8 ms ein Interrupt). Diese Frequenz kannst du auch anpassen, wenn dein Rechner schneller als 12 MHz ist *g*. Allerdings sollte das für das meiste reichen. Besser ist allerdings, zwei Timer zur Verfügung zu stellen.

Zitat
(3)Gibt es Anwendungen wo das nicht verschmerzbar ist? (TCP/IP, bst. Treiber, Audio + Video)
Hängt wieder von den Treibern und deren Implementation ab. Besonders für Multimedia musst du u.U. auch einen Hochgeschwindigkeitstimer anbieten, mit einer bedeutend höheren Frequenz. Unter Linux hast du die Funktionen sleep (in ms) und usleep (in µs) - daran kannst du dich auch orientieren.

Zitat
(4)Muss ich solche getimeten Prozesse den anderen im Multitasking vorziehen, was wenn zwei Prozesse vorgezogen werden wollen?
Das hängt davon ab, ob du Echtzeitfähigkeit haben möchtest oder die relativ unwichtig ist. Sicher ist, dass du möglichst schnell auf einen Timer reagieren musst, um Pufferunterläufe o.ä. zu vermeiden.

Zitat
Was ist, wenn ein Prozess die ganze Zeit einen Timer on hat, nur um länger ausgeführt zu werden?
Um mich nochmal auf Minix zu beziehen: Dort gibt es für Timer prinzipiell zwei Möglichkeiten - jeder Prozess darf genau EINEN Alarm setzen. Zu diesem Zeitpunkt wird dem Prozess ein Signal (SIGALARM) gesendet, dass er verarbeiten (oder ignorieren) muss. Die zweite Variante ist, dass das Programm ein sleep() oder [Linux] usleep() aufruft, und so lange geblockt (d.h. im Scheduler ausgetragen) wird, bis die Zeit abgelaufen ist.

So umgeht man das Problem, dass ein Prozess den Timer "ausnutzt", um sich Zeit zu geben. Zudem sollten kritische Services (Kernel, Treiber) grundsätzlich auf "ewig" laufen gelassen werden, d.h. bis sie fertig sind und blocken.

Ich hoffe, es hilft dir.

edit: Mir fällt gerade ein: Ich glaube, usleep wird mit Busy-Waiting (also ne sehr enge Schleife) implementiert, weil kein hardwareseitig schneller Interrupt verfügbar ist. sleep wartet auf den Int vom Timer.

Gruß,
Svenska
« Letzte Änderung: 23. February 2007, 14:42 von Svenska »

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 23. February 2007, 15:08 »
Zitat
Zitat
(1)Ist es möglich einen Timer-Dienst zu implementieren und als Taks laufen zu lassen oder ist es notwendig das im Kernel zu haben.
Es ist notwendig, wenn du kurze Timerlaufzeiten haben möchtest. Da der Timer über Interrupts arbeitet, müsstest du für jeden Timerinterrupt eh in den Kernel schalten und wenn du sowieso schon dort bist, kannst du auch die Schedule-Anweisungen und Tabellen mitverarbeiten.
Das heisst also, dass ich bei jedem Timeraufruf jeden Task durchgehen muss und den Timerwert um die Zeit, welche der Timer hat verkleinern muss. Braucht das nicht relativ viel Zeit? Vorallem, wenn der Timer noch jede ms ausgeführt wird um alle ms Werte zu ermöglichen.

Zitat
Zitat
(2)Welchen Timer(-Chip) nehm ich? (Wenn ich den vom Multitasking nehm, dann können die Tasks die den Timer-Dienst benutzen wollen nur solche Werte nehmen, die teilbar durch die Einstellung des IRQ 0 sind)
Du hast mehrere zur Auswahl; Minix benutzt einen der drei Timer und lässt diesen in einer Auflösung von 60 Hz arbeiten (d.h. alle 16,8 ms ein Interrupt). Diese Frequenz kannst du auch anpassen, wenn dein Rechner schneller als 12 MHz ist *g*. Allerdings sollte das für das meiste reichen. Besser ist allerdings, zwei Timer zur Verfügung zu stellen.
Wie heissen denn die 2 anderen Timer ausser dem Multitasking-Timer?

Zitat
Zitat
(4)Muss ich solche getimeten Prozesse den anderen im Multitasking vorziehen, was wenn zwei Prozesse vorgezogen werden wollen?
Das hängt davon ab, ob du Echtzeitfähigkeit haben möchtest oder die relativ unwichtig ist. Sicher ist, dass du möglichst schnell auf einen Timer reagieren musst, um Pufferunterläufe o.ä. zu vermeiden.
Was mach ich denn, wenn bei 2 Prozessen gleichzeitig die Zeit abgelaufen ist?

Zitat
edit: Mir fällt gerade ein: Ich glaube, usleep wird mit Busy-Waiting (also ne sehr enge Schleife) implementiert, weil kein hardwareseitig schneller Interrupt verfügbar ist. sleep wartet auf den Int vom Timer.
Dann ist aber das ganze Betriebsystem geblockt während diese Schleife ausgeführt wird.


Gruss
Nooooooooooos

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 24. February 2007, 00:10 »
Zitat
Zitat
(1)Ist es möglich einen Timer-Dienst zu implementieren und als Taks laufen zu lassen oder ist es notwendig das im Kernel zu haben.
Es ist notwendig, wenn du kurze Timerlaufzeiten haben möchtest. Da der Timer über Interrupts arbeitet, müsstest du für jeden Timerinterrupt eh in den Kernel schalten und wenn du sowieso schon dort bist, kannst du auch die Schedule-Anweisungen und Tabellen mitverarbeiten.
Das heisst also, dass ich bei jedem Timeraufruf jeden Task durchgehen muss und den Timerwert um die Zeit, welche der Timer hat verkleinern muss. Braucht das nicht relativ viel Zeit? Vorallem, wenn der Timer noch jede ms ausgeführt wird um alle ms Werte zu ermöglichen.
Der Timer ist ein kritischer Prozess, das stimmt. In Minix wird hierbei im Programmablauf eine gewisse Zeitspanne festgelegt, wann der nächste Timer-Interrupt etwas "tun" muss. Dieser Zähler wird dann vom Interrupt dekrementiert (was nicht lange dauert und den Handler die meiste Zeit kurz hält) und erst dann, wenn dieser Zähler null wird (also etwas zu tun ist), wird dann der Timer-Task/-Daemon aufgerufen. So kann man auch auf lahmen Kisten (4,77 MHz) einen 60 Hz-Timer versorgen. Bei höheren Geschwindigkeiten (ich gehe bei dir mal von so 500+ MHz aus) kannst du die Timerfrequenz natürlich höher setzen, aber der Interrupt sollte die meiste Zeit nur wenig tun.

Zitat
Zitat
Zitat
(2)Welchen Timer(-Chip) nehm ich? (Wenn ich den vom Multitasking nehm, dann können die Tasks die den Timer-Dienst benutzen wollen nur solche Werte nehmen, die teilbar durch die Einstellung des IRQ 0 sind)
Du hast mehrere zur Auswahl; Minix benutzt einen der drei Timer und lässt diesen in einer Auflösung von 60 Hz arbeiten (d.h. alle 16,8 ms ein Interrupt). Diese Frequenz kannst du auch anpassen, wenn dein Rechner schneller als 12 MHz ist *g*. Allerdings sollte das für das meiste reichen. Besser ist allerdings, zwei Timer zur Verfügung zu stellen.
Wie heissen denn die 2 anderen Timer ausser dem Multitasking-Timer?
Du hast doch 3 Timer zur Verfügung - einen für die Speicherauffrischung, einen frei programmierbaren und den dritten kann ich dir aus dem Kopf nicht sagen. Jedenfalls hast du dort drei programmierbare Timer, die du benutzen kannst.

Zitat
Zitat
Zitat
(4)Muss ich solche getimeten Prozesse den anderen im Multitasking vorziehen, was wenn zwei Prozesse vorgezogen werden wollen?
Das hängt davon ab, ob du Echtzeitfähigkeit haben möchtest oder die relativ unwichtig ist. Sicher ist, dass du möglichst schnell auf einen Timer reagieren musst, um Pufferunterläufe o.ä. zu vermeiden.
Was mach ich denn, wenn bei 2 Prozessen gleichzeitig die Zeit abgelaufen ist?
Nacheinander schedulen? Wenn du alle 100ms einen Taskswitch ausführst und die meisten Tasks nicht schedult werden (weil diese eben nichts zu tun haben), dann liegt in dem Fall die maximale Zeitdauer bei 100 ms (+Overhead) - was zu verschmerzen sein sollte. Mit einem Prozessor kannst du ohnehin nichts dagegen tun. Dafür tritt der Fall nur selten auf. :-)

Zitat
Zitat
edit: Mir fällt gerade ein: Ich glaube, usleep wird mit Busy-Waiting (also ne sehr enge Schleife) implementiert, weil kein hardwareseitig schneller Interrupt verfügbar ist. sleep wartet auf den Int vom Timer.
Dann ist aber das ganze Betriebsystem geblockt während diese Schleife ausgeführt wird.
Stimmt. Das fällt aber bei Wartezeiten von wenigen µs nicht ins Gewicht. Da wiegt ein fehlgeschlagenes Protokoll oder ein untergelaufener Soundpuffer schon mehr...

Gruß,
Svenska

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 24. February 2007, 08:41 »
Also würdest du NICHT den Timer IRQ-0 vom Multitasing nehmen?? Wie gross würdest du die Zeitspanne in der der Timer nichts tun muss ansetzen?? Kann ich auch zwei verschidene Zeitspannen nehmen?

Gruss
Nooooooooos

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 26. February 2007, 15:51 »
Also ... ich habe mich unklar ausgedrückt und weiß nicht, wie ich es jetzt besser machen soll...

Und zwar wird diese Zeitspanne nicht festgelegt, sondern ergibt sich. Es wird im Prinzip eine Liste geführt, in der jedes Ereignis (z.B. Zeitscheibe für Taskwechsel o.ä.) eingetragen wird. Diese ist sortiert und das vorderste Element (das also als nächstes dran ist) ist in einer weiteren Variablen drin.
Diese Variable wird, sofern nichts passieren muss, vom Interrupt dekrementiert. Wenn nun etwas passieren muss, dekrementiert der Interrupt diese Variable, stellt fest, dass sie nun null ist und ruft den Handler im Timer-Task auf.
Der entfernt das vorderste Element aus der Liste und passt die Zeit in der gesamten Liste an die zwischenzeitlich vergangene Zeit an, sodaß das vorderste Element wieder auf das nächste Ereignis zeigt und die Zeit dessen auch stimmt. Dann geht das Spielchen wieder von vorne los.

Die Länge der Ausführungszeit eines Tasks beträgt unter Windows 3.1 (für 386SX-16!) mindestens 20ms - wenn bspw. ein Interrupt während der Ausführungszeit der Anwendung die Rechenleistung für sich braucht, bekommt sie eine weitere Zeitscheibe zugeteilt, bevor ihr die Rechenleistung wieder entzogen wird. Ich denke mal, dass man mit 10-100ms eigentlich ganz gut hinkommt. Aber die Zeitscheibe ist nicht fest, sondern richtet sich nach den Erfordernissen der Anwendungen.

Gruß,
Svenska

Korona

  • Beiträge: 94
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 26. February 2007, 16:06 »
Du kannst auch den APIC Timer oder rdtsc benutzen um sehr kurze Zeitangaben zu messen oder zu warten.

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 28. February 2007, 17:20 »
Svenska, wenn ich also die Zeitspanne des IRQ-0 z.B. auf 10ms setze, dann können also die Tasks das als kleinste Zeit nehmen, oder? Und jedes mal wenn der IRQ0-fürs Multitasking aktiviert wird, muss ich die oberste Variable dekrementieren? Oder ist das Multitasking selbst dort eingetragen?


Gruss
Noooooooooos

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 28. February 2007, 21:08 »
Sofern deine Anwendungen dann diesen Timer benutzen, ist dessen Auflösung (+Overhead) die kleinstmögliche Zeit. Ja. Für kürzere Zeitabschnitte kannst du nicht mehr mit Interrupts arbeiten, weil die dann nicht mehr garantiert ankommen.

Um den Interrupt-Handler kleinzuhalten, wird nur eine vorher vom Treiber festgelegte Variable dekrementiert. Erst, wenn diese 0 ist [es also etwas zu tun gibt], wird der eigentliche Treiber aufgerufen.

Gruß,
Svenska

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 01. March 2007, 20:00 »
Ok..meine andere Frage war noch, ob man die Ausführung des Codes, welcher den Task wechselt, vorzüglich als Ereignis in die Timerliste einträgt, um kleinere Zeiten zu ermöglichen oder jedes mal, wenn der INT aufgerufen wird, den Task zu wechseln, was allerdings eben die Timerzeit eher höher hält.

Ab ca. welcher Zeit sind Ints auf Grossteilen der Computer nich mehr zuverlässig??


Gruss
Nooooooooooos

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 03. March 2007, 12:50 »
Ich würde den nächsten Taskwechsel ebenfalls in diese Liste eintragen. Sonst würdest du ja alle 16,8ms den Task wechseln und das finde ich etwas zu heftig. :-)
Zur Zuverlässigkeit...die hängt von der Implementierung ab. Wenn du Treiber und Interrupt-Handler nicht schedulst (die laufen, bis sie fertig sind), dann darf kein Treiber jemals länger dauern als zwei Clock-Ints, weil dann der erste u.U. verfällt. Treiber sollte man grundsätzlich nicht schedulen, weil man sonst u.U. ein Timing (z.B. IDE, seriell) nicht sauber implementieren kann.

Gruß,
Svenska

nooooooooos

  • Beiträge: 734
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 03. March 2007, 19:09 »
Blöd ist jetzt dabei nur mein OS-Design...Weil ich den Timer-Handler, welcher bei einem fälligen Eintrag in der Liste aufgerufen wird, als eigener Task auslagern will...Dazu braucht es aber den Timer-Int...aber naja mal schaun

Danke
Noooooooooooos

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 03. March 2007, 20:05 »
Treiber sollte man grundsätzlich nicht schedulen
leute, die einen präemptiven kernel implementieren, sehen das genau andersherum. mit etwas denkaufwand sollte man es hinkriegen bei diesem modell sämtliche zeitlichen restriktionen zu bedienen. insbesondere die geschichte mit den irqs, die bei einem nicht präempitiven kernel nicht rechtzeitig behandelt werden könnten.
Dieser Text wird unter jedem Beitrag angezeigt.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 04. March 2007, 10:12 »
@nooooooooos:
Der Timer ist auch so ziemlich das einzige, was bei Minix im Kernel gehalten wird (selbst memory management und file system sind Extra-Tasks).
Du müsstest damit den Interrupt und dessen Handler vom Timer-Task trennen und dem Handler die Möglichkeit geben, eine Message/ein Signal an den Task weiterzuleiten.

@PorkChicken:
Da hast du natürlich auch wieder recht. Aber präemptive Treiber zu implementieren ist unglaublich schwieriger, vor allem, wenn man die Hardware mit einem zeitkritischen Protokoll ansprechen muss.
Also korrigiere ich mich: Man muss sie nicht schedulen, aber es ist einfacher, wenn man es tut. :-)

Gruß,
Svenska

 

Einloggen