. Introducao-a-Processos
Esse documento representa parte dos meus estudos acerca do Livro - Operational Systems Three Easy Pieces, de dominio publico.
Um processo representa um programa em execucao e seus respectivos componentes. O programa armazenado em si, nao representa nada alem de instrucoes e algum tipo de dado estatico, ele so passa a ter algum valor de fato quando executado pelo SO. Neste contexto, cria-se uma problematica. Se um programa so pode ser validado ao ser executado, como podemos executar varios programas em apenas uma maquina fisica, a qual tem apenas uma unidade de processamento?
podemos utilizar da virtualizacao da CPU. A tecnica para executar varios programas é conhecida como Compartilhamento de tempo da CPU. Esta tecnica permite executarmos processos de forma concorrente, com apenas uma pequena perda de performance, ja que a CPU estara sendo compartilhada.
Utilizamos Mecanismos, que sao metodos e protocolos low level que implementam funcionalidades do sistema. Um exemplo de mecanismo: Context Switcher, que permite a pausa e intercalacao da execucao de programas.
Abstraindo processos
Um processo, evidentemente, é apenas uma abstracao dada a um programa, o qual acessa e/ou modifica partes do sistema. Para entendermos um processo, precisamos entender primeiramente o que sao os Estados de Maquina: todos os componentes o qual o programa consegue alterar. A exemplo, o estado da memoria. As instrucoes de um programa se compreendem dentro da memoria, assim como todo dado armazenado. Desta forma, o address space faz parte da construcao de um processo, juntamente aos registrados que participam das operacoes (por exemplo o program counter ou o stack pointer).
Process API
Uma API de processo deve poder:
- criar: invocado ao se executar qualquer programa (gerar um PID, virtualizar memoria e gerenciar o lifecycle e context)
- destruir: matar o processo (kill)
- esperar: apenas permitir a execucao do processo e sua finalizacao.
- controle variado: suspensao e resumo do processo, e.g.
- status: devolver info sobre o estado do processo.
Criacao de um processo
O primeiro passo é o carregamento de memoria (o codigo e variaveis inicializadas) para a memoria principal e, consequentemente, para os registradores necessarios. Este carregamento pode ser feita de 2 formas: a forma “pensa num bicho ansioso”, o qual o programa é inteiramente carregado, sem injecao ou associacao de dependencias, ou, da maneira preguicosa (Lazy Loading), a qual carregamos o programa e suas dependencias durante o tempo de execucao, baseado na necessidade de utilizar x ou y dep. Cobriremos mais estes topicos quando falarmos de tecnicas como paginacao e swapping.
O segundo passo é criar uma run-time stack, ou seja, alocar memoria para o programa poder armazenar informacoes locais como variaveis, system calls ou qualquer outra coisa. O processo tambem pode inicializar a stack com, por exemplo, args externas, passadas em C pelo argc e argv, e.g.
Tambem é alocado um espaco da heap caso seja explicitamente chamado, ou podemos setar qualquer metodo de alocacao.
Podemos tambem criar tags, como no linux, file descriptors, que permitem input, output e descricoes de erro de forma simplificada.
Quando finalizado o carregamento, o SO passa o controle via um mecanismo para a rotina principal do programa executado (main() em C).
Estados do processo
- Running: executando as instrucoes.
- Ready: esta pronto, mas nao executando as instrucoes, por algum motivo.
- blocked: quando o processo precisa de alguma resposta de outro evento, e.g, I/O calls.
A alteracao de um processo pode ser feita via Scheduling, onde um processo é Scheduled para executar as instrucoes (running state) e descheduled para esperar qualquer coisa.
Estrutura de Dados
Como um programa, o SO precisa de estruturas de dados padrao para mapear algumas atividades. Por exemplo, para mapear os estados dos processos, pode-se criar uma process list que registra todos os processos no estado ready e/ou running.
Podemos ver um exemplo de structs/registros que representam o contexto de registradores
// the registers xv6 will save and restore
// to stop and subsequently restart a process
struct context {
int eip;
int esp;
int ebx;
int ecx;
int edx;
int esi;
int edi;
int ebp;
};
// the different states a process can be in
enum proc_state { UNUSED, EMBRYO, SLEEPING,
RUNNABLE, RUNNING, ZOMBIE };
// the information xv6 tracks about each process
// including its register context and state
struct proc {
char *mem; // Start of process memory
uint sz; // Size of process memory
char *kstack; // Bottom of kernel stack
// for this process
enum proc_state state; // Process state
int pid; // Process ID
struct proc *parent; // Parent process
void *chan; // If !zero, sleeping on chan
int killed; // If !zero, has been killed
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
struct context context; // Switch here to run process
struct trapframe *tf; // Trap frame for the
// current interrupt
}Este contexto de registradores pode ser alterado pela tecnica de context switch.

