kernel do linux

83
Curso de Pós-Graduação “Lato Sensu” (Especialização) a Distância Administração em Redes Linux KERNEL DO LINUX Marluce Rodrigues Pereira Universidade Federal de Lavras – UFLA Fundação de Apoio ao Ensino, Pesquisa e Extensão – FAEPE Lavras – MG

Upload: arl-ufla

Post on 18-Mar-2016

246 views

Category:

Documents


0 download

DESCRIPTION

KERNEL DO LINUX

TRANSCRIPT

Page 1: KERNEL DO LINUX

Curso de Pós-Graduação“Lato Sensu” (Especialização) a Distância

Administração em Redes Linux

KERNEL DO LINUX

Marluce Rodrigues Pereira

Universidade Federal de Lavras – UFLAFundação de Apoio ao Ensino, Pesquisa e Extensão – FAEPE

Lavras – MG

Page 2: KERNEL DO LINUX

PARCERIAUFLA – Universidade Federal de LavrasFAEPE – Fundação de Apoio ao Ensino, Pesquisa e Extensão

REITORAntônio Nazareno Guimarães Mendes

VICE-REITORRicardo Pereira Reis

DIRETOR DA EDITORAMarco Antônio Rezende Alvarenga

PRÓ-REITOR DE PÓS-GRADUAÇÃOJoel Augusto Muniz

PRÓ-REITOR ADJUNTO DE PÓS-GRADUAÇÃO “LATO SENSU”Marcelo Silva de Oliveira

COORDENADOR DO CURSOHeitor Augustus Xavier Costa

PRESIDENTE DO CONSELHO DELIBERATIVO DA FAEPELuis Antônio Lima

