Quando um processo está no modo de usuário, ele pode ser interrompido a qualquer momento (alternando para o modo kernel). Quando o kernel retorna ao modo de usuário, ele verifica se há algum sinal pendente (incluindo os que são usados para interromper o processo, como SIGTERM
e SIGKILL
). Isso significa que um processo pode ser eliminado apenas ao retornar ao modo de usuário.
A razão pela qual um processo não pode ser eliminado no modo kernel é que ele pode potencialmente corromper as estruturas do kernel usadas por todos os outros processos na mesma máquina (da mesma forma que matar um encadeamento pode potencialmente corromper as estruturas de dados usadas por outros encadeamentos no mesmo processo) .
Quando o kernel precisa fazer algo que pode levar muito tempo (aguardando um pipe escrito por outro processo ou aguardando o hardware fazer algo, por exemplo), ele dorme marcando-se como adormecido e chamando o agendador para mudar para outro processo (se não houver um processo que não seja adormecido, ele alterna para um processo "fictício" que instrui a CPU a desacelerar um pouco e fica em um loop - o loop inativo).
Se um sinal é enviado para um processo adormecido, ele deve ser acordado antes de retornar ao espaço do usuário e, assim, processar o sinal pendente. Aqui temos a diferença entre os dois principais tipos de sono:
TASK_INTERRUPTIBLE
, o sono interrompível. Se uma tarefa estiver marcada com esse sinalizador, ela estará em suspensão, mas poderá ser despertada por sinais. Isso significa que o código que marcou a tarefa como inativa está esperando um possível sinal e, depois que acordar, procurará por ele e retornará da chamada do sistema. Depois que o sinal é tratado, a chamada do sistema pode potencialmente ser reiniciada automaticamente (e não entrarei em detalhes sobre como isso funciona).
TASK_UNINTERRUPTIBLE
, o sono ininterrupto. Se uma tarefa estiver marcada com esse sinalizador, ela não espera ser acordada por nada além do que está esperando, porque ela não pode ser reiniciada facilmente ou porque os programas esperam que a chamada do sistema seja atômica. Isso também pode ser usado para dorme conhecido por ser muito curto.
TASK_KILLABLE
(mencionado no artigo do LWN vinculado pela resposta da ddaa) é uma nova variante.
Isso responde à sua primeira pergunta. Quanto à sua segunda pergunta: você não pode evitar interrupções ininterruptas, elas são normais (acontece, por exemplo, toda vez que um processo lê / grava no / para o disco); no entanto, eles devem durar apenas uma fração de segundo. Se eles duram muito mais, geralmente significa um problema de hardware (ou um problema de driver de dispositivo, que parece o mesmo com o kernel), em que o driver de dispositivo aguarda o hardware fazer algo que nunca acontecerá. Também pode significar que você está usando o NFS e o servidor NFS está inoperante (está aguardando a recuperação do servidor; você também pode usar a opção "intr" para evitar o problema).
Finalmente, o motivo pelo qual você não pode se recuperar é o mesmo motivo pelo qual o kernel aguarda até retornar ao modo de usuário para emitir um sinal ou interromper o processo: ele potencialmente corromperia as estruturas de dados do kernel (o código aguardando um sono interrompido pode receber um erro que informa para retornar ao espaço do usuário, onde o processo pode ser interrompido; o código aguardando um sono ininterrupto não espera nenhum erro).
TASK_UNINTERUPTIBLE
estado sempre que o sistema não está em um estado ocioso, coletando dados à força, aguardando a transmissão assim que o superusuário sai? Isso seria uma mina de ouro para hackers recuperar informações, retornar ao estado de zumbi e transmitir informações pela rede em modo inativo. Alguns podem argumentar que essa é uma maneira de criar umBlackdoor
para os poderes existentes, de entrar e sair de qualquer sistema, conforme desejado. Eu acredito firmemente que essa brecha pode ser selada definitivamente, eliminando o `TASK_UNINTERUPTIB