Pesquisar neste blog

sábado, 7 de janeiro de 2012

Estrutura básica de um Kernel Linux

O Kernel Linux é um Kernel monolítico, ou seja, todas as suas funções (acesso e gravação nos filesystems (sistemas de arquivos), operações de entrada e saída, gerenciamento de memória, e agendamento de processos) são realizadas no espaço do próprio Kernel, ou seja, são todas realizadas em um único bloco com todas as funcionalidades básicas carregadas na memória.

A grande vantagem do Kernel Linux é que muitas funções podem ser compiladas e executadas como módulos (LKM – Loadable Kernel Modules ou Módulos Carregáveis do Kernel), que são bibliotecas compiladas separadamente da parte principal do Kernel e podem ser carregadas e descarregadas pelo sistema mesmo com o Kernel já estando em execução (pra quem não sabe, compilar um programa ou módulo é basicamente “fazer com que um compilador o reescreva, já interpretado”, para transformar as instruções de alto nível  (linguagem mais próxima da linguagem humana) nele contidas em instruções de baixo nível (linguagem “de máquina”), para que não ocorram, durante a execução do mesmo, perdas de tempo com interpretação de instruções).

Outra característica fantástica do Kernel Linux é sua portabilidade, que permite que o mesmo seja utilizado em sistemas mínimalistas (como celulares e palmtops) até sistemas de enorme porte, como densos mainframes. Por outro lado, temos também a enorme portabilidade no sentido do Kernel ser extremamente compatível com uma imensa variedade de fontes que podem ser compiladas e utilizadas em Linux.

Como funciona o Kernel?

1- Os filesystems (sistemas de arquivos)

Filesystem, ou sistema de arquivos, é o sistema utilizado pelo Kernel Linux para organizar, acessar e escrever os arquivos nos discos ou mídia de armazenamento disponível no sistema. Ou seja, é um artifício usado pelo Kernel para controlar a gravação e leitura dos dados (no seu disco rígido, por exemplo).
Existem vários tipos de filesystems, sendo que os mais conhecidos para GNU/Linux são:

- os baseados em discos -> Ext2 , Ext3 , ReiserFS , XFS , JFS  e ISO 9660 ;
- os baseados em rede -> NFS , SMBfs , Coda  e AFS ;
- os filesystems especiais -> Utilizados em diretórios como o /proc, ramfs e devfs.

Cada filesystem tem suas especificações, tais como tamanho de blocos (ou espaços delimitados destinados ao recebimento dos arquivos) e técnicas especiais de recuperação em caso de falhas.

Filesystems “jornalados” ou journaling filesystems, são filesystems que utilizam técnicas de recuperações em caso de falhas (como desligamentos abruptos, queda de energia e outros tipos de desastre de sistemas de arquivos). A expressão “journal” está ligada à ideia de se manter um log ou registro de eventos realizados no filesystem.

Os sistemas de arquivos com journaling mais utilizados atualmente em sistemas operacionais GNU/Linux são: 


O sistema GNU/Linux atualmente também é capaz de ler e escrever no sistema de arquivos NTFS (sistema de arquivos proprietário da empresa microsoft).

2 – Operações I/O ou E/S (In/Out ou Entrada/Saída)

São as operações de comunicação do Kernel Linux com os dispositivos de hardware da máquina. As operações de entrada e saída realizadas pelo Kernel Linux são implementadas através dos device drivers, ou seja, para cada dispositivo de hardware da máquina, existe um device do Kernel (arquivo que serve de ligação com os dispositivos de hardware, criado pelo Kernel no diretório /dev do filesystem (sistema de arquivos)).

O Kernel Linux realiza todas as operações de E/S com uma sequëncia de bytes, sem qualquer conceito de registro ou métodos de acesso. Dessa forma, ocorre uma comunicação mais direta com os dispositivos de hardware, de maneira uniforme. O Kernel pode acessar e escrever nos arquivos de ligação do diretório /dev (ou devices do Kernel) da mesma forma que ocorre em qualquer outro arquivo do filesystem, utilizando chamadas do sistema (system calls) de leitura e gravação.

