Às vezes, sempre que eu escrevo um programa no Linux e ele trava devido a algum tipo de bug, ele se torna um processo ininterrupto e continua em execução para sempre até eu reiniciar o computador (mesmo se eu sair). Minhas perguntas são:
- O que faz com que um processo se torne ininterrupto?
- Como faço para impedir que isso aconteça?
- Essa provavelmente é uma pergunta idiota, mas existe alguma maneira de interrompê-la sem reiniciar o computador?
linux
scheduling
preemption
Jason Baker
fonte
fonte
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_UNINTERUPTIBRespostas:
Um processo ininterrupto é um processo que ocorre em uma chamada do sistema (função kernel) que não pode ser interrompida por um sinal.
Para entender o que isso significa, você precisa entender o conceito de uma chamada de sistema interrompível. O exemplo clássico é
read()
. Essa é uma chamada do sistema que pode demorar muito tempo (segundos), pois pode envolver girar um disco rígido ou mover cabeças. Durante a maior parte desse tempo, o processo ficará inativo, bloqueando o hardware.Enquanto o processo está inativo na chamada do sistema, ele pode receber um sinal assíncrono Unix (por exemplo, SIGTERM), e acontece o seguinte:
Retornar cedo da chamada do sistema permite que o código de espaço do usuário altere imediatamente seu comportamento em resposta ao sinal. Por exemplo, terminando de forma limpa em reação ao SIGINT ou SIGTERM.
Por outro lado, algumas chamadas do sistema não podem ser interrompidas dessa maneira. Se o sistema chamar paradas por algum motivo, o processo poderá permanecer indefinidamente nesse estado inábil.
O LWN publicou um bom artigo que abordou esse tópico em julho.
Para responder à pergunta original:
Como evitar que isso aconteça: descubra qual driver está causando problemas e pare de usar ou torne-se um hacker de kernel e corrija-o.
Como matar um processo ininterrupto sem reiniciar: de alguma forma, faça a chamada do sistema terminar. Freqüentemente, a maneira mais eficaz de fazer isso sem pressionar o botão liga / desliga é puxar o cabo de alimentação. Você também pode se tornar um hacker de kernel e fazer com que o driver use TASK_KILLABLE, conforme explicado no artigo LWN.
fonte
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
eSIGKILL
). 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).
fonte
Processos ininterruptos geralmente aguardam E / S após uma falha na página.
Considere isto:
O processo / tarefa não pode ser interrompido nesse estado, porque não pode manipular nenhum sinal; se isso acontecesse, outra falha de página ocorreria e estaria de volta onde estava.
Quando digo "processo", quero dizer realmente "tarefa", que no Linux (2.6) traduz aproximadamente para "thread", que pode ou não ter uma entrada individual de "grupo de threads" em / proc
Em alguns casos, pode demorar um longo tempo. Um exemplo típico disso seria onde o arquivo executável ou mmap está em um sistema de arquivos de rede em que o servidor falhou. Se a E / S tiver êxito, a tarefa continuará. Se, eventualmente, falhar, a tarefa geralmente receberá um SIGBUS ou algo assim.
fonte
Para sua terceira pergunta: eu acho que você pode matar os processos ininterruptos executando
sudo kill -HUP 1
. Ele reiniciará o init sem encerrar os processos em execução e, após executá-lo, meus processos ininterruptos se foram.fonte
Se você está falando sobre um processo "zumbi" (que é designado como "zumbi" na saída ps), esse é um registro inofensivo na lista de processos, à espera de alguém para coletar seu código de retorno e pode ser ignorado com segurança.
Você poderia descrever o que é um "processo ininterrupto" para você? Ele sobrevive ao "kill -9" e se diverte alegremente? Se esse for o caso, ele ficará preso em algum syscall, que está preso em algum driver, e você ficará preso nesse processo até a reinicialização (e às vezes é melhor reiniciar em breve) ou descarregar o driver relevante (o que é improvável) . Você pode tentar usar "strace" para descobrir onde seu processo está travado e evitá-lo no futuro.
fonte