EDITORAÇÃOGrupo Ginux (http://ginux.comp.ufla.br/)

IMPRESSÃOGráfica Universitária/UFLA

Ficha Catalográfica preparada pela Divisão de Processos Técnicosda Biblioteca Central da UFLA

Pereira, Marluce RodriguesKernel do Linux/ Marluce Rodrigues Pereira. - - Lavras: UFLA/FAEPE, 2006.83 p. : il. - Curso de Pós-Graduação “Lato Sensu” (Especialização) à

Distância: Administração em Redes Linux.

Bibliografia.

1. Informática 2. Sistemas operacionais. 3. Linux. 4. Gerência deprocessos. 5. Gerência de memória. 6. Gerência de arquivos. 7. Gerênciade E/S. I. Universidade Federal de Lavras. II. Fundação de Apoio ao Ensino,Pesquisa e Extensão. III. Título.

CDD-005.133-005.4

Nenhuma parte desta publicação pode ser reproduzida, por qualquermeio ou forma, sem a prévia autorização.

Page 3: KERNEL DO LINUX

SUMÁRIO

1 Introdução 71.1 Estrutura da apostila . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81.2 Agradecimentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

2 Visão Geral de Sistemas Operacionais e o Kernel do Linux 112.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112.2 Visão geral dos sistemas operacionais . . . . . . . . . . . . . . . . . . . . . . 122.3 História do Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152.4 O Kernel do Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

2.4.1 Obtenção, configuração e compilação do kernel do Linux . . . . . . . 192.5 Inicialização de um sistema em um PC . . . . . . . . . . . . . . . . . . . . . 222.6 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

3 Gerência de Processos 253.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253.2 Criação de processos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283.3 Descritor de processo e a estrutura de tarefas . . . . . . . . . . . . . . . . . 303.4 Contexto do processo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323.5 Árvore da família de processos . . . . . . . . . . . . . . . . . . . . . . . . . . 323.6 Implementação de threads no Linux . . . . . . . . . . . . . . . . . . . . . . . 333.7 Escalonamento de processos . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

3.7.1 Interrupções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373.7.2 Sincronização no kernel . . . . . . . . . . . . . . . . . . . . . . . . . . 38

3.8 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

4 Gerência de memória 414.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414.2 Organização da memória . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414.3 Memória virtual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444.4 Thrashing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474.5 Gerência de memória no kernel do Linux . . . . . . . . . . . . . . . . . . . . 48

4.5.1 Gerência da memória física . . . . . . . . . . . . . . . . . . . . . . . . 484.5.2 Memória virtual no Linux . . . . . . . . . . . . . . . . . . . . . . . . . 494.5.3 Mapeamento de programas na memória . . . . . . . . . . . . . . . . . 52

4.6 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

5 Sistema de arquivos 555.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555.2 Conceito de arquivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555.3 Métodos de acesso a arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . 565.4 Estrutura de diretórios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

5.4.1 Diretório de um nível . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

Page 4: KERNEL DO LINUX

5.4.2 Diretório em dois níveis . . . . . . . . . . . . . . . . . . . . . . . . . . 585.4.3 Diretório estruturado em árvore . . . . . . . . . . . . . . . . . . . . . . 595.4.4 Diretório de grafos cíclicos . . . . . . . . . . . . . . . . . . . . . . . . 595.4.5 Diretório como estrutura de grafo geral . . . . . . . . . . . . . . . . . 60

5.5 Sistemas de arquivos no Linux . . . . . . . . . . . . . . . . . . . . . . . . . . 605.6 O sistema de arquivos ext2 do Linux . . . . . . . . . . . . . . . . . . . . . . . 625.7 O sistema de arquivos proc do Linux . . . . . . . . . . . . . . . . . . . . . . . 645.8 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

6 Gerência de Entrada e Saída 676.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

6.1.1 Escalonamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676.1.2 Alocação em buffers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 686.1.3 Alocação em caches . . . . . . . . . . . . . . . . . . . . . . . . . . . . 686.1.4 Spooling e reserva de dispositivos . . . . . . . . . . . . . . . . . . . . 696.1.5 Manipulação de erros . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

6.2 Entrada e Saída no Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 696.2.1 Dispositivos de blocos . . . . . . . . . . . . . . . . . . . . . . . . . . . 706.2.2 Dispositivos de caracteres . . . . . . . . . . . . . . . . . . . . . . . . . 716.2.3 Estrutura de rede . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

6.3 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

7 Comparação entre Solaris, Linux e FreeBSD 737.1 Escalonamento e escalonadores . . . . . . . . . . . . . . . . . . . . . . . . . 737.2 Gerência de memória e paginação . . . . . . . . . . . . . . . . . . . . . . . . 74

7.2.1 Paginação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 757.3 Sistema de arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 767.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

8 Considerações finais 79

Referências Bibliográficas 818.1 SOBRE SISTEMAS OPERACIONAIS EM GERAL . . . . . . . . . . . . . . . 818.2 SOBRE SISTEMA UNIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 818.3 SOBRE SISTEMA LINUX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 818.4 OUTROS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82

Page 5: KERNEL DO LINUX

LISTA DE FIGURAS

2.1 Visualização da arquitetura do kernel [Maxwell (2000)] . . . . . . . . . . . . . 17

3.1 O descritor do processo e a lista de tarefas [Love (2005)] . . . . . . . . . . . 303.2 Diagrama de estados de processos no kernel do Linux . . . . . . . . . . . . . 313.3 Código da estrutura para interação entre processo pai e filho. . . . . . . . . . 333.4 Exemplo de seção crítica com dois processos. . . . . . . . . . . . . . . . . . 39

4.1 Endereço lógico na paginação . . . . . . . . . . . . . . . . . . . . . . . . . . 454.2 Formato da memória para programas ELF [Silberschatz (2004)] . . . . . . . 53

5.1 Arquivo de acesso seqüencial [Silberschatz (2004)] . . . . . . . . . . . . . . 565.2 Estrutura de diretório de um nível. . . . . . . . . . . . . . . . . . . . . . . . . 585.3 Estrutura de diretório em dois níveis. . . . . . . . . . . . . . . . . . . . . . . . 585.4 Estrutura de diretório em árvore. . . . . . . . . . . . . . . . . . . . . . . . . . 595.5 Estrutura de diretório de grafos cíclicos . . . . . . . . . . . . . . . . . . . . . 605.6 Estrutura de diretório de grafo geral. . . . . . . . . . . . . . . . . . . . . . . . 615.7 Políticas de alocação de blocos do ext2fs [Love (2005)] . . . . . . . . . . . . 63

6.1 Estrutura de blocos do driver de dispositivo . . . . . . . . . . . . . . . . . . . 70

Page 6: KERNEL DO LINUX

LISTA DE TABELAS

2.1 Diretórios na árvore do fonte do kernel [Love (2005)] . . . . . . . . . . . . . . 20

3.1 Timeslices do escalonador . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353.2 Principais chamadas de sistema relacionadas ao escalonador . . . . . . . . 36

7.1 Lista parcial de sistemas de arquivos [Bruning (2005)] . . . . . . . . . . . . . 76

Page 7: KERNEL DO LINUX

1INTRODUÇÃO

Um sistema operacional é responsável por gerenciar o sistema de computação. Porisso, conhecer quais são os componentes de um sistema operacional, como os compo-nentes são gerenciados, como surgiu o kernel do Linux e como é a gerência destes com-ponentes no Linux torna-se imprescindível para um administrador de uma rede Linux.

Um sistema de computação pode ser dividido em quatro componentes: o hardware, osistema operacional, os programas aplicativos e os usuários [Silberschatz (2004)]. O hard-ware é composto pela Unidade Central de Processamento (CPU - Central Processing Unit),a memória e os dispositivos de entrada e saída (I/O - Input/Output). Os programas aplica-tivos compreendem os processadores de texto, planilhas, compiladores e navegadores daweb. Cabe aos programas aplicativos definirem como serão utilizados os recursos computa-cionais para resolver os problemas computacionais dos usuários. O sistema operacional éresponsável pela coordenação e controle do uso do hardware pelos programas aplicativospara os diversos usuários.

Com o desenvolvimento da tecnologia utilizada nos sistemas computacionais o de-sempenho e a facilidade de interação com o usuário também melhoraram. Conseqüen-temente, os sistemas operacionais tendem a se desenvolver com o passar dos anos, bus-cando atender ao planejamento das atividades computacionais de modo a assegurar o bomdesempenho do sistema de computação e proporcionar um ambiente adequado para o de-senvolvimento e execução de programas.

Um programa é um conjunto de instruções a serem executadas. Quando o programaestá sendo executado, ele pode ser denominado de processo e necessita de vários recur-sos, tais como tempo de CPU, memória, arquivos e dispositivos de entrada e saída. Emum sistema com vários processos, estes recursos serão utilizados por todos eles, mas nãoao mesmo tempo. Para uma utilização eficiente dos recursos é necessário algum geren-ciamento, que é realizado pelo sistema operacional. Vários sistemas operacionais foramdesenvolvidos buscando utilizar eficientemente os recursos computacionais.

Em 1969, o grupo de desenvolvedores dos laboratórios Bell Labs [Garrels (2002)]começaram o desenvolvimento de um sistema operacional, escrito em linguagem C. O pro-

Page 8: KERNEL DO LINUX

8 EDITORA - UFLA/FAEPE - Kernel do Linux

jeto recebeu o nome de UNIX 1 e foi sendo aprimorado para diferentes arquiteturas com opassar dos anos [UNIX (2007)].

Em 1991, Linus Torvalds desenvolveu o sistema Linux baseando-se no sistema ope-racional UNIX. Linus implementou o Linux conforme o padrão POSIX (Portable OperatingSystem) 2, que é o mesmo utilizado pela API (Application Programming Inteface) UNIX, masnão utilizou o código fonte do UNIX. Por isso, se diz que Linux é um Unix e não um UNIX[Cisneiros (2007)].

Gerada a primeira versão do Linux, o código fonte foi disponibilizado pela Internet etornou-se popular. A partir de então, tornou-se um projeto colaborativo e várias distribuiçõesdo Linux foram geradas, atendendo a diferentes plataformas de hardware. A parte princi-pal é o kernel do Linux, que possui código aberto e livre. Desenvolvedores podem realizarmodificações no kernel do Linux, porém as funcionalidades básicas são comuns a todasas distribuições. As funcionalidades básicas do kernel do Linux são: tratamento de in-terrupções, escalonamento do processador, gerência de memória, gerência de entrada esaída e serviços de sistema tais como rede e comunicação entre processos. Este textoaborda detalhadamente estas funcionalidades.

O objetivo deste curso é apresentar os conceitos gerais sobre sistemas operacionaise como o kernel do Linux implementa estes conceitos.

1.1 ESTRUTURA DA APOSTILA

A apostila está dividida em sete capítulos, cujo conteúdo aborda desde uma visãogeral de sistemas operacionais, história do UNIX e Linux, implementação do Linux, até umacomparação entre Linux e algumas versões de sistemas baseados em Unix POSIX.

O Capítulo 2 mostra uma visão geral dos sistemas operacionais, apresentando umhistórico de desenvolvimento dos sistemas operacionais, como o kernel do Linux surgiu esuas características principais. Além disso, é explicado como obter o kernel do Linux.

O Capítulo 3 apresenta o conceito de processos, como criar processo e as estruturasde dados utilizadas pelo kernel para armazenar processo, como é realizada a comunicaçãoentre processos, como é feito o escalonamento de processos e como é realizado o sincro-nismo entre processos.

O Capítulo 4 apresenta gerência de memória, incluindo paginação, tabelas hierárquicase memória virtual. A forma como o kernel do Linux gerencia memória e quais as estruturasutilizadas são destacadas neste capítulo.

1A marca UNIX é registrada por The Open Group [Bell (2007)].2Norma estabelecida pelo IEEE (Institute of Electrical and Electronics Engineers) para intercomunicação

entre diferentes sistemas operacionais [Santos (1999)]

Page 9: KERNEL DO LINUX

Introdução 9

O Capítulo 5 apresenta o sistema de arquivos em um sistema operacional e no Linux,em específico. Os métodos de acesso a arquivos e a estrutura de diretórios são abordados.

O Capítulo 6 aborda gerência de entrada e saída.Para terminar este apostila, o Capítulo 7 apresenta uma comparação entre os sis-

temas operacionais Solaris, FreeBSD e Linux.Esta apostila tem a maior parte de suas informações sobre sistemas operacionais

baseada na referência [Silberschatz (2004)]. A maioria das informações sobre kernel doLinux foram baseadas nas referências [Love (2005), Maxwell (2000)]. A comparação entreLinux e sistemas baseado em Unix tem como referência o trabalho de [Bruning (2005)].Para o leitor ter um conhecimento mais aprofundado sobre sistemas operacionais, os sis-temas Unix e o kernel do Linux, sugere-se a leitura destas referências.

1.2 AGRADECIMENTOS

Aos professores Joaquim Quinteiro Uchôa e Denilson Vedoveto Martins, pela revisãodeste texto e sugestões em relação a organização do texto e bibliografia utilizada.

Page 10: KERNEL DO LINUX

10 EDITORA - UFLA/FAEPE - Kernel do Linux

Page 11: KERNEL DO LINUX

2VISÃO GERAL DE SISTEMAS

OPERACIONAIS E O KERNEL DO LINUX

O objetivo deste capítulo é apresentar uma visão geral de sistemas operacionais comobase para o surgimento do Linux. Por isso, são abordados os principais conceitos em sis-temas operacionais e sua evolução história, com ênfase na história do Linux. As principaisreferências bibliográficas utilizadas foram [Silberschatz (2004)], [Love (2005)], [Bovet (2002)]e [Mazioli (2006)].

2.1 INTRODUÇÃO

Um sistema operacional é uma parte essencial de qualquer computador e pode serdefinido como um programa que atua como um intermediário entre o usuário e o hardwarede um computador. Sua finalidade é prover um ambiente no qual um usuário possa executarprogramas de uma forma conveniente e eficiente [Silberschatz (2004)].

Outra definição para um sistema operacional moderno é considerá-lo como sendo aspartes do sistema responsáveis pelo uso básico e administração, o que inclui o kernel edevice drivers, boot loader, shell ou outras interfaces com o usuário, e arquivos básicos eutilitários do sistema [Love (2005)]. Os primeiros sistemas operacionais eram responsáveisapenas por transferir automaticamente o controle de uma tarefa para a seguinte.

Com o objetivo de melhorar o desempenho dos sistemas, foram sendo introduzidosnovos recursos de hardware, como, por exemplo, a tecnologia de disco, exigindo tam-bém uma evolução dos sistemas operacionais, que passaram a oferecer mais serviços aosusuários e aos programas destes usuários. Alguns dos serviços oferecidos pelos sistemasoperacionais atuais são listados a seguir:

• Carregamento de programa na memória e execução deste programa

• Gerenciamento de operações de entrada e saída

• Manipulação de arquivos (criação, leitura, escrita, busca, entre outras)

• Detecção de erros relacionados à CPU, acesso à memória, entrada e saída ouprograma do usuário

Page 12: KERNEL DO LINUX

12 EDITORA - UFLA/FAEPE - Kernel do Linux

• Alocação de recursos, tais como CPU e memória, aos processos dos usuários

O Linux, portanto, provê estes serviços e busca acompanhar a evolução dos sistemascomputacionais para prover serviços a diferentes plataformas.

2.2 VISÃO GERAL DOS SISTEMAS OPERACIONAIS

Os primeiros sistemas computacionais surgiram na década de 1950 com os main-frames, que eram usados para atender aplicações comerciais e científicas. Inicialmente,estes computadores eram operados a partir de uma console. Os dispositivos de entradaeram as leitoras de cartões e os drives de fita. Os dispositivos de saída eram as impres-soras de linha, os drives de fita e as perfuradoras de cartões. Os jobs do usuário (cartõesperfurados contendo o programa, dados e informações de controle do job) eram submeti-dos aos operador da máquina. Estes jobs eram armazenados em lotes (batches) de acordocom suas características semelhantes na tentativa de aumentar a velocidade de processa-mento. O sistema operacional era responsável somente por transferir o controle de um jobpara o seguinte. Estes sistemas eram denominados sistemas batch (lote) e apresentavamgrande ociosidade da CPU.

Em seguida, surgiu a tecnologia dos discos, permitindo ao sistema operacional deixartodos os jobs em um disco, podendo acessá-los diretamente. Assim, o sistema operacionalpoderia executar o agendamento ou escalonamento (scheduling) de jobs de modo a utilizaros recursos e executar as tarefas eficientemente.

Com o agendamento de jobs surgiu a capacidade de multiprogramar, aumentando autilização da CPU, pois os jobs eram organizados de modo que um deles sempre estariautilizando a CPU. Estes sistemas foram denominados sistemas multiprogramados.

Em um sistema multiprogramado, o sistema operacional possui a função de simples-mente redirecionar para um novo job e o executar. Quando o job selecionado necessitaraguardar, a CPU é redirecionada para outro job e assim por diante. O agendamento dosjobs, a gerência dos programas em memória e a escolha do próximo job a ser executadosão responsabilidades do sistema operacional.

Os sistemas multiprogramados não propiciavam a interação do usuário com o sistemacomputacional. A extensão da multiprogramação para tempo compartilhado permitiu quea CPU executasse múltiplos jobs, mas permutando entre eles de forma que as permutasocorressem com muita freqüência de forma que os usuários pudessem interagir com cadaprograma, diretamente, usando um teclado ou um mouse, e aguardar por resultados imedi-atos. Assim, vários usuários podem compartilhar o computador simultaneamente.

Os sistemas operacionais de tempo compartilhado usam o agendamento da CPU ea multiprogramação para atender cada usuário com uma pequena porção do computadorde tempo compartilhado. Além de gerência e proteção de memória, os sistemas de tempo

Page 13: KERNEL DO LINUX

Visão Geral de Sistemas Operacionais e o Kernel do Linux 13

compartilhado precisam gerar um tempo de resposta para os jobs que seja razoável. Paraisso, os jobs são permutados entre a memória principal e o disco, que então funciona comouma memória de retaguarda para a memória principal. O método utilizado para alcançareste objetivo é a memória virtual, pois permite a execução de um job que pode não estarcompletamente na memória. A vantagem deste esquema é que os programas podem sermaiores do que a memória física. Os sistemas de tempo compartilhado devem prover, tam-bém, um sistema de arquivos e um mecanismo para execução concorrente, necessitandode um esquema de escalonamento de CPU mais sofisticado. Além disso, o sistema devefornecer mecanismos para sincronização e comunicação de jobs, para garantir execuçãoordenada. Deve, também, assegurar que os jobs não ficarão eternamente um esperandopelo outro (deadlock). A construção de um sistema que atenda a todas estas necessidadesé dispendioso. Por isso, a idéia de tempo compartilhado foi demonstrada desde de 1960,mas somente no início da década de 1970 é que se tornou mais comum.

Foi na década de 1970 que surgiram os computadores pessoais (PCs). Inicialmente,os PCs não possuíam as facilidades necessárias para proteger um sistema operacionaldos programas dos usuários. Mas, com o tempo, os objetivos dos sistemas operacionaispassaram de maximizar a utilização da CPU e dos periféricos para maximizar a eficácia e acapacidade de resposta para o usuário. Estes sistemas incluem os PCs que executam sobo Microsoft Windows 1 e o Apple Macintosh 2. O sistema operacional Linux foi inicialmenteconstruído para um PC.

Os sistemas operacionais para PCs beneficiaram-se dos sistemas operacionais jáexistentes para mainframes. Porém, a utilização de CPU para um PC não era mais umproblema primordial, pois os indivíduos faziam uso isolado do computador. Mas algumascaracterísticas dos sistemas operacionais dos mainframes ainda eram importantes. Porexemplo, a proteção de arquivo, que a princípio não seria necessária para um PC, coma interligação dos computadores por uma rede ou outras conexões da Internet, tornou-senecessária.

Na década de 1980 começaram a surgir os sistemas multiprocessadores (ou sistemasparalelos ou sistemas fortemente acoplados). Estes sistemas possuem mais de um proces-sador, que se comunicam, compartilham o mesmo barramento, o relógio e, algumas vezes,a memória e os dispositivos periféricos.

Os sistemas multiprocessadores mais comuns usam multiprocessamento simétrico(SMP - Symmetric Multiprocesing), no qual cada processador executa concorrentementeuma cópia idêntica do sistema operacional, e estas cópias comunicam-se umas com asoutras quando necessário. Outros utilizam multiprocessamento assimétrico, no qual a cadaprocessador é designada uma tarefa específica. Este esquema define um relacionamento

1Marca registrada pela Microsoft Corporation [Microsoft (2007)]2Marca registrada pela Apple [Apple (2007)]

Page 14: KERNEL DO LINUX

14 EDITORA - UFLA/FAEPE - Kernel do Linux

mestre-escravo, onde um processador mestre controla o sistema e os demais (escravos)ou se dirigem ao mestre para instruções ou possuem tarefas pré-definidas.

A diferença entre os multiprocessamentos simétrico e assimétrico pode ser apresen-tada no hardware ou no software. Um hardware especial pode diferenciar os processadoresmúltiplos, ou um software pode ser escrito para permitir somente um mestre e múltiplos es-cravos. Por exemplo, o sistema operacional SunOS Versão 4 oferece multiprocessamentoassimétrico. A Versão 5 (Solaris 2) é simétrica sobre o mesmo hardware.

Com o crescimento das redes de computadores, especialmente a Internet e a WorldWide Web (WWW), praticamente todos os PCs e estações de trabalho podem acessar aInternet por uma rede local ou conexão por telefone. Assim, as redes de computadoresconstituem-se de uma coleção de processadores que não compartilham memória ou umrelógio. Cada processador tem sua memória local e comunicam-se através de barramentosde alta velocidade ou linha telefônica. Estes sistemas são denominados sistemas distribuí-dos ou sistemas fracamente acoplados.

Os sistemas distribuídos podem compartilhar tarefas de computação e oferecer umrico conjunto de recursos aos usuários.

Com o avanço da tecnologia, os PCs têm-se tornado mais rápidos, poderosos ebaratos, fazendo com que os projetistas afastem-se de sistemas centralizados e concentrem-se mais em PCs. Assim, os sistemas centralizados atuam hoje como sistemas servidorespara satisfazer as requisições geradas por sistemas clientes e são denominados cliente-servidor. Um sistema servidor pode ser classificado em sistema servidor de processamento(compute-server) e sistema servidor de arquivos (file-server system).

O sistema servidor de processamento oferece uma interface que permite ao clienteenviar requisições para realizar uma ação. O servidor, em resposta, executa a ação e enviaos resultados de volta ao cliente. Já o sistema servidor de arquivos oferece uma interfacepara o sistema de arquivos, permitindo ao cliente criar, atualizar, ler e excluir arquivos.

Um sistema distribuído pode ter também a estrutura de um sistema peer-to-peer(P2P), onde clientes e servidores não são diferenciados um do outro. Todos os nós dentrodo sistema podem atuar tanto como cliente quanto como servidor. A vantagem deste sis-tema em relação aos sistemas cliente-servidor é que os serviços podem ser oferecidos porvários nós, distribuídos por meio da rede, evitando o gargalo em um único servidor.

Outro desenvolvimento em sistemas operacionais envolve os sistemas em clusters,que reúnem diversas CPUs para realizar trabalho de computação. Estes sistemas sãoutilizados para oferecer serviço de alta disponibilidade, ou seja, um serviço que continuaráa ser fornecido mesmo com falha em um ou mais sistemas no cluster. Uma camada desoftware de cluster é executada nos nós do cluster, permitindo, assim, que cada nó monitoreum ou mais nós da rede. Se a máquina monitorada falhar, aquela que a estiver monitorando

Page 15: KERNEL DO LINUX

Visão Geral de Sistemas Operacionais e o Kernel do Linux 15

poderá assumir o armazenamento e reiniciar as aplicações que estavam sendo executadasna máquina que falhou.

Os sistemas em cluster podem ser assimétricos ou simétricos. No modo assimétrico,uma máquina está no modo hot-standby, enquanto a outra está executando as aplicações.A máquina hot-standby apenas monitora o servidor ativo. Se esse servidor falhar, o hot-standby se torna o servidor ativo. No modo simétrico, dois ou mais hosts estão executandoaplicações, e eles estão monitorando um ao outro.

Outra forma de sistema operacional de uso especial é o sistema de tempo real (real-time system), que é usado quando existem requisitos de tempo rígidos na operação de umprocessador ou do fluxo de dados. O processamento precisa ser feito dentro das restriçõesdefinidas, ou então o sistema falhará.

Os sistemas portáteis são dispositivos de tamanho limitado, conseqüentemente, pos-suem pequena quantidade de memória, processadores lentos e telas de vídeo pequenas,para que o consumo de energia também seja pequeno. Entre estes dispositivos estão oPalm, Pocket-PCs e telefones celulares. O sistema operacional e as aplicações para estesdispositivos precisam ser elaborados de forma a não sobrecarregar o processador. As limi-tações na funcionalidade dos PDAs é compensada por sua conveniência e portabilidade.

Dentro desta evolução dos sistemas operacionais, surgiu o Linux, que é apresentadona seção seguinte.

2.3 HISTÓRIA DO LINUX

O sistema operacional UNIX foi criado em 1969 por Dennis Ritchie e Ken Thomp-son, que eram pesquisadores da Bell Labs AT&T. A partir de 1977, começaram a ser liber-adas versões do sistema operacional UNIX com código fonte, permitindo o desenvolvimentode outras versões de sistemas operacionais, baseadas no UNIX, por outras organizações.Como exemplo, podemos citar os sistemas operacionais Berkeley Software Distributions(BSD), da Universidade da Califórnia em Berkeley, o Solaris da Sun e o AIX da IBM.

Como havia várias distribuições do UNIX, mas nenhuma padronização, surgiram duasiniciativas de padronização: POSIX e X/Open [Tanenbaum (1995)].

O Comitê de Padronização do IEEE, organização muito respeitada, no projeto POSIX(POS = Portable Operating System; IX foi adicionado para lembrar o Unix) criou o padrão1003.x, que define um conjunto de rotinas de biblioteca que todo sistema Unix produzidoem conformidade com este padrão deve suprir.

O X/Open foi um consórcio fundado por diversos fornecedores de sistemas Unix daEuropa com o objetivo de identificar e promover padrões abertos na área de tecnologiada informação. Seus membros originais eram a Bull, ICL, Siemens, Olivetti e Nixdorf. O

Page 16: KERNEL DO LINUX

16 EDITORA - UFLA/FAEPE - Kernel do Linux

X/Open gerenciou a marca UNIX de 1993 até 1996, quando ele foi fundido com o OpenSoftware Foundation para formar o The Open Group [UNIX (2007)].

A marca UNIX tornou-se uma marca registrada da Bell Labs AT&T, pois esta empresahavia criado originalmente o UNIX e por algum tempo somente seus clientes podiam chamarseus sistemas de UNIX. Assim, os sistemas operacionais que eram baseados no padrãoPOSIX, não podiam ser considerados sistemas UNIX.

Em 1991, Linus Torvalds desenvolveu o Linux como um sistema operacional paracomputadores que utilizavam o microprocessador 80386 da Intel, que naquele tempo eraum processador novo e avançado. Ele se baseou inicialmente no Minix, que era um sistemaUNIX de baixo custo usado como ferramenta de ensino, mas depois decidiu escrever seupróprio sistema operacional. Assim, o Linux compartilha algumas idéias do UNIX, mas nãoé um descendente direto do código fonte UNIX, pois foi desenvolvido utilizando o padrãoPOSIX. A primeira versão do Linux foi distribuída pela Internet e conquistou novos desen-volvedores e usuários, tornando-se um projeto colaborativo. in Hoje em dia, Linux é umsistema operacional que pode ser executado em diferentes plataformas, como AMD x86-64, ARM, Compaq Alpha, CRIS, DEC VAX, H8/300, Hitachi SuperH, HP PA-RISC, IBMS/390, Intel IA-64, MIPS, Motorola 68000, PowerPC, SPARC e UltraSPARC [Love (2005)].

A principal característica do Linux é ser um projeto colaborativo, desenvolvido por dife-rentes desenvolvedores utilizando a Internet como meio de troca de informações e disponi-bilização. Desta forma, apesar de Linus permanecer como o criador do Linux e mantenedordo kernel o progresso do sistema continua através dos grupos de desenvolvedores. O ker-nel do Linux é um software de código aberto, licenciado sob a GNU General Public License(GPL), e qualquer pessoa pode realizar download do código fonte.

Um sistema Linux básico é composto pelo kernel, bibliotecas, compilador, ferramen-tas e utilitários básicos do sistema, tais como processo de login e shell. Mas o sistemapode incluir também uma moderna implementação X Window System (sistema de janelas),incluindo um ambiente desktop, tal como GNOME.

2.4 O KERNEL DO LINUX

O kernel de um sistema operacional é a parte mais interna, o centro. Seus com-ponentes típicos são os tratadores de interrupções para requisições de serviços de inter-rupção, um escalonador para um processador de tempo compartilhado entre múltiplos pro-cessos, um sistema de gerenciamento de memória para gerenciar espaços de endereça-mento de processos e serviços de sistema, tais como rede e comunicação entre processos.A Figura 2.1 apresenta uma visualização da arquitetura do kernel, mas esta figura nãoilustra todos os componentes.

Page 17: KERNEL DO LINUX

Visão Geral de Sistemas Operacionais e o Kernel do Linux 17

Figura 2.1: Visualização da arquitetura do kernel [Maxwell (2000)]

Em sistemas onde as unidades de gerência de memória são protegidas, o kernelreside em um estado do sistema mais elevado do que as aplicações de um usuário normal.Este estado do kernel permite o acesso ao espaço de memória protegido e ao hardware e éreferido como espaço do kernel (kernel-space). Quando o kernel está executando o sistemaestá no modo kernel. As aplicações do usuário executam no espaço do usuário (user-space), possuem acesso somente a um subconjunto de recursos disponíveis da máquinae são capazes de realizar certas funções do sistema. Quando um usuário normal estáexecutando, o sistema está no modo usuário.

As aplicações que estão executando em um sistema comunicam-se com o kernelatravés de chamadas de sistema.

O kernel gerencia o hardware do sistema. O hardware utiliza interrupções para co-municar com o sistema. Uma interrupção gerada pelo hardware interrompe o kernel epode ser identificada por um número. O kernel utiliza o número para executar e respon-der a interrupção. Por exemplo, quando o usuário digita alguma coisa, o controlador do

Page 18: KERNEL DO LINUX

18 EDITORA - UFLA/FAEPE - Kernel do Linux

teclado caracteriza uma interrupção e comunica ao sistema que há um novo dado no bufferdo teclado. Através do número da interrupção o kernel executa o tratador de interrupçãocorreto. O tratador de interrupção processa o dado do teclado e notifica o controlador doteclado de que está pronto para novos dados.

Como mencionado anteriormente, o kernel do Linux possui a mesma API dos kernelsmodernos do Unix. Para realizar uma comparação entre o kernel do Linux e os kernelsclássicos do Unix, considere a classificação dos kernels em monolítico e microkernel.

Os kernels monolíticos são implementados como um processo grande executandoem um único espaço de endereçamento. Desta forma, o kernel fica em um disco comouma única biblioteca estática binária. Todos os serviços do kernel existem e executam emum espaço grande de endereçamento do kernel. O kernel pode invocar funções direta-mente assim como uma aplicação do espaço do usuário. A maioria dos sistemas Unix sãomonolíticos.

Os microkernels não são implementados como um único processo grande. As fun-cionalidades do kernel são quebradas em processos separados, chamados servidores. So-mente os servidores que necessitarem de modo de execução privilegiado é que podem serexecutados neste modo. Os demais servidores executam no espaço do usuário. Todos osservidores são mantidos separados e executam em diferentes espaços de endereçamento.A invocação direta de funções não é possível. A comunicação é feita através da passagemde mensagens. Um mecanismo de comunicação entre processos (InterProcess Commu-nication - IPC) é construído no sistema e os vários servidores comunicam-se e invocamserviços entre si enviando mensagens.

O kernel do Linux é do tipo monolítico, isto é, executa em um único espaço de en-dereçamento inteiramente no modo kernel. Porém, possui algumas características de mi-crokernel: possui um projeto modular com kernel preemptivo, suporte a threads de kernel ea capacidade de dinamicamente carregar bibliotecas separadas do kernel (kernel modules).Tudo é executado no modo kernel, com a invocação direta de funções. Linux é modular ebaseado em threads. Algumas diferenças do kernel do Linux em relação a outras variantesdo Unix são apresentadas a seguir.

• O Linux suporta o carregamento dinâmico de módulos do kernel

• O Linux tem suporte a multiprocessador simétrico (Symmetrical Multiprocessor -SMP), enquanto que a maioria das implementações Unix não suportam

• O kernel do Linux é preemptivo, permitindo interromper uma tarefa mesmo se elaestiver executando no kernel, o que não é comum na maioria dos kernels tradi-cionais do Unix

• Linux possui uma estratégia interessante de suporte a thread: não diferencia entrethreads e processos normais. Para o kernel, todos os processos são iguais, per-

Page 19: KERNEL DO LINUX

Visão Geral de Sistemas Operacionais e o Kernel do Linux 19

mitindo o compartilhamento de recursos. (Os conceitos de processo e thread sãodetalhados no Capítulo 3)

• Linux provê um modelo de dispositivos orientados a objeto com classes de dispo-sitivos, eventos hotpluggable e um user-space device filesystem (sysfs) (Maioresdetalhes são encontrados no Capítulo 5)

O kernel do Linux suportar o carregamento dinâmico de módulos significa que o kernelnão precisa estar todo na memória. Algumas porções são fundamentais para o funciona-mento do kernel, tais como, o código para escalonamento de processos. Mas outras, sópreciam ser carregadas quando se fazem necessárias pelo kernel, podendo estar ausentesno resto do tempo, como é o caso da maioria dos drivers de dispositivos.

Considere, por exemplo, o código que habilita o kernel a acessar seu drive de CD-ROM. Este código, só precisa estar em memória durante o acesso ao aparelho, de formaque o kernel pode ser configurado para carregar tal código um pouco antes de cada acesso.Após o acesso o código poderá ser removido.

As seções do kernel que podem ser adicionadas ou removidas durante o funciona-mento do sistema são chamadas de módulos do kernel.

Os módulos do kernel introduzem um custo em nível de complexidade, pois a adiçãoe remoção de partes do kernel durante a execução necessita de uma codificação extra.Este custo de complexidade pode ser diminuído se for delegado a um programa externo,pois distribuirá a complexidade. O programa externo utilizado para este propósito é o mod-probe. Existem várias funções do kernel que interagem com o modprobe para carregarmódulos. Por exemplo, a função request_module() é a função que o restante do ker-nel chama quando descobre que há necessidade de se carregar um módulo e a funçãoexec_modprobe() executa o programa que anexa o módulo ao kernel.

Os kernels do Linux distinguem-se entre estáveis e em desenvolvimento com umesquema de nomes formado por três números, separados por um ponto [Love (2005),Mazioli (2006)]. O primeiro valor corresponde à release maior, o segundo é a release menore o terceiro é revisão (patchlevel). A release menor determina se o kernel é estável ou estáem desenvolvimento. Um número par significa que o kernel é estável e um número ímparsignifica que está em desenvolvimento. Por exemplo, kernel 2.6.0 significa que tem umaversão maior 2, tem uma versão menor 6 (que é estável) e está na revisão 0.

2.4.1 Obtenção, configuração e compilação do kernel do Linux

O código fonte mais atual do Linux está sempre disponível, na versão completa e empatches incrementais, na página oficial do kernel do Linux: http://www.kernel.org.

A versão completa do código fonte do kernel do Linux é distribuída no formato GNUzip (gzip) e no formato bzip2. O formato bzip2 possui o nome linux-x.y.z.tar.bz2, onde x.y.zé a versão de uma release particular do fonte do kernel. Após realizar o download do fonte,

Page 20: KERNEL DO LINUX

20 EDITORA - UFLA/FAEPE - Kernel do Linux

é necessário descompactá-lo. Se for a versão completa compactada com bzip2, bastaexecutar:

$ tar xvjf linux-x.y.z.tar.bz2.

Se for a versão compactada com GNU zip, basta executar:

$ tar xvzf linux-x.y.z.tar.gz.

Após descompactar o fonte será gerado o diretório linux-x.y.z.

A comunidade de kernel do Linux distribui mudanças no código através de patches.Assim, os patches incrementais permitem passar de uma versão do fonte do kernel paraoutra. Ao invés de realizar download da versão completa do fonte do kernel, o desenvolve-dor pode simplesmente aplicar um patch incremental e passar de uma versão para outra.Esta opção é mais rápida pois os arquivos são menores. Para aplicar um patch incremental,de dentro da árvore de fonte do kernel, basta executar:

$ patch p1 < ../patch-x.y.z

Geralmente, um patch para uma dada versão do kernel é aplicada à versão anterior.

A árvore de arquivos fontes do kernel do Linux é dividida em diretórios e subdiretórios.A Tabela 2.1 apresenta os diretórios e suas descrições.

Diretório Descriçãoarch Códigos específicos para arquiteturas (i386, alpha, mips, etc.)Documentation Documentação do fonte do kerneldrivers Device drivers para placas de vídeo, placas de rede, adaptadores

SCSI, etc.fs Sistemas de arquivos suportados pelo Linux, como, por exemplo,

o ext2include Arquivos de cabeçalhos do kernel (.h)init Código de inicialização do kernelipc Código de comunicação entre processoskernel Parte principal do kernel: processos, execução de programa,

sinais, módulos, escalonador, etclib Funções do kernel de propósito geralmm Subsistema de gerência de memórianet Subsistema de redescripts Programas externos usados para construir a imagem do kernelsecurity Módulo de Segurança do Linuxsound Subsistema de somusr Código de espaço de usuários

Tabela 2.1: Diretórios na árvore do fonte do kernel [Love (2005)]

Page 21: KERNEL DO LINUX

Visão Geral de Sistemas Operacionais e o Kernel do Linux 21

O kernel 2.6 do Linux introduziu opções novas de configuração e construção do sis-tema. Como o código fonte do kernel do Linux está disponível, é possível configurar ecustomizá-lo antes de compilá-lo.

O kernel possui várias características e suporte a diferentes tipos de hardware, porisso é necessário configurá-lo. As opções de configuração são prefixadas pelo CONFIGna forma CONFIG_FEATURE. Por exemplo, multiprocessamento simétrico (SMP) é contro-lado pela opção de configuração CONFIG_SMP. Se esta opção estiver habilitada, SMP éhabilitado, caso contrário ficará desabilitado. As opções de configuração são usadas paradecidir quais os arquivos a serem gerados e quais códigos manipulados via diretivas depreprocessador.

O kernel possui múltiplas ferramentas para facilitar a configuração. A mais simples ébaseada em texto, utilizando o utilitário em linha de comando:

$ make config

Este utilitário vai através de cada opção, uma por uma, solicitando ao usuário pararesponder yes (sim), no (não) ou module. Esta forma gasta muito tempo para ser executada.Porém, existem outras formas mais rápidas. Por exemplo, um utilitário gráfico, pode serexecutado pelo comando:

$ make menuconfig

Um utilitário gráfico baseado em X11 pode ser invocado por:

$ make xconfig

Um utilitário gráfico baseado em gtk+ é chamado pelo comando:

$ make gconfig

Estes três utilitários dividem as várias opções de configuração em categorias, deacordo com o tipo de processador e características. Pode-se mover através das catego-rias, ver as opções de kernel e alterar seus valores.

O comando $ make defconfig cria uma configuração baseada nos valores defaultda arquitetura. As opções de configuração são armazenadas no root da árvore do fonte dokernel, no arquivo denominado .config. Este arquivo pode ser editado diretamente.

Depois de configurado o kernel, o seguinte comando é necessário para construí-lo:

$ make

Após a construção do kernel é necessário instalá-lo, mas isso depende da arquiteturae do boot loader. É necessário consultar as orientações do boot loader usado de ondecopiar a imagem do kernel e como setá-lo para boot. Por exemplo, considere a arquiteturax86 usando o boot loader Grub 3. É necessário copiar arch/i386/boot/bzImage para /boot,nomeá-lo como algo do tipo vmlinuz-version e editar /boot/grub/grub.conf com a nova

3Grub - Grand Unified Boot Loader é um gerenciador de boot que permite inicializar diferentes sistemasoperacionais e dá suporte a diferentes sistemas de arquivos [Mazioli (2006)]

Page 22: KERNEL DO LINUX

22 EDITORA - UFLA/FAEPE - Kernel do Linux

entrada para o novo kernel. Em sistemas usando LILO 4 para boot, o arquivo a ser edi-tado é /etc/lilo.conf e em seguida é necessário reexecutar lilo. A instalação de módulos éautomatizada e independente da arquitetura. Como root, basta executar o comando:

% make modules_install

e serão instalados todos os módulos compilados no diretório /lib. O processo deconstrução também cria o arquivo System.map no root da árvore de fontes do kernel.Ele contém uma tabela de símbolos, que mapeia símbolos do kernel para seus endereçosiniciais. É usado durante depuração para tradução de endereços de memória para nomesde funções e variáveis.

2.5 INICIALIZAÇÃO DE UM SISTEMA EM UM PC

Cada CPU existente no PC deve inicializar e para isso executa um auto-teste duranteuma fração de segundo [Bovet (2002)]. Se houver dois processadores Pentium, por exem-plo, uma das CPUs é sempre a CPU primária e a outra é a secundária. A primária seencarrega de todo o trabalho restante na inicialização e o kernel ativará a segunda CPUmais tarde. Para o restante do procedimento de boot há apenas uma CPU para se preocu-par, mas posteriormente o kernel deverá ativar explicitamente quaisquer CPUs adicionais.

A seguir, a CPU busca e executa as instruções localizadas no endereço 0xfffffff0, bempróximas do último endereço possível em uma CPU de 32 bits. Não havendo memóriaRAM normal localizada neste endereço, o hardware de memória simula sua existência. Ainstrução existente neste endereço é um salto para o BIOS (Basic Input/Output System)que está montado na placa-mãe e é responsável pelo próximo estágio da inicialização.

O BIOS começa pela escolha de um dispositivo de inicialização, utilizando regras in-corporadas a seu funcionamento. O mais comum é o BIOS tentar, em primeiro lugar, darandamento à inicialização a partir de uma unidade para discos flexíveis e, no caso de falha,a partir do disco rígido primário. Se esta tentativa falhar, a tentativa poderá ser a partir deum drive de CD-ROM. Esta discussão assumirá a inicialização pelo disco rígido.

A partir do dispositivo de inicialização, o BIOS lê o primeiro setor denominado MasterBoot Record (MBR). O que acontece a seguir depende de como o Linux foi instalado nosistema. Assumindo que o LILO é o carregador do kernel, o BIOS chega alguns valorespresentes no MBR e inspeciona para obter a localização do setor de inicialização. O BIOScarregará esse setor, que contém o início do LILO, para a memória e se posicionará emseu princípio. a partir de então o LILO estará no controle e carregará sua parte restante eencontrará seus dados de configuração no disco, que lhe informará onde encontrar o kernel

4LILO - Linux Loader é gerenciador de partida padrão para quem deseja iniciar o GNU/Linux através dodisco rígido. Ele permite selecionar qual sistema operacional será iniciado (caso haja mais de um) e funcionatanto em discos rígidos IDE como SCSI [Mazioli (2006)].

Page 23: KERNEL DO LINUX

Visão Geral de Sistemas Operacionais e o Kernel do Linux 23

e quais as opções a serem passadas para a inicialização. O LILO carregará o kernel para amemória e passará a utilizá-lo. O kernel que está inicialmente compactado se descompactae transfere o controle para o kernel não compactado.

Após a carga do kernel na memória e depois que alguns dispositivos de hardwareessenciais, como a unidade de gerência de memória, forem configurados em um nível baixo,o kernel pulará para a função start_kernel() que inicializa todas as estruturas de dadosnecessárias ao kernel, habilita interrupções e cria outra thread do kernel (processo 1), co-nhecida como processo init, pois executa a função init(), que torna completa a inicializaçãodo kernel. A função init() invoca a chamada de sistema execve() para carregar o programaexecutável init. Como resultado, a thread do kernel init torna-se um processo regular tendosua própria estrutura de dados do kernel por processo. O processo init fica ativo até queo sistema seja desligado, já que ele cria e monitora a atividade de todos os processos queimplementam os outros níveis do sistema operacional.

2.6 RESUMO

Este capítulo apresentou noções gerais sobre o histórico de evolução dos sistemasoperacionais, os serviços que são oferecidos por um sistema operacional, o histórico ecaracterísticas do Linux, estrutura do kernel do Linux, como obter os fontes e configurarinstalar o kernel do Linux.

Page 24: KERNEL DO LINUX

24 EDITORA - UFLA/FAEPE - Kernel do Linux

Page 25: KERNEL DO LINUX

3GERÊNCIA DE PROCESSOS

Este capítulo apresenta conceitos importantes sobre processos, como os estados, acriação, as estruturas de dados utilizadas na implementação do Linux e o escalonamento.A referência principal utilizada neste capítulo foi [Silberschatz (2004)].

3.1 INTRODUÇÃO

Nos sistemas computacionais atuais, a multiprogramação permite que vários pro-gramas sejam carregados na memória e executados de forma concorrente. Além disso,espera-se que o usuário seja atendido na execução de seus programas o melhor e maisrápido possível. Desta forma, foi verificada a necessidade de um controle melhor da exe-cução dos programas e tarefas do sistema. Por isso, o conceito de processo surgiu.

Um processo pode ser definido como um programa em execução. Mas um processotambém inclui um conjunto de recursos tais como arquivos abertos e sinais pendentes, da-dos internos do kernel, estado do processador, um espaço de endereçamento, um ou maisthreads de execução e uma seção de dados contendo variáveis globais. Assim, um pro-grama por si só não é um processo. Um processo é um programa ativo e seus recursosrelacionados. Dois ou mais processos existentes podem estar executando o mesmo pro-grama e estarão, neste caso, compartilhando vários recursos, tais como arquivos abertosou um espaço de endereçamento. Do ponto de vista do kernel, o propósito de um processoé atuar como uma entidade para a qual os recursos do sistema (tempo de CPU, memória,etc) são alocados.

A interface entre um processo e o sistema operacional é denominada chamada desistema. Ela ocorre quando um processo de usuário solicita um srviço proporcionado pelokernel por meio da chamada de uma função especial. O processo do usuário é colocadoem espera e o kernel examina a solicitação, tenta executá-la e passa o resultado de voltapara o processo de usuário, que então é reiniciado. Exemplos de chamadas de sistemarelacionadas a processos são: fork, execve, kill.

Um processo, durante sua execução, passa por diferentes estados. Os estados pos-síveis para um processo são os seguintes [Silberschatz (2004)]:

Page 26: KERNEL DO LINUX

26 EDITORA - UFLA/FAEPE - Kernel do Linux

• Novo: quando o processo está sendo criado

• Executando: as instruções estão sendo executadas

• Esperando: o processo está esperando pela ocorrência de algum evento (como otérmino de entrada e saída ou a recepção de um sinal)

• Pronto: o processo está esperando para ser designado a um processador

• Terminado: o processo terminou sua execução

Quando um processo filho é criado, ele é quase idêntico ao seu pai (processo queo criou). Ele recebe um cópia lógica do espaço de endereçamento do pai e executa omesmo código como o pai, começando na próxima instrução após a chamada de sistemaque criou o processo. Embora pai e filho possam compartilhar as páginas contendo ocódigo do programa (texto), eles possuem cópias separadas de dados (pilha e heap), talque as mudanças realizadas pelo filho em uma locação de memória são invisíveis ao pai (evice-versa).

Cada processo é representado no sistema operacional por um bloco de controle deprocesso (PCB - Process Control Block), que contém informações associadas ao processoespecífico, tais como:

Estado do processo: o estado pode ser novo, pronto, executando, esperando, etc

Contador de programa: indica o endereço da próxima instrução a ser executada peloprocesso

Registradores da CPU: incluem acumuladores, registradores de índice, ponteiros depilha, registradores de uso e informações de código de condição. Quando ocorre umainterrupção, esta informação de estado deve ser salva juntamente com o contador deprograma, para que o processo possa continuar corretamente mais tarde

Informação de escalonamento de CPU: inclui prioridade do processo, ponteiros parafilas de escalonamento e quaisquer outros parâmetros de escalonamento

Informação de gerência de memória: inclui os valores dos registradores base e limite, astabelas de páginas ou as tabelas de segmentos, dependendo do sistema de memóriautilizado pelo sistema operacional

Informação de contabilização: inclui a quantidade de tempo de CPU e de tempo realutilizado, limites de tempo, registros de contabilidade, números de jobs ou processos,etc

Informação de estado de E/S: inclui a lista de dispositivos de E/S alocados a este pro-cesso, uma lista de arquivos abertos, etc

O PCB serve como repositório para qualquer informação que possa variar de um pro-cesso para outro.

Page 27: KERNEL DO LINUX

Gerência de Processos 27

Threads de execução ou simplesmente threads, são os objetos de atividade dentro doprocesso. Cada thread é composta por um contador de programa único, pilha de processoe um conjunto de registradores do processador.

Os sistemas Unix modernos suportam aplicações multithread, onde os programasdos usuários possuem muitos fluxos de execução relativamente independentes que com-partilham uma grande porção das estruturas de dados da aplicação. Nestes sistemas, umprocesso é composto por diversas threads, cada uma representando um fluxo de execuçãodo processo. A maioria das aplicações multithread são escritas usando um conjunto padrãode funções de biblioteca chamadas bibliotecas pthread (POSIX thread).

Versões mais antigas do kernel do Linux não ofereciam suporte a aplicações mul-tithread. Do ponto de vista do kernel, uma aplicação multithread era um processo nor-mal. Os múltiplos fluxos de execução de uma aplicação multithread eram criados, trata-dos e escalonados inteiramente no modo usuário, geralmente por uma biblioteca pthread.Porém, tais implementações não eram muito satisfatórias. Por exemplo, suponha que umprograma de xadrez utilize duas threads: uma para controlar o tabuleiro gráfico, esperarpelo movimento do jogador humano e mostrar os movimentos do computador, enquanto aoutra thread reflete sobre o próximo movimento do jogo. Enquanto a primeira thread es-pera pelo movimento humano, a segunda thread deve executar continuamente, explorandoo tempo de pensamento do jogador humano. Entretanto, se o programa de xadrez é umúnico processo, a primeira thread não pode simplesmente realizar uma chamada de sis-tema bloqueante para esperar por uma ação do usuário, pois neste caso a segunda threadseria bloqueada também. Assim, a primeira thread deve utilizar técnicas não bloqueantessofisticadas para garantir que o processo permaneça executando.

O Linux utiliza processos leves (lightweight processes) para oferecer melhor suportepara aplicações multithread. Basicamente, dois processos leves podem compartilhar algunsrecursos, como espaço de endereçamento, arquivos abertos, etc. Quando um deles modi-fica um recurso compartilhado, o outro imediatamente vê a alteração. Porém, é necessárioque os dois processos realizem sincronização para acessar o recurso compartilhado.

Se processos leves estão disponíveis, uma forma de implementar aplicações multi-thread é associando um processo leve com cada thread. Desta forma, as threads podemacessar o mesmo conjunto de estruturas de dados da aplicação simplesmente compartil-hando o mesmo espaço de endereçamento de memória, o mesmo conjunto de arquivosabertos e assim por diante. Ao mesmo tempo, cada thread pode ser escalonada indepen-dentemente pelo kernel tal que possa dormir enquanto a outra permaneça executando. Doisexemplos de bibliotecas pthreads compatíveis com POSIX que utilizam processos levesdo Linux são Linux Threads [Bovet (2002)] e o Next Generation Posix Threading Package(NGPT) da IBM [Seebac (2004)].

Page 28: KERNEL DO LINUX

28 EDITORA - UFLA/FAEPE - Kernel do Linux

O kernel escalona threads individuais, não processos, pois thread é considerada comoum tipo especial de processo.

3.2 CRIAÇÃO DE PROCESSOS

A criação de processos no Linux ocorre através da chamada de sistema fork(), quecria um novo processo duplicando um processo existente. O processo que chama o fork()é o processo pai, enquanto que o novo processo é o processo filho. O pai prossegue aexecução e o filho começa a execução do mesmo ponto onde a chamada do fork() foi feita.Esta chamada de sistema retorna do kernel duas vezes: uma no processo pai e outro noprocesso filho. Os dois processos diferem no seu PID, que é um identificador único paracada processo.

Imediatamente após um fork() é desejável executar um programa diferente. A famíliaexec() de chamadas de função é usada para criar um novo espaço de endereçamento ecarregar um novo programa nele.

Um programa termina sua execução via chamada de sistema exit(). Esta função ter-mina o processo e libera todos os seus recursos. Um processo pai pode informar-se sobreo estado de um filho terminado via a chamada de sistema wait(), que permite a um processoesperar pela terminação de um processo específico. Quando um processo termina, ele écolocado no estado zumbi, que é usado para representar um processo filho que terminou,até que o processo pai chame wait() ou waitpid().

O Linux implementa fork() via a chamada de sistema clone(). Esta chamada possuiuma série de flags que especificam que recursos devem ser compartilhados entre os pro-cessos pai e filho. As chamadas fork(), vfork() e __clone() invocam a chamada sistemaclone() com as flags de requisito. A chamada de sistema clone(), por sua vez, chamado_fork(), que é definido em kernel/fork.c.

A função do_fork(), chama copy_process() e então inicia a execução do processo.copy_process() realiza as seguintes atividades:

• Cria uma nova pilha de kernel, uma estrutura com informações de threads e umdescritor de processo para o novo processo. Os novos valores são idênticos àque-les da tarefa corrente. Neste ponto, os descritores de processo do processo pai edo filho são idênticos

• Verifica se o novo filho não excederá os limites de recursos para o número deprocesso do usuário atual

• Para o filho se diferenciar do pais, vários campos do descritor de processo sãolimpados ou setados para valores iniciais. Membros do descritor de processo quenão são herdados são informações estatísticas primárias. O conjunto de dados nodescritor de processo é compartilhado

Page 29: KERNEL DO LINUX

Gerência de Processos 29

• Em seguida, o estado do filho é setado para TASK_UNINTERRUPTIBLE, paragarantir que ele não execute ainda

• Então, copy_process() seta as flags do descritor de processo

• Dependendo das flags passadas para clone(), copy_process() duplica ou compar-tilha arquivos abertos, informações sobre sistema de arquivos, tratadores de sinais,espaço de endereçamento de processos e espaço de nomes

• A seguir, o timeslice restante entre pai e filho é dividido entre eles

• copy_process() limpa e retorna, para o processo que o chamou, um ponteiro parao novo filho. Voltando ao do_fork(), se copy_process() retorna com sucesso, o novofilho é acordado e executa

O código a seguir apresenta um exemplo de programa para a criação de processo noLinux [Silberschatz (2004)] e ilustra a utilização das chamadas de sistema fork(), wait() eexit().

1 # inc lude < s t d i o . h>2 vo id main ( i n t argc , char ∗argv [ ] )3 {4 i n t p id ;5 /∗ c r i ou um novo processo ∗ /6 p id = f o r k ( ) ;7 i f ( p id <0) { /∗ er ro oco r r i do ∗ /8 f p r i n t f ( s tde r r , " Fork fa lhou " ) ;9 e x i t (−1);10 } e lse i f ( p id ==0) { /∗ processo f i l h o ∗ /11 execlp ( " / b in / l s " , " l s " , NULL ) ;12 }13 else { /∗ processo pa i ∗ /14 /∗ pai i r á esperar pela conclusão do f i l h o ∗ /15 wa i t (NULL ) ;16 p r i n t f ( " F i l ho completou " ) ;17 e x i t ( 0 ) ;18 }19 }

Este programa cria um novo processo na linha 6 com a chamada fork(). Na variávelpid é retornado zero para o processo filho e identificador do filho para o processo pai. Apóso fork() pai e filho continuam a execução do código. Na linha 11, execlp é usada pararealocar espaço de memória do processo a um novo programa. A chamada execlp carregaum arquivo binário na memória e inicia sua execução. Deste modo, pai e filho são capazesde estabelecer comunicação e então seguir seus caminhos separados. O filho executa oprograma ls e o pai aguarda pela conclusão do processo filho com a chamada de sistema

Page 30: KERNEL DO LINUX

30 EDITORA - UFLA/FAEPE - Kernel do Linux

wait (linha 15). Quando o processo filho termina, o processo pai reassume a partir dachamada wait e termina usando a chamada de sistema exit (linha17).

3.3 DESCRITOR DE PROCESSO E A ESTRUTURA DE TAREFAS

O kernel armazena a lista de processos em uma lista encadeada duplamente circulardenominada lista de tarefas. Cada elemento na lista de tarefas é um descritor de processodo tipo struct task_struct, que é definido em <linux/sched.h>, e contém todas as infor-mações sobre um processo específico. Então, no Linux o bloco de controle de processos éimplementado nesta estrutura. Portanto, todas as informações sobre os arquivos abertos,o espaço de endereçamento do processo, os sinais pendentes, o estado do processo, etc,são armazenados nesta estrutura. A Figura 3.1 representa o descritor do processo e listade tarefas.

Figura 3.1: O descritor do processo e a lista de tarefas [Love (2005)]

Os estados do processo no kernel do Linux são os seguintes:

• TASK_RUNNING: o processo está executando

• TASK_INTERRUPTIBLE: o processo está bloqueado (dormindo), esperando poralguma condição para existir. Quando esta condição existe o kernel seta o estadodo processo para TASK_RUNNING. O processo também acorda prematuramentee torna-se executável se ele receber um sinal

Page 31: KERNEL DO LINUX

Gerência de Processos 31

• TASK_UNINTERRUPTIBLE: estado idêntico ao estado TASK_INTERRUPTIBLE,exceto que ele não acorda e torna-se executável se ele receber um sinal. Esteestado é usado em situações onde o processo deve esperar sem interrupção ouquando o evento é esperado ocorrer muito rapidamente

• TASK_ZOMBIE: a tarefa terminou, mas seu processo pai ainda não realizou umachamada de sistema wait4(). O descritor de processo da tarefa deve permanecer,pois o pai pode querer acessá-lo. Se o pai chama wait4(), o descritor do processoé desalocado

• TASK_STOPPED: a execução do processo terminou; a tarefa não está executandonem está elegível para executar. Isto ocorre se a tarefa recebe o signal SIGSTOP,SIGTSTP, SIGTTIN ou SIGTTOU ou se ela recebe um sinal enquanto está sendodepurada

A Figura 3.2 apresenta o diagrama de estados de processos no kernel do Linux e suastransições possíveis.

Figura 3.2: Diagrama de estados de processos no kernel do Linux

O código do kernel freqüentemente precisa mudar o estado do processo. O meca-nismo preferido é utilizando a seguinte função:

Page 32: KERNEL DO LINUX

32 EDITORA - UFLA/FAEPE - Kernel do Linux

set_task_state(task, state);

Esta função seta a tarefa task para o estado state. Se aplicável, a função tambémprovidencia uma barreira para forçar a ordenação dos outros processo (isto é necessáriosomente em sistemas SMP).

3.4 CONTEXTO DO PROCESSO

Uma das partes mais importantes de um processo é a execução do código do pro-grama, que é lido de um arquivo executável e executado dentro do espaço de endereça-mento do programa. Um programa normal é executado no espaço do usuário. Quando esteprograma executa uma chamada de sistema ou dispara uma exceção, ele entra no espaçodo kernel. Neste ponto, o kernel é dito estar no contexto do processo.

Chamadas de sistema e tratadores de exceções são interfaces bem definidas dentrodo kernel. Um processo pode começar a execução no espaço do kernel somente atravésde uma dessas interfaces.

3.5 ÁRVORE DA FAMÍLIA DE PROCESSOS

No Linux, há uma hierarquia entre os processos. Todos os processos são descen-dentes do processo init, cujo PID é 1 [Love (2005)]. O kernel inicializa init no último passodo processo de boot. O processo init, em resposta, lê os scripts de inicialização e executamais programas, completando o processo de boot.

Todo processo no sistema, tem exatamente um pai e todo processo tem zero ou maisfilhos. Processos que são filhos do mesmo pai são denominados processos irmãos. O rela-cionamento entre os processo é armazenado no descritor de processo. Cada task_structtem um ponteiro para a task_struct do pai, denominado parent, e uma lista de filhos, de-nominada children. Conseqüentemente, dado o processo corrente, é possível obter o des-critor do processo de seu pai com o seguinte código:

struct task_struct *my_parent = current->parent;

Similarmente, é possível interagir sobre um filho do processo com o código apresen-tado na Figura 3.3.

É possível seguir a hierarquia de qualquer processo no sistema pois a lista de tarefasé uma lista duplamente encadeada circular. Assim, para obter a próxima tarefa na lista,dada qualquer tarefa válida, basta usar:

list_entry(task->tasks.next, struct task_struct, tasks)

Para obter a tarefa anterior é da mesma forma:

list_entry(task->tasks.prev, struct task_struct, tasks)

Page 33: KERNEL DO LINUX

Gerência de Processos 33

Figura 3.3: Código da estrutura para interação entre processo pai e filho.

3.6 IMPLEMENTAÇÃO DE THREADS NO LINUX

Para o kernel do Linux, não há conceito de thread. Linux implementa todas as threadscomo processos padrão. Não há nenhuma semântica de escalonamento especial ou es-truturas de dados para representar threads. Uma thread é meramente um processo quecompartilha certos recursos com outros processos. Cada thread tem uma task_struct únicae para o kernel é como um processo normal (que ocorre para compartilhar recursos, taiscomo um espaço de endereçamento, com outros processos). Para o Linux, threads sãosimplesmente uma forma de compartilhar recursos entre processos.

Threads são criadas como tarefas normais, com a exceção que para a chamada desistema clone() são passadas flags correspondendo aos recursos específicos a serem com-partilhados:

clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);CLONE_VM: pai e filho compartilham o espaço de endereçamento.CLONE_FS: pai e filho compartilham informação do sistema de arquivos.CLONE_FILES: pai e filho compartilham arquivos abertos.CLONE_SIGHAND: pai e filho compartilham tratadores de sinais e sinais bloqueados.As flags de clone() são definidas em linux/sched.h. O código anterior resulta em

