Sei sulla pagina 1di 37

TOPICOS DE SISTEMAS

OPERACIONAIS

1
SISTEMAS OPERACIONAIS
1 INTRODUÇÃO................................................................................................................................3
1.1 O que é um SO?........................................................................................................................3
1.2 SO x Empresa...........................................................................................................................3
1.3 Perspectivas de um SO.............................................................................................................4
1.4 Ecossistema...............................................................................................................................4
1.5 Gerações de Sistemas Operacionais.........................................................................................5
1.6 Tipos de Sistemas de Operacionais...........................................................................................6
1.7 Hardware...................................................................................................................................7
1.8 A carga do Sistema Operacional...............................................................................................7
1.9 Conceitos - Processos...............................................................................................................8
1.10 Conceitos - Memória..............................................................................................................9
1.11 Interpretador de Comandos.....................................................................................................9
1.12 Chamadas de Sistemas..........................................................................................................10
1.13 Organização de Sistemas Operacionais (Tipos de Projeto)..................................................11
2 GERÊNCIA DE PROCESSOS......................................................................................................13
2.1 Conceitos Básicos...................................................................................................................13
2.2 Criação de Processos..............................................................................................................14
2.3 Término de Processos.............................................................................................................15
2.4 Hierarquia de Processos..........................................................................................................15
2.5 Estados de Processos (Ciclo de Vida dos Processos)..............................................................16
2.6 Interrupções............................................................................................................................17
3 GERENCIA DE MEMÓRIA.........................................................................................................19
3.1 Gerenciador de memória.........................................................................................................19
3.2 Acesso à memória...................................................................................................................19
3.3 Problemas de Gerenciamento de Memória.............................................................................19
3.4 Gerente de Memória...............................................................................................................20
3.5 Monoprogramação..................................................................................................................20
3.6 Modelo de Multiprogramação................................................................................................21
3.7 Gerenciamento Básico - Multiprogramação...........................................................................21
3.8 Overlays..................................................................................................................................25
3.9 MEMÓRIA PAGINADA........................................................................................................25
4 Gerencia de E/S..............................................................................................................................32
4.1 Introdução...............................................................................................................................32
4.2 Esquemas de E/S.....................................................................................................................33
4.3 DMA (Direct Memory Access)...............................................................................................34
5 Sistemas de Arquivos.....................................................................................................................36
5.1 Introdução...............................................................................................................................36
1 INTRODUÇÃO

1.1 O que é um SO?


Um sistema operacional pode ser encarado como um conjunto de programas que auxiliam o usuário
na utilização do computador. Dentre esse conjunto de aplicações pode estar editores de texto,
navegadores web, interpretadores de comandos, dentre outros. Pois bem, com essa definição é
difícil estabelecer que programas fazem parte do SO. Por exemplo, você pode achar que todos os
programas que foram instalados com a mídia do SO fazem parte do sistema operacional.
Após o exposto aqui gostaria definir o foco de estudo deste material, que é basicamente o núcleo
(kernel) do sistema operacional. Nesse curso estaremos preocupados com os aspectos relacionados
ao projeto de kernels de sistemas operacionais. De forma que apenas algumas aplicações auxiliares
(externas ao contexto do SO) serão citadas como o caso do interpretador de comandos e do
bootloader.

1.2 SO x Empresa

Uma analogia que pode ser feita é do SO com uma grande empresa. Uma empresa está inserida em
um ambiente onde ela terá que tratar com diversos agentes externos, aqui para exemplificar, temos:
Clientes, Fornecedores e o Governo.
Dentro da empresa cada recurso é especializado para interagir de alguma forma com um ou mais de
um destes elementos. O Depto. Comercial Faz o relacionamento com o cliente até a venda. O
Depto. técnico assume o relacionamento com esse cliente a após a venda. O Depto. de Pessoas
Gerencia os recursos humanos da empresa. Já o Depto. Financeiro é responsável pela cobrança e
pagamentos.
As empresas tendem a se dividir em áreas de especialização, essa estratégia é conhecida como
dividir para conquistar, e tem o objetivo de dividir um problema maior em partes menores, tornando
mais claro os processos internos e atendendo melhor a demanda do cliente. Observe que essa
divisão é sugerida e pode variar de empresa para empresa, o fato é que os administradores aceitam
essa divisão como uma boa prática.
Um sistema operacional pode ser visto da mesma forma. Os departamentos de uma empresa podem
ser comparados as gerências de um SO: Por exemplo o Ger. de Processos é responsável por criar os
processos e alocá-los para a CPU conforme a sua característica ou prioridade. Já o Ger. de
Memória será responsável por tratar as requisições de memória do processo como também garantir
a disponibilidade de memória para outros processos. A Ger. de E/S é acionada sempre que algum
processo precisa comunicar-se com o mundo externo, porém elementos internos do próprio SO,
podem querer também se comunicar com o mundo externo. Observe que esta é uma divisão também
sugerida, e os projetistas de sistemas operacionais tem aceito isso como uma boa forma de organizar
as rotinas do SO.

1.3 Perspectivas de um SO
O SO existe basicamente para cumprir duas missões básicas:
• Gerenciar a expectativa do usuário: atendendo a suas requisições dentro do esperado pelo
usuário;
• Gerenciar recursos do Sistema: Controlando e disponibilizando recursos para atender as
demandas dos usuários.

Maquina Estendida
O usuário quer que as suas solicitações sejam atendidas, mas não quer, de maneira alguma, saber
como isso vai ser feito. Sendo assim o usuário “preenche um formulário” e o SO se encarrega de
atender a sua solicitação. Por exemplo, um processo pode pedir: SO Abra um arquivo. Informando o
caminho do arquivo, e o local onde será guardado o descritor para o arquivo. O SO por sua vez deve
criar as condições para o que o usuário possa realizar operações sobre o arquivo aberto, desta forma
o SO através dos diferentes subsistemas deve preparar-se para eventuais solicitações do usuário para
aquele arquivo.

Gerente de Recursos
Como gerente de recursos o sistema operacional tem a função de garantir a disponibilidade dos
recursos, para que as solicitações dos processos possam ser atendidas. Muitos processos podem
solicitar uma impressão por exemplo. Porém, dada a sua natureza, a porta de impressão só pode ser
usada para atender uma requisição por vez, e sendo assim o sistema operacional deve enfileirar
essas requisições e atendê-las da maneira mais otimizada possível.

1.4 Ecossistema

O diagrama acima apresenta os diferentes elementos de um sistema operacional moderno. Nos


primeiros sistemas computacionais não havia essas camadas, o usuário interagia direto com o
hardware. Desta forma só quem poderia operar o computador eram pessoas extremamente
especializadas.
Com o passar do tempo diferentes camadas foram introduzidas no sentido de facilitar o uso do
computador, reduzindo a sua complexidade e tornando o seu uso possível por pessoas cada vez
menos especializadas.
Por exemplo, o SO tem como uma de suas finalidades esconder a complexidade do hardware (HW)
para o usuário. Porém o uso da interface bruta (API) do sistema operacional, ainda é bastante
complicado.
Para esconder a complexidade do sistema operacional, existe o interpretador de comandos, também
conhecido como SHELL. O SHELL é uma aplicação como outra qualquer, é através dele que o
usuário “preenche o formulário” com a sua solicitação para o SO, ou seja, é através do SHELL que
o usuário poderá lançar e terminar aplicações. copiar arquivos, desligar o computador, dentre outras
operações.
Um computador é uma ferramenta de trabalho programável, o que ele pode fazer é limitado apenas
pela imaginação do seu programador. Sendo assim, alguns usuários mais especializados podem
querer programá-los, para isso existem duas formas, a primeira é escrever um código em linguagem
de máquina (0s e 1s), a segunda seria escrever um código em um nível mais elevado e usa-se os
montadores e compiladores para traduzir esse código em linguagem de nível mais elevado em
código de máquina. Esse código gerado é o que chamamos de aplicativos (APPS).

1.5 Gerações de Sistemas Operacionais


Geração Hardware Programação
1a. (45-55) Válvulas Painéis Programação
2a. (55-65) Transistores Sistemas de Lote
3a. (65-80) Circuitos integrados Multiprogramação e Timesharing
SO especializados
Alto Grau de Integração - LSI
3a. (80-hoje) Desktop
CHIPS
Tempo Real

1a Geração de Computadores (45-55)


Neste primeiro momento os computadores eram projetados, construídos e programados pelas
mesmas pessoas, não existia o comercio destes equipamentos. A programação era realizada em
código absoluto, através de fios, plugs e chaves para controlar as funções básicas da máquina, ainda
não existia o conceito de linguagem de programação e os sistemas operacionais ainda não existiam.
Os computadores podiam ter até 20.000 válvulas. nessa época os programas processados pelos
computadores eram constituídos essencialmente por cálculos numéricos repetitivos, como por
exemplo a geração de tabelas de funções trigonométricas. Ainda nesta geração, no começo dos anos
50, se criou os cartões perfurados para evitar a programação em painéis.
São exemplos de computadores desta época o COLOSSUS, ENIAC e EDVAC.
2a Geração de Computadores (55-65)
A principal característica destes computadores é o uso do transistor (inventados no inicio dos anos
50) ao invés das válvulas. Isso teve um grande impacto no custo e no tamanho dos computadores.
Nesta época os computadores eram extremamente caros, e surgiram as primeiras técnicas que
tinham por objetivo otimizar o uso dos computadores, pois anteriormente perdia-se muito tempo
carregando-se programas e dados para o processamento posterior. Foi nesta época que foi criado o
sistema de processamento em lote (batch).
Os sistemas em lote, consistem no uso de um computador de pequeno porte (ex.: IBM 1401) para a
leitura dos jobs (programas + dados) para a fita magnética. Essa fita, contendo os jobs era levada
para o computador responsável pelo processamento (ex.: IBM 7094), onde eram executados em
sequência.
O principal uso destes computadores foi o cálculo matemático. Esses computadores eram
programados em linguagem de montagem ou FORTRAN, são exemplos de sistemas operacionais
desta época, o FMS (Fortran Monitor System) e o IBSYS do 7094.
3a Geração de Computadores (65-80)
Essa geração de computadores trouxe 3 grandes avanços:
O primeiro deles foi a integração, um conceito que permite agrupar vários transistores em uma
única pastilha de silício. Com isso era possível construir circuitos integrados para funções
específicas, com centenas de transistores, isso trouxe redução no custo, no tamanho e no consumo
de energia destes computadores, além do aumento na velocidade de processamento.
O outro avanço foi a multiprogramação. Para entender a vantagem desta técnica é preciso
entender como um job faz a leitura e saída dos dados. Em geral, os computadores possui
dispositivos de E/S responsáveis por fazer a leitura dos dados e eventuais impressões de resultados.
O fato é que, tanto na época como hoje, os dispositivos de E/S são mais lentos que a CPU, sendo
assim, sempre que um job acessa dados em uma fita por exemplo, a unidade de processamento fica
ociosa, até que o resultado seja transferido para a memória. Se durante essa transferência for
possível rodar outro job, esse tempo de CPU não seria desperdiçado. Lembrando que um job para
rodar precisa está na memória RAM, então se num dado momento existem vários jobs disponíveis
na memória para executar, durante um acesso de E/S por parte de um job a CPU poderá ser alocada
para outro job. Essa é a ideia da multiprogramação: Permitir que vários jobs estejam na memória do
computador em um dado instante.
O ultimo avanço foi o Timesharing. Esse tipo de recurso, provê a chamada interatividade para
sistemas computacionais. Em um primeiro momento, a interatividade permitiu o uso de terminais
on-line conectados a um sistema computacional. Cada terminal pode ser operado por um usuário e
este poderá submeter diversos jobs (processos). O sistema operacional se encarregará de escalonar a
CPU entre as diferentes requisições, através do compartilhamento do tempo da CPU
4a Geração de Computadores (80 - dias Atuais)
O principal avanço desta geração é a integração em Larga escala (LSI), isso tornou os computadores
muito baratos, criando as condições para o surgimento dos chamados computadores pessoais (PC).

