¿Por qué no se debe adquirir un mutex en una rutina de servicio de interrupción?

Esto depende del sistema operativo, pero generalmente no se puede adquirir un mutex en un controlador de interrupciones porque los mutex se bloquean cuando se contestan, colocando el proceso en una cola de espera, poniendo el proceso en suspensión y programando un nuevo proceso para que se ejecute. En la mayoría de los sistemas, los manejadores de interrupciones no son procesos. No tienen entidades programables que los respalden. Por lo tanto, no pueden bloquear y no pueden adquirir un mutex.

Además, generalmente no querrá adquirir un mutex en un controlador de interrupciones, incluso si pudiera, ya que el controlador de interrupciones está diseñado para ejecutarse rápidamente. El potencial de un bloqueo de mutex derrotaría ese objetivo muchas veces.

Por estas razones, los sistemas a menudo dividen el procesamiento de interrupción en dos mitades. El controlador de interrupciones es la “mitad superior”, se ejecuta sincrónicamente en respuesta a la interrupción, se espera que sea rápido y no tiene contexto de proceso, por lo que no puede bloquear (a menudo roba el contexto de lo que sea que haya interrumpido). Cualquier trabajo laborioso está programado para más tarde, en la “mitad inferior” del proceso de interrupción. A menudo, la mitad inferior se ejecuta en un hilo del núcleo y, por lo tanto, puede adquirir mutexes.

Porque las rutinas de servicio de interrupción se ejecutan en contextos parcialmente prestados.

Cada proceso en ejecución tiene un contexto. Cuando los procesos cambian, intercambia contextos (llamado como cambio de contexto). Cuando un mutex en el proceso P1 duerme, la CPU puede programar otro proceso P2 usando el cambio de contexto. Cuando el mutex se activa, el contexto del proceso de suspensión P1 se restaura y la ejecución continúa.

Cuando un dispositivo genera una interrupción, el contexto del proceso se cambia parcialmente a interrupciones de servicio rápidamente y restablece el pin de interrupción en el dispositivo. Si una interrupción tiene un mutex y duerme, la CPU no sabrá cómo guardar y restaurar este contexto correctamente. En segundo lugar, si hay un mutex dormido, la interrupción puede no ser atendida tan rápidamente. Las interrupciones deben ser atendidas rápidamente para que los dispositivos de hardware puedan reanudarse (en lugar de esperar la interrupción). Además, varios dispositivos pueden compartir una sola línea de interrupción y tomar demasiado tiempo para dar servicio a una interrupción puede evitar que otro dispositivo provoque una interrupción. Por lo tanto, no se permite dormir en las rutinas de servicio de interrupción en la mayoría de los sistemas operativos.

¡Puedes usar un spin-lock en su lugar!

Cuando un subproceso intenta adquirir un mutex y si no tiene éxito, ya sea debido a que otro subproceso ya lo ha adquirido o debido a un cambio de contexto, el subproceso se pone en suspensión hasta que se activa, lo cual es crítico si se usa en un ISR.

Mientras que cuando un hilo no logra adquirir un spin-lock, intenta continuamente adquirirlo, hasta que finalmente tiene éxito, evitando así dormir en un ISR. El uso de spin-locks en la “mitad superior” es una práctica común que se sigue al escribir controladores de interrupción de controladores de dispositivos Linux.

Creo que seriamente tendría que cuestionar mi diseño si requiriera algún tipo de bloqueo de datos en un controlador de interrupciones. Si necesita trabajar exclusivamente con datos en un controlador de interrupciones, debe usar las funciones atómicas pero no como un bloqueo de datos. Esta es una excelente manera de indicarle a la mitad inferior que se ocupe.