Pregunta

Yo escribo un código para Linux kernel módulo y experimentar un comportamiento extraño en ella. Aquí está mi código:

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

 }

Básicamente yo estaba tratando de esperar a que las discusiones para terminar y luego imprimir algo después de eso. El código anterior hace lograr ese objetivo, pero no "printk("debug\n");" CON comentado. Tan pronto como se comento hacia fuera printk("debug\n"); para ejecutar el código sin depurar y cargar el módulo a través de comandos insmod, se bloquea el módulo de encendido y parece que se pierde en la recursividad. No me porqué los efectos de mi código de una manera tan grande printk?

Cualquier ayuda sería apreciada.

respecto.

¿Fue útil?

Solución

Con la llamada a printk() eliminó el compilador está optimizando el bucle en while (1);. Cuando se agrega la llamada a printk() el compilador no es seguro que data no se cambia y por lo comprueba el valor cada vez a través del bucle.

Puede insertar una barrera en el bucle, lo que obliga al compilador que data reevaluar en cada iteración. por ejemplo:

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

        barrier();
}

Otros consejos

No está sincronizando el acceso a los datos variables. Lo que sucede es que el compilador generará un bucle infinito. He aquí por qué:

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

El compilador puede detectar que el valor de los datos nunca cambia dentro del bucle while. Por lo tanto se puede mover por completo el registro de salida del bucle y que va a terminar con un simple

 while (1) {} 

Si inserta printk el compilador tiene que asumir que los datos variables globales pueden cambiar (después de todo - el compilador no tiene idea de lo que printk hace en detalle), por tanto, su código comenzará a trabajar de nuevo (en una especie comportamiento no definido de manera ..)

¿Cómo solucionar este problema:

Use primitivas de sincronización de rosca adecuada. Si envuelve el acceso a los datos en una sección de código protegido por un mutex el código funcionará. También puede sustituir los datos variables y utilizar un semáforo contados en su lugar.

Editar

Este enlace se explica cómo el bloqueo en las obras de linux-kernel:

http://www.linuxgrill.com/ Anonymous / fuego / netfilter / kernel-piratería-COMO-5.html

Tal vez los datos debe ser declarada volátil? Podría ser que el compilador no va a la memoria para obtener los datos en el bucle.

La respuesta de Nils Pipenbrinck en el clavo. Voy a añadir algunos indicadores.

de Rusty Guía Informal al Bloqueo de kernel (todos los hackers del núcleo debería leer éste). turismo Els href="http://lwn.net/Articles/166195/" rel="nofollow"> adiós semáforos? , la API mutex (artículos lwn.net sobre la nueva API mutex introdujo a principios de 2006, antes de que el núcleo Linux utiliza semáforos como mutex).

Además, dado que los datos compartidos es un simple contador, sólo puede utilizar la API atómica (básicamente, declarar su contador como atomic_t y acceder a ella usando atomic_ * funciones).

fuerza volátil no siempre sea "mala idea". Uno tiene que separar el caso de cuando volátil que se necesita y cuando la exclusión mutua Se necesita mecanismo. Es no óptima cuando uno utiliza o usos indebidos un mecanismo para el otro. En el caso anterior. Yo sugeriría para solución óptima, que ambos mecanismos son necesarios: mutex para proporcionar exclusión mutua, volátil para indicar al compilador que "Información" debe ser fresca lectura del hardware. De lo contrario, en algunos situación (optimización de O2, O3), los compiladores podrían inadvertidamente dejar de lado los códigos necesarios.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top