um comportamento idêntico a um fork() normal, exceto que o espaço de endereçamento,recursos do sistema de arquivos, descritores de arquivos e tratadores de sinal são compar-tilhados. A nova tarefa e seu pai são chamados de threads.

3.7 ESCALONAMENTO DE PROCESSOS

O escalonador de processos é o componente do kernel que seleciona qual processoserá o próximo a ser executado. Ele pode ser visto como um subsistema do kernel quedivide o recurso finito do tempo de processador entre os processos executáveis em umsistema. Ao decidir que processo pode executar, o escalonador é responsável pela me-

Page 34: KERNEL DO LINUX

34 EDITORA - UFLA/FAEPE - Kernel do Linux

lhor utilização do sistema e dar a impressão que múltiplos processos estão executandosimultaneamente. O objetivo de um escalonador é utilizar melhor o tempo do processador,fazendo com que sempre haja um processo executando.

Um sistema operacional multitarefa é aquele que pode permitir a execução de mais deum processo. Em máquinas com um único processador, dá a ilusão de que múltiplos pro-cessos estão executando concorrentemente. Em máquinas multiprocessadas, isto tambémpermite que processos realmente executem concorrentemente, em paralelo, em diferentesprocessadores. Em sistemas operacionais Linux modernos é possível ter 100 processosem memória mas somente um no estado executável por processador.