1.6 Tipos de Sistemas de Operacionais


Os sistemas operacionais mais conhecidos hoje em dia, são em sua maioria de proposito geral, ou
seja, pode se encaixar em vários dos tipos abaixo. Por exemplo: o GNU/Linux poderá ser usado em
Mainframe, Computadores Pessoais e Servidores, mas também é um sistema que pode ter
escalonamento de Tempo Real e ainda ser usado em dispositivos embarcados. Então, tenha em
mente que a classificação abaixo é apenas para fins didáticos.
• Para computadores de Grande Porte (Main Frame): Essas máquinas se caracterizam pela
especialização do Hardware, o que lhe dá um alto poder de processamento.
• Para Multiprocessamento: Sistemas Computacionais com mais de um núcleo de
processamento;
• Multiusuário e Multitarefa: Esse sistema prove proteção entre recursos dos usuários
(privacidade) e a capacidade de executar várias tarefas ao “mesmo tempo”;
• Tempo Real: São Sistemas Operacionais que devem entregar uma resposta de solicitação
dentro de um prazo acordado (SLA);
• Embutido: Esse tipo de Sistema Operacional normalmente roda em hardware com
limitações de processamento e memória;

1.7 Hardware
O sistema operacional que você irá desenvolver rodará sobre um hardware. Você deve conhecer os
aspectos deste hardware para que obter um melhor despenho do sistema operacional. Os principais
aspectos que você deve observar:
• CPU: O Conjunto de instruções disponíveis, registradores, mecanismos de proteção
existentes, modos de acesso à memória, modo de endereçamento dos controladores de
dispositivos, hardware de gerencia de memória.
• Memória: Memórias disponíveis no sistema, se existe armazenamento persistente. Se o
modelo de memória tem espaço separado para instrução e dados.
• E/S: Existe disponibilidade de interrupções, Controlador de interrupções, Controlador
DMA?
• Barramentos: Os barramentos são padrões de mercado. A tratativa em relação a alguns
barramentos mais importantes (ex. PCI/ISA) devem está incluída diretamente no SO
(gerencia de E/S), para outros barramentos pode-se implementar o suporte através de drivers
de dispositivo.

1.8 A carga do Sistema Operacional


Em Computadores mais complexos, o SO costuma está em uma memória não volátil, o processo de
copiar esse sistema, ou partes dele, para a memória e transferir o controle da CPU é o que chamo
aqui de carga do SO. maneira como o Controle da CPU é transferido para o Sistema Operacional
pode variar de acordo com o hardware em questão. Aqui vamos explicar o processo de boot de um
sistema baseado na arquitetura intel x86.

1.8.1 BIOS, CMOS ,POST, Bootloader


Quando um computador é ligado, via hardware, o controle da CPU é transferido para BIOS (Binary
Input Output System), esse é o primeiro programa que executa em um computador deste tipo. Esse
software (firmware) fica localizado em uma memória não volátil conhecida como CMOS e durante
o processo de inicialização, o conteúdo da CMOS é transferido para uma localização na memória.
A primeira instrução executada pelo computador está no endereço 0xFFFF0 (1048560), essa
instrução é justamente um salto para o endereço inicial do código da BIOS. A BIOS faz, dentre
outras coisas, o chamado POST (Power On Self Test), que é uma verificação da saúde dos
componentes de hardware. Após a verificação, a BIOS vai procurar um o Bootloader em um MBR.
Uma das configurações que é feita na BIOS é a sequência de inicialização, ou seja, em quais
"discos" e em qual sequência o bootloader deve ser procurado. O Bootloader é o sistema
responsável pela carga do sistema operacional e fica armazenado nos primeiros 440 bytes do
primeiro setor do disco ou partição.
A BIOS vai carregar para a memória o MBR que estiver assinado, , um MBR é considerado
assinado, ou seja, o dispositivo é considerado inicializável, se os 2 últimos bytes do primeiro setor
do disco em questão, forem respectivamente 0xAA55. O bootloader é copiado para o endereço
0000:7C00 e controle da CPU é transferido para o Bootloader.
Em ultima instancia o Bootloader faz a carga do sistema operacional na memória e transfere o
controle para a mesmo. Isso encerra a carga do SO. A Tabela a seguir ilustra o esquema de um
MBR.
000-439 Código do Bootloader 440 bytes
440-445 Nulo 6 bytes
446-509 Tabela de Partições 64 bytes
510-511 Assinatura 0xAA55 2 bytes

1.9 Conceitos - Processos


Processos vs. Programas
A definição clássica diz que um processo é um programa em execução. Podemos dizer que um
processo é uma instância de um programa. O programa é estático, e normalmente está em alguma
memória não volátil (disco), já o processo é dinâmico, e além do código executável, é composto de
variáveis, pilha, etc. Ou seja no processo os dados podem variar ao longo do tempo. Um programa
pode ser inicializado várias vezes, gerando vários processos totalmente distintos entre si.
Espaço de Endereçamento
É o conjunto da memória acessível ao processo, guarda o executável, as variáveis e a pilha, e
normalmente começa de zero e vai até um valor específico. Nos sistemas operacionais mais
modernos esse espaço de endereço é continuo, porém a sua organização física na RAM é
fragmentada, para suportar isso existem os conceitos de Memória Real e Virtual.
Tabela de Processos
É a estrutura onde é guardada as informações sobre todos os processos que estão na memória do
computador, nesta estrutura tem informações sobre estados do processo e contexto. Normalmente
implementado através de uma tabela ou lista encadeada.
Registradores e Contexto de Processo
Em um sistema multiprogramado, processos podem se alternar no uso da CPU, um processo quando
retorna a CPU ele deve continuar de onde ele estava quando deixou a CPU em sua execução
anterior, para garantir isso, é preciso salvar o chamado contexto do processo, que é basicamente é
constituído dos registradores de uso geral, status, program counter (PC), a pilha de execução, dentre
outros.

1.9.1 Hierarquia de Processos


Apos a carga do SO esse inicia o primeiro processo, esse processo é responsável pela carga de
outros processos e estes podem chamar outros processos. Quando um processo é criado um dos seus
atributos é o identificador do processo que o criou, neste caso chamado de processo pai.
Esse tipo de relação gera a chamada hierarquia de processos, onde os processos do sistema podem
ser organizados em forma de arvore.

1.9.2 Atributos de Processos


Quando um processo é iniciado ele é registrado no sistema operacional, em uma estrutura conhecida
como tabela de processos, neste cadastro o processo recebe certos atributos que podem ser usados
para que tanto o SO como o administrador possam gerenciá-los. São exemplos de atributos: o PID
(Process ID), ID do usuário que o criou, comando/programa que originou o processo, etc.
1.9.3 Compilação x Interpretação
Existem duas formas de se fazer a tradução da linguagem de nível N (mais alto) para a de nível N-1
(mais baixo), compilação e interpretação. No processo de compilação, a tradução do código é feita
por completo em uma única vez, gerando o código na linguagem N-1, chamado código objeto. Já no
processo de interpretação a tradução do código é feita em tempo de execução do programa, para
isso o código de linguagem N é executado com o auxílio de um software conhecido como
interpretador.

1.10 Conceitos - Memória

1.10.1 Endereçamento
A memória pode ser vista como um array de posições para armazenamento de dados e instruções.
Esse conceito foi introduzido por Von Neumann. O espaço de memória ocupado por um processo é
chamado de espaço de endereçamento, e é só nesta área que o processo poderá atuar. Aqui é
importante lembrar que as arquiteturas de 32 Bits só permitem o endereçamento de 4GB por parte
do processo. Isso também é um limite para o SO. Para quebrar esse limite na arquitetura IA32 a
Intel criou uma extensão para seus processadores chamada de PAE (Physical Address Extension),
com essa extensão os limites de 4Gb para o processo continua, mas o SO consegue agora gerenciar
até 64GB de memória.

1.10.2 Fragmentação
Uma das finalidades do SO é gerenciar memória, entenda-se por isso prover memória para
processos e também gerenciar porções livres da memória. Para o SO gerenciar cada posição de
memória seria muito caro em termos de processamento e memória. Por isso os sistemas optam por
dividir a memória em blocos, e é esses blocos que serão alocados para os processos. Em algumas
situações o processo não conseguirá usar todo espaço do bloco, provocando desperdício de
memória, a isso chamamos de fragmentação interna. Em outros casos quando o processo é obrigado
a ocupar um espaço continuo na memória, podem surgir áreas de memória entre processos que
sejam tão pequenas que não poderão ser ocupadas por nenhum processo, o que também gera
desperdício, a esse tipo de situação chamamos de fragmentação externa.

1.10.3 Memória Virtual


Para evitar que os programadores tenham que trabalhar diretamente sobre a memória física, foi
criado o conceito de memória virtual. Sendo assim independente da área de memória onde o
processo foi alocado, o espaço de endereçamento do processo sempre vai de zero até um valor
específico. A tradução do endereço virtual para o real é sempre feita com o apoio de hardware
específico.

