Open Source im professionellen Einsatz
Linux-Magazin 08/2016
© psdesign1, Fotolia

© psdesign1, Fotolia

Kernel- und Treiberprogrammierung mit dem Linux-Kernel – Folge 87

Kern-Technik

,

Zeit exakt zu messen und definierte Pausen zu verordnen, das gehört zum Wesen von Realtime-Betriebssystemen. Aber auch universelle Betriebssysteme brauchen gute Timer- und Delay-Prozeduren. Welche Funktionen mit welcher Auflösung und Genauigkeit Linux bietet, ist Thema dieser Kern-Technik.

1044

"Die Zeit ist Amm' und Mutter alles Guten", weiß Proteus in "Die beiden Veroneser" zu berichten; für moderne Software gilt die Shakespearische Weisheit nicht minder. Linux nennt auf Anfrage die aktuelle Zeit und vermittelt der Software so etwas wie ein Zeitgefühl. Obwohl konzeptionell anfangs nicht vorgesehen, besitzt der Kernel zudem Realzeit-Fähigkeiten.

In dieser Kern-Technik soll es darum gehen, dass Linux Software anbietet, um einen Prozess im Rahmen der Zeitsteuerung für ein gewünschtes Intervall zu pausieren. In vielen Fällen bilden für Programmierer die gebotene Auflösung und die erzielte Genauigkeit die wesentlichen Kriterien. Prinzipiell löst Linux im Nanosekunden-Bereich auf und verspricht eine Genauigkeit im Bereich von Mikrosekunden. Prinzipiell. Das Ganze ist abhängig von der Hardware, aber auch davon, wie man's macht.

In puncto Zeitmessung und -steuerung hat sich auf dem Weg von Unix zu Linux in den Jahren einiges getan, insbesondere ist der Umgang mit Zeit professioneller geworden. Statt der alten Funktion »time()« verwenden Entwickler von Applikationen heute »clock_gettime()« und »clock_nanosleep()« anstelle von »sleep()« (siehe Kasten "Schlafkur für Applikationen"). Die modernen Funktionen berücksichtigen über so genannte Zeitgeber beispielsweise das Drehen an der Uhr, etwa bei der Sommer-Winterzeit-Umstellung.

Im Kernel tickt die Welt etwas komplizierter [1]. Hier gibt es mehrere Ebenen und damit unterschiedliche Kontexte, die den Code abarbeiten (Abbildung 1). Abhängig vom Kontext stehen einige Funktionen nicht zur Verfügung. Die Funktion »clock_nanosleep()« beispielsweise legt – wie der Name schon sagt – eine Funktion schlafen. Im Interrupt-Kontext ist so etwas weder möglich noch erlaubt. Seit der letzten Kern-Technik, die sich mit dem Clockwork des Kernels befasst hat [2] im Jahr 2006, haben die Entwickler viel erneuert und verfeinert.

Abbildung 1: Je nach Kontext sind Programmierer in der Funktionsauswahl eingeschränkt.

Schlafkur für Applikationen

Haben die Anwendungsprogramme-Entwickler in den Unix-Anfangstagen mit der Funktion »time()« die Zeit in Sekundenauflösung erfasst, greift der Programmierer heute zu »clock_gettime()« . Neben der deutlich besseren Auflösung von Nanosekunden berücksichtigt diese Funktion unterschiedliche Zeitgeber: Standardisiert sind »CLOCK_REALTIIME« und »CLOCK_MONOTONIC« . Während »CLOCK_REALTIME« die vergangene Zeit seit dem 1.1.1970 (Unix-Epoche) zurückgibt, liefert »CLOCK_MONOTONIC« eine Zeit, die zumeist mit dem Systemstart angefangen hat zu ticken. »CLOCK_REALTIME« berücksichtigt Korrekturen an der Uhr, »CLOCK_MONOTONIC« dagegen zählt bei Sommer-Winterzeit-Umstellungen unbeeindruckt weiter.

Wie die Funktion »time()« veraltet ist, sollten Programmierer auch »sleep()« und »nanosleep()« nicht mehr verwenden. Die Funktion »clock_nanosleep()« berücksichtigt nicht nur den Zeitgeber und arbeitet mit »struct timespec« , sie lässt den Programmierer auch zwischen relativem und absolutem Schlafen wählen – also ob sein Prozess für eine Zeitdauer x verharrt oder bis zum Zeitpunkt y.

Unterbricht ein Ereignis unvorhergesehen einen zeitgesteuert schlafenden Rechenprozess vor Ablauf der Wunschzeit – etwa weil der Rechenprozess ein Signal geschickt bekommt –, kann der Programmierer das Schlafen leicht neu aufsetzen: Im vierten Parameter übergibt er die Adresse eines Speicherbereichs, in dem beim Abbruch die Restzeit abgelegt ist.

Wer hat an der Uhr gedreht?

Das Zeitmanagement des Linux-Kernels basiert auf High-Resolution-Timern (Hrtimer, [1]). Diese verarbeiten und speichern genaue Zeiten in der Datenstruktur »ktime_t« . Hinter diesem Typ steckt eine 64 Bit breite Variable, die die Zeit in einer Auflösung von Nanosekunden speichert. Zum Lesen der Zeit mit der passenden Auflösung besitzt der Kernel die Funktionen »ktime_get_ts()« und »ktime_get_real_ts()« . Sie präsentieren die Zeit in der aus dem Userland bekannten Form »struct timespec« , also in Sekunden und die Restzeit in Nanosekunden.