Linux é um sistema multitarefa e preemptivo. Neste modelo, o escalonador decidequando um processo deve interromper a execução e um novo processo deve ser escalo-nado para retomar a execução. O ato de suspender um processo que está executando édenominado preemptivo. O tempo que um processo executa antes de ser suspenso é pre-determinado e é denominado timeslice do processo. O timeslice dá a cada processo prontopara ser executado uma fatia de tempo do processador. Gerenciar o timeslice permite aoescalonador tomar decisões de escalonamento global para o sistema e prevenir que umprocesso monopolize o processador. Para realizar um escalonamento é necessário quehaja alguma política.

Política de escalonamento é o comportamento do escalonador que determina o quee quando executar, de maneira que haja utilização ótima do tempo do processador.

Processos podem ser classificados como I/O-bound ou CPU-bound.

Processos I/O-bound são aqueles que gastam a maior parte de seu tempo subme-tendo e esperando por requisições de I/O (entrada e saída).

Processos CPU-bound gastam mais tempo executando código. Eles tendem a exe-cutar até serem interrompidos, pois eles não bloqueiam para atender requisições de I/Ocom muita freqüência.

O Linux busca proporcionar uma boa resposta interativa, otimizando a resposta a pro-cessos. Assim, favorece mais os processos I/O-bound do que os processos CPU-bound.

Um algoritmo de escalonamento baseado em prioridade busca ordenar os processosbaseado em sua necessidade de tempo de processador. Assim, processos com priori-dade mais alta executam antes daqueles com uma prioridade mais baixa, enquanto queos processos com a mesma prioridade são escalonados de forma round-robin (um apóso outro, repetidamente). No Linux, os processos com prioridade mais alta recebem times-lices maiores. Processos prontos para executar com timeslice restantes e prioridade maisalta sempre executam. Tanto o sistema quanto o usuário podem setar uma prioridade doprocesso para influenciar o comportamento do escalonamento do sistema.

O Linux implementa um escalonamento baseado em prioridade dinâmica, onde háuma prioridade inicial para os processos e então é permitido ao escalonador aumentar ou

Page 35: KERNEL DO LINUX

Gerência de Processos 35

diminuir a prioridade dinamicamente para preencher os objetivos do escalonamento. Porexemplo, um processo que está gastando mais tempo esperando por I/O do que executandoé I/O-bound. No Linux, ele recebe um prioridade dinâmica elevada. Em contra partida, umprocesso que continuamente usa seu timeslice inteiro é CPU-bound e deveria receber umaprioridade dinâmica mais baixa.

O kernel do Linux implementa dois intervalos de prioridade separados. O primeiro éum valor nice que varia de−20 a +19 com o default igual a 0. Valores maiores correspondema uma prioridade mais baixa. Processos com um valor nice mais baixo (maior prioridade)executam antes de processos com um valor nice mais alto (menor prioridade). O valor niceajuda determinar quão longo é um timeslice que um processo recebe. Um processo comum valor nice −20 recebe o timeslice maior possível, enquanto que um processo com umvalor nice 19 recebe o timeslice menor possível.

O segundo intervalo de valores é a prioridade de tempo real. Os valores são confi-guráveis, mas por default variam entre 0 e 99. Todos os processos de tempo real são deprioridade mais alta do que processos normais. Linux implementa prioridades de temporeal de acordo com o padrão POSIX.

O Linux implementa os timeslices do escalonador de acordo com a Tabela 3.1. Ao sercriado, o processo filho recebe o valor nice do pai e timeslice correspondente à metade dotempo do processo pai. Tarefas com prioridade mínima têm duração de timeslice igual a 5ms; tarefas com prioridade default a duração é de 100 ms. e tarefas com prioridade máximaé de 800 ms. Entretanto, o escalonador Linux dinamicamente determina o timeslice de umprocesso baseado na prioridade. Isto permite que processos com prioridade mais altaexecutam por tempo mais longo e com mais freqüência. A implementação de timeslices eprioridades dinâmicas provê um desempenho de escalonamento robusto.

