Sistemas Operacionais – Filippe Jabour – v. 2.0.1 Universidade Severino Sombra – USS. Universidade Presidente Antônio Carlos - UNIPAC Sistemas Operacionais. Autor: Filippe Jabour. Versão: 2.0.1. Atualizada em: 01/03/2004. Sistemas Operacionais Índice 1. Introdução: .................................................................................................................................................................... 2 1.1 Histórico:............................................................................................................................................................... 2 1.1.1 2ª geração, 1955 a 1965: ............................................................................................................................... 2 1.1.2 3ª geração, 1965 a 1980: ............................................................................................................................... 2 1.1.3 4ª geração, 1980 até hoje: .............................................................................................................................. 2 1.2 Conceitos básicos: ................................................................................................................................................. 3 1.2.1 Sistema Operacional: .................................................................................................................................... 3 1.2.2 Operação de sistemas computacionais: ......................................................................................................... 3 1.2.3 Chamadas de sistema (system calls):............................................................................................................. 3 1.2.4 Processo: ....................................................................................................................................................... 4 1.2.5 Shell: ............................................................................................................................................................. 4 1.3 Estrutura do S.O.: .................................................................................................................................................. 4 1.3.1 Sistemas monolíticos: .................................................................................................................................... 4 1.3.2 Sistemas em camadas: ................................................................................................................................... 4 1.3.3 Máquina virtual: ............................................................................................................................................ 5 1.3.4 Modelo Cliente-Servidor: .............................................................................................................................. 5 2 Processos:...................................................................................................................................................................... 5 2.1 Introdução: ............................................................................................................................................................ 5 2.1.1 Modelo de processo: ..................................................................................................................................... 6 2.1.2 Alternância entre processos: .......................................................................................................................... 6 2.1.3 Exercícios: ..................................................................................................................................................... 7 2.2 Threads ou processos leves: .................................................................................................................................. 8 2.3 Escalonamento de processos: ................................................................................................................................ 9 2.4 Métodos de escalonamento: .................................................................................................................................. 9 2.4.1 Primeiro a chegar, primeiro a ser servido (PCPS) (First in first out – FIFO):............................................... 9 2.4.2 Menor primeiro (MP): ................................................................................................................................. 10 2.4.3 Alocação por prioridade: ............................................................................................................................. 11 2.4.4 Alocação circular (AC) (Round Robin): ...................................................................................................... 11 2.4.5 Exercícios: ................................................................................................................................................... 12 3 Gerenciamento de Memória ........................................................................................................................................ 13 3.1 Fundamentos ....................................................................................................................................................... 13 3.2 Troca de Processos .............................................................................................................................................. 13 3.3 Alocação contígua de memória ........................................................................................................................... 13 3.3.1 Alocação com diversas partições ................................................................................................................ 14 3.4 Paginação ............................................................................................................................................................ 14 3.4.1 Método básico ............................................................................................................................................. 14 3.4.2 Páginas Compartilhadas .............................................................................................................................. 15 3.5 Segmentação ....................................................................................................................................................... 16 3.5.1 Proteção e compartilhamento ...................................................................................................................... 17 3.5.2 Fragmentação: ............................................................................................................................................. 17 4 Bibliografia ................................................................................................................................................................. 17 1 Sistemas Operacionais – Filippe Jabour – v. 2.0.1 1. Introdução: 1.1 Histórico: 1.1.1 2ª geração, 1955 a 1965: Batch Systems e transistor. Leitura de cartões de vários programas para fitas feita em computadores auxiliares. O "ancestral" dos Sistemas Operacionais (S.O.) lê as fitas e executa os programas um a um, gravando os resultados também em fita. Esta etapa é executada no computador principal. Impressão dos resultados no computador auxiliar. Comunicação entre computador auxiliar e computador central feita pelo operador. 1.1.2 3ª geração, 1965 a 1980: Multiprogramação e circuito integrado Computadores de uso geral (científico + comercial) compatíveis entre si (família) o que implicou em S.O. muito complexos e com muitos erros. Mesmo assim foi introduzido um conceito de extrema importância, a multiprogramação. Objetivo da multiprogramação: Aproveitar momentos ociosos de CPU (tipicamente existentes durante operações de I/O) para processar outros jobs (programas). Como funciona a multiprogramação: Divisão da memória e carga de mais de um programa possibilitando o chaveamento de um para outro durante os momentos de ociosidade citados anteriormente. Ver figura 1. Programa 3 Partições de memória Programa 2 Programa 1 S.O. Figura 1 É necessário que haja proteção de um programa com relação a outro para que não ocorra invasão de outras áreas de memória. Aqui esta proteção era implementada em hardware. Outra habilidade introduzida foi a capacidade de leitura dos programas dos cartões para o disco logo que os mesmos eram trazidos para a sala do computador. Assim, quando um job terminava, outro poderia ser carregado (spooling). Também se utilizava spooling para saída. Computadores auxiliares da 2ª geração não eram mais necessários. Surge a técnica de time-sharing ou compartilhamento de CPU. Cada usuário tem um terminal on-line e todos compartilham a CPU. Sistema operacional Multics é reescrito em C dando origem ao Unix. 1.1.3 4ª geração, 1980 até hoje: Integração em larga escala (LSI e VLSI) Surge o PC, muito mais barato do que os computadores das gerações anteriores. O uso do computador de dissemina amplamente. S.O. deve ser amigável (user-friendly) buscando dar comodidade ao usuário. 2 Sistemas Operacionais – Filippe Jabour – v. 2.0.1 Sistemas que surgem e/ou se popularizam: MS-DOS, Unix/Linux, Apple, Windows 95/98/2000/ME/CE/NT/XP Nesta geração ocorre a descentralização do processamento. S.O. de rede: Usuários estão cientes da existência de múltiplos computadores, podendo conectar-se a máquinas remotas e utilizar recursos destas máquinas. S.O. distribuídos: Aparecem para o usuário como um sistema convencional mas, na verdade, recursos distribuídos estão sendo disponibilizados. O usuário não tem conhecimento da localização dos seu arquivos nem do local onde seus programas estão sendo executados. Nesta fase torna-se marcante a maior importância da comodidade do usuário sobre a eficiência do sistema Com a expansão dos dispositivos móveis de computação, S.O. específicos, com características próprias de interface, economia de energia e utilização de recursos de conectividade vêm sendo desenvolvidos. 1.2 Conceitos básicos: 1.2.1 Sistema Operacional: É difícil conceituar objetivamente S.O.. Serão colocadas a seguir algumas definições. É o software que gerencia o hardware. É um gerenciador de recursos, de processos, de segurança e de compartilhamento. Entenda-se por recursos os arquivos, memória principal, periféricos como discos e impressoras, etc. É um programa que controla e coordena o uso do hardware por vários programas aplicativos de vários usuários. Conjunto de módulos de software que rege a utilização dos recursos do sistema, resolve conflitos, simplifica o uso da máquina e busca otimizar seu desempenho global. 1.2.2 Operação de sistemas computacionais: Um sistema computacional moderno, de propósito geral, consiste em uma CPU e vários controladores de dispositivos conectados por um barramento comum que oferece acesso a uma memória compartilhada (ver [1], figura 2.1, p. 45). A CPU e os controladores de dispositivos podem ser executados simultaneamente, competindo por ciclos de memória. Para assegurar um acesso ordenado à memória compartilhada, existe um controlador de memória, cuja função é sincronizar os acessos a ela. Seqüência inicial de funcionamento de um computador e as etapas subseqüentes de operação do sistema operacional. 1. O equipamento é ligado. 2. BIOS (Basic I/O System): Executa testes no sistema (hardware), reconhece controladores de dispositivos, busca o primeiro programa a ser executado. 3. Este primeiro programa (programa de bootstrap), bastante simples, inicializa os valores de alguns registradores, localiza, carrega e põe em execução o sistema operacional. 4. O núcleo do sistema operacional foi então carregado e fica em execução durante toda a sessão de trabalho. Neste primeiro momento um processo do sistema operacional é iniciado e fica aguardando a ocorrência de algum evento. A ocorrência de um evento é em geral sinalizada por uma interrupção de hardware (enviada pelo barramento de sistema) ou de software (através de uma operação especial denominada chamada de sistema – system call). Podem gerar uma interrupção, a conclusão de uma operação de entrada e saída (E/S), divisão por zero, acesso a uma posição inválida de memória, requisição a um serviço do sistema operacional etc. Para cada interrupção existe uma rotina específica que irá tratá-la. Quando ocorre uma interrupção, a CPU pára o que está fazendo e transfere imediatamente a execução para uma posição fixa de memória onde está o endereço inicial da rotina de tratamento. 1.2.3 Chamadas de sistema (system calls): A interface entre o S.O. e os programas de usuário é definida pelo conjunto de instruções estendidas que o S.O. proporciona. Exemplo: read(file,buffer,mbytes): chamada de sistema para ler um arquivo de um certo tamanho para um determinado buffer. 3 Sistemas Operacionais – Filippe Jabour – v. 2.0.1 1.2.4 Processo: É um programa (ou parte de um programa) em execução. 1.2.5 Shell: É o prompt do sistema que aguarda a digitação de um comando. Quando este é digitado, o interpretador de comandos traduz a linha digitada e o S.O. executa o comando. 1.3 Estrutura do S.O.: 1.3.1 Sistemas monolíticos: Trata-se de um único módulo executável onde qualquer procedimento enxerga os demais e pode executá-los livremente. Podemos ter um nível de estruturação como descrito a seguir: 1. A máquina está em modo usuário executando um processo. 2. É executada uma instrução especial de interrupção conhecida como chamada de kernel ou chamada de supervisor, comutando a máquina do modo usuário (nem todas as instruções são permitidas) para o modo kernel ou modo monitor (todas as instruções são permitidas). 3. S.O. termina de executar as instruções desejadas em modo Kernel e retorna com a máquina para o modo usuário, reiniciando a execução de um dado processo. 1.3.2 Sistemas em camadas: Uma camada tem suas funções bem definidas e oferece serviços à camada superior. A camada superior não precisa "se preocupar" como a camada inferior implementa um serviço, ela apenas utiliza tal serviço. Um exemplo (Dijkstra, 1968): Camada 5 4 Função Operador Programa usuário 3 Gerenciamento de I/O (entrada e saída) (E/S) 2 Comunicação Processo 1 Gerenciamento de processos em memória e disco (paginação) 0 Alocação do processador e multiprogramação Operador X Observações Processo de operação dos sistemas e programas Não tem que se preocupar com gerência de processos, de memória, de console ou de E/S. Gerencia dispositivos de E/S e os respectivos buffers. Acima desta camada, cada processo pode lidar com dispositivos abstratos e amigáveis de E/S. Manipula a comunicação entre cada processo e o console do operador. Acima desta camada cada processo possui virtualmente seu próprio console de operação. Coloca os processos em memória e, caso não haja espaço, partes deles (páginas) em disco. Não se preocupa como e quando estes processos serão postos em execução na CPU e quando serão retirados da CPU pois isto é função da camada zero. Cuida para que, quando necessário, as páginas certas estejam na memória. Aloca CPU para os diversos processos baseado em critérios de escalonamento (ex.: fatia de tempo) e em interrupções. Proporciona a multiprogramação. Tabela 1 O MULTICS (precursor do Unix) generalizou o esquema de camadas para uma organização em anéis concêntricos. Os anéis internos são privilegiados com relação aos externos. Quando um procedimento em um anel externo quer chamar outro em um anel interno, ele tem que fazer o equivalente a uma chamada de sistema. Os parâmetros desta chamada são cuidadosamente verificados e validados antes da permissão de execução. 4 Sistemas Operacionais – Filippe Jabour – v. 2.0.1 1.3.3 Máquina virtual: Um módulo (monitor de máquina virtual) executa sobre o hardware básico e, através de multiprogramação, oferece várias "cópias" virtuais deste hardware básico. Em cada uma destas cópias (máquinas virtuais) é executado um S.O. (não necessariamente o mesmo) e ela se mostra aos níveis superiores como se fosse o próprio hardware básico. S.O. MV 1 S.O. S.O. MV 2 MV 3 Monitor de máquina virtual Hardware básico ......... ......... Figura 2 1.3.4 Modelo Cliente-Servidor: Migra diversas funções do S.O. para processos servidores a serem executados no modo usuário e deixa menos atribuições para o kernel do S.O. (basicamente gerenciar a comunicação entre clientes e servidores e executar instruções complexas típicas do modo kernel.) Modo usuário Processo Processo Cliente Cliente ...... Servidor de terminal ...... Servidor Servidor de de memória arquivos Kernel Modo Kernel Figura 3 Se considerarmos que processos clientes e servidores podem estar rodando em máquinas diferentes, temos uma extrapolação para Sistemas Distribuídos. 2 Processos: 2.1 Introdução: Conceitualmente, Processo é a abstração de um programa (ou parte de um programa) em execução. É um modelo apropriado para a compreensão da multiprogramação (presente em todos os S.O. modernos). Todos os computadores modernos podem fazer várias coisas ao mesmo tempo. Enquanto executa um programa do usuário, um computador também pode estar lendo a partir do disco e dando saída a texto para uma tela ou impressora. Em um sistema de multiprogramação, a CPU também alterna de um programa para outro, executando cada um por dezenas ou centenas de milissegundos. Enquanto, estritamente falando, em qualquer instante de tempo, a CPU está executando só um programa, no curso de 1 segundo, ela pode funcionar para vários programas, dando aos usuários a ilusão de paralelismo. Às vezes, as pessoas falam de pseudoparalelismo querendo referir-se a essa rápida alternância da CPU entre programas, em contraste 5 Sistemas Operacionais – Filippe Jabour – v. 2.0.1 com o paralelismo verdadeiro em hardware dos sistemas multiprocessadores (que têm duas ou mais CPUs compartilhando a mesma memória física). Monitorar múltiplas atividades paralelas é um problema complicado. Assim, com os anos, os projetistas de S.O. desenvolveram um modelo (processos seqüenciais) que torna o paralelismo mais fácil de tratar. [2] 2.1.1 Modelo de processo: Programa = Somatório de Processos Processo = Código executável + Contador de programa + Valores de registradores + Área de dados Estado da CPU Processos podem criar e destruir "N" processos filhos. Processo bloqueado o processo se colocou em estado de espera por algum evento externo (entrada/saída de dados). Diagrama de estados de um processo: 6 Novo Terminado Executando 1 3 2 4 Pronto Bloqueado 5 Figura 4 1. 2. 3. 4. 5. 6. Processo está sendo criado Processo bloqueia para aguardar uma entrada Escalonador dá a CPU a outro processo Escalonador dá a CPU ao processo A entrada aguardada em 2 torna-se disponível Processo concluiu sua execução 2.1.2 Alternância entre processos: Temos na figura 3 a representação de processos que executam programas usuários e processos que executam serviços do S.O.. O kernel se encarrega basicamente de escalonar processos para o uso da CPU, gerenciar interrupções e comunicação interprocessos. Diante deste cenário vamos analisar a alternância de processos na CPU através de um exemplo extraído do S.O. Minix, uma variante simplificada no Unix. Associada a cada dispositivo de E/S (drive de disquete, disco rígido, temporizadores, portas de comunicação) existe uma interrupção (interrupt request – IRQ). O conjunto destas interrupções forma o vetor de interrupção que contém o endereço de memória do procedimento que trata cada interrupção, ou seja, o endereço da rotina de tratamento de cada operação de E/S. Veja a sequência. 1. Processo Pi executando. 2. IRQ de disco. 3. O hardware de interrupção grava o contador de programa (PC) e possivelmente outros dados em uma pilha e salta para o vetor de interrupção. 6 Sistemas Operacionais – Filippe Jabour – v. 2.0.1 4. A execução salta para o endereço de memória apontado pelo vetor de interrupção, para a posição correspondente à IRQ de disco. 5. O procedimento do item 4 inicia sua execução salvando todos os registradores em uma tabela de processos que armazena informações sobre o estado dos processos. São elas: valor do contador de programa (PC), dados sobre alocação de memória, status dos arquivos abertos, etc. Esta rotina é escrita em Assembly e, neste caso, está salvando o estado de Pi. 6. O processo de disco passa de bloqueado para pronto. 7. O agendador é chamado. Geralmente os processos manipuladores de E/S têm prioridade mais alta. 8. O restante da rotina de tratamento de IRQ (em C) executa o acesso a disco (leitura ou escrita). 9. Pi é reescalonado e passa de bloqueado para pronto e logo retomará sua execução. 10. O estado de Pi é recuperado (rotina em Assembly) e Pi reassume a CPU. 2.1.3 Exercícios: 1. Diga o que é e comente as vantagens da utilização de multiprogramação pelos Sistemas Operacionais. 2. Considere os programas descritos abaixo: Prg 1: 1-a) Recebe N números a partir do teclado. 1-b) Efetua cálculos matemáticos complexos com estes números. 1-c) Imprime em papel um relatório extenso como resultado. Prg 2: 2-a) Executa a indexação de um arquivo de dados segundo um campo qualquer. Prg 3: Enquanto existirem palavras 3-a) Busca palavra em um texto que já está na memória RAM 3-b) Imprime em papel a palavra fim-enquanto Segundo o princípio da multiprogramação e considerando que os 3 programas foram iniciados aproximadamente ao mesmo tempo, organize os procedimentos 1-a, 1-b, 1-c, 2-a, 3-a e 3-b em uma ordem coerente de execução na CPU. Considere que procedimentos ou processos podem utilizar a CPU e retornar à CPU caso não tenham sido concluídos. Teça comentários sobre sua solução. 3. Defina Sistema Operacional, em seguida ilustre os conceitos utilizados através de analogias práticas com um Sistema Operacional que você conheça. 4. Um processo está em execução e é retirado da CPU. Nesta etapa o valor do contador de programa é armazenado. Por quê? 5. Defina e explique as funções do vetor de interrupções. 6. Máxima eficiência X Comodidade do usuário. Comente este paralelo levando em conta inclusive fatores históricos da evolução dos Sistemas Operacionais. 7. Defina Chamadas de Sistema (system calls). 8. Relacione as colunas: 1. Processo está utilizando a CPU ( ) Novo 2. Processo concluiu seu processamento ( ) Pronto 3. Processo foi retirado da CPU para que ( ) Bloqueado ( ) Terminado o Sistema Operacional resolva uma interrupção relacionada a outro processo 4. Usuário acaba de comandar a 7 Sistemas Operacionais – Filippe Jabour – v. 2.0.1 execução de um programa 5. Processo requisitou leitura de dados cruciais para a continuidade ( ) Executando do processamento 9. Qual o principal objetivo (vantagem) da multiprogramação? 10. Como funciona a multiprogramação? 11. O que é mais importante nos Sistemas Operacionais modernos, máxima eficiência ou comodidade do usuário? Comente sua resposta. 12. Como age o Sistema Operacional com relação aos recursos de hardware disponíveis? Quais são estes recursos de hardware? 13. Defina processo. 14. Fale sobre o modelo Cliente-Servidor de Sistemas Operacionais. 15. Dentro do contexto desta disciplina, explique o que é proteção. 16. Complete a figura com as 6 setas que representam as transições de estado que pode sofrer um processo. Diga o que está ocorrendo em cada uma destas transições de estado. Terminado Novo Executando Pronto Bloqueado 2.2 Threads ou processos leves: Se dentro de um processo temos múltiplas linhas de controle e múltiplos contadores de programa, mas com um único espaço de endereçamento, podemos ter múltiplos threads compondo um processo. S.O. modernos oferecem suporte a threads. Podemos entender threads como fluxos de execução distintos pertencentes ao mesmo processo. Um exemplo de boa aplicação para threads é o processo servidor de arquivos que trabalha com múltiplas requisições e uma área de armazenamento, no caso de um chache de disco em RAM. Quando um thread bloqueia em espera a uma E/S, o processo continua executando outros threads. Outro exemplo é o tratamento de múltiplas conexões TCP em um navegador Web com uma conexão por imagem. No caso de threads temos uma tabela de estado de threads (contador de programa e registradores). Os threads podem estar nos estados executando, pronto ou bloqueado. O esquema de threads pode ser gerenciado inteiramente no espaço usuário. O próprio processo escalona outro thread quando aquele em execução está prestes a bloquear. Em outros casos o próprio S.O. 8 Sistemas Operacionais – Filippe Jabour – v. 2.0.1 escalona diretamente os threads, alternando mesmo entre threads de processos distintos. Existem vantagens nas duas formas e ambas são utilizadas. Existem questões complexas de integridade de informações quando se usa threads. Por exemplo, dois threads do mesmo processo bloqueados por espera ao teclado: quando chegar a entrada de teclado, qual dos threads deve captura-la? Existem vários outros problemas a serem tratados e a introdução do uso de threads exige uma revisão geral no S.O.. 2.3 Escalonamento de processos: Podemos ter em um mesmo instante mais de um processo no estado Pronto (ver figura 4), ou seja, vários processos em condição de rodar. Nesta situação o S.O. deve decidir qual deles irá assumir a CPU. A parte do S.O. a quem cabe tomar esta decisão é o escalonador. O escalonador executa o algoritmo de escalonamento. Os processos prontos ficam armazenados em uma fila e é sobre esta fila que o escalonador toma a sua decisão. Existem também filas para a utilização de outros dispositivos, por exemplo, uma fila de E/S onde estão os processos que aguardam sua vez de utilizarem recursos de E/S. Vejamos quais as características que devem estar presentes em um bom algoritmo de escalonamento: 1. Justiça: garantir que todos os processos do sistema tenham chances iguais de usar o processador, salvo em situações onde exista prioridade. Neste último caso, a justiça está em oferecer aos processos de uma mesma classe (mesma prioridade) chances iguais de uso da CPU. 2. Eficiência (utilização da CPU): manter o processador ocupado durante o maior tempo possível. 3. Tempo de resposta: minimizar o tempo de resposta para os usuários interativos. 4. Turnaround: minimizar o tempo que os usuários batch devem esperar pela saída. 5. Throughput (vazão) (produtividade): maximizar o número de processos atendidos na unidade de tempo. Podemos observar que existem conflitos a serem tratados. Os itens 3 e 4, por exemplo, são conflitantes. Se não executarmos nenhum job batch, os usuários interativos terão melhor resposta do sistema. De um modo geral, sempre que se oferta recursos adicionais a uma classe de usuários, outra classe está sendo prejudicada. Outro fator importante é o fato dos processos terem comportamentos únicos e imprevisíveis. O escalonador não consegue prever se um processo irá gastar muito tempo com E/S ou se tentará permanecer muito tempo na CPU. Quando coloca um processo para rodar, o escalonador não sabe quanto tempo o processo irá demorar para bloquear e deve se precaver para que ele não fique tempo demais na CPU. Os computadores modernos possuem um relógio interno que gera periodicamente um sinal de interrupção chamado interrupção de tempo. A freqüência de geração desta IRQ de tempo pode ser fixo ( 50 ou 60 Hz) ou pode ser programada pelo S.O. no hardware, caso este permita. A cada IRQ de tempo o S.O. assume a CPU e decide se aquele processo continua executando ou se passa para o estado de Pronto. A estratégia de permitir a suspensão temporária de processos que poderiam continuar executando é chamada de escalonamento preemptivo. Esta técnica é, sem dúvida, a mais adequada para sistemas de uso geral. 2.4 Métodos de escalonamento: A alocação da CPU trata do problema de decidir qual dos processos na fila de prontos vai ser executado pela CPU. A seguir serão discutidos diversos deles. 2.4.1 Primeiro a chegar, primeiro a ser servido (PCPS) (First in first out – FIFO): Como o próprio nome diz, os processos serão atendidos na mesma ordem em que chegam à fila de prontos. Exemplo: Ordem de chegada Processo 1º 2º 3º P1 P2 P3 Duração da fase de uso da CPU (ms) 24 3 3 9 Sistemas Operacionais – Filippe Jabour – v. 2.0.1 Tabela 2 Resultado: P1 assumirá a CPU imediatamente, P2 em 24 ms e P3 em 27 ms, sem considerar o tempo gasto com mudança de contexto. O tempo médio de espera é de ( 0 + 24 + 27 ) / 3 = 17 ms. Se os processos entram na fila na ordem P2, P3 e P1 o resultado para o tempo de espera seria: P2 = 0 , P3 = 3 e P1 = 6 e a média seria de 3ms. Este algoritmo é não-preemptivo. Uma vez assumindo a CPU, um processo só sai quando termina sua execução ou quando bloqueia por uma requisição sua de E/S. Ele não é retirado por término da sua fatia de tempo. Este algoritmo apresenta problemas diante de processos que requerem muito uso da CPU e pouca E/S. Estes processos ficarão muito tempo na CPU fazendo com que os outros permaneçam muito tempo na fila de espera. Nos sistemas de tempo compartilhado (time-sharing), onde se espera uma alocação regular da CPU entre os vários usuários seria desastroso permitir que um processo assumisse a CPU por um longo período de tempo. 2.4.2 Menor primeiro (MP): Nesta abordagem é atribuída a cada processo a duração da sua próxima fase de uso da CPU (D P). Quando fica disponível, a CPU é alocada ao processo com menor duração da próxima fase de uso. Se este valor for igual para dois ou mais processos aplica-se o esquema PCPS. Note que o critério é a duração da próxima fase de uso da CPU e não o tempo total de execução do processo. Vamos ao exemplo: Processo P1 P2 P3 P4 Duração da próxima fase de uso da CPU (ms) DP1 = 6 DP2 = 8 DP3 = 7 DP4 = 3 Tabela 3 Resultado: P4 é atendido imediatamente, P1 em 3 ms, P3 em 9 ms e P2 em 16 ms, sem considerar o tempo gasto com mudança de contexto. O tempo médio de espera é de 7 ms enquanto seria de 10,25 ms se estivéssemos utilizando PCPS. A grande dificuldade deste algoritmo é determinar os valores de DP para cada processo P. Este algoritmo é utilizado freqüentemente na alocação de processos que demandam muito tempo de processamento. Nestes casos uma opção é o próprio usuário determinar o valor de D P. Para ser utilizado na prática, este esquema tem que gerar o valor de D P. O que se faz é buscar uma boa estimativa para este valor. É esperado, para um dado processo P, que o valor de D P seja similar aos valores de fases anteriores de uso da CPU. Portanto, por intermédio do cálculo de aproximações para D P , podemos escolher o processo que, segundo nossa previsão, tenha o menor D P. Geralmente se utiliza a média exponencial de durações medidas em fases anteriores. Seja t n a duração da enésima fase de uso da CPU (informação mais recente), n representa a história passada, e seja n+1 o valor previsto para a duração da n+1-ésima fase de uso da CPU. Então, para entre 0 e 1, temos: n+1 = tn + (1 - ) n Equação 1 O algoritmo MP pode ser tanto preemptivo quanto não-preemptivo. Vamos a outro exemplo: Processo Tempo de chegada P1 P2 P3 P4 0 1 2 3 Tabela 4 Duração da próxima fase de uso da CPU (ms) DP1 = 8 DP2 = 4 DP3 = 9 DP4 = 5 Para alocação MP preemptiva temos o seguinte resultado (diagrama de Gantt): 10 Sistemas Operacionais – Filippe Jabour – v. 2.0.1 P1 0 P2 P4 1 P1 5 P3 10 17 26 Figura 5 O tempo de espera médio para este exemplo é ((10-1)+(1-1)+(17-2)+(5-3)) / 4 = 26 / 4 = 6,5 ms. Para um esquema de alocação não-preemptivo o tempo de espera médio seria de 7,75 ms. 2.4.3 Alocação por prioridade: Uma prioridade é associada a cada processo, sendo a CPU alocada ao processo que tem a maior prioridade. Processos com prioridades iguais são enfileirados e atendidos segundo um critério secundário (PCPS por exemplo). Veja o exemplo abaixo supondo que todos os processos chegaram à fila de prontos em um tempo inicial zero: Processo Duração da fase de uso da CPU (ms) 10 1 2 1 5 Tabela 5 P1 P2 P3 P4 P5 P2 0 1 P5 Prioridade 3 1 3 4 2 P1 P3 6 16 P4 18 19 Figura 6 – Diagrama de Gantt O tempo de espera médio é de 8,2 ms. A alocação por prioridade pode ser tanto preemptiva quanto não-preemptiva. Problemas neste algoritmo estão relacionados com o abandono de processos de baixa prioridade, que podem nunca assumir a CPU devido à existência contínua de processos de alta prioridade. Uma solução pode ser o aumento de prioridade com o envelhecimento do processo. A prioridade dos processos pode ser definida internamente pelo S.O. ou já vir definida por alguma entidade externa. 2.4.4 Alocação circular (AC) (Round Robin): Este algoritmo é um dos mais antigos, sendo simples, justo e muito utilizado. Cada processo tem um intervalo de tempo durante o qual poderá utilizar a CPU (um quantum). Se o seu quantum terminou e ele não concluiu seu processamento, o processo é retirado da CPU e vai para o final da fila de prontos (esquema preemptivo). Se o processamento terminou ou bloqueou antes de esgotado o quantum de tempo a comutação para outro processo é imediata. Neste esquema, tudo o que o escalonador tem que fazer é manter uma lista de processos prontos e gerenciar o rodízio. Veja a figura 7. Próximo processo A G Processo Corrente D F B t=x 11 Sistemas Operacionais – Filippe Jabour – v. 2.0.1 B A G D F t = x + quantum(B) Figura 7 A determinação do tamanho do quantum é importante no algoritmo Round Robin. Toda vez que se alterna entre processos gasta-se tempo com tarefas burocráticas: salvar registradores, mapas de memória, atualização de tabelas e listas. É a chamada troca de contexto. Vamos analisar algumas situações supondo o tempo para troca de contexto valendo 5 ms: Valor do quantum (em ms) 20 500 Overhead (porcentagem do tempo útil do processador gasto com escalonamento de processos) Observações 20% Menos de 1% 100 menos de 5% Overhead alto Overhead baixo. Entretanto, um alto valor para o Quantum pode fazer com que processos esperem muito tempo até poderem usar a CPU. Imagine 10 processos iniciados ao mesmo tempo, o último da fila de prontos terá que esperar quase 5 s para utilizar a CPU pela primeira vez (caso cada um dos outros utilizem 100% do seu quantum), o que é inadmissível. Devemos balancear o valor do quantum de forma a otimizar o overhead com a espera pela CPU por parte dos processos. Este valor costuma ser uma boa solução de compromisso mas sempre cabe uma análise cuidadosa para os diversos casos. Tabela 6 A seguir mais um exemplo (com o quantum valendo 4 ms): Processo P1 P2 P3 P1 0 P2 4 P3 7 Duração da fase de uso da CPU (ms) 24 3 3 Tabela 7 P1 10 P1 14 P1 18 P1 22 P1 26 30 Figura 8 – Diagrama de Gantt O tempo de espera médio é (6+4+7) / 3 = 17 / 3 = 5,66 ms. 2.4.5 Exercícios: 1 – Comente as diferenças de requisitos de escalonamento que existem entre processos oriundos de programas interativos e processos de programas que rodam em segundo plano sem interagir com usuários. 2 – Se os processos P1, P2 e P3 estão disputando a CPU e PE é o processo escalonador, crie uma seqüência qualquer de utilização da CPU que seja coerente. 3 – O que é um esquema preemptivo de alocação de CPU? 4 – Qual o principal problema do algoritmo PCPS? 5 – Preencha a tabela abaixo com os valores previstos para as etapas de uso da CPU. Utilize o método de média exponencial onde a duração da última etapa de uso da CPU tem o mesmo peso que a história passada. A história passada é definida como a média de todas as fases de uso da CPU anteriores. Fases de uso da 4 6 4 6 4 13 13 13 ... 12 Sistemas Operacionais – Filippe Jabour – v. 2.0.1 CPU (ti) Previsões (i) 10 ... 3 Gerenciamento de Memória 3.1 Fundamentos Memória: A CPU busca instruções na memória de acordo com o contador de instruções do programa em execução. Essas instruções podem buscar novos valores em endereços específicos de memória e armazenar novos valores em endereços específicos da memória. 3.2 Troca de Processos Para que um processo seja executado, seu código precisa estar armazenado na memória principal, tipicamente a memória RAM. Enquanto não estiver com o controle da CPU, o código de um processo pode ser transferido temporariamente para uma memória secundária (disco por exemplo). Posteriormente este código é recarregado na memória principal para que o processo continue sua execução. O ideal é que sempre haja na memória principal (memória RAM) um processo pronto para ser executado, quando o escalonador quiser alocar a CPU a um processo. Esta troca recebe o nome de swapping. Vejamos algumas situações possíveis: a) O escalonador decidiu que o processo P que está no início da fila de prontos deve assumir a CPU. O código deste processo está na memória principal. O que ocorre: O Despachante (dispatcher) é chamado, faz a troca de contexto e põe o processo P em execução. b) O escalonador decidiu que o processo P que está no início da fila de prontos deve assumir a CPU. O código deste processo está na memória secundária. Existe espaço livre na memória principal para a alocação (ou carga) do código do processo. O que ocorre: O código do processo P e transferido da memória secundária para a principal (de disco para RAM), o Despachante é chamado, faz a troca de contexto e põe o processo P em execução. c) O escalonador decidiu que o processo P que está no início da fila de prontos deve assumir a CPU. O código deste processo está na memória secundária. Não existe espaço livre na memória principal para a alocação (ou carga) do código do processo. O que ocorre: Algum outro processo é removido da memória principal, o código do processo P e transferido da memória secundária para a principal (de disco para RAM), o Despachante é chamado, faz a troca de contexto e põe o processo P em execução. Este sistema de troca de processos envolve grande atraso gerado pela leitura de processos em disco (memória secundária) e a sua carga em memória RAM (memória principal). Entretanto, é necessário usar este esquema para que o número de processos disputando a CPU em um sistema com multiprogramação não fique limitado pela quantidade de memória RAM existente no sistema, ou seja, no computador. È recomendável que o tamanho do Quantum em um sistema de alocação circular de CPU seja bem maior que o tempo médio de carga de processos do disco para a RAM. Este tempo médio é função do tamanho médio dos processos e da taxa média de acesso ao disco. Com o grande aumento da quantidade de memória RAM disponíveis nos computadores atuais, este modelo tradicional de swapping vem sendo menos utilizado. Isto se dá devido aos grande atraso que acarretam na execução dos processos. Unix: Muitas versões do Unix mantém a troca de processos normalmente desabilitada. Quando muitos processos estão em execução e a utilização de memória ultrapassa um determinado limite, a troca e habilitada temporariamente. Quando a carga do sistema diminui a função é novamente desabilitada. 3.3 Alocação contígua de memória A memória principal é normalmente dividida em duas partes. A primeira é usada para armazenar o sistema operacional e a segunda para processos de usuários. Na alocação contígua, o processo é carregado em memória na forma de um único bloco, ou seja, não é dividido em duas partes. 13 Sistemas Operacionais – Filippe Jabour – v. 2.0.1 3.3.1 Alocação com diversas partições Antes de analisar este esquema precisamos considerar a necessidade do código e dos dados do sistema operacional serem protegidos. Esta proteção deve se dar de maneira a evitar que eles possam (acidentalmente ou maliciosamente) ser mudados por processos de usuários. É necessário também proteger os processos dos usuários uns dos outros. Endereço lógico: São os endereços de memória usados e gerados pelos programas em execução. Endereço físico: São os endereços de memória reais, efetivamente acessados na memória RAM. O mapeamento entre endereços lógicos e físicos é feito pela Unidade de Gerenciamento de Memória (UGM), um dispositivos de hardware. Exemplo: Registrador base = 14000 Endereço gerado pelo programa usuário: 0 Endereço físico gerado pela UGM: 14000 Registrador base = 14000 Endereço gerado pelo programa usuário: 346 Endereço físico gerado pela UGM: 14346 A proteção pode ser feita utilizando-se um registrador base e um registrador limite. O registrador base contém o valor do menor endereço físico. O registrado limite contém o tamanho do intervalo dos endereços lógicos. Desta forma pode-se garantir que o programa usuário não acessará qualquer endereço de memória fora da faixa a ele reservada. Exemplo: Registrador base = 300040 Valor do registrador limite: 120900 Espaço lógico de endereçamento do processo: De 300040 a (300040 + 120900) , ou seja, de 300040 a 420940. Agora que analisamos brevemente a questão relacionada à proteção, vamos estudar a forma mais simples de alocação, aquela em que as partições possuem tamanho fixo. Cada partição pode conter apenas um processo. O grau de multiprogramação é limitado ao número de partições. Quando uma partição está livre, um processo é selecionado na fila de entrada (em disco) e armazenado nesta partição. Quando o processo termina a sua partição é liberada. Este esquema não é mais utilizado. Uma generalização do esquema acima é aquela em que o tamanho da partição não é fixo. O sistema operacional mantém uma tabela com as áreas livres e ocupadas da memória. Quando um processo precisa de memória, um espaço de memória suficiente é procurado. Se for encontrado, o espaço é alocado ao processo. Este método leva à fragmentação da memória. A memória fragmentada pode ter vários espaços de memória que agrupados poderiam comportar um novo processo (Fragmentação Externa). Uma solução é a compactação (faça uma analogia com a desfragmentação de disco). A compactação implica no deslocamento de processos de um ponto para outra da memória e isto só é possível se o método de endereçamento for dinâmico, ou seja, ajustado em tempo de execução. 3.4 Paginação Outra solução para o problema da fragmentação externa é permitir que o espaço de endereçamento lógico do processo seja não contíguo. Uma maneira de implementar esta solução é a utilização de um mecanismo de paginação. Este método é muito utilizado. 3.4.1 Método básico A memória lógica é dividida em partes do mesmo tamanho, chamadas páginas. A memória física é dividida em partes do mesmo tamanho das páginas, chamadas blocos. Para a execução de um processo, suas páginas, armazenadas em memória secundária, são carregadas em quaisquer blocos disponíveis na memória. A memória secundária também é dividida em partes do mesmo tamanho que os blocos de memória. Todo endereço gerado pela CPU é dividido em duas partes: número da página (n) e posição na página (p). O número da página (n) é usado como índice em uma tabela de páginas. A tabela de páginas contém o endereço base de cada página na memória física, ou seja, endereço base do bloco 14 Sistemas Operacionais – Filippe Jabour – v. 2.0.1 correspondente à página. Este endereço base é combinado (somado) com a posição (p) para definir o endereço de memória que é enviado à unidade de memória. O tamanho da página (e conseqüentemente do bloco) é definido pelo hardware. Páginas 0 1 2 3 Tabela de páginas Página 0 1 2 3 Blocos Bloco 1 4 3 7 0 1 2 3 4 5 6 7 Memória Lógica Página armazenada no bloco Página 0 Página 2 Página 1 Página 3 Memória Física Figura 9 Neste esquema não ocorre fragmentação externa. Entretanto, ocorre um outro tipo de fragmentação, a chamada Fragmentação Interna. Esta ocorre quando um processo precisa de uma quantidade de memória que não é igual a uma quantidade inteira de blocos. Desta forma, o último bloco alocado não será totalmente ocupado. Veja o exemplo: Tamanho do bloco = 2048 bytes Processo precisa de 72766 bytes Número de páginas necessárias = 36 , ou seja, 36 x 2048 = 73728 Fragmentação interna com ( 73728 – 72766 ) = 962 bytes não usados. Podemos então fazer a seguinte análise: Tamanho de página menor implica em menor perda de memória por fragmentação interna. Entretanto, tamanho de página menor implica em tabela de páginas maior e maior custo de controle. E ainda, tamanho de página maior implica em otimização no acesso a disco (maior volume de dados a transferir). No ano 2000, o tamanho de páginas era de 2 ou 4 Kbytes. A maioria dos computadores modernos usa tabelas de páginas muito grandes (por exemplo, com um milhão de entradas). Quando um processo fica pronto para ser executado, seu tamanho, em número de páginas, é examinado. A seguir, as páginas são carregadas nos blocos disponíveis. Visão da memória por parte do programa usuário: Espaço único e contíguo. O que ocorre de fato: Programa espalhado pela memória, em meio a outros programas. A tradução de endereços é feita pelo hardware. O mapeamento é escondido do usuário e controlado pelo Sistema Operacional. 3.4.2 Páginas Compartilhadas Outra vantagem do mecanismo de paginação é a possibilidade do compartilhamento de código. Conceito: Código reentrante (ou código puro): Código que não modifica a si próprio, ou seja, ele nunca é modificado durante a execução. Se um programa tiver código reentrante, dois ou mais processos podem executar o mesmo código “simultaneamente”. Á área de dados é distinta para cada processo, mas o código executável (reentrante) é único, e carregado uma única vez na memória. As páginas relativas ao código executável constam da tabela de páginas de todos os processos que as utilizam. Exemplo: Editor de texto com código reentrante de 150 K e área de dados de 50 K. 40 usuários utilizando o editor em um ambiente de tempo compartilhado, seriam necessários 200 K x 40 = 8000 K. Se o código executável for compartilhado, serão consumidos apenas ( 50 K x 40 ) + 150 K = 2150 K. 15 Sistemas Operacionais – Filippe Jabour – v. 2.0.1 3.5 Segmentação Os programas são divididos em segmentos de tamanhos diferentes. A memória é acessada por um endereço lógico representado pela dupla <número do segmento, posição no segmento>. Comumente o programa do usuário é compilado e o compilador constrói automaticamente os segmentos. Exemplo: Pilha Subrotina Segmento 3 Segmento 0 Tabela de símbolos Tabela de segmentos Segmento Limite Base 0 1000 1400 1 400 6300 2 400 4300 3 1100 3200 4 1000 4700 Segmento 4 Função Sqrt 1400 Segmento 1 Programa Principal Segmento 0 2400 Segmento 2 3200 Espaço de endereço lógico Segmento 3 4300 Segmento 2 4700 Segmento 4 5700 6300 6700 Segmento 1 Memória Física Figura 10 A tabela de segmentos contém o endereço físico do início do segmento (Base) e o tamanho do segmento (limite). O segmento 2 tem um tamanho de 400 bytes e começa na posição 4300 da memória. Uma referência ao byte 53 do segmento 2 é transformada no endereço físico 4300 + 53 = 4353. Uma referência ao segmento 3, byte 852, é mapeada em 3200 + 582 = 4052. 16 Sistemas Operacionais – Filippe Jabour – v. 2.0.1 Uma referência ao byte 1222 do segmento 0 provocaria uma interrupção de software, uma vez que esse segmento possui apenas 1000 bytes. 3.5.1 Proteção e compartilhamento Os segmentos podem ter atributos diferentes quanto ao acesso. Em outras palavras, segmentos de código (ou se instruções) terão permissão para “somente leitura” ou “somente execução”, enquanto segmentos de dados poderão receber gravação. Com isto temos proteção das áreas de instruções. O mesmo esquema descrito em 3.4.2 pode ser implementado com segmentação. Neste caso, um editor de textos completo, de tamanho possivelmente grande, composto por vários segmentos, pode ser executado por vários usuários em um ambiente de tempo compartilhado. Neste caso, os segmentos de código executável serão compartilhados por todos os usuários e a área de dados irá gerar segmentos de dados distintos para cada programa usuário. 3.5.2 Fragmentação: A segmentação pode levar à fragmentação externa de memória. 4 Bibliografia [1] Abraham Silberschatz e Peter Baer Galvin. Sistemas Operacionais: Conceitos. Makron Books do Brasil Ltda. Quinta Edição. [2] Abraham Silberschatz, Peter Baer Galvin e greg Gagne. Sistemas Operacionais: Conceitos e Aplicações. Rio de Janeiro. Campus. 2000. [3] Tanenbaum, Andrew S. e Woodhull, Albert S. Sistemas Operacionais: projeto e implementação; trad. Edson Furmankiewics - Porto Alegre: Bookman, 2000. Segunda edição. [4] Tanenbaum, Andrew S. - Sistemas Operacionais Modernos - Rio de Janeiro - LTC - 1992/1999. [5] Machado, Francis B. e Maia, Luiz Paulo - Arquitetura de Sistemas Operacionais – LTC – 2ª edição. 17