Die Funktion »ktime_get_real_ts()« liefert – in Abgrenzung zu »ktime_get_ts()« – die Zeit seit dem 1.1.1970, also seit dem Beginn der Unix-Epoche, zurück. Dabei berücksichtigt sie auch ein Drehen an der Uhr, wie es bei der Sommer-Winterzeit-Umstellung stattfindet (Zeitgeber »CLOCK_REALTIME« ). »ktime_get_ts()« berechnet die Zeit relativ zu einer internen Basis – zumeist dem Systemstart – (Zeitgeber »CLOCK_MONOTONIC« ).

Der Startschuss fällt beim Laden des Moduls

Für einfache Zeitverzögerungen stehen die in Tabelle 1 gelisteten Funktionen bereit. Bestimmungsgemäß sollten sie die aufrufende Codesequenz für die angegebene Zeit Nano-, Mikro- oder Millisekunden-genau pausieren lassen. Wegen des Multitasking und der Interruptverarbeitung der CPU gelingt ihnen dies in der Praxis aber mehr schlecht als recht. Um es klarer zu sagen: In Linux' Pausen schleichen sich oft solche Ungenauigkeiten ein, dass man bei Ausreißern geneigt ist, von einem fehlerhaften Verhalten auszugehen.

Der Beweis dafür ist mit ein wenig Aufwand zu erbringen: Ein für diesen Artikel entwickeltes einfaches Kernelmodul soll die Genauigkeit dieser Zeitverzögerungsfunktionen messen. Das Modul ist so gebaut, dass es die Messung beim Laden durchführt. Allerdings meldet es nach der Messung absichtlich einen Fehler, um das eigene Einnisten in den Kernel zu verhindern. Der Trick spart das ansonsten notwendige Entladen.

Der Quellcode lässt sich auf einem PC und – falls der Linux-Quellcode auf dem Gerät vorhanden ist – auch auf einem Raspberry Pi übersetzen. Abbildung 2 zeigt das Makefile (alle Sourcen gibt es auf dem FTP-Server des Linux-Magazins [3]), den Übersetzungsvorgang und das Laden des binären Moduls per »sudo insmod messung.ko« .

Die Messung der einzelnen Zeitverzögerungsfunktionen – unterschiedlich parametrisiert – dauert knapp 10 Minuten. Anschließend erscheint die erwähnte Fehlermeldung. Die Ausgabe des Kernelmoduls landet im Syslog des Systems, das man am besten in einem separaten Terminalfenster mit Hilfe des Kommandos »tail -f /var/log/kern.log« verfolgt.

Tabelle 1

Kernelfunktionen zur Zeitverzögerung

Atomic-Kontext (ISR, Tasklet, Soft-IRQ)

ndelay(unsigned long nsecs)

Verzögerungszeit in Nanosekunden

udelay(unsigned long usecs)

Verzögerungszeit in Mikrosekunden

mdelay(unsigned long msecs)

Verzögerungszeit in Millisekunden

Non-atomic-Kontext (Kernelthread, normale Treiberfunktionen)

udelay(unsigned long usecs)

Verzögerungszeit in Mikrosekunden

usleep_range(unsigned long min, unsigned long max)

Schlafenszeit in Mikrosekunden

msleep(unsigned long msecs)

Schlafenszeit in Mikrosekunden

msleep_interruptible(unsigned long msecs)

Schlafenszeit in Mikrosekunden

schedule_timeout(long timeout)

Schlafenszeit in Jiffies

schedule_timeout_interruptible(long timeout)

Schlafenszeit in Jiffies

Abbildung 2: Eine Messung der Verzögerungszeiten kann jeder Kern-Technik-Leser auf seinen Systemen mit wenig Aufwand selbst durchführen.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 5 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Kern-Technik

    Trotz Taktveränderungen durch Speedstep oder Quiet'n'Cool im Kernel exakte Zeiten messen? Diese Folge der Kern-Technik stellt Kernelfunktionen für den richtigen Umgang mit der Zeit vor.

  • Kern-Technik

    Mit der Integration der hochauflösenden High-Resolution-Timer lässt Linus Torvalds die schleichende Unterwanderung der traditionellen, auf Jiffies basierenden Zeitverwaltung zu. Die Auswirkungen auf den Linux-Kernel sind gewaltig.

  • Kern-Technik

    Systemaufrufe bilden die Schnittstelle zwischen Userspace und Kernel. Dieser Artikel zeigt, wie sie funktionieren und wie man sogar eigene Systemcalls implementiert.

  • Prozessor-Schwinger

    Die meisten Programme zur Anzeige der CPU-Auslastung wie Top und Xosview bedienen sich aus dem »/proc«-Dateisystem des Linux-Kernels. Unter bestimmten Umständen liefert diese Schnittstelle jedoch unkorrekte Werte. Das beschriebene Patch behebt das Problem.

  • Kern-Technik

    Wer mit Linux zu tun hat, sieht sich realen, virtuellen oder Boot-Konsolen gegenüber, begegnet klassischen, Pseudo- oder auch Controlling-Terminals. Die Kern-Technik bringt Ordnung in die babylonische Sprachverwirrung und zeigt, wie man einen eigenen Terminaltreiber schreibt.

comments powered by Disqus

Ausgabe 07/2017

Digitale Ausgabe: Preis € 6,40
(inkl. 19% MwSt.)

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.