Tabela 3.1: Timeslices do escalonadorTipo de tarefa Valor Nice Duração do TimesliceCriada inicialmente valor do processo pai metade do processo paiPrioridade mínima +19 5 ms. (MIN_TIMESLICE)Prioridade default 0 100 ms. (DEF_TIMESLICE)Prioridade máxima 20 800 ms. (MAX_TIMESLICE

Sendo o sistema operacional Linux um sistema preemptivo, quando um processo entrano estado TASK_RUNNING, o kernel verifica se sua prioridade é maior do que a prioridadedo processo que está atualmente executando. Se for, o escalonador é invocado para in-terromper a processo em execução e colocar para executar um novo processo que estiverpronto para executar. Além disso, quando um timeslice do processo alcançar zero, ele éinterrompido e o escalonador é novamente invocado para selecionar o novo processo.

Page 36: KERNEL DO LINUX

36 EDITORA - UFLA/FAEPE - Kernel do Linux

O algoritmo de escalonamento do kernel do Linux está definido em kernel/sched.c.A estrutura de dados básica no escalonador está na fila de execução, que é definida comostruct runqueue. Cada processo pronto para executar está exatamente em uma runqueue.A runqueue contém também informação de escalonamento por processador. Conseqüen-temente, é uma estrutura de escalonamento primária para cada processador.

Cada fila de execução contém dois vetores de prioridade, o vetor ativo e o expirado.Vetores de prioridade são definidos em kernel/sched.c como struct prio_array. Cada vetorde prioridade contém uma fila de processos prontos para executar por nível de prioridade.Essas filas contém lista de processos prontos para executar em cada nível de prioridade.Os vetores de prioridade também possuem um mapa de bits de prioridade usados paraeficientemente descobrir a tarefa executável de mais alta prioridade no sistema.

No Linux, a troca de contexto, ou seja, a troca de uma tarefa executável para outra,é realizada pela função context_switch() definida em kernel/sched.c. Quando um novoprocesso é selecionado para executar ocorre a troca do mapeamento da memória virtualdo processo anterior para o novo processo; o estado do processador do processo anteriorpara o processo o processo corrente, salvando e restaurando as informações da pilha eregistradores do processador.

O Linux possui uma família de chamadas de sistema para gerenciar os parâmetros doescalonador. As chamadas de sistema permitem a manipulação de prioridade do processo,política de escalonamento, entre outras. A Tabela 3.2 apresenta algumas chamadas desistema relacionadas ao escalonador e sua descrição.

Tabela 3.2: Principais chamadas de sistema relacionadas ao escalonadorChamada de sistema Descriçãonice() Seta um valor nice de um processosched_setscheduler() Seta a política de escalonamento de um processosched_getscheduler() Obtém uma política de escalonamento de um processosched_setparam() Seta uma prioridade de tempo real de um processosched_getparam() Obtém uma prioridade de tempo real de um processosched_get_priority_max() Obtém a prioridade de tempo real máximasched_get_priority_min() Obtém a prioridade de tempo real mínimasched_rr_get_interval() Obtém um valor de timeslice de um processo

As chamadas de sistema (denominadas syscalls no Linux) são acessadas via chama-das de funções, que necessitam de um ou mais argumentos (entradas) e pode resultar emum ou mais efeitos, por exemplo escrevendo em um arquivo ou copiando algum dado emum ponteiro. As chamadas de sistema também possuem um valor de retorno do tipo longque significa sucesso ou erro.

Page 37: KERNEL DO LINUX

Gerência de Processos 37

O kernel do Linux implementa as chamadas de sistema e a cadeia de eventos ne-cessários para executar uma chamada de sistema. Os eventos podem ser: execução deinstruções trap dentro do kernel, transmissão do número da chamada de sistema e os ar-gumentos necessários, execução da função de chamada de sistema correta e retorno aoespaço do usuário, em geral, com o valor de retorno da chamada de sistema.

3.7.1 Interrupções

Uma responsabilidade primária do kernel é gerenciar o hardware conectado à máquina.Por isso, o kernel precisa comunicar-se com os dispositivos individuais da máquina. Os pro-cessadores são bem mais rápidos que o restante do hardware. Portanto, não é ideal parao kernel fazer uma requisição e ficar esperando por uma resposta do hardware mais lento.O kernel deve ser livre para tratar outros trabalhos e realizar chamadas ao hardware so-mente depois que ele realmente completar seu trabalho. Uma solução para esse problemaé polling, onde o kernel, periodicamente pode verificar o estado do hardware no sistemae dar uma resposta. Isto implica em overhead, independentemente se o hardware estáativo ou pronto, pois o polling ocorre repetidamente em intervalos regulares. Uma soluçãomelhor é prover um mecanismo para o hardware sinalizar o kernel quando sua atenção fornecessária. Esta solução são as interrupções, que permitem ao hardware comunicar-secom o processador.

Por exemplo, quando o usuário digita alguma coisa, o hardware que gerencia (contro-lador) o teclado envia um sinal elétrico (interrupções) ao processador para alertar o sistemaoperacional para novamente disponibilizar o pressionamento de tecla. O processador re-cebe a interrupção e sinaliza o sistema operacional para permitir a resposta a um novodado. Dispositivos de hardware geram interrupções assincronamente em relação ao clockdo processador, pois elas podem ocorrer a qualquer momento. Conseqüentemente, o ker-nel pode ser interrompido a qualquer tempo para processar interrupções.

Uma interrupção é fisicamente produzida por sinais eletrônicos originados dos dispo-sitivos de hardware e dirigidos para o controlador de interrupções. Este controlador, emresposta, envia um sinal ao processador, que detecta este sinal e interrompe sua execuçãoatual para tratar a interrupção. O processador pode notificar o sistema operacional que umainterrupção ocorreu e o sistema operacional pode tratar a interrupção adequadamente.

Os valores de interrupção são chamados de interrupt request (IRQ). Por exemplo, emum PC, o IRQ 0 é a interrupção de tempo e o IRQ 1 é a interrupção do teclado. Umainterrupção específica está associada com um dispositivo específico e o kernel conheceesta informação.

A função no kernel que executa em resposta a uma interrupção específica é chamadaum tratador (handler) de interrupção ou rotina de serviço de interrupção (ISR - Interrupt Ser-vice Routine). Cada dispositivo que gera interrupção tem um tratador específico. O kernel

Page 38: KERNEL DO LINUX

38 EDITORA - UFLA/FAEPE - Kernel do Linux

do Linux implementa uma família de interfaces para manipular o estado das interrupções emuma máquina. Essas interfaces permitem ao usuário desabilitar o sistema de interrupçãopara o processador corrente ou mascarar uma interrupção para a máquina inteira. Essasrotinas são dependentes da arquitetura e podem ser encontradas em <asm/system.h> e<asm/irq.g>.

3.7.2 Sincronização no kernel

Os recursos compartilhados no kernel necessitam de proteção de acesso concorrenteporque se múltiplas threads de execução acessam e manipulam os dados ao mesmo tempo,as threads podem sobrescrever alterações realizadas por outras threads ou acessar dadosenquanto estes estiverem em um estado inconsistente. Acesso concorrente a dados com-partilhados é fonte de erros de execução. Por isso, é necessária a proteção apropriada derecursos compartilhados.

Trechos de código que acessam e manipulam dados compartilhados são denomina-dos seções críticas. Para prevenir acesso concorrente a regiões críticas, o programadordeve garantir que o código execute atomicamente, isto é, a execução do código completesem interrupção como se a região crítica inteira fosse uma instrução indivisível. Se for pos-sível duas threads de execução estarem ao mesmo tempo na região crítica ocorre erro.Quando isso ocorre é denominado condição de corrida , pois as threads correram paraacessarem a mesma região ao mesmo tempo. O ato de garantir que concorrência não se-gura seja prevenida e que condições de corrida não ocorram é denominada sincronização.

Uma solução para o problema da seção crítica deve satisfazer às três seguintes exi-gências:

Exclusão mútua: Se o processo Pi estiver executando em sua seção crítica, então nenhumoutro processo poderá estar executando em sua seção crítica.

Progresso: Se nenhum processo estiver executando em sua seção crítica e se algum pro-cesso quiser entrar em sua seção crítica, somente aqueles processos que não es-tiverem executando em sua seção remanescente poderão participar da decisão sobrequal processo será o próximo a entrar em sua seção crítica e esta seleção não poderáser adiada indefinidamente.

Espera limitada: Existe um limite parta o número de vezes em que outros processos po-dem obter permissão para entrar em suas seções críticas depois que um processotenha feito uma solicitação para entrar em sua seção crítica e antes que a solicitaçãoseja atendida.

Ao apresentar um algoritmo, somente as variáveis usadas para sincronização sãoapresentadas. A Figura 3.4 mostra um exemplo de solução para seção crítica com 2 pro-cessos. Nesta figura, o processo Pi, verifica se é sua vez de entrar na seção crítica (flag[j]

Page 39: KERNEL DO LINUX

Gerência de Processos 39

== TRUE) e se é a sua vez (turn == j). Se estas duas condições forem satisfeitas o pro-cesso entra na seção crítica, altera a variável compartilhada e libera a seção crítica (flag[i]= FALSE) para o outro processo.

Figura 3.4: Exemplo de seção crítica com dois processos.

Um método geral de sincronização é utilizar locks para proteger as regiões críticas.O lock mais comum no kernel do Linux é o spin lock. Um spin lock é um lock que

pode ser segurado por no máximo uma thread de execução. Se uma thread de execuçãotenta obter (acquire) um spin lock enquanto ele já está ocupado (por outra thread), a threadfica em um loop (espera ocupada) até que o lock torne-se disponível. Se o lock não estiverocupado, a thread pode imediatamente obter o lock e continuar.

Há máquinas que fornecem instruções especiais de hardware que nos permitem tantotestar e modificar o conteúdo de uma palavra, como permitir os conteúdos de duas palavrasatomicamente, ou seja, como uma unidade não interrompível. Estas instruções permitemresolver o problema da seção crítica. As instruções TestAndSet e Swap são exemplosdestas instruções.

Outra ferramenta de sincronização é o semáforo, que consiste em uma variável in-teira, que à parte a inicialização, é acessada somente através de duas operações atômicaspadrão: wait e signal.

Além dos semáforos, existem os monitores, que são caracterizados por um conjuntode operadores definidos pelo programador. A representação de um tipo monitor consisteem declarações de variáveis cujos valores definem o estado de uma instância deste tipo,bem como os corpos de procedimentos ou funções que implementam operações sobre otipo.

Deadlock é uma condição que envolve um ou mais threads de execução e um oumais recursos, tal que cada thread fica esperando por um dos recursos, mas todos os

Page 40: KERNEL DO LINUX

40 EDITORA - UFLA/FAEPE - Kernel do Linux

recursos já estão sendo utilizados. As threads estão todas esperando umas pelas outras,mas elas nunca irão fazer progresso para liberar os recursos que já estão prendendo. Então,nenhuma das threads pode continuar, caracterizando um deadlock.

Considere o exemplo onde uma thread tenta adquirir um lock que já está seguro poroutra thread, ela tem que esperar que o lock seja liberado. Mas ele nunca liberará o lock,porque ele está ocupado esperando pelo lock e o resultado é deadlock.

3.8 RESUMO

Este capítulo apresentou uma visão geral sobre o conceito de processo, como podeser criado um processo, os estados possíveis, threads de um processo, concorrência entreprocessos e problemas relacionados.

Page 41: KERNEL DO LINUX

4GERÊNCIA DE MEMÓRIA

Este capítulo aborda, inicialmente, gerência de memória de uma forma geral e, emseguida, explica como é realizada no Linux. Neste capítulo foram utilizadas basicamente asseguintes referências [Silberschatz (2004), Love (2005)].

4.1 INTRODUÇÃO

A memória de um sistema de computação consiste em um grande array de palavrasou bytes, cada um com seus próprios endereços. A CPU obtém instruções a partir damemória de acordo com o valor do contador de programa. A unidade de memória enxergaapenas uma cadeia de endereços de memória.

Um programa reside em um disco como um arquivo binário executável. Para que sejaexecutado, o programa deve ser carregado na memória e inserido em um processo. Depen-dendo do esquema de gerência de memória utilizado, o processo pode ser movimentadoentre o disco e a memória durante sua execução.

A memória principal deve acomodar tanto o sistema operacional como os vários pro-cessos dos usuários. Por isso, é necessário alocar porções diferentes da memória damaneira mais eficiente possível.

A gerência de memória é responsável por controlar quais partes da memória estão emuso e quais não estão, de forma a alocar memória a processos quando estes precisarem,liberar a memória que estava sendo ocupada por um processo que terminou e tratar doproblema do swapping entre a memória principal e o disco, quando a memória principal nãofor grande o suficiente para guardar todos os processos, entre outros aspectos.

4.2 ORGANIZAÇÃO DA MEMÓRIA

Em um sistema computacional tanto a CPU quanto o subsistema de entrada e saídainteragem com a memória. Dado que cada palavra ou byte armazenado na memória possuiseu próprio endereço, a interação é feita através de uma seqüência de leituras e escritasa endereços de memória específicos. Existem diferentes tipos de memória em um sis-

Page 42: KERNEL DO LINUX

42 EDITORA - UFLA/FAEPE - Kernel do Linux

tema computacional, com diferentes características relativas à capacidade de armazena-mento, custo e tempo de acesso. Estas memórias podem ser classificadas em memóriasecundária, memória principal e memória cache.

A memória secundária é capaz de armazenar uma grande quantidade de informação,possui custo por bit menor e o tempo de acesso é maior do que à memória principal e àcache.

A memória principal armazena relativamente menor quantidade de informação do quea memória secundária, possui custo por bit um pouco maior e tempo de acesso menor.

A memória cache possui menor capacidade de armazenamento de informação emrelação às memórias secundária e principal, possui custo por bit mais elevado e tempo deacesso bem menor.

A organização de memória é o modo como a memória principal é vista pelo sis-tema, levando em consideração quantos usuários utilizarão a memória, quanto espaço dememória será dado a cada um deles, como a memória será dividida, em quantas partições,se os processos deverão ser alocados de forma contígua ou poderão estar espalhados pelamemória principal, entre outras considerações.

Na organização da memória em partições fixas, a memória é dividida em númerofixo de partições ou regiões. A cada partição pode ser atribuído um processo para serexecutado. Quando existe uma partição livre, um processo é selecionado de uma fila ecarregado naquela partição. Quando ele termina sua execução, a partição torna-se livrepara um outro processo.

Em relação à fila de processos, esta pode ser única para cada partição ou únicapara as várias partições. Quando existe uma única fila para cada partição, a estratégia éclassificar os processos segundo sua quantidade de memória necessária e colocá-lo nafila correspondente. Quando existe uma única fila para todas as partições, o escalonadorde processos seleciona o próximo processo que será executado e em qual partição serácarregado.

Como existem diversos processos residentes na memória simultaneamente, devemhaver mecanismos para proteger tanto o sistema operacional quanto os processos. A pro-teção deve ocorrer tanto na relocação estática quanto na relocação dinâmica.

A proteção na relocação estática é realizada em tempo de montagem ou tempode carga. Para isto são utilizados os dois registradores de limite inferior e superior. Cadaendereço lógico gerado deve ser maior ou igual ao conteúdo armazenado no registrador delimite inferior e menor ou igual ao conteúdo armazenado no registrador de limite superior.Se for um acesso válido o endereço é então enviado à memória.

A proteção na relocação dinâmica é feita em tempo de execução. Nesta proteçãosão empregados um registrador base e um registrador limite. O registrador base contém ovalor do menor endereço físico. O registrador limite contém a faixa dos endereços lógicos.

Page 43: KERNEL DO LINUX

Gerência de memória 43

Com os registradores base e limite, cada endereço lógico deve ser menor que o conteúdoarmazenado no registrador limite. Esse endereço, se válido, é então calculado dinamica-mente adicionando-se o valor contido no registrador base. O endereço calculado é entãoenviado à memória.

Com a divisão da memória em partições fixas podemos ter ainda, o problema da frag-mentação da memória. Existe fragmentação interna quando há um processo sendo exe-cutado em uma partição e ele não a ocupa por completo. Já a fragmentação externa existequando uma partição não é utilizada, por ser pequena demais para qualquer processo queesteja esperando. Tanto a fragmentação interna quanto a externa são prejudiciais ao de-sempenho do sistema. Na organização de memória em partições fixas podem ocorrer osdois tipos de fragmentação.

O problema principal das partições fixas é a determinação do tamanho das partiçõesde modo que a fragmentação interna e externa seja mínima. A organização da memóriacom partições variáveis visa solucionar este problema permitindo que os tamanhos daspartições variem dinamicamente.

Para implementar a organização de memória com partições variáveis, o sistema ope-racional mantém uma tabela indicando quais partes da memória estão disponíveis e quaisestão ocupadas. A princípio toda a memória está disponível e é considerada como umgrande bloco de memória. Quando um processo chega e necessita de memória, é realizadauma busca por um espaço que seja grande o suficiente para armazená-lo. Se existe tal es-paço é atribuído ao processo somente a quantidade de memória necessária. O restantedo espaço, que pode haver, é deixado disponível para futuras requisições. Sempre que umprocesso termina sua execução ele libera seu espaço de memória. Esse espaço liberado écolocado de volta junto com os espaços de memória disponíveis. Neste ponto, procura-severificar se há áreas adjacentes que possam ser recombinadas de modo a formar espaçosde tamanhos maiores.

Em qualquer momento, há um conjunto de espaços livres, de tamanhos variados eespalhados pela memória. Além disso, existe um conjunto de processos esperando paraserem executados. Esta situação pode ser vista como uma aplicação geral do problemade alocação de memória dinâmica. O problema consiste em como satisfazer um pedido detamanho n de uma lista de espaços livres. As estratégias mais comuns para selecionar umespaço de memória são: first-fit, best-fit ou worst-fit.

A estratégia first-fit aloca o primeiro bloco que seja grande o suficiente. Não necessitade uma busca por toda a lista e é a estratégia mais rápida.

A estratégia best-fit aloca o menor bloco que seja grande o suficiente. Se a lista não forordenada por tamanho, é necessário varrer a lista inteira. Esta estratégia é a que provocamenor fragmentação da memória.

Page 44: KERNEL DO LINUX

44 EDITORA - UFLA/FAEPE - Kernel do Linux

A estratégia worst-fit aloca o maior bloco. Se a lista não for ordenada por tamanho, énecessário varrer a lista inteira. Esta estratégia visa deixar espaços de memória maioreslivres.

Estas estratégias levam à fragmentação externa. À medida que os processos sãocarregados e removidos da memória, o espaço livre de memória é quebrado em pequenospedaços. A fragmentação externa ocorre quando existe espaço de memória total suficientepara atender a solicitação, mas ele não é contíguo; a memória é fragmentada em um grandenúmero de pequenos blocos livres.

Uma solução para o problema de fragmentação externa é permitir que o espaço deendereçamento lógico de um processo seja não contíguo, possibilitando assim que sejaalocada memória física a um processo em qualquer lugar onde haja disponibilidade. Duastécnicas complementares atendem a esta solução: a paginação e a segmentação. Estastécnicas também podem ser combinadas.

4.3 MEMÓRIA VIRTUAL

A técnica de memória virtual foi criada para permitir a execução de vários processosque não necessariamente estejam armazenados por inteiro na memória principal. A imple-mentação de memória virtual é comumente realizada com paginação sob demanda ou comsegmentação sob demanda.

A técnica de swapping requer que o sistema possua um backing store ou memória deretaguarda (memória secundária, geralmente um disco rápido). A memória de retaguardadeve ser grande o suficiente para armazenar cópias de todos os programas de usuários efornecer acesso direto a esses programas. O swapping nada mais é do que a troca do con-teúdo de um determinado espaço de memória. Um processo é escolhido para ser retiradoda memória e levado a memória de retaguarda. Este processo deve estar completamenteocioso.

Na paginação o espaço de endereçamento físico de um processo não é contíguo. Amemória física é vista como se estivesse dividida em blocos de tamanho fixo, denominadosquadros (frames). A memória lógica é também dividida em blocos do mesmo tamanho,chamados páginas. Quando um processo está para ser executado, suas páginas são car-regadas em quaisquer quadros de memória disponíveis, a partir da memória de retaguarda(disco). A memória de retaguarda é dividida em blocos de tamanho fixo do mesmo tamanhodos quadros de memória.

O tamanho da página e o tamanho do quadro são definidos por hardware. Normal-mente, o tamanho da página é uma potência de 2, variando entre 512 bytes e 16MB porpágina, dependendo da arquitetura do computador. Se o tamanho do espaço de endereçoslógicos for 2m e o tamanho da página for 2n unidades de endereçamento, então os m−n bits

Page 45: KERNEL DO LINUX

Gerência de memória 45

de alta ordem de um endereço lógico designam o número de página e os n bits de baixaordem designam o deslocamento de página. Assim, o endereço lógico é o como mostradona Figura 4.1, onde p é um índice para a tabela de página e d é o deslocamento dentro dapágina.

Figura 4.1: Endereço lógico na paginação

Um aspecto importante da paginação é a clara separação entre a visão que o usuáriotem da memória e a memória física real. Os programas de usuário visualizam a memóriacomo um espaço contíguo único contendo apenas seu programa. A diferença entre avisão do usuário sobre a memória e a memória física real é reconciliada pelo hardwarede tradução de endereços. Os endereços lógicos são traduzidos para endereços físicos.Este mapeamento é controlado pelo sistema operacional. Por isso, ele mantém uma es-trutura de dados chamada tabela de quadros, que tem uma entrada para cada quadro depágina físico, indicando se o último quadro está livre ou alocado e, se ele estiver alocado, aqual página de qual processo ou processos estará alocado.

A segmentação é um esquema de gerência de memória que admite a visão damemória pelo usuário como uma coleção de segmentos (espaço de endereços lógicos).Cada segmento possui um nome e um tamanho. Os endereços especificam o nome dosegmento e o deslocamento dentro do segmento. O usuário especifica o endereço por umnome de segmento e um deslocamento.

Para simplificar, os segmentos são numerados e referenciados com um número desegmento, em vez de um nome de segmento. Assim, um endereço lógico consiste em:

<número-segmento, deslocamento>A tabela de segmentos é responsável por associar os endereços bidimensionais de-

finidos pelo usuário aos endereços físicos unidimensionais. Cada entrada na tabela desegmentos possui uma base de segmento e um limite de segmento. A base de segmentopossui o endereço físico inicial no qual o segmento reside na memória, enquanto o limitede segmento especifica a extensão do segmento.

A proteção na segmentação é associada a cada segmento. Cada entrada na tabela desegmentos contém informações para prevenir acesso ilegal de leitura/escrita ou de acessofora dos limites do segmento.

A paginação sob demanda é similar a um sistema paginado com swapping. Osprogramas residem na memória secundária. Quando se inicia a execução, os programas

Page 46: KERNEL DO LINUX

46 EDITORA - UFLA/FAEPE - Kernel do Linux

são trazidos para a memória principal. Porém, nunca uma página é trazida para a memóriase ela não for necessária. Com isso, diminui-se o tempo de troca e a quantidade de memóriafísica necessária.

Para controlar o armazenamento das páginas trazidas para a memória, a tabela depáginas possui um bit de válido/inválido. Esse bit é ativado quando a página está presentena memória. Se o programa tenta acessar uma página que ainda não foi trazida para amemória, então é gerada uma interrupção por falta de página (page fault). Neste caso, apágina será carregada na memória.

Se a memória estivesse completa, ou seja, não houvesse mais quadros livres paraserem alocados, seria necessário substituir alguma página. Para isso, seria necessário uti-lizar alguma estratégia de substituição de páginas. Existem várias técnicas de substituiçãode páginas: FIFO, OPT, LRU, Algoritmo da segunda chance, entre outras.

O algoritmo FIFO (First-In First-Out) consiste em associar a cada página o tempo emque ela foi trazida para a memória. Quando uma página tiver que ser substituída, a páginamais antiga na memória é escolhida. Se houver uma página bastante utilizada e há muitotempo que ela está na memória, esta página poderá ser retirada e causará novas faltas depáginas. Isso aumentará a taxa de falta de páginas e torna a execução do algoritmo maislenta.

O algoritmo OPT (Optimal Replacement) é o algoritmo que apresenta a menor taxade falta de páginas. Este algoritmo substitui a página que não será utilizada pelo maiorperíodo de tempo. Este algoritmo requer conhecimento sobre o futuro das referências àmemória.

O algoritmo LRU (Least Recently Used) é uma tentativa de aproximação ao algoritmoótimo. Ele utiliza o conhecimento da história passada recente das referências à memória,como uma aproximação do futuro. Este algoritmo associa a cada página seu último tempode uso. Quando houver necessidade de substituir uma página, é escolhida aquela quenão foi utilizada pelo maior período de tempo. Essa estratégia é conveniente ao princípioda localidade. Por esse princípio, quando uma página é referenciada, existe uma grandechance de que ela seja novamente referenciada em breve. O problema com este algoritmoencontra-se na forma de sua implementação. O sistema precisa manter uma lista daspáginas da memória, ordenada por último uso. Há duas formas de implementação:

• Contador: a cada entrada na tabela de páginas é associado um registrador detempo de uso. Sempre que uma referência à página é feita, o valor do tempo écarregado no registrador. A página substituída deve ser aquela com o menor valorde tempo

• Pilha: nessa abordagem é mantida uma estrutura de pilha dos números das pági-nas. Quando a página é referenciada, ela é removida da pilha e colocada no topo.Dessa forma, o fundo da pilha sempre contém a página usada menos recentemente

Page 47: KERNEL DO LINUX

Gerência de memória 47

As implementações do LRU necessitam de algum auxílio do hardware. A atualizaçãodos registradores ou da pilha deve ser feita a cada referência à memória. Se for utilizadauma interrupção a cada referência à memória, para permitir ao software atualizar as estru-turas de dados, o sistema se degrada.

Alguns sistemas oferecem uma ajuda de hardware sob a forma de um bit de referência.O bit de referência para uma página é ligado pelo hardware sempre que aquela página forreferenciada (leitura ou gravação de qualquer byte da página). Os bits de referência sãoassociados a cada entrada da tabela de páginas.

O sistema operacional, inicialmente, zera todos os bits. Quando um processo dousuário é executado, o bit associado a cada página referenciada é ligado pelo hardware.Assim, é possível determinar que páginas foram utilizadas e quais não o foram, pela examedos bits de referência.

O algoritmo da segunda chance é um algoritmo de substituição FIFO. Quando umapágina for selecionada seu bit de referência é inspecionado. Se o valor for 0, prossegue-secom a substituição da página. Se o bit for 1, dá-se àquela página uma segunda chance epassa-se a selecionar a próxima página FIFO. Quando uma página recebe uma segundachance, seu bit de referência é desligado e sua hora de chegada é reposicionada para ahora corrente. Assim, a página à qual é dada uma segunda chance não será substituídaaté que todas as outras páginas tenham sido substituídas (ou tenham recebido segundaschances). Se uma página for utilizada com freqüência suficiente para manter seu bit dereferência ligado, ela nunca será substituída.

A implementação deste algoritmo é como uma fila circular. Um ponteiro indica qual éa página a ser substituída primeiro. Quando um quadro for necessário, o ponteiro avançaráaté encontrar uma página com um bit de referência igual a 0. Conforme o ponteiro avança,desliga os bits de referência. Uma vez que uma página vítima seja encontrada, ela é subs-tituída e a nova página é inserida na fila circular, naquela posição.

4.4 THRASHING

Um processo está em thrashing, se ele passa mais tempo paginando do que execu-tando. Este estado causa sérios problemas de desempenho no sistema. Para entendermelhor como isso ocorre, considere que exista no sistema um número de páginas que es-tão em uso ativo. Como conseqüência, ocorre uma alta taxa de falta de páginas (pagefaults). Por exemplo, as páginas em uso ativo podem gerar referências às páginas quenão estejam presentes na memória, logo elas precisam ser carregadas. Por sua vez, estaspáginas recém carregadas geram novas referências e assim por diante. Esta alta atividadede paginação é denominada thrashing.

Page 48: KERNEL DO LINUX

48 EDITORA - UFLA/FAEPE - Kernel do Linux

4.5 GERÊNCIA DE MEMÓRIA NO KERNEL DO LINUX

A gerência de memória no Linux possui dois componentes. O primeiro deles trata daalocação e liberação da memória física: páginas, grupos de páginas e pequenos blocos dememória. O segundo componente manipula a memória virtual, que é a memória mapeadano espaço de endereçamento dos processos em execução.

4.5.1 Gerência da memória física

O kernel trata página física como unidade básica da gerência de memória. Emboraa menor unidade endereçável do processador seja uma palavra (ou mesmo um byte), aunidade de gerência de memória tipicamente trabalha com páginas.

O gerenciador principal da memória física no kernel do Linux é o alocador de pági-nas, que é responsável por alocar e liberar todas as páginas físicas e é capaz de alocarintervalos de páginas fisicamente contíguas mediante solicitação. O alocador utiliza umalgoritmo de agrupamento de parceiros (buddy-heap algorithm) para gerenciar páginasfísicas disponíveis. Este alocador agrupa duas a duas as unidades adjacentes de memóriaalocável. Sempre que duas regiões parceiras alocadas forem liberadas, elas serão combi-nadas para formar uma região maior. Essa região mais ampla tem uma parceira com a qualpode se combinar para formar uma região livre ainda maior. Alternativamente, se uma so-licitação por pouca memória não puder ser atendida através da alocação de uma pequenaregião livre existente, então uma região livre maior será subdividida em duas regiões par-ceiras para atender à solicitação. As regiões livres de memória de cada um dos tamanhospossíveis são registradas em listas encadeadas separadas. O menor tamanho alocável sobeste mecanismo é uma única página física.

Todas as alocações de memória no kernel do Linux ocorrem tanto de forma estática,por drivers que reservam uma área de memória contígua em tempo de inicialização dosistema, quanto de forma dinâmica, pelo alocador de páginas.

Os subsistemas de gerência de memória mais importantes do kernel são: o alocadorde tamanho variável kmalloc; e os dois caches de dados persistentes do kernel, o cache-buffer e o cache de páginas.

O serviço kmalloc aloca páginas sob demanda, mas depois as subdivide em pedaçosmenores. Este serviço é útil para solicitações de tamanhos arbitrários, onde o tamanhode uma solicitação não é conhecido com antecedência e pode corresponder a somentepoucos bytes e não a uma página inteira. Tanto as páginas quanto os alocadores kmallocnão sofrem interrupções. Uma função que queira alocar memória deve passar uma pri-oridade de solicitação para a função de alocação. As regiões de memória exigidas pelosistema kmalloc ficam permanentemente alocadas até que sejam explicitamente liberadas.

Page 49: KERNEL DO LINUX

Gerência de memória 49

O sistema kmalloc não pode realocar ou reclamar essas regiões em resposta à falta dememória.

O cache-buffer é o principal cache do kernel para dispositivos orientados a blocos,como os drives de disco, e é o mecanismo principal através do qual é realizada I/O paraestes dispositivos. Os sistemas de arquivos baseados em disco, nativos do Linux, e o sis-tema de arquivos em rede NFS utilizam cache de páginas. Este mecanismo aloca páginasinteiras de conteúdo de arquivos em caches e não é limitado aos dispositivos de blocos; eletambém pode alocar em caches os dados da rede. O sistema de memória virtual administrao conteúdo do espaço de endereços virtuais de cada processo.

O cache-buffer, o cache de páginas e o sistema de memória virtual interagem forte-mente uns com os outros. A leitura de uma página de dados no cache de páginas exige apassagem temporária pelo cache-buffer. As páginas no cache de páginas também podemser mapeadas no sistema de memória virtual se um processo tiver mapeado um arquivono seu espaço de endereços. Um contador de referência é mantido pelo kernel em cadapágina da memória física, de forma que as páginas compartilhadas por dois ou mais dessessubsistemas possam ser liberadas quando não estiverem mais em uso.

4.5.2 Memória virtual no Linux

O kernel do Linux gerencia sua própria memória e, também, o espaço de endereça-mento do usuário, mantendo o espaço de endereços visível para cada processo. As páginasde memória virtual são criadas sob demanda. O kernel gerencia a carga dessas páginas apartir do disco ou o seu retorno ao disco, conforme necessário. O gerenciador de memóriavirtual mantém duas visões separadas do espaço de endereços de um processo: como umconjunto de regiões separadas e como um conjunto de páginas.

A visão do espaço de endereços como um conjunto de regiões separadas é a visãológica que descreve as instruções que o sistema de memória virtual recebeu em relação aoformato do espaço de endereços. O espaço de endereço é composto de um conjunto deregiões que não podem ser superpostas, cada uma destas representando um subconjuntodo espaço de endereços contínuo e alinhado com as páginas. Cada região é descritainternamente por uma única estrutura vm_area_struct que define as propriedades da região,incluindo permissões de leitura, gravação e execução na região, bem como informaçãosobre quaisquer arquivos associados com a região.

A visão do espaço de endereços como um conjunto de páginas armazena as páginasem tabelas. As entradas da tabela de páginas determinam a exata localização corrente decada página da memória virtual, quer ela esteja em disco ou em memória física. A visãofísica é gerenciada por um conjunto de rotinas invocadas a partir dos manipuladores deinterrupções de software do kernel sempre que um processo tentar acessar uma páginaque naquele momento não esteja presente na tabela de páginas.

Page 50: KERNEL DO LINUX

50 EDITORA - UFLA/FAEPE - Kernel do Linux

Cada vm_area_struct na descrição do espaço de endereços contém um campo queaponta para uma tabela de funções que implementam as funções-chave de gerenciamentode páginas para cada região específica de memória virtual. Todas as solicitações para ler ougravar uma página indisponível são finalmente despachadas para o manipulador apropriadona tabela de funções da vm_area_struct, de modo que as rotinas centrais de gerenciamentode memória não tenham que conhecer os detalhes de gerenciamento de cada tipo possívelde região de memória.

O Linux implementa diferentes tipos de região de memória virtual. A memória de re-taguarda descreve de onde provêm as páginas para uma região. A maioria das regiõesde memória é reservada tanto por um arquivo como por nada. Uma região reservadapor nada é o tipo mais simples de memória virtual e representa a memória de demandazero. Quando um processo tenta ler uma página em tal região, é retornada uma página dememória preenchida com zeros.

Uma região reservada por arquivos atua como uma porta de visualização para umaseção do arquivo. Quando um processo tentar acessar uma página dentro da região, atabela de páginas será preenchida com o endereço de uma página dentro do cache de pági-nas do kernel, correspondente ao deslocamento apropriado do arquivo. A mesma páginade memória física é utilizada tanto pelo cache de páginas quanto pelas tabelas de páginasdo processo, de modo que quaisquer mudanças feitas no arquivo pelo sistema de arquivossejam imediatamente visíveis por quaisquer processos que tenham mapeado o arquivo noseu espaço de endereços.

Uma região de memória virtual é também definida por sua reação às gravações. Omapeamento de uma região no espaço de endereços do processo pode ser feito de formaprivada ou compartilhada. Se um processo gravar de forma privada em uma região ma-peada, então o paginador detectará que é necessária uma operação de copy-on-write paramanter as mudanças locais ao processo. Por outro lado, as gravações em uma região com-partilhada resultam na atualização do objeto que foi mapeado nesta região, de modo que amudança seja visível por qualquer outro processo que esteja mapeando aquele objeto.

A criação de um novo espaço de endereços virtual pelo kernel ocorre quando um pro-cesso realiza uma chamada de sistema fork() para criar um novo processo e quando umprocesso executa um novo programa com a chamada de sistema exec(). A criação de umnovo processo com fork() envolve a criação de uma cópia completa do espaço de en-dereços virtual do processo pai. O kernel copia os descritores vm_area_struct do processopai, criando depois um novo conjunto de tabelas de páginas para o filho. As tabelas depáginas do pai são copiadas diretamente nas tabelas de páginas do filho, incrementando-se o contador de referência de cada página. Após o fork(), pai e filho compartilham asmesmas páginas físicas de memória nos seus espaços de endereços.

Page 51: KERNEL DO LINUX

Gerência de memória 51

Quando um novo programa é executado com a chamada exec(), o processo recebeum novo espaço de endereços virtuais completamente vazio. É tarefa das rotinas car-regarem o programa para popular o espaço de endereços com regiões de memória virtual.

Um sistema de memória virtual possui a tarefa importante de definir como é a expulsãode páginas da memória física para o disco, quando a memória for necessária. O Linux utilizao mecanismo de paginação mais recente. Na paginação utilizada pelo Linux, o algoritmodecide que páginas gravar no disco e quando gravá-las. Em seguida, o mecanismo depaginação realiza a transferência e pagina os dados de volta na memória física quandoforem novamente necessários.

A política de expulsão de páginas do Linux utiliza um algoritmo similar ao algoritmoda segunda chance (descrito anteriormente). Porém, o Linux utiliza um relógio de passosmúltiplos e toda página possui uma idade que é ajustada a cada passo do relógio. A idade éuma medida da juventude da página ou de quanta atividade a página realizou recentemente.A cada passo, páginas acessadas com freqüência irão atingir valores maiores de idade,enquanto a idade das páginas pouco acessadas irá tendendo a zero. Esta quantificação daidade permite ao paginador selecionar páginas a serem expulsas da memória baseando-sena política da menos freqüentemente utilizada (LFU - Least Frequently Used).

O mecanismo de paginação suporta a paginação tanto para dispositivos de swap de-dicados quanto para partições e para arquivos normais. A memória física mantém um mapade bits (bitmap) relativos aos blocos utilizados. Os dispositivos de swap alocam os blocosde acordo com este mapa de bits. O alocador utiliza um algoritmo do tipo próximo-aptopara tentar gravar páginas em contínuas execuções de blocos de disco, com o objetivo demelhorar o desempenho. O alocador registra o fato de que uma página foi expulsa para odisco ligando o bit página-não-presente da entrada da tabela de páginas, permitindo que orestante da entrada seja preenchido com um índice identificador do local onde a página foigravada.

O kernel reserva para seu uso interno uma região constante do espaço de endereçosvirtual de todo processo. As entradas na tabela de páginas que mapeiam para essas pági-nas do kernel são marcadas como protegidas, de modo que as páginas não sejam visíveisou modificáveis quando o processador estiver operando em modo usuário. Esta área dememória virtual do kernel possui duas regiões. Uma área estática que contém referênciasda tabela de páginas para toda página física da memória disponível no sistema, de modoque ocorra uma simples tradução de endereços físicos para virtuais quando o código dokernel entrar em execução. O núcleo do kernel e todas as páginas alocadas pelo alocadornormal residem nesta região.

O restante da seção reservada do espaço de endereços do kernel não é destinadoa qualquer propósito específico. As entradas da tabela de páginas neste intervalo de en-dereços podem ser modificadas pelo kernel para apontar para quaisquer outras áreas de

Page 52: KERNEL DO LINUX

52 EDITORA - UFLA/FAEPE - Kernel do Linux

memória conforme necessário. O kernel fornece um par de recursos que permitem aosprocessos utilizarem esta memória virtual. A função vmalloc aloca um número arbitrário depáginas físicas de memória e as mapeia em uma única região da memória virtual do kernel,permitindo a alocação de grandes porções de memória contígua mesmo se não existiremsuficientes páginas físicas livres adjacentes para atender à solicitação. A função vremapmapeia uma seqüência de endereços virtuais que apontam para uma área de memóriautilizada por um driver de dispositivo para I/O mapeado em memória.

4.5.3 Mapeamento de programas na memória

No Linux, a execução de programas de usuário pelo kernel é disparada pela chamadade sistema exec(). Esta chamada ordena ao kernel que execute um novo programa dentrodo processo corrente, superpondo o contexto de execução corrente com o contexto inicialdo novo programa. O primeiro job deste serviço do sistema é verificar se o processo queinvocou o novo programa possui direitos de permissão para o arquivo que está sendo exe-cutado. Em seguida, o kernel invoca uma rotina de carga para começar a execução doprograma.

O carregador binário não carrega um arquivo binário na memória física. As páginas doarquivo binário são mapeadas em regiões de memória virtual. Quando o programa tentaracessar uma determinada pagina é que irá ocorrer um erro de página com o objetivo decarregar a página desejada na memória física.

A Figura 4.2 apresenta o formato típico das regiões de memória estabelecidas pelocarregador ELF. O kernel permanece um uma região reservada numa das extremidadesdo espaço de endereços. Os programas em modalidade de usuário não podem acessar amemória virtual do kernel. O restante da memória virtual é disponibilizada às aplicaçõesque podem utilizar as funções de mapeamento em memória do kernel para criar regiões quemapeiam uma parte do arquivo ou que ficam disponíveis para os dados das aplicações.

O carregador é responsável por estabelecer o mapeamento inicial em memória parapermitir o início da execução do programa. As regiões que precisam ser inicializadas são apilha e o texto do programa e suas regiões de dados.

A pilha é criada no topo da memória virtual de modalidade de usuário e cresce deforma descendente, em direção aos endereços de numeração mais baixa. A pilha incluicópias das variáveis de argumentos e do ambiente, fornecidas ao programa na chamadade sistema exec. As outras regiões são criadas perto da extremidade que compõe a baseda memória virtual. As seções do arquivo binário que contêm texto de programa ou dadosde somente leitura são mapeadas em seguida. Dados não inicializados são mapeadoscomo uma região privada de demanda zero.

Logo após estas regiões de tamanho fixo, fica uma região de tamanho variável que osprogramas podem expandir conforme necessário para manter dados alocados em tempo de

Page 53: KERNEL DO LINUX

Gerência de memória 53

Figura 4.2: Formato da memória para programas ELF [Silberschatz (2004)]

execução. Cada processo possui um ponteiro, o brk, que aponta para a extensão correntedesta região de dados e os processos podem estender ou contrair sua região brk com umaúnica chamada de sistema.

Após realizados todos os mapeamentos, o carregador inicializa o registrador contadorde programas do processo com o ponto de início registrado no cabeçalho do ELF e o pro-cesso pode ser submetido ao escalonador. Quando o programa inicia sua execução, todosos conteúdos do arquivo binário já estão no espaço de endereços virtuais do processo.

4.6 RESUMO

Este capítulo apresentou um visão geral sobre a gerência de memória nos sistemasoperacionais de uma forma geral e como o kernel do Linux implementa esta gerência.

Page 54: KERNEL DO LINUX

54 EDITORA - UFLA/FAEPE - Kernel do Linux

Page 55: KERNEL DO LINUX

5SISTEMA DE ARQUIVOS

O sistema de arquivos fornece o mecanismo para armazenamento e acesso a dadosde programas do sistema operacional e de todos os usuários do sistema de computação.É constituído de uma coleção de arquivos e uma estrutura de diretórios, que organiza efornece informações sobre todos os arquivos do sistema. Este capítulo aborda as car-acterísticas de um sistema de arquivos e como é implementado no Linux. As principaisreferências utilizadas foram [Silberschatz (2004), Love (2005)].

5.1 INTRODUÇÃO

5.2 CONCEITO DE ARQUIVO

Um arquivo (file) pode ser definido como uma unidade lógica de armazenamento deinformação, destinada a abstrair as propriedades físicas dos meios de armazenamento.Ou ainda, é uma coleção nomeada de informação relacionada, registrada em memóriasecundária.

Para conveniência dos usuários humanos, um arquivo é referenciado por seu nome,que é composto por uma cadeia de caracteres. Um arquivo tem propriedades tais comonome, identificador, tipo, tempo de criação, tamanho, nome do proprietário, proteção, hora,data, entre outras. Essas informações ficam armazenadas em um diretório, que é umatabela de símbolos que permite identificar tais informações.

Um arquivo tem uma estrutura definida de acordo com a sua utilização. Por exemplo,um arquivo texto é uma seqüência de caracteres organizada em linhas e possivelmente empáginas. Um arquivo fonte é uma seqüência de subrotinas e funções, cada uma das quaisorganizada como declarações seguidas de comandos executáveis. Um arquivo executável éuma sequência de seções de código que o carregador do sistema pode conduzir à memóriae executar.

Um arquivo é um tipo abstrato de dados e existem certas operações que podem serrealizadas sobre ele através de chamadas ao sistema operacional, que são descritas aseguir:

Page 56: KERNEL DO LINUX

56 EDITORA - UFLA/FAEPE - Kernel do Linux

Criação: é necessário encontrar um espaço para ele no dispositivo de armazenamento ecolocar a entrada do arquivo no diretório informando seu nome e sua localização nodispositivo

Escrita: é feita através de uma chamada ao sistema especificando o nome do arquivo e ainformação a ser escrita

Leitura: é realizada por uma chamada ao sistema especificando o nome do arquivo e alocalização onde o bloco lido será colocado

Reposicionamento dentro do arquivo: o diretório é percorrido em busca da entradaapropriada e a posição corrente do arquivo é posicionada para um determinado valor

Apagando um arquivo: o diretório é pesquisado e quando a entrada associada ao arquivoé encontrada, é liberado todo o espaço destinado ao arquivo e invalidada sua entradano diretório

Truncando um arquivo: o usuário pode desejar apagar o conteúdo de um arquivo, masconservar seus atributos. Esta função permite que todos os atributos permaneçam in-alterados, exceto o tamanho, reposicionando o arquivo com tamanho zero e liberandoseu espaço

5.3 MÉTODOS DE ACESSO A ARQUIVOS

Os acessos aos arquivos tanto podem ser seqüenciais quanto diretos. O acesso se-qüencial é o modo de acesso de arquivos, onde a informação é buscada em ordem, umaposição após a outra. Após um registro avança-se o ponteiro para o próximo registro noarquivo.

O grande volume de operações em um arquivo são leituras e escritas. Além disso, oarquivo pode ser reposicionado, e em alguns sistemas, um programa pode ser capaz dedeslocar n registros para frente ou para trás, por algum valor de n inteiro como mostra aFigura 5.1.

Figura 5.1: Arquivo de acesso seqüencial [Silberschatz (2004)]

No acesso direto o arquivo é visto como uma seqüência numerada de blocos. Umbloco é geralmente uma quantidade de informação de tamanho fixo, definida pelo sistema

Page 57: KERNEL DO LINUX

Sistema de arquivos 57

operacional. O acesso direto não tem restrições na ordem de acesso a cada bloco. As-sim, qualquer bloco pode ser lido ou escrito aleatoriamente. O método de acesso direto ébastante utilizado para acesso imediato a grandes informações.

Outros métodos de acesso podem ser construídos a partir do método de acesso direto.Estes métodos geralmente envolvem a construção de um índice para o arquivo. O índicecontém ponteiros para os vários blocos. Para encontrar um registro no arquivo, primeiroé necessário pesquisar o índice e então utilizar o ponteiro para fazer acesso ao arquivodiretamente e encontrar o registro desejado.

5.4 ESTRUTURA DE DIRETÓRIOS

A estrutura de diretório é um meio de organizar os muitos arquivos presentes no sis-tema. No diretório são armazenados dois tipos de informação. A primeira informação estárelacionada com o dispositivo físico (a localização do arquivo, seu tamanho e modo dealocação). A segunda está relacionada à organização lógica dos arquivos (nome, tipo, pro-prietário, códigos de proteção).

As operações que podem ser desenvolvidas sobre o diretório são:

• Busca de arquivo: operação para encontrar a entrada para um arquivo em parti-cular no sistema de diretórios

• Criar um arquivo: novos arquivos precisam ser criados e adicionados ao diretório

• Apagar um arquivo: quando um arquivo não é mais necessário, é preciso removê-lo do diretório

• Listar um diretório: listar os arquivos de um diretório e o conteúdo da entrada dodiretório para cada arquivo da lista

• Renomear um arquivo: como o nome de um arquivo representa o seu conteúdopara os seus usuários, ele deve ser alterável quando mudar o conteúdo ou utiliza-ção do arquivo. A renomeação de um arquivo pode também permitir a modificaçãode sua posição dentro da estrutura do diretório

• Percorrer o sistema de arquivos: acessar cada diretório e cada arquivo dentro deuma estrutura de diretórios

Muitas estruturas de diretório diferentes têm sido utilizadas. O diretório é essencial-mente uma tabela de símbolos. O sistema operacional utiliza o nome do arquivo simbólicopara achar o arquivo. Ao considerar uma estrutura de diretório em particular é importantelembrar as operações que podem ser realizadas no diretório.

Page 58: KERNEL DO LINUX

58 EDITORA - UFLA/FAEPE - Kernel do Linux

5.4.1 Diretório de um nível

Na estrutura de diretório de um nível todos os arquivos estão contidos no mesmo di-retório. É fácil de dar suporte e entender. Este tipo de diretório tem a limitação de que todosos arquivos devem ter nomes distintos. A Figura 5.2 ilustra esta estrutura. A desvantagemdesta estrutura é a possibilidade de confusão entre os nomes de arquivos de usuários dife-rentes. Todos os usuários compartilham o diretório.

Figura 5.2: Estrutura de diretório de um nível.

5.4.2 Diretório em dois níveis

Na estrutura de diretório de dois níveis, cada usuário tem seu próprio diretório dearquivo de usuário (user file directory - UFD). Cada diretório de usuário tem uma estruturasimilar. Quando um usuário entra no sistema, o diretório de arquivo mestre (master filedirectory - MFD) do sistema é pesquisado. O MFD é indexado pelo nome do usuário ouum número de contabilidade. Cada entrada aponta para o diretório de um usuário. Quandoum usuário se refere a um arquivo em particular, somente um diretório é pesquisado. Estaestrutura é ilustrada na Figura 5.3.

Figura 5.3: Estrutura de diretório em dois níveis.

Esta estrutura isola um usuário do outro. A desvantagem em dois níveis existe quandoum usuário quer utilizar arquivos de outros usuários. Alguns sistemas não permitem esteacesso. Se o acesso é permitido, ele é feito através do nome do usuário e do nome doarquivo, que definem o nome do caminho (path name). Todo arquivo no sistema tem umúnico path name.

Page 59: KERNEL DO LINUX

Sistema de arquivos 59

5.4.3 Diretório estruturado em árvore

Nos diretórios estruturados em árvore existe um diretório raiz da árvore. Os nós in-termediários da árvore são os diretórios dos usuários, que podem ainda criar seus própriossubdiretórios e organizar seus arquivos. A Figura 5.4 ilustra esta estrutura.

Figura 5.4: Estrutura de diretório em árvore.

Todo arquivo no sistema tem um único nome considerando seu path name, que é ocaminho da raiz através de todos os subdiretórios ao arquivo especificado. A seqüênciade diretórios pesquisada quando um arquivo é buscado é chamada de caminho de busca(search path). O path name pode ser apresentado de duas maneiras diferentes:

• Completo ou absoluto: define um caminho da raiz ao arquivo

• Relativo: define um caminho do diretório corrente ao arquivo

Os arquivos podem ser facilmente compartilhados. Por exemplo, um usuário pode criarum subdiretório contendo os arquivos que serão compartilhados com outros usuários. Umdestes usuários pode fazer o acesso aos arquivos compartilhados especificando o pathname dos arquivos.

A maneira de se apagar um diretório estruturado em árvore é uma política de decisãointeressante. Se um diretório está vazio ele pode ser apagado. Se ele não estiver vaziopodemos decidir entre duas abordagens. A primeira, é só apagar o diretório se estiver vazio.Isso implica em apagar todos os arquivos e subdiretórios contidos nele primeiro. A segundaabordagem, é assumir que quando é pedido para se apagar um diretório, deva-se apagartambém todos os seus arquivos e subdiretórios. A escolha da forma de implementação éuma decisão de projeto e ambas são utilizadas nos sistemas.

5.4.4 Diretório de grafos cíclicos

Um diretório de grafos cíclicos permite que subdiretórios e arquivos sejam comparti-lhados. A Figura 5.5 ilustra esta estrutura de diretório.

Page 60: KERNEL DO LINUX

60 EDITORA - UFLA/FAEPE - Kernel do Linux

Figura 5.5: Estrutura de diretório de grafos cíclicos

O compartilhamento de arquivos ou diretórios pode ser implementado de diversas for-mas. A maneira mais comum é criar uma entrada de diretório nova chamada hard link, queé um ponteiro para outro subdiretório ou arquivo. Uma outra implementação, é duplicar asinformações em ambos os diretórios. O problema nesta abordagem é manter consistêncianas informações se o arquivo for modificado.

Uma estrutura de diretório de grafo acíclico é mais flexível que uma estrutura emárvore simples, mas também é mais complexa. Os problemas como buscar um determinadoarquivo ou apagá-lo devem ser cuidadosamente considerados.

Um arquivo pode ter vários nomes completos. Dessa forma, nomes com caminhosdiferentes podem ser referenciar ao mesmo arquivo.

Como cada arquivo tem mais de uma trajetória de busca, a eliminação de um arquivopode ser feita de várias maneiras. Quando são utilizados hard links, apagar um arquivoimplica na retirada do hard link, não afetando o arquivo. Esse só é removido quando foremretirados todos os hard links.

5.4.5 Diretório como estrutura de grafo geral

Um diretório como estrutura de grafo geral permite que subdiretórios formem ciclos,resultando numa estrutura como a ilustrada na Figura 5.6.

5.5 SISTEMAS DE ARQUIVOS NO LINUX

O Linux utiliza o modelo de sistema de arquivos padrão do Unix. Os arquivos Unixpodem ser qualquer objeto capaz de manipular a entrada ou saída de uma cadeia de da-dos. O kernel do Linux manipula todos esses tipos de arquivos ocultando seus detalhesde implementação sob uma camada de software, o sistema de arquivos virtual (virtual filesystem - VFS).

Page 61: KERNEL DO LINUX

Sistema de arquivos 61

Figura 5.6: Estrutura de diretório de grafo geral.

O VFS possui um conjunto de definições que estabelecem o que pode ser um objeto-arquivo e uma camada de software para manipular esses objetos. Os tipos principais deobjetos são: objeto-inode, estruturas do objeto-arquivo e o objeto-sistema-de-arquivos.

O objeto-sistema-de-arquivos representa um conjunto conectado de arquivos que formauma hierarquia de diretórios auto-suficientes. A principal responsabilidade do objeto sistema-de-arquivos é dar acesso aos inodes.

O VFS identifica todo inode por um único par (número do inode - sistema de arquivos)e encontra o inode correspondente a um número particular de inode, solicitando ao objetosistema-de-arquivos que retorne o inode com aquele número.

Um objeto-inode representa o arquivo como um todo e o objeto-arquivo representaum ponto de acesso aos dados do arquivo. Um processo não pode acessar o conteúdo dedados de um inode sem primeiro obter um objeto-arquivo que aponte para o inode. Paraadministrar I/O de arquivos seqüenciais, o objeto-arquivo rastreia o local do arquivo de ondeo processo está lendo ou onde está gravando, a cada momento. É também registrado seo processo solicitou permissões de gravação quando o arquivo foi aberto e rastreada aatividade do processo se for necessário realizar leituras adiante adaptativas, extraindo osdados do arquivo para a memória antes que o processo os solicite, com objetivo de melhoraro desempenho.

Os objetos-arquivo pertencem a um único processo. Mesmo que um arquivo nãoesteja mais sendo usado por nenhum processo, seu objeto-inode pode ser alocado a umcache pelo VFS, para melhorar o desempenho se o arquivo for novamente utilizado em

Page 62: KERNEL DO LINUX

62 EDITORA - UFLA/FAEPE - Kernel do Linux

futuro próximo. Todos os dados do arquivo alocados a cache são encadeados em umalista do objeto-inode do arquivo. O inode também mantém informação padrão sobre cadaarquivo, como seu proprietário, tamanho e hora da última modificação.

5.6 O SISTEMA DE ARQUIVOS EXT2 DO LINUX

O Linux foi originalmente programado com um sistema de arquivos compatível com oMinix, para facilitar a troca de dados. Como o sistema de arquivos do Minix possuía algumasrestrições em nomes de arquivos (máximo 14 caracteres) e tamanho máximo do sistema dearquivos (até 64 MB), foi desenvolvido um sistema de arquivos estendido (extfs - extendedfile system). Para melhorar o desempenho e escalabilidade, bem como adicionar algumascaracterísticas que faltavam surgiu o segundo sistema de arquivos estendido (ext2fs - sec-ond extended file system).

O ext2fs1 utiliza um mecanismo semelhante para localização dos blocos de dados per-tencentes a um arquivo específico, armazenando ponteiros de blocos de dados em blocosindiretos com até três níveis, através do sistema de arquivos. Os arquivos de diretório sãoarmazenados no disco como arquivos normais, mas seus conteúdos são interpretados deforma diferente. Cada bloco de um arquivo de diretório consiste em uma lista encadeadade entradas, onde cada entrada contém o tamanho da entrada, o nome de um arquivo e onumero do inode ao qual a entrada se refere.

O sistema de arquivos do ext2fs é particionado em múltiplos grupos de blocos. Aoalocar um arquivo, o ext2fs deve primeiro selecionar o grupo de blocos para aquele arquivo.Para blocos de dados, ele tenta escolher o mesmo grupo de blocos no qual o inode do ar-quivo foi alocado. Para alocações de inodes, ele seleciona o mesmo grupo de blocos comodiretório pai do arquivo, para arquivos não pertencentes a diretórios. Arquivos em diretóriosnão são mantidos juntos, sendo dispersos através dos grupos de blocos disponíveis. Essaspolíticas são projetadas para guardar informação relacionada dentro do mesmo grupo deblocos, mas também para distribuir a carga do disco entre os seus grupos de blocos, nosentido de reduzir a fragmentação das áreas do disco.

O ext2fs busca tentar reduzir a fragmentação dentro de um grupo de blocos atravésda manutenção de alocações fisicamente contíguas. Ele mantém um bitmap de todos osblocos livres em um grupo de blocos. Ao alocar os primeiros blocos para um novo arquivo,ele começa buscando um bloco livre a partir do início do grupo de blocos; ao estender umarquivo, ele continua a busca a partir do último bloco alocado ao arquivo. A busca inicial é deum byte completamente livre no bitmap; se não o encontrar, é procurado qualquer bit livre.A busca por bytes livres objetiva alocar onde for possível o espaço do disco em pedaços depelo menos oito blocos. Quando um bloco livre é identificado, a busca retroage até encontrar

1http://en.wikipedia.org/wiki/Ext2

Page 63: KERNEL DO LINUX

Sistema de arquivos 63

um bloco alocado. Quando um byte livre é encontrado no bitmap, esta busca retroativaevita que o ext2fs deixe um buraco entre o último bloco alocado no byte diferente de zeroanterior e o byte igual a zero encontrado. Uma vez que o próximo bloco a ser alocadotenha sido encontrado, seja pela busca do bit, seja pela do byte o ext2fs avança a alocaçãoaté oito blocos e pré-aloca esses blocos extras ao arquivo. Esta pré-alocação ajuda areduzir a fragmentação durante as gravações intercaladas para arquivos separados e reduzo custo da CPU devido à alocação de discos, já que múltiplos blocos são simultaneamentealocados. Os blocos pré-alocados são retornados ao bitmap de espaço livre quando oarquivo é fechado.

A Figura 5.7 ilustra as políticas de alocação de blocos do ext2fs. Cada linha representauma seqüência de bits ligados e desligados em um bitmap de alocação, indicando blocosutilizados e blocos livres no disco. Na alocação de blocos livres espalhados, se foremencontrados blocos livres suficientemente próximos ao início da busca, estes deverão seralocados sem levar em conta o nível de fragmentação em que possam estar. A fragmen-tação é parcialmente compensada pelo fato de que os blocos estarão juntos e poderãoprovavelmente ser lidos sem a necessidade de quaisquer buscas no disco. Além disso, aalocação de todos eles a um arquivo é melhor a longo prazo do que a alocação de blocosisolados para arquivos separados, uma vez que grandes áreas livres se tornam escassasno disco. No segundo caso, não é encontrado de imediato um bloco livre próximo, e assimé necessário avançar na busca por um byte completamente livre no bitmap. Se esse byteé alocado como um todo, acaba-se criando, antes dele, uma área fragmentada de espaçoslivres. Assim, antes de realizar a alocação, é melhor reservá-la de modo que ela flua coma alocação precedente e realizar então uma alocação para diante de como a satisfazer aalocação default de oito blocos.

Figura 5.7: Políticas de alocação de blocos do ext2fs [Love (2005)]

Page 64: KERNEL DO LINUX

64 EDITORA - UFLA/FAEPE - Kernel do Linux

O ext32 (third extended filesystem) é uma extensão do ext2, do qual difere por apre-sentar melhorias e ser um sistema de arquivos journalled [?].

O ext43 (fourth extended filesystem) ainda está em desenvolvimento e é um sistemade arquivos de 64 bits. Ele está sendo integrado ao kernel 2.6.19 do Linux [Vivier (2007)].

5.7 O SISTEMA DE ARQUIVOS PROC DO LINUX

O sistema de arquivos de processos do Linux, denominado sistema de arquivos proc, éum exemplo de um sistema de arquivos cujos conteúdos não estão realmente armazenadosem qualquer lugar, mas são processados sob demanda de acordo com as solicitações deI/O dos arquivos do usuário.

O sistema de arquivos proc foi introduzido pelo Unix SVR4, como uma interface efi-ciente para suporte à depuração de processos do kernel. Cada subdiretório do sistemade arquivos não correspondia a um diretório em qualquer disco, mas sim a um processoativo no sistema corrente. Uma listagem do sistema de arquivos revela um diretório porprocesso, com o nome do diretório sendo a representação decimal ASCII do identificadorúnico do processo (PID - process ID).

O Linux adicionou diretórios extras e arquivos texto sob o diretório raiz deste sistemade arquivos. Esses novos arquivos e diretórios correspondem a estatísticas do kernel edrivers associados carregados. O sistema de arquivos proc fornece um meio para queos programas acessem esta informação como arquivos de texto plenos, que podem serprocessador por intermédio de ferramentas poderosas oferecidas pelo ambiente de usuáriopadrão do Unix.

O sistema de arquivos proc deve implementar uma estrutura de diretório e o con-teúdo dos arquivos dentro dela. Um sistema de arquivos Unix é definido como um conjuntode arquivos e inodes de diretórios identificados por seus números de inode, o sistema dearquivos proc deve definir um número de inode persistente e único para cada diretório earquivos associados. Uma vez que exista tal mapeamento, ele pode usar este número deinode para identificar que operação será necessária quando um usuário tentar ler a partirde um inode de arquivo em particular, ou realizar uma pesquisa em um determinado inodede diretório. Quando os dados forem lidos a partir de um desses arquivos, o sistema dearquivos proc irá coletar a informação apropriada, formatá-la em forma textual e colocá-lano buffer de leitura do processo solicitante.

O mapeamento do número do inode para o tipo de informação subdivide o númerodo inode em dois campos. No Linux, um PID tem 16 bits, enquanto um número de inodetem 32 bits. Os 16 bits mais altos do número do inode são representados como um PID,

2http://en.wikipedia.org/wiki/Ext33http://en.wikipedia.org/wiki/Ext4

Page 65: KERNEL DO LINUX

Sistema de arquivos 65

e os bits restantes definem o tipo de informação que está sendo solicitada sobre aqueleprocesso.

Um PID igual a zero não é válido, de modo que um campo de PID zero no número doinode significa que este inode contém informação global. Existem arquivos globais separa-dos no proc para relatar informação como a versão do kernel, a memória livre, estatísticasde desempenho e drivers em execução corrente.

O kernel pode alocar novos mapeamentos de inodes do proc dinamicamente, man-tendo um bitmap de números de inodes alocados. Ele também mantém uma estrutura dedados em árvore de entradas globais registradas do sistema de arquivos proc. Cada en-trada contém o número do inode do arquivo, o nome do arquivo, as permissões de acessoe funções especiais utilizadas para gerar o conteúdo dos arquivos. Os drivers podem in-cluir e excluir entradas nesta árvore a qualquer momento, e uma seção especial da árvore -que aparece sob o diretório /proc/sys. Os arquivos sob esta árvore são trabalhados por umconjunto de manipuladores comuns que permitem tanto a leitura como a gravação dessasvariáveis, de modo que o administrador do sistema possa ajustar o valor dos parâmetrosdo kernel simplesmente gravando os novos valores desejados em decimal ASCII para oarquivo apropriado.

5.8 RESUMO

Este capítulo apresentou uma visão geral sobre gerenciamento de arquivos e como érealizado no Linux.

Page 66: KERNEL DO LINUX

66 EDITORA - UFLA/FAEPE - Kernel do Linux

Page 67: KERNEL DO LINUX

6GERÊNCIA DE ENTRADA E SAÍDA

O papel de um sistema operacional em relação a I/O (entrada e saída) do computadoré gerenciar e controlar as operações e os dispositivos de I/O. Este capítulo apresenta umavisão geral sobre os fundamentos do hardware de I/O, os serviços de I/O fornecidos pelosistema operacional e como o Linux implementa estes serviços. As principais referênciasutilizadas foram [Silberschatz (2004), Love (2005)].

6.1 INTRODUÇÃO

O kernel oferece diversos serviços relacionados a I/O, tais como escalonamento, alo-cação em buffers, alocação em caches, spooling, reserva de dispositivos e manipulação deerros, que são descritos a seguir.

6.1.1 Escalonamento

Os desenvolvedores de sistemas operacionais implementam o escalonamento man-tendo uma fila de solicitações para cada dispositivo. Quando uma aplicação emite umachamada de sistema para I/O bloqueada, a solicitação é colocada na fila do dispositivo deinteresse. O escalonador reordena a fila para melhorar o tempo médio de resposta paraas aplicações e a eficiência global do sistema. Existem vários algoritmos para realizar oescalonamento de disco: FCFS, SSTF, SCAN, C-SCAN, LOOK.

O algoritmo FCFS (First-Come, First-Served) é um algoritmo de atendimento na ordemde chegada das solicitações. É um algoritmo justo, mas geralmente não oferece o serviçomais rápido.

O algoritmo SSTF (Shortest-Seek-Time-First) ou algoritmo de prioridade para o menortempo de busca atende a todas as solicitações perto da posição corrente do cabeçote antesde movê-lo para muito longe com o intuito de atender a outras solicitações.

No algoritmo SCAN o braço do disco começa em uma extremidade do disco e semove em direção à outra extremidade, atendendo às solicitações à medida que passa peloscilindros até atingir a outra extremidade do disco. Chegando aí, o sentido do movimento do

Page 68: KERNEL DO LINUX

68 EDITORA - UFLA/FAEPE - Kernel do Linux

cabeçote é invertido e o atendimento continua. O cabeçote varre o disco continuamente deuma extremidade a outra.

O algoritmo C-SCAN (SCAN circular) é uma variação do SCAN e foi projetado parafornecer um tempo de espera mais uniforme. Este algoritmo trata os cilindros como umalista circular que, ao chegar ao cilindro final, volta ao primeiro. O C-SCAN move o cabeçotede uma extremidade a outra do disco atendendo solicitações, mas ao retornar volta ao iníciodo disco sem atender solicitações pelo caminho.

Na prática, a implementação do SCAN e do C-SCAN não ocorre como descrito. Omais comum é que o braço só vá até a última solicitação em cada sentido. Depois elemuda imediatamente de sentido, sem ir até o final do disco. Essas versões do SCAN e doC-SCAN são denominadas de escalonamento LOOK e C-LOOK, pois eles procuram poruma solicitação antes de continuar a se mover em um dado sentido.

6.1.2 Alocação em buffers

Um buffer é uma área de memória que armazena dados enquanto eles são transferi-dos entre dois dispositivos ou entre um dispositivo e uma aplicação. A utilização de buffersocorre para fornecer uma interligação veloz entre o produtor e o consumidor de uma cadeiade dados; adaptação entre dispositivos de tamanhos diferentes para transferir dados e su-portar semântica de cópias para o I/O da aplicação.

Como exemplo de utilização para semântica de cópias, pode-se considerar que umaaplicação possua um buffer de dados a serem gravados em disco. Para isso, a aplicaçãoinvocará uma chamada de sistema write() fornecendo um ponteiro para o buffer e um inteirocorrespondente ao número de bytes a serem gravados. A semântica de cópias garante quea versão dos dados gravada em disco é a versão vigente no momento da chamada desistema da aplicação, independente de quaisquer mudanças subseqüentes realizadas nobuffer da aplicação.

6.1.3 Alocação em caches

Cache é uma região de memória rápida que mantém cópias de dados. A diferençaentre cache e buffer é que o buffer pode manter uma única cópia existente de um item dedado, enquanto um cache apenas mantém uma cópia em memória mais rápida de um itemque resida em qualquer local.

Os buffers são utilizados como cache para melhorar a eficiência de I/O no caso dearquivos compartilhados entre aplicações ou que estão sendo gravados e relidos rapida-mente. Quando o kernel recebe uma solicitação de I/O para um arquivo, acessa em primeirolugar o cache-buffer para ver se aquela região do arquivo já está disponível na memóriaprincipal. Em caso afirmativo, será evitado um I/O de disco físico.

Page 69: KERNEL DO LINUX

Gerência de Entrada e Saída 69

6.1.4 Spooling e reserva de dispositivos

Spool é um buffer que mantém saídas para um dispositivo, tal como impressora, quenão pode aceitar fluxos de dados intercalados. A saída para impressora, de cada aplicação,é interceptada pelo sistema operacional que a armazena em um spool para um arquivo dedisco separado. Quando uma aplicação termina de imprimir, o sistema de criação do spoolenfileira o arquivo spool correspondente para saída na impressora. O sistema de criação dospool copia arquivos spool enfileirados, um de cada vez. Em alguns sistemas operacionais,a alocação em spool é gerenciado por um processo de sistema daemon e em outros émanipulado por thread no kernel. Em ambos os casos, o sistema oferece uma interface decontrole que habilita os usuários e administradores do sistema a exibir a fila, para que osjobs indesejados sejam removidos antes de serem impressos.

6.1.5 Manipulação de erros

Dispositivos e transferências de I/O podem falhar de diversas maneiras, por exemplo,por uma sobrecarga na rede (razão transitória) ou por um controlador de disco defeituoso(razão permanente).

O sistema operacional Unix possui uma variável inteira adicional denominada errnoque é utilizada para retornar um código de erro quando uma chamada de sistema para I/Ofalha. O código de erro indica a natureza geral da falha. Por exemplo, argumento fora dointervalo, ponteiro corrompido ou arquivo não aberto.

6.2 ENTRADA E SAÍDA NO LINUX

O kernel do Linux utiliza várias estruturas similares para rastrear as conexões de rede,comunicações de dispositivos de caracteres e outras atividades de I/O. Assim, todos osdispositivos são subdivididos em dispositivos de blocos, dispositivos de caracteres e dispo-sitivos de rede.

Os dispositivos de blocos incluem todos os dispositivos que permitem acesso alea-tório a blocos de dados de tamanho fixo completamente independentes, inclusive discosrígidos, discos flexíveis e CD-ROMs. São utilizados para armazenar sistemas de arquivos.O acesso direto a um dispositivo de blocos é possível, assim programas podem criar ereparar o sistema de arquivos contido no dispositivo.

Os dispositivos de caracteres incluem a maioria dos demais dispositivos, com ex-ceção dos dispositivos de rede.

Os dispositivos de rede são utilizados de maneira diferente dos demais. Os usuáriosnão podem transferir dados diretamente para os dispositivos de rede. Eles podem se co-municar abrindo uma conexão para o subsistema de conexão de rede do kernel.

A Figura 6.1 apresenta a estrutura de blocos do driver de dispositivo.

Page 70: KERNEL DO LINUX

70 EDITORA - UFLA/FAEPE - Kernel do Linux

Figura 6.1: Estrutura de blocos do driver de dispositivo

6.2.1 Dispositivos de blocos

Os dispositivos de blocos representam a interface principal para todos os dispositivosde disco de um sistema. Por isso, possui dois componentes para fornecer funcionalidadeque garanta o acesso mais rápido possível ao disco: o cache-buffer de blocos e o gerenci-ador de solicitações.

O cache-buffer de blocos atua como uma cadeia de buffers para I/O ativo e como umcache para I/O que se completou. Os buffers são formados por um conjunto de páginasdinamicamente dimensionadas, alocadas a partir da cadeia de memória principal do kernel.Cada página é subdividida em buffers de mesmo tamanho. Um conjunto de descritoresde buffers (cabeças de buffers) inclui um descritor para cada buffer do cache. As cabeçasde buffers contêm toda a informação que o kernel mantém sobre os buffers, como, porexemplo, a identidade do buffer. Existem listas separadas para buffers vazios, ocupados etrancados, e livres. Cada buffer não incluído na lista de buffers livres é indexado por umafunção hash aplicada sobre seu dispositivo e número de bloco, e é encadeado em uma listacorrespondente de buscas por hash.

O gerenciador de solicitações é a camada de software que gerencia a leitura e gravaçãodo conteúdo do buffer para um driver de dispositivo de blocos a partir dele. O sistemade solicitações funciona com base numa função que realiza leituras e gravações de baixonível associadas aos dispositivos de blocos. Esta função toma uma lista de descritores debuffers buffer_head e um flag de leitura-gravação como seu argumento, posicionando o I/Oem curso para todos esses buffers, sem esperar que I/O complete.

Page 71: KERNEL DO LINUX

Gerência de Entrada e Saída 71

Para cada driver de dispositivo de blocos é mantida uma lista separada de solicitações,que são incluídas em um escalonamento de acordo com um algoritmo unidirecional (C-SCAN) que explora a ordem na qual as solicitações são inseridas nas listas por dispositivoe delas removidas.

Quando novas solicitações de I/O são realizadas, o gerenciador de solicitações tentaintercalar as solicitações nas listas por dispositivo.

6.2.2 Dispositivos de caracteres

Quaisquer drivers de dispositivos de caracteres registrados para o kernel do Linux de-vem registrar um conjunto de funções que implementem as operações de I/O em arquivosque o driver possa manipular. O kernel simplesmente passa para o dispositivo a solicitaçãode leitura ou gravação de um arquivo relacionada a um dispositivo de caracteres. A exceçãoé o subconjunto especial de drivers de dispositivo de caracteres que implementam disposi-tivos de terminais. Neste caso, o kernel mantém uma interface padrão para esses driverspor meio de um conjunto de estruturas tty_struct. Essas estruturas fornecem alocação embuffers e controle de fluxo das cadeias de dados provenientes do dispositivo terminal ealimenta esses dados em um orientador de rota.

O orientador de rota é um interpretador para a informação do dispositivo terminal. Oorientador de rota mais comum é o tty, que adere a cadeia de dados do terminal às cadeiaspadrões de entrada e saída dos processo em execução de um usuário, permitindo queesses processos se comuniquem diretamente com o terminal do usuário.

6.2.3 Estrutura de rede

A conexão em rede do kernel do Linux é implementada por três camadas de software:a interface de socket, drivers de protocolos e drivers de dispositivo de rede. As aplicaçõesde usuário realizam todas as solicitações de conexão à rede através da interface de socket.

A camada de protocolo pode regravar pacotes, criar novos pacotes subdividir ou re-montar pacotes em fragmentos ou simplesmente descartar dados que estiverem chegando.A camada de protocolo decide para qual socket ou dispositivo enviar o pacote. O conjuntomais importante de protocolos do Linux é o de protocolos de Internet (IP- Internet Protocol)

6.3 RESUMO

Este capítulo apresentou conceitos relacionados a gerenciamento de I/O e como oLinux implementa este gerenciamento.

Com este último capítulo, encerra-se a apostila de Kernel do Linux, onde foi vista umavisão geral sobre os conceitos relacionados a sistemas operacionais, gerência de proces-sos, gerência de memória, o sistema de arquivos e gerência de entrada e saída.

Page 72: KERNEL DO LINUX

72 EDITORA - UFLA/FAEPE - Kernel do Linux

Page 73: KERNEL DO LINUX

7COMPARAÇÃO ENTRE SOLARIS, LINUX E

FREEBSD

Max Bruning [Bruning 2005] comparou o kernel do Solaris 10, com o kernel do Linux2.6 e o do FreeBSD 5.3. Os três subsistemas examinados foram: escalonamento, gerên-cia de memória e arquitetura de sistema de arquivos, pois existem em qualquer sistemaoperacional.

Cada um dos sistemas operacionais comparados suportam escalonamento de threadsde tempo compartilhado, paginação por demanda com um algoritmo de substituição depágina não recentemente utilizada e uma camada de sistema de arquivo virtual para permitira implementação de diferentes arquiteturas de sistemas de arquivos.

Linux utiliza os conceitos de alocador de memória slab do Solaris. Muito da terminolo-gia encontrada no fonte do FreeBSD está também presente no Solaris.

7.1 ESCALONAMENTO E ESCALONADORES

A unidade básica de escalonamento no Solaris é a kthread_t; no FreeBSD, a thread;e no Linux, a task_struct. Solaris representa cada processo como um proc_t e cada threaddentro do processo tem uma kthread_t. Linux representa processos (e threads) pelasestruturas task_struct. Um processo com uma única thread, em Linux, tem uma únicatask_struct. Um processo com uma única thread, no Solaris tem um proc_t, uma únicakthread_t e uma klwp_t. O klwp_t provê uma área salva para troca de threads entre os mo-dos usuário e kernel. Um processo com única thread em FreeBSD tem uma proc struct, umathread struct e uma ksegrp struct. O ksegrp é um grupo de entidades de escalonamento dokernel. Resumidamente, todos os 3 sistemas operacionais escalonam threads, onde umathread é uma kthread_t em Solaris, uma struct thread em FreeBSD e uma task_struct emLinux.

As decisões de escalonamento são baseadas em prioridade. Linux e FreeBSD pos-suem o menor valor de prioridade como o mais baixo. Isto é, um valor próximo a 0 repre-sentam uma prioridade mais alta. Em Solaris, o valor maior representa a prioridade maisalta.

Page 74: KERNEL DO LINUX

74 EDITORA - UFLA/FAEPE - Kernel do Linux

Solaris, FreeBSD e Linux usam uma runqueue por CPU. FreeBSD e Linux usam umafila active e uma fila expired. Threads são escalonadas em prioridade de fila active. Umathread move de uma fila active para a fila expired quando ela usa todo seu time slice.Quando a fila active está vazia, o kernel troca as filas active e expired. FreeBSD possuiuma terceira fila para threads idle. Threads entram nesta fila quando as outras duas filasestão vazias. Solaris usa um dispatch queue por CPU. Se uma thread usa seu time slice,o kernel dá a ela uma nova prioridade e a retorna para a dispatch queue. FreeBSD usauma lista por prioridade para as 4 prioridades nas runqueues e Solaris e Linux usam listasseparadas para cada prioridade.

Uma grande diferença entre Solaris e os outros dois sistemas operacionais está na ca-pacidade de suportar múltiplas classes de escalonamento no sistema ao mesmo tempo. Ostrês sistemas operacionais suportam Posix SCHED_FIFO, SCHED_RR, e SCHED_OTHER(ou SCHED_NORMAL). SCHED_FIFO e SCHED_RR tipicamente resultam em threads detempo real. Solaris tem suporte para uma classe de prioridade fixa, uma classe de sistemapara sistema de threads (tal como threads page-out), uma classe interativa usada parathreads executnam em um ambiente de janelas sob controle de servidor X e um escalonadorde recursos justo em suporte ao gerenciamento de recursos. O escalonador no FreeBSD éescolhido em tempo de compilação e no Linux o escalonador depende da versão do Linux.

7.2 GERÊNCIA DE MEMÓRIA E PAGINAÇÃO

No Solaris, todo processo tem um espaço de endereçamento composto de divisõesde seções lógicas chamadas segmentos. Os segmentos do espaço de endereçamento doprocesso são visíveis via pmap(1). Solaris divide o código de gerência de memória e asestruturas de dados em partes independentes da plataforma e específicas da plataforma.A gerência de memória de porções específicas da plataforma está na camada HAT (Hard-ware Address Translation). FreeBSD descreve seu espaço de endereçamento de processopor um vmspace, dividido em seções lógicas chamadas regiões. Porções dependentes dohardware estão no módulo pmap (physical map) e rotinas vmap tratam porções indepen-dentes do hardware e estruturas de dados. Linux usa um descritor de memória para dividiro espaço de endereçamento de processo em seções lógicas chamadas áreas de memóriapara descrever o espaço de endereçamento de processo. Linux também tem um comandopmap para examinar o espaço de endereçamento de processo.

Linux divide camadas dependentes da máquina de camadas dependentes da máquinaem um nível muito mais alto no software. Em Solaris e FreeBSD, muito do código de trata-mento, por exemplo, tratamento de falha de página é independente da máquina. No Linux,o código para tratar falha de página é muito mais dependente da máquina no início do trata-mento de falha. Uma conseqüência disso é que o Linux pode tratar o código de paginação

Page 75: KERNEL DO LINUX

Comparação entre Solaris, Linux e FreeBSD 75

mais rapidamente pois há menos abstração de dados no código. O custo disso é que umamudança no hardware ou modelo requer mais mudanças no código. Solaris e FreeBSDisolam tais mudanças nas camadas HAT e pmap.

7.2.1 Paginação

Todos os três sistemas operacionais usam uma variação do algoritmo LRU para subs-tituição de página. Todos os três possuem um daemon de processo/thread para fazer asubstituição de página. No FreeBSD, o daemon vm_pageout acorda periodicamente equando a memória livre torna-se baixa. Quando a memória livre torna-se abaixo de al-gum limite, vm_pageout executa uma rotina (vm_pageou_scan) para buscar memória paratentar liberar algumas páginas. A rotina vm_pageout_scan pode necessitar escrever pági-nas modificadas assincronamente para o disco antes de liberá-las. Solaris também tem umdaemon pageout que executa periodicamente e em resposta a situações de baixa memórialivre. Limites de paginação em Solaris são automaticamente calibrados no startup do sis-tema tal que o daemon não use excessivamente a CPU ou sobrecarregue o disco comrequisições page-out. O daemon FreeBSD usa valores tais que, para a maior parte, sãoajustados para determinar limites de paginação. Linux também usa um algoritmo LRU queé dinamicamente ajustado. No Linux, pode haver múltiplos daemons kswapd. Os 3 sistemasutilizam a política working set global.

FreeBSD tem diversas listas de página para manter trilha de páginas recentementeusadas. As listas são de páginas ativas (active), inativas (inactive), em cache (cached)e livres (free). Páginas freqüentemente usadas tendem a ficar na lista ativa. Páginas dedados de um processo que sai pode ser imediatamente colocada na lista de livres.

Linux também utiliza diferentes listas de páginas para facilitar um algoritmo estilo LRU.Linux divide memória física em 3 zonas: uma para páginas DMA, uma para páginas normaise uma para memória alocada dinamicamente. Páginas movem-se entre listas hot, cold efree. Listas freqüentemente acessadas ficarão na lista hot. Páginas livres estarão nas listascold ou free.

Solaris usa lista de páginas free, hash e vnode para manter sua variação de um al-goritmo LRU. Solaris escaneia todas as páginas usando um algorimo two-handed clock. Ofront hand age sobre a página limpando os bits de referência para a página. Se nenhumprocesso tiver referenciado a página desde que o front hand visitou a página, o back handliberará a página (a página é primeiro escrita para o disco se tiver sido modificada).

Todos os 3 sistemas operacionais possuem localidade numa durante paginação. Ocache buffer I/O e a page cache de memória virtual é merged em um sistema de page cachenos 3 sistemas. O sistema de page cache é usado para leituras e escritas de arquivos assimcomo arquivos mmapped e texto e dados de aplicações.

Page 76: KERNEL DO LINUX

76 EDITORA - UFLA/FAEPE - Kernel do Linux

7.3 SISTEMA DE ARQUIVOS

Os 3 sistemas operacionais usam uma camada de abstração de dados para escon-der das aplicações os detalhes de implementação do sistema de arquivos. São usadas aschamadas de sistema open, close, read, write, stat, etc. para acessar arquivos. Solaris eFreeBSD chamam este mecanismo de VFS (Virtual File System) e a estrutura de dadosprincipal é o vnode ou virtual node. Todo arquivo que está sendo acessado em Solaris ouFreeBSD tem um vnode atribuído a ele. Além disso, para informação de arquivo genérico, ovnode contém ponteiros para informação específica do sistema de arquivos. Linux tambémusa um mecanismo similar, denominado VFS (Virtual Filesystem Switch). No Linux, a es-trutura de dados independente do sistema de arquivos é um inode. Esta estrutura é similarao vnode no Solaris/FreeBSD. VFS permite a implementação de muitos tipos de sistemasde arquivos

Linux tem duas estruturas diferentes, uma para operações de arquivos e outra paraoperações inode. Solaris e FreeBSD combinam essas operações vnode.

VFS permite a implementação de muitos tipos de sistemas de arquivos no sistema.A Tabela 7.1 lista alguns tipos de sistemas de arquivos implementados em cada sistemaoperacional.

Solaris ufs Sistema de arquivos local padrão (baseado no sistema de arquivos rápido do BSD)nfs Arquivos remotos /procnamefs Sistema de arquivo de nomes; permite abertura de portas ou streams como arquivosctfs Sistema de arquivos contratado usado com a facilidade de gerência de serviçotmpfs Usa espaço anônimo (memória/swap) para arquivos temporáriosswapfs Mantém informações de espaços anônimos (dados, heap, pilha, etc)objfs Mantém informações de módulos do kerneldevfs Mantém informações de arquivos /devices

FreeBSD ufs Sistema de arquivos default (ufs2, baseado no sistema de arquivos rápido do BSD)defvs Mantém informações de arquivos /devext2 Sistema de arquivos Linux ext2 (GNU-based)nfs Arquivos remotosntfs Sistema de arquivos Windows NTsmbfs Sistema de arquivos Sambaportalfs Monta um process sobre um diretóriokernfs Arquivos contendo várias informações de sistema

Linux ext3 Sistema de arquivos baseado no ext2ext2 Sistema de arquivos extent-basedafs Suporte a cliente AFS para compartilhamento de arquivo remotonfs Arquivos remotoscoda Outro sistema de arquivos de redeprocfs Processos, processadores, barramentos, plataformas específicasreiserfs Sistema de arquivos

Tabela 7.1: Lista parcial de sistemas de arquivos [Bruning (2005)]

Page 77: KERNEL DO LINUX

Comparação entre Solaris, Linux e FreeBSD 77

7.4 RESUMO

Os mecanismos de implementação dos subsistemas do kernel são similares nos trêssistemas operacionais. O Linux tende a usar abstração de dados de nível mais alto, comcódigo e estruturas de dados mais dependentes da máquina.

Em termos de documentação, FreeBSD tem grande parte da implementação do kerneldocumentada e disponível. O Linux também tem bastante documentação, mas está associ-ada a release. Além, disso, Linux tem uma comunidade extensa disponível para responderquestões.

Page 78: KERNEL DO LINUX

78 EDITORA - UFLA/FAEPE - Kernel do Linux

Page 79: KERNEL DO LINUX

8CONSIDERAÇÕES FINAIS

Esta apostila apresenta uma visão geral sobre sistemas operacionais, com ênfaseno kernel do Linux. Pode-se observar que objetivo principal de um sistema operacional,que é realizar a interface entre o usuário e o hardware é atendido por qualquer sistemaoperacional. Porém, cada sistema operacional, inclusive cada distribuição do Linux, possuifuncionalidades adicionais para tornar ainda mais fácil e rápida esta interação, e fazer comque o sistema operacional seja portável para várias plataformas.

Para um aprofundamento maior no kernel do Linux são citadas várias referências paralivros, sites e documentações sobre o assunto, em Referências Bibliográficas.

Page 80: KERNEL DO LINUX

80 EDITORA - UFLA/FAEPE - Kernel do Linux

Page 81: KERNEL DO LINUX

REFERÊNCIAS BIBLIOGRÁFICAS

8.1 SOBRE SISTEMAS OPERACIONAIS EM GERAL

[Oliveira (2001)] Oliveira, R. S., Carissimi, A. S. e Toscani, S. S. Sistemas Operacionais,Sagra Luzzatto. Série Livros Didáticos, Número 11, Segunda Edição. 2001.

[Silberschatz (2004)] Silberzchatz, A., Galvin, P. B. and Gagne, G. Fundamentos de Sis-temas Operacionais, LTC. Sexta Edição. Rio de Janeiro. 2004.

[Tanenbaum (1995)] Tanenbaum, A. S. Sistemas Operacionais Modernos, LTC. 1995.

8.2 SOBRE SISTEMA UNIX

[Bell (2007)] Bell Labs. The Creation of the UNIX* Operating System. 2007. Available athttp://www.bell-labs.com/history/unix/.

[UNIX (2007)] The Open Group. History and Timeline. 2007. Available athttp://www.unix.org/what_is_unix/history_timeline.html.

8.3 SOBRE SISTEMA LINUX

[Beck (1998)] Beck, M., Böhme, H., Dziadzka, M., Kunitz, U., Magnus, R. and Verworner,D.Linux Kernel Internals, Second Edition, Addison-Wesley. 1998.

[Bovet (2002)] Bovet, D. P. & Cesati, M. Understanding the Linux Kernel, Second Edition,O’Reilly. 2002.

[Cisneiros (2007)] Cisneiros, H. The Linux Manual. Capítulo 1. Introdução ao Linux 2006.Disponível em http://www.devin.com.br/eitch/tlm4/s1-diferenca-linux-unix.html.

Page 82: KERNEL DO LINUX

82 EDITORA - UFLA/FAEPE - Kernel do Linux

[Garrels (2002)] Garrels, M. Introduction to Linux - A Hands on Guide. 2002. Available athttp://www.tldp.org/LDP/intro-linux/intro-linux.pdf.

[Godoy (2006)] Godoy, J., Hogbin, E. J., Komarinski, M. F. and Merrill, D. C. The LinuxDocumentation Project. 2006. Available at http://www.tldp.org/guides.html.

[Kernel (2007)] Linux Kernel Organization, Inc. The Linux Kernel Archives. Available athttp://www.kernel.org, Jan. 2007.

[Love (2005)] Love, R. Linux Kernel Development, Second Edition, Sams Publishing. 2005.

[Maxwell (2000)] Maxwell, S. Kernel do Linux, Makron Books. 2000.

[Mazioli] Mazioli, G. Guia Foca Linux, em vários níveis. Disponível emhttp://focalinux.cipsga.org.br/

[Mazioli (2006)] Mazioli, G. Guia Foca GNU/Linux - Capítulo 16 - Kernel e Módulos. 2006.Disponível em http://focalinux.cipsga.org.br/guia/intermediario/ch-kern.htm

[Mazioli (2006)] Mazioli, G. Guia Foca GNU/Linux - Capítulo 6 -Gerenciadores de Partida (boot loaders). 2006. Disponível emhttp://focalinux.cipsga.org.br/guia/intermediario/ch-boot.htm

[Nemeth (2002)] Nemeth, E., Snyder, G. and Hein, T. R. Linux Administration Handbook,Prentice Hall PTR. 2002.

[Corbet (2005)] Corbet, J., Rubini, A., Kroah-Hartman, G. Linux Device Drivers, Third Edi-tion, O’Reilly, 2005. Available at http://lwn.net/Kernel/LDD3/.

[Santos (1999)] Santos, C. A. M. Linux Portuguese-HOWTO.Universidade Federal de Pelotas. 1999. Disponível emhttp://br.tldp.org/projetos/howto/arquivos/html/Portuguese-HOWTO/Portuguese-HOWTO.pt_BR-195.html.

[Wirzenius (2005)] Wirzenius, L., Oja, J., Stafford, S. and Weeks, A. The Linux SystemAdministrator’s Guide. 2005. Available at http://www.tldp.org/LDP/sag/sag.pdf.

8.4 OUTROS

[Apple (2007)] Apple Inc. 2007. Available at http://www.apple.com/.

[Bruning (2005)] Max Bruning. A Comparison of Solaris, Linux, and FreeBSDKernels, 2005. Available at http://www.opensolaris.org/os/article/2005-10-14_a_comparison_of_solaris__linux__and_freebsd_kernels/ em February, 2007.

Page 83: KERNEL DO LINUX

Referências Bibliográficas 83

[Microsoft (2007)] Microsoft Brasil. 2007. Disponível emhttp://www.microsoft.com/brasil/exchange2007/default.mspx.

[Seebac (2004)] Seebach, P. IBM: Basic use of pthreads. 2004. Available at http://www-128.ibm.com/developerworks/linux/library/l-pthred.html.

[Vivier (2007)] Vivier, L. Ext4 Development project. 2007. Available athttp://www.bullopensource.org/ext4/.

[Johnson (2001)] Johnson, M. K. Whitepaper: Red Hat’s New Journaling File System: ext3.2001. Available at http://www.redhat.com/support/wpapers/redhat/ext3/.