O Kernel Linux trabalha com dois tipos de operações de E/S: orientadas a blocos e orientadas a caracter. As operações orientadas a bloco são geralmente utilizadas em dispositivos com uma taxa alta de transferência de dados (como por exemplo discos rígidos) fazendo com que seja reduzido o número de transferências necessárias entre o device do Kernel e a memória, já que em cada tranferência de dados são enviadas várias informações simultaneamente em blocos (agrupamentos). Já os dispositivos de hardware mais lentos, ou que demandam uma transferência menor de dados, são orientados a caracter, ou seja, a transferência entre o dispositivo e a memória são realizadas caracter a caracter.

3- Gerenciamento de memória

Entenda que quando executamos aplicativos ou funções do sistema operacional, o processador da máquina executa trocas dinâmicas com a memória principal do sistema (memória RAM). Isto ocorre pois o processador precisa armazenar as informações que recebeu para processá-las aos poucos de acordo com sua capacidade. O subsistema de gerenciamento de memória do Kernel Linux, preocupa-se especialmente com alguns fatores responsáveis pelo correto e eficaz gerenciamento dessas trocas dinâmicas.

Os principais aspectos do gerenciamento de memória são:

- Utilização de memória e swapping: O Kernel Linux sempre utiliza a maior quantidade de memória RAM possível, já que quando executamos um programa qualquer, tornando-o um processo do sistema, ele armazena temporariamente na memória RAM os dados necessários à sua execução, e esses dados não são apagados imediatamente após o encerramento de sua execução. Eles permanecem carregados na memória o máximo de tempo possível, pois caso o mesmo processo seja executado novamente em breve, os dados ainda estarão lá disponíveis, agilizando muito a execução. Essa técnica de manter os dados de programas executados na memória RAM chama-se Buffer Cache, e é utilizada para os dados que são utilizados pelos device drivers (drivers de dispositivos de hardware de que falamos acima em operações E/S). O Buffer Cache só é apagado parcialmente ou totalmente da memória RAM quando não há mais espaço suficiente para carregar um novo programa, e os dados escolhidos a serem apagados são aqueles que estão há mais tempo sem serem acessados, o que mostra ao Kernel que eles provavelmente não serão mais utilizados tão breve. Esse método de escolha é chamado de swapping, que utiliza um conceito de “envelhecimento” de informações conforme as mesmas não são utilizadas, e “rejuvenecimento” de informações conforme as mesmas são acessadas (não confundir swapping com memória virtual ou swap).

- Proteção: O Kernel Linux divide e separa os processos carregados na memória RAM da máquina como processos do kernel e processos do usuário.

- Mapeamento de memória: Os processos em execução no sistema são divididos em páginas e somente algumas dessas páginas estão realmente na memória física do computador. Outras delas são “endereços virtuais” que agilizam o processo de acesso da memória. A utilização de endereços virtuais com endereços reais (físicos) de memória é chamada de mapeamento de memória. Todos os processos tem referências em uma estrutura de dados chamada pelo Kernel Linux de “mm_struct”. Esta estrutura contém informações sobre o que está sendo executado no momento e possui apontamentos para uma outra estrutura de dados chamada “vm_area_structure”, que contém “o endereço” de todos os PFN (Page Frame Numbers – que podemos entender de maneira menos técnica como o “endereço” ou localização exata de onde estão realmente as informações na memória do computador).

- Alocação: O Kernel Linux utiliza o algoritmo Buddy (Companheiro – nome pelo qual é conhecido o algoritmo de alocação) para alocar e desalocar páginas de memória utilizando blocos de páginas. O gerenciamento de memória do Kernel aloca e desaloca páginas de memória com extremo dinamismo, causando assim uma fragmentação de memória, que é resolvida pelo Kernel com um processo de desfragmentação que junta espaços preenchidos de memória que são categoricamente semelhantes.

Memória Cache: É utilizada para otimizar e agilizar o acesso a informações. Exemplos de Cache utilizadas pelo Kernel Linux: Buffer Cache (vimos acima quando falei de operações E/S – são blocos de tamanho fixo usados por device drivers que agilizam o acesso a informações que já estejam nesse buffer, tornando desnecessário o acesso direto ao dispositivo de hardware), o Page Cache(usado para tornar mais rápido o acesso a vários tipos de informação no disco), e o Swap Cache(que faz com que apenas páginas de memória modificadas sejam salvas na memória virtual física (que veremos abaixo) sendo que as páginas de memória inalteradas com seu acesso podem ser descartadas sem a necessidade de gravá-las fisicamente).

