4.10. Cronómetros de Carreras: Un Pasatiempo del Núcleo

Los cronómetros pueden producir sus propios problemas con las carreras. Considera una colección de objeros (listas, hash, etc) donde cada objeto tiene un cronómetro que lo va a destruir.

Si quieres destruir la colección entera (digamos en el borrado de un módulo), quizás realices lo siguiente:


        /* ESTE CÓDIGO ES MALO MALO MALO MALO: SI HUBIERA ALGO PEOR
           USUARÍA NOTACIÓN HÚNGARA */
        spin_lock_bh(&list_lock);

        while (list) {
                struct foo *next = list->next;
                del_timer(&list->timer);
                kfree(list);
                list = next;
        }

        spin_unlock_bh(&list_lock);
    

Tarde o temprano, esto rompería en SMP, porque un cronómetro puede acabar antes que spin_lock_bh(), y sólo obtendría el bloqueo después de spin_unlock_bh(), y entonces intentaría liberar el elemento (¡el cual ya ha sido liberado!).

Esto puede ser eliminado comprobando el resultado de del_timer(): si retorna 1, el cronómetro ha sido borrado. Si 0, significa (en este caso) que está actualmente ejecutándose, por lo tanto lo que podemos hacer es:


        retry:  
                spin_lock_bh(&list_lock);

                while (list) {
                        struct foo *next = list->next;
                        if (!del_timer(&list->timer)) {
                                /* Le da al cronómetro una oportunidad para borrarlo */
                                spin_unlock_bh(&list_lock);
                                goto retry;
                        }
                        kfree(list);
                        list = next;
                }

                spin_unlock_bh(&list_lock);
    

Otro problema común es el borrando de cronómetros que se reinician a ellos mismos (llamando a add_timer() al final de su función cronómetro). Porque este es un caso bastante común que es propenso a carreras, puedes poner una llamada a timer_exit() muy al funal de tu función cronómetro, y usar del_timer_sync() para manejar este caso. Él retorna el número de veces que el cronómetro tuvo que ser borrado antes de que finalmente lo paráramos añadiéndolo otra vez.