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.