Process management - Jorge Peixoto

Post on 07-Jan-2017

222 views 1 download

Transcript of Process management - Jorge Peixoto

Process Management 1

Process ManagementProcess Managementbaseado na versão 2.6 do kernel do Linux

Jorge Luiz Silva Peixotojorge@ravel.ufrj.brjorgepeixoto@{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()