5.7. Treiberinstanzen

Wird in einer Applikation ein open-Systemcall aufgerufen, instanziert der Betriebssystemkern eine Datenstruktur vom Typ struct file. Diese repräsentiert eine so genannte Treiberinstanz.

Auch der Treiber muss im Regelfall Daten abspeichern, die für jede Instanz spezifisch sind. Bei einem »Hello World«-Treiber, der pro Treiberinstanz (also für jedes Open) genau einmal den String »Hello World« zurückgeben soll, muss beispielsweise mitgezählt werden, wieviel Bytes eine Treiberinstanz bereits abgerufen hat. Beim ersten Aufruf wird die Anzahl der Bytes des Strings (strlen("Hello World\n")+1=13) zurückgegeben. Gleichzeitig wird diese Anzahl von der insgesamt zur Verfügung stehenden Anzahl Bytes abgezogen. Beim zweiten Aufruf wird festgestellt, dass keine Bytes mehr zu kopieren sind, und die Funktion gibt »0« als Zeichen für End Of File zurück.

Würde der dazu notwendige Zähler in Form einer globalen Variablen verwaltet werden, könnten nicht mehrere Treiberinstanzen auf den Treiber zu einem Zeitpunkt zugreifen, ohne dass es zu einer Race Condition kommt. Ein nach einem read erfolgendes open würde beispielsweise vergessen machen, dass bereits Werte zurückgegeben wurden.

Task 1: open -> ZurVerfuegung=13;
Task 1: read 13 Bytes -> ZurVerfuegung=0; beim nächsten Lesen
                            muesste der Prozess EOF zurückbekommen.
Task 2: open -> ZurVerfuegung=13;
Task 1: read 13 Bytes

In vielen Treibern gibt es demnach instanzenspezifische Informationen. Diese können mit der zugehörigen Treiberinstanz verknüpft werden. Zunächst wird dazu eine Datenstruktur deklariert:

struct _instance_data {
    int counter;
    // other instance specific data
};

Abbildung 5-15. Erweitern der Treiberinstanz um instanzenspezifische Parameter

In der Funktion driver_open wird hernach eine solche Datenstruktur für die aktuelle Treiberinstanz dynamisch angelegt. Dazu kann kmalloc verwendet werden (siehe Kapitel Dynamische Speicherverwaltung). Falls kmalloc den Speicher nicht allozieren kann, gibt es »0« zurück. In diesem Fall muss die driver_open-Funktion des Treibers den Fehlercode »-ENOMEM« an die Applikation weiterreichen. Ansonsten wird die neu angelegte Datenstruktur mit der struct file verbunden, in dem die Adresse der neuen Datenstruktur im Feld private_data abgespeichert wird.

Schließt die Applikation den Treiber wieder, muss innerhalb der Funtkion driver_close der Speicher für die instanzenspezifischen Parameter wieder freigegeben werden. Diese Abläufe skizziert Beispiel Die Verwaltung instanzenspezifischer Parameter.

Beispiel 5-27. Die Verwaltung instanzenspezifischer Parameter

static int driver_open( struct inode *geraetedatei, struct file *instance )
{
    struct _instance_data *iptr;

    iptr = (struct _instance_data *)kmalloc(sizeof(struct _instance_data),(1)
        GFP_KERNEL);
    if( iptr==0 ) {
        printk("not enough kernel mem\n");
        return -ENOMEM;
    }
    iptr->counter= strlen("Hello World\n")+1;
    instance->private_data = (void *)iptr;                 (2)
    return 0;
}

static void driver_close( struct file *instance )
{
    if( instance->private_data )
        kfree( instance->private_data );                   (3)
}
(1)
Mit jeder neuen Instanz wird Speicher angelegt. Da kmalloc »void *« zurückgibt, muss ein Type-Casting durchgeführt werden.

Der Parameter »GFP_KERNEL« besagt, dass der aufrufende Prozess (Treiberinstanz) in den Zustand warten versetzt werden darf, falls gerade im Kernel kein Speicher zur Verfügung steht.

(2)
Hier werden die Treiberdaten mit der vom Kernel angelegten Datenstruktur »Instance« verbunden.
(3)
Es darf nicht vergessen werden, allozierten Speicher wieder freizugeben.


Lizenz