Frage

Ich schreibe einen Code für Linux-Kernel-Modul und ein seltsames Verhalten in ihm erlebt. Hier ist mein Code:

int data = 0;
void threadfn1()
{
    int j;
    for( j = 0; j < 10; j++ )
        printk(KERN_INFO "I AM THREAD 1 %d\n",j);   
    data++;
}

void threadfn2()
{
    int j;
    for( j = 0; j < 10; j++ )
        printk(KERN_INFO "I AM THREAD 2 %d\n",j);
    data++; 
}
static int __init abc_init(void)
{
        struct task_struct *t1 = kthread_run(threadfn1, NULL, "thread1");
        struct task_struct *t2 = kthread_run(threadfn2, NULL, "thread2");
        while( 1 )
        {
        printk("debug\n"); // runs ok
            if( data >= 2 )
            {
                kthread_stop(t1);
                kthread_stop(t2);
                break;
            }
        }
        printk(KERN_INFO "HELLO WORLD\n");

 }

Im Grunde habe ich versucht, um für Threads zu warten zu beenden und dann etwas danach drucken. Der obige Code funktioniert das Ziel erreichen, aber mit "printk("debug\n");" nicht kommentiert. Sobald ich printk("debug\n"); auf Kommentar zu laufen scheint, den Code ohne Debuggen und laden Sie das Modul durch insmod Befehl, das Modul hängt an und es, wie es in Rekursion verloren geht. Ich nicht, warum printk Effekte meinen Code in einem so großen Weg?

Jede mögliche Hilfe würde geschätzt.

Bezug.

War es hilfreich?

Lösung

Mit dem Aufruf von printk() entfernt der Compiler die Schleife in while (1); optimiert. Wenn Sie den Anruf hinzufügen, der Compiler printk() ist nicht sicher, dass data nicht verändert wird und so prüft der Wert jedes Mal durch die Schleife.

Sie können eine Barriere in die Schleife eingefügt, die bei jeder Iteration die Compiler neu zu bewerten data zwingt. zB:

while (1) {
        if (data >= 2) {
                kthread_stop(t1);
                kthread_stop(t2);
                break;
        }

        barrier();
}

Andere Tipps

Sie Synchronisierung nicht den Zugriff auf die Daten-Variable. Was passiert, ist, dass der Compiler eine Endlosschleife zu erzeugen. Hier ist der Grund:

  while( 1 )
        {
            if( data >= 2 )
            {
                kthread_stop(t1);
                kthread_stop(t2);
                break;
            }
        }

Der Compiler kann erkennen, dass der Wert der Daten nicht innerhalb der while-Schleife ändert. Daher kann es vollständig die Kontrolle aus der Schleife bewegen, und Sie werden mit einem einfachen Ende

 while (1) {} 

Wenn Sie die Compiler printk einfügen muss davon ausgehen, dass die globalen Variable Daten ändern können (schließlich - der Compiler keine Ahnung hat, was printk im Detail funktioniert) wird daher Ihr Code Arbeit erneut starten (in einer undefinierten Verhalten Art und Weise ..)

Wie dieses Problem zu beheben:

Verwenden Sie eine korrekte Synchronisation von Threads Primitiven. Wenn Sie den Zugriff auf die Daten in einen Codeabschnitt geschützt durch einen Mutex wickeln wird der Code arbeiten. Sie könnten auch die variablen Daten ersetzen und eine Semaphore stattdessen gezählt verwenden.

Edit:

Dieser Link wird erläutert, wie in der Linux-Kernel funktionieren Sperren:

http://www.linuxgrill.com/ anonymous / Feuer / netfilter / kernel-Hacking-HOWTO-5.html

Vielleicht sollten Daten volatile deklariert werden? Es könnte sein, dass der Compiler nicht in dem Speicher wird Daten in der Schleife zu erhalten.

Nils Pipenbrinck Antwort ist vor Ort auf. Ich werde nur einige Hinweise hinzufügen.

Rusty Unzuverlässige Guide to Kernel Locking (jeder Kernel-Hacker sollten diese eine lesen).
Auf Wiedersehen Semaphore? , die Mutex API ( lwn.net Artikel auf dem neuen Mutex API eingeführt Anfang 2006 vor, dass die Linux-Kernel Semaphore als mutexes verwendet wird).

Da auch Ihre freigegebenen Daten ein einfacher Zähler ist, können Sie einfach die atomare API verwenden (im Grunde, erklären Ihren Zähler als atomic_t und greifen Sie atomic_ * Funktionen).

Flüchtige nicht immer „schlechte Idee“ sein. Man muss trennen der Fall, wenn flüchtige benötigt wird, und wenn mutual exclusion Mechanismus benötigt. Es ist nicht optimal, wenn man benutzt oder mißbraucht ein Mechanismus für den anderen. Im obigen Fall. ich würde vorschlagen für eine optimale Lösung, dass beide Mechanismen sind erforderlich: Mutex bieten mutual exclusion, flüchtig, um anzuzeigen, zu Compiler, „Info“ muss gelesen frisch aus Hardware sein. Ansonsten in einigen Situation (Optimierung -O2, O3), Compiler könnte versehentlich auslassen die benötigten Codes.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top