Memória Virtual: Memória virtual ou memória SWAP é um recurso utilizado pelo Kernel Linux que consiste em reservar uma parte da memória secundária da máquina (o disco rígido), especificada pelo usuário, para ser uma extensão da memória primária (memória RAM). O conceito de memória virtual está, ao contrário do que muitos pensam, ligado ao produto final da junção entre a memória primária e o espaço reservado da memória secundária. Ou seja… A memória virtual = Memória RAM + Memória SWAP. O processador transfere os dados do processo que está executando diretamente para a memória RAM (primária). Quando surge a necessidade de esvaziamento de parte da RAM para executar outro processo (e surge mesmo, pois lembre-se que o Kernel Linux utiliza sempre o máximo de memória possível devido ao Buffer Cache, para agilizar os processos), alguns processos existentes, mais envelhecidos (pelo swapping) que estiverem esperando para continuar sua execução, são transferidos para a o disco rígido, para a parte reservada à memória SWAP. Para que esse recurso possa ser utilizado, uma partição deve ser criada no disco durante a instalação do sistema operacional e especificada (reservada) como partição SWAP. O tamanho ideal para uma partição swap é um assunto que merece atenção exclusiva, e por isso, falarei sobre isso e sobre planejamento de particionamento num próximo post.

4- Agendamento de processos

Primeiramente vamos esclarecer de uma ver por todas o que é processo. Processo é uma instância de um programa em execução. Todo processo tem um pai (ou processo criador) e um número único atribuído pelo Kernel no momento de sua execução, que o identifica no sistema… o PID(Process Identifier). Para fazer um planejamento e compartilhamento adequado do tempo do processador, o Kernel Linux usa um sistema de 2 tipos de classificação, que avalia cada processo e lhe atribui qualidades que permitem que seja determinada uma prioridade de execução para cada processo avaliado. Os processos são classificados pelo Kernel quanto a sua responsividade (ou seja, se o processo responde em tempo realinterativo ou em segundo plano) e quanto a suaintensidade de atividade (ou seja, se o processo utiliza muito tempo de processador (CPU-Bound ou Limite de CPU) e se faz muitas operações de E/S (I/O-Bound ou Limite de Entrada e Saída)). Essas duas classificações são relativamente independentes, ou seja, um processo pode, por exemplo, ter uma baixa responsividade (como um daemon por exemplo, executado em segundo plano) e ao mesmo tempo ter uma grande intensidade de atividade (ou seja, ter um grande consumo de operações de E/S)… Podemos citar como o exemplo o caso do Servidor Web Apache2 servindo um banco de dados MySQL. Avaliadas essas classificações, o Kernel Linux utiliza seu sistema de prioridades e organiza os processos. A identificação da prioridade de um processo pode serestática ou dinâmica, e varia de 1 (maior prioridade) a 139 (menor prioridade), sendo que os números de 1 a 99 são atribuídos a processos executados em tempo real, e de 100 a 139 são atribuidos a processos tradicionais (processos interativos ou processos executados em segundo plano).

Os processos executados em tempo real são classificados como FIFO (First-In, First-Out) ou RR (Round-Robin), e eles somente passam a ser excluídos do processamento atual nos casos de: fim de sua execução; para ser substituído por um processo que possua prioridade ainda maior; executar uma operação de bloqueio; espontaneamente pelo próprio processo; quando o processo é RR (Round-Robing) e esgotou seu quantum de processamento.

Um processo tradicional (processos interativos e os executados em segundo plano) tem inicialmente uma prioridade estática atribuída (normalmente 120) que determina o seu quantum de processamento, mas pode ter uma prioridade dinâmica, que é o valor analisado pelo agendador de processos do Kernel quando percorrer a lista de processos para determinar de qual processo é a vez de utilizar o processador. A prioridade dinâmica pode alterar o valor da prioridade estática em + ou – 5 pontos dependendo do passado do processo (lembre-se que quando menor a pontuação, maior a prioridade do processo). Ou seja, o passado do processo irá beneficiá-lo caso o mesmo tenha ficado muito tempo esperando por sua execução fora do processador (sleep time). Caso o sleep time seja pequeno, o processo irá ser penalizado, ou seja, seu número de prioridade irá aumentar, tornando sua prioridade de execução menor.

Fonte: aptscience

Nenhum comentário: