Revista Do Linux  
EDIÇÃO DO MÊS
  A Catedral e o Bazar
  A nova técnica dos Hackers
  Conexão inteligente
  Desvendando o Flagship
  Doutores em Linux
  Firewalls a partir do IP Masquerade
  Internet grátis, uai!
  Intranet - Benefícios que você nem conhece
  Linux World Expo
  Linux para macho
  Nos bastidores do Linux brasileiro
  Por um Linux fácil
  Rendering: virtualmente real
  Rádio Linux
  Servidor Linuxcom estações Windows
  Viagem ao centro do kernel
  vi, vim e venci

Viagem ao centro do kernel

Pequenos e grandes segredos úteis para programadores com algum conhecimento de linguagem C e ambientes Unix

Pessoas pelo mundo afora estão programando no kernel do Linux, especialmente para escrever drivers de dispositivos (device drivers), melhorando, aperfeiçoando e consertando o sistema. Esta é uma das inúmeras razões pelas quais o Linux se tornou um sistema com um rápido e estável desenvolvimento. Munidos de uma lista de discussão com alto tráfego de mensagens, os progamadores do kernel do Linux (também conhecidos como kernel hackers) possuem uma grande integração entre si. A cada novo código, conserto ou aperfeiçoamento no kernel, tudo é intensamente revisado e discutido. Neste artigo, que inaugura uma série a ser publicada mensalmente na Revista do Linux, pretendo introduzir o leitor, que já tem um conhecimento de programação e interesse em novos desenvolvimentos, a um outro nível de programação: o kernel level. Pressupõe-se que o leitor tenha um conhecimento básico em programação com a linguagem C e em ambientes Unix.

O mundo do kernel do Linux gira em torno de duas palavras: device drivers. Um device driver (acionadores de dispositivos), como o nome diz, é um código que compreende o dispositivo e realiza uma comunicação com ele. O aperfeiçoamento, criaçatilde;o e conserto de device drivers é o principal trabalho dos atuais programadores do kernel do Linux. Como foi dito anteriormente, esses programadores fazem alterações no kernel, através da lista de discussões chamada linux-kernel. Caso o leitor se interesse por ingressar nesta lista, sugiro que visite o site www.tux.org/lkml, onde existem instruções para inscrição. Já aviso ao leitor que o tráfego da lista é grande, pode facilmente ultrapassar duzentas, chegando a trezentas mensagens por dia. Uma outra opção para os leitores que não gostem de tanto tráfego nos seus endereços de e-mail é sempre observar o site Kernel Traffic (kt.linuxcare.com), que possui um sumário semanal com as mensagens mais importantes discutidas.

A organização do kernel.O kernel do Linux é um código relativamente complexo, comparando-se a pequenas aplicações. O tamanho do código fonte do kernel atualmente é de aproximadamente 75 Megabytes, incluídos todos os device drivers oficiais. Para se compreender um código desse tamanho é necessária uma certa organização. O código do kernel do Linux é distribuído livremente conforme as regras da Licença Pública da GNU.

O código fonte do kernel pode ser baixado por diversos meios, como ftp ou http. Você pode facilmente encontrar o código do kernel no endereço www.kernel.org,que é a distribuição oficial do kernel. Para um acesso mais rápido, sugiro utilizar o espelho brasileiro da distribuição, localizado no ftp no endereço ftp.br.kernel.org .

A seguir, vou tentar exemplificar a organização assumidapelos programadores do kernel, virtualmente e fisicamente.Virtualmente, o kernel do Linux, assim como a maioria dos kernels dos Unixs atuais, é dividido em várias partes, para melhor compreensão, como vemos a seguir:

Gerência de processos: cuida da criação, eliminação e gerência dos processos. Um processo não é nada mais do que uma tarefa sendo executada continuamente. Comunicação e escalonamento de processos também são gerenciados por esta parte.Gerência de memória: gerencia a memória do computador através de vários algoritmos para possibilitar o melhor uso da memória, que é o maior recurso do computador. Muitas partes do kernel interagem com o gerenciamento de memória, requisitando ou dispensando memória para utilização.

Sistemas de arquivos: Todo sistema Unix é altamente baseado em arquivos. Quase tudo em Unix pode ser tratado como um arquivo. Através de um sistema de arquivos virtual, o Linux suporta vários sistemas de arquivos que possuem diversas formas de organizar a informação no meio físico.

Drivers de dispositivos: uma das partes mais importantes do kernel. Com exceção do processador, memória e algumas outras pequenas partes, a maior parte do código é executada por drivers de dispositivos. O kernel necessita ter um driver para cada dispositivo integrado ao computador, de teclados a câmeras de vídeo.

Interligação em redes: a interligação em redes é controlada pelo kernel. Recebimento, envio, transformação

de pacotes são operações controladas pelo kernel, que possui mecanismos para repassar os pacotes a processos, conhecidos como sockets (soquetes).

Além dessas partes, o kernel do Linux, principalmente, possui uma parte especial, que adiciona uma nova funcionalidade ao kernel: a habilidade de expandir seu código enquanto está em execução. Isso significa que você pode adicionar funcionalidades ao kernel enquanto o sistema está em execução. Cada pedaço de código adicionado ao kernel é chamado de módulo. Existem diversos tipos de módulos, como módulos que são drivers de dispositivos ou drivers de rede, ou apenas pequenas modificações no código do kernel.

Fisicamente, o código do kernel do Linux é dividido em vários diretórios.
Documentation/ documentação relativa ao kernel
arch/ código dependente de arquitetura
drivers/ drivers de dispositivos

fs/ sistemas de arquivos

include/ definições e protótipos de funç= ;ões

init/ código de inicialização

ipc/ comunicação entre processos

kernel/ código base do kernel

lib/ funções básicas

mm/ gerenciamento de memória

modules/ armazenamento de módulos compilados

net/ código de interligação em redes

scripts/ scripts diversos para configuração/

compilação dokernel

Dentro do diretório arch/ está contido o código dependente de arquitetura. O resto dos diretórios é o mais portável possível, tornando o Linux facilmente portável entre diversas plataformas.

Tipos de dispositivos e módulos

A maneira como os sistemas Unix oferecem seus devices (dispositivos), geralmente pode ser classificada em três categorias, cada uma dedicada a tarefas diferentes. O Linux pode carregar cada um desses tipos de devices em forma de módulos, permitindo que o usuário teste novos hardwares sem a necessidade de reinicialização total do sistema.

Os três tipos de devices são especificados a seguir.

Dispositivos de caractere (char devices): Os devices de caractere são aqueles que podem ser acessados e manejados como um arquivo normal. Este tipo de driver geralmente implementa as funções primitivas como open(), close(), read() e write(). O console e a porta paralela são exemplos de char devices. Esses devices são acessados geralmente utilizando arquivos especiais, contidos no diretório /dev, como por exemplo: /dev/tty1, /dev/lp1. A grande e única diferença entre os char devices e arquivos é que em arquivos normais pode-se retroceder e ler os dados novamente, enquanto nos char devices não existe esta possibilidade, pois geralmente são canais de informações, em que você apenas pode ler seqüencialmente.

Dispositivos de bloco (block devices): Os dispositivos de bloco são geralmente dispositivos que podem conter um sistema de arquivos, como por exemplo um disco rígido. Na maioria dos sistemas Unix, dispositivos de bloco somente podem ser acessados em múltiplos de um bloco, em que um bloco geralmente é 1 Kilobyte de informação. O Linux kernel permite que você escreva e leia de um dispositivo de bloco como se fosse um dispositivo de caracter. Como resultado, dispositivos de bloco e de caractere apenas diferem na forma como são gerenciados internamente pelo kernel.

Dispositivos de rede (network interfaces): qualquer transação entre redes é reaizada através de uma interface (uma ligação). Geralmente uma interface é um dispositivo de hardware, mas pode ser qualquer software, como por exemplo a interface de loopback (que representa a própria máquina). Uma interface geralmente gerencia o envio e recebimento de pacotes entre a rede, processando-os através de um subsistema do kernel. Os sistemas Unix costumam nomear as suas interfaces por seus nomes, como por exemplo: eth0, que seria a primeira interface ethernet do sistema. A comunicação entre o kernel e as interfaces é completamente diferente dos dispositivos anteriores. Basicamente, em vez de utilizar primitivas como read() ou write(), ele gerencia a transmissão de dados através do recebimento e envi de pacotes em uma fila. Esses são os principais tipos de dispositivos existentes no kernel do Linux. De fato existe mais uma classe de dispositivos, os dispositivos SCSI. São gerenciados de uma forma diferente no kernel, mas isto é assunto para outro artigo.

Programando e executando módulos.Agora vamos ao que realmente interessa, a hora de começar a programar para o kernel. Esta seção introduz ao básico do básico dos conceitos sobre módulos, não se referindo a qualquer tipo de dispositivo específico. Analisemos o seguinte código:

#define MODULE

#include <linux/module.h>

#include <linux/kernel.h>

int init_module(void)

{

printk("<1>Olá Mundo!\n");

return(0);

}

void cleanup_module(void)

{

printk("<1> Duh, adeus mundo cruel!\n");

}

Analisando o código linha por linha temos:

#define MODULE

Definição que é uma module, necessária em = todos os módulos.

#include <linux/module.h>

#include <linux/kernel.h>

Cabeçalhos básicos em qualquer módulo, o primeiro= com definições

padrão dos módulos e outro do kernel.

int init_module(void)

printk("<1>Olá Mundo!\n");

printk() é uma das funções mais utilizadas pelo kernel do Linux. Tem uma pequena similaridade com o famoso printf(). A string <1> é a prioridade da mensagem, e sempre deve vir no início da linha. Neste caso foi especificada a maior prioridade para que esta mensagem apareça no console.

void cleanup_module(void)

Declaração da função cleanup_module(), esta função é outra que está presente em todos os módulos sem exceção. Quando um módulo é dinamicamente retirado do kernel ela é chamada para fazer a "limpeza".

Para testar o módulo, você pode utilizar dois comandos: insmod(1) e rmmod(1). Eles adicionam o módulo ou retiram o módulo do kernel, respectivamente.

Você pode observar a sintaxe dos comandos abaixo. Lembre-se de que só o superusuário (root) pode carregar ou descarregar módulos do sistema.

# gcc -c module.c

# insmod module.o

Olá Mundo!

# rmmod module.o

Duh, adeus mundo cruel!

#

Como você mesmo pode observar, escrever módulos não é tão difícil assim. É claro que o que foi presentado aqui é o básico do básico da programação no kernel, e com o passar dos artigos pretendo ensinar mais sobre como programar nesse fantástico sistema operacional que o Linux se tornou. Sintam-se à vontade para enviar comentários, dúvidas e sugestões para meu e-mail.

 

A Revista do Linux é editada pela Conectiva S/A
Todos os Direitos Reservados.

Política de Privacidade