Process management - Jorge Peixoto
Transcript of Process management - Jorge Peixoto
Process Management 1
Process ManagementProcess Managementbaseado na versão 2.6 do kernel do Linux
Jorge Luiz Silva [email protected]@{cos.ufrj.br, gmail.com}
PESC / COPPE / UFRJSistemas OperacionaisProf. Vitor Santos Costa, Ph.D.
Process Management2
Introdução e Motivação Introdução e Motivação O que é um processo?
Um programa em execução. É composto de:
Espaço deendereçamento
ThreadsKerneldata
Sinaispendentes
Estado
Arquivosabertos
PCPilha
Registradores
Process Management3
Introdução e Motivação Introdução e Motivação Ciclo de vida do processo:
Reproduz (assexuadamente):exec() ou fork()
Nasce:fork() ou exec()
Cresce:faz_algo()
Morre:exit() ou
Sinal
Reclicla:wait()
Slab allocator
Process Management4
ProgramaçãoProgramação Descritor de Processos Estados de Processos Contexto de Processo vs de
SistemaEspaço de Usuário vs de Sistema
Hierarquia de Processos Criação de Processos Copy-on-Write fork() copy_process()
vfork() Threads Threads – Implementação Kernel Threads Finalização de Processos do_exit() Remoção do Descritor de
Processos release_task() Processos Órfãos
Process Management5
Descritor de ProcessosDescritor de Processos Em Linux:
task = process O kernel mantém os
processos numa lista circular duplamente encadeada chamada task list.
Cada elemento da lista é um process descriptor do tipo struct task_struct
Process Management6
Descritor de ProcessosDescritor de Processos struct task_struct é alocado
dinamicamente via slab allocator que provê reuso de objetos e cache coloring. [cap. 11]
Antes do kernel 2.6, task_struct era alocado estaticamente no final da pilha de kernel de cada processo, dessa forma era possível calcular a localização da estrutura através do ponteira da pilha. O objetivo era economizar registradores.
Atualmente, um ponteiro é armazenado em struct thread_info que fica localizado na final da pilha.
Process Management7
Descritor de ProcessosDescritor de Processos PID identifica unicamente um processo no sistema. PID é do tipo pid_t (tipicamente um int). Por questões de
compatibilidade o valor máximo é 32.768 (short int). O administrador por alterar esse valor em /proc/sys/kernel/pid_max
Processos são tipicamente referenciados por um ponteiro para seu task_struct, conseqüentemente, é interessante que o acesso seja rápido (implementado pelo macro current).
Sua implementação é dependente da arquitetura. No x86, o endereço da pilha de kernel do processo é usado calcular o endereço de thread_info que contém task_struct. No PowerPC, o valor é armazenado diretamente num registrador.
Process Management8
Estados de ProcessosEstados de Processos TASK_RUNNING: processo ou está
rodando, ou está na fila esperando para rodar.
TASK_INTERRUPTIBLE: processo está dormindo (bloqueado) esperando por algum recurso. Muda para TASK_RUNNING, se for liberado o recurso ou receber um sinal.
TASK_UNINTERRUPTIBLE: idêntico ao anterior, exceto que o processo não acorda se receber um sinal.
TASK_ZOMBIE: o processo finalizou, mas seu pai ainda não chamou a system call wait().
TASK_STOPPED: a execução do processo está congelada; o processo não está executando nem é executável.
Process Management9
Contexto de Processo Contexto de Processo vsvs de Sistema de SistemaEspaço de Usuário Espaço de Usuário vsvs de Sistema de Sistema Programas “normais”
executam em process context e em user mode.
Quando um programa “normal” chama uma syscall ou dispara uma exceção, ele entra em kernel mode.
Em system context, o kernel não está representando um processo, mas executando um interrupt handler.
Process Management10
Hierarquia de ProcessosHierarquia de Processos
Todos os processos são filhos de init (PID 1).Na inicialização, o último passo do kernel é
chamar o init que chama o script inittab que conseqüentemente chama outros programas.
Todo processo tem apenas um pai, mas um pai pode ter zero ou mais processos filhos.
O relacionamento entre processos está registrado no descritor de processos.
É possível seguir na hierarquia de processos de qualquer processo para qualquer outro.
Process Management11
Criação de ProcessosCriação de Processos A maioria dos sistemas
operacionais usa um mecanismo de spawn para criar um novo processo a partir de um outro executável.
No Unix, são usadas duas funções distintas: fork() e exec().
fork() cria um processo filho idêntico ao pai, exceto pelo PID, PPID, e alguns recursos, como: estatísticas do processo e sinais pendentes.
exec()carrega e executa um novo programa.
Outros SOs: fork() + exec()
if((result = fork()) == 0) { /* child code */ if(execve("new_program", ...) < 0) perror {"execve failed"); exit (1); } else if(result < 0) { perror("fork"); /* fork failed */ ) /* parent continues here */
Process Management12
Copy-on-WriteCopy-on-Write Como alternativa a significante ineficiência do fork(),
no Linux, o fork() é implementado usando uma técnica chamada copy-on-write (COW).
Essa técnica atrasa ou evita a cópia dos dados. Ao invés de copiar o espaço de endereçamento do processo pai, ambos podem compartilha uma única cópia somente leitura. Se uma escrita é feita, uma duplicação é feita e cada processo recebe uma cópia. Conseqüentemente, a duplicação é feita apenas quando necessário, economizando tempo e espaço.
O único overhead realmente necessário do fork() é a duplicação da tabela de páginas do processo pai e a criação de um novo PID para o filho.
Process Management13
fork()fork()
O Linux implementa fork() através da syscall clone() que recebe como entrada várias flags que especificam que recursos devem ser compartilhados.
fork() chama do_fork() que chama copy_process(), onde é feito a maior parte do trabalho.
Process Management14
copy_process()copy_process() Chama dup_task_struct() que cria uma nova pilha de kernel, as estruturas
thread_info e task_struct. Os valores são iguais ao do processo pai. Checa se o novo filho não irá exceder os limites de recursos do usuário. Vários campos do descritor do processo são zerados ou atribuídos valores iniciais.
Dados estatísticos do processo não são herdados. A parte principal dos dados do descritor do processo é compartilhada.
Ao estado do processo filho é atribuído TASK_UNINTERRUPTIBLE. copy_process() chama copy_flags() para atualizar os flags de
task_struct. Chama get_pid() para atribuir o novo PID do processo filho. Dependendo dos flags passado à syscall clone(), copy_process() ou
duplica ou compartilha arquivos abertos, informações de sistema de arquivo, signal handlers, espaço de endereçamento e namespace. Esses recursos são tipicamente compartilhados entre threads.
Então, o restante de time slice é dividido entre o processo pai e o filho. Finalmente, copy_process() retorna para um ponteiro para o novo processo
filho.
Process Management15
vfork()vfork()
Mesmo efeito do fork(), exceto por não copiar a tabela de páginas do processo pai.
Filho executa diretamente no espaço de endereçamento do pai.
Pai fica bloqueado até o filho chamar exec() ou sair. Não é permitido ao filho escrever no espaço de
endereçamento do processo pai. Otimização sugerida nos tempos de 3BSD. Hoje, com o copy-on-write, o único benefício é a não
cópia da tabela de páginas do processo pai.
Process Management16
ThreadsThreads Em Linux, threads = processos Thread é meramente um processo que
compartilha recursos com outros processos. Abordagem diferente do Microsoft
Windows e do Sun Solaris que explicitamente têm suporte do kernel para threads (lightweight processes).
Exemplo: em Solares: existem 2 processos que consistem de 3 e 2 threads cada. Existirá um descritor de processos que aponta para cada conjunto de threads descrevendo os recursos compartilhados, como, o espaço de endereçamento e arquivos aberto. Cada thread então descreve os recursos que cada uma possui. Em Linux, simplesmente existe 5 processos e 5 estruturas task_struct. Os processos estão configurados para compartilhar certos recursos.
Process Management17
Threads – ImplementaçãoThreads – Implementação Criados pela syscall clone(). Exemplo de chamada:
clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);
Essa chamada criará uma thread que compartilha o espaço de endereçamento, recursos dos sistema de arquivos, descritores de arquivos e signal handlers.
Os flags passados para a syscall clone() descrevem o comportamento do processo filho e detalha os recursos compartilhados. Outros exemplo:fork() = clone(SIGHLD, 0);vfork() = clone(CLONE_VFORK | CLONE_VM | SIGHLD, 0);
Process Management18
Kernel ThreadsKernel Threads
Kernel threads são processos que rodam apenas no espaço do kernel, não há mudança de contexto para o espaço de usuário.
Kernel threads não possuem espaço de endereçamento (ponteiro para mm é NULL).
São preemptivas e escalonáveis como qualquer outro processo.
São criadas por apenas outras kernel threads. Assim como os processos normais, são criados através
da syscall clone() com o uso de flags especiais. Exemplos: pdflush, ksoftirqd, nfsd (equivalente).
Process Management19
Finalização de ProcessosFinalização de Processos
O kernel libera os recursos e notifica o processo pai.
A finalização do processo pode ocorrer:– Voluntariamente e explicitamente, através da
chamada a syscall exit();– Voluntariamente e implicitamente, com o retorno da
função main() de qualquer programa;– Involuntariamente, quando o processo recebe um
sinal ou quando ocorre um exceção que não pode tratar ou ignorar.
Process Management20
do_exit()do_exit() Ativa o flag PF_EXITING em task_struct. Invoca del_timer_sync() para remover qualquer timer de
kernel. Após o retorno, é garantido que nenhum timer estará enfileirado e nenhum timer handler estará rodando.
Se BSD process accounting estiver ativo, chama acct_process().
Chama __exit_mm() para liberar mm_struct, se não estiver compartilhado, desaloca.
Chama exit_sem() para liberar semáforos. Chama __exit_files(), __exit_fs(), exit_namespace(),
and exit_sighand(). Atribuí o código de saída do processo (variável exit_code de
task_struct) para posterior análise pelo processo pai. Chama exit_notify() e atribui o estado TASK_ZOMBIE. Chama schedule().
Process Management21
Remoção do Descritor de ProcesosRemoção do Descritor de Procesos
Finalizada a syscall exit(), o processo ainda existe!
Somente após chamar a syscall wait4(), o processo é liberado (descritor de processos é desalocado).
Os únicos objetos associados ao processo são a sua pilha de kernel, thread_info e task_struct.
O funcionamento padrão do wait() é suspender o processor chamador até que um filho finalize. Retorna o PID do filho.
Process Management22
release_task()release_task() Sua função é liberar o descritor de processos. Chama free_uid() para decrementar o contador de
uso de processos do usuário. Unhash_process(), remove o processo da tabela hash
de PID e remove o processo da task list. Se ptrace foi usado, repatriar o processo para o pai
original e remove da ptrace list. Chama put_task_struct() para liberar as páginas
contendo a pilha de kernel do processo e a estrutura thread_info e desalocar o slab cache contendo task_struct.
Process Management23
Processos ÓrfãosProcessos ÓrfãosReparent o processo órfão a um processo do
grupo que pertence, se falha, ao processo init.Evitar o acumulo de processo zumbis,
desperdiçando memória.
Process Management24
RevisãoRevisão Processo é uma das abstrações fundamentais do Linux Relação entre processos e threads Como o processo é representado no Linux kernel: task_struct e thread_info
Como é criado: fork() e clone() Como novos imagens de executáveis são carregados: exec()
Como o pai coleta informações dos seus “falecidos” processos filhos: wait()
Como um processo morre: exit()