1.10.4 Proteção
O espaço de endereçamento de um processo deve ser protegido de acessos por parte de outros
processos. Em geral o sistema operacional conta com o apoio do hardware para prover esse tipo
proteção. Quando um processo tenta acessar uma memória que está fora do seu espaço de
endereçamento o hardware gera uma (exceção)interrupção e o processo é terminado imediatamente.

1.11 Interpretador de Comandos


A função básica do shell é tornar o uso do sistema operacional mais fácil para os usuários.
Basicamente o usuário digita um comando no prompt do shell, e este traduz aquela solicitação em
uma requisição para o sistema operacional.
Existem três paradigmas mais usados para usabilidade dos shells. Alguns interpretadores de
comandos se apresentam na forma de menu, e o usuário escolhe a operação dentre as opções
existente nestes menus. Outros interpretadores podem ser acionados através de comandos digitados
em um prompt de comando, esses interpretadores são conhecidos como interpretadores de linha de
comando ou CLI (command line interface). Por fim existem os interpretadores capazes de tratar
cliques de mouse, esses são os interpretadores gráficos. Por exemplo, no Windows: experimente
matar o processo explorer.exe, você verá que não será possível interagir mais com o Windows.
Sendo assim podemos dizer que o explorer.exe é uma espécie de interpretador de comandos
gráficos (cliques de mouse).
Um dos principais usos do interpretador de comandos é o lançamento de aplicações. Em geral, cada
comando corresponde a um arquivo no sistema onde está o código de máquina da aplicação. Porém
alguns dos comandos disponíveis para uso não são aplicações e tem a sua programação feita
internamente dentro do interpretador, esses comandos são conhecidos como comandos internos do
interpretador. Todo sistema operacional possui o comando CD nos interpretadores, mas nenhum
deles tem um “CD.EXE”.
Em geral os interpretadores permitem a execução em lote de programas através de arquivos, que são
conhecidos como batches. Um batch é um arquivo contendo uma sequencia de comandos válidos
para o interpretador de comandos. Esses comandos podem ser aplicações ou comandos internos.
Alguns interpretadores possuem comandos internos que permitem programar desvios de fluxo (if) e
laços (for e while) com base no código de retorno gerado ao final da execução dos comandos. A
grande parte dos interpretadores presentes nos sistemas operacionais possui uma linguagem de
programação (Linguagem Script), os programas escritos nessas linguagens não precisam ser
compilados, e são traduzidos para linguagem de máquina pelo interpretador em tempo de execução.
Após a digitação de um comando, em geral uma saída (resultado) é gerada na tela. A medida que o
usuário digita mais comandos essa saída vai desaparecendo, para dar lugar as novas saídas geradas,
de forma que aquele resultado não estará mais disponível. Para evitar isso, os interpretadores
possuem o recurso de redirecionamento, com ele é possível direcionar as saídas (padrão e erro) de
um comando para um arquivo colocando os caracteres > ou >> entre o comando e o arquivo de
saída.
Outra funcionalidade disponível nos interpretadores é acoplar as saídas de um comando na entrada
de outro, esse recurso é conhecido como pipe e pode ser utilizando o caractere '|' entre os comandos.

1.12 Chamadas de Sistemas

1.12.1 Conceitos
Uma chamada de sistema é a forma como o sistema operacional oferece os seus serviços. Em geral
quando se faz um programa, existem certas instruções que o programa em execução, aqui chamado
de processo, pode executar, como por exemplo operar com posições de memória pertencentes ao
seu espaço de endereçamento. Exemplo: um processo pode perfeitamente somar o conteúdo de duas
posições de memória e armazenar numa terceira sem precisar do Sistema Operacional, porém se
esse processo precisa armazenar isso em um arquivo, mandar via rede ou simplesmente mostrar na
tela, ele vai precisar do Sistema operacional para isso.
Como usar uma chamada de sistema?
Para usar as chamadas de sistema oferecidas por um sistema operacional é necessário conhecer a
API ou SPI do sistema operacional que define quais chamadas estão disponíveis e quais são os
parâmetros que devem ser passados. Os desenvolvedores de sistemas operacionais devem
disponibilizar a documentação desta API, se ele deseja que as pessoas façam programas para o seu
sistema. Aqui você encontra a documentação da API do Windows e Linux.
Para explicar esses conceitos utilizaremos GNU/Linux, porém eles se aplicam a qualquer sistema
operacional. Cada uma destas chamadas recebe parâmetros que devem ser colocados em
registradores específicos. Para exemplificar imagine o programa que tem as seguintes atribuições:
ler o conteúdo de um arquivo e exibi-lo na tela. Em termos de chamadas de sistema, o programa
deve ser organizado da seguinte forma: Abrir o arquivo (Open), Ler o seu conteúdo (Read) e
Escrever na saída (write), Fechar o arquivo (close) e por fim, terminar o processo (exit). No
GNU/Linux essas chamadas de sistemas tem os seguintes números:
1 – exit
3 – read
4 – write
5 – open
6 – Close
A chamada Open apresenta os parâmetros Arquivo e Modo, onde Arquivo é o nome do arquivo que
será aberto e modo é como o arquivo será aberto. O código a seguir ilustra o uso desta chamada
usando a linguagem assembly:
section .data

sys_open: equ 5 ; sys_open = 5


f: db "file.txt",0 ; f = "file.txt"
f_id: dd 0 ; f_id = 0
o_rdonly: equ 0
section .text
global _start

_start:

mov eax, sys_open ; move a chamada para o registrador eax


mov ebx, f ; move o nome do arquivo para o registrador ebx
mov ecx, o_rdonly ; move o modo de abertura para ecx
int 80h ; chama o SO
mov dword [f_id], eax ; O retorno (resultado) da chamada é armazenado em f_id (file descriptor)

1.13 Organização de Sistemas Operacionais (Tipos de Projeto)


Monolítico: Esse tipo de projeto caracteriza-se por todo o código do sistema operacional rodar com
o processador em modo supervisor. Isso torna, em tese, a execução das atividades mais eficiente,
pois todas as operações têm acesso a instruções privilégiadas não necessitando repassar requisições
deste tipo a um outro módulo (microkernel). Os críticos deste tipo de projeto citam a segurança e a
falta de organização como desvantagem deste tipo de projeto. Um exemplo clássico deste projeto é
o Linux.
Microkernel: Esse projeto seria o contraponto ao projeto monolítico. Os procedimentos do sistema
operacional são agrupados em bibliotecas e apenas uma pequena porção do código será executada
em modo supervisor. Isso proporciona uma execução mais segura do SO, porém a eficiência das
tarefas básicas do SO podem ser prejudicadas haja vista que procedimentos privilégiados terão que
ser repassados para o microkernel. Olhando o relacionamento dos componentes do SO Windows,
pode-se concluir que trata-se de um projeto microkernel (Carece de referência).
Cliente Servidor: Pode ser encarado como um SO distribuído, ou seja, diferentes componentes do
SO ficariam em diferentes hosts distribuídos geograficamente. (Carece de exemplos).
Exokernel: Esse projeto é usado para escrever os hypervisors, usados na Virtualização de Sistemas
Operacionais. A IBM criou essa possibilidade na década de 70 e isso voltou muito forte nos últimos
anos. A ideia principal deste projeto é ter um kernel realmente mínimo com o objetivo de prover
interface para que vários kernels possam compartilhar o mesmo hardware.
2 GERÊNCIA DE PROCESSOS

2.1 Conceitos Básicos


Não é fácil localizar na história quando surgiu o conceito de processo. Creio eu, que no momento
em que houve separação entre um programa supervisor (ancestral do SO) e o job que executa a
tarefa para o qual o computador foi comprado (computador não foi comprado para executar SO!),
neste ponto podemos dizer que essa tarefa é uma espécie de ancestral do processo. O conceito
moderno de processo está relacionado a um conjunto de instruções numa memória volátil e um
estado de processo, além disso um processo detém memória bem definida, CPU (por alguns
instantes), arquivos abertos, contexto, dentre outras características. Como já falamos anteriormente
um processo é um programa em execução.

2.1.1 Multiprogramação
As instruções que executam na CPU devem passar obrigatoriamente pela memória RAM, sendo
assim, um processo para ser executado precisa está na RAM. Os primeiros sistemas operacionais
eram monoprogramados, isso que dizer que em um dado momento somente um processo ocuparia a
memória além do SO. Em um sistema multiprogramado, a memória poderá está ocupada por vários
processos, cada um com o seu espaço de endereçamento. A ideia desta abordagem surgiu nos SOs
da 3a geração, para resolver o problema de desperdício de tempo de CPU durante uma operação de
E/S realizada por uma tarefa, isso ocorre principalmente porquê os dispositivos de E/S são mais
lentos que a CPU. Em ambiente multiprogramado a CPU poderá ser chaveada rapidamente entre
várias tarefas, desta forma, uma situação onde o programa espera por E/S, a CPU poderá ser
entregue a outro processo evitando o desperdício de tempo de CPU.

2.1.2 Pseudo Paralelismo


Em sala de aula a pergunta que normalmente faço é: O que é um sistema operacional multitarefa? A
resposta mais comum é: "Um sistema que executa várias tarefas ao mesmo tempo". Pois bem, essa é
de fato a sensação que os usuários experimentam, porém não bem assim que funciona.
Para possibilitar essa "experiência multitarefa", o que ocorre é que a CPU é compartilhada entre os
processos que estão na memória aguardando CPU. Funciona da seguinte forma: É escolhido um
tempo máximo, conhecido como quantum ou timeslice (fatias de tempo), em que a CPU será
entregue a cada processo, por exemplo 20ms , desta forma, em único segundo a CPU, terá sido
alocada para vários processos. no exemplo 50 vezes teoricamente. Desta forma, para o usuário
parece que os vários processos executam juntos, mas o que houve foi um compartilhamento do
tempo de CPU. Essa técnica é conhecida como timesharing e foi implementada a partir dos sistemas
da 3a Geração. Para que isso funcione é necessário que exista apoio do hardware, neste caso um
gerador de interrupções, conhecido como relógio. A cada intervalo de tempo a CPU terá o fluxo de
execução desviado para o Sistema Operacional e neste ponto o SO assumirá o controle do sistema,
até entregar novamente a CPU a outro processo.

2.1.3 Mudança de Contexto


