OBS: As informações aqui contidas foram extraídas, modificadas e/ou adaptadas de diversas fontes bibliográficas, dentre as quais destacam-se Arquitetura de Sistemas Operacionais (Francis B. Machado e Luiz Paulo Maia), Sistemas Operacionais (Deitel & Deitel) e Sistemas Operacionais Modernos (A. Tanenbaum) e de vários sites com propósitos educativos voltados para uma disciplina, dentro de um particular contexto educacional. O propósito desse material é puramente educativo e NÃO se destina a qualquer tipo ou forma de comércio e/ou fins promocionais de qualquer espécie. [email protected] 1 Siglas ENIAC ENIAC – Fotos 005 006 007 1.0 1.1 1.2 1.3 1.4 Visão Geral Recursos do Sistema Computacional Compartilhamento de Recursos Máquina de Níveis Breve Histórico 011 012 013 013 014 2.0 2.1 2.1.1 2.1.2 2.1.2.1 2.1.2.2 2.1.2.3 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 Componentes de um Sistema Operacional Tipos de Sistemas Operacionais Sistema Monogramável/Monotarefa Sistema Multiprogramável/Multitarefa Sistemas em Lotes (Batches) Sistemas de Tempo Compartilhado Sistemas de Tempo Real : Críticos e Não Críticos Sistemas com Múltiplos Processadores Sistemas Fortemente Acoplados: Simétricos e Não Simétricos Sistemas Fracamente Acoplados: de Rede e Distribuídos Sistemas em Cluster Sistemas Embarcados Sistemas de Cartões Inteligentes 018 020 020 021 022 022 023 024 025 027 028 028 028 3.0 3.1 3.2 3.3 3.4 Arquitetura de Sistemas Operacionais Sistema Monolítico Sistema em Camadas Sistema Micronúcleo (Microkernel) Características de um Sistema Operacional 030 030 031 032 033 4.0 4.1 4.2 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.8 4.3 4.4 4.5 Concorrência Interrupções Operacões de Entrada e Saída (E/S) E/S Controlada por Programa Polling E/S Controlada por Interrupção DMA (Direct Memory Access) Canal de E/S Processador de E/S Buffer Spooling Reentrância Proteção ao Sistema Modos de Execução 035 035 037 037 037 037 037 037 038 038 038 038 039 039 5.0 5.1 5.2 5.3 5.3.1 5.3.2 5.3.3 CPU – Unidade Central de Processamento Registradores Visíveis Registradores Invisíveis CPU, Comunicação e Periféricos Loop de Status Interrupções Via DMA 040 040 040 041 042 042 043 2 6.0 6.1 6.2 6.3 6.4 6.5 6.5.1 6.5.2 6.5.3 6.5.4 Processos Componentes de Processo Contexto de um Processo Estados Básicos de um Processo Mudanças de Estado Tipos de Processos Processo CPU Bound Processo I/O Bound Processo em Foreground Processo em Background 045 045 045 048 050 050 050 050 051 051 7.0 7.1 7.2 7.2.1 7.2.2 7.2.3 7.2.4 7.3 7.3.1 7.3.2 7.3.3 7.3.4 7.3.5 7.3.6 7.3.7 7.3.8 7.3.9 7.4 7.5 Gerenciamento da CPU Algoritmos de Escalonamento Critérios de Escalonamento Utilização da CPU Eficiência Tempo de Turnaround Tempo de Resposta Tipos de Escalonamento Escalonamento FIFO Escalonamento Shortest Job First (SJF) Escalonamento Shortest Remaining Time (SRT) Escalonamento Cooperativo Escalonamento Circular (Round Robin) Escalonamento por Prioridades Escalonamento por Múltiplas Filas Escalonamento por Múltiplas Filas com Realimentação Escalonamento por Fração Justa (Fair Share) Escalonamento em Sistemas de Tempo Real Escalonamento com Múltiplos Processadores (CPUs) 052 053 054 054 054 054 054 054 054 055 055 056 056 057 058 058 059 059 061 8.0 8.1 8.2 8.3 8.4 8.5 8.6 8.7 8.8 8.9 8.10 8.10.1 8.10.2 8.10.3 8.10.4 8.10.5 8.10.6 Gerenciamento de Memória Introdução Funções Alocação Contígua Simples Segmentação de Programas Alocação Particionada Estática Alocação Particionada Dinâmica Estratégias de Alocação de Partição Swapping Memória Virtual Algoritmos de Substituição de Páginas Algoritmo Ótimo Algoritmo Aleatório Algoritmo FIFO Algoritmo LFU Algoritmo LRU Algoritmo NRU 062 062 062 062 063 064 066 066 067 068 070 070 070 070 070 071 071 3 9.0 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.3 9.4 Gerenciamento de Sistemas de Arquivos Estrutura de Diretórios Nìvel Único Diretório Pessoal Múltiplos Níveis Sistemas de Alocação de Arquivos FAT FAT32 NTFS Gerência de Espaço Livre Proteção de Acesso 072 072 072 072 072 072 072 072 072 072 073 10.0 10.1 10.2 10.3 10.4 10.5 10.6 Exemplos de Sistemas Operacionais DOS UNIX OS/2 Windows Windows NT Linux 075 075 076 077 077 079 081 11.0 Bibliografia 082 12.0 Dicionário de Termos (Glossário) 083 4 Siglas ALU ASCII CDC CISC CPU DEC DMA DRAM ENIAC EEPROM EPROM HD IBM I/O IOP IP IRQ E/S LAN MAN PROM RAM RISC ROM SRAM TCP UCP ULA WAN WWW - Aritmethic Logical Unit American Standard Code for Information Interchange Control Data Corporation Complex Instruction Set Computer Central Processing Unit Digital Equipment Corporation Direct Memory Acess Dinamic RAM Electronic Numerical Intregator and Computer Electricaly Erasable Programmable Read Only Memory Erasable Programmable Read Only Memory Hard Disk International Business Machines Input and Output Input and Output Processor Internet Protocol Interrupt Request Entrada e Saída Local Area Network Metropolitan Area Network Programmable Read Only Memory Random Access Memory Reduced Instruction Set Computer Read Only Memory Static RAM Transport Control Protocol Unidade Central de Processamento Unidade Lógica Aritmética Wide Area Network Wide World Web 5 ENIAC (Electronic Numerical Intregator and Computer) O 1º computador, o Harvard Mark I, foi projetado por Aiken, da universidade de Harvard em 1939 e foi implementado com relés pela IBM em 1944 e , por isso mesmo não é considerado o primeiro computador eletrônico do mundo. O 1º computador eletrônico, o ENIAC (Electronic Numerical Intregator and Computer), teve seu projeto iniciado em 1943, com a aplicação específica de efetuar os cálculos para a geração de tabelas balísticas para tiros de canhões, tendo ficado operacional em 1946, ou seja, logo após o término da 2ª Grande Guerra Mundial. Ele pesava cerca de 30 toneladas e suas partes ocupavam várias salas do prédio onde ele estava sendo construído. O computador media 5,50 m de altura e 25 m de comprimento e ocupava 180 m² de área construída. Foi construído sobre estruturas metálicas com 2,75 m de altura e contava com 70 mil resistores e entre 17.468 e 18.000 válvulas a vácuo ocupando a área de um ginásio desportivo. Segundo Tom Forester, quando acionado pela primeira vez, o ENIAC consumiu tanta energia que as luzes de Filadélfia piscaram várias vezes. As milhares de válvulas consumiam uma quantidade enorme de eletricidade e dissipavam muito calor, sendo necessários vários aparelhos de ar condicionado para refrigerá-lo. No ENIAC, a programação era efetuada por chaves e pela colocação de vários fios em soquetes específicos (plugboard wiring). Esta máquina não tinha um sistema operacional e seu funcionamento era parecido com uma calculadora simples de hoje. O ENIAC, assim como uma calculadora, tinha de ser operado manualmente. A calculadora efetua os cálculos a partir das teclas pressionadas, fazendo interação direta com o hardware. No ENIAC era preciso conectar fios, relês e seqüências de chaves para que se determinasse a tarefa a ser executada. À cada tarefa diferente o processo deveria ser refeito. A resposta era dada por uma seqüencia de lâmpadas. Não era nada fácil mudar o programa e, através dessa experiência negativa, evoluiu-se para o conceito de programa armazenado (stored program concept), cuja idéia foi apresentada ainda em 1946 pelos pesquisadores Burks, Goldstine e Von Neumann, tendo este último emprestado seu nome para o que conhecemos como a clássica “máquina tipo Von Neumann”. Abaixo podem ser observadas algumas fotos de partes do ENIAC acessadas e obtidas em 18 de Março de 2009, para fins didáticos e não comerciais, a partir dos links abaixo relacionados: http://pt.wikipedia.org/wiki/ENIAC ; http://www.google.com.br/imgres?imgurl=http://www.enciclopedia.com.pt/images/eniac.jpg&imgre furl=http://www.enciclopedia.com.pt/articles.php%3Farticle_id%3D536&h=440&w=629&sz=160& tbnid=FCp-056MiXZ8AM::&tbnh=96&tbnw=137&prev=/images%3Fq%3Deniac&hl=ptBR&usg=__yNVCmHPFVCJf_o6fnpQiCGnkHAs=&ei=J3HKSfzrOobpnQezzp2OAw&sa=X&oi=i mage_result&resnum=4&ct=image&cd=1 ; http://images.google.com.br/images?hl=ptBR&q=fotos+eniac&revid=932243387&ei=J3HKSfzrOobpnQezzp2OAw&resnum=0&um=1&ie=U TF-&ei=FXLKSZvTH5LsnQeZt7SSAw&sa=X&oi=image_result_group&resnum=4&ct=title 6 7 http://news.cnet.com/Photos-ENIAC-in-the-works/2009-1006_3-6038088.html?tag=txt 8 http://news.cnet.com/Photos-ENIAC-in-the-works---page-2/2009-1006_3-6038088-2.html?tag=txt 9 http://news.cnet.com/Photos-ENIAC-in-the-works---page-4/2009-1006_3-6038088-4.html?tag=txt http://news.cnet.com/Photos-ENIAC-in-the-works---page-8/2009-1006_3-6038088-8.html?tag=txt 10 SISTEMAS OPERACIONAIS 1.0 Visão Geral Um sistema operacional pode ser entendido (ou “visto”) como um programa que atua como intermediário entre um ou mais usuários e o hardware de um computador. O propósito básico de um sistema operacional é propiciar um ambiente no qual os usuários possam executar programas de forma conveniente e eficiente. Compreender as razões que estão por trás do desenvolvimento dos sistemas operacionais nos dá uma melhor compreensao das tarefas que eles executam e da forma como o fazem. . Um sistema operacional, em seu sentido mais amplo, deve ser capaz de garantir a operação correta de um sistema computacional, partilhando os recursos disponíveis (memória, CPU e dispositivos de E/S (entrada e saída) da melhor forma possível. Os serviços fornecidos, é claro, diferem de um sistema operacional para outro, mas nosso objetivo é explorar classes comuns à maioria dos sistemas operacionais (S.O.), não nos atendo à particularidades deste ou daquele. Sistemas de computadores evoluíram dos primeiros que não continham nenhum sistema operacional como o ENIAC, por exemplo, para máquinas de multiprogramação, e dessas para máquinas de tempo compartilhado, e depois para computadores pessoais e, por fim, para sistemas verdadeiramente distribudos. À medida que a demanda por novas características e melhor eficiencia cresciam e o hardware mudava. os sistemas operacionais evoluíram para cumprir novos papéis. Por mais complexo que possa parecer, um sistema operacional é apenas um conjunto de rotinas sendo executadas “harmoniosamente” pela CPU (processador), da mesma forma que qualquer outro programa. Sua principal função é gerenciar os diversos recursos existentes no sistema computacional, i.e., memória, CPU, e dispositivos de entrada e saída (E/S). Atualmente, o usuário pode interagir com os sistemas operacionais via comandos fornecidos diretamente a este ou via operações do tipo “click” (click) ou “duplo-click” (double click), onde um dispositivo de apontamento (pointing device) é utilizado para percorrer a tela no sentido vertical e horizontal de forma a permitir ao usuário “apontar” para o aplicativo a ser executado. No caso de comandos fornecidos via operações de “clicks”, torna-se necessária a existência de uma interface gráfica com a qual o usuário possa interagir de forma fácil e intuitiva. As interfaces que possuem essa propriedade recebem o nome de GUIs (Graphic User Interface) sendo normalmente bastante amigáveis quanto à sua utilização, o que contribui em muito para o aumento da produtividade dos usuários que dela fazem uso. As interações com os usuários normalmente se dá via caixas de diálogos (dialog boxes) com botões e campos de texto, como mostrado abaixo. 11 No caso de comandos fornecidos pela linha de comando há um aplicativo denominado interpretador de linha de comando, ou CLI (Command Line Interpreter) que é responsável pela validação da sintaxe do comando, i.e., se a grafia do comando está correta assim como os eventuais parametros passados juntamente com o comando como, por exemplo, nos comandos do DOS fornecidos abaixo, onde alguns comandos são válidados e executados e outros, escritos erroneamente, são descartados. A utilização de linhas de comando é bastante tediosa visto que exige do usuário o conhecimento dos comandos, seus parametros e de suas respectivas sintaxes, porém é ainda bastante comum em ambientes do tipo mainframe ou em plataformas do tipo UNIX,com seu Shell , seus comandos e sua conhecida verbose. O nome sistema operacional nao é unico para designar esse conjunto de programas. Nomes como monitor, executivo, supervisor ou controlador possuem, normalmente, o mesmo significado. Um sistema operacional possui inúmeras funções, mas para efeitos didáticos, resumiremos em apenas 2: a facilidade de acesso aos recursos e o compartilhamento desses recursos de forma organizada. 1.1 Recursos do Sistema Computacional Um sistema de computação possui, normalmente, diversos elementos que o constituem, tais como unidades de disco, monitores (vídeos/terminais), impressoras, fitas etc. Quando um desses dispositivos é utilizado, sobre a ótica/perspectiva do usuário, não há a preocupação sobre como essa utilização será realizada, assim como os detalhes técnicos envolvidos. Por exemplo, uma operação cotidiana como a leitura de um arquivo em disco ou disquete pode parecer simples mas, na verdade, nessa operação “simples”, foi utilizado um grande conjunto de rotinas especificas, todas elas controladas pelo sistema operacional, Foi o sistema operacional que acionou a cabeça de leitura e gravação da unidade de disco, posicionou-a na trilha e setor onde estão os dados, transferiu os dados do disco para a memória e, finalmente, comunicou ao aplicativo que solicitou a operação que esta foi concluída com exito, entregando ao aplicativo solicitante os dados. O exemplo acima ilustra como o sistema operacional age de interface entre os usuários e os recursos disponíveis no sistema, tornando esta comunicação transparente e permitindo aos usuários um trabalho mais eficiente e com menores chances de erros. Este conceito de ambiente simulado, criado pelo sistema operacional, é denominado de máquina estendida/expandida ou máquina virtual (virtual machine) e está presente, de alguma forma, na maioria dos sistemas atuais. 12 É comum ter-se a idéia que aplicativos tais como os compiladores, depuradores, linkers e outras ferramentas fazem parte do sistema operacional, mas na verdade, esses aplicativos são apenas utilitarios, destinados a ajudar a interação do usuário com o computador. Eles podem estar ou não presentes em um sistema computacional qualquer, sem que o sistema operacional necessite deles. Sob a ótica do sistema, esses aplicativos são apenas mais alguns processos que serão executados. 1.2 Compartilhamento de Recursos Em sistemas do tipo multiusuário, onde vários usuários podem estar compartilhando os mesmos recursos, como, por exemplo, CPU, memória e periféricos, é necessário que todos tenham a oportunidade de ter acesso a esses recursos, de forma tal que um usuário não venha a interferir no trabalho do outro. Por exemplo, uma impressora que pode ser utilizada por vários usuários do sistema, deverá possuir algum nível de controle para impedir que a impressao de um usuário interrompa a impressão de outros. Novamente, o sistema operacional é responsável por permitir o acesso concorrente à impressora e a outros recursos eventualmente disponíveis, de forma organizada e protegida, dando ao usuario a impressao de ser o único a utilizá-los. O compartilhamento de recursos permite, tambem, a diminuição drástica dos custos, na medida em que mais de um usuário pode utilizar as mesmas facilidades concorrentemente, como discos, impressoras, recursos de rede etc. Nao é somente em sistemas do tipo multiusuário que o sistema operacional é importante. Em um computador pessoal do tipo desktop ou laptop é o sistema operacional neles residente (Windows, Linux etc.) que permite a execução de várias tarefas, como por exemplo, a impressão de um documento, uma sessão de conversação via web com imagens e sons, a cópia de um arquivo pela Internet ou a execução de uma planilha eletrônica. 1.3 Máquina de Níveis Um sistema computacional qualquer, visto somente como um ou mais gabinetes compostos de circuitos eletrônicos, cabos, fios e fontes de alimentação (hardware), nao tem nenhuma utilidade. É através da utilização dos programas (software) que o computador consegue armazenar dados em discos, imprimir relatórios, gerar gráficos, realizar cálculos dentre tantas outras funções. O hardware é o responsável final pela execução das instruções de um programa, com a finalidade de se realizar alguma tarefa. Uma operação efetuada pelo software pode ser implementada em hardware e, análogamente, uma instrução executada pelo hardware pode ser simulada via software. Esta decisão fica a cargo dos projetistas de computadores em função de aspectos tais como custo, confiabilidade e desempenho. Tanto o hardware quanto o software são lógicamente equivalentes, interagindo de uma forma única para o usuário. Nos primeiros computadores, a programação era realizada em painéis, através de fios, plugs e cabos, exigindo um grande conhecimento do hardware e de sua linguagem de máquina. Isso era uma grande dificuldade para os programadores da época. A solução para esse problema foi o surgimento do sistema operacional, que tornou a interação entre usuário e computador mais simples, confiável e eficiente. A partir desse acontecimento, nao existia mais a necessidade de o programador se envolver com a complexidade do hardware para poder trabalhar; ou seja, a parte física do computador tomou-se transparente para o usuário. Partindo desse principio, podemos considerar o computador como uma máquina de niveis ou camadas, onde inicialmente existem dois niveis: o nível 0 (hardware) e o nível 1 (sistema operacional - software). Sendo assim, o usuário leigo pode ver a máquina como sendo apenas constituída do sistema operacional, com quem realmente interage, como se o hardware não existisse. Reforça-se aqui o conceito de que se dá à essa visão abstrata o nome de máquina virtual ou máquina estendida/expandida já abordado anteriormente. 13 Um sistema computacional qualquer evidentemente não é constituído de apenas 2 níveis, mas de quantos níveis forem necessários para que o usuário possa interagir com o hardware – essa é uma abstração normalmente empregue do ponto de vista didático – sendo que o usuário não precisa saber de em qual camada ele se encontra. 1.4 Breve Histórico A evolução dos sistemas operacionais sempre esteve ligada à história da evolução do hardware. O ENIAC não dispunha de um sistema operacional ou qualquer outro tipo de software tal como o conhecemos atualmente. A programação era feita mediante a utilização de cabos elétricos especiais que eram conectados em diferentes partes da máquina. Esse trabalho era executado por pessoas capacitadas para fazê-lo, como por exemplo, cientistas e engenheiros, ou pessoas especialmente treinadas por estes. Com o desenvolvimento do transistor e consequente susbstituição das válvulas por estes novos componentes, a miniaturização teve início e, com ela, a drástica diminuição do tamanho dos computadores. Com o contínuo avanço da tecnologia, o conceito de Von Neumann, pode ser implementado em uma máquina eletrônica, dando origem aos computadores programáveis e, juntamente com eles o desenvolvimento dos primeiros programas para serem executados. À medida que os empresários e os governos foram se apercebendo da enorme aplicabilidade dessas máquinas, mais e mais aplicações foram sendo desenvolvidas até que foi sentida a necessidade de se ter um programa maior e mais complexo capaz de coordenar todas essas diferentes tarefas de uma forma mais fácil e coordenada do que aquela que vinha sendo executada. Dessa necessidade crescente nasceram os primeiros sistemas operacionais, que foram sendo instalados nos grandes computadores comerciais. Os primeiros sistemas operacionais eram do tipo monousuário (monouser) e monotarefa (monotask) e, com isso, as tarefas eram executadas de forma sequencial, i.e., uma após outra. As tarefas podiam ser agrupadas e executadas em lotes (batches), cada lote pertencendo à uma determinada empresa, que pagava os custos decorrentes do processamento. O conceito de datacenters ,i.e., empresas especializadas em processar os dados de outras empresas, acabara de nascer e já estava se desenvolvendo. As crescentes necessidades comerciais fizeram com que um novo tipo de sistema operacional fosse desenvolvido e entrasse nesse cenário. Nascia o conceito de sistema operacional do tipo multitarefa (multi-task) que era capaz de executar e controlar várias tarefas simultaneamente, tornando ainda maior a aplicabilidade dessas máquinas. O próximo passo foi o desenvolvimento de sistemas operacionais do tipo multi-usuário (multiuser), onde vários usuários diferentes podiam utilizar o mesmo computador e seus diferentes recursos. Além disso, cada usuário podia ter o seu próprio conjunto de tarefas sendo executadas. Quanto mais recursos da máquina eram alocados por determinado usuário (e suas tarefas), maior era o preço do processamento decorrente, fazendo com que somente grandes empresas e governos pudessem pagar por esses serviços. O total da conta era de certa forma proporcional à quantidade de recursos utilizados por aquele usuário (e suas tarefas). Itens como quantidade de memória, tempo de CPU, espaço em disco e em fitas magnéticas etc., eram inicialmente calculados por pessoas treinadas para esse serviço, porém com o passar do tempo, essa tarefa passou também a ser executada por processos especificamente desenvolvidos para esse fim. 14 O ínicio da era dos grandes computadores, constituídos por dezenas de placas contendo milhares de componentes eletrônicos e dispositivos de armazenamento de dados (discos e fitas magnéticas) havia começado e ainda perdura até nos dias de hoje. Somente no ínicio da década de 1980, com o desenvolvimento e amadurecimento do conceito de circuitos integrados e, posteriormente, com o desenvolvimento da tecnologia que permitiu a sua criação e disseminação, apareceram os primeiros computadores pessoais. Novamente a história iria se repetir, só que desta vez na escala residencial e não mais na empresarial. O primeiro sistema operacional, por assim dizer, voltado para os recém chegados PCs, foi o DOS (Disk Operating System) desenvolvido em regime de parceira pela IBM e pela Microsoft. Não tardou para que os novos usuários domésticos também passassem a demandar novos serviços e com eles um novo sistema operacional, o MS-Windows. As primeiras versões do MS-Windows não foram bem sucedidas comercialmente devido ao excessivo processamento que este novo sistema demandava da CPU e que esta não conseguia suprir adequadamente. Somente com uma nova linha de CPUs, mais rápidas e poderosas, desenvolvida pela Intel é que o sistema Windows começou a ganhar mercado e a se impor como padrão. Exemplos de sistemas operacionais para máquinas de grande porte (mainframes) são o UNIX, o Open VMS, o MPX-32, o Sun OS e o OS/370, dentre tantos outros. Atualmente, há várias versões do UNIX, cada qual adaptada e desenvolvida por fabricantes diferentes, tais como o HPUX, o AIX (IBM), o SOLARIS (SUN) e o Tru-64 (DEC/HP). Atualmente, há vários tipos de sistemas operacionais voltados para os PCs (desktops e laptops) derivados do UNIX, como por exemplo o Linux, o Librix, o Xenix, o QNX, o Fedora, o Suse etc. Plataformas mainframes de alto desempenho podem apresentar mais de uma CPU em sua arquitetura, o que demanda sistemas operacionais ainda mais complexos, capazes de tirar proveito do grande poder de processamento dessas CPUs. Resumindo : a) O sistema operacional separa as diversas aplicações sendo executadas em um computador do hardware por elas acessado. Ele pode ser visto como uma camada de software (SW) envolvendo o hardware (HW), de forma a tornar este último transparente ao usuário comum. b) Cabe ainda ao Sistema Operacional, primordialmente, gerenciar os diversos recursos pertencentes não somente ao reino do hardware tais como processadores, memória, dispositivos de entrada/saída; dispositivos de comunicação, mas também ao reino do software tais como as mais diversas aplicações de software que o usuário utiliza. c) Os sistemas operacionais passaram por diversas fases de evolução ao longo dessas 6 últimas décadas 15 A evolução dos Sistemas Operacionais, sempre em sincronia com a evolução de um hardware cada mais melhor e mais rápido pode ser vista, década à década, abaixo : Década de 1940 (utilizavam-se válvulas, plugs e relés) Os primeiros computadores não dispunham de sistemas operacionais. Década de 1950 (utilizavam-se válvulas, plugs e relés) Executavam um serviço (job) por vez. Dispunham de tecnologias que facilitavam a transição de um job para outro. Eram chamados de sistemas de processamento em lote de fluxo único. Os programas e dados eram submetidos consecutivamente em uma fita magnética. Década de 1960 (aparecimento dos transistores) Permanecem como sistemas de processamento em lote Processam vários serviços (jobs) simultaneamente Multiprogramação Um job podia usar o processador enquanto outros utilizavam os dispositivos periféricos. Desenvolveram-se sistemas operacionais avançados para atender a diversos usuários de forma interativa Esses sistemas foram desenvolvidos para apoiar usuários interativos simultâneos. O tempo de retorno foi reduzido a minutos ou segundos. Aparecem os primeiros sistemas de tempo real Fornecem respostas dentro de um prazo determinado. O tempo e os métodos de desenvolvimento foram aperfeiçoados. O MIT usou o sistema CTSS para desenvolver seu próprio sucessor, o Multics. Os sistemas TSS, Multics e CP/CMS, incorporavam memória virtual, endereçam mais localizações de memória do que as realmente existentes. Década de 1970 (apareceram os primeiros circuitos integrados) Os sistemas de tempo compartilhado eram primordialmente multimodais, isto é, suportavam processamento em lote, tempo compartilhado e aplicações de tempo real. A computação pessoal estava apenas em seu estágio inicial, tendo sido favorecida por desenvolvimentos anteriores à tecnologia de multiprocessadores. O Departamento de Defesa Americano patrocinou o desenvolvimento do TCP/IP, inicialmente denominado de ARPANET (Advanced Research Projects Agency NETwork), que pretendia-se ser utilizado como protocolo de comunicação padrão. Esse protocolo passou a ser amplamente usado em ambientes militares e universitários, porém, apresentava alguns problemas de segurança, dado que crescentes volumes de informação eram transmitidos por linhas vulneráveis. Década de 1980 (apareceram os primeiros circuitos integrados de baixa escala) Foi a década do surgimento dos computadores pessoais e das estações de trabalho. A computação era distribuída aos locais em que era necessária, gerando demanda. Era relativamente fácil aprender a usar um computador pessoal. Apareceram as primeiras interfaces gráficas com o usuário (GUI) A transferência de informações entre computadores interconectados em rede tornou-se mais econômica e prática. O modelo de computação cliente/servidor se disseminou e com isso, os clientes são os próprios computadores que solicitam serviços variados e os servidores são os computadores que executam os serviços solicitados. O campo da engenharia de software continuou a evoluir, recebendo grande impulso do governo dos Estados Unidos, que visava controlar de modo mais rígido os projetos de software do 16 Departamento de Defesa. Uma das metas era a reutilização de códigos o que podia ser obtido pelo maior grau de abstração nos idiomas de programação. Vários threads de instrução podiam ser executados independentemente. Década de 1990 (apareceram os primeiros circuitos integrados de larga escala) O desempenho do hardware melhorou exponencialmente, com uma crescente capacidade de processamento e armazenamento cada vez mais acessível. A execução de programas grandes e complexos passou a poder ser feita em computadores pessoais. Teve início o desenvolvimento dos serviços extensivos aos banco de dados e processamento remoto. A computação distribuída ganhou ímpeto e com isso, inúmeros computadores independentes podiam executar tarefas comuns. O suporte a sistemas operacionais para tarefas de rede tornaram-se padrão, com grande aumento da produtividade e comunicação. A Microsoft Corporation tornou-se dominante no mercado, com suas várias versões dos seus sistemas operacionais Windows, que empregava vários conceitos usados nos primeiros sistemas operacionais Macintosh e que permitia que os usários executassem várias aplicações concorrentes com facilidade. A tecnologia de objeto tornou-se popular em várias áreas da computação, com diversas aplicações sendo desenvolvidas em linguagens de programação orientadas a objetos, como por exemplo, o C++ e o Java. Apareceram alguns sistemas operacionais orientados a objetos (SOOO), onde os objetos representavam componentes do sistema operacional. A maioria dos softwares comerciais era vendida como código-objeto e o código-fonte não era incluído, permitindo aos fabricantes que ocultassem informações e técnicas de programação patenteadas. Os softwares gratuitos e de fonte aberto tornaram-se muito comuns na década de 1990. O software de fonte aberto era distribuído com o código-fonte, permitindo que outras pessoas examinassem e modificassem o software. O sistema operacional Linux e o servidor Web Apache são ambos software de fonte aberto. Richard Stallman lançou o projeto GNU, que recriava e ampliava as ferramentas do sistema operacional UNIX da AT&T. Stallman discordava do conceito de pagar licença para usar um software. Grande porte (mainframes) 1990 1950 1960 1º Sistema Operacional Monoprogramável Monotarefa 1970 Sistemas Multitarefa Introduzido o conceito de Memória Virtual 1980 Sistemas Multiprogramáveis Multitarefa Microcomputadores 17 2.0 Componentes de um Sistema Operacional Conforme já visto anteriormente, um usuário interage com o sistema operacional via uma ou mais aplicações de usuário e, muitas vezes, por meio de uma aplicação especial denominada Shell ou CLI, ou interpretador de comandos. A maioria dos interpretadores de comando atuais é implementada como interfaces de texto que habilitam o usuário a emitir comandos por meio de um tec1ado, ou como GUIs (Graphic User Interface) que permitem que o usuario 'aponte-eclique' e 'arraste-e-solte' ícones para requisitar serviços ao sistema operacional, como por exemplo, para abrir uma aplicação como um editor de textos, um aplicativo para apresentações ou mesmo uma planilha eletrônica. O Microsoft Windows XP, por exemplo, fornece uma GUI por meio da qual os usuários podem fornecer comandos. O usuário pode abrir alternativamente uma janela de comandos (Command Prompt (antigo DOS)) que aceite os comandos fornecidos pelo usuário. O software que contém os componentes centrais do sistema operacional chama-se núcleo do sistema, ou kernel (em alemão). Os principais componentes centrais de um sistema operacional são: a) o escalonador de processo, que determina quando e por quanto tempo um processo é executado em um processador. b) o gerenciador de memória, que determina quando e como a memória é alocada aos processos e quais ações tomar quando a memória principal estiver toda ela ocupada. c) o gerenciador de E/S, que atende as solicitações de E/S de e para dispositivos de hardware, respectivamente. d) o gerenciador de comunicação interprocessos, IPC (Inter Process Communication), que permite que os processos se comuniquem uns com os outros. e) o gerenciador de sistema de arquivos, que organiza coleções nomeadas de dados em dispositivos de armazenamento e fornece uma interface para acessar os dados nesses dispositivos. Quase todos os sistemas operacionais atuais suportam um ambiente de multiprogramação no qual várias aplicações podem ser executadas concorrentemente. Uma das responsabilidades mais fundamentais de um sistema operacional é deterrninar qual processador executa um processo e durante quanto tempo esse processo será executado. Um programa pode conter diversos elementos que compartilhem dados e que podem ser executados concorrentemente. Por exemplo, um navegador Web pode conter componentes isolados para ler a HTML de uma página Web, recuperar a mídia da página (ou seja, imagens, texto e vídeo) e exibir esta página apresentando seu conteúdo na janela do navegador. Esses componentes de programa, executados independentemente, mas que realizam seu trabalho em um espaço de memória comum, sao chamados de threads (fluxos de execução). Normalmente, muitos processos competem para usar o processador e o escalonador de processos pode basear suas decisões em diversos critérios, como a importância atribuída a um processo, o tempo estimado de execução etc. O gerenciador de memória aloca memória para o sistema operacional e para os processos. Com a tarefa de garantir que os processos nãoo interfiram na operação normal do sistema operacional ou uns nos outros, o gerenciador de memória impede que cada processador acesse memória que não lhe tenha sido alocada. Quase todos os sistemas operacionais atuais suportam memória virtual. 18 Uma outra função central do sistema operacional é gerenciar os dispositivos de E/S (entrada/saída) do computador. São exemplos de dispositivos de entrada os teclados, mouses, microfones e scanners. São exemplos de dispositivos de saída os monitores, impressoras e altofalantes. Dispositivos de armazenamento (por exemplo, discos rígidos, fitas, discos óticos regraváveis ou não) e placas de rede funcionam como dispositivos de entrada e saída. Quando um processo quer acessar um dispositivo de E/S, deve emitir uma chamada ao sistema operacional. Aquela chamada é subseqiientemente utilizada por um driver de dispositivo, que é um componente de software que interage diretamente com o hardware e, em geral, contém comandos e outras instruções específicas do dispositivo para realizar as operações de E/S requisitadas. A rnaioria dos sistemas de computador pode armazenar dados persistentemente (isto e, após o computador ter sido desligado). Como a memória principal (RAM) é geralmente relativamente pequena e perde seus dados quando a fonte de energia é desligada (memórias voláteis), são usados dispositivos secundários de armazenamento persistente (não voláteis), mais comumente discos rígidos. Um operação de E/S no disco - uma das formas mais comuns de E/S - ocorre quando um processo requisita acesso à informações que estão em um dispositivo de disco. Entretanto, o armazenamento secundário é muito mais lento do que os processadores e a memória principal. O escalonador de disco de um sistema operacional é responsável pela reordenação das requisições de E/S por disco para maximizar o desempenho e minimizar a quantidade de tempo que um processo espera pelo tpermino das operações de E/S por disco. Os sistemas de arranjo redundante de discos independentes, RAID, (Redundant Array of Independent Disks) tentam reduzir o tempo que um processo espera pela operação de E/S por disco, utilizando vários discos ao mesmo tempo para atender às requisições de E/S. Existem vários algoritmos de escalonamento de discos e sistemas RAID, todos objetivando o ganho de performance. Os sistemas operacionais usam sistemas de arquivo para organizar e acessar eficientemente coleções nomeadas de dados, denominadas arquivos e localizadas em dispositivos de armazenamento. Esses arquivos por sua vez, podem encontrar-se agrupados em áreas denominadas diretórios, onde um diretório pode apresentar vários subdiretórios e estes outros mais, sucessivamente em uma estrutura de árvore. Com frequência, os processos (threads) cooperam para cumprir uma meta comum. Assim, muitos sistemas operacionais proporcionam comunicação entre processos (IPC) e mecanismos de sincronização para simplificar essas programações concorrentes. A comunicação entre processos habilita os processos a se comunicarem via mensagens enviadas entre eles (e entre as threads). A sincronização fornece estruturas que podem ser usadas para assegurar que processos (e threads) compartilhem os dados adequadamente. 19 2.1 Tipos de Sistemas Operacionais Tipos de Sistemas Operacionais Sistemas Monoprogramável/ Monotarefa Sistemas Multiprogramável/ Multitarefa Sistemas Com Múltiplos Processadores 2.1.1 Sistemas Monoprogramável/Monotarefa Os primeiros sistemas operacionais eram voltados tipicamente para a execução de um único programa. Qualquer outra aplicação, para ser executada, deveria aguardar o término do programa corrente. Neste tipo de sistema, o processador, a memória e os periféricos permanecem exclusivamente dedicados à execução de um único programa. Esse único programa monopoliza a CPU. Os sistemas monoprogramáveis estão diretamente ligados ao surgimento, na década de 50/60, dos primeiros computadores. Embora os sistemas operacionais já tivessem evoluído com as tecnologias de multitarefa e multiprogramáveis, os sistemas monoprogramáveis voltaram a ser utilizados na plataforma de microcomputadores pessoais e estações de trabalho devido à baixa capacidade de armazenamento destas máquinas, na época. Era muito clara a desvantagem deste tipo de sistema, no que diz respeito à limitação de tarefas (uma de cada vez), o que provocava um grande desperdício de recursos de hardware. _______ _______ _______ _______ _______ CPU Memória Principal (RAM) Dispositivos E/S Programa/Tarefa Sistema Monoprogramável/Monotarefa 20 Comparados a outros sistemas, os monoprogramáveis são de simples implementação, não existindo muita preocupação com problemas decorrentes do compartilhamento de recursos como memória, processador e dispositivos de E/S. 2.1.2 Sistemas Multiprogramável/Multitarefa Constituindo-se uma evolução dos sistemas monoprogramáveis, neste tipo de sistema os recursos computacionais são compartilhados entre os diversos usuários e aplicações: enquanto um programa espera por um evento, outros programas podem estar processando neste mesmo intervalo de tempo. Neste caso, podemos observar o compartilhamento da memória e do processador. O sistema operacional se incumbe de gerenciar o acesso concorrente aos seus diversos recursos, como processador, memória e periféricos, de forma ordenada e protegida, entre os diversos programas. As vantagens do uso deste tipo de sistema são a redução do tempo de resposta das aplicações, além dos custos reduzidos devido ao compartilhamento dos recursos do sistema entre as diferentes aplicações. Apesar de mais eficientes que os monoprogramáveis, os sistemas multiprogramáveis são de implementação muito mais complexa. Programa_1/Tarefa_1 Programa_4/Tarefa_4 _______ _______ _______ _______ _______ _______ _______ _______ _______ _______ _______ _______ _______ _______ _______ CPU Memória Principal (RAM) Dispositivos E/S _______ _______ _______ _______ _______ Programa_3/Tarefa_3 Programa_2/Tarefa_2 Sistema Multiprogramável/Multitarefa 21 Os sistemas multiprogramáveis/multitarefa podem ser classificados de acordo com a forma com que suas aplicações são gerenciadas, podendo ser divididos em sistemas batch, de tempo compartilhado e de tempo real, de acordo com a figura abaixo. Sistemas Multiprogramáveis/ Multitarefa Sistemas em Lotes Sistemas de Tempo Compartilhado Sistemas de Tempo Real 2.1.2.1 Sistemas em Lotes (Batches) Foram os primeiros sistemas multiprogramáveis a serem implementados na década de 60. Nesta modalidade, os programas eram submetidos para execução através de cartões perfurados e armazenados em disco ou fita, para posterior execução. Vem daí o nome batch (lote de cartões). O processamento em batch tem como característica não exigir interação do usuário com o sistema ou com a aplicação. Todas as entradas ou saídas são implementadas por meio de algum tipo de memória secundária, geralmente disco ou fita. Aplicações deste tipo eram utilizadas em cálculo numérico, compilações, back-ups, etc. Estes sistemas, se bem projetados, podem ser bastante eficientes devido à melhor utilização do processador, mas podem oferecer tempos de resposta bastante longos. Atualmente, os sistemas operacionais simulam este tipo de processamento, não havendo sistemas dedicados a este tipo de execução. 2.1.2.2 Sistemas de Tempo Compartilhado Também chamados sistemas de time-sharing, são sistemas que permitem que diversos programas sejam executados a partir da divisão de tempo da CPU em pequenos intervalos, denominados fatia de tempo (time slices) ou quantum. Caso a fatia de tempo não seja suficiente para a conclusão do programa, este é interrompido pelo sistema operacional e substituído na CPU por outro, enquanto aguarda uma nova fatia de tempo. Neste tipo de processamento, cada usuário tem a impressão de que a máquina está dedicada ao seu programa, como se ele fosse o único usuário a se utilizar do sistema. Geralmente permitem interação do usuário com a aplicação através de terminais compostos por monitor, teclado e mouse. Estes sistemas possuem uma linguagem de controle que permite ao usuário interagir com o sistema operacional através de comandos. Assim, é possível verificar arquivos armazenados em disco ou cancelar execução de programas. Normalmente, o sistema responde em apenas alguns segundos à maioria destes comandos, o que se levou a chamá-los também de sistemas on-line. A maioria das aplicações comerciais atualmente é processada em ambiente de tempo compartilhado, que oferece tempos baixos de respostas a seus usuários e menores custos, em função do alto grau de compartilhamento dos diversos recursos do sistema. 22 2.1.2.3 Sistemas Operacionais de Tempo Real : Críticos e Não Críticos Este tipo de sistema é implementado de forma bastante semelhante ao de tempo compartilhado. O que caracteriza a diferença entre eles é o tempo exigido no processamento das aplicações. Enquanto nos sistemas de tempo compartilhado o tempo de processamento pode variar sem comprometer as aplicações em execução, nos sistemas de tempo real os tempos de execução devem estar dentro de limites rígidos, que devem ser obedecidos, caso contrário poderão ocorrer problemas irreparáveis. No sistema de tempo real não existe a idéia de fatia de tempo como nos sistemas de tempo compartilhado. Um programa ocupa o processador o tempo que for necessário ou até que apareça um outro com um nível de prioridade maior. Esta prioridade de execução é definida pela própria aplicação e não pelo sistema operacional, como nos sistemas de tempo compartilhado. Estes sistemas são utilizados em aplicações de controle de processos, como monitoramento de refinarias de petróleo, controle de tráfego aéreo, de usinas, ou em qualquer aplicação onde o tempo de processamento é fator fundamental. Um sistema desse tipo é utilizado quando existem requisitos rígidos de tempo na operação de um processador ou no fIuxo de dados no sistema. Ele é normalmente utilizado em aplicações dedicadas e críticas no tempo, como por exemplo, no controle de usinas nucleares, usinas elétricas, no controle de aeronaves, controle de experimentos científicos, sistemas de imagens médicas, sistemas de controle industrial, sistemas de injeção eletrônica de combustivel em motores de veículos, controladores de eletrodomésticos e sistemas bélicos. Um sistema de tempo real tem limitações de tempo bem definidas, rígidas e fixas. O processamento tem de ser feito dentro dos limites definidos ou o sistema poderá falhar, como por exemplo no controle de braços robóticos na construção de carros em uma linha de montagem automatizada – aqui, o tempo é fator decisivo, diferentemente do que ocorre com um sistema de tempo compartilhado, em que é desejável , mas não obrigatório, uma resposta rápida. Existem 2 tipos de sistema de tempo real : o crítico e o não crítico. Um sistema de tempo real crítico procura garantir que as tarefas críticas sejam executadas a tempo. Essa meta requer que todos os atrasos no sistema sejam limitados, desde a recuperação dos dados armazenados até o tempo que o sistema operacional precisa para terminar qualquer solicitação realizada. As limitações de tempo inerentes em aplicações críticas incluem o acesso aos diferentes tipos de memórias, voláteis ou não, de acesso aleatório ou sequencial. Claramente pode-se ver que a utilização de armazenamento secundário de qualquer tipo geralmente é muito limitado e normalmente ausente, sendo desejável que os dados sejam armazenados em memórias de acesso aleatórias de alta velocidade. Outros recursos mais avançados, existentes na maioria dos sistemas operacionais também estão ausentes, como por exemplo a utilização de memória virtual. Essa caracterísitica quase nunca é encontrada nos sistemas de tempo real, pelos motivos relacionados e, portanto, os sistemas de tempo real crítico não são compatíveis com a operação dos sistemas de tempo compartilhado, e os dois não devem ser combinados. . Um tipo menos restritivo de sistema de tempo real é o sistema de tempo real não-crítico, no qual uma tarefa considerada crítica recebe prioridade sobre as demais tarefas não críticas, mantendo essa prioridade até ser concluída. Como ocorre com os sistema de tempo real crítico, os atrasos internos ao kernel precisam ser limitados: uma tarefa de tempo real não pode ficar esperando 23 indefinidamente para ser executada.. O tempo real não-crítico é uma meta alcançável que pode ser combinada com outros tipos de sistemas. Os sistemas de tempo real não-crítico, no entanto, tem utilidade mais limitada do que os sistema de tempo real crítico. Considerando sua arquitetura e projeto, eles não são apropriados para controle industrial, como por exemplo, aplicações robóticas. No entanto, existem várias áreas nas quais são úteis, incluindo-se aplicações com multimídia, realidade virtual e projetos cientificos avançados, tais como explorações submarinas e astronáuticas. Esses sistemas precisam de recursos avançados presentes em sistemas operacionais e que não são apropriados para sistemas de tempo real crítico. As diferentes versões baseadas no sistema operacional UNIX constituem bons exemplos de sistemas de tempo real não críticos, assim como o QNX e o VxWorks. 2.2 Sistemas com Múltiplos Processadores Os sistemas com múltiplos processadores caracterizam-se por possuir duas ou mais CPUs interligadas e trabalhando em conjunto. A vantagem deste tipo de sistema é permitir que vários programas sejam executados ao mesmo tempo ou que um mesmo programa seja subdividido em várias partes para serem executadas simultaneamente em mais de um processador. Esta técnica permitiu a criação de sistemas computacionais voltados para processamento científico, prospecção de petróleo, simulações, processamento de imagens e CAD. Um fator chave no desenvolvimento dos sistemas multiprocessados é a forma de comunicação entre as CPUs e o grau de compartilhamento da memória e dos dispositivos de E/S. Em função destes fatores, podemos classificar os sistemas multiprocessados de acordo com a figura a seguir: Sistemas com Múltiplos Processadores Sistemas Fortemente Acoplados Simétricos Sistemas Fracamente Acoplados Assimétricos Redes Distribuídos Tipos de Sistemas com Múltiplos Processadores 24 2.2.1 Sistemas Fortemente Acoplados : Simétricos e Não Simétricos Na figura anterior pode-se perceber a divisão dos sistemas multiprocessados em duas categorias iniciais: sistemas fortemente acoplados e fracamente acoplados. A grande diferença entre estas duas categorias é que nos sistemas fortemente acoplados existe apenas uma memória e um barramento a ser compartilhada pelos processadores do conjunto, enquanto que nos sistemas fracamente acoplados cada sistema tem sua própria memória individual. A taxa de transferência de dados entre CPUs e memória em sistemas fortemente acoplados é muito maior que nos fracamente acoplados. Nos sistemas fortemente acoplados a memória principal e os dispositivos de E/S são gerenciados por um único sistema operacional. Quando todos os processadores na arquitetura são iguais e as funções também são iguais, diz-se que o sistema é simétrico. No entanto, quando os processadores são iguais, porém com funções diferentes, a arquitetura denomina-se assimétrica . A maioria dos sistemas atuais são sistemas de um único processador, ou seja, com somente uma CPU principal. No entanto, existe uma forte tendência em direção aos sistemas com mais de uma CPU, os assim chamados sistemas multiprocessados. Tais sistemas tem mais de um processador em comunicação ativa, compartilhando elementos comuns, tais como o barramento, o relógio do sistema (clock) e, as vezes, a memória e alguns dispositivos periféricos. A esses sistemas dá-se o nome de sistemas fortemente acoplados (tightly coupled systems). Há vários motivos para a existência desses sistemas, como por exemplo uma maior eficiência (throughput) na execução dos vários processos. Ao se aumentar o número de processadores, espera-se realizar mais trabalho em menos tempo, mas isso não ocorre. A taxa de aumento de velocidade com n processadores, entretanto, não é n, mas menor que n, ou seja não é uma relação linear. Quando vários processadores cooperam em uma tarefa, uma determinada quantidade de esforço é necessária para manter todas as partes trabalhando corretamente. Esse esforço, em adição à constante disputa por recursos compartilhados, diminui o ganho esperado dos processadores adicionais. Da mesma forma que um grupo de n programadores trabalhando em conjunto não redunda em n vezes a quantidade de trabalho sendo realizada. Outro motivo para a existência de sistemas com múltiplos processadores é o aumento da confiabilidade. Se as funções forem distribuídas adequadamente entre os vários processadores, a falha de um processador não irá interromper o funcionamento de todo o sistema, mas apenas reduzir a sua velocidade como um todo. Por exemplo, no caso de haver 8 processadores e um dentre eles vier a falhar, cada um dos outros 7 processadores poderá arcar com o trabalho extra que estava sendo executado pelo processador defeituoso. O usuário poderá perceber ou não um pequeno aumento na lentidão do sistema. À capacidade de continuar a fornecer serviços proporcionais, em sistemas multiprocessados, dáse o nome de degradação normal e, os sistemas projetados para degradação normal tambem são conhecidos como sistemas tolerantes a falhas. A operação continuada, mesmo com falhas exige um mecanismo para permitir que a falha seja detectada, diagnosticada e corrigida, se possível for. Um exemplo dessa arquitetura é o sistema Tandem que utiliza hardware e software duplicados para garantir a operação contínua, apesar das falhas. O sistema consiste de 2 processadores idênticos, cada qual com sua própria memória local. Os 2 processadores são conectados por um barramento comum, sendo que um dos processadores é o primário e o outro, o back-up. Cada processo sendo executado possui 2 cópias, uma no processador primário e outra no back-up. Em pontos de verificação previamente estabelecidos (checkpoints), durante a execução normal do sistema, as informações sobre o status de cada processo (incluindo cópia da imagem da memoria) são copiadas da máquina primária para a back-up e, se uma falha é detectada, a cópia reserva é 25 ativada e reiniciada a partir do ponto de verificação mais recente. É fácil de se perceber que sistemas tolerantes à falhas são inerentemente mais caros que sistemas tradicionais. Os sistemas com 2 ou mais processadores mais comuns utilizam-se do multiprocessamento simétrico, onde cada processador executa sua própria cópia do sistema operacional, sendo que essas cópias comunicam-se entre si toda vez que for necessário fazê-lo. Outros sistemas podem valer-se de multiprocessamento assimétrico, onde cada processador recebe sua própria tarefa para ser executada. Um processador principal (master) controla todo o sistema e todos os outros processadores escravos (slaves) procuram o mestre para receber instruções ou continuam a executar suas tarefas pré definidas. Esse esquema define uma relação do tipo mestre-escravo (master-slave relationship), onde o processador mestre escalona e aloca trabalho para os processadores escravos. Já no multiprocessamento simétrico , SMP (symmetric multiprocessing), todos os processadores são iguais, não existindo uma relação do tipo mestre-escravo entre os processadores. Cada processador executa uma cópia do sistema operacional de forma concorrente, partilhando um barramento (bus) e uma memória, ambos comuns. Nesse modelo de arquitetura operacional, deve-se ter muito cuidado com as operações de E/S de forma a garantir que as informações (dados) cheguem ao processador correto. Como as CPUs são independentes, uma pode estar ociosa enquanto outra está sobrecarregada, resultando em um sistema ineficiente, o que pode ser minimizado se os processadores compartilharem determinadas estruturas de dados. Um sistema multiprocessado desse tipo permitirá que processos e recursos, como a memória, sejam compartilhados de forma dinâmica entre vários processadores, podendo diminuir a diferença entre os processadores. Um sistema desse tipo deve ser cuidadosamente elaborado, como sera visto no Capitulo 7. Praticamente todos os sistemas operacionais modernos - incluindo o Windows NT, Solaris, Digital UNIX, OS/2 e Linux agora fornecem suporte a SMP. A diferença entre multiprocessamento simétrico e assimétrico pode ser resultado de hardware ou software específicos. Um hardware especial pode diferenciar os múltiplos processadores, ou então o software pode ser escrito de forma a permitir um mestre e vários escravos. Exemplos : o sistema operacional SunOS versão 4 da Sun, fornece multiprocessamento assimétrico, enquanto a versao 5 (Solaris 2) é simétrica, valendo-se do mesmo hardware. CPU1 CPU2 CPU3 CPU4 CPU5 Barramento Compartilhado Controlador de memória Memória compartilhada Arquitetura de multiprocessamento simétrico 26 2.2.2 Sistemas Fracamente Acoplados : de Rede e Distribuídos O grande crescimento das redes de computadores e, em especial, da Internet teve um impacto profundo no desenvolvimento recente dos sistemas operacionais. Quando os PCs surgiram no final dos anos 70 com a finalidade de serem utilizados para uso "pessoal", eles eram considerados computadores independentes. Com o uso mais e mais generalizado da Internet no ínicio dos anos 90, os PCs passaram a poder se conectar à redes de computadores. Com a massiva popularização da WWW (Wide World Web), ou simplesmente Web, em meados da década de 1990, a conectividade de rede passou a ser considerada um componente essencial de um sistema de computação, incluindo-se aí os computadores pessoais. Praticamente todos os PCs e estações de trabalho modernas são capazes de executar browsers (Netscape, Internet Explorer, FireFox etc.) para acessar documentos to tipo hipertexto na Web. Sistemas operacionais como o Windows, MacOS, Linux e UNIX, dentre tantos outros agora também incluem o software de comunicação utilizado na Web, como por exemplo o TCP/IP que permite a um computador acessar a Internet via uma rede local ou conexão telefônica (dial up). Nos sistemas fracamente acoplados, como os processadores estão em arquiteturas diferentes, somente interligados por cabos de interconexão, cada CPU constitui uma máquina independente, com memória própria, dispositivos de E/S e sistemas operacionais independentes. Nesta subdivisão, temos como exemplo as redes e os sistemas distribuídos. No ambiente de rede, existem dois ou mais sistemas independentes (hosts), interligados por linhas telefônicas, que oferecem algum tipo de serviço aos demais, permitindo que um host compartilhe seus recursos, como impressora e diretórios, com os outros hosts da rede. Enquanto nos sistemas em rede os usuários têm conhecimento dos hosts e seus serviços, nos sistemas distribuídos os sistema operacional esconde os detalhes dos hosts individuais e passa a tratá-los como um conjunto único, como se fosse um sistema só, fortemente acoplado. Os sistemas distribuídos permitem, por exemplo, que uma aplicação seja dividida em partes e que cada parte seja executada por hosts diferentes na rede. Para os usuários e suas aplicações é como se não existisse a rede, mas um único sistema centralizado. 27 2.2.3 Sistemas em Clusters Outros exemplos de sistemas distribuídos são os clusters. Em um cluster podem existir dois ou mais servidores ligados por algum tipo de conexão de alto desempenho, e o usuário não conhece os nomes dos membros do cluster e nem quantos são. Quando é necessário algum serviço, basta solicitar ao cluster para obtê-lo, sem se preocupar com quem vai dispor e oferecer tal serviço. Clusters são muito utilizados em servidores de bancos de dados e Web. Em cada servidor, cujo hardware é identico, o software também deve ser idêntico, i.e., existe um sistema operacional exatamente igual, com a mesma versão, mesmo firmware, mesmas quotas de disco, quotas de memória, mesmos usuários e mesmos privilégios, mesmas tarefas/processos sendo executados etc. 2.2.4 Sistemas Embarcados Continuando a descer na escala de tamanho dos sistemas operacionais, vemos os sistemas de computadores de mão e embarcados. Um computador de mão, também conhecido como PDA (Personal Digital Assistant), é um pequeno computador que cabe em um bolso de camisa e realiza um pequeno número de funções como por exemplo, atuar como agenda eletrônica ou um livro de endereços. Sistemas embarcados são executados em computadores que controlam dispositivos que geralmente não são considerados computadores tais como aparelhos de TV, fornos de microondas e telefones móveis. Eles tem, muitas vezes, características de sistemas de tempo real, mas tambem apresentam restrições de tamanho, memória e de consumo de energia que os fazem especiais. Exemplos desses sistemas operacionais sao o PalmOS e o Windows CE (Consumer Electronics). Os telefones celulares também constituem exemplos de sistemas operacionais embarcados, visto que as várias possibilidades oferecidas por esses aparelhos necessitam de um controle operacional e, em especial, aqueles com recursos multimídia e possibilidades de acesso à Internet. O sistema operacional embarcado mais comum é o Symbian, criado para rodar nos celulares "multimídia" com suporte para cameras fotográficas, MMS, wireless, bluetooth dentre outras funções. Este sistema operacional é predominantemente baseado em um ambiente gráfico bastante simples. Por ser pequeno, robusto e modular, como a maioria dos sistemas embarcados, a grande preocupação do Symbian é evitar ao máximo o desperdício dos recursos do celular, como bateria e memória. Para isso ele conta com diversos mecanismos que são eficientes ao tratar com esses problemas. Em sua versão mais nova, a 9.5, foi reduzido o consumo de memória em 30% em relação a versão anterior. Atualmente o Symbian lidera como sendo o SO mais utilizado em smartphones, á frente do Linux e do Windows Mobile, entre outros. 2.2.5 Sistemas de Cartões Inteligentes Os menores sistemas operacionais estão presentes nos assim chamados cartões inteligentes (smart cards) - dispositivos do tamanho de cartões de crédito que contém um chip de CPU, que na maioria das vezes é um microcontrolador. Esses sistemas possuem restrições severas de consumo de energia elétrica e de memória. Alguns deles podem realizar apenas uma única função, como por exemplo pagamentos eletrônicos, mas outros podem efetuar múltiplas funções no mesmo cartao inteligente. Esses sistemas são normalmente sistemas proprietários. Alguns desses cartões inteligentes são orientados à Java, o que significa dizer que a ROM do cartao inteligente contém um interpretador para a máquina virtual Java (Java Virtual Machine JVM). As pequenas aplicações Java denominadas applets são carregadas no cartão e interpretadas pelo JVM. Alguns desses cartões podem tratar várias applets Java ao mesmo tempo, gerando um 28 ambiente de multiprogramação (multitask) e a conseqüente necessidade de escalonamento dessas tarefas (processos). O gerenciamento de recursos e os aspectos relacionados à proteção, quando 2 ou mais applets estão presentes simultaneamente, podem se transformar em problemas potenciais, problemas esses que devem ser tratados pelo sistema operacional contido no cartão. 29 3.0 Arquiteturas de Sistemas Operacionais 3.1 Sistema Monolítico Um sistema operacional é dito ser monolítico quando todos os seus componentes estão contidos no seu próprio kernel , i.e, dentro do próprio sistema operacional e, em assim sendo, todo componente pode comunicar-se diretamente com qualquer outro de maneira rápida, ainda que não de forma modular e estruturada. Tal abordagem tende a ser altamente eficaz, dado que muito pouco tempo é gasto nas chamadas internas ao próprio sistema, entretanto a grande desvantagem dessa abordagem é que por não ser uma concepção modular, fica muito mais difícil a determinação e correção dos erros mais sutis. Aplicação Aplicação Modo Usuário Modo Kernel System Call Núcleo do Sistema Hardware 30 3.2 Sistemas em Camadas Na tentativa de se fugir do conceito e da implementação de um sistema operacional monolítico, tentou-se um outra abordagem, de conceituação mais modular, i.e, o agrupamento de componentes que executam funções semelhantes. Nessa nova abordagem, cada camada comunica-se apenas com as camadas imediatamente acima ou abaixo dela. Dessa forma, as solicitações dos processos devem passar por várias camadas para serem concluídas e, com certeza, o desempenho (rendimento) do sistema pode ser menor do que o dos núcleos monolíticos, mas ganha-se na modularidade no projeto, o que é, por si só, uma enorme vantagem em caso de se depurar o sistema operacional, ainda em seus estágios mais preliminares. Além disso, outros métodos precisam ser chamados para transmitir dados e controle, obedecendo-se à uma hierarquia, tal qual a hierarquia existente em uma empresa. Um dos primeiros sistemas operacionais a abordar o conceito “em camadas” foi o sistema operacional THE (Technische Hogeschool Eindhoven), elaborado por Dijkstra na Holanda em 1968 e esquematizado abaixo: Um outro exemplo comumente mencionado ao se tratar de sistemas operacionais em camadas é o sistema operacional da antiga DEC (Digital Equipment Corporation, que foi comprada pela Compaq, atual HP), o Open VMS. Este sistema se tornou extremamente aceito no mercado em função da sua estabilidade operacional, rapidez e pelo baixo número de problemas decorrentes da utilização dos seus aplicativos (e do seu kernel). 31 3.3 Sistema de Micronúcleo (Microkernel) Um sistema operacional de micronúcleo fornece, como seu próprio nome sugere, somente um número pequeno de serviços e com isso, manter seu kernel pequeno e coeso, porém mantendo um alto grau de modularidade. Esses sistemas operacionais são normalmente extensíveis, portáteis e escaláveis,o quer requer um maior nível de comunicação entre módulos, o que, em contrapartida, acarreta uma diminuição do desempenho do sistema. Servidor Arquivo Servidor Memória Servidor Processo Servidor Impressão Servidor Rede Modo Usuário Modo Kernel Microkernel Hardware 32 3.4 Características de um Sistema Operacional De uma forma geral, algumas das principais características desejáveis nos sistemas operacionais, do ponto de vista dos usuários (U) e dos projetistas (P) de Sistemas Operacionais são : eficiência modularidade robustez escalabilidade extensibilidade portabilidade usabilidade segurança estabilidade operacional velocidade operacional interatividade preço acessível boa documentação (U, P) (P) (U, P) (U, P) (U, P) (U, P) (U, P) (U, P) (U, P) (U, P) (U) (U) (U, P) Um sistema computacional qualquer é composto pelo Hardware (HW), como por exemplo, pela(s) CPU(s), pela mais diversos tipos de memória, dispositivos de E/S (impressoras, vídeo, placas de comunicação), controladores, fios, componentes eletrônicos, conectores etc. e pelo Software(SW), que pode ser subdividido em aplicativos (comprados e/ou desenvolvidos pelos usuários) e pelo próprio sistema operacional, normalmente adquirido de um fabricante especializado. Considerando-se os tipos de sistemas operacionais descritos anteriormente, reforça-se o conceito de que multiprogramação é nome dado às técnicas que possibilitam que um sistema computacional qualquer dotado de uma única CPU seja compartilhado entre os diferentes processos ativados pelo usuário. Um sistema operacional eficiente alcança alto rendimento e baixo tempo de retorno. O rendimento mede a quantidade de trabalbo que um processador pode conduir em um certo período de tempo. Um dos papeis de um sistema operacional é fornecer serviços a muitas aplicações. Um sistema operacional eficiente minimiza o tempo gasto oferecendo esses serviços. Um sistema operacional robusto é tolerante á falhas e confiável - o sistema não falhará devido a erros isolados de aplicações ou de hardware e, se falhar, ele o fará de forma gradual, minimizando perda de trabalho e evitando danos ao hardware do sistema. Determinado sistema operacional fornecerá serviços à cada aplicação, a menos que o hardware venha a falhar. Um sistema operacional escalável é capaz de usar recursos na medida em que vão sendo acrescentados ao computador. Se um sistema operacional nao for escalável, rapidamente chegará a um ponto em que recursos adicionais não serão utilizados totalmente. Um sistema operacional escalavel pode ajustar imediatamente seu grau de multiprogramação. A escalabilidade é um atributo particularmente importante dos sistemas multiprocessadores na medida em que são adicionados mais processadores ao sistema. 33 Idealmente a capacidade de processamento deve crescer proporcionalmente ao número de processos, embora, na prática, isso nao aconteça. Um sistema operacional extensivel adapta-se bem às novas tecnologias e fornece capacidades de estender o sistema operacional para executar tarefas que vão além de seu projeto original. Um sistema operacional portável é projetado de modo tal que possa operar em muitas configurações de hardware. A portabilidade de aplicações tambem é importante porque desenvolver aplicações custa caro - a mesma aplicação deve rodar em uma variedade de configurações de hardware para reduzir os custos de desenvolvimento. O sistema operacional é crucial para se obter esse tipo de portabilidade. Um sistema operacional seguro impede que usuários e software acessem serviços e recursos sem autorização. A proteção refere-se aos mecanismos que implementam a política de segurança do sistema. Um sistema operacional interativo permite que aplicações respondam rapidamente às ações do usuário ou aos eventos que venham a ocorrer. Um sistema operacional utilizável é aquele que tem o potencial de atender à uma base significativa de usuários. Esses sistemas operacionais geralmente fornecem uma interface com o usuario fácil de usar. Sistemas operacionais como o Linux, Windows XP e MacOS são caracterizados como utilizáveis porque cada um suporta um grande conjunto de aplicações e fomece as interfaces-padrao com o usuario. Muitos sistemas operacionais experimentais e acadêmicos não suportam um grande número de aplicações e nem fornecem interfaces amigáveis com o usuario e, portanto, não são considerados utilizáveis. 34 4.0 Concorrência Os sistemas monoprogramáveis sub-utilizam os recursos do sistema computacional como um todo, i.e., a CPU (processador), a utilização da memória principal e todos os periféricos associados a tal sistema. Sistema Monoprogramável x Sistema Multiprogramável Ao realizar uma operação qualquer de E/S (I/O) o processo perde o uso da CPU temporáriamente para retornar, após a operação de E/S ter sido terminada, para o estado em que se encontrava anteriormente. Observe que nos gráficos acima representados, no sistema monoprogramável, enquanto uma determinada operação de E/S ocorre, a CPU fica ociosa, ao passo que no sistema multiprogramável, isso já não ocorre, ou seja, a operação de E/S ocorre em paralelo com a execução do processo 2. Há situações em que alguns processos fazem uso mais intensivo da CPU do que de operações de E/S e, portanto, a utilização da CPU para esses processos torna-se prioritária e essencial – dá-se o nome de processos polarizados na CPU para tais processos (CPU biased process ou CPU bounded process), como por exemplo, durante a execução de cálculos matemáticos simulando um determinado processo físico (simulações financeiras, previsão numérica de tempo etc.). Por outro lado, há situações em que há uma demanda maior de operações de E/S ao invés de CPU e, portanto, dá-se o nome de processos polarizados em E/S (I/O biased process ou I/O bounded process), como por exemplo, durante o processo de desfragmentação de um disco ou de cópia de arquivos de um disco para outro. Nesses casos, a CPU é utilizada de forma bem menos intensiva, o que a torna disponível para executar mais processos. 4.1 Interrupções As interrupções podem ser vistas como intervenções do sistema operacional devido à ocorrência de algum evento previsto ou imprevisto. Elas podem ocorrer de forma síncrona, i.e., interrupções que são previstas para ocorrer em intervalos regulares e periódicos, como por exemplo, a interrupção do relógio do sistema (system clock), que não devem ser confundidas com o relógio do computador, mostrado abaixo, e que nos informa do dia, mês, ano, hora e minuto. Já as interrupções assíncronas não tem um tempo certo para ocorrer, podendo ocorrer ou não durante um determinado período de tempo, como por exemplo, o que ocorre com as chamadas 35 telefônicas oriundas de um telefone fixo ou celular. Elas podem ocorrer ou não ao longo de um determinado período de tempo e, se ocorrerem, não há como prever quando elas ocorrerão, quanto tempo durarão e quantas vezes elas acontecerão. Isso confere um caráter aleatório a esses acontecimentos, sendo portanto chamados de assíncronos. As interrupções, quando ocorrem, desviam o fluxo de execução anteriormente sendo executado pela CPU para uma rotina de tratamento da interrupção própria para aquele tipo de interrupção, sendo necessário para isso que a interrupção traga consigo a informação de quem a gerou. As interrupções podem ser geradas internamente a um programa, pelo próprio sistema operacional ou por um evento externo, tal como por exemplo, uma interrupção gerada pelo hardware. Cada interrupção possui uma rotina de tratamento associada, e a associação entre elas é mantida em uma estrutura denominada vetor de interrupção. As interrupções ainda podem ser do tipo internas e externas: a)Internas: há instruções de máquina que são vistas como sendo interrupções internas, como por exemplo a instrução INT das CPUs Intel 8080 e 8085. Essas instruções ao serem executadas pela CPU gera um efeito semelhante à de uma interrupção externa. Uma exceção é um tipo de interrupção normalmente associada à um erro como por exemplo um estouro de capacidade (overflow) ou por uma tentativa de divisão por zero. b)Externas: interrupções externas são aquelas geradas pelo SO ou por algum dispositivo periférico (HW) pertencente ao sistema computacional, como por exemplo, o término de uma dterminada operação de E/S em disco ou impressora, ou o clickar de algum dos botões do mouse, dentre tantos outros exemplos. Para que uma interrupção possa ser atendida pela CPU, algumas condições essenciais devem ocorrer, como por exemplo as macro-ações dadas acima (salvamento dos registradores, identificação da causa da interrupção, processamento do código inerente ao atendimento daquela interrupção em particular, a restauração dos conteúdos dos registradores anteriormente salvos e o retorno ao ponto em que a interrupão ocorrreu. 36 As interrupções podem ser do tipo mascaráveis ou não mascaráveis. Se a interrupção externa puder ser desabilitada pela CPU ela é denominada mascarável (masked interrupt) e será ignorada, não recebendo tratamento. Caso contrário, ela é chamada de interrupção não-mascarável ou do tipo NMI (non-masked interrupt) e o tratamento será obrigatório. As interrupções podem ser ou não aninhadas, i.e, uma determinada interrupção pode ser interrompida por uma outra mais prioritária e assim por diante. Como há uma prioridade associada à cada interrupção, uma determinada interrupção só pode ser interrompida por uma outra interrupção de prioridade maior. A hierarquia deve ser respeitada, entretanto, mesmo as interrupções de prioridade menor devem ser atendidas ainda que mais tardiamente, portanto a regra geral é que toda interrupção deve ser atendida. 4.2 Operações de Entrada e Saída (E/S): Inicialmente, a CPU executava todas as instruções de E/S e, para isso, essas instruções tinham que conter informações detalhadas sobre os diversos periféricos tais como por exemplo as trilhas e setores que poderiam ser lidos ou gravados em uma unidade de disco. Com o passar do tempo, o controlador (ou interface) criou a independência entre a CPU e os dispositivos de E/S, pois este faz a intermediação entre os dois. As características dos dispositivos ficaram a cargo do controlador e as instruções de E/S foram, portanto, simplificadas. O monitoramento do dispositivo e a transferência de dados entre a CPU e os periféricos evoluiu com o tempo, mas algumas das técnicas utilizadas até hoje são dadas abaixo: 4.2.1 E/S Controlada por Programa A CPU inicia a transferência e indaga continuamente o periférico sobre o final da instrução de E/S – essa atitude é um grande desperdício de tempo da CPU. 4.2.2 Polling O status do dispositivo periférico era testado em intervalos de tempo, liberando a CPU para a execução de outro(s) programa(s). No caso de existirem muitos periféricos, o sistema interrompia freqüentemente o processamento para testar o término exato da operação. 4.2.3 E/S Controlada por Interrupção A CPU envia um comando para o controlador que se encarrega de ler o disco e armazenar na memória ou em registradores internos (próprios). Ao término, o controlador sinaliza uma interrupção ao processador que, ao tratá-la, busca os dados solitados. Várias operações de E/S podem ser executadas paralelamente, porém toda a transferência de dados entre a memória e os periféricos exige utilização da CPU. 4.2.4 DMA (Direct Memory Access) O controlador recebe informações de onde os dados se encontram, qual o dispositivo de E/S envolvido, posição inicial de memória onde os dados serão lidos ou gravados e o tamanho do bloco de dados. Com essas informações, a transferência é realizada pelo controlador (que assume temporariamente o controle do barramento), utilizando para essa transferência uma área de memória temporária denominada buffer, descrita a seguir. 4.2.5 Canal de E/S (I/O Channel) É um processador com controle total sobre os dispositivos de E/S a ele conectados (vários controladores), o qual executa um programa de canal (armazenado na memória RAM) que especifica os dispositivos e os buffers e controla possíveis erros da transferência, sinalizando a CPU ao final da operação. 37 4.2.6 Processador de E/S (IOP – Input Output Processor) O canal passou a ter sua própria memória de modo que a intervenção da CPU se tornou mínima, deixando a maior parte do trabalho de transferência de dados para o processador de E/S (ou IOP – Input Output Processor). 4.2.7 Buffers Dá-se o nome de buffer à uma parte da memória principal ou secundária para possibilitar a transferência de dados entre os periféricos e a CPU. Essa área de buffer é temporária, normalmente alocada dinamicamente e visa minimizar as diferenças de velocidade do processamento da CPU e dos dispositivos de E/S e mesmo entre os vários dispositivos de E/S. A unidade lógica que normalmente é associada à utilização de buffers é denominada “registro” e que é normalmente formatado em função de um determinado dispositivo de E/S, como por exemplo, uma linha a ser impressa, a leitura de cada caracter de teclado) ou da leitura e/ou gravação de um registro lógico de um arquivo. O dispositivo transfere um dado para o buffer e pode iniciar nova leitura. A CPU pode manipular o dado no buffer simultaneamente às leituras do dispositivos. Na gravação o processo é semelhante, com a CPU alocando dados no buffer, sendo que neste podem existir dados lidos mas não processados, ou processados e ainda não gravados. 4.2.8 Spooling (Simultaneous Peripheral Operation On-Line) Surgiu como opção para um melhor aproveitamento da CPU e dos dispositivos periféricos utilizados no início da década de 60 e objetivava principalmente, a impressão. Ao invés de enviar os resultados gerados pelos diferentes jobs diretamente para a impressora e ficar esperando o término da impressão para iniciar a execução de outro programa, a CPU envia os resultados de cada job para um arquivo intermediário que no início ficava armazenado em um fita magnética. Este arquivo era então lido e então, impresso, sendo que a ordem de impressão dos jobs era determinada pelas prioridades a eles atribuídas. O nome de spooler era dado ao sistema que gerenciava as impressões. Atualmente, as funções atribuídas ao spooler ainda se encontram presentes em diversos servidores de impressão, com funções e características bem mais sofisticadas do que as antigas. 4.3 Reentrância Reentrância consiste na capacidade de um determinado processo apresentar um código reentrante, i.e., um código especialmente elaborado para ser compartilhado, na memória, por diversos usuários. Dessa forma há normalmente apenas um cópia carregada para a memória e, em sendo assim, este código, por razões óbvias, não pode ser alterado. A reentrância se aproveita do fato de que todo programa pode ser desenvolvido de tal forma que a área de código deste se encontra separada da área de dados e desta forma cada usuário pode estar em um ponto diverso do programa, manipulando seus próprios dados. Vários utilitários do sistema tais como editores, compiladores, linkeditores são exemplos de códigos reentrantes. 38 4.4 Proteção ao Sistema Em ambientes onde muitos usuários compartilham recursos e dados, o sistema operacional deve prover mecanismos que garantam: a) Integridade dos dados de cada usuário: um programa não pode acessar a área de memória do outro (acidentalmente ou não). O mecanismo de gerência de memória determina a forma de controle. b) Compartilhamento de dispositivos de E/S: um programa só pode utilizar um dispositivo de E/S no momento em que o primeiro programa o liberar. c) Compartilhamento de arquivos: o SO provê mecanismo de controle de acesso à arquivos de modo que as informações do usuário permaneçam consistentes. d) Compartilhamento de CPU: o uso da CPU deve ser compartilhado entre os diferentes programas de maneira rígida, pois é o principal componente do sistema. 4.5 Modos de Execução Cada vez que o usuário necessita utilizar um recurso do sistema computacional ele o solicita ao Sistema Operacional através de funções (rotinas) do próprio sistema denominadas de System Calls ou System Services ou Sytem Internals. Essas rotinas, para acessarem os recursos disponibilizados, devem possuir mecanismos de proteção. O mecanismo mais utilizado nos sistemas multiprogramáveis é chamado de modo de execução. Consiste de uma característica que, associada ao programa em execução, determina se ele pode executar certas instruções ou funções do sistema operacional. O modo corrente é armazenado em um registrador especial da CPU, o qual é verificado pelo hardware e assim executar ou não a instrução. Há 2 modos de execução: a) Modo Usuário: o programa só executa instruções que não afetem diretamente os outros programas (instruções não privilegiadas). b) Modo Supervisor (monitor ou kernel): qualquer instrução pode ser executada, mesmo rotinas do sistema (instruções privilegiadas). Em uma leitura, por exemplo, o programa solicita o acesso ao disco ao Sistema Operacional que verifica se o arquivo pode ser acessado. Se sim, muda o Modo de Execução para supervisor, realiza a operação de leitura e retorna o Modo de Execução para usuário, continuando o processamento. O sistema operacional sempre executa em modo supervisor, pois é responsável pelo compartilhamento dos recursos, e deve possuir esta capacidade. 39 5.0 CPU – Unidade Central de Processamento (Central Processing Unit) A CPU é composta por vários blocos funcionais interligados como por exemplo a unidade de controle, a unidade de busca e decodificação, a ULA (Unidade Lógica e Artmética), os registradores etc. Os registradores são áreas destinadas ao armazenamento temporário de informações, localizadas no interior da CPU, apresentando tempo de acesso mais rápido do que as palavras da memória principal. Distinguimos 2 conjuntos básicos de registradores: 5.1 Registradores Visíveis São considerados registradores visíveis ao programador todos aqueles registradores considerados como sendo de uso geral, como por exemplo, o acumulador, os registradores r0, r1, ..., rn (ou quaisquer que sejam os seus nomes). Além desses há ainda os registradores de controle e de funções especiais tais como o PC, o SP e o PSW. O registrador PC (program counter) contém o endereço de memória da próxima instrução a ser buscada; o registrador SP (stack pointer) contém o endereço de memória do topo da pilha (stack) e o registrador PSW (processor status word) é a palavra de estado da CPU que contém os flags, que nada mais são do que indicadores específicos da ocorrência de determinadas condições que refletem o estado da última instrução/operação lógico aritmética realizada. 5.2 Registradores Invisíveis Os registradores “invisíveis” são todos aqueles registradores utilizados para controle interno da CPU, como por exemplo os registradores MAR, MDR etc. e utilizados somente para a microprogramação interna à própria CPU. Os programadores não possuem acesso a esses registradores. Funcionalmente, a CPU pode encontrar-se em 1 dentre 2 estados: o de suspensão ou em processamento. No estado de suspensão, ela aguarda por um evento externo (geralmente uma interrupção) para passar ao estado de processamento; no estado de processamento, ela realiza continuamente um ciclo de busca, decodificação e execução de instruções. 1) A fase de busca consiste na leitura da palavra de memória cujo endereço está especificado no registrador PC. 2) A fase de decodificação consiste em desmembrar a instrução em seus diversos componentes (código de operação e operandos). 3) Como uma instrução pode ser codificada em mais de uma palavra de memória, as fases de busca e decodificação são, na verdade, inter-dependentes. 4) Ao final da fase de busca/decodificação, o registrador PC deverá conter o endereço da palavra seguinte à última palavra da instrução em questão. A execução da instrução assemelha-se ao conceito matemático de função: uma operação (especificada pelo código de operação) é realizada sobre os operandos (especificados por modos de endereçamento). Há instruções que envolvem zero (0) , 1 ou 2 operandos. Para ser executada, cada instrução (especificada em um programa em linguagem de montagem (Assembly Language)) é decomposta em uma série de microinstruções, armazenadas em uma memória interna à CPU, denominada de memória de microprograma. 40 As CPUs do tipo CISC (Complex Instruction Set Computer) possuem microprogramas complexos, onde a maior parte das instruções executadas pela CPU são quebradas em instruções ainda menores, denominadas microinstruções ou microcódigo. Esse microcódigo fica armazenado na memória de microcontrole, interna à CPU. As CPUs do tipo RISC (Reduced Instruction Set Computer) possuem, em seu repertório, instruções já bastante próximas (ou mesmo idênticas) às microinstruções, algumas vezes dispensando a existência do microprograma. Os modos de endereçamento especificam a localização dos operandos, que podem estar em 3 localidades: em registradores internos da CPU, na memória principal ou em registradores das controladoras dos periféricos (normalmente denominados portas). Alguns modos importantes de endereçamento são: Modo registrador: Modo absoluto: Modo imediato: Modo indireto: Modo base+deslocamento: Modo de entrada/saída: mov mov mov mov mov out r0,r1 234,r2 #421,sp [r3],r0 [r3+20],r2 r3,255 ; in 300,r1 Algumas CPUs possuem instruções que admitem mais de um operando externo (que não está em um registrador da CPU); outras admitem, no máximo, uma referência a dados externos por instrução. Para implementar alguns mecanismos básicos de proteção em um sistema operacional, é essencial que a CPU possa funcionar em pelo menos 2 modos de execução: o modo usuário (ou não privilegiado) e o modo supervisor (Kernel ou privilegiado). Funcionando em modo supervisor (ou kernel), a CPU pode executar qualquer instrução do seu repertório de instruções, sem restrições quanto à localização dos operandos. No modo usuário, a tentativa de executar algumas instruções especiais causa exceções, como por exemplo a instrução HALT (parar, em Alemão). A execução dessa instrução instrui a CPU a interromper imediatamente todo e qualquer processamento, fazendo-a entrar no modo idle . A única forma de tirar a CPU desse estado de suspensão é através de um reset do hardware ou momentaneamente através de uma interrupção externa. O modo corrente de funcionamento é armazenado em um bit da PSW (processor status word) e, nesse caso, o valor 0 pode significar modo Supervisor e o valor 1 pode significar modo Usuário. A transição do modo kernel para o modo usuário não oferece problemas desde que se tenha as prerrogativas (privilégios) para fazê-lo, bastando para isso colocar o bit correspondente na PSW em “1” ou em “0”; Já a transição contrária deve ser feita através de uma instrução especial (TRAP) que, ao mesmo tempo que inverte o valor do referido bit, provoca a chamada a uma subrotina situada em um endereço bem conhecido pelo sistema operacional. 5.3 CPU, Comunicação e Periféricos São atualmente conectados ao barramento através de interfaces controladoras e acionados através de comandos parametrizados enviados pelas CPUs, mas a situação nem sempre foi assim. 41 O diálogo entre a CPU e a controladora envolve operações de leitura e escrita nos registradores internos da controladora. Esses registradores possuem endereços e o acesso a eles se faz basicamente de duas maneiras, dependendo da arquitetura escolhida: através de instruções especiais para entrada e saída, como IN e OUT (E/S direta ou via IOP); através de instruções regulares da CPU, que utilizam uma faixa de endereços não direcionada à memória principal (E/S mapeada). Há 3 técnicas importantes para o tratamento de entrada e saída: 5.3.1 Loop de Status A CPU comanda a operação desejada, escrevendo os parâmetros e o código de operação nos registradores da controladora. A conclusão da operação é aguardada em uma malha, na qual são lidos registradores de estado da controladora até que algum padrão de bits neles se evidencie. Durante a malha, a CPU não pode ser dedicada a outras atividades. Normalmente a malha não é repetida indefinidamente, mas até um número máximo de vezes (timeout), para evitar o monopólio da CPU. 5.3. 2 Interrupção A CPU comanda a operação desejada, escrevendo os parâmetros e o código de operação nos registradores da controladora, dedicando-se, em seguida, a outras tarefas. Quando o periférico conclui a operação, a controladora interrompe a CPU, depositando no barramento sua identificação, a identificação da CPU a ser interrompida e o sinal de interrupção. As CPUs, ao fim de cada ciclo de busca/decodificação/execução, verificam a existência de pedidos de interrupção (caso não estejam mascaradas). Baseada na identificação do periférico, a CPU interrompida simula uma chamada a uma subrotina de atendimento da interrupção, situada a partir de um endereço de memória calculado em função da identificação da controladora. São empilhadas informações que possibilitem o retorno inequívoco ao ponto de execução que está sendo interrompido (PC e PSW). A subrotina de atendimento: empilha todos os registradores de uso geral (r0, r1, ...); avalia os resultados da operação comandada (lendo registradores de estado da controladora); realiza, se necessária, a transferência de dados entre a memória e a controladora; comanda uma próxima operação, se for o caso. Ao terminar seu processamento, a subrotina de atendimento desempilha os registradores de uso geral e utiliza uma instrução especial de retorno de subrotina (IRET), que desempilhará a PSW e o PC; isto causará o retorno ao ponto onde o processamento foi interrompido. Há vários tipos de operações que podem gerar diversas interrupções ao longo de seu processamento. Portanto, muitas vezes, as subrotinas de atendimento devem implementar uma máquina de estados, a fim de processar corretamente os diversos estágios da operação. 42 5.3.3 Via DMA (Direct Memory Access) É um processador que se ocupa da transferência de dados entre a controladora e a memória principal. A programação do DMA pode ser explícita ou implícita ao comando de entrada e saída enviado pela CPU à controladora do periférico. Devem ser informados: o endereço de memória a partir do qual os dados serão lidos ou escritos; o número de palavras a transferir; o sentido da transferência (controlador memória, em caso de leitura ou memória controlador, em caso de escrita). A transferência dos dados se dá sem intervenção da CPU, diretamente entre a controladora e a memória principal através de uma técnica denominada de roubo de ciclo (cycle stealing), onde o controlador de DMA rouba ciclos da CPU. A operação comandada só é considerada concluída quando os dados já estiverem transferidos. O DMA pode ser usado tanto em tratamento por loop de status quanto em tratamento por interrupção. Ao perceber um sinal de interrupção pendente, a CPU deverá simular uma chamada à subrotina de atendimento: É necessário que esta subrotina esteja na memória principal, armazenada a partir de um determinado endereço. Como várias controladoras podem enviar pedidos de interrupção a uma CPU, o comum é organizar uma tabela, denominada vetor de interrupções, situada em um endereço de memória bem conhecido pela CPU (pode haver um registrador que armazene este endereço). Cada entrada desta tabela refere-se a uma fonte externa de interrupção e deve conter, dentre outras informações, o endereço da subrotina de atendimento específica daquela interrupção. De posse da identificação da controladora (informada à CPU juntamente com o pedido de interrupção), após empilhar o PC e a PSW, a CPU indexa esta tabela, atribuindo ao PC o endereço da subrotina de atendimento. A fim de priorizar o atendimento de alguns periféricos sobre outros, as CPUs costumam associar níveis de prioridade ao atendimento de interrupções, permitindo o aninhamento de subrotinas de atendimento: Em um campo da PSW, fica guardado o nível corrente de funcionamento. Se a CPU está em processamento normal (não atendendo interrupções) o nível corrente é 0. Quando uma controladora interrompe, deve informar à CPU o nível da interrupção que está solicitando. A CPU só admite interrupções de nível superior ao corrente; do contrário, o pedido ficará pendente até que a CPU possa atendê-lo. Quando uma interrupção é atendida, o PSW é empilhado juntamente com o PC e o nível corrente na PSW passa a ser o nível desta interrupção. Ao retornar do atendimento (instrução IRET – Interruption Return), a CPU desempilha os valores do PC e da PSW e o nível corrente volta ao que era imediatamente antes do atendimento. A função de salvar e restaurar os conteúdos de todos os registradores internos à CPU é de responsabilidade do programador, sendo vital que ele o faça. O assim chamado “empilhamento” dos conteúdos dos registradores da CPU dá-se em uma área de memória RAM cujo endereço é dado pelo conteúdo do registrador SP (Stack 43 Pointer), ou ponteiro de pilha, cujo conteúdo vai sendo alterado à medida em que os dados vão sendo “empilhados”. O “desempilhamento” desses mesmos conteúdos deve ser feito na ordem exata em que foram “empilhados”, caso contrário o conteúdo de um registrador pode ser alocado em outro registrador, o que pode acarretar erros no processamento assim que a CPU voltar ao fluxo de processamento anterior à interrupção. Concluindo: o registrador PSW, no nosso modelo, deverá conter os seguintes campos: Flags (indicadores, como Zero, Carry, Negative, Overflow, Parity, etc...); Modo Corrente de Execução (0 = supervisor, 1 = usuário); Nível Corrente de Aninhamento de Interrupções. 44 6.0 Processos O conceito básico de processo é o de um programa sendo executado pela CPU e que possui seu próprio contexto operacional. Os processos podem ser de natureza interna ou externa. Os de natureza interna são os processos internos ao próprio sistema operacional e os de natureza externa são aqueles que tem origem em aplicativos desenvolvidos ou ativados pelo usuário, como por exemplo, um programa Java, um editor de texto, um aplicativo para processamento de imagens e sons etc. O conceito de processo é a base para a implementação de um sistema multiprogramável. O processador é projetado apenas para executar instruções, não sendo capaz de distinguir qual programa se encontra em execução.A gerência de um ambiente multiprogramável é função exclusiva do sistema operacional, que deve controlar a execução dos diversos programas e o uso concorrente do processador. A gerência do processador é uma das principais funções de um sistema operacional. Através dos processos, um programa pode alocar recursos, compartilhar dados e trocar informações. 6.1 Componentes do Processo Conforme já mencionado, um processo pode ser entendido inicialmente como um programa em execução, que tem suas informações mantidas pelo sistema operacional e em um sistema multiusuário, cada usuário tem a impressão de possuir o processador e todos os demais recursos reservados exclusivamente para si, mas isto não é verdade. Todos os recursos estão sendo compartilhados, inclusive a CPU. Neste caso, o processador executa o processo do usuário por um intervalo de tempo e, no instante seguinte, poderá estar processando um outro programa, do mesmo ou de outro usuário. O mesmo é válido para um sistema monousuário mas multitarefa, onde o único usuário tem a “impressão” de que todos os processos estão sendo executados simultaneamente – essa impressão advém da velocidade de execução da CPU. Se a CPU em questão for lenta, essa impressão de simultaneidade se dissipa rapidamente e o usuário passa a ter a percepção de que o sistema como um todo está lento. Para que a troca de processos possa ser feita sem problemas, é necessário que todas as informações do programa que está sendo interrompido sejam armazenadas em uma área segura, para que a CPU possa retomar a sua execução exatamente do ponto em que parou, não lhe faltando nenhuma informação vital à sua continuação. Todas as informações necessárias à execução de um programa fazem parte do processo. Um processo também pode ser definido como o ambiente onde o programa é executado. Este ambiente, além das informações sobre a execução, possui também a quantidade de recursos do sistema que o programa pode utilizar,como espaço de endereçamento, tempo do processador e área em disco. 6.2 Contexto e PCB Cada processo possui seu próprio ambiente de execução que é denominado contexto de execução desse processo. Um mesmo processo, dependendo do contexto no qual está sendo executado em um determinado sistema computacional poderá eventualmente obter resultados diferentes, como por exemplo no caso de um processo sendo executado em um ambiente operacional no qual há cotas de utilização de disco limitadas e o mesmo processo sendo executado em um outro ambiente operacional no qual não há cotas de disco estabelecidas. No primeiro caso, o processo 45 poderá ser abortado pelo sistema operacional por tentar utilizar mais espaço em disco do que o permitido e no segundo caso ele poderá ser executado até o final sem qualquer problema. O sistema operacional utiliza estruturas de dados conhecidas como Bloco de Controle de Processos (PCB – Process Control Block) que são associadas a cada processo em execução. Se houver 100 processos sendo executados em um determinado sistema operacional, haverá 100 PCBs, cada uma delas associada a um processo. Se houver 1000 processos (internos e/ou externos) no total, haverá 1000 PCBs. A estrutura de uma PCB pode variar de sistema para sistema, assim como os dados nela armazenados, mas de uma forma geral, há uma estrutura comum, em maior ou menor grau, que é detalhada abaixo, onde PID designa a identificação do processo (Process Identification) . PID Ponteiro para a área de memória deste PCB PID Ponteiro para o PCB deste processo PID Ponteiro para o PCB deste processo PID Ponteiro para o PCB deste processo Registradores internos à CPU PID Ponteiro para o PCB deste processo PID Ponteiro para o PCB deste processo Prioridade atual do processo Status operacional do processo PID Ponteiro para o PCB deste processo Identificação do processo (PID) ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Nome simbólico do processo PID Ponteiro para o PCB deste processo Quotas de memória Quotas de disco Dados sobre o processo pai Dados sobre cada processo filho Informações adicionais 46 Na figura anterior, do lado direito, há um campo denominado Registradores internos à CPU e que é constituído por vários outros campos, cada campo contendo o conteúdo de cada um dos registradores internos à CPU, i.e., se a CPU tiver 8 registradores esse campo terá 8 sub-campos, por assim dizer, e se ela tiver 10, 12, 16 ou n registradores haverão 10, 12, 16 ou n sub-campos, conforme detalhado na figura abaixo, onde uma CPU hipotética contem n registradores no total. Registradores internos à CPU Conteúdo do PC Conteúdo do SP Conteúdo do PSW Conteúdo do acumulador Conteúdo do R0 Conteúdo do R1 ::::::::::::::::::::::::::::::::::::::::::::::::: :: ::::::::::::::::::::::::::::::::::::::::::::::::: Conteúdo do Rn A mesma abordagem pode acontecer para outros campos do PCB, i.e, mais ponteiros indicando o endereço inicial de outras estruturas, mas isto é função da implementação do sistema operacional e não uma regra rígida. O sistema operacional gerencia os processos através das system calls, que realizam diversas operações , tais como acesso à discos, alocação e dealocação de áreas de memória, verificação de privilégios de usuários, criação, remoção, eliminação, sincronização e suspensão de processos, dentre muitas outras funções. O contexto de um processo pode ainda ser subdividido em 3 elementos básicos, que integrados, fornecem o contexto de qualquer processo: a) contexto de software: o contexto de software se aplica às características operacionais do processo, como por exemplo a identificação do processo, a PID (Process Identification), os privilégios que este processo pode possuir, a identificação do usuário que o iniciou, quotas de utilização de disco e memória, número máximo de arquivos simultaneamente abertos, tamanho dos buffers para operações de E/S etc. Dentre todos esses, destacam-se : 1) Identificação: neste grupo são guardadas informações sobre o usuário que criou o processo, e, em função disso, suas áreas de atuação no sistema. 2) Quotas: são os limites de recursos do sistema que um processo pode alocar, como a área utilizada em disco, em memória, limite de linhas impressas, número máximo de arquivos abertos, número máximo de operações de E/S pendentes, tempo limite de CPU, etc. 3) Privilégios: dizem respeito principalmente às prioridades assumidas pelo processo durante sua execução. 47 b) contexto de hardware: o contexto de hardware se aplica principalmente aos conteúdos dos registradores da CPU. A manutenção desse contexto é fundamental para a implementação de sistemas de tempo compartilhado (time sharing). Essa é uma característica básica em qualquer sistema do tipo multitarefa e a troca de um processo por outro na CPU, realizada pelo sistema operacional é conhecida como mudança de contexto (context switching) . A mudança de contexto consiste em salvar os conteúdos dos registradores da CPU e carregá-los com os conteúdos dos registradores do processo que está ganhando a CPU. c) espaço de endereçamento na memória: o espaço de endereçamento é a área de memória atribuída pelo sistema operacional ao programa que após ser carregado para a memória será executado. Essa área pertence somente ao processo, devendo ser protegida dos demais processos. 6.3 Estados Básicos de um Processo Um processo em um sistema do tipo multitarefa não é executado todo o tempo e de forma contínua pela CPU. Durante o período de sua “existência” ele transita entre vários estados e esse transitar é gerenciado pelo sistema operacional. Para efeitos de simplicidade vamos considerar um conjunto de 3 estados básicos nos quais um determinado processo pode estar: EXECUTANDO (running), PRONTO (ready) e ESPERANDO (waiting) o estado ESPERANDO é também conhecido por ESPERA ou SUSPENSO. O conjunto desses 3 estados ilustra o que é conhecido como diagrama de estados ou máquina de estados de um processo por possibilitar a visualização da mudança de um estado para outro, mudança essa que pode ser ocasionada pelo sistema operacional ou às vezes pelo próprio processo que pode, por exemplo, se auto-suspender por um determinado tempo ou esperar que um outro processo termine ou comece. Execução Ativação/início Esperando Processo 45 Processo 89 finalização/término Pronto Processo 3 Processo 10 Processo 14 À cada um desses estados, representados nessa máquina de estados, está associada uma estrutura de dados parecida com um lista encadeada que cresce e diminui dinamicamente (simbolizado pela seta de 2 extemidades) e que contém as identificações de todos os processos alocados nesses estados. Como cada processo possui sua própria PCB é possível a restauração do contexto de 48 cada um desses processos a partir das informações que constam nas respectivas PBCs associadas aos processos. Na ilustração acima, vê-se que há 2 processos em estado de espera e 3 processos prontos para serem executados e somente 1 processo em execução. Mesmo se fosse o caso de um sistema multiprocessado ,i.e., com várias CPUs , a regra ontinua valendo, pois cada uma dessas CPUs estará executando somente 1 processo durante um determinado intervalo de tempo, intervalo esse cujo valor é fixo e constante. Esse intervalo de tempo também recebe o nome de quantum e os diferentes processos poderão receber diferentes valores de quantuns em função de sua prioridade pré-estabelecida quando da sua criação ou quando do seu escalonamento. Quanto maior o número de quantuns atribuídos a um processo, maior será o tempo que esse processo terá para ser executado pela CPU. Num sistema multiprogramável, um processo não deve alocar a CPU com exclusividade, de forma que possa existir um compartilhamento no uso do processador. Os processos passam por diferentes estados ao longo do processamento, em função de eventos gerados pelo sistema operacional, pelo hardware, ou pelo próprio programa. São estados possíveis de um processo: Criação/ativação: neste estado o processo está sendo alocado na memória, sendo criado no sistema. Todos os recursos necessários à execução do processo são reservados durante a passagem do processo por este estado, o que acontece uma única vez. Vários processos podem estar neste estado, ao mesmo tempo. Pronto: é o estado onde os processos, depois de criados ou quando retornam do tratamento de uma interrupção, permanecem aguardando a liberação da CPU para que possam iniciar ou continuar seu processamento. É como se fosse uma fila, gerenciada pelo sistema operacional, que se incumbe de organizar os processos de acordo com as informações contidas no contexto de software (identificação, quotas e privilégios). Vários processos podem estar neste estado, ao mesmo tempo. Execução: é onde o processo efetivamente utiliza a CPU. Ele permanece em execução na CPU até que seja interrompido ou termine sua execução. Neste estado, em um sistema monoprocessado, i.e., com somente uma única CPU, há somente um processo. Espera: neste estado estão todos os processos que sofreram algum tipo de interrupção de E/S, onde permanecem até que a intervenção seja resolvida. Vários processos podem estar neste estado, ao mesmo tempo. Saída/término: é o estado final do processo, quando este termina seu processamento. Vários processos podem estar neste estado, ao mesmo tempo, aguardando o seu desviculamento efetivo e por completo do sistema computacional. 49 6.4 Mudanças de Estado Um processo muda de estado diversas vezes durante sua permanência no sistema devido aos eventos ocorridos durante sua execução. As mudanças possíveis são: Criação Pronto: o processo foi criado, tem seus recursos alocados, e está apto a disputar o uso da CPU. Pronto Execução: o processo é o primeiro da fila de pronto e a CPU fica disponível. Neste momento o processo passa a ocupar a CPU, permanecendo em execução até que seja interrompido ou termine sua execução. Execução Pronto: o processo foi interrompido por fatia de tempo ou por prioridade. Ainda precisa de mais tempo na CPU para terminar sua execução, não tem nenhuma intervenção pendente, por isso volta à fila de pronto para disputar novamente o uso da CPU. Execução Espera: esta transição acontece quando o processo foi interrompido por E/S. Significa que deve permanecer no estado de espera até que a interrupção seja tratada pelo sistema. Neste estado o processo fica impedido de disputar o uso da CPU. Espera Pronto: Após o término do tratamento da interrupção, o processo volta à fila de pronto para disputar novamente o uso da CPU. Execução Saída: o processo terminou, e não mais disputará o uso da CPU. 6.5 Tipos de processos Além dos processos do usuário, a CPU também executa processos internos do sistema. São aqueles que oferecem os serviços do sistema operacional aos usuários, como criação/eliminação de processos, tratamento de interrupção e todos aqueles correspondentes às funções de um sistema operacional. Todos os processos internos ao sistema operacional são executados, sempre, com certa prioridade, concorrendo com todos os processos do usuário. Os processos em execução, do usuário, podem ser de dois tipos diferentes, de acordo com suas características de utilização da CPU e periféricos: 6.5.1 Processo CPU-Bound: é aquele processo que faz utilização intensa da CPU. Ele ganha uma fatia de tempo (quantum) e a utiliza por inteiro, sem desperdiçar nenhum tempo. É o caso de programas científicos, de aplicações numéricas diversas, de aplicações estatísticas, pesquisas matemáticas, e também na área de simulação. Esses processos normalmente fazem pouca ou nenhuma entrada de dados (input), e muito processamento. 6.5.2 Processo I/O-Bound: é aquele tipo de processo que utiliza muito mais os dispositivos de E/S do que CPU. Aplicações que envolvem banco de dados, onde se fazem consultas e atualizações constantes em arquivos em disco são bons exemplos deste tipo de processo. De acordo com essas características, podemos dizer que este tipo de processo permanece mais tempo em espera do que própriamente em execução, ocupando a CPU por períodos mínimos de tempo. 50 Com relação às formas de interação com o(s) usuário(s), os processos podem ser de dois tipos: os de plano frontal (foreground) e os de plano de fundo (backgroundl). Os processos de plano de fundo podem dar a impressão de que não estão sendo executados pela CPU, já que aparentam não estar se comunicando com o(s) usuário(s), entretanto, eles continuam a ser executados e a disputar a CPU e o seu precioso tempo. 6.5.3 Processo em Foreground: é aquele processo com está interagindo diretamente com o usuário, como por exemplo quando o usuário está atualizando os dados de uma planilha eletrônica, ou alterando algum texto através de um editor de texto, ‘navegando’ na Internet, compilando um programa etc. Múltiplas janelas, cada uma delas com um aplicativo sendo executado, podem estar abertas e não minimizadas, entretanto, somente uma delas está ativa. Esta janela ativa constitui um exemplo de processo em foreground. 6.5.4 Processo em Background: é aquele processo que foi ativado em algum instante pelo usuário e que está momentaneamente sendo executado em outro plano de execução que não o frontal, ou seja, que não está interagindo diretamente com o usuário. São exemplos de processos em background todos aqueles que foram ‘minimizados’ pelo usuário, como por exemplos, sessões de download que ainda estão ocorrendo, uma ou mais janelas de navegação pela Internet, abertas, acessadas e minimizadas ou não pelo usuário. O ato de minimizar uma determinada janela, com seu respectivo aplicativo sendo executado não caracteriza um processo em background. Múltiplas janelas, cada uma delas com um aplicativo sendo executado, podem estar abertas e não minimizadas, entretanto, somente uma delas está ativa (foreground) – todas as demais janelas constituem-se de exemplos de processos em background. 51 7.0 Gerenciamento da CPU A idéia central que tornou viável a implementação dos sistemas multiprogramáveis foi a possibilidade da CPU poder ser compartilhada entre diversos processos, ou em outra palavras, poder ser multiplexada no tempo entre esses diversos processos. Para isso, todo sistema multiprogramável possui um critério para determinar qual a ordem na escolha dos processos para execução entre os vários que concorrem pela utilização da CPU (processador). O(s) critério(s) utilizado(s) na seleção de qual processo será executado é uma das principais funções realizadas por um sistema operacional e é conhecido como escalonamento (scheduling). O processo interno do sistema operacional responsável pelo escalonamento dos processos é chamada de escalonador (scheduler) . Os principais objetivos do escalonamento são : a) manter a CPU “ocupada” a maior parte do tempo b) balancear a utilização do processador entre os diversos processos c) maximizar a eficiência (throughput) do sistema computacional como um todo d) oferecer tempos de resposta razoáveis para os usuários Esses objetivos devem ser atendidos de forma que o sistema procure tratar todos os processos de forma igualitária, evitando que um processo venha a monopolizar o tempo da CPU, ao mesmo tempo emque procura evitar que um outro processo fique indefinidamente esperando pela utilização da CPU (starvation). Para atender alguns desses objetivos conflitantes, os sistemas operacionais devem levar em consideração algumas das principais caracteristicas dos processos, ou seja, se esse processo é do tipo batch, interativo, CPU-bound ou I/O-bound, requisitos de memória desses processos etc. Sistemas de tempo real ou de tempo compartilhado tambem são aspectos fundamentais para a implementação de uma politica adequada de escalonamento. A mesma abordagem já adotada para conceituar processos, i.e., programas sendo executados pela CPU, será adotada aos conceitos de subprocessos e threads. Um algoritmo de escalonamento tem como principal função decidir qual, dentre todos os processos internos ou externos aos sistema operacional, e que estão na fila de “prontos” para execução, qual deles será executado pela UCP. Cada sistema operacional necessita de um algoritmo de escalonamento adequado a seu tipo de processamento. Um tópico fundamental, relacionado ao escalonamento, é o momento certo de tomar as decisões de escalonar. Claro que há uma variedade de situações nas quais o escalonamento é necessário. Primeiramente, quando se cria um novo processo, é necessário tomar uma decisão entre executar o processo pai ou o processo filho. Como ambos os processos estão no estado de “pronto”, essa é uma decisao normal de escalonamento e pode levar à escolha de um ou de outro - isto é, o escalonador pode escolher legitimamente executar o pai ou o filho. Em segundo lugar, uma decisão de escalonamento deve ser tomada ao término de um processo. Como o processo não pode executar mais (já que ele não existe mais), algum outro processo deve ser escolhido entre os processos “prontos”. Se nenhum processo estiver pronto, é executado um processo ocioso, gerado pelo sistema, normalmente denominado idle. Em terceiro lugar, quando um processo é suspenso para efetuar uma operação E/S, um outro processo precisa ser selecionado para ser executado, tirando vantagem da CPU “ociosa”. 52 Em quarto lugar, quando ocorre uma interrupção de E/S, pode-se tomar uma decisão de escalonamento. Se a interrupção vem de um dispositivo de E/S que acabou de fazer seu trabalho, o processo que estava bloqueado, esperando pela E/S, pode agora ficar pronto para execução. É o escalonador quem decide se executa o processo que acabou de ficar pronto, se continua executando o processo atual (que estava executando no momento da interrupção) ou se seleciona um terceiro processo para executar. Se um temporizador (system clock) fornece interrupções de hardware periódicamente, o algoritmo de escalonamento poderá ser ativado à cada interrupção e um uma decisão de escalonamento pode ser tomada a cada interrupção de relógio ou a cada fração desse tempo. as algoritmos de escalonamento podem ser divididos em duas categorias quanto ao modo como tratam essas interrupções. Um algoritmo de escalonamento não preemptivo escolhe um processo para executar e entao o deixa executando até que ele seja bloqueado (à espera de uma operação de E/S ou de um outro processo) ou até que ele voluntariarnente libere a CPU. Mesmo que ele execute por horas, nao será compulsoriamente suspenso. Na verdade, nenhuma decisao de escalonamento será tomada durante as interrupções do system clock. Depois que o tratamento da interrupção do system clock termina, o processo que estava executando antes da interrupção prossegue até acabar. Por outro lado, um algoritmo de escalonamento preemptivo escolhe um processo e o deixa em execulção por um intervalo de tempo máximo previamente fixado. Se ainda estiver executando ao final desse intervalo de tempo, o processo será suspenso e o escalonador escolherá outro processo para ser executado (se houver algum disponivel). O escalonamento preemptivo requer a existência de uma interrupção de relógio ao fim do intervalo de tempo para que o controle sobre a CPU seja devolvido ao escalonador. Se nao houver relógio disponível, o escalonamento não preemptivo será a única opção. 7.1 Algoritmos de Escalonamento Para ambientes diferentes são necessários diferentes algoritmos de escalonamento. Essa situação ocorre porque diferentes áreas de aplicação e, diferentes tipos de sistemas operacionais, tem objetivos diferentes. Em outras palavras, o que deve ser otimizado pelo escalonador não é o mesmo para todos os sistemas. e, por isso mesmo, são verificados 3 ambientes diferentes: 1. Lote (batch) 2. Interativo (usuários) 3. Tempo real (aplicações críticas) Nos sistemas em lote não há em seus terminais, usuários esperando por uma resposta rápida. Consequentemente, os algoritmos não preemptivos ou preemptivos com longo intervalo de tempo para cada processo são em geral aceitáveis, o que reduz as alternâncias entre processos, melhorando a performance geral do sistema. Em um ambiente com usuários interativos, a preempção torna-se essencial para evitar que um processo monopolize a CPU e com isso negue serviços aos demais processos. Mesmo que nenhum processo “deseje” ser executado para sempre, uma falha (bug) no programa pode levá-lo a impedir indefinidamente que todos os outros executem. A preempção é vital para coibir tal comportamento. Em sistemas de tempo real a preempção é, paradoxalmente, desnecessária em alguns casos pois os processos sabem que não podem executar por muito tempo e em geral se auto-suspendem rapidamente. A diferença em relação aos sistemas interativos é que os sistemas de tempo real 53 executam apenas programas que visam ao progresso da aplicação como um todo. Os sistemas interativos são de propósito geral e por isso mesmo podem executar processos arbitrários não cooperativos e até mesmo processos de finalidade duvidosa. 7.2 Critérios de Escalonamento 7.2.1 Utilização da CPU Na maioria dos sistemas computacionais é desejável que a CPU permaneça a maior parte do seu tempo ocupada em algum processo importante. Uma utilização na faixa de até 40% indica um sistema com uma carga de processamento baixa, ao passo que uma taxa de utilização acima de 80% indica um sistema bastante carregado, próximo da sua capacidade total. Picos de processamento são comuns em qualquer sistema computacional, entretanto, a contínua utilização dos recursos computacionais em uma faixa próxima dos 80% pode significar que um upgrade no hardware e/ou no software pode ser necessário em breve. 7.2.2 Eficiência (Throughput) A eficiência (throughput) representa o número de processos executados em um determinado intervalo de tempo. Quanto maior a eficiência, maior o número de processos executados em função do tempo. A maximização da eficiência é almejada na maioria dos sistemas. 7.2.3 Tempo de Turnaround Esse é o tempo que um processo leva desde sua admissão no sistema ate ao seu término, levando em consideração o tempo de espera para alocação de memoria, espera na fila de processos prontos para execução, processamento na CPU e operações de E/S. 7.2.4 Tempo de Resposta Em sistemas interativos, o tempo de resposta é o tempo decorrido do momento da submissão de um pedido ao sistema até a primeira resposta produzida. O tempo de resposta não é o tempo utilizado no processamento total de uma tarefa, e sim o tempo decorrido até que resposta seja apresentada. Este tempo, geralmente, é limitado pela velocidade do dispositivo de saída. De uma maneira geral, qualquer algoritmo de escalonamento busca otimizar a utilização da CPU e o throughput, enquanto tenta diminuir os tempos de turnaround e de resposta. Dependendo do tipo do sistema, um critério pode ser mais enfatizado do que outros, como, por exemplo, nos sistemas interativos, onde o tempo de resposta deve ser mais considerado.O algoritmo de escalonamento não é o único responsável pelo tempo de execução de um processo. Outros fatores, como o tempo de processamento e de espera em operações de E/S, devem ser considerados no tempo total da execução. O escalonamento somente afeta o tempo de espera de processos na fila de prontos. 7.3 Tipos de Escalonamento 7.3.1 Escalonamento First-In First Out (FIFO) Nesse tipo de escalonamento, o processo que chegar primeiro (first-in) será o primeiro a ser selecionado para execução (first-out). Seu algoritmo de implementação é bastante simples, sendo necessária apenas uma fila, onde os processos que passam para o estado de prontos entram no seu final e são escalonados quando chegarem ao início da fila. Nesse esquema, quando um processo ganha a CPU, ele a utilizará sem ser interrompido. O principal problema do escalonamento do tipo FIFO é a impossibilidade de se prever quando um processo terá sua execução iniciada, já que 54 isso varia em função do tempo de execução dos demais processos que se encontram na sua frente. Outro problema é a possibilidade de processos do tipo CPU-bound de menor importância prejudicarem os processos I/O-bound mais prioritários. Esse tipo de escalonamento é também conhecido como “o primeiro a chegar é o primeiro a ser servido” (first come, first served). Abaixo, um exemplo de escalonamento utilizando o método FIFO: a ordem de chegada dos processos (A, B, C) na fila de pronto foi obedecida, e, não tendo sido interrompidos por E/S, os processos executaram inteiramente até terminar, de acordo com seus tempos necessários para execução. 0 10 Processo A 10 u.t. 18 Processo B 8 u.t. 27 Processo C 9 u.t. 7.3.2 Escalonamento Shortest-Job-First (SJF) Esse algoritmo de escalonamento associa cada processo ao seu tempo de execução. Dessa forma, quando a CPU estiver livre, o processo em estado de pronto que precisar de menos tempo de CPU para terminar seu processamento será selecionado para execução (shortest-job-first). Esse tipo de escalonamento favorece os processos que executam programas menores, além de reduzir o tempo médio de espera em relação ao escalonamento do tipo FIFO. O problema em relação a esse algoritmo é determinar, exatamente, quanto tempo de UCP cada processo necessitará para terminar seu processamento. Esse tempo nem sempre é determinado de forma precisa. Em ambientes de produção, onde os programas executam frequentemente, é possível estimar o tempo de execução, mas em ambientes de desenvolvimento isso se torna bastante difícil. Tanto o SJF quanto o FIFO não são algoritmos de escalonamento aplicados aos sistemas de tempo compartilhado, onde um tempo de resposta razoável deve ser garantido ao usuário, que utilzia o sistema computacional de forma interativa. Como exemplo, vamos utilizar os mesmos processos executados no escalonamento FIFO acima, com seus respectivos tempos de execução em u.t. (unidades de tempo): processo A com 10 u.t., processo B com 8 u.t, e o processo C com 9 u.t. Como neste escalonamento o que importa é o tempo de execução, a nova ordem de escalonamento para utilização da CPU será B, C e A, como segue: 0 8 Processo B Processo C 17 27 Processo A 7.3.3 Escalonamento Shortest RemainingTime (SRT) Um outro tipo de escalonamento é o próximo de menor tempo restante (shortest remaining time), no qual o escalonador sempre seleciona o processo cujo tempo de execução restante seja o menor deles. O problema com esse tipo de escalonamento é que, de novo, o tempo de execução total deve ser conhecido e, além disso, se algum processo chegar que demande um tempo menor de 55 processamento do que o processo atual, então esse será suspenso deixando a CPU para o processo récem chegado. Esse esquema permite que os jobs curtos obtenham um bom desempenho. 7.3.4 Escalonamento Cooperativo No escalonamento cooperativo alguma política não-preemptiva deve ser adotada. A partir do momento que um processo está em execução, este voluntariamente libera a CPU, retornando para a fila de prontos. Este tipo de escalonamento permite a implementação de sistemas multiprogramáveis com uma melhor distribuição do uso do processador entre os processos. Sua principal característica está no fato de a liberação do processador ser uma tarefa realizada exclusivamente pelo processo em execução que, de uma maneira cooperativa, libera a CPU para um outro processo. No escalonamento cooperativo, não existe nenhuma intervenção do sistema operacional na execução do processo, o que pode ocasionar sérios problemas na medida em que um programa em loop poderá não liberar a CPU, monopolizando-a para si. Os sistemas da Microsoft, o Windows 3.1 e o Windows 3.11 foram implementados utilizando o conceito de multitarefa cooperativa. Nestes sistemas, as aplicações verificam uma fila de mensagens periodicamente, para determinar se existem outras aplicações que desejam a CPU. Caso um processo não faça essa verificação, os outros processos não terão chance de serem executados até o término de execução desse processo. 7.3.5 Escalonamento Circular (Round Robin) O escalonamento circular (round robin) segue um algoritmo implementado para sistemas de tempo compartilhado, similar ao do FIFO, porém, quando um processo ganha a CPU, há um tempo máximo contínuo, denominado time-slice ou quantum, para sua utilização. Quando esse tempo acaba, sem que antes o processo tenha liberado a CPU, este volta ao estado de “pronto”, dando a vez para outro processo. Dá-se a esse mecanismo o nome de preempção por tempo e a fila de processos no estado de “pronto” é tratada como uma fila circular. Dessa forma, o escalonamento é realizado e a CPU é alocada para cada processo presente na fila de “pronto”, atribuindo a cada um deles um intervalo de tempo determinado pelo valor do quantum, valor esse que geralmente assume valores na faixa entre 100 e 300 ms. Através do escalonamento circular, nenhum processo será capaz de monopolizar a CPU. O tempo máximo alocado continuamente para um determinado processo é igual ao quantum definido pelo sistema. No caso de sistemas de tempo compartilhado, onde vários usuários utilizam o sistema computacional de forma concorrente, esse algoritmo é bastante apropriado. A figura abaixo mostra o escalonamento circular com 3 processos, onde a fatia de tempo é igual a 2 u.t. No exemplo não estão sendo levados em consideração tempos de troca de contexto entre os processos, nem o tempo perdido em operações de E/S. Os processos A, B e C, gastam 10 u.t, 6 u.t e 3 u.t., respectivamente. A B C 2 4 6 8 10 11 17 u.t. 56 7.3.6 Escalonamento por Prioridades O escalonamento circular consegue uma melhor distribuição do tempo da CPU, relativamente aos escalonamentos nao-preemptivos, porém ainda assim não é capaz de implementar um compartilhamento igualitário entre os diferentes tipos de processos presentes em um sistema computacional. Isso se deve pelo fato de o escalonamento circular tratar todos os processos de uma maneira igual, o que nem sempre é desejável no mundo real. Para solucionar esse problema, os processos do tipo I/O-bound devem levar alguma vantagem no escalonamento, compensando o tempo gasto no estado de espera pelo término do I/O. Como alguns processos devem ser tratados diferentemente dos outros, torna-se necessária a associação de uma prioridade de execução a cada um deles. Dessa forma, processos de maior prioridade sao escalonados preferencialmente e , toda vez que um processo for para a fila de “pronto” com prioridade superior ao do processo em execução, o sistema deverá interromper o processo corrente, colocando-o no estado de “pronto” e selecionando o de maior prioridade para ser executado. Esse mecanismo é definido como preempção por prioridade. A preempção por prioridade é implementada mediante um temporizador (system clock), que interrompe o processador em determinados intervalos de tempo, permitindo que o escalonador reavalie as prioridades e, possivelmente, escalone outro processo. Considerando-se 2 processos distintos, um processo A do tipo CPU-bound e um processo B do tipo I/O bound nota-se que para distribuir o tempo da CPU de forma igual, deveremos associar ao processo B uma prioridade superior a do processo A, com o objetivo de compensar seu tipo de processamento. Todos os sistemas de tempo compartilhado implementam algum esquema de prioridade, de forma a atribuir maior importância a um processo no momento do escalonamento. A prioridade é uma característica do contexto de software de um processo, podendo ser estática ou dinâmica. A prioridade é dita ser estática quando não é modificada durante toda a existência do processo, o que pode gerar tempos de resposta elevados.Na prioridade dinâmica, a prioridade do processo pode ser ajustada de acordo com o tipo de processamento realizado pelo processo e/ou a carga do sistema. Todo o processo, ao sair do estado de espera, poderá receber um acréscimo à sua prioridade e, assim, os processos do tipo I/O-bound terão mais chance de serem escalonados, compensando o tempo em que passam no estado de “espera”. De uma forma geral, foi observado que apesar da maior complexidade, esse algoritmo gera um tempo de resposta mais apropriado. A figura abaixo mostra a execução dos processos A, B e C, com tempos de execução de 10, 4 e 3 u.t. respectivamente, e valores de prioridades de 2, 1 e 3, também respectivamente. Na maioria dos sistemas, valores menores correspondem à MAIOR prioridade. Assim, a ordem de execução será invertida para B, A e C. A B C 4 14 17 u.t. 57 7.3.7 Escalonamento por Múltiplas Filas Como os diversos processos de um sistema computacional podem possuir características de processamento diferentes, é muito difícil que um único mecanismo de escalonamento atenda adequadamente a todos os tipos de processo. Uma solução de contorno seria a classificação dos diferentes processos em função do tipo de processamento realizado e aplicar a cada grupo mecanismos de escalonamentos diferentes. Com base nisso, o escalonamento por múltiplas filas (multi-level queues) implementa diversas filas de processos no estado de "pronto”, onde cada processo é associado exclusivamente à uma delas. Cada fila possui seu próprio algoritmo de escalonamento em função das características do processo. Nesse esquema, os processos devem ser classificados, previamente, em função do tipo de processamento, para poderem ser encaminhados á uma determinada fila. Cada fila possuí uma prioridade è ela associada, que estabelece quais filas são prioritárias em relação às outras. O sistema só poderá escalonar processos de uma fila se todas as outras filas de prioridade maior estiverem vazias. Considere que os processos, em função de suas características, sejam divididos em 3 grupos: sistema, interativo e batch. Os processos pertencentes ao sistema deverão ser colocados em uma fila de prioridade superior ao dos outros processos, implementando um escalonamento baseado em prioridades. Os processos de usuários interativos devem estar em uma fila de prioridade média, implementando por exemplo o escalonamento round robin (circular). Para os processos em lote (batch) o mesmo escalonamento circular poderia ser utilizado, só que com uma prioridade mais baixa que aquela atribuída aos usuários. 7.3.8 Escalonamento por Múltiplas Filas com Realimentação Na modalidade do escalonamento por múltiplas filas, os processos eram préviamente classificados para serem associados à uma determinada fila, com uma determinada prioridade. Se o processo alterar o seu comportamento no decorrer do tempo, aquela abordagem mostra-se falha visto que o processo não poderá ser redirecionado para uma outra fila mais adequada. Um mecanismo ideal seria aquele em que o sistema conheça como os diversos processos e o próprio sistema se comportam ao longo do tempo, ajustando dinamicamente seus tipos de escalonamento. O escalonamento por múltiplas filas com realimentação (multi-level feedback queues), similar ao escalonamento por múltiplas filas, implementa diversas filas, onde cada qual tem associada uma prioridade de execução, porém, nesta abordagem, os processos não permanecem em uma mesma fila até o término do processamento. Neste escalonamento, o sistema tenta identificar de forma dinãmica o comportamento de cada processo, ajustando assim suas prioridades de execução e os mecanismos de escalonamento. Esse esquema permite que os processos sejam redirecionados entre as filas do sistema, fazendo com que o sistema operacional implemente um mecanismo de ajuste dinâmico, denominado mecanismo adaptativo, que tem como objetivo ajustar os processos em função do comportamento do sistema. Os processos não são previamente associados às filas de pronto, e sim direcionados pelo sistema entre as diversas filas com base no seu comportamento. Um processo, ao ser criado, entra no final da fila de mais alta prioridade. Cada fila implementa o mecanismo de FIFO para o escalonamento. Quando um processo sendo executado libera a CPU, seja por preempção por prioridade ou por solicitação à um recurso do sistema, ele é reescalonado dentro da mesma fila. Quando este processo esgotar seu quantum de tempo, ele será redirecionado para uma fila de menor prioridade (preempção por tempo). 58 O escalonamento de um processo em uma fila só acontece quando todas as outras filas de prioridades mais altas estiverem vazias. A fila de mais baixa prioridade implementa o mecanisrno do escalonamento circular. O quantum em cada fila varia em função da sua prioridade. Quanto maior a prioridade da fila, menor será o seu quantum de tempo. O quantum dos processos não é então estático uma vez que poderá variar em função da fila de “pronto” na qual ele se encontra. Essa política de escalonamento atende as necessidades dos diversos tipos de processos. No caso de processos do tipo I/O-bound, ela oferece um born tempo de resposta, já que esses processos tem prioridades altas por permanecerem a maior parte do tempo nas filas de mais alta ordem. No caso de processos CPU-bound, a tendência é de que, ao entrar na fila de mais alta prioridade, o processo ganhe a CPU, gaste seu quantum de tempo e seja direcionado para uma fila de menor prioridade. Dessa forma, quanto mais tempo um processo a CPU, mais ele cairá para filas de menor prioridade. Esse algoritmo apresenta um caráter de generalidade que pode ser aplicado à qualquer tipo de sistema, entretanto tal generalidade tem um preço alto a ser pago – o overhead no processamento dos vários processos. 7.3.9 Escalonamento por Fração Justa (Fair Share) Considerando o caso em que 2 usuários, 1 e 2, onde o usuário 1 inicia 9 processos e o usuário 2 inicia um processo, com altemancia circular ou com prioridades iguais, o usuário 1 obterá 90 por cento da CPU e o usuário 2 terá somente 10 por cento dela. Para evitar isso, alguns sistemas consideram a propriedade do processo antes de escaloná-lo. Nesse modelo, a cada usuário é alocada uma fração do tempo da CPU e o escalonador escolhe os processos de modo que essa fração seja garantida. Assim, se dois usuários tiverem 50 por cento da CPU alocada para cada um deles, cada um terá os 50 por cento, nao importando quantos processos eles tenham gerado. Como exemplo, imagine um sistema com 2 usuarios, cada qual com 50 por cento do tempo da CPU prometida a ele. O usuário 1 tem 4 processos, A, B, C e D, e o usuário 2 tem somente um processo, E. Se for usado o escalonamento circular, uma possível sequência de escalonamento que cumpra todas as exigências poderá ser a sequência dada abaixo: A E B E C E D E A E B E C E D E... Por outro lado, se ao usuário 1 se destinar duas vezes mais tempo de CPU do que para o usuário 2, obterernos: A B E C D E A B E C D E... É claro que existem inúmeras outras possibilidades, porém nem todas elas justas. 7.4 Escalonamento em Sistemas de Tempo Real Sistemas de tempo real são frequentemente utilizados em aplicações de controle de processos. Sistemas que controlam indústrias, de controle de tráfego aéreo entre outros são exemplos deste tipo de sistema.Nos sistemas operacionais de tempo real, o fator tempo é crítico. Diferentemente dos sistemas de tempo compartilhado, onde um pequeno tempo de resposta é desejado, mas não obrigat6rio, todo processamento em tempo real deve ser realizado dentro de limites rígidos de tempo ou, caso contrário, todo o sistema poderá ficar comprometido. No escalonamento para este tipo de sistema não existe o conceito de quantum ou time-slice. 59 O escalonamento é realizado únicamente com base no esquema de prioridades. Para cada processo é atribuída uma prioridade associada à sua importância dentro do sistema. Esta prioridade deve ser estática, não devendo ser alterada no decorrer do processamento. O escalonamento de tempo real deve ser empregue na solução de aplicações onde existam graus de exigêcia na execução de suas tarefas. Quanto maior a importancia de uma tarefa, maior será sua prioridade de execução em relação às demais. Dessa forma, é possível implementar níveis de prioridade entre as tarefas da aplicação, conforme a necessidade na solução de cada problema. Um sistema de tempo real é aquele no qual o tempo tem uma função essencial. Em geral, um ou mais dispositivos físicos extemos ao computador geram estímulos, aos quais a CPU deve reagir apropriadamente a todos eles dentro de um dado intervalo de tempo. Por exemplo, a CPU em um tocador de CD obtém os bits que chegam do drive, necessitando convertê-los em sinais sonoros audíveis (também denominado música) em um intervalo crítico de tempo. Se o cálculo que ele fizer for muito demorado, a música irá soar diferente. Outros exemplos ao sistemas de tempo real incluem a monitoração de pacientes em UTIs de hospitais, o piloto automático de aeronaves e robôs de controle em fábricas automatizadas. Em todos esses casos, ter a resposta certa mas tardia é tão ruim quanto não ter nada. Sistemas de tempo real são em geral categorizados como tempo real crítico, i.e., há prazos absolutos que devem ser cumpridos ou, então, como tempo real nao crítico, no qual o descumprimento ocasional de um prazo, apesar de indesejável, pode ser tolerável. Em ambos os casos, o comportamento de tempo real é implementado dividindo-se o programa em vários processos cujos comportamentos são préviamente conhecidos. De modo geral, esses processos tem vida curta e podem executar em bem menos de um segundo. Quando um evento externo é detectado, o trabalho do escalonador é escalonar os processos de tal forma que todos os prazos sejam cumpridos. Os eventos aos quais um sistema de tempo real pode precisar responder podem ser divididos em periódicos (ocorrem em intervalos regulares) ou aperiódicos (acontecem de modo imprevisível). Um sistema pode ter de responder a múltiplos fluxos de eventos periódicos. Dependendo de quanto tempo cada evento necessite para ser processado, talvez nem seja possivel tratar de todos. Por exemplo, se houver m eventos periódicos e o evento i ocorrer com período Pi e necessitar de Ci segundos de CPU para tratar cada evento, entao a carga total a ser tratada será dada pela soma de todos os tempos Ci dividida pelo seu respectivo período Pi deverá ser menor igual a 1. Um sistema de tempo real que satisfaça a esse critério é chamado de escalonável. Considerando-se um sistema de tempo real não crítico com 3 eventos periódicos, com períodos iguais a 100, 200 e 500 ms, respectivamente. Se esses eventos requererem 50, 30 e 100 ms de tempo de CPU por evento, nessa ordem, o sistema é escalonável porque 0,5 + 0,15 + 0,2 < 1. Se um quarto evento, com periodo de 1 s, for adicionado, o sistema permanecerá escalonável desde que esse evento nao precise de mais de 150 ms do tempo da CPU por evento. Implícito nesse cálculo está a hipótese de que o custo extra do chaveamento de contexto é tão pequeno que pode ser desprezado. Os algoritmos de escalonamento de tempo real podem ser estáticos ou dinâmicos. Os primeiros tomam suas decisões de escalonamento antes de o sistema começar a executar. Os últimos o fazem em tempo de execução. O escalonamento estático só funciona quando há informações prévias e exatas sobre o trabalho necessário a ser feito e os prazos que devem ser cumpridos. Os algoritmos de escalonamento dinâmico nao apresentam essas restrições. 60 7.5 Escalonamento com Múltiplos Processadores O mecanismo de escalonamento para sistemas com múltiplas CPUs é bem mais complexo que com uma única CPU. A abordagem é ainda mais diferenciada quando se trata de sistemas fracamente acoplados ou fortemente acoplados. Em sistemas fracamente acoplados, cada CPU faz seu próprio escalonamento localmente. Todo sistema possui, além da CPU, sua memória principal, seu sistema operacional com seu algoritmo de escalonamento e sua propria fila de processos prontos para execução. Nos sistemas fortemente acoplados é possível implementar uma única fila de “pronto” para todas as CPUs. Todos os processos estão presentes nesta única fila e são escalonados na primeira CPU disponível. Nesta solução é importante que, para a execução do algoritmo de escalonamento, seja implementada a exclusão mútua para seu código. No caso de mais de uma CPU se tomar disponível em um mesmo instante, não poderá haver a possibilidade de um mesmo processo vir a ser ser escalonado por 2 CPUs diferentes. A exclusão mútua do escalonador pode ser obtida através de mecanismos como semáforos e monitores, implementados no sistema operacional. Vale notar que, como a memoria é única para todos os processadores, ela conterá todos os processos desse sistema computacional, não importando qual processador executará o processo. 61 8. Gerência de Memória / Memória Virtual 8.1 Introdução Historicamente, a memória principal sempre foi vista como um recurso escasso e caro. Uma das maiores preocupações dos projetistas foi desenvolver sistemas operacionais que não ocupassem muito espaço de memória e, ao mesmo tempo, otimizassem a utilização dos recursos computacionais. Mesmo atualmente, com a redução do custo e o aumento considerável da capacidade da memória principal, seu gerenciamento é dos fatores mais importantes no projeto e implementação dos sistemas operacionais. Enquanto nos sistemas monoprogramáveis a gerência de memória não é muito complexa, nos sistemas multiprogramáveis essa gerência se torna crítica, devido à necessidade de se maximizar o número de usuários e aplicações utilizando eficientemente o espaço da memória principal. 8.2 Funções Geralmente, os programas são armazenados em memórias secundárias, de uso permanente e não voláteis, como discos ou fitas. Como o processador somente executa o que está na memória principal, o sistema operacional deve sempre transferir programas da memória secundária para a principal antes de serem executados.Como o tempo de acesso às memórias secundárias é muito superior ao tempo de acesso à memória principal, o sistema operacional deve buscar reduzir o número de operações de E/S (acessos à memória secundária) a fim de não comprometer o desempenho do sistema. A gerência de memória deve tentar manter na memória principal o maior número de processos residentes, permitindo maximizar o compartilhamento do processador e demais recursos computacionais. Mesmo não havendo espaço livre, o sistema deve permitir que novos processos sejam aceitos e executados. Outra preocupação na gerência de memória é permitir a execução de programas maiores do que a memória física disponível. Em um ambiente de multiprogramação o sistema operacional deve proteger as áreas de memória ocupadas por cada processo, além da área onde reside o próprio sistema. Caso um programa tente realizar algum acesso indevido à memória, o sistema deve, de alguma forma, impedir o acesso. 8.3 Alocação Contígua Simples Este tipo de alocação foi implementado nos primeiros sistemas operacionais, embora ainda nos dias de hoje esteja presente em alguns sistemas monoprogramáveis. Nesse modelo, a memória principal é dividida em duas partes, uma para o sistema operacional e a outra para o programa do usuário. Dessa forma, o programador deve desenvolver suas aplicações preocupado apenas em não ultrapassar o espaço de memória disponível. Neste esquema o usuário tem total controle sobre toda a memória, exceto naquela área onde reside o sistema operacional, cujo endereçamento é protegido por um registrador, impedindo acesso indevido pelo usuário. 62 Sistema Operacional registrador Área livre para programas do usuário Proteção na alocação contígua simples Apesar de simples implementação e código reduzido, a alocação contígua simples não permite a utilização eficiente dos recursos do sistema, pois apenas um usuário pode dispor destes recursos. Há inclusive um desperdício de espaço de memória, caso o programa não venha a ocupar toda a área reservada para ele. Sistema Operacional Programa usuário do Área livre Sub-utilização da memória principal 8.4 Segmentação de Programas Na alocação contígua simples todos os programas estão limitados ao tamanho da memória principal disponível para o usuário. Uma solução encontrada para o problema é dividir o programa em módulos, de modo que seja possível a execução independente de cada módulo, utilizando a mesma área de memória. A esta técnica dá-se o nome de segmentação ou overlay. Consideremos um programa que tenha três módulos: um principal, um de cadastramento e outro de impressão, sendo os módulos de cadastramento e impressão independentes. A independência significa que quando um módulo estiver na memória para execução, o outro não necessariamente precisa estar presente.O módulo principal é comum aos outros dois, logo, precisa estar na memória durante todo o tempo da execução do programa. 63 Na figura a seguir, a memória é insuficiente para armazenar todo o programa, que totaliza 9 KB. A técnica de overlay utiliza uma área de memória comum para armazenar o módulo principal do programa e uma outra área na mesma memória, chamada área de overlay, que será compartilhada entre os módulos de cadastramento e impressão. Assim, sempre que um dos módulos for referenciado no módulo principal, o sistema o carregará da memória secundária para a área de overlay, sobrepondo o módulo antigo na memória. Memória Principal 2 KB 3 KB 4 KB Sistema Operacional Cadastramento Módulo Principal 4 KB Área de Overlay Impressão 2 KB 1 KB Área livre 2 KB Técnica de Overlay A área de memória deve ser suficientemente grande para comportar o programa principal e o maior dos segmentos. Caso ainda não seja possível executar o programa, deve-se procurar dividir o programa em segmentos ainda menores, cabendo ao programador, efetuar essa divisão de forma lógica-funcional, através de comandos específicos da linguagem de programação utilizada, assim como a utilização das system calls apropriadas. A grande vantagem da utilização desta técnica, apesar de trabalhosa, consiste em se poder executar programas maiores do que a memória principal (RAM) disponível, evitando-se a utilização da memória secundária (discos etc;). 8.5 Alocação Particionada Estática Os sistemas operacionais evoluíram no sentido de proporcionar melhor aproveitamento dos recursos disponíveis. Nos sistemas monoprogramáveis o processador permanece grande parte do tempo ocioso e a memória principal é sub-utilizada. Os sistemas multiprogramáveis já são muito mais eficientes no uso do processador, necessitando que vários processos estejam na memória principal ao mesmo tempo e que novas formas de gerência de memória sejam implementadas. Nos primeiros sistemas multiprogramáveis a memória era dividida em blocos de tamanho fixo, chamados partições.O tamanho dessas partições, estabelecido em tempo de inicialização do sistema, era definido em função do tamanho dos programas que executariam no ambiente.Sempre que fosse necessária a alteração do tamanho de uma partição, o sistema deveria ser inicializado novamente com uma nova configuração. 64 Sistema Sistema Operacional Operacional Partição 1 2 KB Partição 2 5 KB Partição 3 8 KB Inicialmente, os programas só podiam ser carregados e executados em apenas uma partição específica, mesmo que as outras estivessem disponíveis. Esta limitação se devia aos compiladores e linkeditores, que geravam apenas código absoluto. No código absoluto, todas as referências a endereços no programa são posições físicas na memória, ou seja, o programa só poderia ser carregado a partir do endereço de memória especificado no seu próprio código. A esse tipo de alocação de memória chamou-se alocação particionada estática absoluta. Com a evolução dos compiladores, linkeditores, montadores e loaders, o código gerado deixou de ser absoluto e passou a ser relocável . No código relocável, todas as referências a endereços no programa são relativas ao início do código e não a endereços fixos na memória. Desta forma, os programas puderam ser alocados em qualquer partição livre, independente do endereço inicial e da partição para a qual o código foi criado. A esse tipo de alocação deu-se o nome de alocação particionada estática relocável. Tanto nos sistemas de alocação absoluta como nos de alocação relocável, os programas, normalmente, não ocupam totalmente as partições onde são alocados, deixando algum espaço livre dentro das partições. Este tipo de problema, decorrente do esquema de alocação fixa de partições, é chamado fragmentação interna.A figura abaixo ilustra o particionamento estático de uma memória e sua fragmentação interna. Memória Principal Sistema Operacional Programa C 1 KB Programa A 3 KB Fragmentação interna Programa E 5 KB Alocação particionada estática com fragmentação interna 65 8.6 Alocação Particionada Dinâmica A alocação particionada estática deixou clara a necessidade de uma nova forma de gerência de memória principal, onde o problema da fragmentação interna fosse reduzido e, conseqüentemente, o grau de compartilhamento da memória aumentado. Na alocação particionada dinâmica, foi eliminado o conceito de partições de tamanho fixo. Nesse esquema, cada programa, ao ser carregado, utilizaria o espaço necessário à sua execução, tornando esse espaço a sua partição. Assim, como os programas utilizam apenas o espaço de que necessitam, no esquema de alocação particionada dinâmica o problema da fragmentação interna deixa de existir. Porém, com o término de alguns programas e o início de outros, passam a existir na memória blocos cada vez menores na memória, não permitindo o ingresso de novos programas. A este tipo de problema dá-se o nome de fragmentação externa. Para resolver o problema da fragmentação externa, os fabricantes tentaram duas soluções: a) reunião de todos os blocos livres adjacentes, formando uma grande área livre, que se transforma em uma nova partição; b) realocação de todas as partições ainda ocupadas para a parte inicial da memória, eliminando os blocos livres entre elas, formando uma grande área livre no final da memória, que podia ser distribuída entre os processos ainda por executar. A este tipo de compactação de espaços livres foi dado o nome de alocação particionada dinâmica com realocação. Estas soluções ajudaram a diminuir os problemas da fragmentação (tanto interna como externa), mas, devido á complexidade dos algoritmos, nem todos os sistemas operacionais as utilizaram. 8.7 Estratégias de Alocação de Partição Os sistemas operacionais implementam basicamente três estratégias para determinar em qual área livre um programa será alocado para execução. Essas estratégias tentam evitar ou diminuir o problema da fragmentação. A melhor estratégia a ser adotada por um sistema depende de uma série de fatores, sendo o mais importante o tamanho dos programas executados no ambiente. Independentemente do algoritmo utilizado, o sistema possui uma lista das áreas livres, com endereço e tamanho de cada área. São estratégias de alocação: Best-fit: é escolhida a melhor partição, ou seja, aquela que deixa o menor espaço sem utilização. Uma grande desvantagem desta estratégia é que, como são alocados primeiramente as partições menores, deixando pequenos blocos, a fragmentação aparece mais rapidamente. Worst-fit: aloca o programa na pior partição, ou seja, aquela que deixa o maior espaço livre. Esta técnica, apesar de aproveitar primeiro as partições maiores, acaba deixando espaços livres grandes o suficiente para que outros programas utilizem esses espaços, permitindo que um número maior de processos se utilizem da memória, diminuindo ou retardando a fragmentação. First-fit: esta estratégia aloca o programa na primeira partição que o couber, independente do espaço livre que vai deixar. Das três estratégias, esta é a mais rápida, consumindo menos recursos do sistema. 66 8.8 Swapping É uma técnica aplicada à gerência de memória que visa dar maior taxa de utilização à memória principal, melhorando seu compartilhamento. Visa também resolver o problema da falta de memória principal num sistema. Toda vez que um programa precisa ser alocado para execução e não há espaço na memória principal, o sistema operacional escolhe entre os processos alocados que não tem previsão de utilizar a CPU nos próximos instantes (quase sempre entre aqueles que estão em interrupção de E/S ou no final da fila de pronto), e “descarrega” este processo da memória para uma área especial em disco, chamada arquivo de swap, onde o processo fica armazenado temporariamente. Durante o tempo em que o processo fica em swap, o outro que necessitava de memória entra em execução ocupando o espaço deixado pelo que saiu. Pouco antes de chegar a vez do processo armazenado em swap utilizar a CPU, o sistema escolhe um outro processo para descarregar para swap e devolve o anterior da área de swap para a memória principal, para que este possa ser executado novamente. E vai trabalhando assim até que os processos vão terminando. O problema dessa técnica é que pode provocar um número excessivo de acesso à memória secundária (disco), levando o sistema a uma queda de desempenho. 67 8.9 Memória Virtual Anteriormente foram apresentadas diversas técnicas de gerenciamento de memória que evoluíram no sentido de maximizar o número de processos residentes na memória principal e reduzir o problema da fragmentação, porém os esquemas vistos se mostraram muitas vezes ineficientes. Além disso, o tamanho dos programas e de suas estruturas de dados estava limitado ao tamanho da memória disponível. Como vimos, a utilização da técnica de overlay para contornar este problema é de difícil implementação na prática e nem sempre uma solução garantida e eficiente. Memória virtual é uma técnica sofisticada e poderosa de gerência de memória onde as memórias principal e secundária são combinadas, dando ao usuário a impressão de que existe muito mais memória do que a capacidade real de memória principal. O conceito de memória virtual baseia-se em não vincular o endereçamento feito pelo programa aos endereços físicos da memória principal. Desta forma, o programa e suas estruturas de dados deixam de estar limitados ao tamanho da memória física disponível, pois podem possuir endereços vinculados à memória secundária, que funciona como uma extensão da memória principal. Outra vantagem desta técnica é permitir um número maior de processos compartilhando a memória principal, já que apenas partes de cada processo estarão residentes. Isto leva a uma utilização mais eficiente do processador, além de minimizar (ou quase eliminar) o problema da fragmentação. A seguir, os conceitos que envolvem a gerência de memória virtual, incluindo a paginação: Espaço de endereçamento virtual: é o conjunto de endereços virtuais que um processo pode endereçar. Espaço de endereçamento real: analogamente, é o conjunto de endereços reais que um processo pode endereçar. Mapeamento: como o espaço de endereçamento virtual não tem nenhuma relação com o espaço de endereçamento real, um programa pode fazer referência a um endereço virtual que esteja fora dos limites da memória principal (real), ou seja, os programas e suas estruturas de dados não estão mais limitados ao tamanho da memória física disponível. Quando um programa é executado, apenas uma parte do seu código fica residente na memória principal, permanecendo o restante na memória virtual até o momento de ser referenciado. Este esquema de endereçamento virtual é ignorado pelo programador no desenvolvimento das aplicações. Cabe ao compilador e ao linker gerar os códigos executáveis em função do endereçamento virtual, e o sistema operacional se incumbe de administrar os detalhes durante a sua execução. O processador apenas executa instruções e referencia dados residentes no espaço de endereçamento real. Portanto, deve existir um mecanismo que transforme os endereços virtuais em endereços reais. Este mecanismo é o que chamamos de mapeamento, e consiste em permitir a tradução do endereço virtual em endereço real. Como conseqüência, um programa não mais precisa estar necessariamente em endereços contíguos na memória real para ser executado. 68 Tabela de endereçamento de páginas: estrutura mantida pelo sistema para armazenar, entre outras informações, o mapeamento. É única e exclusiva para cada processo, relacionando os endereços virtuais do processo ás suas posições na memória real. Memória virtual por paginação: é a técnica de gerência de memória onde o espaço de endereçamento virtual e o espaço de endereçamento real são divididos em blocos do mesmo tamanho chamados páginas. As páginas do espaço virtual são chamadas páginas virtuais, enquanto as páginas do espaço real são chamadas páginas reais ou frames. Page fault: é a falha de página. Sempre que o processo referencia um endereço virtual, o sistema verifica se a página correspondente já está carregada na memória real. Se não estiver, acontece o page fault. Neste caso, o sistema deve transferir a página virtual para um endereço na memória real. Esta transferência é chamada de paginação. O número de page faults gerados por um processo em um determinado intervalo de tempo é chamado de taxa de paginação do processo. Se esta taxa atingir valores elevados, pode haver um comprometimento do desempenho do sistema. Um page fault provoca uma interrupção no processo, pois há a necessidade de acessar operações de E/S. Assim, sempre que acontece a paginação, uma interrupção de E/S fará com que o processo em execução seja interrompido e colocado em estado de espera até que sua intervenção de E/S seja realizada, quando então o processo voltará à fila de pronto e entrará em execução de acordo com o escalonamento normal. Enquanto o sistema trata a interrupção deste processo, um outro ocupará a CPU. Working-set: é o conjunto de páginas de um processo, em memória real, em um determinado instante. Este conceito surgiu com o objetivo de reduzir o problema do thrashing e está relacionado ao princípio da localidade. Existem dois tipos de localidade que são observados durante a execução da maioria dos programas. A localidade espacial é a tendência de que, após uma referência a um endereço de memória, sejam realizadas novas referências a endereços próximos ou adjacentes. A localidade espacial é a tendência de que, após a referência a uma posição de memória, esta mesma posição seja referenciada novamente num curto intervalo de tempo. A partir desse princípio de localidade, o processador tenderá a concentrar suas referências a um conjunto de páginas do processo durante um determinado período de tempo. Imagine um loop principal de um programa que ocupe três páginas. A tendência é que estas três páginas tenham um alto índice de referências durante a execução do programa. Thrashing: é o efeito causado pelo excesso de page faults durante a execução de um processo. Pode acontecer a nível de programa ou de sistema. No âmbito do programa, pode ser provocado por um programa mal escrito, com desvios incondicionais espalhados por seu código (desobedecendo portanto aos princípios da localidade), ou por um limite de working-set muito pequeno (que não comporte o loop principal do programa, por exemplo). A solução para estes casos é reescrever o programa ou aumentar o limite do working-set. No caso de thrashing de sistema, significa que há mais páginas sendo requeridas na memória real do que ela pode realmente suportar. A solução é aumentar o tamanho da memória física. Tamanho da página: deve estar entre 512 bytes e 128KB, aproximadamente. Páginas menores promovem maior compartilhamento da memória, permitindo que mais programas possam ser executados. Páginas maiores diminuem o grau de compartilhamento da memória, com menos programas disputando o processador. Assim conclui-se que quanto menor o tamanho da página, MAIOR é o grau de compartilhamento da memória e da CPU. Políticas de busca de páginas: definem como as páginas serão carregadas da memória virtual para a memória real. A política por demanda estabelece que uma página somente será carregada quando for referenciada. Este mecanismo é conveniente, pois leva para a memória real somente 69 as páginas realmente necessárias à execução do programa, ficando as outras na memória virtual. A outra política, chamada paginação antecipada, funciona carregando antecipadamente várias páginas da memória virtual para a principal, na tentativa de economizar tempo de E/S. Nem sempre o sistema acerta na antecipação, mas o índice de acertos é quase sempre maior que o de erros. Políticas de alocação de páginas: determinam quantos frames cada processo pode manter na memória real. A política de alocação fixa determina um limite de working-set igual para todos os processos, e pode ser vista como uma política injusta, na medida em que processos maiores normalmente necessitam de um working-set maior. A outra política é a variável, que define um limite de working-set diferente e variável para cada processo, em função de seu tamanho, taxa de paginação ou até mesmo da taxa de ocupação da memória principal. Políticas de substituição de páginas: definem onde serão trocadas as páginas, quando se fizer necessária uma substituição. Na política local, somente as páginas do processo que gerou o page fault são candidatas a serem substituídas. Já na política global, todas as páginas alocadas na memória principal são candidatas à substituição, independente do processo que gerou o page fault. Como uma página de qualquer processo pode ser escolhida, pode ser que este processo sofra um aumento temporário da taxa de paginação em função da diminuição das suas páginas alocadas em memória. 8.10 Algoritmos de Substituição de Páginas O maior problema na gerência de memória virtual por paginação não é decidir quais páginas carregar para a memória real, mas sim quais páginas liberar. Quando há a necessidade de carregar uma página, o sistema deve selecionar entre as diversas páginas alocadas na memória qual delas deverá ser liberada pelo processo. Os algoritmos de substituição de páginas têm o objetivo de selecionar os frames que tenham as menores chances de serem referenciados num futuro próximo. Caso contrário, o frame poderia retornar diversas vezes para a memória real, provocando excesso de page faults. São algoritmos de substituição de páginas: 8.10.1 Algoritmo Otimo: impossível de ser implementado, pois o processador não consegue prever com segurança qual frame não será mais referenciado durante a execução do programa. Tal fato deve-se à lógica do programa e aos dados que ele manipula, desconhecidos pelo processador. 8.10.2 Algoritmo Aleatório: escolhe qualquer página, entre as alocadas na memória, para fazer a substituição. Em função de sua baixa eficiência, este algoritmo não é muito utilizado, embora consuma poucos recursos do sistema. 8.10.3 Algoritmo FIFO (First In, First Out): escolhe a página que está há mais tempo na memória principal para fazer a troca. É um algoritmo de simples implementação, mas corre o risco de retirar uma página que, embora tenha sido carregada há mais tempo, esteja sendo muito utilizada. Por essa razão não é muito usado. 8.10.4 Algoritmo LFU (Least Frequently Used): elege a página menos freqüentemente usada para efetuar a troca. Através de um contador, armazenado na tabela de endereçamento de páginas, mo sistema identifica quantas referências cada página teve e utiliza esta informação para escolher a página. 70 8.10.5 Algoritmo LRU (Least Recently Used): elege a página menos recentemente usada para fazer a troca. O sistema mantém na tabela de endereçamento de páginas um campo onde são armazenadas a data e a hora da última referência de cada página, e com base nestas informações faz a seleção. 8.10.6 Algoritmo NRU (Not Recently Used): elege a página menos recentemente usada para efetuar a troca. O sistema exclui da decisão a página mais recente e escolhe entre as outras, pelo método FIFO, qual página deve sair. 71 9. Gerência de Sistemas de Arquivos 9.1 Estrutura de Diretórios É como o Sistema organiza logicamente os arquivos. Contém entradas associadas aos arquivos, com as informações de localização, nome, organização e outros atributos: 9.1.1 Nível Único: é a implementação mais simples de uma estrutura de diretórios, onde existe um único diretório contendo todos os arquivos do disco. É muito limitado, não permitindo a criação de arquivos com o mesmo nome. 9.1.2 Diretório Pessoal: Evolução do modelo anterior, permite a cada usuário ter ser “diretório” particular, sem a preocupação de conhecer os outros arquivos do disco. Neste modelo há um diretório “master” que indexa todos os diretórios particulares dos usuários, provendo o acesso a cada um. 9.1.3 Múltiplos Níveis (ÁRVORE): É o modelo utilizado hoje em dia em quase todos os Sistemas Operacionais. Nesta modalidade cada usuário pode criar vários níveis de diretórios (ou sub-diretórios), sendo que cada diretório pode conter arquivos e sub-diretórios. O número de níveis possíveis depende do Sistema Operacional. 9.2 Sistemas de Alocação de Arquivos 9.2.1 FAT: sistema criado no MS-DOS e depois utilizado no Windows. Usa listas encadeadas, tem um limite de área utilizável em partições de 2 GB, caracteriza-se por um baixo desempenho no acesso e armazenamento. 9.2.2 FAT32: igual ao FAT no que diz respeito a organização e desempenho, mas pode trabalhar com partições de até 2TB. 9.2.3 NTFS: NT File System, original da plataforma Windows NT/2000/XP. Opera com uma estrutura em árvore binária, oferecendo bom grau de segurança e desempenho. Apresenta as seguintes características: 1) nomes de arquivo com até 255 caracteres, podendo conter maiúsculas, minúsculas e espaços em branco; 2) dispensa ferramentas de recuperação de erros; 3) bom sistema de proteção de arquivos; 4) criptografia; 5) suporta discos de até 264 bytes. O UNIX utiliza um diretório hierárquico, com um raiz e outros diretórios subordinados. Neste sistema operacional todos os arquivos são considerados apenas como uma “seqüência” de bytes, sem significado para o sistema. É responsabilidade da aplicação controlar os métodos de acesso aos arquivos. O UNIX utiliza também alguns diretórios padronizados, de exclusividade do sistema. 9.3 Gerência de Espaço Livre Há 3 formas de se implementar estruturas de espaços livres. Uma delas é através de uma tabela denominada mapa de bits, onde cada entrada da tabela é associada a um bloco do disco representado por um bit, que estando com valor 0 indica que o espaço está livre, e com valor 1 72 representa um espaço ocupado. Gasta muita memória, pois para cada bloco do disco há uma entrada na tabela. A segunda forma é utilizando uma lista encadeada dos blocos livres do disco. Desse modo, cada bloco possui uma área reservada para armazenar o endereço do próximo bloco livre. Apresenta problemas de lentidão no acesso, devido às constantes buscas seqüenciais na lista. A terceira forma é a tabela de blocos livres. Nesta, leva em consideração que blocos contíguos de dados geralmente são alocados/liberados simultaneamente. Desta forma, pode-se enxergar o disco como um conjunto de segmentos de blocos livres. Assim, pode-se manter uma tabela com o endereço do primeiro bloco de cada segmento e o número de blocos contíguos que se seguem. Alocação contígua: armazena o arquivo em blocos seqüencialmente dispostos no disco. O arquivo é localizado através do endereço do primeiro bloco de sua extensão em blocos. O principal problema neste tipo de alocação é a existência de espaço livre para novos arquivos, que deve ser contígua. Utiliza as estratégias best-fit, worst-fit e first-fit (já conhecidas) para definir onde o arquivo será alocado. Causa alto índice de fragmentação no disco. Alocação encadeada: nesta modalidade o arquivo é organizado como um conjunto de blocos ligados logicamente no disco, independente de sua localização física, onde cada bloco possui um ponteiro para o bloco seguinte. A fragmentação não representa problemas na alocação encadeada, pois os blocos livres para alocação do arquivo não necessariamente precisam estar contíguos. O que acontece é a quebra do arquivo em vários pedaços, o que aumenta o tempo de acesso. Neste tipo de alocação só se permite acesso seqüencial aos blocos do arquivo, sendo esta uma das principais desvantagens da técnica. Outra desvantagem é a perda de espaço nos blocos com o armazenamento dos ponteiros. Alocação indexada: esta técnica soluciona a limitação da alocação encadeada, no que diz respeito ao acesso, pois permite acesso direto aos blocos do arquivo. Isso é conseguido mantendo-se os ponteiros de todos os blocos do arquivo em uma única estrutura chamada bloco de índice. Este tipo de alocação, além de permitir acesso direto aos blocos, não utiliza informações de controle nos blocos de dados. 9.4 Proteção de Acesso Considerando-se que os meios de armazenamento são compartilhados por vários usuários, é fundamental que mecanismos de proteção sejam implementados para garantir a integridade e proteção individual dos arquivos e diretórios: Senha de acesso: mecanismo de simples implementação, mas apresenta duas desvantagens: não é possível determinar quais os tipos de operação podem ser efetuadas no arquivo, e, se este for compartilhado, todos os usuários que o utilizam devem conhecer a senha de acesso. Grupos de usuário: é muito utilizada em muitos Sistemas Operacionais. Consiste em associar cada usuário a um grupo. Os grupos são organizados logicamente com o objetivo de compartilhar arquivos e diretórios no disco. Este mecanismo implementa três níveis de proteção: OWNER (dono), GROUP (grupo) e ALL (todos). Na criação do arquivo o usuário especifica se o arquivo pode ser acessado somente pelo seu criador, pelo grupo ou por todos os usuários, além de definir que tipos de acesso podem ser realizados (leitura, escrita, execução e eliminação) Lista de controle de acesso: é uma lista associada ao arquivo onde são especificados quais os usuários e os tipos de acesso permitidos. O tamanho dessa estrutura pode ser bastante extenso se 73 considerarmos que um arquivo pode ser compartilhado por vários usuários. Além deste problema, há o inconveniente de se fazer acesso seqüencial à lista toda vez que um acesso é solicitado. Em determinados sistemas de arquivos pode-se utilizar uma combinação de proteção por grupos de usuários ou por listas de acesso, oferecendo assim maior flexibilidade ao mecanismo de proteção de arquivos e diretórios. Nos sistemas baseados no sistema operacional UNIX, como o Linux, os arquivos apresentam a propriedade de serem protegidos dessa forma. Às vezes, deseja-se que um ou mais arquivos estejam disponíveis, ao grupo e aos outros usuários, somente para leitura e execução, mas não para a escrita/alteração do(s) mesmo(s), pelo fato de o desenvolvedor do(s) mesmo(s) ainda estar trabalhando nele(s). Nesse caso, o proprietário (owner), valendo-se das facilidades de segurança oferecidas pelo sistema operacional pode proteger seus arquivos da forma que desejar. O exemplo abaixo ilustra o arquivo TESTE.TXT, totalmente acessível ao seu proprietário (RWX), para leitura e execução para o grupo (R-X) e somente para execução para os outros (--X). Vale lembrar que as letras R, W e X estão associadas respectivamente às operações de Read(leitura), Write(escrita) e eXecute (execução). TESTE.TXT RWX R-X --X 74 10. Exemplos de Sistemas Operacionais São dados abaixo algumas informações sobre alguns dos sistemas operacionais mais comuns. Numa rápida cronologia dos principais sistemas operacionais que deixaram sua marca nas últimas décadas, temos os seguintes eventos: 1969: Nascimento do Unix; 1976: Apple Primeiro micro computador pessoal; 1981: IBMPC Micro computador pessoal de arquitetura aberta; 1985: Macintosh Interface Gráfica; 1990: Windows 3.0 – Ambiente gráfico para o DOS; 1991: Linux – Sistema operacional de código fonte aberto; 1993: Windows NT: Sistema operacional gráfico e desvinculado do DOS A Apple, que introduziu quase todas as novidades em micro computadores pessoais, não conseguiu transformar suas idéias em grande participação de mercado, em parte por manter o monopólio sobre sua plataforma. Atualmente a Apple continua inovando, e o seu sistema MacOS X usa um núcleo FreeBSD (Unix) por baixo da primorosa interface gráfica, que confirma mais uma vez a tendência recente de adoção generalizada do padrão de núcleo de sistema operacional Open Source. Por outro lado, a IBM sofreu uma concorrênccia pesada dos clones (IBM PC compatible) por ter aberto a arquitetura do seu PC, mas foi justamente isso que permitiu a popularização do computador pessoal devido à redução do preço. No mercado do computador pessoal quem mais lucrou foi a Microsoft com o Windows e a Intel com sua linha de processadores x86. Numericamente, ambos têm hoje algo em torno de 90% desse mercado. Já no caso do sistema servidor de médio e grande porte a história tem sido diferente, e desde o final dos anos 1980, a plataforma predominante tem sido o RISC sob Unix, em um mercado dividido entre vários fabricantes. Entre os mais polulares sistemas operacionais estão DOS, Windows, OS/2, Unix e Linux. Dessa lista, alguns não são mais usados, porém foram escolhidos por razões históricas e/ou didáticas. 10.1 DOS (Disk Operating System) O conceito DOS (Disk Operating System) teve sua origem nos anos 1960 como uma variação de TOS (Tape Operating System), e foi usado nos mainframes IBM System/360. Nessa máquina o sistema operacional era o OS/360 e podia ser instalado em disco, e nesse caso também era chamado de DOS/360 para diferenciar de TOS/360 (na fita). A história do DOS no IBM-PC se inicia em 1978 quando a Intel lançou o seu processador 8086 que é o primeiro de 16 bits. Logo na seqüência, a IBM anunciou que lançaria o seu computador pessoal (IBM-PC) com o processador 8086. Este novo computador necessitava de um sistema operacional, e o mais próximo que existia à época era o CP/M (Control Program for Microprocessors) da Digital Research que era executado nos processadores Z80 (Zilog) e 8080/85 (Intel), que são de 8 bits. E do Zilog Z80 pode-se dizer que foi o processador de 8 bits mais popular na sua época, além de ser compatível com o 8080. À época, a Digital Research prometeu uma versão do CP/M para o 8086, porém posteriormente a IBM desistiu do 8086, que foi substituído pelo 8088. E isso tirou momentaneamente a chance de a Digital Research fornecer o sistema operacional em tempo para o lançamento do IBM-PC. Aproveitando a lacuna deixada pela Digital Research, Jim Paterson da Seattle Computer Products 75 criou rapidamente um sistema operacional baseado no CP/M, que foi chamado de Q-DOS (Quick and Dirty Operating System, em alusão ao número de bugs no código) e que rodava no 8088. Posteriormente, o QDOS foi rebatizado para 86DOS. O lançamento do IBM-PC ocorreu em 1981 com o processador Intel 8088, que é idêntico ao 8086 exceto quanto ao BUS (barramento), que foi reduzido para 8 bits para reduzir o preço. Ou seja, o 8088 internamente é de 16 bits, porém o barramento externo é de 8 bits. Para o lançamento do IBM-PC, a Microsoft que nessa época ainda era uma pequena empresa desenvolvedora de software – comprou todos os direitos do Q-DOS da Seattle Computer Products. Foi a partir do Q-DOS que a Microsoft atendeu à requisição da IBM e forneceu o PC-DOS para equipar essa nova máquina. Podese considerar que o precursor do DOS no IBMPC foi o CP/M da Digital Research, porém sem esquecer das influências e contribuições do Unix e de outros sistemas operacionais usados à época. Numa análise mais rigorosa, podemos até afirmar que o QDOS foi uma imitação do CP/M. Comercialmente o DOS inicialmente foi disponibilizado ao mercado de duas formas: PC-DOS, embutido nos equipamentos fabricados pela IBM, e MS-DOS, vendido pela Microsoft para os demais fabricantes de hardware IBM-PC compatíveis (clones). Do ponto de vista técnico, a diferença entre PC-DOS e MS-DOS era muito pequena. Convém notar que, à medida que os clones do IBMPC foram dominando o mercado, o MS-DOS foi alavancado à uma condição de plena popularidade. 10.2 UNIX Precursor de muitos sistemas operacionais, o UNIX comegou a ser desenvolvido por volta dos anos 1960, resultante de um projeto conjunto da AT&T, Honeywell, GE e o MIT (Massachussets Institute of Techonology), batizado de MULTICS (Multiplexed Information and Computing Service). Tratava-se de um sistema modular, montado em uma bancada de processadores, memórias e equipamentos de comunicação de alta velocidade para aquela época. Pelo projeto original, partes do computador poderiam ser desligadas para manutenção, sem que outras partes ou os usuários fossem afetados. No entanto, devido aos atrasos no cronograma do projeto, a AT&T decidiu abandoná-lo em 1969, mas o MIT continuou trabalhando no seu desenvolvimento. Nesse mesmo ano, alguns pesquisadores que haviam trabalhando no projeto do MULTICS se uniram para desenvolver um outro projeto na Bell Laboratories, surgindo em 1971 a primeira versão do Unix. Inicialmente, o Unix foi utilizado em máquinas da DEC (Digital Equipment Corporation) e em mainframes. Mas em 1973 o Unix foi reescrito em linguagem C, mantendo apenas uma pequena parte do núcleo escrita em linguagem Assembly. A parte desenvolvida em linguagem C permitiu sua portabilidade para outras arquiteturas de computador e a parte em Assembly teve que ser reescrita para C ou para a linguagem Assembly da outra CPU. O Unix começou a se popularizar a partir de 1975, quando foi lançada a versão V6, a primeira disponibilizada fora dos domínios da Bell Laboratories. Nessa época, a Universidade de Berkley (EUA) comprou os códigos fontes do Unix, possibilitando aos alunos realizarem modificações no sistema. Em 1979 o Unix foi portado para máquinas VAX, da DEC, e a partir de 1992 foi adaptado para a arquitetura RISC, como as da HP, Sun, IBM, DEC, entre outras. 76 A partir dos anos 1980 diferentes fabricantes de Unix começaram a divergir das características iniciais do sistema e então foi criado o comitê POSIX (Portable Operating System Unix) que especificou todas as características que um sistema operacional devia possuir para pertencer ao padrão Unix. Desde então tornou-se técnicamente mais correto tratar o Unix como uma família de sistemas operacionais, ou seja, considera-se membro dessa família todo sistema operacional que apresentar determinadas características na interface e conjunto de biblioteca de sistema. Atualmente existem cerca de 30 "sabores" de Unix e alguns exemplos importantes dessa grande família são SunOS (Solaris), HPUX, AIX, BSD, FreeBSD e Linux. Atualmente, o Unix é popular nas universidades, institutos de pesquisa e nos CPDs do ambiente corporativo, rodando principalmente sob a arquitetura RISC e atendendo às empresas de médio e grande porte. As exceções são Linux e FreeBSD, que lentamente estão conquistando também o segmento desktop. 10.3 OS/2 Antes de partir para o desenvolvimento do Windows, a Microsoft lançou em 1986, em conjunto com a IBM, as primeiras versões do sistema operacional OS/2. Mas a partir de 1990 as duas empresas optaram por seguir caminhos separados. Lançada no primeiro semestre de 1992, a versão 2.0 apresentava uma série de recursos de compatibilidade, entre os quais a possibilidade de rodar programas do Windows e do DOS, além de adotar a tecnologia de 32 bits que aproveitava melhor a potencialidade dos IBM-PCs 386, que eram executados por CPUs da Intel. A interface do OS/2 era muito semelhante à do Windows 95, apresentando área de trabalho composta por janelas e ícones. Em 1992, a IBM lançou o OS/2 WARP, que integrava a tecnologia orientada a objeto. Porém, o OS/2 não vingou tanto pela carência de aplicações quanto por ser muito "pesado" para os computadores da época. É fato que a parceria da Microsoft no desenvolvimento do OS/2 influenciou na posterior concepção do Windows NT, que também contou em seu time de projetistas para esse novo sistema operacional, experientes desenvolvedores de software e de sistemas operacionais, em particular, egressos da Digital Equipment Corporation que haviam trabalhado no desenvolvimento do sistema operacional Open VMS. 10.4 Windows Em 1985 a Microsoft lançou a primeira versão do Windows, que não era sistema operacional mas sim interface gráfica que rodava sobre o DOS. Em novembro de 1987 veio a versão 2.0, que ao contrário da versão 1.0, era capaz de sobrepor janelas. Foi na versão 2.0 que vieram pela primeira vez as aplicações Word e Excel para Windows, porém de início não foram sucesso quando comparadas com suas versões para DOS, de linha de comando. O Windows começou a fazer sucesso na versão 2.1, mas ficou popular mesmo a partir da versão 3.0, disponibilizada em 1990, já relativamente leve mesmo para os PCs mais básicos da época. A versão 4.0 do Windows, conhecida como Windows 95, foi disponibilizada ao mercado em 1995 e rapidamente tornou-se um dos sistemas operacionais mais populares devido a sua facilidade de uso, compatibilidade e principalmente devido à grande disponibilidade de software aplicativo que era executado nese sistema. Embora fosse um sistema multitarefa e com estrutura de 32 bits, grande parte do seu código era baseado no Windows 3.11. Para o ambiente corporativo foi desenvolvido o NT (New Technology), que foi o primeiro sistema operacional de 32 bits da Microsoft. A primeira versão do NT foi a 3.1, de 1993, e que tinha a aparência da interface gráfica do ambiente operacional Windows 3.1. Ao longo da sua história o Windows, basicamente, passa por 3 fases distintas: 77 ● Fase 1 (1985 a 1995): É ambiente gráfico sobre o DOS. As versões vão da 1.0 até 3.1; ● Fase 2 (1995 a 2000): O DOS está "embarcado" (embutido) no ambiente gráfico. As versões vão da 4.0 (Windows95) até 4.9 (Millennium); ● Fase 3 (1993 até hoje): São baseados no NT. O controle de versão é diferente das anteriores, inicia em 3.1 e atualmente está em 5.2 (Windows 2003 Server). É da Fase 3 a origem dos atuais sistemas Windows2000, XP e 2003 Server, que são sistemas operacionais gráficos e não tem mais nenhuma relação com o DOS. Estes sistemas são ditos "baseados no NT". Outra diferença é que a FASE 3 já inicia em 32 bits, ao contrário das anteriores que sempre mantiveram pelo menos alguma relação original com os 16 bits. Outro aspecto interessante está relacionada à multitarefa no Windows, na Fase 1 é cooperativa pois o Windows é ambiente gráfico que é executado sobre o DOS. Nas demais fases já é multitarefa real ou preemptiva. Na multitarefa cooperativa as aplicações para Windows precisam cooperar para garantir a multitarefa, na preemptiva os processos são escalonados e cada um recebe determinado tempo de CPU. Uma análise das versões do Windows desde o lançamento em 1985 até hoje (ver tabela abaixo), evidencia uma nítida seqüência evolutiva. Porém, é importante notar que a linha atual nasce com a versão NT 3.1 de 1993, enquanto a linha original (baseada no DOS) é descontinuada em 2000. 78 10.5 Windows NT O desenvolvimento do Windows NT iniciou em 1988, após a Microsoft contratar um grupo de programadores experientes que veio da Digital Equipment Corporation (DEC). O projeto foi conduzido por David Cutler, também ex projetista da DEC. A intenção inicial do projeto NT era ser a nova versão do OS/2, versão 3.0, desenvolvida em parceria com a IBM. Porém, o grande sucesso do Windows 3.0 de 1990 encorajou a Microsoft a seguir seu próprio rumo, isso após romper a parceria no desenvolvimento do OS/2. O projeto NT deveria contemplar sistemas servidores e estações de trabalho totalmente 32 bits para o ambiente corporativo em redes de computadores, e foi considerado ambicioso na medida em que podia ser utilizado em arquiteturas de computador desenvolvidas por diferentes fabricantes, como as da Digital (Alpha), IBM (Power PC), Intel (Pentium), Silicon Graphics (MIPS), entre outros. O objetivo da Microsoft era desenvolver um sistema operacional multitarefa para ser utilizado tanto em ambientes monousuário como multiusuário. O NT também se caracterizaria por ser compatível com o sistema operacional MSDOS. O lançamento do NT ocorreu em 1993 e contemplou versões para servidores e para estações de trabalho, além de ser multiplataforma e de fato totalmente 32 bits. O nome Windows NT vem de New Technology, escolhido de propósito para descolar do antigo Windows 3.1 que, por rodar sobre o DOS, apresentava um número muito grande de problemas e jamais poderia ser imaginado como servidor de rede. Surpreendentemente, na escolha da versão inicial para o NT foi invocada a versão do Windows 3.1. Inclusive, a primeira versão do NT tinha a interface gráfica do Windows 3.1 e não mais a original do OS/2. Logo na seqüência, a versão 4.0 alterou essa interface para ser igual a do recém lançado Windows 95. A proposta inicial do NT era ofertar estações de trabalho suficientemente confiáveis e competitivas a ponto de serem adotadas em larga escala nos diversos ambientes corporativos, além do servidor de rede para atender a essas estações. Na versão 3.1 do NT havia apenas workstation e server, mas posteriormente nas novas versões essas subdivisões foram aumentando, conforme poderá ser visto na tabela abaixo. A diferença básica entre workstation e server estava no modo de operação (cliente e servidor), nos serviços oferecidos e aos segmentos para os quais cada um deles foi desenvolvido, além do número de processadores suportados. Como pode ser visto na tabela 4, abaixo, tanto o NT 5.0 quanto NT 5.2 oferecem 4 subdivisões que indicam uma maior diversificação da linha quando comparados como o NT 3.1. Essa diversificação ocorre para melhor atender aos diferentes segmentos de servidores dos ambientes corporativos, diversificação essa que aparentemente continuará a aumentar nas futuras versões caso continue a boa aceitação do Windows nesse segmento. É válido observar que a partir do NT 5.2 o conceito original de estação de trabalho wokstation, que passou a ser chamado de professional no NT 5.0, passa a ter uma linha independente baseada no XP. 79 Da tabela acima pode ser notado que o NT 5.2 oferece também versões verdadeiramente de 64 bits quando estiver sobre a arquitetura EPIC. A linha de processadores da Intel (x86) atualmente ainda está nos 32 bits. Porém, devido à necessidade de endereçamento de memória além dos 4 GB, a partir do Pentium Pro seus chips incorporam a tecnologia PAE (Intel Physical Addressing Extensions), que permite endereçar até 64 GBytes de memória RAM numa CPU de 32 bits. A tecnologia PAE extende para 36 bits o endereçamento de memória, mas para que o sistema operacional lance mão dessa solução é necessário também suporte no chipset (placa mãe). Num caso típico de estação de trabalho Windows, raramente se torna necessário ir além de poucos gigabytes de memória, porém num sistema servidor mesmo de médio porte é imprescindível ir bem além do limite de 4 GB imposto pela arquitetura de 32 bits. E tendo em vista a necessidade de permitir maior alocação de memória para servidores baseados no x86, a Intel lançou também a extensão de 64 bits. Essa é a tecnologia EM64T (Extended Memory), que é uma extensão de 64 bits para a alocação de memória numa CPU de 32 bits. Como produtos, estão o P4 (Pentium 4) e Xeon, que são CPUs típicas em servidores baseados em CISC. No entanto, ao contrário do PAE, a tecnologia EM64T não está disponível em toda a linha de CPUs, mas apenas naquelas destinados ao segmento de servidores. Antes de a Intel lançar a tecnologia EM64T, a AMD, concorrente da Intel, já tinha essas extensões na sua arquitetura X8664. Outra conclusão importante a partir da tabela acima, é que com o EPIC (Itanium) o NT 5.2 finalmente chegou aos 64 bits e voltou a ser multiplataforma. No lançamento do NT (1993) havia o suporte a RISC, que posteriormente foi retirado. A geração dos sistemas operacionais Windows XP (NT 5.1) foi idealizada com o objetivo de unificar em torno de um único produto o mercado corporativo e o de usuários domésticos. 80 Nesse sentido foram desenvolvidas 2 versões: ● Windows XP (eXPerience) Personal Edition, voltado para o mercado doméstico e com a proposta de substituir os Windows 9.X, Millennium e NT Workstation; ● Windows XP Professional Edition, para o mercado corporativo e cuja proposta original era substituir o NT inclusive nas versões server. Sabe-se hoje que o XP server não vingou, e que em seu lugar veio o Windows 2003 Server (NT 5.2). Desse modo, as 4 subdivisões do NT 5.2 apresentadas na tabela 4 são todas de sistemas operacionais servidores. Já o NT 5.0 também tem 4 subdivisões, porém uma delas é o Windows 2000 professional que é estação de trabalho, desse modo confirmando mais uma vez o aumento na diversificação da linha NT a cada nova versão. 10.6 Linux Originalmente escrito por Linus Torvalds, do Departamento de Ciência da Computação da Universidade de Helsink, na Finlândia e, contando com a colaboração de vários programadores voluntários que trabalharam em conjunto através da Internet, o Linux teve sua primeira versão oficial lançada em 5 de outubro de 1991. O sistema foi desenvolvido como um hobby por Torvalds que se inspirou no Minix, o mini sistema Unix desenvolvido por Andrew Tanenbaum. 81 11.0 Bibliografia Arquitetura de Sistemas Operacionais Francis B. Machado Ed. LTC Sistemas Operacionais: Conceitos e Aplicações Abraham Silberschatz Ed. Campus Sistemas Operacionais Modernos A.S. Tanenbaum Ed. Campus 82 12.0 Dicionário de Termos (Glossário) Algoritmo: dá-se o nome de algoritmo à uma sequência de passos ou ações necessárias para que algo determinado e esperado aconteça. Algoritmos podem ser escritos ou não em uma metalinguagem, como por exemplo, as instruções contidas em receitas de bolos, torta, doces etc. Um algoritmo pode também ser escrito em uma determinada linguagem de programação, como por exemplo Java, VB, C, C++ etc. APM : é a sigla para Advanced Power Management, uma norma de gerenciamento de energia usada inicialmente em computadores portáteis (laptop), mas que mais tarde foi adotada também nos computadores de mesa (desktop). A sua principal função é controlar diversos componentes do sistema de modo a ativar modos de poupança de energia quando não estão a ser utilizados. Recentemente esta tecnologia vem sendo substituída pela norma ACPI, que não se limita somente à gestão do consumo de energia. ACPI : a ACPI (Advanced Configuration and Power Interface) é um padrão desenvolvido pela HP, Intel, Microsoft, Phoenix e Toshiba para configuração e gerenciamento de energia do computador. A ACPI tem como proposta suplantar o APM; enquanto a primeira coloca o sistema operacional no controle do gerenciamento de energia, o APM usa o BIOS para isso. A implementação da ACPI depende não apenas de software, mas também de hardware compatível. Este padrão prevê atualmente os seguintes estados energéticos : Sub-estados de energia globais G3 : Mechanical Off (desligado mecanicamente). G2 : Soft Off (desligado por software) — existe uma corrente elétrica mínima e não é seguro desmontar o equipamento. Este estado pode também ser denominado S5. G1 : Sleeping ("dormindo") — o computador parece desligado mas quando ele "acorda" (wake) o sistema operacional não precisa ser reiniciado. G0 : Working (“ em funcionamento”) — apesar de o computador estar ligado, os periféricos podem estar em estados variáveis de conservação de energia. Sub-estados do modo sleeping As especificações da ACPI não dão nome específicos aos estados abaixo listados, de forma que vários nomes são usados para a mesma coisa, e às vezes um mesmo nome é usado em sentidos diversos. S1 : Baixa conservação de energia, sem a perda do contexto no qual a CPU está trabalhando. S2 : Semelhante ao S1, mas o contexto da CPU é perdido, e o sistema operacional é responsável por reestabelecer esse contexto quando a máquina "acordar". S3 : A memória RAM continua recebendo energia, mas não a CPU e o cache de memória. Quando o sistema "acorda", a informação armazenada na RAM é utilizada para reestabelecer o estado prévio. No Windows esse estado é denominado de "modo de espera" e e "Suspender para RAM" em outros sistemas. S4 : Nem a memória RAM recebe energia e quando o computador "acorda", o estado prévio é recuperado através de informações armazenadas no disco rígido. Conhecido como "hibernar" no Windows e "Suspender para o disco" em outros sistemas operacionais. 83 Sub-estados do modo Working C0 : Processando informações C1-3 : Inativo, mas reativados no caso de instruções, com latência progressivamante maior. Sub-estados associados aos dispositivos D3 : Off (desligado). D2-1 : Estados intermediários; especificação depende do tipo de dispositivo. D0 : Fully-On (“energizado (ou ligado”)). Para dispositivos em D0 e processadores em C0, é possível especificar dois ou mais níveis de consumo de energia sendo P0 o estado de maior gasto. No caso dos processadores, a Intel chama essa tecnologia de SpeedStep e a AMD de Cool'n'Quiet Barramento (Bus) : barramento é um conjunto de linhas de comunicação que permitem a interligação entre dispositivos, como o CPU, a memória e outros periféricos, de forma a permitir a comunicação entre esses elementos. Ele também pode ser visto como um conjunto de sinais (linhas) que viabilizam a comunicação entre os demais módulos. Distinguem-se, pelo menos, 3 tipos de linhas: de dados, de endereços e de controle. Podemos assumir que, enquanto um par de módulos dialoga através do barramento, um árbitro de barramento (o bus controller) garante que nenhum outro par seja capaz de fazê-lo simultaneamente. O barramento interliga diversas CPUs, a memória principal e as controladoras dos periféricos. A memória é considerada global, visível a todas as CPUs e controladores de periféricos, assim como os próprios periféricos. Este barramento, também denominado de barramento central, pode ser sub-dividido em 3 conjuntos: 1) barramento de dados: onde trafegam os dados; 2) barramento de endereços: onde trafegam os endereços; 3) barramento de controle: sinais de controle que sincronizam os barramentos de dados e de endereços. O desempenho do barramento é medido pela sua largura de banda (quantidade de bits que podem ser transmitidos ao mesmo tempo), normalmente expressos em potências de 2, ou seja 8 bits, 16 bits, 32 bits, 64bits, 128 bits e assim por diante, assim como também pela velocidade da transmissão medida em bps (bits por segundo), como por exemplo 10 bps, 160 Kbps, 100 Mbps, 1 Gbps etc. É através do barramento que o processador faz a comunicação com o seu exterior. Nele trafegam os dados lidos da memória, escritos na memória, enviados para interfaces e recebidos de interfaces. São exemplos de barramentos centrais os seguintes tipos de barramentos: AGP ; AMR ; EISA ; FireWire ; IrDA ; ISA ; MCA ; PCI ; PCI Express ;Pipeline ; VESA Local Bus ; USB ; PS/2 etc. Nas CPUs mais modernas, com arquiteturas mais recentes, há um barramento interno à própria CPU que pode ser sub-dividido em três grupos: a)barramento de cache : o barramento em cache, existente em arquiteturas de computadores mais recentes, é um barramento dedicado para acesso à memória cache do computador. 84 b)barramento de memória : o barramento de memória é responsável pela conexão da memória principal ao processador. É um barramento de alta velocidade que varia de CPU para CPU e atualmente gira em torno de 533MHz a 1333MHz. c)barramento de Entrada e Saída : o barramento de E/S é um conjunto de circuitos e linhas de comunicação que se ligam ao resto do computador com a finalidade de possibilitar a expansão de periféricos e a instalação de novas placas. Permitem a conexão com dispositivos tais como placa gráficas ; placas de rede ; placas de som ; mouse ; teclado ; modem etc. Compilador: dá-se o nome de compilador ao utilitário que aceita como entrada um arquivo fonte (arquivo texto) escrito em uma determinada linguagem de programação e gera como saída um arquivo objeto, pronto para ser transformado em um arquivo executável pelo linker. Como exemplos de compiladores temos os compiladores Fortran, Pascal, Cobol, C etc. Cotas em disco: o regime de cotas em disco foi incorporado ao kernel de alguns sistemas operacionais (Windows, Linux etc.) e ao subsistema de gerenciamento de discos. Nesse regime, existe a opção dos administradores de definirem o quanto de espaço em um determinado disco cada usuário pode ocupar. Cotas de tempo : para cada processo é atribuído uma cota de tempo para que este possa ser executado pela CPU. Isso impede que um processo obtenha todo o tempo da CPU para si próprio. Para sistemas do tipo monotarefa (monotask), como o antigo DOS (Disk Operating System), isso não representa problema algum, mas para sistemas do tipo multitarefas (multitask), como por exemplo o UNIX, o QNX, o Open VMS, o Linux e assemelhados, além do próprio MS-Windows, isso é algo que não pode acontecer, visto que todos os outros demais processos, incluíndo-se aí os vários processos do próprio sistema operacional, podem não ser mais executados, levando o sistema a uma situação de erro insustentável. Deadlock (abraço mortal, impasse) : no contexto do sistemas operacionais o deadlock caracteriza uma situação em que ocorre um impasse e 2 ou mais processos ficam impedidos de continuar suas execuções, ou seja, ficam bloqueados. Trata-se de um problema bastante estudado no contexto dos Sistemas Operacionais, assim como em outras disciplinas, como banco de dados, pois é inerente à própria natureza desses sistemas. O deadlock ocorre com um conjunto de processos e recursos não-preemptíveis, onde um ou mais processos desse conjunto está aguardando a liberação de um recurso por um outro processo que, por sua vez, aguarda a liberação de outro recurso alocado ou dependente do primeiro processo, criando uma cadeia de esperas. No entanto, algumas observações são pertinentes: o deadlock pode ocorrer mesmo que haja somente um processo no SO, considerando que este processo utilize múltiplas threads e que tais threads requisitem os recursos alocados a outras threads no mesmo processo; o deadlock independe da quantidade de recursos disponíveis no sistema; normalmente o deadlock ocorre com recursos como dispositivos, arquivos, memória etc. Apesar da CPU também ser um recurso para o SO, em geral é um recurso fácilmente 85 preemptível, pois existem os escalonadores para compartilhar o processador entre os diversos processos, quando trata-se de um ambiente multitarefa. Debugger (depurador): o desenvolvimento de programas está sujeito a muitos erros de lógica, independentemente das metodologias ou linguagens de programação utilizadas pelo programador. A depuração é um dos estágios desse desenvolvimento, e a utilização de ferramentas adequadas é essencial para acelerar o processo de desenvolvimento e correção dos programas. Nesse contexto, o depurador (debugger) é o utilitário que permite ao usuário controlar toda a execução de um programa a fim de detectar erros na sua estrutura. Este utilitário oferece ao usuário uma grande gama de recursos tais como: 1) acompanhar a execução de um programa instrução por instrução (step by step); 2) possibilitar a alteração e visualização dos conteúdos das variáveis utilizadas no programa; 3) implementar pontos de parada dentro do programa, também conhecidos por breakpoints, de tal forma que, durante a execução do programa, o programa pare nesses pontos; 4) especificar condições de teste diversas, baseadas nos conteúdos de uma ou mais variáveis 5) enviar mensagens específicas sobre acontecimentos que o usuário deseje acompanhar Hardware: apesar de a palavra hardware poder ser aplicada para tudo aquilo que é material, no sentido físico da palavra, atualmente, ela é empregada para denotar todo e qualquer dispositivo eletrônico ou eletro-mecânico encontrado nos computadores, sejam eles de uso pessoal (PC) ou não, como por exemplo, os grandes computadores, também conhecidos por mainframes, sejam eles de uso científico ou não. Exemplos de hardware são as placas mães (motherboards), os discos magnéticos ou óticos, a CPU, impressoras, scanners, webcams etc Interpretador: dá-se o nome de interpretador ao utilitário que aceita como entrada um arquivo fonte (arquivo texto) escrito em uma determinada linguagem de programação e gera como saída um arquivo intermediário, que será posteriormente lido e executado por um outro programa. Esse código intermediário pode ser copiado para outra máquina que contenha esse interpretador sem que seja necessário uma nova interpretação. Exemplos de interpretadores são os da linguagem PERL, PHP e Java. O interpretador Java gera um arquivo do tipo .CLASS que pode ser executado em qualquer máquina que contenha o JVM e o JRE dentre outros requisitos. No jargão do “mundo” Java, dá-se o nome de bytecodes ao código intermediário produzido pelo interpretador Java. JCL (Job Control Language): A linguagem de controle, também denominada linguagem de comando, é a forma mais direta de um usuário se comunicar com o sistema operacional. Esta linguagem é oferecida por cada sistema operacional e, portanto, diferem entre si. Valendo-se dos recursos oferecidos pela JCL, através de comandos relativamente simples, o usuário pode ter acesso à rotinas específicas do sistema operacional. Esses comandos, quando fornecidos e digitados pelos usuários, são interpretados por um outro programa denominado interpretador de comandos ou simplesmente shel). O interpretador reconhece a linha de comando, verifica sua sintaxe, envia mensagens de erro e faz chamadas a rotinas do sistema. Dessa forma, o usuário dispõe de uma interface interativa com o sistema operacional, para realizar tarefas como acessar arquivos em disco, consultar diretórios e sub-diretórios, assim como acessar dados referentes à cada arquivo existente no computador tais como, data de criação, última data de alteração ou de leitura, atributos quando da sua criação etc. 86 Algumas linguagens de controle são tão poderosas e práticas que chegam a oferecer a possibilidade de serem criados programas com estruturas de decisão e iteração, podendo o usuário interagir com tais programas, que são conhecidos também por scripts. Esses programas nada mais são do que uma sequencia de comandos JCL armazenadosob a forma de arquivo (arquivo de comandos), que podem ser executados sempre que necessário. As linguagens de controle evoluiram tanto que algumas delas chegam a interfaces graficas para a comunicação com o usuário. Linguagem de Máquina: A linguagem de máquina de um computador é a linguagem de programação que a CPU realmente consegue executar. Cada modelo de CPU possui um conjunto único de instruções de máquina, definido pelo proprio fabricante. As instruções especificarn detalhes tais como quais registradores podem ser utilizados para funções específicas ou não, seus modos de endereçamento e tipos de dados, que caracterizam uma CPU e suas potencialidades . Um programa em linguagem de máquina é total mente expresso (codificado) em formato binário, ou seja em uma sequência de “1”s e “0”s, o que torna o seu entendimento, para nós humanos, muitíssimo mais confuso e tedioso, por ser essa linguagem totalmente voltada para a CPU. Programas expressos em linguagem de máquina podem ser diretamente processados pela CPU, nao requerendo qualquer tipo de tradução ou relocação. Um programa escrito em linguagem de máquina para um determinado modelo de CPU normalmente não pode ser executado em outra CPU de modelo diferente. Isso acontece porque o conjunto de instruções de uma maquina é caracteristica de cada CPU. Nos últimos anos isso deixou de ser algo impactante como por exemplo nos casos reais envolvendo algumas CPUs da Intel e da AMD e da Intel com a Zilog. Linker: dá-se o nome de linker ao programa que aceita como entrada um arquivo objeto, gerado por um compilador, e atribui os endereços de memória referenciados pelo programa e necessários à execução desse programa pela CPU. Loader: é também chamado de carregador. È o utilitário responsável por colocar fisicamente na memória um programa para ser executado. O procedimento de carga varia com o c6digo gerado pelo linker e, em função deste, o loader é cIassificado como sendo do tipo absoluto ou relocável. Se o código executável tiver sido gerado como sendo do tipo absoluto, o loader só necessita conhecer o endereço de memória inicial e o tamanho do módulo para realizar o carregamento. Então o loader lê o programa a ser executado da memória secundária (disco, CD etc.) para a memoria principal (RAM) e inicia sua execução. Por outro lado, se o c6digo tiver sido gerado como sendo do tipo relocável, o programa a ser executado pode ser carregado para qualquer posição da memória RAM, sendo o loader o responsável pela relocação do código no momento do carregamento. Por relocação deve-se entender como sendo a atribuição de novos endereços de memória, disponibilizados pelo sistema operacional, ao programa a ser executado, sem que com isso haja qualquer prejuízo em relação ao código originalmente gerado. Memória: dá-se o nome de memória à todo o tipo de elemento capaz de armazenar informações, sejam elas permanentes ou temporárias. As memórias se dividem em memórias voláteis e nãovoláteis (veja abaixo). Há memórias de acesso aleatório (random) e de acesso sequencial. As memórias de acesso sequencial são aquelas que tem o maior tempo de acesso, comparativamente às memórias de acesso aleatório. Exemplos de memórias do tipo sequencial são as fitas magnéticas (de áudio, videocassete ou de computador) onde, por exemplo, para se ouvir a última 87 música ou recuperar o último registro é necessário esperar até que a cabeça de leitura chegue ao final da fita, o que pode demandar bastante tempo. A memória pode ser vista como um conjunto de posições seqüenciais, univocamente identificadas por endereços, onde à cada posição de memória corresponde um endereço. Cada posição de memória é denominada uma palavra e tem seu tamanho dado em bits. Tipicamente, uma palavra de memória corresponde a 16, 32 ou 64 bits. Funcionalmente, a memória responde a 2 operações básicas: a) leitura do conteúdo de uma ou mais palavras consecutivas. b) escrita de um determinado valor (cujo tamanho em bits pode corresponder a uma ou mais palavras. Memórias de acesso aleatório são aquelas em que as informações podem ser obtidas de qualquer forma, como por exemplo as memórias semicondutoras de um computador, ou uma particular trilha e setor de um disco magnético ou disco ótico. Para se ouvir, por exemplo, uma determinada faixa musical de um CD ou de um DVD, o usuário pode fornecer diretamente o número da trilha (track) onde a música está e ouví-la sem ter que esperar muito tempo. O tipo de memória conhecido como FLASH é o tipo mais moderno dentre os apresentados aqui, mas é uma variação do tipo EEPROM. Tornaram-se muito populares por dois motivos: a utilização de dispositivos de armazenamento removíveis como os chamados pen drives, a aplicação em equipamentos de som que reproduzem música no formato MP3 e os cartões de memória das câmeras digitais. Os dados armazenados neste tipo de memória permanecem ali sem a necessidade de alimentação. Sua gravação é feita em geral através da porta USB que fornece o nível de tensão (voltagem) e corrente (amperagem) necessárias para alimentação. As memórias de massa podem armazenar grande quantidade de informação e têm tido seu tamanho reduzido a cada dia. O disco rígido é o meio mais comum neste tipo de memória, mas os disquetes ainda ocupam uma pequena parcela do mercado. As memórias de massa não são tão rápidas como a memória flash mas já podem ser utilizadas em equipamentos de reprodução de música e filmes como os portáteis que reproduzem videoclipes de música em vários formatos. Observe abaixo algumas fotos de memórias do tipo semicondutoras: 88 Memória Cache : Na área da computação, cache é um dispositivo de acesso rápido, interno a um sistema, que serve de intermediário entre um operador de um processo e o dispositivo de armazenamento ao qual esse operador acessa. A vantagem principal na utilização de uma cache consiste em evitar o acesso ao dispositivo de armazenamento - que pode ser demorado -, armazenando os dados em meios de acesso mais rápidos. Memória Cache é uma pequena quantidade de memória estática de alto desempenho que tem por finalidade aumentar o desempenho do processador. Com os avanços tecnológicos, vários tipos de cache foram desenvolvidos. Atualmente há cache em processadores, discos-rígidos, sistemas, servidores, nas placas-mães, dentre outros exemplos. Qualquer dispositivo que requeira do usuário uma solicitação/requisição a algum outro recurso, seja de rede ou local, interno ou externo a essa rede, pode requerer ou possuir de fábrica o recurso de cache. Por ser mais caro, o recurso mais rápido não pode ser usado para armazenar todas as informações e, sendo assim, usa-se a cache para armazenar apenas as informações mais frequentemente usadas. Nas unidades de disco também conhecidas como disco rígido ou hard disk (HD), também existem chips de cache nas placas eletrônicas que os acompanham, como por explo, a unidade Samsung de 160 GB que tem 8 Mbytes de cache. A memória cache é útil em vários contextos, tais como: nos casos dos processadores, em que a cache disponibiliza alguns dados já requisitados e outros ainda “a processar”; 89 no caso dos navegadores, em que as páginas são guardadas localmente para evitar consultas constantes à rede (especialmente úteis quando se navega por páginas estáticas); no caso das redes de computadores , o acesso externo , ou à Internet , se dá por meio de um software que compartilha a conexão ou link , software este também chamado de proxy , que tem por função rotear as requisições a IPs externos à rede que se encontra , nestes proxys temos ainda um cache , que na verdade é uma enorme lista de todos os sites que foram visitados pelos usuários dos computadores desta rede, fazendo com isto a mesma função que os caches presentes nos navegadores , ou browsers, só que com a atribuição de servir a toda a rede e com isso aumentar a taxa de acerto dos proxys , minimizar o consumo do link e agilizar a navegação. os servidores Web, também dispõem de caches configurados pelo administrador, que variam de tamanho conforme o número de page views que o servidor tem a oferecer. A memória cache é um bloco de memória para o armazenamento temporário de dados que possuem uma grande probabilidade de serem utilizados novamente. Uma definição mais simples de cache poderia ser: uma área de armazenamento temporária onde os dados freqüentemente acedidos são armazenados para acesso rápido. Uma cache é feita de uma fila de elementos. Cada elemento tem um dado que é a cópia exata do dado presente em algum outro local (original). Cada elemento tem uma etiqueta que especifica a identidade do dado no local de armazenamento original, que foi copiado. Quando o cliente da cache (CPU, navegador etc.) deseja acessar a um dado que acredita estar no local de armazenamento, primeiramente ele verifica a cache. Se uma entrada for encontrada com uma etiqueta correspondente ao dado desejado, o elemento da cache é então utilizado ao invés do dado original. Essa situação é conhecida como acerto do cache (cache hit). Como exemplo, um navegador poderia verificar a sua cache local no disco para ver se tem uma cópia local dos conteúdos de uma página Web numa URL particular. Nesse exemplo, a URL é a etiqueta e o conteúdo da página é o dado desejado. A percentagem de acessos que resultam em cache hits é conhecida como a taxa de acerto (hit rate ou hit ratio) da cache. Uma situação alternativa, que ocorre quando a cache é consultada e não contém um dado com a etiqueta desejada, é conhecida como cache miss (erro do cache). O dado então é copiado do local original de armazenamento e inserido na cache, ficando pronto para o próximo acesso. Se a cache possuir capacidade de armazenamento limitada (algo comum de acontecer devido ao seu custo), e não houver mais espaço para armazenar o novo dado, algum outro elemento deve ser retirado dela para que liberte espaço para o novo elemento. A forma (heurística) utilizada para seleccionar o elemento a ser retirado é conhecida como política de troca (replacement policy). Uma política de troca muito popular é a LRU (least recently used), que significa algo como “elemento recentemente menos usado”. Quando um dado é escrito na cache, ele deve ser gravado no local de armazenamento em algum momento. O momento da escrita é controlado pela política de escrita (write policy). Existem diferentes políticas. A política de write-through (algo como “escrita através”) funciona da seguinte forma: a cada vez que um elemento é colocado no cache, ele também é gravado no local de armazenamento original. Alternativamente, pode ser utilizada a política de write-back (escrever de volta), onde as escritas não são directamente espelhadas no armazenamento. Ao invés, o mecanismo de cache identifica quais de seus elementos foram sobrepostos (marcados como sujos) e somente essas posições são colocadas de volta nos locais de armazenamento quando o elemento for retirado do cache. Por essa razão, quando ocorre um cache miss (erro de acesso ao cache pelo fato de um elemento não existir nele) em um cache com a política write-back, são necessários dois acessos à memória: um para recuperar o dado necessário e outro para gravar o dado que foi modificado no cache. 90 O mecanismo de write-back pode ser accionado por outras políticas também. O cliente pode primeiro realizar diversas mudanças nos dados do cache e depois solicitar ao cache para gravar os dados no dispositivo de uma única vez. Os dados disponíveis nos locais de armazenamento original podem ser modificados por outras entidades diferentes, além do próprio cache. Nesse caso, a cópia existente no cache pode se tornar inválida. Da mesma forma, quando um cliente atualiza os dados no cache, as cópias do dado que estejam presentes em outros caches se tornarão inválidas. Protocolos de comunicação entre gerentes de cache são responsáveis por manter os dados consistentes e são conhecidos por protocolos de coerência. Chama-se de “princípio da localidade” à tendência de o processador ao longo de uma execução referenciar instruções e dados da memória principal localizados em endereços próximos. Tal tendência é justificada devido as estruturas de repetição e as estruturas de dados, vetores e tabelas utilizarem a memória de forma subseqüente (um dado após o outro). Assim a aplicabilidade da cache internamente ao processador fazendo o intermédio entre a memória principal e o processador de forma a adiantar as informações da memória principal para o processador. Um erro de MIS ocorre quando o processador necessita de um dado, e este não está presente no cache, ele terá de realizar a busca diretamente na memória RAM, utilizando estados de espera (wait states) e reduzindo o desempenho do computador. Como provavelmente será requisitado novamente (localidade temporal) o dado que foi buscado na RAM é copiado na cache. Níveis de Cache : Cache L1 : uma pequena porção de memória estática presente dentro do processador. Em alguns tipos de processador, como o Pentium 2, o L1 é dividido em dois níveis: dados e instruções (que "dizem" o que fazer com os dados). A partir do Intel 486, começou a se colocar a L1 no próprio processador. Geralmente tem entre 16KB e 512KB. O AMD Sempron 2600+ possui 64KB de cache L1. Neste aspecto a Intel fica a perder em relação à AMD, visto possuir menor memória cache nível 1 do que a sua concorrrente direta. Assim já existem processadores AMD com 128K de memória cache nível 1, como por exemplo o AMD Turion 64 ML-40. Cache L2 : possuindo o Cache L1 um tamanho reduzido e não apresentando uma solução ideal, foi desenvolvido o cache L2, que contém muito mais memória que o cache L1. Ela é mais um caminho para que a informação requisitada não tenha que ser procurada na lenta memória principal. Alguns processadores colocam essa cache fora do processador, por questões econômicas, pois uma cache grande implica num custo grande, mas há exceções, como no Pentium II, por exemplo, cujas caches L1 e L2 estão no mesmo cartucho que está o processador. É neste aspecto essencial que a Intel ganha todo o prestígio e rendimento dos seus processadores. A memória cache L2 é, sobre tudo, um dos elementos essenciais para um bom rendimento do processador mesmo que tenha um clock baixo. Um exemplo prático é o caso do Intel Xeon (para servidores) que tem apenas 1.4 GHz de clock interno e ganha de longe do atual Intel Extreme, pelo fato de possuir uma memória cache de 12Mb. Quanto mais alto é o clock do processador, mais este aquece e mais instável se torna. Os processadores Intel Celeron tem tão fraco desempenho por possuir menor memória cache L2. Um Pentium M 730 de 1.6 GHz de clock interno, 533 MHz FSB e 2 MB de cache L2, tem rendimento semelhante a um Intel Pentium 4 2.4 GHz, aquece muito menos e torna-se muito mais estável e bem mais rentável do que o Intel Celeron M 440 de 1.86 GHz de clock interno, 533 MHz FSB e 1 MB de cache L2. Cache L3 : terceiro nível de cache de memória. Inicialmente utilizado pelo AMD K6-III (por apresentar o cache L2 integrado ao seu núcleo) utilizava o cache externo presente na placa-mãe 91 como uma memória de cache adicional. Ainda é um tipo de cache raro devido a complexidade dos processadores atuais, com suas áreas chegando a milhões de transístores por micrometros ou picometros de área. Ela será muito útil, é possível a necessidade futura de níveis ainda mais elevados de cache, como L4 e assim por diante. Usando a técnica de nominada de Write-Back Cache a CPU escreve dados diretamente na cache, cabendo ao sistema a escrita posterior da informação na memória principal. Como resultado o CPU fica livre mais rapidamente para executar outras operações. Em contrapartida, a latência do controlador pode induzir problemas de consistência de dados na memória principal, em sistemas multiprocessados com memória compartilhada. Esses problemas são tratados por protocolos de consistência da cache. Exemplo: A escrita de um endereço e feita inicialmente numa linha da cache, e somente na cache. Quando mais tarde algum novo endereço necessitar desta linha da cache, estando esta já ocupada, então o endereço inicial é guardado na memoria e o novo endereço ocupa-lhe o lugar na respectiva linha da cache. Para reduzir a frequência de escrita de blocos de endereços na memoria quando da substituição é usado um "dirty bit", este é um bit de estado, ou seja, quando o endereço é instanciado inicialmente numa linha da cache, estando essa linha vazia, o valor inicial é implicitamente '0', quando o bloco do endereço e modificado (quando ocorre uma substituição) o valor inicial passa a '1' e diz-se que o bloco do endereço está "dirty". Vantagens: -A escrita ocorre à velocidade da cache; escritas múltiplas de um endereço requerem apenas uma escrita na memória Desvantagens: -Difícil de implementar; nem sempre existe consistência entre os dados existentes na cache e na memoria; leituras de blocos de endereços na cache podem resultar em escritas de blocos de endereços "dirty" na memoria. 92 Memórias não-voláteis: as memórias não-voláteis utilizam tecnologia semicondutora e são elementos capazes de armazenar informações de forma definitiva. Memórias não-voláteis são aquelas em que os dados não são perdidos quando a energia elétrica é suprimida. Exemplos de memórias não-voláteis são as do tipo ROM(Read Only Memory), as do tipo PROM (Programmable Read Only Memory) , as do tipo EPROM (Erasable Programmable Read Only Memory), as do tipo EEPROM (ou EEROM) (Electricaly Erasable Programmable Read Only Memory), as do tipo Flash dentre outros tipos. Há outros tipos de memória não-voláteis que não utilizam tecnologia semicondutora, como por exemplo os discos magnéticos, os discos óticos (DVDs e CDs), fitas magnéticas do tipo CCT (Computer Compatible Tape), fitas do tipo DAT (Digital Audio Tape) , as antigas e populares fitas do tipo cassette (k-7) e as fitas para vídeo cassettes padrão VHS. Para gravar uma memória semicondutora dentre os tipos dados abaixo são necessários alguns equipamentos específicos. Dentre as memórias tidas como sendo do tipo ROM destacam-se as seguintes: Sigla Nome Tecnologia Read Only Memory (memória ROM Gravada na fábrica uma única vez somente de leitura) Programable Read Only Memory (memória PROM Gravada pelo usuário uma única vez programável somente de leitura) Pode ser gravada ou regravada por meio de um equipamento que fornece as voltagens Erasable Programable Read adequadas em cada pino. Para apagar os dados Only Memory (memória EPROM nela contidos, basta iluminar o chip com raios programável e apagável ultravioleta. Isto pode ser feito através de uma somente de leitura) pequena janela de cristal presente no circuito integrado. Electrically Erasable Programable Read Only Pode ser gravada, apagada ou regravada Memory (memória EEPROM utilizando um equipamento que fornece as programável e apagável voltagens adequadas em cada pino. eletronicamente somente de leitura) Uma memória do tipo ROM/PROM Uma memória do tipo EPROM (observe a janela) 93 Conforme já mencionado, uma EPROM é programada por um dispositivo eletrônico que dá voltagens maiores do que os usados normalmente em circuitos elétricos. Uma vez programado, uma EPROM pode ser apagada apenas por exposição a uma forte luz ultravioleta. EPROMs são facilmente reconhecíveis pela janela transparente no topo do pacote, pela qual o chip de silício pode ser visto, e que admite luz ultravioleta durante o apagamento. Esta janela transparente é feita de cristal para permitir a passagem da luz ultravioleta, pois o vidro comum bloqueia grande parte do UV. O corpo de uma EPROM é feito em Cerâmica, pois o Epoxy comumente usado em outros chips não seria apropriado para garantir a fixação da janela de cristal. O processo de apagamento dura de 10 a 30 minutos. Uma EPROM programada mantém seus dados por um período de aproximadamente 10 a 20 anos e pode ser lida ilimitadas vezes. A janela de apagamento tem que ser mantida coberta para evitar apagamento acidental pela luz do sol, rica em raios ultravioletas. Antigos chips de BIOS de PC eram freqüentemente EPROMs, e a janela de apagamento era frequentemente coberta com um adesivo contendo o nome do produtor da BIOS, a revisão da BIOS, e um aviso de Copyright. Segue abaixo alguns modelos das antigas memórias EPROM , ainda encontradas em muitos computadores e circuitos eletrônicos. Na fota acima, observem a janela por onde a luz ultravioleta entrava para gerar a fotocorrente para apagar os dados armazenados. Uma vez gravadas com a versão final, a janela era protegida com um fita colante escura, protegendo-a da luz solar. Existem EPROMs de vários tamanhos físicos, formatos e capacidades. Veja a foto e tabela abaixo: Tipo de EPROM Tamanho bits Tamanho bytes Tamanho (hex) Último endereço (hex) 2716, 27C16 16 Kbit 2KBytes 800 007FF 2732, 27C32 32 Kbit 4KBytes 1000 00FFF 2764, 27C64 64 Kbit 8KBytes 2000 01FFF 27128, 27C128 128Kkbit 16KBytes 4000 03FFF 27256, 27C256 256 Kbit 32KBytes 8000 07FFF 27512, 27C512 512 Kbit 64KBytes 10000 0FFFF 27C010, 27C100 1Mbit 128KBytes 20000 1FFFF 27C020 2 Mbit 256 Kbytes 40000 3FFFF 27C040 4 Mbit 512 Kbyte 80000 7FFFF NOTA: As séries de EPROMs 27x contendo um C no nome são baseados em CMOS, sem o C são NMOS 94 Memórias voláteis: as memórias voláteis utilizam tecnologia semicondutora e são elementos capazes de armazenar informações de forma temporária. Memórias voláteis são aquelas em que os dados são perdidos quando a energia elétrica é suprimida. Exemplos de memórias voláteis são as RAM(Random Access Memory) e suas assemelhadas (DRAM e SRAM). As memórias voláteis se caracterizam pela velocidade com que respondem aos acessos da CPU. Memória dinâmica (DRAM) : a memória dinâmica (Dinamic Random Access Memory) é a mais barata das memórias RAM e, portanto, a mais utilizada nos computadores e são aquelas que foram popularizadas como sendo as memórias RAM conhecidas. Na realidade, existem outras memórias de acesso aleatório nos computadores, inclusive as não voláteis e portanto, é importante ter o conhecimento de que o nome RAM é apenas uma popularização do nome da memória principal dos computadores, utilizada para armazenar os programas e dados no momento da execução. O nome dinamica se refere à tecnologia utilizada para armazenar os dados e não à forma de acessá-los. De modo simplista ela funciona como uma bateria que deve ser recarregada sempre que apresentar carga insuficiente para alimentar o equipamento. A esse processo de “recarga” dáse o nome de refrescamento da memória (refresh), o que faz com esse tipo de memória seja mais lenta e barata que as memórias do tipo SRAM. Memória estática (SRAM) : a memória estática (Static Random Access Memory) não necessita ser “refrescada” em intervalos regulares. Fabricada com circuitos eletrônicos conhecidos como latches, elas guardam a informação pelo tempo em que estiverem alimentadas com eletricidade. Devido à tecnologia empregue na sua construção, esse tipo de memória é mais cara e mais rápida que as memórias do tipo DRAM. Montador: dá-se o nome de montador (Assembler) ao programa que aceita como entrada um arquivo fonte (arquivo texto) escrito em linguagem de montagem (linguagem Assembly) e gera um arquivo escrito em linguagem de máquina, específico para uma particular CPU. Placa-mãe : também denominada mainboard ou motherboard, é uma placa de circuito impresso, que serve como base para a instalação dos demais componentes de um computador, como o processador, memória RAM, os circuitos de apoio, as placas controladoras, os slots do barramento e o chipset. 95 Plug and Play: essa tecnologia permite ao sistema operacional a deteccção e identificação de um determinado dispositivo periférico recentemente acoplado ao computador. A adição desse novo dispositivo é identificada e a localização do seu driver, dentre os vários drivers disponibilizados e reconhecidos pelo sistema, é iniciada. Se o driver não for achado dentre esses vários drivers já instalados, será solicitado a sua instalação e após o término exitoso desta, este novo dispositivoi poderá ser utilizado, facilitando o gerenciamento do sistema. Programa: dá-se o nome de programa à codificação de um determinado algoritmo em uma determinada linguagem de programação. Processo: dá-se o nome de processo a todo o programa sendo executado pela CPU. São constituintes do processo os conteúdos de todos os registradores da CPU e todas as posições de memória alocadas pelo processo e para o processo pelo sistema operacional. 96 Starvation (inanição) : em programação concorrente, a inanição ocorre quando um processo nunca é executado, vindo a "morrer de fome", pois processos de prioridade maior sempre o impedem de ser executado. Num ambiente computacional multitarefa, a execução de diversos processos simultâneos deve seguir a uma regra de escalonamento destes para uso do processador. Isto se deve ao fato de que, durante a mudança de contexto pelo processador, é feita a escolha do próximo processo a ser executado a partir da prioridade deste. Quando o escalonamento não é feito adequadamente, pode haver inanição. Uma solução para esta situação é a atribuição de um tempo máximo de espera por algum evento. A ocorrência da inanição se dá quando os programas rodam indefinidamente (razão pela qual também se dá o nome de preterição indefinida a esta situação) e não fazem nenhum progresso em seu processamento, ao contrário do deadlock, que ocorre quando os processos permanecem bloqueados, dependendo da liberação dos recursos por eles alocados. Num sistema dinâmico, as requisições de recursos ocorrem durante todo o tempo. Algumas políticas são necessárias para subsidiar a decisão de quem vai ficar com qual recurso e em que momento. Essas políticas, apesar de parecerem extremamente razoáveis, podem fazer com que alguns processos nunca sejam servidos, apesar de não estarem em deadlock. Um exemplo disso é a alocação de uma impressora. Considerando que o sistema utilize algum algoritmo que garanta que a alocação da impressora não vai levar à situações de deadlock, e considerando também que diversos processos desejam utilizá-la ao mesmo tempo. Deve-se definir qual dos processos tem o direito de usá-la. Um algorítmo possível para implementar a alocação da impressora é o que escolhe o processo com o menor arquivo a ser impresso (assumindo que esta informação esteja disponível). Este algoritmo maximiza o número de usuários satisfeitos com o sistema, e parece ser um algoritmo justo. Consideremos, no entanto, o que acontece num sistema muito carregado, quando um determinado processo tem um arquivo imenso a ser impresso. Cada vez que a impressora estiver disponível, o sistema vai escolher, para usar a impressora, o processo com o menor arquivo a ser impresso. Se houver um fluxo constante de processos no sistema com arquivos pequenos, aquele ou aqueles com arquivos grandes jamais poderão usar a impressora. Eles apenas “morrerão de fome” (como o próprio sentido da palavra inanição estabelece), ou seja, serão preteridos indefinidamente em favor de outros, como se estivessem bloqueados. A preterição por tempo indeterminado pode ser evitada usando-se uma política de alocação baseada na regra do primeiro-a-chegar é o primeiro-a-ser-servido. Com esta abordagem, o processo que espera há mais tempo é o primeiro a receber serviço por parte do recurso liberado. Fica claro que qualquer dos processos será o mais antigo com o passar do tempo, recebendo, assim, o direito ao uso do recurso pelo qual estiver esperando. Outra solução é fazer com que o processo em inanição consiga aumentar a sua prioridade de acordo com o seu tempo de espera, o que também pode resolver o problema. Software: o termo software é atualmente utilizado para denotar todos os tipos de programas de computadores, sejam eles de uso pessoal ou não. Exemplos de softwares são os editores de texto, as planilhas eletrônicas, as linguagens de programação, sistemas operacionais etc. 97 Unicode: O Unicode é um padrão criado por um consórcio (www.unicode.org) para que sistemas de todo o mundo consigam se comunicar. Define os caracteres utilizados em línguas do mundo todo. Enquanto o padrão ASCII (American Standard Code for Information Interchange) utiliza 8 bits (com um universo possível de 256 caracteres diferentes), o padrão Unicode utiliza 16 bits (aumentando o universo de caracteres para 65.536 - atualmente mais de 38.000 caracteres ja foram mapeados neste padrão). 98