Li que não se deve usar uma chamada de sistema de bloqueio em um manipulador de interrupção.
Para sistemas de processador único, isso faz sentido, mas, para sistemas multiprocessadores, tal operação de bloqueio realmente bloqueará o sistema inteiro? Ou apenas o processador em que ele roda?
Baseado em: https://static.lwn.net/images/pdf/LDD3/ch10.pdf
Quando uma interrupção é recebida pelo processador, ele primeiro executa um pouco de código assembler específico da arquitetura e depois salta para
do_IRQ
: uma parte do código do manipulador de interrupções que é comum a todas as interrupções.Do parágrafo Os aspectos internos do tratamento de interrupções no x86 (página 11 do link acima):
Então o controlador de interrupção tem permissão para gerar outra instância da mesma interrupção, mas qualquer processador que tentasse lidar com isso seria bloqueado por um spinlock até que a instância atual da interrupção fosse tratada. Em outras palavras, outros processadores/núcleos não são bloqueados de executar código : eles são apenas bloqueados de entrar no mesmo manipulador de interrupção que agora está sendo executado no núcleo atual. E o bloqueio é com um spinlock, então a expectativa é que a espera necessária seja muito curta.
Uma chamada de sistema de bloqueio é aquela que envolve esperar que algo aconteça: enquanto espera, o processador pode ser (e normalmente é) programado para executar outras tarefas.
Mas se o núcleo atual (que está executando um manipulador de interrupção) for agendado para executar outras tarefas/processos, o spinlock que ele está segurando é deixado bloqueado. E não há garantia de que o contexto que iniciou o manipulador de interrupção seria agendado para execução novamente em um tempo razoável. Enquanto isso, se a mesma interrupção for sinalizada novamente, qualquer processador que tentar manipulá-la será mantido no spinlock. A menos que o contexto de interrupção que esperou seja prontamente agendado para execução novamente, conclua o processamento de interrupção e desbloqueie o spinlock, há um risco de que todos os núcleos acabem presos pelo spinlock, causando um deadlock completo no sistema.
Portanto, um núcleo que esteja executando um manipulador de interrupção não deve ser agendado para outras tarefas até que o manipulador de interrupção seja concluído. Uma interrupção de nível mais alto pode antecipar o contexto de interrupção atual, mas, uma vez concluído, o núcleo deve retornar para concluir o manipulador de interrupção o mais rápido possível.
E assim, o "não deve usar uma chamada de sistema de bloqueio em um manipulador de interrupção" é, na verdade, apenas um subconjunto de "você não deve fazer com que um núcleo seja agendado para outras tarefas enquanto estiver executando um manipulador de interrupção" .
(Historicamente, quando o Linux começou como um sistema operacional de processador único, costumava haver um único Big Kernel Lock que era usado para controlar o acesso a muitas partes do kernel. Quando o suporte a vários processadores foi adicionado, isso logo se tornou um problema de limitação de desempenho, e muito esforço foi gasto na transição do Big Kernel Lock para métodos sem bloqueio sempre que possível e para bloqueios mais refinados de outra forma.)