Em um sistema de tempo compartilhado, quando um processo é interrompido por alguma razão
(interrupção ou chamada de sistema), este deverá retornar a CPU no futuro próximo, quando o
processo retornar ele deve continuar do ponto onde parou. Para que isso ocorra é importante que
algumas informações sejam salvas antes que a CPU seja utilizada por qualquer outro software (SO
ou processo). A essa informação é chamada de contexto do processo e é composta basicamente de
registradores da CPU, como por exemplo o PC (program counter), Os registradores acumuladores,
o registrador de status, dentre outros (existem outras informações que não são registradores, mas
essas serão tratadas em um momento oportuno).
Dito isso, podemos dizer que quando um processo deixa a CPU, antes de qualquer coisa o SO
precisa realizar o Salvamento do Contexto e antes que o SO passe o controle da CPU para um
processo, é preciso que seja restaurado o contexto do processo. A esse evento de saída de um
processo da CPU e entrada de outro, chamamos de troca ou mudança de contexto.

2.1.4 Processo X Programa


Já abordamos isso anteriormente. Um processo tem características que são dinâmicas e que mudam
ao longo do tempo. Dentre essas características podemos citar variáveis, estado, arquivos abertos,
contexto. O programa é o código (instruções) que encontra-se eu uma memória não volátil
diferentemente do processo que estará obrigatoriamente na RAM, quando em execução.
OBS.: Sabemos que um processo pode ocupar uma área em disco conhecida como área de troca.
Porém é importante lembrar que essa área estende a memória RAM de certa forma, porém um
processo para executar (ocupar a CPU) terá que ser movido desta área para a RAM.

2.1.5 Comportamento do Processo (I/O x CPU).


Conhecer o perfil de execução de um processo é importante no momento de escolher (escalonar)
um processo que vai usar a CPU, o motivo de tal afirmação será mostrado na aula de escalonamento
de processos. Existem 2 perfis de execução de processo. O perfil Orientado a CPU (CPU bound)
usa extensivamente a CPU. Esses processos quando ocupam a CPU costumam usar toda a sua fatia
de tempo. Por exemplo em cálculos matemáticos complexos (ex.: fatorial de 80.000). Já no perfil
Orientado a E/S (I/O bound) os processos quando ocupam a CPU usam uma pequena fração da sua
fatia de tempo e logo acionam o SO para alguma tarefa.

2.2 Criação de Processos


Em linhas gerais o Sistema Operacional é o conjunto de aplicações que tornam possível o uso do
computador. Para o nosso estudo estamos preocupados especificamente com o Kernel do SO. O
kernel será responsável por prover recursos para que as demais aplicações possam executar suas
atividades. Aqui consideramos processos todas aquelas aplicações que NÃO rodam em modo
supervisor do processador.
Inicialização do SO
Por mais rápido que seja o computador, existe sempre um tempo entre o momento que se pressiona
o botão ligar e o instante em que o sistema estará pronto para uso. Boa parte deste tempo é usado
pelo SO para preparar o sistema. Esse preparo consiste basicamente na inicialização de processos
que são primordiais para o funcionamento do sistema. O termo usado para esses processos é
Daemon (Serviço).
Através de um processo
Um processo poderá ser iniciado dentro de um outro processo, usando uma chamada de sistema. No
Windows a chamada de sistema CreateProcess() poderá ser usada para criar um processo. Nos
sistemas POSIX (Linux, AIX, SUnOS, Opensolaris, HPUX, MacOs), A chamada de sistema usada
para criar um processo é a fork(). Essa chamada não recebe nenhum parâmetro e o que ela faz é
criar um processo filho que é idêntico ao processo que fez a chamada. Para substituir esse processo
filho por um novo processo é executada a chamada de sistema exec(). Essa técnica é o conhecida
como fork-exec e á maneira como esses sistemas disparam novos processos.
Requisição de Usuário
Um usuário pode a qualquer momento solicitar a criação de um processo. Em um sistema
operacional gráfico ele fará isso através de um clique de mouse. Já em uma interface de linha de
comando (CLI) isso será feito digitando um comando.

2.3 Término de Processos


Podemos dizer que um processo foi finalizado quando este não estiver mais presente na tabela de
processos. Isso implica que toda a memória alocada e todos os recursos alocados anteriormente para
aquele processo agora estarão livres. Esta seção fala das diversas formas de um processo terminar.
Saída Programada Normal e Por Erro
Alguns aplicativos executam por um certo tempo até executar a tarefa e depois são terminados. Um
exemplo de aplicação é o comando DIR do Windows. Esse termino é sempre codificado pelo
programador da aplicação. Outra forma de um processo sair é no caso de algum erro detectado pelo
programador durante a execução do processo. Por exemplo num sistema onde o usuário entra algum
valor inesperado e o programador devia o fluxo para uma instrução de saída. Nestes casos instrução
passada pelo programador para o termino da aplicação se traduzirá sempre em uma chamada de
sistema que deve ser usada para avisar o SO para tomar as providências para finalizar o processo
em questão. No Windows essa chamada de sistema é o ExitProcess(). Nos Sistemas POSIX a
chamada de sistema em questão é a exit().
Erro Fatal
O erro fatal ocorre quando o processo executa alguma operação ilegal (por exemplo divisão por
zero). Quando ocorre esse tipo de situação é gerada uma interrupção a nível de hardware e o
processo atual é interrompido e o controle da CPU volta ao sistema operacional. Nestes casos o
comportamento padrão do SO é excluir o processo da lista dos processos em execução e liberar
todos os recursos. Algumas linguagens de programação trabalham com o conceito de exceção para
impedir que o processo seja terminado, nestes casos a instrução ilegal é capturada (possivelmente
por um interpretador ou máquina virtual) antes de ser passada a CPU.
Cancelamento
O cancelamento de um processo é um evento externo ao processo (provocado pelo SO ou outro
processo). Quando esse evento ocorre, o processo tem o seu fluxo normal de execução interrompido
e é desviado para uma função que vai tratar da finalização do processo. Um exemplo desta situação
ocorre quando você pressiona o [X] para fechar o MS/Word. Nesta situação, o MS/Word é desviado
para uma rotina que, dentre outras coisas, vai questionar sobre o salvamento dos documentos não
salvos. Em alguns casos é possível interromper o processo abruptamente (sem o devido tratamento).
Um exemplo deste tipo desta última situação ocorre quando você fecha uma janela que não está
mais respondendo.

2.4 Hierarquia de Processos


