Domanda

Sto scrivendo un codice per il kernel Linux del modulo e di sperimentare un comportamento strano in esso. Ecco il mio codice:

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");

 }

In fondo stavo cercando di aspettare per i thread per finire e quindi stampare qualcosa dopo. Il codice di cui sopra fa raggiungere tale obiettivo, ma CON "printk("debug\n");" non ha commentato. Appena io commento printk("debug\n"); per eseguire il codice senza il debug e caricare il modulo attraverso il comando di insmod, si blocca sul modulo e sembra che si perde nella ricorsione. I dont perché effetti il ??mio codice in un grande modo così printk?

Qualsiasi aiuto sarebbe apprezzato.

saluti.

È stato utile?

Soluzione

Con la chiamata printk() rimosso il compilatore ottimizza il loop in while (1);. Quando si aggiunge la chiamata a printk() il compilatore non è sicuro che data non è cambiato e così controlla il valore di ogni iterazione del ciclo.

È possibile inserire una barriera nel circuito, che costringe il compilatore di rivalutare data ad ogni iterazione. ad esempio:

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

        barrier();
}

Altri suggerimenti

Lei non è la sincronizzazione l'accesso alla variabile di dati. Quello che succede è che il compilatore genererà un ciclo infinito. Ecco perché:

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

Il compilatore in grado di rilevare che il valore dei dati non cambia mai all'interno del ciclo while. Pertanto si può muovere completamente il controllo fuori dal giro e vi ritroverete con un semplice

 while (1) {} 

Se si inserisce printk il compilatore deve assumere che i dati delle variabili globali possono cambiare (dopo tutto - il compilatore ha idea di cosa printk fa in dettaglio), pertanto il codice inizierà a lavorare di nuovo (in una sorta comportamento indefinito di modo ..)

Come risolvere questo problema:

Usa primitive di sincronizzazione corretta filetto. Se si avvolgono l'accesso ai dati in una sezione di codice protetto da un mutex il codice funzionerà. Si potrebbe anche sostituire i dati variabili e utilizzare un contato semaforo posto.

Modifica

Questo legame spiega come il blocco nelle opere linux-kernel:

http://www.linuxgrill.com/ anonimo / incendio / netfilter / kernel-hacking-HOWTO-5.html

Forse i dati dovrebbe essere dichiarato volatili? Potrebbe essere che il compilatore non sta per memoria per ottenere i dati nel circuito.

La risposta di Nils Pipenbrinck è a posto. Io solo aggiungere alcune indicazioni.

di Rusty inaffidabile Guida al Kernel di bloccaggio (ogni kernel hacker, dovrebbe leggere questo).
Addio semafori? , il mutex API ( lwn.net articoli sulla nuova API mutex introdotto nei primi mesi del 2006, prima che il kernel Linux semafori come mutex) utilizzato.

Inoltre, dal momento che i dati condivisi è un semplice contatore, si può semplicemente utilizzare l'API atomica (in pratica, dichiarare il vostro contatore come atomic_t e accedervi utilizzando atomic_ * funzioni).

potrebbe volatile non sempre essere "cattiva idea". Uno ha bisogno di separare il caso di quando volatili è necessario e quando mutua esclusione è necessario meccanismo. E non è ottimale quando si usa o abusi un meccanismo per l'altro. Nel caso di cui sopra. io suggerirei per soluzione ottimale, che entrambi i meccanismi sono necessari: mutex fornire mutua esclusione, volatile per indicare al compilatore "Info" deve essere fresco lettura dall'hardware. In caso contrario, in qualche situazione (ottimizzazione -O2, -O3), compilatori potrebbe inavvertitamente lasciare fuori i codici necessari.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top