Question

Je suis en train d'écrire un code pour le module noyau linux et connaît un comportement étrange en elle. Voici mon 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");

 }

En fait je tentais d'attendre les discussions pour terminer, puis imprimer quelque chose après. Le code ci-dessus n'atteint cet objectif, mais avec "printk("debug\n");" pas fait de commentaires. Dès que je commente sur printk("debug\n"); pour exécuter le code sans débogage et charger le module via la commande insmod, le module se bloque sur et il semble que cela se perd dans récursivité. Je ne printk pourquoi les effets de mon code dans un tel chemin?

Toute aide serait appréciée.

concernant.

Était-ce utile?

La solution

Avec l'appel à printk() éliminé le compilateur optimise la boucle dans while (1);. Lorsque vous ajoutez l'appel à printk() le compilateur est pas sûr que data ne change pas et ainsi vérifie la valeur à chaque fois dans la boucle.

Vous pouvez insérer une barrière dans la boucle, ce qui oblige le compilateur à Réévaluer data à chaque itération. par exemple:

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

        barrier();
}

Autres conseils

Vous n'êtes pas synchroniser l'accès aux données variables. Ce qui se passe est que le compilateur génère une boucle infinie. Voici pourquoi:

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

Le compilateur peut détecter que la valeur des données ne change jamais dans la boucle while. Par conséquent, il peut complètement déplacer le départ de la boucle et vous finirez par un simple

 while (1) {} 

Si vous insérez printk le compilateur doit supposer que les données variables globales peuvent changer (après tout - le compilateur n'a aucune idée de ce que printk fait en détail) donc votre code commencera à travailler à nouveau (dans une sorte de chemin de comportement non défini ..)

Comment résoudre ce problème:

Utilisation des primitives de synchronisation de fil correspondant. Si vous enveloppez l'accès aux données dans une section de code protégé par un mutex le code fonctionnera. Vous pouvez également remplacer les données variables et d'utiliser un compté sémaphores à la place.

Modifier

Ce lien explique comment le verrouillage dans les travaux linux-kernel:

http://www.linuxgrill.com/ anonyme / feu / netfilter / kernel-hacking-HOWTO-5.html

Peut-être que des données doit être déclarée volatile? Il se pourrait que le compilateur ne va pas à la mémoire pour obtenir des données dans la boucle.

La réponse de Nils Pipenbrinck est sur place. Je vais juste ajouter quelques indications.

Guide de Rusty à verrouillage du noyau Unreliable (chaque hacker noyau doit lire celui-ci).
Au revoir sémaphores? , l'API mutex ( lwn.net des articles sur la nouvelle API mutex introduit au début de 2006, avant que le noyau Linux utilisé sémaphores mutex).

En outre, étant donné que vos données partagées est un simple compteur, vous pouvez simplement utiliser l'API atomique (essentiellement, déclarer votre compteur comme atomic_t et l'accès à l'aide atomic_ * fonctions).

peut Volatile pas toujours « mauvaise idée ». Il faut se séparer le cas quand est nécessaire volatile et quand l'exclusion mutuelle mécanisme est nécessaire. Il est non optimale lorsque l'on utilise ou mésusages un mécanisme pour l'autre. Dans le cas ci-dessus. je voudrais suggerer pour une solution optimale, que les deux mécanismes sont nécessaires: mutex fournir l'exclusion mutuelle, volatile pour indiquer au compilateur « Info » doit être lu frais du matériel. Dans le cas contraire, dans certains situation (optimisation -O2, -O3), compilateurs pourrait par inadvertance laisser les codes nécessaires.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top