Conheça e entenda como funcionam os processos Pai, Filhos, Órfãos e Zumbis em sistemas baseados em UNIX, principalmente o Linux.
| Se você apoia nosso site, desative o AdBlock quando visitá-lo, inclusive em Mobile!
Os anúncios são poucos e não invasivos. Se quiser contribuir com nosso trabalho, clique em qualquer banner de sua preferência, exceto dos Parceiros. Mais detalhes clicando aqui.
1. Introdução
Nos sistemas operacionais de maneira geral, processo é o nome que damos a um programa em execução.
É o programa estando em execução, que utiliza os recursos do computador – processador, memória, etc – para a realização das tarefas.
Em outras palavras, abriu o Chrome? Ele deixa de ser um mero programa e se torna um Processo. A seguir, você verá os principais conceitos relacionados a processos dos sistemas baseados em UNIX e as ferramentas usadas para gerenciá-los.
2. Noções Básicas
O sistema operacional lida com uma infinidade de processos e, por isso, é necessário ter meios que permitam controlá-los. Para isso, os processos contam com um conjunto de características, dentre as quais:
- Proprietário do processo. – qual usuário iniciou.
- Estado do processo – em espera, em execução, etc.
- Prioridade de execução. – na fila de execução
- Recursos de memória. – quanto será alocado
O trabalho de gerenciamento de processos precisa contar com as informações acima e com outras de igual importância para que as tarefas sejam executadas da maneira mais eficiente. Um dos meios usados para isso é atribuir a cada processo um PID.
3. PID e PPID
Um PID – Process Identifier – é um número de identificação que o sistema dá a cada processo. Para cada novo processo, um novo número deve ser atribuído, ou seja, não se pode ter um único PID para dois ou mais processos ao mesmo tempo.
O PID funciona como um CPF para os processos!
Os sistemas baseados em Unix precisam que um processo já existente se duplique para que a cópia possa ser atribuída a uma tarefa nova. Quando isso ocorre, o processo copiado recebe o nome de processo pai, enquanto que o novo é denominado processo filho. É nesse ponto que o PPID – Parent Process Identifier – passa a ser usado: o PPID de um processo nada mais é do que o PID de seu processo pai.
4. Sinais de Processos
Os sinais são meios usados para que os processos possam se comunicar e para que o sistema possa interferir em seu funcionamento. Por exemplo, se o usuário executar o comando kill para interromper um processo, isso será feito por meio de um sinal.
Quando um processo recebe um determinado sinal e conta com instruções sobre o que fazer com ele, tal ação é colocada em prática. Se não houver instruções pré-programadas, o próprio kernel Linux pode executar a ação de acordo com suas rotinas. Entre os sinais existentes, tem-se os mais populares:
- STOP (-17 ou -19) – esse sinal tem a função de interromper a execução de um processo e só reativá-lo após o recebimento do sinal CONT;
- CONT (-18 ou -25) – esse sinal tem a função de instruir a execução de um processo após este ter sido interrompido;
- SEGV (-11) – esse sinal informa erros de endereços de memória;
- TERM (-15) – esse sinal tem a função de terminar completamente o processo, ou seja, este deixa de existir após a finalização;
- ILL (-4) – esse sinal informa erros de instrução ilegal, por exemplo, quando ocorre divisão por zero;
- KILL (-9) – esse sinal tem a função de “matar” um processo e é usado em momentos de criticidade.
A especificação Single Unix Specification apresenta os seguintes sinais definidos, no kernel, no arquivo de cabeçalho <signal.h> em Linguagem C.
Apresentar-lo-ei a lista completa para vocês, como curiosidade:
- SIGABRT – processo abortado
- SIGALRM – sinal levantado por alarme
- SIGBUS – erro de barramento: “access to undefined portion of memory object”
- SIGCHLD – sinal enviado a um processo filho, preservando o pai
- SIGCONT – continuar um processo parado
- SIGFPE – exceção de ponto flutuante: “erroneous arithmetic operation”
- SIGHUP – término de comunicação com terminal
- SIGILL – instrução ilegal
- SIGINT – interrupção
- SIGKILL – kill (-9)
- SIGPIPE – escrita em uma canalização em que nenhum processo lê
- SIGQUIT – quit – sair
- SIGSEGV – falha de segmentação
- SIGSTOP – parada temporária na execução
- SIGTERM – término (código -15)
- SIGTSTP – término enviado por um terminal de controle
- SIGTTIN – tentativa de leitura (“in”) de um processo em “background”
- SIGTTOU – tentativa de escrita (“out”) de um processo em “background”
- SIGUSR1 – definida pelo usuário 1
- SIGUSR2 – definida pelo usuário 2
- *SIGPOLL – evento pesquisável
- *SIGPROF – temporizador expirado
- *SIGSYS – chamada de sistema incorreta invocada
- *SIGTRAP – trap
- SIGURG – dados urgentes disponíveis em um socket
- *SIGVTALRM – sinal disparado por um temporizador de tempo virtual: “virtual timer expired”
- *SIGXCPU – limite de tempo da CPU excedido
- *SIGXFSZ – limite de tamanho de arquivo excedido
Nota: As seções marcadas por um asterisco denotam antigas extensões da X/Open System Interfaces (XSI). As demais são as utilizadas na especificação Single Unix Specification (SUS). A especificação XSI é mais antiga, a atual, coordenada pela The Open Group, proprietária da marca UNIX®, cuida da SUS que se tornou o atual padrão. Alguns sistemas atuais utilizam de extensões XSI de maneira não oficial.
O kill também é um comando que o usuário pode usar para enviar qualquer sinal da tabela, porém, se ele for usado de maneira isolada, ou seja, sem o parâmetro de um sinal, o kill por padrão executa o sinal TERM, encerrando o processo. A sintaxe para a utilização do comando kill é a seguinte:
$ kill -SINAL PID
Como exemplo, vamos supor que você deseja interromper temporariamente a execução do processo de PID 4220. Para isso, pode-se usar o seguinte comando:
$ kill -STOP 4220
Para que o processo 4220 volte a ser executado, basta usar o comando:
$ kill -CONT 4220
Se o sinal precisa ser enviado a todos os processos, pode-se usar o número -1 no lugar do PID. Por exemplo:
$ kill -STOP -1
Se preferir usar SIGTERM como seu número correspondente, faça assim:
$ kill -15 4220
Sem um parâmetro o comando kill vai mandar um SIGTERM para que o processo feche de maneira “amigável”.
$ kill 4220
Como já dito, usar o comando kill isoladamente – por exemplo, kill 4220 – faz com que este use o sinal TERM por padrão. Esse sinal, no entanto, pode ser ignorado ou acatado pelos processos, por opção deles.
É por isso que quando se pretende matar um processo em caráter emergencial, é melhor usar o comando “kill -9 PID” para isso, pois o número nove representa o sinal kill e este, junto do SIGSTOP, não pode ser ignorado pelo processo: o comando parte do Kernel quem dá a ordem máxima de encerramento naquele momento!
Se o comando Kill 9 for dado, o processo deve morrer!
Isso deixa claro que se você conhecer o número que é atribuído a um sinal, você pode usá-lo no lugar de seu nome. Com exceção de alguns sinais, a numeração de cada um pode mudar de acordo com a distribuição ou com a versão do kernel. Como mostrado acima, alguns sinais são usados no BSD, outros são de padrões POSIX de 1990, ante o atual de 2001.
Agora, imagine que você não saiba qual o PID de um processo e tenha se esquecido que o comando ps – visto mais à frente – descobre tal informação. Neste caso, pode-se usar o comando killall, desde que você saiba o nome do processo. A sintaxe é:
$ killall -SINAL processo
Por exemplo:
$ killall -stop firefox
Ou apenas como SIGTERM para fechar o Firefox:
$ killall firefox
5. Estado de um Processo
Quando um processo é criado, isso não significa que ele será imediatamente executado. Além disso, determinados processos podem ser temporariamente paralisados para que o processador possa executar um processo prioritário, de acordo com a fila de prioridade.
Como devem saber, um computador multitarefas não executa tudo em tempo real, ou seja, ao mesmo tempo, mas atribui um tempo de execução: pausa aquele processo, executa o próximo da fila, por assim vai.
Centenas de processos podem ser executados em poucos segundos dando a sensação enganosa de que o computador é multitarefas. Com exceção dos processos em tempo real, como a reprodução de uma música, os demais devem respeitar a fila de espera/execução. Isso quer dizer que os processos, em certos momentos, podem estar em situações de execução diferentes.
Esclarecendo: Num computador com um processador com mais de 1 núcleo, cada núcleo pode executar um processo – Assim como na linha Intel Hyperthread, um núcleo pode executar um processo principal e, com as flags remanescentes, pode executar mais processos (núcleo virtual)
Os sistemas baseados em UNIX trabalham, essencialmente, com quatro tipos de estados:
- Executando: o processo está executando nesse momento, em tempo real ou numa fila sequencial.
- Dormindo: o processo precisa aguardar alguma coisa acontecer para ser executado. Só depois dessa “coisa” acontecer é que ele passa para o estado executando.
- Parado: o processo está “congelado”, ou seja, não pode ser executado.
- Zumbi: o processo é considerado “morto”, mas, por alguma razão, ainda existe na tabela de processos.
6. Processos Pai e Filhos
Um processo que cria outros é chamado de processo Pai. Já os processos gerados por este pai são chamados de processos filhos. Isso é decidido no momento em que um programa é construído, quando se define se o processo pai continua sendo executado – de maneira concorrente – com os seus filhos ou se espera que os seus filhos – ou alguns deles – sejam encerrados.
A ideia de pai>filho é bem mais simplista do que parece:
Não existe uma hierarquia avô, pai, filho e neto… Se um processo pai1 gera um filho1, e o filho1 tiver um filho2, o filho1 pode ser chamado de processo pai2 do filho2. Da mesma maneira que um único pai pode ter muitos filhos.
Por fim, é importante saber que os sistemas operacionais da família Windows não permitem que os filhos continuem “vivos” se o processo pai foi encerrado. Assim, ao matar o pai, todos os filhos devem morrer. Esse trabalho de encerrar os filhos, após a morte do pai, é tipicamente feito pelo próprio sistema. Esse é o chamado encerramento em cascata.
Nos sistemas baseados em UNIX, funciona de forma diferente: Se um pai for encerrado, os filhos recebem um novo pai: o processo SystemD, para sistemas mais atuais como o Ubuntu ou Fedora; ou o processo Init, caso seja um sistema como o Debian em suas versões mais antigas.
De certa forma isso dá estabilidade no sistema pois um processo importante não é encerrado em caso de travamento de um processo pai; porém gera oportunidade para problemas, caso o sistema pare por inanição de recursos consumidos por processos zumbis – falaremos deles mais abaixo.
7. O “Mr. Catra” dos Sistemas Operacionais
O SystemD é um grande pai nos sistemas, principalmente o Linux; dentre seus filhos está a interface de usuário, processos de gestão de usuários e grupos, conexão á internet, etc.
Para ver todos os processos do sistema, seus pais e filhos, digite no terminal:
$ pstree
Cada pai é um “tronco” e cada filho é um “galho”
Exemplo:
systemd──ModemManager─┬─{gdbus} .................................................└─{gm ain}
No exemplo acima, o SystemD é pai do ModemManager
ModemManager é filho do SystemD e ao mesmo tempo é pai dos seguintes filhos: {gdbus} e {gmain}
Note que o SystemD ou Init é o primeiro no topo, pai de todos, cujo “pai” deste pai é o kernel Linux, quem o cria no momento do boot do sistema!
8. Órfãos
O nome foi muito bem escolhido: O processo pai terminou/morreu e o processo atual filho agora é órfão. No entanto todo processo de sistemas baseados em UNIX precisam de um pai, por isso o sistema vai automaticamente fazer com que o processo init/systemd adote o processo órfão. Essa operação é chamada reparenting. Numa situação normal o processo init/systemd não deve ter muitos filhos adotados; Normalmente eles morrem pouco tempo após a adoção por outros motivos.
A criação intencional de processos órfãos é normalmente ligada a daemons – processos que rodam em background e não precisam de interação de usuário ou comandos stdin/stdout/stderr. Normalmente são processos benéficos e desejados e não há com que se preocupar.
Por outro lado, processos órfãos também podem ser criados se o processo pai morre ou é morto sem fazer a limpeza necessária e simplesmente abandona os processos filhos. Nesse caso eles vão continuar rodando e consumindo recursos do sistema, o que geralmente não é bom. Isso ocorre com frequência em programas executados pelo Wine nos sistemas Linux, BSD e macOS. Como o Wine é o processo Pai que controla todos os demais ali dentro, inclusive os .exe, caso ele morra, pode deixar vários processos em aberto consumindo recursos do sistema.
Não existe uma forma simples de identificar processos órfãos, exceto examinar todos os filhos do processo init/systemd e verificar se eles são legítimos ou não.
Você pode verificar todos os processos do sistema, com seus respectivos filhos, com o comando:
$ pstree
Repetindo o exemplo acima:
Cada pai é um “tronco” e cada filho é um “galho”
Exemplo:
.........systemd──ModemManager─┬─{gdbus} .........................................................└─{gm ain}
Caso o ModemManager morra, deixará o {gdbus} e o {gmain}
órfãos, que serão adotados pelo SystemD, ficando assim:
.........systemd─┬─{gdbus} .........................└─{gmain}
OBS: Acima foi um caso hipotético, é mais provável que os filhos morram caso o pai também morra.
Para matar um processo órfão, um simples kill (term -15 ou kill -9) resolve o caso.
9. Zumbi
Quando um processo pai gera um filho ele aguarda a conclusão desse filho e no encerramento do mesmo – terminated – lê o código de saída; esse código funciona como uma carta de despedida. Quando isso acontece o processo é retirado da tabela de processos e a vida continua!
No entanto algum bug no código do processo pai pode criar um processo filho mas nunca ler o código de saída do mesmo. É como a carta de despedida que nunca chegou. Por isso o processo vai estar encerrado – terminated – mas ainda vai constar na tabela de processos.
Os zumbis usam um pouco de memória, mas geralmente não representam um problema. A entrada na tabela de processos é pequena, mas, até que seja liberada, o ID do processo não pode ser reutilizado e em um sistema de 64 bits, isso estará longe de causar algum transtorno.
Um grande número de zumbis pode, possivelmente, afetar a quantidade de memória livre para outros processos. Se você tiver uma horda de zumbis, no entanto, você está com um problema sério com um aplicativo pai ou um bug do sistema operacional e isso poderá congelar o sistema completamente por inanição de recursos.
Para encontrar processos Zumbis em seu sistema:
$ ps aux | egrep "Z | defunct"
Eles serão exibidos como:
O problema é matar processos zumbis.
Você não pode simplesmente matar um processo zumbi porque ele já está morto. Ele não responderá a nenhum sinal porque foi removido da memória – não há para onde enviar um SIGKILL. Você pode tentar enviar o SIGCHLD para o processo pai, mas se não funcionou quando o processo filho foi encerrado, também é improvável que funcione agora.
Como você mata algo que já está morto?
Uma opção – que normalmente não vai funciona em sistemas gerenciados pelo init mas foi um problema que foi corrigido no SystemD – é descobrir qual o processo pai do zumbi e mandar um SIGCHLD pra ele. (kill -17).
9.1 Exemplo
O ID do processo do primeiro zumbi encontrado é 7641, mas precisamos encontrar o ID do seu processo pai. Podemos fazer isso usando ps novamente. Usaremos a opção de saída ( -o) para informar a exibição apenas do ID de processo do pai e, em seguida, passá-lo com o ppid=sinalizador.
O processo que queremos encontrar será indicado usando a opção -p (processo) e, em seguida, passando o ID do processo do zumbi.
Portanto, digitamos o seguinte comando para pesquisar as informações do processo para o processo 7641, mas ele reportará apenas o ID do processo pai:
$ ps -o ppid = -p 7641
Encontramos o ID do processo pai, que é 7636. Agora podemos fazer uma referência cruzada usando ps mais uma vez.
$ ps aux | grep 7636
Para encerrar o processo pai, use a opção SIGKILL com o comando kill da seguinte maneira:
$ kill -SIGKILL 7636
Dependendo do proprietário do processo pai, você precisará usar sudo.
10. Processos com Comando TOP
O comando TOP exibe um resumo do que está acontecendo no sistema.
Digite:
$ top
E você verá no cabeçalho dele, por exemplo, isto:
Tarefas: 186 total, 1 executando, 133 dormindo, 0 parado, 0 zumbi
São a quantidade de processos no total, executando, dormindo, parados e zumbis!
11. Curiosidade
Quer criar um processo Zumbi?
Crie um arquivo de texto plano, como no Gedit ou Pluma, com o nome de zumbi.c e insira isto:
//COMEÇO DO CODIGO #include <stdlib.h> #include <sys/types.h> #include <unistd.h> int main () { pid_t child_pid; child_pid = fork (); if (child_pid > 0) { sleep (60); } else { exit (0); } return 0; } //FIM DO CODIGO
OBS: Substitua todos os sinais de + por espaçamento!
[um sinal de +] = [um espaço]
Compile o arquivo usando seu terminal:
$ cd localizacao-do-arquivo-zumbi.c $ gcc -Wall zumbi.c -o zumbi
Ao término, você terá um arquivo binário chamado zumbi.
Execute-o:
$ ./zumbi &
O & ao final do comando define que o código fique em background e a execução do binário se transforme num processo.
Agora ao rodar o comando
$ top
ou
$ ps -aux | grep Z
você verá que temos 1 processo zumbi em execução!
Se seu sistema utiliza o daemon init:
Mate-o fechando o Terminal em que foi aberto.
Caso ele ainda exista, tente matá-lo com $ kill -9 zumbi
Se ficar atrelado ao desktop environment, só poderá ser morto quando o sistema reiniciar.
Se seu sistema utiliza o daemon systemd:
Basta executar:
$ kill -9 zumbi
E ele será imediatamente morto.
12. Conclusão
Entender como os processos do sistema funcionam é uma base importante para qualquer usuário de sistemas baseados em UNIX: Te dará maior controle do que está acontecendo e até vai te ajudar a identificar quais processos estão consumindo recursos de hardware, causando aquele delay na execução de programas e até causando um lag terrível em determinado game.
#UrbanCompassPony
Fontes:
HowToGeek
GeekLinuxMan: Orfãos vs Zumbis
ITnerante: Sistemas e Processos
Wikipedia: Sinais
Arte do World War Z The Game
Autodidata, me aprofundei em sistemas operacionais baseados em UNIX®, principalmente Linux. Também procuro trazer assuntos correlacionados direta ou indiretamente, como automação, robótica e embarcados.
Ótimo. Obrigado por compartilhar o seu conhecimento.