A possibilidade de criar um processo a partir de outro, dá origem a uma ralação do tipo pai-filho
entre os processos. Um processo quando criado recebe um identificador (Process ID ou PID)
perante o Sistema Operacional. Nos sistemas operacionais que possuem (O Windows não possui)
esse relacionamento os processos costumam guardar em seus atributos também o (Parent Process
ID ou PPID) que é o PID do processo que o criou. Usando esse atributo dos processo é possível
mapear todos os processo do sistema na forma de uma arvore de processos. Essa relação existente
entre os processos dá origem a chamada Hierarquia de Processos a listagem abaixo mostra a arvore
de processos para um sistema GNU/Linux distribuição Debian (saída obtida pelo comando pstree
-p).
init(1)-+-acpid(1823)
|-atd(1888)
|-cron(1908)
|-dhclient3(1839)
|-getty(1927)
|-getty(1929)
|-getty(1931)
|-getty(1933)
|-getty(1935)
|-login(1925)---bash(1951)---pstree(1961)
|-named(1863)-+-{named}(1864)
| |-{named}(1865)
| `-{named}(1866)
|-portmap(1606)
|-rpc.statd(1617)
|-rsyslogd(1809)-+-{rsyslogd}(1811)
| `-{rsyslogd}(1812)
`-udevd(864)

2.5 Estados de Processos (Ciclo de Vida dos Processos)


Durante a sua vida, um processo poderá está em um dos três estados a seguir:
• Pronto (ready): O processo está pronto para ganhar a CPU, tudo o que ele precisa é ser
escolhido, dentre os processos existentes, para ganhar a CPU e continuar processando. Por
favor não confundir esse estado com finalizado.
• Executando (running): Neste estado, o processo estará ocupando a CPU. O número máximo
de processos neste estado em um Sistema será igual a quantidade de CPUs disponíveis.
• Bloqueado (blocked): Neste estado, o processo estará aguardando algo necessário para
continuar a sua execução. Em geral o processo solicitou algo ao SO através de uma chamada
de sistema blocante.
O diagrama abaixo mostra a transição entre esses estados:

Transição 1: Ocorre quando um processo da fila de prontos é escolhido (escalonado) para ocupar a
CPU.
Transição 2: Essa transição ocorre em consequência de uma interrupção de hardware. Um
dispositivo requer atenção. Em SOs preemptivos o relógio de hardware gera uma interrupção para
indicar que a fatia de tempo destinada ao processo acabou.
Transição 3: Ocorre quando o processo solicita algo ao sistema operacional. Por exemplo Entrada e
Saída, mais memória, etc.
Transição 4: Ocorre quando a solicitação do processo está atendida pelo SO. O processo irá ocupar
uma posição na fila de prontos.
OBS.: Observe que esta é uma sugestão do Tanenbaum e que é seguida por grande parte dos
escritores sobre o tema. O fato é que os SOs da atualidade apresentam, muitas vezes com outra
nomeclatura, em seu conjunto de estados, também esses estados sugeridos acima. Por exemplo, o
Windows apresenta além dos estados acima: Exit (marcado para ser removido da memória), New
(Ainda não foi aceito) e Suspended (pausado). Abaixo uma figura com os estados de processo do
Windows tirada desta referência citada. Observe a semelhança do ciclo Ready-Running-Blocked,
com o ciclo descrito anteriormente.

Abaixo uma animação com os estados dos processo para o Linux.

2.6 Interrupções
O termo interrupção aplica-se a um evento inesperado que provoca um desvio no fluxo de execução
atual (o processo que está usando a CPU é interrompido e o fluxo é desviado para o sistema
operacional, esse ponto de desvio faz parte do espaço de instruções do SO é conhecido como rotina
de tratamento de interrupção ou interrupt handler). Em geral o recurso de interrupção está
disponível em qualquer sistema computacional, essa é uma funcionalidade provida pelo hardware
em questão.
A interrupção pode ocorrer tanto em nível de hardware (imprevisível) ou Software (Normalmente
Previsível). A interrupção de Hardware ocorre por solicitação de algum dispositivo que necessita de
atenção imediata, como por exemplo atualização da posição do ponteiro na tela provocada por uma
movimentação do mouse. Já interrupção de Software, é provocada pelo processo e ocorre quando
um programa solicita algum serviço do sistema operacional. Anteriormente vimos que para um
processo executar uma chamada de sistema é necessário a execução da instrução int 80h, essa
instrução provoca o chaveamento do controle para o SO. Esse tipo de interrupção é conhecida na
literatura como interrupção de software e pelo fato de ser uma instrução dada pelo programador da
aplicação, podemos dizer que esse tipo de interrupção é previsível.
Para garantir que o processo que foi interrompido, retorne ao ponto de onde parou, quando esse
ocupar novamente a CPU, é necessário que o tratador de interrupção faça o salvamento do contexto
do processo que foi interrompido. Abaixo uma lista com todos os procedimentos executados por
uma rotina de tratamento de interrupção (Tanenbaum):
• Hardware Empilha o contador de Programa atual (Registrador PC);
• Hardware Carrega novo contador PC a partir do vetor de interrupção;
• Rotina de Baixo nível Salva os Registradores;
• O procedimento para tratamento de interrupção é executado (pode ser em C);
• O escalonador de processos é acionado para escolher o próximo processo que ocupará a
CPU;
• O contexto do processo escolhido é restaurado;
• O Controle é transferido para o processo escolhido.
3 GERENCIA DE MEMÓRIA

3.1 Gerenciador de memória


O problema principal que o gerente de memória deve resolver é como fornecer ao processo acesso à
memória, de maneira escalável e segura, assegurando a mínima ociosidade dos recursos de HW
(CPU, I/O, etc.).
Dois detalhes do capítulo anterior são pertinentes aqui:
• Um processo é uma instância de programa que para ser executado deve está necessariamente
na memória RAM.
• Outro detalhe é que o processo é composto das instruções que são carregadas do arquivo do
programa, e dos dados derivados da execução das instruções.
Lembrete: O sistema Operacional sempre estará na memória, no todo ou em partes.

3.2 Acesso à memória

Em todo computador existe instruções que suportam a manipulação de informações na memória. As


operações típicas são leitura ou escrita que referenciam células específicas de memória. Para fazer
este trabalho de interface com a memória as CPUs contam com dois registradores específicos: o
MAR (ligado ao barramento de endereços) e o MBR (ligado ao barramento de dados). O MAR
(Memory Address Register), tem o papel de selecionar a célula de memória que será afetada
(leitura/escrita) e o registrador MBR (Memory Buffer Register) tem o papel de receber o dado que
vem da memória, em caso de leitura. Em caso de escrita, esse registrador deve conter o dado que
será armazenado no endereço informado pelo MAR. A unidade de controle (UC), ligada ao
barramento de controle, através da decodificação da instrução vai informar se a operação é de
leitura ou escrita.

3.3 Problemas de Gerenciamento de Memória


Todos os problemas relacionados a Gerencia de Memória tem a mesma origem: O programador.
O programador quer cada vez mais e mais memória e mais rápida;
O programador ou é desonesto ou é relapso, de forma que não devemos permitir que ele possa
acessar memória de outros processos ou do SO.
É importante entender que quanto mais rápida a memória, mais cara ela será. O ideal seria ter um
computador com memória rápida em abundância, porém ele seria muito caro. O que os engenheiros
de computação tentam fazer é o balanceamento entre os tipos de memória: Uma pequena
quantidade de memória muito rápida (cache, registrador), com uma quantidade maior de memória
menos rápida (RAM), e abundancia de memória lenta (HD), porém persistente. Esse balanceamento
é conhecido como hierarquia de memória.
3.4 Gerente de Memória
O gerente de memória é o módulo do SO que implementa os serviços de memória que um processo
precisa. Por exemplo:
• Alocar memória para um processo recém-criado, permitindo ou não o compartilhamento de
memória.
• Fornecer a possibilidade de um processo crescer ou diminuir em termos de memória.
Exemplo: em C o programador faz uma chamada a uma função malloc ou free, ou em
java, quando um programador estancia uma determinada classe;
• Em alguns SOs, permitir que a demanda por memória seja maior que a quantidade de
memória física disponível, através do uso de uma área de troca em disco;
• Gerenciar as áreas de memória livre;
• E liberar espaço na memória, antes usados pelos processos que terminaram.
• Gerenciamento Básico de Memória

3.5 Monoprogramação
O Fato de se ter um sistema monoprogramado (um só processo na memória) não dispensa gerência.
Esse processo pode precisar crescer, ou simplesmente ocupar um maior espaço que a RAM
disponível.
Outro detalhe que pode ser percebido é que o Sistema Operacional também deve ocupar a RAM,
pois o processo sempre irá requisitar serviços ao SO, e para atendê-los, o SO deve necessariamente
está em alguma memória acessível rapidamente pela CPU.

As figuras acima ilustram três formas de disponibilizar memória física para o processo.
Na da esquerda o Sistema Operacional e Processo Compartilham a RAM.
Na do centro o Sistema Operacional em ROM e Processo em RAM → Alguns computadores têm a
capacidade de executar instruções direto da ROM.
Na da direita SO e Processo em RAM e Drivers em ROM.
3.6 Modelo de Multiprogramação

Esse modelo ajuda a entender as vantagens de se manter N processos na memória ao mesmo tempo,
baseado em seu percentual de E/S.
Se no desenvolvimento dos processos os engenheiros tivessem conseguido resolver o problema de
E/S ser invariavelmente mais lenta que a CPU, talvez os modelos de gerenciamento de memória
fossem construídos de outra forma.
O Fato é que todo o processo faz E/S e neste tempo, se não estiver disponível na memória outro
processo, a CPU ficará ociosa. Desta forma, o modelo de multiprogramação ajuda reduzir o
desperdício de tempo de CPU.
Mas qual é o grau mínimo de multiprogramação (quantos processos podem ser colocados na
memória) que pode garantir um uso efetivo (100%) de CPU?
É importante lembrar que o modelo proposto acima é ideal (o percentual de E/S sempre varia de
processo para o outro).

3.7 Gerenciamento Básico - Multiprogramação

3.7.1 Particionamento da Memória - Partições de Tamanho Fixo


Para que haja o compartilhamento de tempo da CPU (multitarefa) entre os processos, estes devem
está necessariamente na memória (Multiprogramação).
A solução trivial para gerenciar a memória para permitir que múltiplos processos a ocupem é o seu
particionamento.
O sistema operacional precisa saber onde estão os processos para poder passar o controle para eles,
e também não deve permitir que um processo acesse dados de outro processo (tarefa impossível
sem ajuda do hardware). Essa solução por ser trivial tem alguns problemas:
• Fragmentação Interna: O ideal era que o processo que fosse ocupar uma determinada
partição fosse exatamente do tamanho da partição, raramente isso ocorre, o que acontece na
realidade é que o processo sempre será menor que a partição, e isso gera um espaço interno
que não poderá ser usado por outro processo.
• Número fixo de partições: limita o sistema operacional a executar um número máximo de
processos.
Filas para acesso as partições

É comum em sistemas multiprogramados que exista vários processos sendo criados num dado
instante. Desta forma o sistema operacional deve controlar a forma como as partições deverão ser
entregue ao processo.
A primeira alternativa é manter uma fila de admissão com os processos e a medida que eles
entrarem na fila procurar uma partição vazia para acomodar esse processo. É importante lembrar
que quanto mais próximo o tamanho do processo e da partição, menor será o desperdício, a diante
discutiremos alguns algoritmos para escolha da partição. Na figura (b) podemos ver um esquema
desta técnica.
Procurar uma partição que gere o menor desperdício possível, é uma tarefa que pode requerer um
certo tempo dependendo do tamanho da quantidade de partições. Se for possível criar fila para as
partições esse tempo será reduzido, uma vez que, na criação do processo já será atribuído a ele um
tamanho de partição. Observe que esta técnica pode provocar uma espera desnecessária para o
processo uma vez que pode existir partições ociosas numa fila para processos maiores.

3.7.2 Particionamento da Memória - Partiçoes de Tamanho Variável


Nesta técnica, um processo pode ter o seu inicio e fim em qualquer ponto da memória em que haja
espaço livre continuo para alocá-lo. É uma técnica mais flexível que o particionamento fixo e
resolve os problemas de fragmentação interna e de limite no número de processos. A técnica de
partições variáveis é implementada normalmente com troca de processos.
Problemas e Soluções da Troca de Processos
O fato do processo poder ocupar qualquer espaço na memória, vai gerando espaços vazios na
memória, conforme os processos vão sendo criados e destruídos. Esses espaços gerados são muito
pequenos para serem usados por novos processos, esse problema é conhecido como fragmentação
externa. Para resolver o problema da fragmentação externa, de tempo em tempos, o sistema
operacional pode usar tempo de CPU para agrupar todos os processos no inicio da memória,
gerando um espaço livre maior, essa técnica é conhecida como compactação de memória.
Na vida real os processos são criados com um tamanho e ao longo do tempo tem o seu tamanho de
memória normalmente aumentado (alocação dinâmica de memória). Se um processo está alocado
entre dois processos, não há espaço para crescer, e desta forma pode ser trabalhoso para o sistema
operacional tratar solicitações de memória por parte do processo. Para resolver esse problema, pode
se usar espaço extra (maior que o necessário) na hora de alocar o processo na memória. A figura
abaixo tem duas abordagens para o espaço extra:

3.7.3 Troca de Processos


Num sistema que trabalhe com processos em lote é simples usar partições fixas, O processo entra na
sua partição e lá permanece até terminar sua execução.
Em sistemas de tempo compartilhado interativos, um processo pode ficar indefinidamente
esperando por uma resposta do usuário sem processar absolutamente nada, apenas ocupando
memória.
Em casos como este pode existir vários processos na memória e a CPU pode ainda está ociosa. Em
situações como essa podemos usar a troca de processo para guardar no disco, um processo que
esteja esperando uma resposta do usuário e assim liberar memória para um processo que precise
executar.
Quando o sistema envia o processo todo para o disco essa técnica é conhecida como SWAPPING.
Quando é possível transferir partes do processo para o disco essa técnica é conhecida como
paginação.
O uso da troca de processo permite que um sistema possa ter em execução, uma quantidade de
processos maior que a quantidade de memória física disponível.

3.7.4 Relocação
Uma variável definida em linguagem de alto nível sempre será definida em baixo nível como um
endereço de memória. Para exemplificar podemos citar o seguinte trecho de código:
I=25;
Podemos supor que este código será traduzido em baixo nível para a seguinte trecho, em arquitetura
específica.
MOV 25, $0x0100
A instrução acima, em assembly, vai mover o literal 25 para o endereço de memória 0x0100. Agora
imagine que no modelo de particionamento esse processo poderá ser alocado em uma partição em
que o endereço 0x1000 não faça parte. Ou seja o programador ou compilador não tem a mínima
ideia onde, na memória, o código será carregado. Esse problema é conhecido como relocação de
código e existe algumas técnicas que podem resolver esse problema, uma delas, usada
anteriormente era o carregador relocador , que reescrevia as referencias à memória no executável,
de forma que este refletisse os endereços da partição que será usada pelo processo.
3.7.5 Proteção
Se por acaso algum endereço não pertencente ao espaço de endereçamento do processo for acessado
pelo mesmo, isso será considerado uma falha de proteção. A seguir veremos as soluções disponíveis
para resolver estes dois problemas.

3.7.6 Soluções para relocação e Proteção


Soluções de Software + hardware
O Problema da relocação pode ser resolvido por software (sem auxílio de hardware), bastando
apenas reescrever as referências a memória, porém a questão da proteção, necessita de apoio de
hardware.
Fazer o programador trabalhar em relação a um zero, e depois adicionar um endereço de offset à
referencia pode resolver o problema da relocação. Digamos que uma partição inicia no endereço
0x3000. No exemplo anterior poderíamos dizer que 0x0100 é um endereço relativo ao inicio da
partição, durante o procedimento de carga a instrução seria modificada para 0x3100 (0x100 +
0x3000).
Ainda em relação ao exemplo anterior, imagine que para o programa ser alocado será usado uma
partição de 1K, ou seja, os endereços que poderão ser acessados vão variar de 0x0100 (endereço 0
da partição) até 0x0500 ( 0x1100+1k) endereço final da partição. No entanto no momento da
tradução o endereço relocado foi 0x1100 que é maior que 0x0500 que é o endereço final da
partição. Esse acesso claramente viola a proteção entre processos, um acesso deste tipo, se
permitido ira modificar o conteúdo de uma posição de memória fora de sua partição, e
possivelmente pertencendo a outro processo. A única maneira de evitar esse tipo de acesso é através
de hardware.
Uma solução criada pela IBM para proteção envolvia o uso de 4 BITs no registrador PSW
(STATUS). Com isso a memória do computador era particionada em 16 Partições cada uma com
2K. O SO, tendo acesso privilégiado, escrevia o número da partição nestes bits, e entregava o
controle ao processo. Se uma instrução fizesse acesso a um endereço cujo os 4 bits mais
significativos fossem diferentes dos da PSW, seria gerada uma interrupção de hardware (GPF), e o
processo em questão seria terminado. A comparação entre os bits do endereço e do PSW era feita
via HW.

Para fins didáticos a figura acima ilustra uma memória de 64K com 16 partições de 4k. A idéia é
descrever como funciona a proteção usando a PSW. Observe que temos 2 instruções, a primeira (A)
acessa o endereço 0x0100 (256) do segmento, A segunda (B) o endereço 0x1000 (4096).
No exemplo a instrução pertence a um processo que será alocado na partição 3. Nesta partição os
endereços vão de 0x3000 (12288) a 0x3FFF (16383). Antes da execução do código as referências
precisam ser relocadas, desta forma o carregador irá rescrever os endereços para 0x3100
(12544=12288+256) e 0x4000 (16384=12288+4096) respectivamente.
Dentro da CPU, antes do acesso à memória, é feita a comparação entre os 4 primeiros bits do
endereço que está sendo acessado, e o conteúdo armazenado na PSW. O primeiro acesso passará
normalmente. Já o segundo gerará uma falha pois o conteúdo da PSW (3) será diferente dos 4
primeiros bits do endereço (4).
Soluções em hardware
As soluções mostradas anteriormente se baseavam na modificação das referências à memória direto
no código. Essas soluções em geral foram ruins pois tinham problemas em situações de troca do
processo e cálculo de endereços. A solução por hardware é bem menos complexa, para o
programador do sistema operacional, porém encarece o valor da CPU. Um hardware é responsável
pela validação e tradução do endereço virtual (programador) para físico (célula de memória
específica). Esse hardware é uma unidade de gerência de memória (MMU) elementar. A figura
abaixo tem um esquema de funcionamento deste hardware. O SO antes de entregar ao CPU para o
processo preenche os registradores BASE e LIMITE na MMU. Toda referência ao endereço é
comparada com o registrador limite, caso seja maior é gerada uma interrupção (falha de proteção),
se for menor é passada pelo módulo de soma e finalmente cai no barramento de endereços.

3.8 Overlays
Pela lei de Parkinson, os programadores sempre querem mais memória, neste caso mais memória
que o disponível. Em sistemas de troca de processos isso não é possível. Sendo assim uma solução
que surgiu para esse problema é o chamado Overlay (Programadores clipper/DOS vão lembrar
disto). Nesta técnica, o programador da aplicação é responsável por particionar o seu código de
forma que ele seja chamado em partes. Cada parte quando é chamada substitui a outra na memória
RAM da máquina. A solução definitiva para o problema do processo maior que a RAM é a
Memória Paginada.

3.9 MEMÓRIA PAGINADA

3.9.1 Conceitos
Desde os primeiros sistemas de gerencia de memória não era mais dado ao programador das
aplicações a capacidade de acessar diretamente a memória física. Neste ponto surgiu o conceito de
memória virtual. Esse espaço de endereçamento manipulado pelo programador, seja por definição
de variáveis ou por alocação dinâmica, é conhecido como memória virtual.
Os dados manipulados pelo programa, são armazenados necessariamente em memória física (real),
e neste ponto é necessário que haja alguma tradução. O hardware responsável por essa tradução é a
unidade de gerência de memória ou MMU.
Para o programador o espaço de endereçamento é continuo, porém para permitir que somente partes
de um determinado programa esteja na memória, é necessário dividir o programa em fragmentos.
Esses fragmentos são conhecidos como página. A pagina pode ser virtual, correspondente ao espaço
do programador ou pode ser real, correspondente a pagina realmente ocupada na RAM, esse último
tipo de página é conhecido como moldura de página.
Em um esquema de gerência de memória por paginação existe uma estrutura que mantém o
mapeamento entre páginas e suas respectivas molduras, essa estrutura é conhecida como tabela de
páginas. Numa referencia a memória pode ocorrer duas situações: Se a página virtual estiver na
memória (se na tabela existir uma moldura equivalente) o programa executa normalmente. Caso não
haja moldura correspondente a MMU gera uma interrupção conhecida como PAGE_FAULT. E o
programa é interrompido (Bloqueado) até que página em questão (que está em disco) seja alocada
em alguma moldura.
Mapeamento

A figura acima mostra como funciona o mapeamento de páginas em molduras.


A maquina possui uma capacidade de endereçamento de 64K (16bits). Porém a RAM disponível é
apenas de 32K. (é a mesma coisa para um Pentium que tem 4G de endereçamento mas tem apenas
64MB RAM).
No exemplo, as páginas virtuais que estão com 'X', estão em disco, e qualquer tentativa de acessar
um endereço pertencente a qualquer uma destas páginas vai gerar um PAGE_FALT.
É importante observar que num esquema de paginação o tamanho da moldura e da página virtual
sempre são os mesmos. (Na realidade o SO pode trabalhar com páginas de tamanhos que sejam
múltiplos do tamanho da moldura).
Unidade de Gerencia de Memória
É um HARDWARE fica posicionado entre a CPU e a memória (registrador MAR e barramento de
endereços), é responsável pela validação dos acessos (proteção) e tradução (relocação) das páginas
virtuais em físicas. Não confundir com o sistema de gerencia de memória do sistema operacional.
Pode gerar interrupções relacionadas a falta de páginas, como também falha proteção.
Conversão Endereço Virtual em Físico

A conversão de endereços ocorre apenas nos bits mais significativos. O esquema acima mostra a
conversão com base no exemplo da figura anterior.
Ou seja com um intervalo de endereçamento de 64k e páginas de 4k termos 16 páginas virtuais (0-
15) isso interfere nos quatro bits mais significativos do endereço virtual, pois o resto dos bits (12)
são usados para acessar individualmente o dado dentro da página.
Vejamos como funciona a tradução:
Na parte de baixo do esquema o endereço virtual vindo da CPU na parte de cima o endereço
traduzido (real) que vai para o barramento de endereços.
Vamos analisar o acesso ao endereço virtual 8196 (0010000000000100)
Esse endereço está na página virtual 2 (0010). Segundo a tabela do esquema acima a pagina virtual
2 está na moldura 6 (0110) então o endereço será convertido para: (0110000000000100). O bit mais
significativo pode ser ignorado uma vez que só existem 32K (15bits) endereços reais.
Tabela de páginas
Serve para guardar, dentre outros dados, o mapeamento página virtual, real.
A cada referência à memória é feita uma tradução. Isso significa que o acesso a esta estrutura é
critico para a performance do sistema. Uma tabela de página pode ter um número grande de
páginas, por isso as técnicas de busca nesta tabela devem ser bem trabalhadas.
Em geral existem formas de armazenar essa tabela, e quanto mais rápido for a memória em que
estiver armazenada, maior vai ser a velocidade de acesso.
Implementar essa tabela em hardware, traria ganhos na velocidade de tradução, porém a quantidade
de memória necessária para esse armazenamento pode tornar o projeto caro.
A abordagem mais barata é armazenar na RAM, porém o acesso é lento. Essa é a solução usada
hoje, porém com certas modificações (mas a frente veremos como a TLB ajuda a melhorar a
velocidade).
Tabelas de Páginas Multinível
A implementação linear da tabela de páginas leva a um problema: O número de entradas pode ser
muito grande. Por exemplo: Na arquitetura Intel as páginas são de 4k e o espaço de endereçamento
é de 4G. O resultado é que uma tabela de página para um processo pode ter mais de um milhão de
entradas. Desta forma cada acesso a memória implica numa busca nestas entradas.
Um solução que surge para resolver esse problema é dividir essa busca em níveis, diminuindo assim
o escopo da busca.
Ex: Para 1M páginas é necessário 20bits. Se as páginas fossem organizadas em diretórios de 1K.
Teriamos 1K diretórios com 1K páginas.
Então para buscar um endereço seria necessário pesquisar primeiro a tabela de diretórios de páginas
“raiz” com no máximo 1k entradas, e depois pesquisar na tabela de páginas posterior, também com
1k entradas. Desta forma ao invés de buscar em 1M entradas, a busca será feita em 2k entradas.
Essa implementação de tabelas multinível pode ser feita para diversos níveis, é fácil perceber que
quanto mais níveis existir menor será o número de entradas pesquisadas, porém a complexidade do
sistema de paginação é aumentada.
O sistema operacional GNU/Linux usa 3 níveis, porém existe uma modificação (patch) para usar 4
níveis. (ref: http://lwn.net/Articles/106177/).
O MS/Windows usa dois níveis (Carece de referencias).
Formato de uma Entrada na tabela de páginas
A tabela de páginas além de possuir informações que permite o mapeamento da memória física em
virtual, também guarda outras informações necessárias para o uso do sistema operacional. São elas:
• Número da moldura: Pagina Real
• Presente/Ausente: Existe moldura equivalente? (esta na RAM)?
• Proteção: Simples (rw), Sofisticado (rwx)
• Referenciada: A pagina já foi usada?
• Modificada: A pagina foi alterada?
• Cache desabilitado: A página pode ser colocada na memória cache da(s) CPU(s).
TLB
As TLBs, também conhecidas como memória associativa, são dispositivos de hardware cujo
propósito é mapear endereços virtuais em endereços físicos sem passar pela tabela de páginas na
memória. Usualmente, ela faz parte da MMU. Ela constitui-se de um pequeno número de entradas,
muito rápidas, contendo as entradas das tabelas de páginas mais utilizadas. Quando um endereço
virtual é enviado a MMU, ela primeiramente verifica se o seu número de página virtual está
presente na TLB. Se o resultado for positivo, a moldura de página é tomada diretamente da TLB
sem a necessidade de passar pela tabela de páginas. Caso contrário, a pesquisa é feita normalmente
na tabela de páginas. Uma das entradas é removida da TLB e a entrada da tabela de páginas
pesquisada é colocada em seu lugar.

3.9.2 Algoritmos de substituição de páginas


Como visto anteriormente, sempre que uma página (endereço virtual) não estiver em uma moldura
de página, uma interrupção ocorre e ela deve ser carregada para uma moldura antes de ser
executada. No entanto, alguma página que está atualmente em uma moldura deve ser retirada
(gravada em disco). Os algoritmos de substituição de páginas se preocupam em escolher a melhor
página a ser retirada da moldura de forma a garantir o uso mais eficiente dos recursos do sistema.
Algoritmo ótimo
Deve ser retirada a página que só será referenciada o mais tarde possível. Apesar de, teoricamente,
ser um algoritmo interessante, é extremamente difícil prever quando uma página será referenciada;
Substituição de página não recentemente utilizada
o S.O. mantem uma coleção de estatísticas sobre as páginas referenciadas e/ou modificadas (através
dos bits de referência e modificação das entradas da tabela de páginas) e dão preferência para a
troca de páginas não referenciadas e/ou não modificadas;
Substituição de página FIFO – first-in first-out
A página mais antiga é removida. O principal problema desta abordagem é o fato de se remover
uma página bastante utilizada;
Substituição de página de segunda chance
Uma modificação do algoritmo FIFO, que busca não substituir uma página antiga e bastante
utilizada. A solução é inspecionar o bit R (referenciada) da página mais antiga; se o bit for 1 (foi
referenciada) o bit será limpo e a pesquisa continua. Se todas as páginas tiverem sido referenciadas,
o algoritmo FIFO acaba sendo executado e a página mais antiga (que agora estará com o bit R
limpo) será substituída;
Relógio
O algoritmo do relógio trabalha da mesma forma que o segunda chance, a diferença é que a fila de
páginas é circular, o que o torna mais performático uma vez que não é preciso reinserir páginas no
final da fila, bastando apenas ir para o próximo.
Substituição de página menos recentemente utilizada (MRU)
A ideia é que as páginas que foram intensamente utilizadas nas últimas instruções provavelmente
serão utilizadas de forma intensa no futuro próximo. Desta forma, deve ser removida a página que
não foi utilizada por mais tempo.
Conjunto do Trabalho
Num sistema que use a paginação pura, ao iniciar um programa, nenhuma página seria colocada na
memória, e a medida que existir a necessidade as páginas seriam carregadas, essa técnica é
conhecida como paginação por demanda.
A questão é que uma falta de página é um evento que atrasa processo, pois enquanto o tempo de
execução de uma instrução é da ordem de nanosegundos, a busca de uma página no disco chega a
demorar milisegundos. Sendo assim, os eventos de falta de páginas devem ser evitados ao máximo,
isso pode ser feito fazendo boas escolhas sobre as páginas que devem ir a disco, e tentar escolher
para seu lugar páginas que serão usadas num futuro próximo (pré-paginação).
A ideia deste algoritmo é esta, tentar minimizar a ocorrência de eventos de faltas de páginas, mas
como isso pode ser feito?
Ao se analisar o comportamento de uso das páginas dos processos em geral percebe-se que em dado
intervalo de tempo, o processo acessa somente uma pequena quantidade de suas páginas. Essa
propriedade dos processos é conhecida como localidade de referencia. E as páginas são chamadas
de conjunto do trabalho.
A medida que o processo segue seu fluxo de execução, esse conjunto vai mudando lentamente.
Então a cada falta de página, será escolhida, para ir para disco, uma página do processo que não
pertence ao conjunto do trabalho. O problema é como decidir se uma página pertence a esse
conjunto. A ideia original do algoritmo para resolver isto é marcar as páginas de forma a saber quais
páginas foram usadas nas ultimas k referencias. Se uma página não foi usada nas ultimas k
referencias então ela não pertence ao conjunto do trabalho. Na prática o que usado ao invés de k é o
tempo, ou seja, se uma página não foi referenciada nos últimos t milissegundos ela não pertence ao
conjunto trabalho.

3.9.3 Questões de Projeto


Vimos como funciona um sistema de paginação, agora veremos alguns dos aspectos que devem ser
observados na hora de projetar um sistema destes:
Politica de Alocação: Na hora da substituição da página, o escopo para escolha da página abrange
todas as páginas de todos os processos ou somente páginas do processo que sofreu o page fault?
Controle de Carga: Mesmo com o algoritmo de substituição de páginas ótimo, pode ocorrer
eventos de paginação excessiva (thrashing). Isso deve ocorrer sempre que o conjunto de páginas
necessárias for maior do que a RAM. Ou seja algum processo precisa de mais páginas e nenhum
outro processo pode trabalhar com menos páginas, assim pode ser interessante colocar um processo
todo em disco.
Tamanho da página: Em geral o tamanho da página é definido pelo hardware porém é possível
implementar em nível de SO, paginas que tenha tamanhos que seja múltiplos do tamanho de página
fornecido pelo hardware.
Espaços separados para instruções e Dados: Algumas poucas arquiteturas apresentam 2
memórias (Dados e programa). Nestes casos, a paginação deve ser feita para as duas memórias
independentemente.
Paginas compartilhadas: Em geral qualquer processo pode ser divido em dados e instruções.
Diferentes instâncias de um programa podem ser carregadas na memória. Um sistema de gerencia
de memória que permita que cada processo tenha sua própria área de dados mas possa compartilhar
as instruções pode trazer uma grande economia de memória.
Politica de Limpeza: O sistema de paginação funciona melhor se existir molduras livres. Sendo
assim, ter um serviço responsável por inspecionar a memória em busca de possíveis páginas
candidatas para ir a disco pode ser uma boa ideia. O serviço usará o algoritmo de substituição de
páginas para achar essas páginas.
Interface de Memória Virtual: Prover ou não prover uma forma do programador decidir como o
sistema de paginação vai tratar as páginas do seu programa? Um exemplo disto é dar o poder ao
programador de dizer quais paginas devem ser compartilhadas.

3.9.4 Questões de Implementação


Tratamento de Falta de Página
Quando um processo faz referencia a um endereço que não está em uma moldura, o processo não
pode seguir até que o endereço referenciado esteja em alguma moldura. Aqui vamos descrever a
sequencia de acontecimentos e ações que o SO precisa tomar para garantir que o processo em
questão possa continuar.
1. Interrupção de HW (Page Falt): Uma interrupção é gerada e o controle volta para o sistema
operacional.
2. Salvamento do Contexto: É a primeira coisa que o tratador da interrupção precisa fazer. Os
dados do contexto do processo atual precisam ser salvos para que o processo possa continuar
quando a página estiver disponível.
3. Tratamento da Interrupção: descobrir qual página precisa ser recuperada. Como fazer isso? a)
Através de algum registrador no hardware específico para este fim. b) Ou através do PC (do
contexto) recuperar a instrução para descobrir o endereço que causou a falta.
4. Verificação do endereço: O endereço é válido? o tipo de acesso que está sendo feito é valido?
Existe moldura disponível? Chamar o algoritmo de substituição?
5. Se a moldura precisar ser salva (foi modificada), vai ser necessário acionar o subsistema de E/S,
assim o processo é marcado como bloqueado e outro processo deve ser escalonado, entretanto a
moldura deve ser marcada como indisponível para que outro processo não tente acessá-lo.
6. A página faltante deve ser carregada em uma moldura, até esse momento o processo continua
bloqueado.
7. Quando o disco informar o termino da operação a tabela de páginas deve ser atualizada para
refletir essa nova situação (a pagina agora está em uma moldura).
8. É importante lembrar que a instrução que causou a falta deve ser reexecutada, pois do ponto de
vista do contexto a mesma foi executada, o sistema operacional deve garantir que essa instrução
será reexecutada quando o seu contexto for restaurado.
9. A página está disponível, o processo já pode ser executado, então deve-se marcá-lo como pronto.
10. O processo ao ser escalonado tem o seu contexto restaurado.
4 Gerencia de E/S

4.1 Introdução

Como vimos anteriormente os processos fazem solicitações ao hardware através do SO. Esse
hardware muitas vezes comunicam o sistema computacional ao mundo externo, representado
normalmente por um dispositivo conhecido como periférico.
Cada fabricante tem a sua forma de construir e de interfacear o periférico com o sistema de E/S. No
entanto para isso não deve afetar a forma como o processo interage como o dispositivo. Por
exemplo: O processo vai imprimir da mesma forma independente se a impressora é HP ou EPSON.
Sendo assim o principal problema do Subsistema de E/S é fornecer uma interface para que os
processos e os outros subsistemas do SO possam acessar o hardware de forma mais independente
possível.

Funções do Gerenciador de E/S


Toda vez que um processo solicita uma escrita no disco por exemplo. O SO, através do Gerenciador
de E/S é quem envia comandos para os dispositivos (através de seu controlador).
Em geral, o hardware é mais lento que a CPU, e para que esta não fique monitorando, existe a
interrupção, quando o hardware termina a sua tarefa, ele envia um sinal para a CPU que interrompe
o que está fazendo para tomar as providencias relacionadas ao termino daquela tarefa.
Os demais subsistemas do SO também fazem E/S. Por exemplo, o sistema de gerencia de memória
escreve e ler páginas do disco. Sendo assim é mais prático solicitar ao sistema de E/S que
implementar novamente rotinas de acesso ao hardware.
O processo quer escrever da mesma forma, independentemente se a escrita está sendo feita em disco
rígido, pen drive ou disquete. Sendo assim o SO deve prover uma interface uniforme para estes
acessos.

Princípios do Hardware de E/S


Aqui não trataremos aspectos do projeto do hardware, e sim os aspectos relacionados a
programação do sistema de gerenciamento de E/S. Mas é importante ter em mente que abstrair o
funcionamento do hardware nem sempre é possível.
A maioria dos sistemas operacionais oferece serviços de E/S tendo como base dois tipos distintos de
dispositivo: Bloco e Caractere.
A característica mais importante dos dispositivos de caractere é poder ler ou escrever apenas um
caractere por vez. Esses dispositivos também não suportam o conceito de endereçamento. São
exemplos deste tipo de dispositivos, modems, portas seriais e paralelas.
Já os dispositivos de Bloco, são lidos em blocos, e têm o conceito de unidade de alocação. Ou seja,
mesmo que seja escrito um byte no nível mais alto, esse byte no baixo nível vai ocupar uma unidade
de alocação. Outra característica destes de dispositivo, é a possibilidade de escolher, através de
endereçamento, qual bloco que será lido ou escrito. São exemplos destes tipos de dispositivos
discos rígidos e CDROMs.
É importante lembrar que existem exceções a essa regra.
Controladores de Dispositivo
Os sistemas computacionais nunca trabalham diretamente sobre o dispositivo, ao invés disto, eles
interagem com o controlador e esse por sua vez interage com o dispositivo.
Sendo assim os controladores de dispositivo são responsáveis por fazer a interface entre o
dispositivo ou periférico e o sistema computacional. Ficam conectados a algum barramento interno
(PCI, ISA, USB).
Os periféricos por sua vez se conectam á controladora através de um conector, ex: IDE, SATA,
RS232, USB.
O envio de comandos, leitura e escrita de dados é feito através de registradores internos do
controlador. A seguir veremos as formas de escrever e ler destes registradores.

Comunicação
Ler ou escrever em dispositivo ou ainda mandar um comando consiste basicamente em escrever em
registradores internos da sua controladora.
A escrita nestes registradores é feita através de endereços e existem duas abordagens para isso. A
primeira cria portas, que nada mais são que endereços, e para escrever nestas portas são necessárias
instruções especiais, justamente para não confundir essa escrita com a escrita em memória.
A segunda abordagem mapeia os registradores internos em endereços da memória, e para ler ou
escrever destes endereços é preciso basicamente ler ou escrever em uma posição de memória. Desta
forma não é necessários o uso de instruções especiais.

4.2 Esquemas de E/S

Na figura (a) temos o esquema com endereços especiais de E/S. Na figura (b) os espaços de
endereçamento são os mesmos da RAM. Na figura (c) temos um método híbrido onde o
controlador pode ser acessado tanto através de endereços de memória, como através de portas de
E/S. O Pentium usa um esquema como este último. Os endereços de 0-64k são usados como portas
de E/S e devem ser acessados através de instruções específicas (IN e OUT). Já os endereços 640K a
1M são usados para buffers relacionados a dispositivos.
Barramentos

A Figura (a) mostra a máquina de Von Neumann original previa um barramento único que iria
interligar CPU, E/S e memória. Durante muitos anos os sistemas computacionais trabalharam desta
forma.
O problema com essa abordagem é que em um barramento uma comunicação é possível por vez, e
desta forma a leitura e escrita na memória teria que concorrer com os demais dispositivos.
Na Figura (b) podemos ver um modelo onde existe um barramento exclusivo para a memória. Isso
torna o acesso à memória mais rápido uma vez que não existe concorrência.

4.3 DMA (Direct Memory Access)

Para ler ou escrever dados na controladora é usada a CPU, essa cópia é feita palavra por palavra,
esse tipo de abordagem acaba desperdiçar muitos ciclos de CPU, pois a CPU é sempre mais rápida
que o dispositivo. Para resolver essa questão, a ideia é usar outro dispositivo para fazer essa
transferência: O Controlador de DMA, a função dele é transferir dados entre o controlador de
dispositivos e a memória, nos dois sentidos.
O esquema de uso de DMA, pode ser distribuído, onde a controladora de dispositivo tem também
um controlador de DMA. Outro esquema, mais usado, é ter um controlador de DMA, único na placa
mãe, e este interage com os diferentes dispositivos.
O controlador de DMA é controlado através dos seus registradores internos. Um típico controlador
de DMA pode ter os seguintes registradores internos:
• Endereço de Memória: de onde ou para onde na memória
• Contador de Palavras: Quantas palavras serão transferidas
• Porta de E/S: de qual ou para qual dispositivo
• Sentido: Leitura ou escrita
4.3.1 Funcionamento

O controlador de DMA é programado pela CPU através de seus registradores internos. Então
sempre que a CPU desejar transferir dados entre memória e controlador de dispositivo através de
DMA, os seguintes eventos ocorrem:

1. A CPU Programa o controlador: Informa endereço na memória onde o dado será


armazenado, a quantidade de dados que será transferida, e o tipo de operação (leitura ou
escrita);
2. O controlador de DMA solicita o dado a controladora de dispositivo;
3. O controlador transfere o dado direto para a memória. (existem esquemas onde o dado
precisa passar por um registrador interno do controlador de DMA, isso tem vantagem de
poder fazer transferências diretas entre dispositivos ou memória para memória.
4. O controlador de Disco confirma a transferência, o Controlador de DMA decrementa o
contador e incrementa o endereço. Se o contador não for zero os eventos 2 a 4 ocorrem
novamente. Se o contador for zero o controlador de DMA então interrompe a CPU.
5 Sistemas de Arquivos

Todo sistema computacional deve ter uma forma de armazenamento de dados que possa garantir
que a informação sobreviva ao desligamento do sistema.
Os usuários querem ter uma forma efetiva de acessar seus arquivos sem ter que se preocupar onde
os seus dados vão ficar.
Para fixar o conceito imagine que na sua empresa existe um local para armazenar os seus
documentos pessoais, e que lá existe um armário com uma divisória para cada funcionário.
Em um primeiro caso poderíamos imaginar que os próprios funcionários teriam que armazenar os
seus documentos. Neste caso, a empresa teria que contar com o bom senso de seus colaboradores
para evitar eventuais desvios (documentação misturada, extravios, etc). Tanto nas empresas como
em um sistema operacional, essa gerencia baseada no bom senso não é uma boa ideia.
Segundo caso, imagine que a empresa contratou o FS (Francisco Silva), para armazenar seus
documentos no armário, você agora só precisa entregar os seus papéis ao FS, e ele vai providenciar
o armazenamento dentro dos padrões de conformidade. Quando você precisar da sua documentação
basta pedir ao FS que ele encontra para você e entrega. Em temos de Sistemas Operacionais o FS, é
o File System ou Sistema de Arquivos, responsável por prover o armazenamento e recuperação dos
dados.

5.1 Introdução

Para que os usuários possam acessar os seus dados, a maneira que os sistemas fazem isso hoje é
fornecer duas abstrações: Arquivos e Diretórios (também chamados de pastas).
Com essas abstrações os usuários conseguem localizar os seus dados em discos com grande
números de blocos apenas informando o diretório e o nome do arquivo. Esse é o principal papel do
sistema de arquivos.
Conforme o tempo passa os discos aumentam e os arquivos também. Os bons sistemas de arquivos
devem dar a possibilidade de armazenar grandes arquivos e acessar o seu conteúdo de forma rápida
e eficiente.
Outra característica de um bom sistema de arquivos é o fato de lidar com acessos concorrentes ao
mesmo dado. Em algum momento vários processos podem acessar simultaneamente um
determinado dado, para ler ou alterar o seu conteúdo.

Nomeação
Para acessar um determinado dado armazenado em sistema, o usuário (processo) deve informar o
diretório e o nome do arquivo, a partir daí a localização do dado fica por conta do usuário.
Os diferentes sistemas operacionais tratam essa nomeação de maneira semelhante, porém com
algumas particularidades que vamos citar aqui.
Os sistemas baseado no Unix, como por exemplo o Linux, possuem um esquema de nomeação onde
a “caixa” (maiúscula ou minúscula) determina arquivos diferentes, por exemplo: Teste.txt,
TESTE.TXT e teste.TXT são arquivos diferentes. Já para o MS/Windows esses arquivos
correspondem ao mesmo conjunto de dados.
Outra característica é a extensão: Sistemas baseados em Unix não se baseiam em extensão. Ou seja
o que vem depois do '.' é uma informação que é util apenas em nível de usuário. Pois o SO não vai
tratar o arquivo de uma maneira especial tendo como base a sua extensão.
Já o MS/Windows, por exemplo, só executa arquivos com determinadas extensões (com, exe, pif,
bat, etc).

Arquivos

Os sistemas operacionais mais modernos não se preocupam com a estruturação interna dos
arquivos, a consequência disto é que, o processo do usuário tem que se preocupar com a forma que
os arquivos estão estruturados. A Figura (a) ilustra essa situação. Windows e Linux se encaixam
nesta categoria.
Diferentemente dos atuais, nos sistemas operacionais mais antigos, o SO fornece uma estruturação
elementar para o conteúdo dos arquivos. Dois exemplos são dados, Figura (b), estruturação em
registros, e Figura (c) estruturação hierárquica.

Tipos de Arquivos
Muitos sistemas operacionais classificam os arquivos conforme a sua finalidade, outros podem
classificar conforme o seu conteúdo. Porém todos os sistemas apresentam pelo menos dois tipos de
arquivo: Texto com alguma codificação específica: ASC-II ou UTF-8, ou binários, arquivos com
bytes não “imprimíveis”, que tem a sua finalidade compreendida apenas pelos programas que o
usam.

Potrebbero piacerti anche