4.2. Deadlock: Simple y Avanzado

Hay un fallo de codificaci�n donde un pedazo de c�digo intenta obtener un spinlock dos veces: �l esperar� siempre, esperando a que el bloqueo sea liberado (spinlocks, rwlocks y sem�foros no son recursivos en Linux). Esto es trivial de diagnosticar: no es un tipo de problema de estar-cinco-noches-despierto-hablando-con-los-suaves-conejitos-del-c�digo.

Para un caso ligeramente m�s complejo, imag�nate que tienes una regi�n compartida por un bottom half y un contexto de usuario. Si usas una llamada spin_lock() para protegerla, es posible que el contexto de usuario sea interrumpido por el bottom half mientras mantiene el bloqueo, y el bottom half entonces esperar� para siempre para obtener el mismo bloqueo.

Ambas son llamadas deadlock (bloqueo muerto), y como se mostr� antes, puede ocurrir con una CPU simple (aunque no en compilaciones para UP, ya que los spinlocks se desvanecen en la compilaci�n del n�cleo con CONFIG_SMP=n. A�n tendr�s corrupci�n de datos en el segundo ejemplo).

Este bloqueo completo es f�cil de diagnosticar: en equipos SMP el cron�metro guardi�n o compilado con DEBUG_SPINLOCKS establecido (include/linux/spinlock.h) nos mostrar� esto inmediatamente cuando suceda.

Un problema m�s complejo es el tambi�n llamado `abrazo mortal', involucrando a dos o m�s bloqueos. Digamos que tienes una tabla hash: cada entrada en la tabla es un spinlock, y una cadena de objetos ordenados. Dentro de un manejador softirq, algunas veces quieres alterar un objeto de un lugar de la tabla hash a otro: coges el spinlock de la vieja cadena hash y el spinlock de la nueva cadena hash, y borras el objeto de la vieja y lo insertas en la nueva.

Aqu� hay dos problemas. El primero es que si tu c�digo siempre intenta mover el objeto a la misma cadena, �l se har� un deadlock cuando se intente bloquear dos veces. El segundo es que si la misma softirq u otra CPU est� intentando mover otro objeto en la direcci�n inversa podr�a pasar lo siguiente:

Tabla 4-1. Consecuencias

CPU 1CPU 2
Pilla bloqueo A -> OKPilla bloqueo B -> OK
Pilla bloqueo B -> spinPilla bloqueo A -> spin

Las dos CPUs esperar�n para siempre, esperando a que el otro libere su bloqueo. �l parecer�, oler�, y se sentir� como si cayera el sistema.

4.2.1. Preveniendo los Deadlocks

Los libros de texto te dir�n que si siempre bloqueas en el mismo orden, nunca obtendr�s esta clase de deadlock. La pr�ctica te dir� que este tipo de aproximaci�n no escala bien: cuando creo un nuevo bloqueo, no entiendo suficientemente el n�cleo para imaginarme d�nde est� �l en la jerarqu�a de los 5000 bloqueos.

Los mejores bloqueos est�n encapsulados; nunca estar�n expuestos en las cabeceras, y nunca se mantendr�n a trav�s de llamadas a funciones no triviales fuera del mismo archivo. Puedes leer a trav�s de este c�digo y ver que nunca har� deadlock, porque nunca intenta tener otro bloqueo mientras tiene el uso. La gente usando tu c�digo no necesita saber nunca que est�s usando un bloqueo.

Un problema cl�sico aqu� es cuando suministras retrollamadas o trampas: si las llamas con el bloqueo mantenido, arriesgas un deadlock simple, o un abrazo mortal (�qui�n sabe lo que har� la llamada?). Recuerda, los otros programadores andan detr�s de ti, por lo tanto no hagas esto.

4.2.2. Sobreentusiasmo en la Prevenci�n de Deadlocks

Los deadlocks son problem�ticos, pero no son tan malos como la corrupci�n de datos. El c�digo que obtiene un bloqueo de lectura, busca una lista, falla al encontrar lo que quiere, tira el bloqueo de lectura, obtiene un bloqueo de escritura e inserta el objeto tiene una condici�n de carrera.

Si no ves porqu�, por favor permanece jodidamente lejos de mi c�digo.