Baixe o app para aproveitar ainda mais
Prévia do material em texto
PDF gerado usando o pacote de ferramentas em código aberto mwlib. Veja http://code.pediapress.com/ para mais informações. PDF generated at: Fri, 06 Dec 2013 10:38:41 UTC Sistemas operacionais Conteúdo Páginas Introdução 1 História 2 Estruturas dos sistemas operacionais 2 Gerência de memória 5 Gerência de dispositivos de entrada e saída 15 Sistemas de arquivos 28 Sistemas embarcados 36 Referências Fontes e Editores da Página 44 Fontes, Licenças e Editores da Imagem 45 Licenças das páginas Licença 46 Introdução 1 Introdução O Software de computador pode ser dividido em dois tipos: programas de sistema e programas aplicativos. O principal programa de sistema é o sistema operacional, que controla todos os recursos do computador e fornece a base lógica sobre a qual os programas aplicativos são escritos. Sua principal função é isolar os programadores da complexidade do hardware. É importante salientar que o sistema operacional propriamente dito é aquela parcela que roda no modo kernel (supervisor). Os compiladores, editores e interpretadores de comando (Shell) executam no modo usuário. Há duas funções principais de um S.O.: •• máquina estendida: o S.O. deve apresentar ao usuário o equivalente a uma máquina estendida ou máquina virtual, teoricamente mais fácil de programar que o hardware; •• gerenciador de recursos: o S.O. deve oferecer uma alocação ordenada e controlada dos processadores, memórias e quaisquer dispositivos de E/S que os programas podem competir. Ou seja, o S.O. tem como função gerenciar eficientemente as diferentes partes do sistema. Existem quatro modelos de S.O.: •• sistemas monolíticos: o S.O. é escrito como uma coleção de procedimentos, que podem chamar quaisquer outros sempre que precisar, sem nenhum tipo de estrutura hierárquica; •• sistemas em camadas: é um S.O. organizado em uma hierarquia de camadas, construída uma sobre a outra; •• máquinas virtuais: formado por um monitor de máquina virtual, que rodava no hardware básico e coordenava a multiprogramação, fornecendo várias máquinas virtuais à camada superior (não máquinas estendidas, e sim cópias exatas do hardware básico); •• modelo cliente-servidor: minimização do kernel (através da remoção de código do S.O., movendo para as camadas mais altas), implementando as funções do S.O. como processos de usuário. Os processos de usuário (clientes) enviam requisições para os processos servidores, que realizam a operação e retornam a resposta necessária. Um S.O., tipicamente, tem quatro grandes componentes: gerenciamento de processos, gerenciamento de dispositivos de E/S, gerenciamento de memória e gerenciamento de arquivos. História 2 História Tradicionalmente, os S.O. podem ser divididos, historicamente, em quatro gerações: •• 1ª. Geração: os programadores desenvolviam o programa e as funções que, atualmente, estão sob a supervisão do S.O; •• 2ª. Geração: o sistema de processamento em lote, que constituía no armazenamento prévio de diversos jobs para serem processados sequenciamente no computador, marcou esta geração. Um job só iniciava seu processamento quanto o seu antecessor terminava; • 3ª. Geração: desenvolvimento do conceito de multiprogramação, ou seja, a partição da memória do computador em diversas parcelas para que múltiplos jobs pudessem ser executados, dando a sensação para o usuário de um paralelismo não existente. Por exemplo, enquanto um job esperava por uma operação de E/S (potencialmente mais demorada), a CPU poderia realizar o processamento de outro job já armazenado na memória; • 4ª. Geração: com o surgimento das estações de trabalho e dos computadores pessoais, o desenvolvimento de interfaces gráficas se torna comum. As redes de computadores impulsionam o surgimento de sistemas operacionais de rede e os sistemas operacionais distribuídos. Estruturas dos sistemas operacionais Um sistema operacional fornecia o ambiente no qual os programas (softwares) são executados. Os SOs variam internamente entre si devido às diversas necessidades e restrições de softwares e hardwares. Estruturas de Sistemas Operacionais Sistemas monolíticos Um micro-computador PC XT rodando o MS DOS 5.0. Também conhecida como estrutura simples, esta é a estrutura dos primeiros SO’s. Consistida, basicamente, por um programa dividido em sub-rotinas, na estrutura monolítica é permitido a qualquer uma dessas sub-rotinas em qualquer parte do programa chamar outra(s) sub-rotina(s). A construção do programa final é dada com base nos módulos compilados separadamente, unidos através de um linker. A boa definição de parâmetros de ligação entre as diferentes rotinas existentes aumenta e muito o desempenho, porém o sistema pode parar devido a algum erro ocasionado por uma dessas rotinas. A exemplo temos o próprio UNIX, o MS DOS, o FreeBSD, dentre outros. Sistemas em camadas Devido ao crescimento das necessidades dos utilizadores e o aperfeiçoamento dos sistemas, foi-se necessário a modularização da organização do sw do SO. Na abordagem em camadas, o SO é particionado em níveis, onde o nível mais “baixo” é o hw, e o nível mais “alto” é a interface com o usuário. A principal vantagem dessa estrutura é justamente a modularização, facilitando sua alteração e depuração de cada camada, além de criar uma hierarquia de níveis de acesso que permite proteger as camadas mais internas. Estruturas dos sistemas operacionais 3 As camadas são selecionadas de tal modo que cada uma delas opere diretamente com a camada seguinte de nível mais baixo. Foi originado na Holanda por Edsger Dijkstra, que utilizou o algoritmo de busca de menor caminho, também de sua própria autoria, para percorrer dentre as várias camadas, as que atenderão as solicitações de “cima”, de maneira mais eficiente. Uma desvantagem desta estrutura é o tempo de resposta ao usuário, pois numa requisição do mesmo, uma camada irá se comunicar com a outra diretamente seguinte, e assim por diante, possibilitando a modificação de parâmetros a cada camada, necessidade de dados e ainda o acréscimo de overhead à chamada do sistema, levando, contudo, ao consumo maior de tempo do que nos SO’s não estruturados em camadas. Por sua vez, tal estrutura tem uma vantagem maior do ponto de vista tanto do projeto quanto da implementação, pois a impossibilidade de comunicação direta das aplicações de cima com as de baixo, leva a um controle maior do SO sobre o hw. A exemplo temos o Windows NT, o THE e o MULTICS. Máquina Virtual Uma máquina virtual é uma cópia via software que busca simular uma máquina real. Uma máquina virtual (Virtual Machine – VM) pode ser definida como “uma duplicata eficiente e isolada de uma máquina real”. A IBM define uma máquina virtual como uma cópia isolada de um sistema físico, e esta cópia está totalmente protegida. Ao invés de ser uma máquina real, isto é, um computador real, feito de hardware e executando um sistema operacional específico, uma máquina virtual é um computador fictício criado por um programa de simulação. Sua memória, processador e outros recursos são virtualizados. A virtualização é a interposição do software (máquina virtual) em várias camadas do sistema. É uma forma de dividir os recursos de um computador em múltiplos ambientes de execução. lancia delta integrale Sistemas Cliente-Servidor Sistemas Cliente-Servidor são modelos de computação que distinguem dois tipos básicos de equipamentos computacionais: servidores e clientes, sendo interligados entre si geralmente utilizando-se uma rede de computadores. Neste modelo, geralmente os servidores agregam as funções mais importantes do sistema, deixando aos clientes apenas o processamento de aplicações mais básicas. As principais características deste tipo de sistema são: •• Elevar a camada onde são implementadas as funções normalmente efetuadas pelo sistema operacional •• Reduzir as funções do sistema operacional •• Tornar menor e de maisfácil a manutenção cada parte do sistema operacional Utilização dos recursos de sistemas Monoprogramação ou monotarefa Em computação, chama-se monotarefa um sistema operacional que permite a realização de apenas uma tarefa (job) de cada vez. O processador, memória e periféricos ficam dedicados a um único usuário, e cada tarefa para ser executada, deve aguardar o encerramento da tarefa atual. Nos sistemas monoprogramados, enquanto uma aplicação aguarda um evento, o processador pode permanecer ocioso, sem realizar qualquer tipo de processamento, a memória pode acabar sendo sub-utilizada quando o programa não a utiliza totalmente e os periféricos são dedicados a um único usuário. Desta forma, os sistemas monoprogramáveis acabam sendo por sua natureza de fácil implementação e com pouca preocupação com proteção. Estruturas dos sistemas operacionais 4 Multiprogramação ou multitarefa Multiprogramação ou Multitarefa é o nome dado à característica de alguns sistemas operacionais de rodar diversas aplicações simultâneas. Na realidade, na execução multitarefa, o tempo do processador é dividido entre as aplicações em execução, e a execução das tarefas passa rapidamente de uma para a outra, criando a ilusão de que as aplicações ocorrem de forma conjunta. Tipos de Sistemas Operacionais Sistemas Batch Os sistemas batch ou sistemas em lote foram os primeiros sistemas multiprogramáveis a serem implementados (primeira fase da computação), caracterizando-se por programas armazenados em disco ou fita, que uma vez iniciados, exigem pouca ou nenhuma interação do usuário, processando de forma sequencial e contínua até o fim do serviço (job), quando então é devolvido o resultado final do processamento. O tempo de execução da tarefa é conhecido como turnaround. Sistemas multiprogramados Nos sistemas monoprogramados o que temos é a existência de um único processo sendo executado de cada vez na memória. Com a multiprogramação existem vários processos na memória aptos à executar e um em execução. Sem dúvida, o conceito de multiprogramação é um dos mais importantes nos sistemas operacionais modernos. Se existirem vários programas carregados na memória ao mesmo tempo, a CPU pode ser compartilhada entre eles, aumentando a eficiência da máquina e produzindo mais resultados em menos tempo. A idéia por detrás da multiprogramação é bastante simples. Quando um programa libera a CPU, seja para realizar alguma operação de E/S ou por outro motivo, ela fica parada. Enquanto espera que o programa volte para executar, a CPU não realiza nenhum trabalho útil. Para acabar com a ociosidade deste tempo vários programas são mantidos ao mesmo tempo na memória e o sistema operacional se encarrega de escolher um deles para executar. Assim, sempre que um programa é interrompido, um outro é escolhido para ser executado em seu lugar. Com isso, a CPU estará durante grande parte do tempo ocupada processando instruções de programas. Os benefícios da multiprogramação são vários: aumento da utilização da CPU e da taxa de saída do sistema computacional, isto é, da quantidade de trabalho realizada dentro de um intervalo de tempo (throughput). Sistemas de Tempo Compartilhado (Time Sharing) São sistemas que compartilham o tempo de uso da CPU entre diversos programas. Também conhecido como time-sharing, consegue executar diversas tarefas simultaneamente, pois existe a divisão do tempo do processador em pequenos intervalos, denominados fatia de tempo. Caso a tarefa não termine durante a fatia a ela determinada, há uma interrupção e ela volta para a fila de escalonamento, aguardando novamente sua vez. Diferente do sistema batch, esse tipo de sistema operacional permite a interação do usuário. Dessa maneira, os terminais possuem teclado, vídeo e mouse. Estruturas dos sistemas operacionais 5 Sistemas de Tempo Real São sistemas no qual o tempo tem uma função essencial. Em geral, um ou mais dispositivos físicos externos ou computador geram estímulos, e o computador deve reagir apropriadamente a eles dentro de um dado intervalo de tempo. Sistemas multiprocessados Sistemas multiprocessados são sistemas construídos sobre máquinas computacionais que possuem mais de um processador para propósitos gerais. Entre suas vantagens estão: • Maior produção (throughput) •• Reconfiguração •• Balanceamento •• Simetria Acoplamento-Sistemas multiprocessáveis Modo de comunicação entre os processadores e o grau de compartilhamento de memória e dos dispositivos de entrada/saída. Chamadas ao Sistema Conhecidas como system calls, são instruções que um programa utiliza para se comunicar com o Sistema Operacional e acessar seus serviços. O aplicativo "chama" o S.O., requisitando algo. Gerência de memória A maioria dos computadores trabalha com o conceito de hierarquia de memória, possuindo uma pequena quantidade de memória cache, muito rápida, uma quantidade de memória principal (RAM) e uma quantidade muito grande de memória de armazenamento em disco (HD), considerada lenta. O problema básico para o gerenciamento de memória é que os programas atuais são muito grandes para rodarem, completamente, na memória cache. O gerenciador de memória deve ser capaz de controlar parte da memória está em uso (e quais não estão), alocar memória para processos quando eles necessitam e desalocar quando eles terminam e, principalmente, gerenciar a troca entre a memória principal e o disco, quando a memória principal é muito pequena para armazenar todos os processos. Existem dois tipos de memória principal: a memória lógica e a memória física. A memória lógica é aquela manipulada pelos programas, ela é visível para os programas; sempre que um programa necessita alocar um espaço na memória esse espaço é alocado em memória lógica. A memória física é a memória implementada pelos circuitos integrados é nela que os espaços alocados em memória lógica vão realmente residir, portanto a memória física tem tamanho menor que a memória lógica, geralmente. Para isso é necessário realizar uma tradução de endereços lógicos para endereços físicos, pois assim um programa que aloca uma memória lógica possa ter de fato uma memória física alocada para si. Esse processo de tradução de endereços lógicos em endereços físicos é realizado por uma unidade de gerência de memória chamada MMU (Memory Management Unit). Gerência de memória 6 Memória lógica x Memória física Os processos não enxergam a memória física, hardware usado para endereçar os circuitos integrados de memória, e sim a memória lógica, que é a memória capaz de ser endereçada e acessada pelo conjunto de instruções do processador, sendo que cada processo possui a sua memória lógica que é independente da memória lógica dos outros processos. A memória física é implementada pelos circuitos integrados de memória, pela eletrônica do computador. Ela possui espaço de endereçamento físico que é o conjunto formado por todos os endereços dos circuitos integrados que formam a memória, normalmente esses endereços são em formato hexadecimal. A memória lógica possui um espaço de endereçamento lógico, maior que o espaço de endereçamento físico, é formado por todos os endereços lógicos gerado pelo processo, sendo gerado pela CPU e único por processo. Como o processo "enxerga" endereço de memória lógico e o hardware "enxerga" endereço de memória físico é necessário ter a conversão de endereço de memória lógico para endereço de memória físico. Esse mapeamento de endereço lógico em endereço físico é feito pela MMU, unidade de gerência de memória. Basicamente a MMU que vai mapear os endereços lógicos gerados pelos processos nos correspondentes endereços físicos que serão enviados para a memória. Existem duas formas bem simples de transformação do endereço lógico para o físico: •• A MMU verifica se o endereço lógico é maior que o registrador limite inferior e menor que o registrador limite superior, se sim encaminha o acesso com esse endereço válido,se não, gera uma interrupção de endereçamento inválido. Nesse caso o endereço lógico é igual ao endereço físico. •• A MMU verifica se o endereço lógico é menor que o registrador limite superior, se sim adiciona o registrador base ao endereço lógico e encaminha o acesso com esse endereço resultante, se não gera interrupção de endereçamento inválido. Nesse caso o endereço lógico é diferente do endereço físico. A MMU consiste de um chip ou uma coleção de chips. Modelo de memória de processos Para que um programa seja executado ele precisa ser transformado em processo(s), assim é necessário alocar o descritor de processos, alocar espaço na memória para o código (área conhecida como TEXT, onde se localiza o programa principal, as funções e as bibliotecas estáticas), os dados (Data, área onde as variáveis são alocadas - globais, locais estáticas, buffers internos)e a pilha (que possui o HEAP, área onde se localiza as variáveis dinâmicas, e o STACK, endereços de retorno de chamadas e parâmetros de funções). A atribuição de endereço físico para as áreas de código e áreas de dados pode ser feita de três formas: em tempo de compilação, em tempo de carga e em tempo de execução. Em tempo de compilação o programador já faz a conversão de endereço lógico em endereço físico, pois ele tem conhecimento de qual área da memória ira utilizar. Em tempo de carga o código precisa ser relocável de forma que todas as referências a memória sejam corrigidas para que o endereço de carga corresponda (carregador relocador), em outras palavras no momento da carga o programa executável é interpretado e os endereços corrigidos, dispensando a MMU. Em tempo de execução tem-se o código absoluto e é realizada uma relocação dinâmica usando a MMU, não sendo necessário corrigir os endereços no momento da carga do programa em memória. Gerência de memória 7 Gerenciamento Básico de Memória Os Sistemas de Gerenciamento de Memória podem ser divididos em duas classes: aqueles que levam e trazem processos entre a memória principal e o disco durante a execução (fazendo troca de processos e paginação) e aqueles que mantém os processos fixos em memória primária. As próximas seções apresentam os mesmos. Monoprogramação A monoprogramação consiste em executar um processo por vez na memória, dessa forma todos os recursos de hardware são exclusivos para execução do mesmo. Monoprogramação sem troca ou paginação Este é o esquema mais simples possível: só é possível executar um programa de cada vez, compartilhando a memória entre o programa e o S.O. Existem três variações para este modelo: •• O SO é carregado na parte inferior da memória, em RAM (Random Access Memory), e deixa a parte superior da memória disponível para o processo do usuário. O endereçamento por parte do processo usuário inicia do fim da RAM até o limite da memória. •• O SO é carregado na parte superior da memória, em ROM (Read-Only Memory), e deixa a parte inferior da memória disponível para o processo do usuário. O endereçamento do processo usuário vai do endereço 0 ao início da ROM. •• Os drives do SO são carregados em ROM (parte superior) e o restante do SO é carregado em RAM (parte inferior). Quando o sistema está organizado desta maneira, somente um processo por vez pode estar executando, desta forma esse tipo de sistema é usado em aplicações de caráter muito específico, como por exemplo sistemas de controle de temperatura ou pressão. Multiprogramação A multiprogramação nada mais é que manter diversos processos na memória, e essa memória precisa ser dividida de maneira eficiente para que possamos manter o número máximo de processos. Existem diversas técnicas para gerenciar memória que variam de acordo com o hardware do processador. Multiprogramação com Partições Fixas A maneira mais simples de implementar a multiprogramação, em termos de memória, é dividir a mesma, primeiramente em uma parte para uso do sistema operacional e outra para uso dos processos de usuários. Depois, a parte dos usuários é dividida em n partições de tamanhos diferentes, porém com valores fixos. Quando um programa chega, há duas possibilidades: ele é colocado em uma fila de entrada da menor partição capaz de armazená-lo ou ele é colocado em uma fila de entrada única. Com o esquema das partições de tamanho fixos, qualquer espaço não ocupado por um programa é perdido. Na maioria das vezes o programa a ser executado é menor do que a partição alocada para ele. A partição alocada não pode ser menor que o tamanho do programa e é improvável que o tamanho do programa seja exatamente igual ao da partição alocada. Assim, é muito provável que ocorra desperdício de memória para cada programa alocado. Esse desperdício é chamado fragmentação interna, ou seja, perde-se memória dentro do espaço alocado ao processo. Há outra possibilidade de desperdício de espaço de memória, chamada de fragmentação externa. Ela ocorre quando se desperdiça memória fora do espaço ocupado por um processo. Por exemplo, suponha que há duas partições disponíveis e o processo necessita de uma partição de tamanho maior que qualquer uma das duas livres, e ainda, menor que o total de memória livre, somando-se o tamanho de todas partições livres. Neste caso, o processo não será executado devido ao esquema que a memória é gerenciada, mesmo que exista memória total livre disponível. Gerência de memória 8 Outra desvantagem de classificar os programas em entradas separadas é apresentada quando uma fila para uma partição grande está vazia e filas para partições pequenas estão muito cheias. Uma possível alternativa é colocar todos os programas em uma única fila de entrada e sempre que uma partição encontrar-se livre, alocar para o próximo programa da fila. Para não desperdiçar espaço pode-se realizar uma pesquisa para selecionar o programa que melhor se ajuste ao tamanho da partição. No entanto, isto pode deixar programas pequenos de fora, o que também é indesejável. Neste caso, é interessante dispor de pelo menos uma partição pequena para programas pequenos ou criar uma regra que limite o número de vezes que um programa pode ser ignorado, obrigando que o mesmo seja selecionado em um determinado momento. Dois conceitos importantes devem ser introduzidos quando há ocorrência de multiprogramação: realocação e proteção. Programas (jobs) diferentes são colocados em endereços diferentes (partições). Quando um programa é vinculado, o linkeditor deve saber em que endereço o programa deve começar na memória. Como o gerenciador de memória só decide em qual partição (endereço) o programa vai executar quando este chegar, não há garantia sobre em qual partição um programa vai realmente ser executado. Este problema é conhecido como realocação: modificação dos endereços especificados dentro do programa de acordo com a partição onde ele foi colocado. Outra questão importante está na proteção: programas diferentes não podem ter acesso a dados e/ou instruções fora de sua partição. Sem esta proteção, a construção de sistemas maliciosos seria facilitada. Uma possível alternativa para ambos os problemas é equipar a máquina com dois registradores especiais de hardware chamados registradores de base (RB) e registradores de limite (RL). Quando um processo é agendado, o registrador de base é carregado com o endereço de início de sua partição e o registrador de limite com o comprimento de sua partição. Assim, instruções são verificadas em relação ao seu endereço de armazenamento e para verificar se o mesmo não está fora da partição. O hardware protege os RB e RL para impedir que programas de usuário os modifiquem. Multiprogramação com Partições Variáveis Nesse modelo, o tamanho das partições são ajustados de acordo com as necessidades dos processos. Os espaços livres na memória física são mantidos pelo sistema operacional em uma lista, chamada de lista de lacunas. Quando um processo é criado essa lista é percorrida em busca de uma lacuna de tamanho maiorou igual ao requisitado pelo processo, se a lacuna possuir um tamanho maior do que o necessário, será criada uma nova lacuna com a porção extra, dessa forma, o processo receberá o tamanho exato de que necessita. Existem quatro formas de percorrer a lista de lacunas: • First-Fit: utiliza a primeira lacuna com tamanho suficiente; • Best-Fit: utiliza a lacuna que possuir a menor sobra; • Worst-Fit: utiliza a lacuna que possuir a maior sobra; • Circular-Fit: igual ao First-Fit, mas inicia a procura na lacuna seguinte à última sobra. Quando o processo termina, e a memória é liberada, é criada uma nova lacuna. Se essa lacuna for adjacente a outras, elas são unificadas. Com as partições variáveis deixa-se de ter fragmentação interna mas continua com a fragmentação externa (espaços vazios não contíguos), uma solução para resolver este problema seria relocar as partições de forma a eliminar os espaços entre partições criando uma única área contígua porém essa solução consome muito o processador e o acesso ao disco, visto que a cada acesso na memória seria necessário verificar a possibilidade de realocação. Gerência de memória 9 Gerenciamento de memória livre Além de gerenciar quais espaços em memória estão em uso, é também necessário controlar os espaços de memória livres. Existem duas técnicas mais utilizadas para resolver este problema, estas serão vistas nas próximas seções. Gerenciamento de memória livre com mapas de bits Com mapas de bits, a memória é dividida em unidades de alocação. Cada bit do mapa representa uma unidade de alocação, sendo que se o bit for 0, a unidade está livre; caso contrário, a unidade está ocupada. Quanto menor for a unidade de alocação, maior será o mapa de bits e vice-versa. O maior problema com os mapas de bits é que procurar uma lacuna (seqüência de 0s) suficientemente grande para um determinado processo pode ser uma operação muito lenta. O SO mantém um 1 bit para indicar se cada bloco da memória (ou unidade de alocação) está ocupado (1) ou livre (0). A Memória é dividida em unidades de alocação. Considerações sobre o tamanho do bloco de memória: Quanto menor a unidade de alocação, maior será o mapa de bits. - Pequeno: necessidade de muitos bits ⇒ uso ineficiente da memória. Exemplo: se tamanho do bloco = 1 byte, 1/9 da memória serão utilizados para o mapa de bits. - Grande: memória sub-utilizada, pois se o tamanho do processo não for múltiplo do tamanho da unidade de alocação, uma quantidade de memória considerável será desperdiçada no último bloco. Vantagens do uso de mapa de bits: •• Simplicidade: o tamanho do mapa depende apenas do tamanho da memória e das unidades de alocação. Desvantagens: •• Quanto um processo necessita de k unidades de alocação, o gerenciador de memória deve encontrar uma sequência de k bits 0, o que se constitui um processo lento. Gerenciamento de memória livre com listas encadeadas Neste caso, é mantida uma lista encadeada com os segmentos de memória livres e encadeados. Uma possível configuração seria manter, em cada entrada, o endereço em que inicia, o seu comprimento e, evidentemente, o ponteiro para a próxima entrada. A principal vantagem de utilizar uma lista encadeada classificada por endereço é que sua atualização é simples e direta. Vários algoritmos podem ser utilizados para encontrar uma lacuna de memória para alocação de um processo: 1.1. Primeiro ajuste: varre a lista desde o início e aloca no primeiro espaço (lacuna) suficientemente grande; 2.2. Próximo ajuste: varre a lista da posição atual e aloca no primeiro espaço suficientemente grande; 3.3. Melhor ajuste: varre a lista completamente e aloca no espaço que gerar a menor lacuna de memória; 4.4. Pior ajuste: varre a lista completamente e aloca no espaço que gerar a maior lacuna de memória disponível, de modo que a lacuna resultante possa ser suficientemente grande para ser útil; 5.5. Ajuste rápido: mantém diversas listas separadas para os tamanhos de processos mais comuns. Memória Virtual A base do funcionamento da Memória Virtual é o Princípio da Localidade que estabelece que há uma tendência que os futuros endereços de memória de instruções e dados sejam próximos a endereços de memória recentemente acessados. Esse comportamento se deve as características peculiares aos programas, que frequentemente fazem uso de endereços em sequência (vetores), localizados em blocos de código bem definidos e frequentemente invocados (funções), ou de códigos repetitivos (laços de repetição). A ideia básica da memória virtual é que o tamanho combinado do programa, dos seus dados e da pilha pode exceder a quantidade de memória física disponível para ele, ou seja, neste caso, a simples troca, vista anteriormente, não Gerência de memória 10 resolveria o problema. O Sistema Operacional, então, mantém partes do programa atualmente em uso, em forma de páginas ou segmentos, na memória principal e o restante em disco. Essas páginas/segmentos são "trocados" entre memória principal e secundária conforme o SO as solicita, conforme a demanda do programa. A memória virtual também pode trabalhar em um sistema de multiprogramação, com pedaços de vários programas na memória simultaneamente. Enquanto um programa está esperando parte dele próprio ser trazido para a memória (ele fica esperando a E/S e não pode executar) a CPU pode ser dada a outro processo, assim como em qualquer sistema de multiprogramação. Para a implementação desta técnica, alguns recursos mínimos são necessários: localização da página através do hardware MMU, carga de página, substituição de página e área de troca, partição ou arquivo especial de troca (swap ou página) destinada a armazenar páginas. Muitos sistemas de Memória Virtual utilizam uma técnica denominada paginação, vista mais adiante. Troca (Swapping) Em algumas situações não é possível manter todos os processos na memória e uma solução para essas situações é o mecanismo conhecido como swapping (troca). A gerência de memória reserva uma área do disco para esse mecanismo, que é utilizada para receber processos da memória. A execução desse processo é suspensa, com isso é dito que o mesmo sofreu uma swap-out. Mais tarde, esse mesmo processo será copiado do disco para a memória, mecanismo conhecido como swap-in. Esse mecanismo de trocas de processos no disco tem como objetivo permitir que o sistema operacional consiga executar mais processos do que caberia na memória. Esse processo gera um grande custo de tempo de execução para os programas. Fazer a cópia do processo da memória para o disco e depois fazer o inverso é demorado. Paginação O espaço de endereço virtual é dividido em unidades chamadas páginas. As unidades correspondentes na memória física são chamadas molduras de página (ou quadros). As páginas e as molduras (quadros) têm sempre exatamente o mesmo tamanho. No espaço físico (memória) tem-se várias molduras de página. Por exemplo, podem existir 05 páginas situadas no espaço de endereço virtual que são mapeadas na memória física. No entanto, o espaço de endereço virtual é maior que o físico. As outras páginas não são mapeadas. No hardware real, um bit presente/ausente em cada entrada monitora se a página é mapeada ou não. Quando um programa tenta utilizar uma página não mapeada em uma moldura, a MMU detecta o acontecimento (que a página não está mapeada) e gera uma interrupção, passando a CPU para o Sistema Operacional. Tal interrupção é chamada falha de página. O S.O., então, seleciona uma moldura de página pouco utilizada e grava o seu conteúdo de volta ao disco, substituindo-a pela página requisitada. Quanto à forma como a paginação pode ser implementada, podemos considerar a paginação simples e a paginação por demanda. Na primeira, todas as páginas lógicas do processo são mapeadas e carregadas para a memória física, isso supondo-se que o espaço de endereçamento de memória para um processo tenha o tamanho máximo igual à capacidade da memória física alocadapara processos. No caso da paginação por demanda, apenas as páginas lógicas efetivamente acessadas pelos processo são carregadas. Nesse caso, uma página marcada como inválida na tabela de páginas de um processo pode tanto significar que a página está fora do espaço lógico de endereçamento do processo ou que simplesmente a página ainda não foi carregada. Para descobrir qual das situações é a verdadeira basta conferir o descritor de processo, que contém os limites de endereçamento lógico do processo em questão. Gerência de memória 11 Tabelas de Página O propósito de tabelas de página é mapear páginas virtuais em molduras de página. No entanto, existem duas questões que devem ser consideradas: •• A tabela de páginas pode ser extremamente grande, sendo que cada processo necessita de sua própria tabela de páginas; •• O mapeamento deve ser rápido: o mapeamento do virtual para o físico deve ser feito em cada referência da memória, o que pode ocorrer diversas vezes em uma única instrução,não devendo tomar muito tempo para não se tornar um gargalo na execução da instrução. Neste caso, há a necessidade de um mapeamento de páginas rápido e grande. Existem duas formas básicas de projetar tabelas de páginas: 1.1. ter uma única tabela de páginas, através de uma matriz de rápidos registradores de hardware, com uma entrada para cada página virtual, indexada pelo número da página. Esta é uma solução cara se a tabela de páginas é grande; 2.2. manter a tabela de páginas inteiramente na memória principal, sendo que o hardware precisa de apenas um registrador que aponta para o início da tabela de páginas. Esta última solução possui algumas variações que têm desempenho melhor. Uma das propostas que busca evitar o problema de ter enormes tabelas de páginas na memória todo tempo é a de Tabelas de Páginas Multinível. Neste caso, existe uma tabela de primeiro nível e diversas tabelas de segundo nível. O importante aqui é que somente as tabelas mais utilizadas estão presentemente na memória. As demais se encontram em disco. Apesar de permitir um espaço de endereçamento muito grande, o espaço ocupado de memória principal é muito pequeno. O sistema de tabela de páginas de dois níveis pode ser expandido para três, quatro ou mais níveis, sendo que níveis adicionais dão mais flexibilidade, mas a complexidade da implementação acima de três níveis dificilmente vale a pena. Em relação aos detalhes de uma única entrada de uma tabela de páginas, seu arranjo pode depender da máquina, mas os tipos de informação usualmente são os mesmos. O campo mais importante é o número da moldura de página, pois o objetivo do mapeamento de páginas é localizar este valor. Ao lado dele, tem-se o bit de presente/ausente. Se este bit for 1, significa que a entrada é válida e pode ser utilizada. Se for 0, a página virtual a que esta entrada pertence não está atualmente na memória. Ao acessar uma entrada da tabela de páginas com este bit configurado como zero ocorrerá uma falha de página. Os bits "proteção" informam que tipos de acesso são permitidos. Em sua forma simples, este campo contém apenas um bit, com 0 para leitura/gravação e 1 par leitura somente. Um arranjo mais sofisticado é manter 3 bits, cada um para habilitar leitura, gravação e execução da página. Os bits "modificada" e "referenciada" monitoram a utilização da página. Ambos os bits tem como objetivo auxiliar no momento da substituição de páginas. O último bit permite que o cache seja desativado para a página, recurso importante para páginas que são mapeadas em registradores de dispositivo em vez da memória. Alguns bits auxiliares são, normalmente, adicionados na tabela de páginas para facilitar na substituição de páginas quando a memória física estiver cheia e for necessário retirar uma página lógica da memória física para alocar outra página lógica. Tem-se o bit de modificação (dirty bit) assim que a página for carregada tem valor zero se a página for alterada, na memória física, altera-se o valor para 1, portanto se a página for a página vítima e o bit de modificação for zero não será necessário fazer a cópia da página lógica em memória para a página lógica em disco pois as duas são iguais. Bit de referência: é zero assim que a página lógica é alocada na página física, se a página for acessada altera o valor para um (a MMU altera o valor). Bit de trava: usado em páginas que não podem sair da memória física, o Sistema Operacional "tranca" uma página lógica na memória física ativando esse bit. Gerência de memória 12 TLBs – Translation Lookside Buffers – Memória Associativa A TLB, também conhecida como memória associativa, é um dispositivo de hardware cujo propósito é mapear endereços virtuais em endereços físicos sem passar pela tabela de páginas. Usualmente, ela faz parte da MMU. Ela constitui-se de um banco de registradores que armazenam um pequeno número de entradas, muito rápidas, contendo as 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 (hit), a moldura de página é tomada diretamente da TLB sem a necessidade de passar pela tabela de páginas na memória (mais lento). Caso contrário (miss), a pesquisa é feita normalmente na tabela de páginas presente na memória. Então, uma das entradas é removida da TLB e a entrada da tabela de páginas pesquisada é colocada em seu lugar. A TLB melhora bastante o desempenho no acesso à tabela de páginas, visto que registradores são muito mais rápidos que a memória RAM. Suas desvantagens estão em seu custo (registradores são caros), seu tamanho limitado e o fato de existir uma única TLB na MMU, sendo esta compartilhada por todos os processos. Para calcularmos o desempenho da TLB, podemos tomar h como taxa de acerto (taxa em que a página necessária estará na TLB). Então o erro seria 1-h. Sendo assim, a tempo de acesso hit (tempo necessário para pegar a página da TLB) é dada pelo tempo de acesso à TLB mais o tempo de acesso à memória uma única vez. Enquanto o tempo de acesso miss (quando falta a página na TLB) é dada pelo tempo de acesso à TLB mais o tempo de dois acessos à memória. O tempo de acesso médio é dado pelo tempo de acesso hit multiplicado por h somado do tempo de acesso miss multiplicado por (1-h). Resumindo em fórmulas, temos: •• TacessoHit = TacessoTLB + TacessoMemoria •• TacessoMiss = TacessoTLB + TacessoMemoria + TacessoMemoria •• TacessoMedio = h x TacessoHit + (1-h) x TacessoMiss A taxa de acerto (h) depende do tamanho da TLB e do algoritmo que a controla, mantendo as páginas mais utilizadas. Tabelas de Páginas Invertidas Outra abordagem para trabalhar com páginas é manter uma tabela onde cada entrada representa uma moldura de página ao invés de um endereço virtual. Desta forma, a entrada deve monitorar qual página virtual está associada àquela moldura de página. Embora as tabelas de páginas invertidas economizem quantidade significativas de espaço (pelo menos nas situações em que o espaço de endereço virtual é muito maior que a memória física), elas tem a desvantagem de que o mapeamento (tradução) do endereço virtual para o físico é mais complexo e potencialmente mais lento. Uma forma de facilitar a tradução do virtual para o físico é a utilização da TLB pesquisada por software. A pesquisa pode ser feita a partir de um encadeamento de páginas páginas virtuais que possuam um mesmo endereço hash. Tamanho de página Um ponto do qual o projetista deve se preocupar é com o tamanho da página. Conforme visto anteriormente, se esse tamanho de página for grande, pode ocorrer de o processo utilizador não ocupar todo o espaço a ele destinado. Se a página tiver um tamanho demasiadamente pequeno, a tabela de páginas será muito grande. É possível uma modelagem matemática. Considere que cada processo tenha tamanho de s bytes, e cada página tenha tamanho de p bytes. A tabela de páginas terá um espaçode e bytes por entrada. Assim, o numero de páginas que um processo precisará é de s/p. O espaço que esse processo ocupa na tabela de páginas é s*e/p. O tamanho perdido na última página devido a fragmentação interna será de p/2. Assim, haverá um custo de s*e/p + p/2 da tabela de páginas. Para que o tamanho da página seja ideal, o custo será zero. Dessa forma, derivando a expressão anterior e igualando a zero obtemos que o tamanho ideal de página é de s*e*sqrt(2). Gerência de memória 13 Thrashing Estado no qual o sistema operacional ao invés de executar instruções efetivas "gasta" tempo efetuando a troca de páginas entre memória física e memória lógica, em outras palavras desperdiça um tempo significante trazendo ou removendo páginas da memória. Para o usuário a sensação é que o sistema está travado ou congelado e para o hardware há um significante acesso ao disco ao invés de processamento. 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). Veja que o algoritmo escolhido afeta diretamente o desempenho do sistema como um todo, pois "uma escolha errada significa que a página removida será novamente acessada em seguida, gerando uma nova falta de página. É importante que o algoritmo usado seja capaz de remover da memória física páginas que provavelmente não serão necessárias em seguida."[R. da S. Oliveira, A. da S. Carissimi e S. S. Toscani; Sistemas Operacionais 2ª ed] Os algoritmos de substituição de páginas se preocupam em escolher a melhor página a ser retirada da moldura. Existem várias alternativas: • algoritmo de substituição de página ó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; •• algoritmo de substituição de página não recentemente utilizada(NRU): o S.O. e o hardware mantêm 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; • algoritmo de substituição de página “primeira a entrar, primeira a sair (FIFO – first-in first-out): a página mais antiga é removida.No entanto, pode estar sendo removida uma página bastante utilizada; •• algoritmo de substituição de página de segunda chance(SC): uma modificação do algoritmo FIFO, que busca não substituir uma página antiga e, no entanto, 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; • algoritmo de substituição de página menos recentemente utilizada (LRU – least recently used): a idéia é 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. • algoritmo de substituição de página relógio: O algoritmo SC, apesar de mais eficiente do que algoritmo FIFO, reinsere págimas no final da lista constantemente. Uma solução para isso é q a lista seja ordenada em uma circularmente tal como um relógio. O ponteiro do relogio aponta para a pagina mais antiga e assim que ocorrer uma falta a pagina mais antiga é inspecionada. Se o bit R dessa pagina for 0 ele é substituida, se não esse bit é setado como 0 e o ponteiro aponta para a proxima pagina mais antiga. Esse proesso é então repetido até a proxima pagina com o bit 0 ser encontrada. •• algoritmo de substituição de página menos recentemente utilizada(MRU):Trabalha de forma oposta ao algoritmo otimo, pois há a possibilidade de que as paginas que não foram referenciadas continuem não sendo referenciadas. A tarefa de implementa-ló é trabalhosa mas possivel. Ele pode ser implementado de uma maneira mais simples com um contador de 64-bits que é incrementado automaticamente após cada intrução e a tabel de paginas deve ter um campo extra para armazenar o valor do contador. O valor é então armazenado neste campo correpondente à pagina que acabou de ser referênciada. Quando o corre a falta o S.O. examina esse campo e substitui a pagina que tiver o menor deles.Pode-se tambem implementalo com o auxílio de um hardware especial. Gerência de memória 14 Segmentação A memória virtual apresentada anteriormente é unidimensional, ou seja, os endereços virtuais vão de 0 até algum valor máximo. No entanto, em alguns casos, ter dois ou mais espaços de endereços virtuais separados é uma estratégia interessante. A segmentação prove à máquina vários espaços de endereço completamente independentes, chamados segmentos, liberando o programador da tarefa de gerenciar a expansão e a contração de tabelas, da mesma forma que a memória virtual elimina a preocupação de organizar o programa em overlays. Os comprimentos de cada segmento podem ser diferentes e podem variar durante a execução. Como cada segmento constitui um espaço de endereçamento completamente independente e diferente, eles podem aumentar ou encolher sem afetar um ao outro. Para especificar um endereço neste tipo de memória segmentada, o programa deve fornecer um endereço de duas partes: um número de segmento e o endereço dentro do segmento. É importante salientar que cada segmento pode conter várias páginas, logo, toda a discussão apresentada anteriormente sobre paginação continua válida aqui. Outra questão fundamental é que, diferentemente da paginação, que é executada inteiramente pelo S.O., os segmentos são entidades lógicas das quais o programador está ciente e as quais ele pode utilizar como qualquer entidade lógica. Um segmento pode conter um procedimento ou uma matriz, ou uma pilha, mas normalmente ele não contém uma mistura de tipos diferentes. Como cada segmento forma uma entidade lógica da qual o programador está ciente (tal como pilha, procedimentos, etc.) segmentos diferentes podem ter tipos de proteção diferentes: é possível especificar que um procedimento só pode ser executado (sendo proibido ler ou armazenar nele), dados poderão ser lidos e gravados e assim por diante. Este tipo de proteção é útil para detectar erros de programação. A proteção na memória segmentada é importante porque o usuário está ciente do que está em cada segmento. Este modelo é difícil de aplicar a paginação, pois a paginação é invisível ao programador (que não tem como saber de antemão em que página ou moldura um determinado pedaço de programa está), o que não possibilita a separação dos tipos em cada página. Uma das possibilidades da segmentação é que ela pode facilitar o compartilhamento de procedimentos e/ou dados entre vários processos. Um exemplo é uma biblioteca compartilhada. Neste caso, os procedimentos desta biblioteca permanecem em um único segmento que pode ser utilizado por diversos programas (processos), sem que cada um precise possuí-la em seu espaço de endereço. A implementação da segmentação difere da paginação porque as páginas têm tamanho fixo e os segmentos não. A substituição dos processos gera lacunas fazendo com que a memória se transforme em um tabuleiro de xadrez, formado por segmentos e lacunas, que pode ser tratado com compactação. No entanto, se os segmentos são grandes pode ser impossível mantê-los na memória principal em sua totalidade (segmentação pura). Neste caso, pode ocorrer uma segmentação com paginação: o espaço lógico é dividido em segmentos, este são divididos em páginas lógicas sendo que cadasegmento terá uma tabela de páginas associada. A segmentação com paginação pode ser implementada de formas diferentes dependendo do sistema computacional. No Pentium, por exemplo, duas tabelas são utilizadas para a implantação da segmentação: a LDT (Local Descriptor Table) e a GDT (Global Descriptor Table). Cada programa tem sua própria LDT, mas há uma única GDT compartilhada por todos os programas no computador. A LDT descreve segmentos locais para cada programa e a GDT descreve segmentos do sistema, incluindo o próprio S.O. Com a paginação ativada, os endereços gerados são considerados virtuais e o mapeamento para o endereço físico ocorre como explicado anteriormente. Gerência de memória 15 Segmentação com Paginação A segmentação com paginação vem como uma solução aos problemas da segmentação e da paginação.Utilizando o meio termo entre os dois métodos combinaremos suas vantagens: •• A fragmentação interna da paginação é reduzida pela segmentação. •• A fragmentação externa da segmentação é eliminada pela paginação. •• A paginação passaria de forma invisível ao programador. •• A segmentação ofereceria a divisão do processo em módulos(segmentos). •• Teriamos a facilidade do compartilhamento e proteção da memória pela segmentação. Basicamente,teriamos um segmento composto por um número fixo e reduzido de bytes(páginas). A desvantagen seria o uso de 2 tabelas(segmentação e a de paginação) e devido as páginas serem menores teriamos que a tabela de paginação seria maior. Conclusões Sistemas computacionais mais simples não precisam realizar nenhum tipo de gerenciamento pois, usualmente, seus programas rodam diretamente na memória principal disponível. No entanto, esta não é a situação mais comum. Na maioria dos sistemas em uso, os programas são muito maiores que a quantidade de memória principal disponível e/ou é necessário rodar mais de um programa ao mesmo tempo. Nestes casos, a utilização de esquemas de troca, páginas e segmentos pode ser uma alternativa. Um modelo de memória virtual, que fornece um espaço de endereçamento maior do que o físico, pode ser disponibilizado para os programadores no desenvolvimento de seus sistemas. Internamente, no entanto, o S.O. deve ser capaz de gerenciar a memória de forma a manter as partes do programa em uso na memória principal, armazenando as demais partes em disco. Gerência de dispositivos de entrada e saída Uma das principais funções do Sistema Operacional é gerenciar os dispositivos de Entrada e Saída (E/S) ligados ao computador. É tarefa do sistema operacional enviar sinais, informando as ações que o usuário espera que o dispositivo realize; tratar as interrupções e erros gerados pelos dispositivos. Gerência de dispositivos de entrada e saída 16 Existem duas visões sobre o hardware de E/S: A dos engenheiros, que os vêem como chips, ligações elétricas, etc. E a visão dos programadores, que vêem uma interface de programação para se comunicar com o dispositivo. Controladores de dispositivos Dispositivos de hardware precisam ser controlados para proporcionar a entrada e saída de dados para o processador. O controle do hardware é realizado por meio de hardware e software apropriados. A porção de hardware é denominado controlador de hardware e segue padrões determinados pelo barramento (IDE, SCSI, USB, etc), assim, ligados a cada tipo de barramento existem controladores de hardware: controladora de hardware IDE, controladora de hardware SCSI, etc. Para utilizar um dispositivo de hardware, é necessário conectá-lo a interface física da controladora de hardware. Por exemplo, um disco rígido IDE deve ser conectado a uma das quatro interfaces disponíveis pela controladora IDE. Em geral, o Sistema Operacional pode ter softwares controladores de dispositivo (driver de dispositivos). Os drivers de dispositivos para a controladora de hardware, geralmente são genéricos, embutidos no próprio Sistema Operacional. E os drivers para dispositivos de hardware são geralmente específicos, uma vez que controlam funcionalidades específicas providas pelos fabricantes. Periférico é dado como qualquer dispositivo de hardware conectado a um computador de forma a permitir a sua interação com o mundo externo. Princípios do software de E/S Independência do dispositivo Esse conceito trabalho sobre a possibilidade de escrever programas capazes de acessar um dispositivo E/S sem que seja necessário um conhecimento prévio sobre qual é o dispositivo. Ou seja, um programa deverá ser capaz de ler/escrever um arquivo da mesma forma para qualquer dispositivo. Para o caso de se obter a entrada de um dispositivo para saída em outro - como em "/dispositivo1/arquivo > /dispositivo2", o Sistema Operacional fica incumbido de tratar dos problemas causados pelo fato de os dispositivos serem desiguais e necessitarem de sequências de comandos muito diferentes para leitura e escrita. Nomeação uniforme O nome de um arquivo ou de um dispositivo deveria ser uma cadeia de strings ou um número inteiro totalmente independente do dispositivo. Dessa forma, o arquivos e diretórios são endereçados pelo nome do caminho. Tratamento de erros De maneira geral, espera-se que os erros, como de leitura por exemplo, sejam tratados em níveis mais baixos, o mais próximo do hardware. Tipos de conexão e de transferência de dados Os dispositivos I/O podem se conectar de forma serial ou paralela. Na interface serial existe apenas uma linha por onde os dados trafegam. Na interface paralela os dados são transmitidos simultaneamente através das várias linhas para dados, a quantidade de linhas é um múltiplo de 1 byte (8 bits). As informações sobre os endereçamentos de I/O ficam armazenadas, Sistema Operacional Linux, no arquivo /proc/ioports A transferência pode ser síncrona (bloqueante) - a CPU inicia uma transferência e segue realizando outra atividade até ser sinalizada por um interrupção (o que acontece na maioria das E/S físicas), ou assíncrona (orientada à interrupção) - após um read, o programa é suspenso até que os dados estejam disponíveis no buffer. Gerência de dispositivos de entrada e saída 17 Software de E/S O principal objetivo do software gerenciador de E/S é padronizar ao máximo o acesso e controle dos dispositivos, permitindo a inserção de novos dispositivos no sistema computacional sem a necessidade de um outro software auxiliar. Isso se torna uma tarefa bastante complicada devido à grande variedade, complexidade e particularidades dos dispositivos periféricos encontrados. Para facilitar isso, o software de E/S é geralmente é dividido em camadas. Cada camada tem uma função bem definida para executar e uma interface também bem definida para as camadas adjacentes, por meio de uma serie de operações comuns a todos os dispositivos. Uma forma de implementação dessa estrutura é dividir o software em quatro camadas, onde temos a camada superior sendo a E/S vista pelo usuário; a segunda camada o software que enxerga E/S da mesma forma, independente do dispositivo; a terceira camada serve como interface padrão para drivers, e a ultima (mais inferior), composta pelos drivers propriamente ditos. Utilização de buffer O buffer pode ser utilizado em momentos em que os dados não podem ser armazenadas em seu destino final - como acontece com os pacotes que são recebidos pela rede e que precisam ser examinados. Outro exemplo são os dispositivos que apresentam restrições de tempo real, em que os dados devem ser antecipadamente colocados em um buffer de saída a fim de separar a taxa com a qual o buffer é preenchido.Essa taxa é calculada a partir da taxa com a qual ele é esvaziado. Dessa forma, evita-se a sobreposição do buffer. Dispositivos compartilhados vs dedicados Alguns dispositivos, como discos, podem ser usados por vários usuários simultaneamente. Outros, como dispositivos de fita, devem ser dedicados a um usuário até que este termine sua tarefas. O Sistema Operacional deve ser capaz de tratarambos, de forma a evitar problemas. Impasses (Deadlock) Como dito anteriormente, alguns dispositivos devem ser dedicados a um usuário até que este termine sua tarefa, não podendo ser interrompido para atender a solicitação de outro processo. Quando dois processos alocam recursos para si de forma que nenhum dois possa realizar a tarefa, mas também nenhum dos dois disponibilizam estes recursos antes de realizar a tarefa estes processos encontram-se em um impasse (deadlock) e permaneceram ali até que um fator externo os retire dessa situação. O princípio básico do impasse é descrito formalmente: Um conjunto de processos está em um impasse se cada processo do conjunto está esperando um evento que somente outro processo do conjunto pode causar. Como todos os processo estão esperando, nenhum deles jamais causará qualquer dos eventos que poderiam acordar qualquer dos outros membros do conjunto e todos os processos continuam a esperar eternamente. Dispositivos de Entrada e Saída Dispositivos de entrada e saída também chamados de dispositivos de I/O e são classificados em três tipos: Caractere, Bloco, Pseudo-dispositivos. Essa classificação não é 100% abrangente, uma vez que relógios (temporizadores) em hardware não podem ser classificados em nenhum destes tipos. Tais dispositivos se interagem com o SO através de interrupções que podem ser tratadas pelo proprio SO para que seus dados de I/O sejam encaminhadas corretamente. Nem todos os dispositivos de E/S se enquadram nessas duas categorias, por exemplo o relógio que apenas gera sinais de interrupção. Tal dispositivo trabalha em uma ampla variação de velocidade, o que impõe uma considerável pressão sobre o software, que deve trabalhar bem diante das mais diferentes ordens de magnitude de velocidade. Gerência de dispositivos de entrada e saída 18 Dispositivos de Caractere Os conhecidos dispositivos do tipo dispositivos de caractere são assim chamados por terem sua comunicação feita através do envio e recebimento de um fluxo de caracteres. São usados, muitas vezes, para comunicação com dispositivos de interface serial. Geralmente as implementações desse tipo priorizam a eficiência da comunicação em vez do seu volume, neste sentido, é feita de forma não "bufferizada", sendo assim cada caracter é lido/escrito no dispositivo imediatamente [necessita citação]. A exemplo de dispositivos de caracteres que priorizam a comunicação e não necessitam de buffer temos o teclado e o mouse.A exemplo de dispositivos de caracteres que já priorizam o volume ao invés da comunicação temos a impressora, devido a quantidade de dados que chega ser bem maior que sua velocidade de impressão, logo possui um buffer de impressão. Dispositivo de caracteres: É aquele que envia/recebe um fluxo de caracteres, sem considerar qualquer estrutura de blocos, eles não são endereçáveis e não dispõe de qualquer operação de posicionamento. Impressoras e mouses são exemplos desses dispositivos. Dispositivos de Bloco Os dispositivos do tipo dispositivos de bloco são similares aos dispositivos do tipo caractere, porém com uma diferença: O modo de transmissão dos dados, que é feita na forma de blocos. São dispositivos que a comunicação é feita por meio de blocos de dados como em HD's, drivers de CD-ROM, flash drivers e dispositivos de armazenamento em geral. Outra grande diferença é que os dispositivos de bloco em geral utilizam operações de entrada/saídas bufferizadas, no sentido de otimizar o desempenho da transferência de dados. O Sistema Operacional aloca um buffer em um tipo de memória para transferir blocos para cada processo de Entrada e Saída (E/S). Quando um processo envia/requisita dados para/de um dispositivo, o buffer deve ser preenchido para concluir a operação de E/S. Ao encher, o buffer completo é transferido e esvaziado para que seja liberado para uma nova operação. Dispositivo de blocos é aquele que armazena informação em bloco de tamanho fixo, cada um com seu próprio endereço. O tamanho dos blocos normalmente variam de 512 bytes a 32 K bytes. A propriedade essencial de um dispositivo de blocos é que cada bloco pode ser lido/escrito independente dos outros. Discos, são exemplos desses dispositivos. Pseudo-Dispositivos Em sistemas do tipo UNIX, arquivos de dispositivo especiais podem não possuir um dispositivo físico correspondente, estes são chamados de "pseudo-dispositivos". Ex: /dev/null (recebe dados a serem descartados, como uma 'lixeira') , /dev/random (gera números aleatórios) , /dev/zero (gera valores com valor 'zero', útil para criar arquivos preenchidos com esse valor). Interrupção Pedido de Interrupção (IRQ) O Sistema Operacional (SO) chaveia entre os aplicativos ativos para que o usuário tenha a sensação de que estes estão executando em paralelo. O SO permite que um aplicativo utilize o processador durante um determinado período de tempo e então permite que outra aplicação o utilize. Como o chaveamento é feito de uma forma muito rápida temos a impressão de que os aplicativos estão sendo executados ao mesmo tempo. Um pedido de interrupção (abreviação IRQ (em inglês)) é a forma pela qual componentes de hardware requisitam tempo computacional da CPU. Um IRQ é a sinalização de um pedido de interrupção de hardware. Por exemplo: caracteres digitados no teclado, operações de leitura sobre o HD, dados recebidos pelo modem ou mesmo movimentos do mouse devem ser executados mesmo que a máquina esteja processando alguma tarefa. Gerência de dispositivos de entrada e saída 19 Dessa forma IRQ´s são canais de comunicação com o processador. Ao receber um pedido através de algum destes canais, o processador percebe a solicitação de interrompimento de um dispositivo. Quando um programa de usuário emite uma chamada ao sistema, esta é encaminhada ao driver apropriado. Para evitar que a CPU fique ocupada interrogando se dispositivo terminou a operação de E/S (espera ociosa), o driver pede ao dispositivo que lhe sinalize quando isso ocorrer. Dessa forma, o Sistema Operacional poderá executar outras tarefas enquanto o programa que o chamou pedindo o serviço se encontra bloqueado. Ao final da operação, o controlador do dispositivo gera uma interrupção, ao chip controlador de interrupção, para sinalizar à CPU. Caso nenhuma outra interrupção esteja pendente ou em tratamento e nenhum outro dispositivo fez uma requisição de maior prioridade no mesmo momento, a interrupção é tratada imediatamente. Caso contrário, ela é ignorada, e o dispositivo continuará emitindo sinal de interrupção. Após executar uma instrução, a CPU verifica as linhas de interrupções para saber se alguma interrupção foi sinalizada Caso tenha sido sinalizada uma interrupção, o hardware grava os registradores da CPU na pilha do programa que estava em execução e carrega o contador de programa com o endereço da rotina referente à interrupção sinalizada Interrupções podem ser geradas por hardware ou por software. No caso do hardware, pelo dispositivos periféricos ou pelo relógio (timer). As interrupções geradas por software são conhecidas como system calls (chamadas ao sistema) ou trap (armadilha). A diferença primordial entre as interrupções geradas por software e as geradas por hardware, está no fato de que, conhecendo um programa e seus dados, é possível prever quando as interrupções de software irão acontecer - o que não é possível no caso das interrupções de hardware. Interrupções revisitadas Em hardware, as interrupções trabalham da seguinte forma: quando um dispositivo de E/S finaliza seu trabalho ele gera uma interrupção, enviando um sinal pela linha do barramento à qual está associado. O sinal é detectado pelo chip controlador de interrupção localizado na placa mãe, o qual decide o que fazer. Caso esse chip esteja em uso por outro sinal de interrupção ou seja enviado para esse chip outro sinal de maior prioridade, o sinal é posto em uma fila para quando o chip ficar ocioso ele tratar esse sinal. O hardware sempresalva certas informações antes de iniciar a rotina de tratamento da interrupção; no mínimo, o contador de programas (PC) deve ser guardado. Existem duas categorias de interrupções: • Interrupção precisa → Deixa a máquina em um estado bem definido. Possui 4 propriedades: •• 1. O contador de programa é salvo em um lugar conhecido; •• 2. Todas as instruções anteriores àquela apontada pelo PC foram totalmente executadas; •• 3. Nenhuma instrução posterior à apontada pelo PC foi executada; •• 4. O estado de execução da instrução apontada pelo PC é conhecido. • Interrupção imprecisa → Deixa a máquina em um estado não bem definido, pois tem concorrência interna. Complica bastante a vida do projetista do SO, que se vê então obrigado a calcular o que já foi executado e aquilo que ainda não foi executado, para isso é necessário guardar muito mais informação que o normal. Gerência de dispositivos de entrada e saída 20 Tratadores de interrupção As interrupções deveriam ser escondidas para que a menor parte possível do so soubesse de sua existência. A melhor maneira é bloquear o driver que iniciou uma operação de e/s até que a e/s se complete e uma interrupção ocorra. O efeito resultante da interrupção fará com que o driver previamente bloqueado esteja novamente apto a executar. Esse modelo funciona bem sempre que os drivers são estruturados como processos do núcleo do sistema operacional, com seus próprios estados, suas pilhas e seus contadores de programa. Interrupções em sistemas Linux Em antigos computadores, existiam apenas 8 interrupções de hardware. Nos atuais, existem 16 tipos de interrupções de hardware, numeradas de 0 a 15. As interrupções que ocorrem em computadores Linux podem ser vistas digitando no shell o comando: $ cat /proc/interrupts 0 = É o timer do SO. 1 = Interrupção de teclado. 2 = Funciona como ponte para a interrupção 9, e é advinda dos antigos computadores com apenas 8 IRQ's. Dessa forma, ela permite que esses computadores sejam utilizáveis, quando for necessário uso da interrupção 8 para cima. 3 = geralmente usada pela ttyS1, podendo ser usada por outros dispositivos como placas de rede. 4 = geralmente usada pela ttyS0. Quando é usado um mouse serial, ele trabalho através dessa IRQ. 5 = É a segunda porta paralela. Como muitos computadores não possuem essa porta, ela é muito usada pela placa de som. 6 = Usada pelo controlador de disquete 7 = Antigamente, era a primeira porta da impressora. Atualmente várias impressoras não usam IRQ's. 8 = Relógio 9 = Ponte com a IRQ2. 10 = É uma interrupção geralmente livre. Geralmente usada por controladores USB. 11 = Outra interrupção livre 12 = Mais uma IRQ livre. Quando há um mouse PS/2, é trabalhada essa IRQ 13 = Processador de dados numérico. 14 = Usada pela primeira controladora de discos rígidos. 15 = Usada pela segunda controladora de discos rígidos. Convém citar que as IRQ's 14 e 15 não podem ser compartilhadas, devido ao alto grau de importância das mesmas. Os dispositivos PCI/PCI Express são feitos para permitir o compartilhamento de interrupções. Esse trabalho de compartilhamento pode ser feito pelo chipset. Uso de memória por dispositivos E/S mapeada na memória Cada controlador tem alguns registradores usados para a comunicação com a CPU. Por meio da escrita nesses registradores, o SO pode comandar o dispositivo para entregar ou aceitar dados, alternar em ligar/desligar, ou ainda executar alguma outra tarefa. A partir da leitura desses registradores o SO pode descobrir o estado do dispositivo, se ele está preparado para aceitar um novo comando, etc. Além dos registradores, usualmente os dispositivos também possuem um buffer. Gerência de dispositivos de entrada e saída 21 Existe duas formas para a CPU ter acesso a esses registradores e buffers: • 1º → Cada registrador de controle é associado a um número de porta de E/S, usando uma instrução especial de E/S (IN REG, PORT OUT REG, PORT) que seria um acesso direto. • 2º → Mapear todos os registradores de controle no espaço de endereçamento da memória. Cada registrador de controle é associado a um endereço de memória único ao qual nenhuma memória é associada, que seria o mapeamento da E/S na memória. Essa segunda forma, nos trás duas grandes vantagens, a primeira é que o programador pode tratar esses registradores como se trata a memória normal, isso é, como uma variável, isso faz com que um driver possa ser completamente escrito em C/C++, caso seja feita a primeira abordagem, necessariamente o driver terá algum código em ASSEMBLY. A outra vantagem é que não é necessário qualquer mecanismo de proteção especial para impedir que os processos do usuário executem E/S, tudo o que o SO tem de fazer é deixar de mapear aquela porção do espaço de endereçamento associada aos registradores de controle no espaço de endereçamento virtual do usuário. Acesso Direto à Memória (DMA) O Acesso Direto à Memória (DMA) é uma das técnicas utilizadas para otimizar o uso de memória por dispositivos. O DMA é um componente de hardware que permite a transferência direta de dados entre dispositivos periféricos e a memória principal, tornando assim dispensável a participação da CPU neste processo. O controlador de DMA é um hardware desenvolvido para desempenhar toda a sequência de transferência de dados acessando diretamente a memória. Ele gerencia vários canais que podem ser programados para realizar a transferência de dados, quer seja de um dispositivo para a memória ou vice-versa. O SO somente pode usar o DMA se o hardware tem o controlador de DMA. O DMA melhora o desempenho do sistema, pois poupo tempo ocioso da CPU, que poderia muito bem executar a tarefa do DMA, porém como o tempo de E/S é grande principalmetne para grandes quantidades de dados pode fazer com que a CPU fique muito tempo ociosa. Quando a quantidade é pequena as vezes é até mais viável fazer a transferência direto pela CPU que é um hardware mais rápido que o DMA, isso pode causar concorrencia no barramento, pois o barramento utilizado pelo DMA para acessar a memória é o mesmo utilizado pela CPU. Utilizando o DMA, a CPU requisita ao DMA de onde começar a ler os bytes, quantos bytes devem ser lidos/escritos e fica livre para executar outras tarefas que sejam CPU Bound, então quando o DMA termina de realizar sua tarefa, ele transmite um sinal de interrupção para a CPU que simplesmente usa os bytes. Note que a CPU pode fazer exatamente o que o DMA faz, isso fica a cargo de projeto. Coloca uma requisição de leitura no barramento e fica esperando até receber os bytes e assim poder usa-lo, a diferença é que usando a CPU Gerência de dispositivos de entrada e saída 22 para transferencia de uma quantidade maior de dados, poderá ocasionar em CPU ociosa. Um computador tem dois gerenciadores de DMA, divididos em canais. Os canais 0 a 3 são gerenciados por um gerenciador, enquanto os canais 4 a 7 vão para o outro. Para visualizar quais canais estão em uso em sistemas Linux basta digitar no shell o comando: $ cat /proc/dma Os oito canais e seus usos são descritos a seguir: 0 = usado pelo refresh da memória Ram dinâmica. 1 = placas de som de 8 bits, adaptadores SCSI, placas de rede. 2 = controladora de disquete 3 = porta paralela ECP, placas de som de 8 bits, adaptadores SCSI, placas de rede, controladores de scanner antigos. 4 = ponte para a controladora de DMA 0~3 5 a 7 = placas de som, adaptadores SCSI, placas de rede. Os canais 1 a 3 operam sob 8 ou 16 bits, enquanto os canais 5 a 7 operam apenas sob 16 bits. Dispositivos PCI (e outros de alta velocidade) possuem um controlador de DMA embutido, muito mais rápido que o DMA simples. Por exemplo, esse controlador é usado em discos rígidos atuais e pode atingir velocidades de 66MB/s. Processo de Entrada e Saída (E/S) E/S programada Neste método o processador executa o programa e tem o controle total sobre as operações de entrada e saída: •• I - Os dados são copiados parao núcleo; •• II - O Sistema Operacional envia, para a saída, um caractere de cada vez; •• III - A cada caractere enviado, a CPU verifica se o dispositivo está pronto para receber outro; Esse comportamento é chamado de espera ociosa ou polling. A desvantagem desse método é que como o processador geralmente é mais rápido que o dispositivo de E/S ocorrerá um desperdício de processamento. E/S orientada à interrupção Diferentemente da E/S programada, em que a CPU fica verificando o dispositivo para saber se ele está pronto para mais operações ou se terminou, na E/S orientada à interrupção, a CPU passa a realizar outras tarefas escalonadas até que seja informada pelo dispositivo, por meio de uma interrupção, que este está pronto para mais caracteres ou concluiu sua tarefa. Quando isso acontecer, o processador para o que está fazendo para executar o tratador de interrupção, quando sua execução estiver terminada, o processador volta à rotina que foi interrompida inicialmente. Para que seja empregada essa política de interrupções existem detalhes de software e de hardware que devem ser atendidos, e para que esses detalhes sejam executados, a maioria dos computadores possuem um hardware denominado controlador de interrupções. As principais funções do controlador de interrupções são: 1.1. identificar a fonte da interrupção; 2.2. priorizar uma interrupção em relação a outra; 3.3. selecionar quais interrupções serão atendidas. O emprego de interrupções libera o computador para realizar cálculos, então o processador fica responsável apenas por iniciar a operação de entrada-saída, e quando esta for concluída, executar o tratador de interrupção. Gerência de dispositivos de entrada e saída 23 E/S usando DMA No método de E/S orientada à interrupção, a cada caractere processado, é gerado uma nova interrupção à CPU. Para diminuir o peso de processamento sobre a CPU, que perderia muito tempo por conta das contínuas interrupções, passa-se tal tarefa para o DMA, que passará a administrar as interrupções por buffer (não mais por caractere). O DMA executa então a E/S programada (neste caso, não é a CPU que faz o trabalho, mas sim o controlador do DMA). Quando existe uma quantidade de dados significante para ser transferida a técnica de Interrupções se torna ineficaz, sendo melhor a utilização de um hardware especial (Controlador de DMA), que transfere os dados diretamente de um dispositivo de E/S para a memória, ou vice e versa. A transferência por DMA acontece quando o processador inicializa o controlador DMA, fornecendo todas as informações necessárias sobre os dados a serem transferidos (quantidade de dados, origem e destino dos blocos e ainda o sentido da transferência), depois ele dispara a execução do DMA e equanto a transferência estiver ocorrendo o processador pode se dedicar a outra tarefa. Ao final da transferência o DMA sinaliza ao processador por meio de uma interrupção de hardware. Drivers O que são drivers Um driver é uma camada de software que faz a comunicação do sistema operacional com o controlador do hardware que por sua vez faz a interface com o hardware. Drivers escondem as diferenças entre os diversos dispositivos, através de uma interface de programação unica. Driver de dispositivo é responsável por implementar as rotinas necessárias ao acesso e à gerência de um dispositivo específico. A camada de drivers de dispositivo representa uma parte significativa do sistema de entrada e saída em relação às funcionalidades. Ela é responsável por implementar as rotinas necessárias ao acesso e à gerencia de um dispositivo específico.É necessário que o software de E/S realiza a programação de registradores internos de controladores que compõem a interface física dos dispositivos e implementa os respectivos tratadores de interrupção. Assim, cada tipo Gerência de dispositivos de entrada e saída 24 de dispositivo requer um driver apropriado. Essa camada fornece uma abstração a mais genérica possível para a camada superior, a de E/S independente do dispositivo. Cada dispositivo de E/S ligado ao computador precisa de algum código específico do dispositivo para controlá-lo. Esse código, chamado de driver do dispositivo. Para acessar o hardware do dispositivo, o driver normalmente deve ser parte do núcleo do SO. Os sistemas operacionais geralmente classificam os drivers dentre algumas poucas categorias. As categorias mais comuns são dispositivos de bloco - os quais contêm vários blocos de dados que podem ser endereçados independentemente - e os dispositivos de caractere, os quais geram ou aceitam uma sequencia de caracteres. A maioria dos SOs define uma interface-padrão para todos os drivers de blocos e uma segunda interface-padrão para todos os drivers de caracteres. Essas interfaces consistem em um nímero de procedimentos que o restante do so pode utilizar para fazer o driver trabalhar para ele. Um driver de dispositivo apresenta várias funções. A mais óbvia é aceitar e executar requisições abstratas, de leitura ou gravação, de um software independente de um dispositivo localizado na camada acima da camada de drivers dos dispositivos. Mas existem também algumas poucas outras funções que ele tem de executar. Drivers no Linux X Drivers no Windows Enquanto no Windows, os drivers são desenvolvidos pelos próprios fabricantes do dispositivo, precisando ser instalados manualmente e seguindo de um processo de reboot do sistema. Em ambientes GNU/Linux, a instalação dos "drivers" são incorporados diretamente ao Kernel e vêm pré-instalados no sistema. Drivers Linux Em sistemas GNU/Linux os "drivers" são chamados de módulos. O kernel desse sistema é dito monolítico com vantagens de micro-kernel já que os sistemas GNU/Linux são LKM(Loadable Kernel Modules), já que os "drivers" ou módulos são carregáveis ao sistema sem a necessidade de um novo processo de bootstrap após a instalação. Para maior facilidade com o usuário, esse carregamento é feito no processo de bootstrap. Na verdade na maioria dos sistemas operacionais que conta com o desenvolvimento da comunidade do software livre, os módulos são desenvolvidos pela comunidade de desenvolvimento. Se esse módulo tem uma boa aceitação pela própria comunidade e passou por todos os requisitos propostos pela equipe de desenvolvimento do kernel do sistema, esse pode passar a fazer parte do próprio kernel do sistema. Dessa forma, o usuário não precisa correr atrás da instalação uma vez que o driver está incorporado e instalado no sistema. Drivers Windows Nem sempre a companhia que desenvolveu certo hardware, também tem que desenvolver o driver para o mesmo. Há casos em que o hardware foi desenvolvido sobre um certo padrão de hardware. Nesses casos, um driver genérico é desenvolvido pela Microsoft para esse dado padrão. Nem todos os drivers se comunicam diretamente com o dispositivo. Pode haver uma pilha de drivers para determinado dispositivo, em que parte deles age como um filtro, transformando os dados de um formato para o outro, enquanto apenas a base da pilha se comunica diretamente com o dispositivo. Isso pode ser melhor visualizado por uma imagem disponibilizada pela própria Microsoft em seu site: http:/ / i. msdn. microsoft. com/ dynimg/ IC535115. png Também, nem sempre os drivers estarão associados a um dispositivo. Também existe os “Software Drivers”. Em determinados momentos, uma aplicação precisa de acessar recursos que ela só poderia acessar em modo kernel, porém ela está em modo usuário. Então, divide-se essa aplicação em dois componentes: a aplicação que rodará em modo usuário, que fará a interface com o usuário e um driver que rodará em modo kernel, dando acesso aos recursos necessários. Esse driver que roda em modo kernel é chamado de Software Driver. No site da Microsoft também está disponível uma imagem que ilustra isso: Gerência de dispositivos de entrada e saída 25 http:/ / i. msdn. microsoft. com/ dynimg/ IC535116. png Em casos em que determinado
Compartilhar