Interface para gerenciamento de memória

1. Criação de Processos.

A principal chamada utilizada para criação de processos, no Linux, é a fork() (além dela, poderíamos citar a clone() utilizada para criar processos-leves (lightweight process) que não serão tratados aqui), que baseia-se na cópia do processo-pai em um processo filho. Essa idéia se estende para a criação do espaço de endereçamento do processo-filho mas a cópia real de todo o espaço de endereçamento do pai seria uma tarefa muito onerosa e, muitas das vez, desnecessária, visto que muitas vez o processo-filho usa a chamada exec(), que modifica todo o seu código, desperdiçando toda a cópia. A abordagem utilizada pelo Linux para a criação do espaço de enderaçamento do processo-filho é chamada Copy-On-Write, cópia na escrita, que realiza um compartilhamento das páginas entre o pai e o filho, com a suas permissões modificadas somente para leitura assim, quando um dos processos tenta escrever, a página é copiada.
De uma forma simplificada, podemos descrever a sequencia de eventos como:

  • cria-se o processo com a chamada fork();
  • a chamada invoca a chamada copy_mm();
  • a chamada copy_mm() copia o descritor de memória do processo-pai, modificando alguns campos, entre eles, a alocação de um novo diretório de tabela de páginas (tabela de páginas de primeiro nível);
  • é, então, realizada a chamada, dependente da arquitetura init_new_context(), na arquitetura x86, ela é responsável pela cópia, se necessário, da LDT do processo-pai;
  • finalmente, é realizada a chamada dup_map que faz a cópia das regiões de memória e das tabelas de páginas do pai para o filho, para isso, é verificada todas as áreas utilizadas pelo pai, e, para aquelas que estão marcadas como privadas e com permissão de escrita, têm a sua permissão modificada para somente leitura, abrindo caminho para o sistema Copy-On-Write.

2. Troca de contexto de processos.

A primeira etapa da troca de processos executada pelo kernel é justamente a mudança no espaço de endereçamento utilizado para aquele do processo. Isto é feito pela troca do Page Global Directory (diretório de tabelas de páginas). Na arquitetura x86, isto equivale a troca do valor do registrador cr3. Mudanças na TLB, ver TLB no Linux.

3. Page-fault

A ocorrência de uma chamada a um endereço virtual de memória que não está presenta na memória física (a partir da verificação de dados obtidos nas tabelas de páginas) geram umtipo especial de interrupção (também chamada de exceção, uma vez que é gerada pela execuação de uma instrução do próprio processador e não por um dispositivo externo) chamado page-fault. Isso também pode ocorrer, quando o processo tenta acessar uma região de memória sem ter as permissões necessárias, como será explicado mais adiante. Esta exceção deve ser tratada pelo kernel do sistema operacional. No Linux, a chamada responsável pelo tratamento dessa exceção é a do_page_fault(). Entre os parâmetros dessa função, é importante ressaltar um código de erro de 3 bits:

  • o primeiro bit diz sobre a presença ou na da página: 0 significa a ausência da página e 1, a falta das permissões necessárias para realizar a operação;
  • o segundo bit informa qual era o tipo de acesso que gerou a exceçaõ: 0 para leitura ou execução e 1 para escrita;
  • o terceiro bit informa qual o modo em que estava o processo: 0 para modo kernel e 1 para modo usuário.

A partir da combinação dessas informações e de outras, como o endereço estava no últimos gigabyte de endereço, é determinado a ação a ser tomada que pode ser:

  • requisição de página (com ou sem copy-on-write);
  • envio de sinal SIGSEGV (“Segmentation fault”);
  • finalização do processo.

A figura. a seguir, representa esse processo:

page-fault.jpg

4. Remoção de processos

Quando um processo é finalizado, analogamente ao que ocorre quando é inicializado, é realizada a chamada a exit_mm() do kernel. Esta chamada é responsável pela limpeza do descritor de memória do processo e todas as estruturas relacionadas. A maior parte desta tarefa é realizada pela chamada mmput() que libera a LDT, os descritores das regiões de memória e as tabelas de páginas.
O descritor, em si, é liberado quando o processo é, finalmente, desprezado pelo processador, através da chamada finish_task_switch().

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License