Process Management
baseado na versão 2.6 do kernel do Linux
PESC / COPPE / UFRJ
Sistemas Operacionais
Prof. Vitor Santos Costa, Ph.D.
Jorge Luiz Silva Peixoto
[email protected]
jorgepeixoto@{cos.ufrj.br, gmail.com}
Process Management
1
Introdução e Motivação

O que é um processo?
Um programa em execução. É composto de:
Estado
Sinais
pendentes
Arquivos
abertos Kernel
data
Espaço de
endereçamento
Threads
Pilha
PC
Process Management
Registradores
2
Introdução e Motivação

Ciclo de vida do processo:
Nasce:
fork() ou exec()
Reclicla:
wait()
Slab allocator
Cresce:
faz_algo()
Reproduz (assexuadamente):
exec() ou fork()
Morre:
exit() ou
Sinal
Process Management
3
Programação








Descritor de Processos
Estados de Processos
Contexto de Processo vs de
Sistema
Espaço de Usuário vs de
Sistema
Hierarquia de Processos
Criação de Processos
Copy-on-Write
fork()
copy_process()
Process Management









vfork()
Threads
Threads – Implementação
Kernel Threads
Finalização de Processos
do_exit()
Remoção do Descritor de
Processos
release_task()
Processos Órfãos
4
Descritor 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 Management
5
Descritor 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 Management
6
Descritor 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 Management
7
Estados 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 Management
8
Contexto de Processo vs de Sistema
Espaço de Usuário vs 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 Management
9
Hierarquia 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 Management
10
Criaçã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() +
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 */
exec()
Process Management
11
Copy-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 Management
12
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 Management
13
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 Management
14
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 Management
15
Threads




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 Management
16
Threads – 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 Management
17
Kernel 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 Management
18
Finalizaçã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 Management
19
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 Management
20
Remoçã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 Management
21
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 Management
22
Processos Órfãos
Reparent 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 Management
23
Revisã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()
Process Management
24
Download

Process management - Jorge Peixoto - PESC