Baixe o app para aproveitar ainda mais
Prévia do material em texto
SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 1 18) RESUMO AULA PASSADA Áreas de memória do processo. Uma delas é a área de código e as outras é a área de variáveis que são áreas que guardam as diferentes formas de se usar a variável. As globais, as dinâmicas e as locais (que ficam na Pilha). As variáveis globais não tem áreas distintas. Elas podem ficar em uma única área que é o que ocorre no Unix. Esta única área passa a se chamar Area de dados. Um pedaço dessa Area de dados fica as variáveis locais em outra as variáveis dinâmicas. Inicialmente quando o processo começa a área de variáveis dinâmicas e a área de pilha está vazia. Ao colocar as variáveis dinâmicas na Heap e as variáveis locais na Pilha. Estas áreas são ocupadas. Algoritmos de alocação de memória. Algoritmos simples que existem que são três. O First Fit aloca a primeira área livre encontrada. O Best Fit aloca a área pelo critério melhor que é escolher a área de tamanho mais próximo do tamanho do processo a ser alocado. O outro é o Worst Fit que tem o critério diz que tem que ser usado na área de maior tamanho. Não tem um melhor ao que o outro. Todos podem gerar fragmentação. O que podemos afirmar é que o First Fit é o mais rápido de executar porque ele é mais simples de todos. Também falei que tinha outros algoritmos de alocação é que não seria tratado, pois é para coisas mais sofisticadas cujo propósito é aumentar o desempenho de alocação. Fragmentação que é quando você tem espaçozinho na memória, mas não cabem coisas que você quer alocar nesse espaço de memória. A memória tem bastante livre mais está separada e você não consegue usar. Também falei que a unidade de alocação pode ser o processo inteiro com todas as áreas juntas ou pode ser por cada área o Sistema Operacional aloca separadamente. No caso de alocar separadamente vai rodar o algoritmo de alocação várias vezes para alocar separados. Para resolver o problema da fragmentação existe a compactação e mexer os processos na memória para ajuntar todos os lugares livres num lugar só. Então fica com um espaço livre maior. Só que nem sempre é possível. Porque o que acontece que tem um deslocamento do endereço de memória que cada processo ocupa. E isso só vai ser possível no caso que o processo passe a ocupar durante a execução dele outro endereço na memória. Se o Sistema Operacional utilizar endereço absoluto isso não é possível fazer porque você vai usar vários que utilizam endereços que estavam originalmente, então não vai dá. Agora se usar registrador de base já funciona porque com o registrador de base todos os endereços são a partir da base. Se eu mudo o processo na memória e a base também muda então o que acontece? Continua funcionando. Problema Falta de memória Soluções: Overlay, Swap de Processo, Biblioteca compartilhada, Segmentação sob demanda e Paginação sob demanda. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 2 19) SOLUÇÕES PARA FALTA DE MEMÓRIA 19.1) OVERLAY (1ª SOLUÇÃO) Para que um processo possa ser maior do que a quantidade de memória alocada a ele, podemos usar overlays. A idéia do overlay é manter na memória apenas as instruções e dados que são necessários em determinado momento. Quando outras instruções são necessárias, elas são carregadas no espaço de foi anteriormente ocupado por instruções que não são mais necessárias. Algoritmos especiais de relocacao e ligação são necessários para construir os overlays. Os overlays não precisam de suporte especial do SO. Os programadores devem projetar e programas a estrutura do overlay adequadamente. O overlay utiliza dois conjuntos de rotina, as que são usadas com freqüência, e outras que são usadas com pouca freqüência. As rotinas que são pouco utilizadas compartilham um pedaço da área de código alternadamente. O processo é o responsável pela troca de rotinas. Explicação 1: É a mais simples de todas. A função usa o endereço a partir do endereço de memória e usa-se o endereço a partir da função. O programa é dividido em blocos e cada parte é responsável pela parte a ser carregada na memória. Sendo que esta só carregada na memória a medida que é solicitada. Fala sobre falta de memória que é quando não tem memória suficiente. É quando encheu completamente. Não é questão de a memória existir ela está fragmentada. Não a memória não tem. E ai ao invés de dá um erro para o usuário a ideia é tentar dá uma solução para esse problema sem dá erros. Vimos na aula passada no final da aula que o programa este é um tipo de problema que é importante e foi resolvido ao longo do tempo por que a memória das máquinas foram crescendo. Mas, isto não é uma coisa que resolve tudo por que a medida que as memórias foram aumentando de tamanho as máquina passaram também a existir programas que antes não existiam por que não tinha memória o suficiente como já falei e acaba consumindo esta memória que antes não existiam. É uma coisa que claro que diminui ao longo do tempo por que as coisas comuns que eram utilizadas foram resolvidas com a memória que existia. Vamos as soluções tem várias soluções para este problema. Vou falar das soluções que ocorreram ao longo do tempo, mas fora da ordem cronológica. Que é um caso bastante estranho hoje em dia. Conforme mostra a Figura 1. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 3 Digamos que tenho uma memória de 64 KB. Digamos que destes 64 KB eu tenha um Sistema Operacional que ocupe 10 KB. Por consequência a memória útil que posso utilizar com o processo é de 54 KB. Digamos que um processo que quer executar na máquina tivesse 5 KB para área de Pilha 5 KB para área de Dados e finalmente 80 KB para área de Código. Bom com esta composição do suposto processo na memória temos 90 KB. Bom a máquina tem 54 KB de memória livre. Logo, o processo não é capaz de ser colocado ai um processo de 90 KB. Como se fazia? O que era feito então nessa época que as máquina só tinham 64 KB? (Estou falando de 25 anos atrás) Só podia rodar um processo que tivesse uma área de Código de 80 KB e com um tamanho total de 90 KB só que a memória livre é só de 54 KB. O que se fazia é o seguinte o processo não cabia na memória óbvio. Então qual é a ideia da solução? É não colocar ele todo na memória já que ele não cabe todo. Mas, o que fica de fora o que não vai para memória. Nessa solução o que acontece é que o código é aquela parte do processo que não fica todo na memória. Então o que é feito? É feito uma divisão da parte da área de código do processo em partes que são menores que a área de código. Digamos que no exemplo a área de código foi dividida em 20 KB. Como eu tenho 10 KB para as variáveis de 54 KB tiro 10 KB fica 44 KB. Então só vai caber na memória os processos pares. Então dois processos irão para memória e sobra um pouquinho de área livre (4 KB). Conforme mostra a Figura 2. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 4 Então coube na memória? Coube, mas tem algumas coisas que estão fora da memória. O que são o C e D de código? Eu não sei. E qual é o problema destas duas partes não estarem na memória? O problema é que não vai ser possível executar uma subrotina que esteja utilizando estas partes. Por que para CPU poder executar uma rotina o código dela tem que estar na memória senão ela não executa. É a forma que a CPU te dá algum dado para fazer algum processamento a partir desse dado é que este dado tem que está na memória. A CPU não consegue usar diretamente os dados que estão em disco. Digamos que eu tenha uma subrotina na parte C. Conforme mostra a Figura 3. A subrotina X na parte C se no meio do meu código eu estiver chamando a rotina X não vai conseguir executar. Digamos que na parte A tem uma chamada a subrotina X.Conforme mostra a Figura 4. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 5 Não vou poder executar este código simplesmente. Por que o código do X não está na memória. Para poder executar o X tem que colocar o código X na memória. O código de X está na parte C. Conforme mostra a Figura 3. Como isso é feito? Se coloca a parte C na memória. Então a parte B sai e a parte C entra conforme mostra a Figura 3. Entra como? Leitura do disco. Você tem lá um arquivo “P.exe” estão lá as 4 partes. Então o que é feito é lê o pedaço do C e colocar na memória. Depois de fazer isto ai pode chamar a subrotina X apresentada no código1: Procedure X (); Begin ... Y(); ... End; Bom só que nesta subrotina X pode chamar o Y que pode estar em uma parte que não está na memória. Não basta simplesmente chamar o Y. Tem que chamar o endereço do código da memória de Y. Então antes de chamar o Y tem que primeiro carregar a página que contém o código de Y na memória. E ai depois de isto ser feito ai pode-se chamar a rotina Y. Então essa é a ideia da solução. O grande complicador é que quem implementa a lógica para carregar o código não é o Sistema Operacional. Quem é responsável, nesta época, é o próprio programador que programou o código tinha que se preocupar em carregar uma parte do dado que o código que ele chama não estava na memória ainda naquele momento. Ele tinha que carregar aquela parte. Então o que acontecia não teríamos apenas um código com chamada a subrotina teríamos um código mais sofisticado. Exemplo: If parte_carregada < > „C‟ Then carregada_parte(„C‟); X(); O que tem que ser feito é antes de chamar a subrotina carregar a parte que se tem para carregar. Então a questão é a seguintes esta subrotina carrega_parte quem tinha que escrever ela era o próprio programador com um código mais sofisticado para isto. Esta subrotina que toda hora é chamada por que tem que pegar uma parte nova tem que está na memória. Então esse código carrega_parte tem que está na parte do código que nunca sai da memória, porque precisa chamar essa subrotina. Então das duas partes de memória uma delas é sempre fixa. Por que nela que tem o código de rotinas que você vai chamar para carregar. Então no A conforme mostra a Figura 5 encontra-se o código do carrega_parte. Esta parte nunca podia sair da memória A outra parte é que ficava variando. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 6 O que acontecia? O programa era compilado para carregar duas partes só a área A e B. Quando se chamava uma subrotina o código programado carrega_parte era chamado para carregar outra parte no lugar de B. Que era a área de memória variável. Estou simplificando um pouco por que tem algumas questões delicadas por que é mais fácil da maneira que você vai chamar, mas é mais complicado quando você vai voltar a subrotina. Quer dizer isto tem que ser feito também. X chama o Y conforme mostra o código 2: Procedure X(); Begin ... If parte_carrega < > „B‟ Then carrega_parte(„D‟); Y(); ... End; Procedure Y(); Begin ... Volta_parte_anterior(); End; Quando Y acaba de executar volta o X. Só que o X está na parte C, conforme mostra a Figura 6. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 7 Então tem que ter um mecanismo programado antes de finalizar a rotina do Y para voltar a parte anterior para memória. Claro que não é tão fácil assim, pois nem sempre volta a parte anterior. Se tiver uma subrotina Z e o X chama Z e o Z estiver junto na parte C. Não é só voltar para parte anterior. Além de voltar para parte anterior tem que ser experto para saber quando deve voltar e quando não tem. Se X chama o Z e o Z está na parte C. Então não precisa voltar a parte anterior quando acabar o Z. Resumo é uma coisa complicada para programar por que não basta uma lógica de sistema normal feitos hoje em dia tem que se preocupar com questões de memória que hoje não está se preocupando. Era ruim isto? Claro que era ruim, mas era isso ou nada. Se você tivesse um programa mais complexo. Você não conseguia que esse programa era carregado na memória que tinha disponível naquela época. Então você era obrigado como programador para fazer o programa funcionar quebra em partes e carregar na memória a parte que estava sendo usada naquele momento. Então você como programador tinha muito mais trabalho, mas era o que se podia fazer. Se não fizesse isto você não conseguia executar uma coisa mais sofisticada com um código maior. Uma coisa mais concreta nessa naquela época existia. Estou falando de 25 anos atrás. Você tinha máquinas com este tamanho. Sistema Operacional de 10 KB. Uma coisa que hoje é tão obvia, mas não cabe nesse espaço que tinha sobrando era um editor de texto. Um editor de texto um pouco mais sofisticado capaz de imprimir em negrito e itálico. Para ele funcionar era preciso de um código que era maior que 54 KB que não cabia na memória daquela época. Então quem programava um editor de texto um pouco mais sofisticado precisa utilizar o overlay. Senão não iria caber. Então coisas que hoje são triviais nessa época precisa de overlay. Como por exemplo, um editor de texto um pouco mais sofisticado. Editor de texto que não tinha formatação nenhuma de letras cabia na memória disponível na máquina. Mas, editor de texto mais sofisticados que tivesse fontes distintas, tipo de fontes – negrito essas coisas. Precisa de mais código do que cabia na memória naquela época. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 8 E o Sistema Operacional. Ele ajudava nesse trabalho do overlay? Muito pouco. O suporte que o SO dava era para ler um determinado arquivo na memória. É o suporte mais básico que o SO tem que dá mesmo. Mais a frente na matéria vamos falar sobre arquivos. Agente vai vê que uma chamada SO que tem que existir é uma chamada que seja capaz de ler um dado do arquivo e por na memória. Então isto tem que existir no SO. Qualquer arquivo de dados precisa disto. Então essa chamada de leitura de arquivo. Ela era usada pelo programador para carregar um pedaço do arquivo executável para memória. O suporte que o SO dava era só este. Carregar um pedaço de um arquivo para memória. Isto é uma coisa trivial qualquer SO tem que dá mesmo. Além disso, o SO não fazia mais nada todo o resto de troca - troca era feito pelo próprio programador que estava programando o sistema. Bom, então, esse é o overlay é uma solução antiga que era usada. E ela usa uma coisa que era muito comum que é o disco. A maior parte da solução hoje que procura tratar a falta de memória elas de alguma forma usam o disco por não ter memória suficiente. Qual é a ideia básica? É manter em disco. Guardar em disco parte do conteúdo que não cabe na memória. Essa é a ideia. Nesse caso o conteúdo que é mantido na memória é parte do código. O código todo não cabe na memória. Então só uma parte dele está é outra parte fica no disco. Explicação 2: Temos um processo muito grande que não cabe na memória então o programa é dividido em quatro áreas (A, B, C, D) e cada área com 20Kbytes. Ao invés de ter essas quatro áreas carregadas na memória cada módulo irá se preocupar em carregar na memória o módulo chamado que estará em disco. Então se o módulo A precisa de uma rotina que está no módulo C então o módulo A se preocupa em carregar antes o módulo C para a memória. Então esse programa ao invés de ocupar 80 Kb na memória ele ocupará apenas 40Kb. Assim todo o controle de qual o módulo deve está na memória em determinado instante fica sob responsabilidade do programa e não mais do sistema operacional. Esta solução tem pouco suporte do sistema operacional. O único suporte é o de carregar o módulo. Não precisa de nenhumsuporte especial de hardware, exigindo mais do programa. O primeiro sistema operacional que existia para micro era o CPM, que não tinha o suporte para falta de memória. Então nesta época usava-se esta solução (overlay) para o problema de falta de memória. Esta solução exige muito dos programas. Programa A B C D Memória A C 20Kb 20kb 20kb 20kb A B C D Disco SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 9 Explicação 3: Carga na memória somente dos módulos do processo que estão sendo usados no momento. Ex.: O processo 1 é dividido em 4 módulos, cada um com 20 kb. Módulo A Módulo B Módulo C Módulo D Digamos que o 1o módulo a ser utilizado seja o módulo A. A memória estaria assim: SO Módu lo A Se o módulo A necessitar do módulo C, o módulo A solicita ao SO que o módulo C seja carregado na memória. A memória ficaria assim: SO Módulo C Módulo A Se o módulo A não precisar mais do módulo C, mas sim do B, o módulo A solicita ao SO que o módulo B seja carregado, sobrescrevendo a área de memória onde o módulo C se encontrava e que não era mais usado. Com isso, reduz-se o espaço a ser utilizado por um processo. 20 kb 20 kb 20 kb 20 kb Se todo o processo fosse colocado na memória de uma só vez, ocuparia 80 kb. O overlay só permite que fique na memória os módulos necessários em determinado momento. 0 20 kb 500 kb 1000 kb 0 20 kb 40 kb 1000 kb SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 10 Esta técnica usa pouco o SO ( na verdade ele só faz a carga dos módulos quando necessário) e não necessita de suporte especial de HW. 19.2) ECONOMIZAR MEMÓRIA (2ª SOLUÇÃO) Uma outra abordagem utilizada no tratamento da falta de memória que não usa o disco é você evitar que a falta de memória ocorra é gastando menos memória. Quando você economiza a memória você gasta menos. A memória tende a não encher. Esta é uma ideia razoável. Só que não é uma coisa fácil de se ter um mecanismo que em geral gaste menos memória em todos os casos. Cada programador que programa o sistema é capaz de programar um código que gaste menos memória. Uma coisa genérica que o SO pode fazer para gastar menos memória é uma coisa que não vai encontrar por ai. São poucos casos que acontece. Então um deles será mostrado. Mas antes de amostrar este caso de como se economiza a memória vou amostrar como é a geração de um arquivo executável. GERAÇÃO DE UM ARQUIVO EXECUTÁVEL O p.exe é um arquivo executável. Este arquivo é originário de um arquivo fonte e um arquivo compilado. Digamos que o arquivo fonte esteja programado em C, contém código C. Então eu tenho um arquivo fonte em C que contém código C que vai ser compilado. Só que é muito comum que um arquivo executável seja criado a partir de arquivos fonte em estilo de bytes. É interessante você ter programas executáveis associados a vários arquivos fontes. Por duas grandes razões: primeiro por que quando você mexe em um arquivo só não precisa compilar todos os outros. Esta é uma das vantagens de se ter arquivos separados. A outra vantagem de se ter arquivos separados é que se pode programar em grupos. Embora é possível por uma ferramenta você ter várias pessoas envolvidas com o mesmo arquivo fonte isto é mais complicado. É muito mais simples você ter programação paralelo do mesmo programa pessoas distintas que estão usando arquivos fontes diferentes. Então é interessante gerar o código fonte em arquivos separados pela facilidade de programação em paralelo. Bom, então, tem vários arquivos fontes. Existem uma coisa que é a geração do arquivo compilado. E para cada arquivo fonte tem a geração de um arquivo compilado. O resultado do arquivo executável é equivalente ao código do arquivo fonte. No caso do C o arquivo compilado tem a extensão obj. Então a geração do arquivo compilado a partir do código fonte é uma coisa que é a compilação propriamente dita. A compilação que dizer estou gerando o código em linguagem de máquina a partir do código fonte. Mas, a compilação propriamente dita não é igual ao arquivo executável. Então temos outra etapa que é linkar esses arquivos compilados no arquivo executável. Que será utilizado pelo usuário SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 11 depois. Então essa tarefa de juntar é uma outra fase para gerar o arquivo executável. Que é responsável por juntar os arquivos compilados. Tudo isto podemos vê na Figura 7 a seguir: Essa segunda fase tem um nome também é chamada de link-edição. O que essa fase faz? Ela cria um link obviamente, ela concatena, mas ela não faz só isso. Tem também a questão de tratar as chamadas as subrotinas que estão em arquivos distintos. Então digamos que eu tenha no arquivo A uma chamada a rotina X. E a rotina X está no código fonte do arquivo B. Conforme mostra a Figura 9. Então quando o compilador está gerando o arquivo compilado. Como é que faz para gerar a chamada a rotina X? Chamar a subrotina em linguagem de máquina é CALL. Então é gerado em linguagem de máquina um CALL, mas é um CALL que tem que ter como operando um endereço. Só que eu não sei qual é o endereço porque estou chamando uma subrotina que está no código fonte que eu não gerei ainda. Então que valor eu coloco aqui? Eu não sei. Então os compiladores geram um CALL com um buraco vazio porque não sabe o endereço. Ele não é preenchido neste momento. Ele não sabe em que endereço vai ter X quando estiver na memória executando o processo. Depois que compila. Compilo A gera CALL ___ , compilo B ai gera o código X. Conforme mostra a Figura 8. Eu não sei onde foi carregado o X ainda eu só vou saber de fato definir aonde a subrotina esta na memória depois que ocorreu a link-edição. Eu estou juntando todos os arquivos compilados. Então eu vou saber onde está o X na memória. Sabendo onde vai ser carregado na memória o programa no endereço 0 neste exemplo. Então eu vou conseguir saber onde está o X na memória. Então nessa hora é possível preencher o endereço CALL e ai vai ter um valor lá CALL 5000. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 12 Então X fica no endereço 5000 e eu vou chamar o X e gerar o código de X. Claro que isso é feito supondo que o programa é carregado no endereço zero. Então a link-edição não é apenas juntar os arquivos compilados ela também tem o trabalho de carregar os endereços. Isso se chama linkar. Coloca o endereço das componentes de um no outro. Quando as instruções são chamadas. Isto equivale não apenas a subrotina funcionar, mas carregar as variáveis globais. A variável global que é gerada no código fonte B eu estou usando no A. Onde vai ficar a variável global na memória? Eu não sei. Só vou saber quando compilo. Depois no “.exe” eu sei onde ficam as variáveis globais na memória. Consigo definir os endereços onde vão ficar as variáveis globais. Fechar os endereços é uma coisa que só é feita na link-edição. A compilação sempre vai gerar instruções com uma parte do endereço não preenchido. Por que só pode colocar o endereço depois que link-edito. Então a link-edição é importante para poder preencher os pedaços com os endereços corretos. Num programa que você programa e você chama rotinas que você mesmo programou, por exemplo, chamei o X, mas eu também chamo rotinas que eu não trabalhei. Rotinas que estão prontas para eu chamar. Algumas rotinas são rotinas do sistema operacional. Mas, o SO tem as chamadas ao SO que eu posso chamar. Se eu quero ler um arquivo. Isto é uma chamada que eu faço. Uma rotina que eu chamo cujo código está dentro do SO. Se eu quero criar um processo novo o Main é uma rotina que estáprogramada dentro do SO que eu chamo. Tem rotinas por outro lado que eu chamo não foi eu que programei, mas não fazem parte da rotina do sistema operacional. São rotinas que entram serviços de mais alto nível que são mais sofisticadas do que o SO faz. O SO tem rotinas mais simples ligadas ao hardware. Ligadas à memória diretamente. Coisas mais sofisticadas, por exemplo, criar uma janela até tem chamada do SO para isto, mas geralmente elas são de baixo nível muito trabalhoso. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 13 Normalmente, de algo nível tem rotinas que você pode chamar que ajudam a sua vida como programador. E fica mais fácil de você programar utilizando muitas coisas que já estão prontas, mas que não são do SO. São coisas mais sofisticadas que o SO entrega. Vamos ao um caso bem simples para exemplificar isto que é o caso de imprimir o texto em uma tela. Tem uma chamada ao SO para imprimir na tela o texto. Só que está chamada é composta uma string. Tem que passar a string prontinha e você imprimi na tela. Só que ao imprimir alguma coisa em algum momento no programa você não está com a string pronta. As vezes você tem que ler alguma coisa de uma variável. Por exemplo, que imprimir na tela: Salário: R$ 5.000,00 Nome: João da Silva Então você quer imprimir estes dados na tela. Quando eu chamar a rotina SO eu já tenho que ter amarrado esta rotina toda. Só que parte dela é variável. O nome é o salário são variáveis. Então cada linguagem trata isso em uma rotina que estão prontas para executar. Exemplo, o C tem uma rotina pronta chama printf que imprime coisas na tela. É uma coisa simples. Exemplo: Printf(“Nome: ” %s\n”, &nome); Então o printf que é um rotina da linguagem de programação. Gera uma string só e depois chama o SO. E enfim está na tela o que você quer. A chamada ao SO é muito simples. Ela só recebe a string pronta. Se você quer fazer uma coisa mais sofisticadas que envolve gráfico, alinhamento isto vai ser feito pela linguagem. Então a linguagem vão ter sub-rotinas que vão fazer isto para você. Então o C tem printf. O Pascal tem o writeln. Estas rotinas tem que ter um código. Ele tem que estar em algum lugar para poder ser compilado. Mas, não foi você que programou. Então onde está o código? Está em um coisa que é a biblioteca. A linguagem tem um conjunto de rotinas que o fabricante já entrega a rotina já compilada. No arquivo chamado biblioteca. Conforme mostra a Figura 9. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 14 No meu código fonte que eu chamo o printf. O que acontece? Nesse momento meu código de linguagem de máquina tem uma chamada ao código printf. O compilador gera um CALL com um buraco. E durante a link-edição ai o CALL tem seu endereço preenchido. Mas onde vai estar? Para poder chamar esse printf tem que saber onde vai estar dentro do meu executável o código printf. Então tem que levar para o executável a biblioteca. Dentro da biblioteca está o código do printf. Uma vez que está tudo em um arquivo só e eu sei onde está na memória. Então eu posso preencher as lacunas. Colocar o valor do endereço para pegar o printf. A diferença do que foi visto antes é que o printf já está compilado e a rotina que você programou está chamando ele gerando um CALL. E durante a execução o link-editor preenche o local com o valor de onde está o printf depois do programa executável ser colocado na memória. Novamente lembrando, supondo que o programa tenha sido carregado no endereço zero da memória. Então é isto é assim que e o trabalho de geração de um arquivo executável. Esse mecanismo gera uma ineficiência de código duplicados na memória. Eu tenho um processo. O processo tem as suas áreas. Dentro da área de código do processo o que é que tem? Basicamente área de código. Na área de código eu tenho os arquivos que vieram da compilação. Conforme mostra a Figura 10. A área de código do processo 1 (P1) foi criada a partir do arquivo executável “P.exe”. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 15 Digamos que tem outro processo na memória também, P2, conforme mostra a Figura 10. Que também tem código fonte C. Então eu tenho na memoria um outro processo que tem as suas variáveis locais na Pilha, variáveis globais na área de dados e tem seu código. Estou falando de outro programa que tem outros arquivos componentes. Temos dois programas feitos na mesma linguagem, portanto têm a mesma biblioteca. O código da biblioteca vai está duplicado na memória. Isto provoca um desperdício de memória. Estou gastando memória com o mesmo objeto. Vai ficar pior se estiver mais programas na memória utilizando a mesma biblioteca. Isto é resolvido através de um mecanismo chamado biblioteca compartilhada. Conforme mostra a Figura 11. Nesse mecanismo a biblioteca não é incorporada ao arquivo executável na hora que estou link-editando. Então como funciona? Na biblioteca compartilhada o arquivo executável “P.exe” ele não recebe o conteúdo da biblioteca. A biblioteca fica fora, isolada. Isto é uma consequência do que eu mostrei antes. O A.c chama a rotina X. A rotina X está no arquivo B.c. Então na hora que eu compilo a chamada do X eu gero um CALL com uma lacuna. O X vai está no arquivo B.obj e ai n hora que estou gerando o executável na execução eu sei onde vai ficar o código do X e ai preencho o valor do lugar onde sei que está o X. Mas, no caso da chamada ao printf que é o mesmo problema. Terei um CALL com uma lacuna. Como o printf está na biblioteca e não foi executado no arquivo executável não tenho a menor ideia de onde ele vai está na memória ainda. Aonde vai ficar o printf? Sei lá. Depende na hora da execução. Só vou saber quando ele for para a memória neste caso a link-edição vai manter algumas chamadas com lacunas. Então a chamada do printf continua com o endereço não preenchido por que eu não sei onde vai estar o printf na memória. Eu só vou saber na hora que usuário executar o programa. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 16 A área de código do processo 1, por exemplo, não terá mais a biblioteca. Conforme mostra a Figura 11. Só que eu preciso que dentro do C.obje tenha uma chamada ao printf. Então eu preciso do endereço da memória do printf. Nessa hora que tudo está na memória e vou tratar da execução do processo. O SO sabe onde vai estar cada coisa na memória. O SO tem como saber onde está o endereço do printf. Então o que ele faz então no C.obj ele preenche a lacuna da chamada do printf. 19.3) BIBLIOTECA COMPARTILHADA (3ª SOLUÇÃO) Neste mecanismo uma parte comum a vários processos é carregada na memória uma única vez e é acessado por estes vários processos. A biblioteca compartilhada é comum aos processos. Dessa forma eu não vou usar código duplicado. Isto faz que eu tenha menos falta de memória. A biblioteca compartilhada fica na memória enquanto tiver um processo utilizando ela. Se nenhum processo acabar ela não sai da memória, mas se os dois acabarem ela sai da memória. E o SO que coloca e tira a biblioteca compartilhada da memória. O Windows chama a biblioteca compartilhada de Dynamic Link Library (DLL). Por que tem esse nome? Por que um pedaço daquilo que é feito na linkagem que é preencher os espaços. No caso da biblioteca compartilhada ele não é feito, ou seja, o CALL está incompleto. Então endereço do printf será preenchido no CALL quando for carregado na memória. Ai o SO vai no CALL e coloca o endereço. A tarefa de colocar o endereço é tarefa da linkagem, mas neste caso parte da linkagem é adiada para o momento de carga na memória. A linkagem tradicional ela é feita todo no primeiro passo da link-edição. Então todos os endereços são resolvidos não terá mais lacuna nenhuma. SISTEMA OPERACIONALII – PARTE 3 Elaborado por Luciana SA Amancio Página 17 Na biblioteca compartilhada o arquivo executável tem lacuna de endereços ainda. A link-edição não resolveu todos os problemas de endereços. Não deixou tudo fechadinho. Então existem lacunas a serem preenchidas que são preenchidas pelo SO no momento da carga. O SO carrega o processo sabe onde vai ter que executar a rotina e preenche o endereço exato da rotina. Isto é uma tarefa típica de linkagem só que é feita mais tarde na biblioteca compartilhada dai o nome linkagem dinâmica porque é feita dinamicamente bem depois da geração do arquivo executável. Dai o nome de biblioteca de linkagem dinâmica porque a linkagem é feita no momento da carga do arquivo na memória. Bem depois da geração do arquivo executável. No caso do Windows até tem a possibilidade de você mandar durante a execução do processo tem uma chamada ao SO para carregar uma variável nova naquele momento da execução. É uma coisa que não tem no Linux. Então no caso normal é a link-edição gerar o executável com lacuna mais a informação que tem nas bibliotecas que o arquivo vai precisar durante a execução. Então essa informação de controle o SO vai executar essa informação e na hora de colocar na memória e carrega nos processos. O link-editor vai dizer o que esta usando da biblioteca. Isso chamado DLL é uma linguagem sofisticada que envolve você alterar para link-edição funcionar. Agora ela não resolve tudo fica coisa incompleta, um pedaço de endereço não resolvido. É um pouco mais sofisticada e complicada, mas tem benefícios de gasta menos memória, pois você economiza o espaço gasto com a biblioteca. Nesse caso tem endereços que não foram resolvidos ainda. Não resolve logo só resolve depois. Quando? Quando for carregado na memória. O SO vai saber onde está o “.exe” e preenche o endereço. Ela não resolve o problema ela evita que o problema ocorra, pois diminui a memória necessária aos processos e conseqüentemente evita que a falta de memória ocorra. Esta solução é chamada de biblioteca compartilhada. Exemplo: Temos o arquivo fonte 1 ele passa pela fase de compilação e gera o arquivo objeto 1 e o mesmo acontece com o arquivo fonte 2 que também passa pela fase compilação e gera o arquivo objeto 2. Na fase da linkedição esses dois arquivos (arquivo objeto 1 e arquivo objeto 2) são unidos para gerar o arquivo executável. E nesta fase da linkedição o arquivo objeto da biblioteca padrão (rotinas disponibilizadas pela linguagem (C, Pascal)) também é adicionado, e um pedaço deste arquivo fica adicionado no executável também. Mas, no mecanismo de biblioteca compartilhada o arquivo executável não incorpora o código da biblioteca padrão, não replicando este código no executável. Um exemplo disso, tem-se no Windows, que são as DLLs(Dynamic Link Library). SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 18 O sistema operacional carrega uma única vez esta biblioteca padrão na memória, disponibilizando-a para que os processos possam encontrar a rotina solicitada.. Por exemplo, quando o primeiro processo que usa biblioteca padrão é carregado, o sistema operacional carrega o processo e a biblioteca padrão, neste nosso exemplo, P1 está sendo iniciado e precisa da biblioteca padrão então o sistema operacional carrega na memória P1 e a biblioteca padrão e quando um segundo processo, P2, for carregado na memória e solicitar uma rotina da biblioteca padrão esta já estará carregada na memória e será compartilhada pelos processos P1 e P2. Com isso, o código da biblioteca padrão não é replicado em todos os processos que usam a biblioteca padrão. Este mecanismo é o que chamamos de biblioteca compartilhada, é um mecanismo que usa um link dinâmico e não mais estático como antigamente que acoplava uma parte da biblioteca padrão no executável. Memória SO P2 BP P1 Arquivo Fonte 1 Arquivo Fonte 2 Compilação Compilação Arquivo Objeto 1 Arquivo Objeto 2 LinkEdição Arquivo Executável Arquivo Biblioteca Padrão Pedaço da Biblioteca Padrão SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 19 Hoje em dia este mecanismo é muito comum. O problema da biblioteca compartilhada é a robustez. Isto porque, tem que ter carregado na memória todas as bibliotecas compartilhadas que o processo usa. Na linkagem da biblioteca padrão estática não ocorria a incorporação completa da biblioteca padrão, o compilador reconhecia o que era utilizado de rotina da biblioteca padrão e incorporava apenas essas rotinas utilizadas. Então, esse mecanismo não chegava a ser completamente burro. Mecanismo que evita a falta de memória Um programa é constituído por um arquivo-fonte e é compilado para gerar um arquivo .EXE. Digamos que exista um programa de 500.000 linhas. Se uma linha de código for alterada, o programa deverá ser compilado de novo. O linkeditor resolve esse problema de recompilação. Ele junta os arquivos .OBJ e acerta a chamada das rotinas dos arquivos objetos diferentes (acerto dos endereços). Nesse caso, só o arquivo fonte que foi alterado deverá ser recompilado e deverá ser linkeditado com os demais arquivos objetos para gerar um novo arquivo .EXE. Em programas, geralmente são chamadas rotinas que não foram programadas pelo programador (ex.: PRINTF, SCANF etc.). São rotinas que fazem parte de bibliotecas-padrão. As bibliotecas- padrão já são arquivos .OBJ. Arquivo Fonte Arquivo Executáve l Compilado r Arquivo Fonte Arquivo Objeto Compilad or Linkedit or Arquivo Fonte Arquivo Objeto Compilad or Arquivo Fonte Arquivo Objeto Compilad or Arquivo Executável Arquivo Fonte Arquivo Objeto Compilado r Linkedito r Arquivo Fonte Arquivo Objeto Compilado r Arquivo Fonte Arquivo Objeto Compilado r Arquivo Executáve l Arquivo Objeto da Biblioteca- Padrão SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 20 O linkeditor “puxa” o arquivo-objeto da biblioteca-padrão e linkedita junto com os arquivos- objeto do programa para gerar o arquivo .EXE mas as rotinas da biblioteca-padrão ficam separadas do arquivo executável. Todo programa .EXE tem as rotinas da biblioteca-padrão. Logo, todo processo também terá rotinas que fazem parte do código do arquivo-objeto da biblioteca-padrão. Logo, se há vários programas C na memória, haveria várias cópias da biblioteca-padrão na memória. Para economizar espaço, usa-se a biblioteca compartilhada que são rotinas que são comuns a vários processos, sendo colocadas só uma vez na memória. Proce sso 1 Bibli oteca Padrão Proce sso 2 A linkagem do arquivo-objeto da biblioteca-padrão só é feita quando o processo vai ser carregado na memória. O linkeditor só pega do arquivo-objeto da biblioteca-padrão as rotinas que os processos vão utilizar quando forem executados. 19.4) SWAP DE PROCESSOS (4ª SOLUÇÃO) Uma outra maneira de lidar com a falta de memória é o Swap de Processos. Ele também é um recurso que utiliza o disco mais diferente do Overlay o SO faz tudo. NoOverlay é o programador que programa o sistema que implementa a lógica. Neste mecanismo pega o processo que está no estado de bloqueado a mais tempo para fazer um swap para disco. Um processo pode ser removido temporariamente da memória para um armazenamento auxiliar e, em seguida, retornado a memória para continuar sua execução. Normalmente, um processo que é descarregado será carregadop ara o mesmo espaço de endereço de memória que ocupava anteriormente. Essa restrição é determinadapelo método de resolução de endereço. Se a resolução for feita no momento de carga ou montagem, o processo não poderá ser movido para posições diferentes. Se a resolução em tempo de execução estiver sendo executada, é possível passar um processo para um espaço de memória diferente, porque os endereços físicos são calculado em tempo de execução. A troca requer um disco. O sistema mantem uma fila de processos prontos consistindo em todos os processos cujas imagens de memória estejam no disco ou na memória principal e prontas para executar. Sempre que o escalonador de CPU executar um processo, ele chama o dispatcher. Este verifica se o próximo processo na fila está na memória. Se o processo não estiver, e não houver região de memória livre, o dispatcher descarrega um processo que está na memória principal e As bibliotecas compartilhadas são os arquivos .DLL do Windows (Dynamic Link Library). SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 21 carrega o processo desejado em seu lugar. Em seguida, ele carrega os registradores da forma usual e transfere o controle para o processo selecionado. Ao tentar carregar na memória um processo maior que a área livre disponível, o SO pega o processo, dentre os carregados na memória que estivesse bloqueado há mais tempo, o colocava em disco, e nesse espaço de memória entraria o novo processo. Esse processo é gerenciado pelo SO. Ao sair do estado de bloqueado, o processo que saiu da memória e estava em disco, esta sendo monitorado pelo SO, mesmo estando em disco, e o SO sabe que ele está pronto para executar. Assim, o SO repete o processo de swap para que um outro processo vá para disco, dando lugar a um novo processo. A troca de processos é o SO que vai está fazendo isso não é o programador. O que acontece então? Nesse caso aqui. Conforme mostra a Figura 12. A memória está com o SO e com outros processos. Então a memória encheu. E o usuário quis executar o processo 5. O que ocorre é o seguinte: O SO escolhe um dos processos que estão na memória para ser salvo em disco. Digamos que seja o processo 2. Então o processo 2 vai para o disco. Ao fazer isto o SO libera a memória que o processo 2 estava. Conforme mostra a Figura 13. Então essa memória livre ela pode ser suficiente para armazenar o processo 5 que é o programa que o usuário começou a executar agora e não tinha memória para ele. Então nessa área livre vai ser colocada nela o código e os dados de um processo. Não necessariamente o processo 5 vai ocupar o mesmo tamanho do processo 2 na memória. Digamos que o processo 5 ocupe menos espaço conforme mostra a Figura 14. Podia ser o contrario o processo 5 ser maior do que o processo 2 que foi escolhido pelo SO. Então nesse caso, não basta o SO escolher um processo. Se o processo 2 é menor do que o SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 22 processo 5. Não é o caso amostrado na Figura 14. Então não basta salvar o processo 2 no disco tem que salvar o 2 e mais alguém no disco para liberar espaço suficiente para colocar o 5. Nesse caso é o contrário o 5 é menor que o 2. Então bastou salvar o 2 para poder iniciar o 5. Não deu erro para o usuário e está rodando o processo 5 que o usuário mandou rodar. Só tem o seguinte oficialmente eu tenho 5 processos, mas na verdade eu não tenho 5 processos que podem executar. Porque um dos cinco processos está no disco. Os processos que estão no disco não executam. A CPU só consegue executar código que está na memória. A CPU só consegue executar dados que está na memória. No caso do processo 2 nem o código nem os dados está na memória está tudo junto no disco. Então, portanto, a CPU não consegue executar esse processo 2. O processo 2 não será executado enquanto estiver no disco. Digamos que cada processo desse seja implementado para ter uma janela na tela. É um sistema gráfico com interação do usuário e tem uma janela para cada processo. Uma destas janelas é o processo 2. Se o usuário clicar na janela do processo 2. Ele quer usar o processo 2. Ele vai clicar o que se espera que acontece é que o processo 2 faça alguma coisa. Mostre uma mensagem. Nesse caso como está agora (o processo 2 está em disco e o processo 5 ocupa o lugar dele na memória) e o usuário clica no botão da janela do processo 2 não vai ter reação. O processo 2 não vai executar para processar o botão apertado porque o processo está no disco. Então nesse caso que o usuário quis executar o processo 2 para poder o SO conseguir colocar esse processo para executar ele tem que primeiro trazer de volta para memória o processo 2 que agora está em disco. Como a memória não tem ainda lugar suficiente para receber o processo 2 (apesar de ter espaços pequenos mais separados de memória) então a solução que existe é repetir essa ação que foi feita antes quando precisou colocar o processo 5 na memória. Qual foi a solução? Escolher um processo para ser salvo em disco. Então o SO vai repetir a solução escolhendo um processo para ser salvo em disco. Digamos então que ele escolha dessa vez o processo 4. O que vai acontecer é que o processo 4 vai ser escolhido e vai ser salvo no disco. Conforme mostra a Figura 15. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 23 Quando isso é feito o espaço que estava o processo 4 fica livre. E esse espaço livre pode ser usado para colocar de novo na memória o processo 2. O processo 2 foi para o disco (1) e agora o processo 2 volta para memória (3). Ele estando de novo na memória vai poder executar. E agora o botão pode funcionar. Porque isso é possível na medida que o processo 2 está na memória e vai ter um código que vai ser executado em resposta ao botão. Então o usuário ao clicar no botão da janela do processo 2. Ele vai ter esta resposta so vai demorar um pouquinho, pois o processo 2 está no disco. O SO vai salvar o processo 4 no disco vai ter que ler do disco o processo 2 e ai em seguida vai poder executar o código do processo 2 e ai vai dá uma resposta para o usuário. Vai demorar um pouquinho, não vai dá erro e o usuário vai vê aquilo que ele quer. Então a consequência de usar um Swap de processo é o tempo que vai demorar para as coisas acontecerem. O usuário quer a resposta mais vai ter que fazer essa troca de processos na memória. Nesse estado atual, qual o processo que não está na memória? O 4. Se um usuário tentar utilizar o 4 vai se a mesma coisa. O processo não vai ser executado porque não está na memória. O que tem que fazer o SO então? A mesma coisa que fez antes. Escolher um processo, pois a memória continua cheia. Escolher um outro processo para ser salvo em disco, liberar a memória e o processo 4 volta para memória. Então enquanto o usuário está usando estas coisas estão acontecendo como a memória está cheia fica ocorrendo uma troca entre o disco e a memória. Os processos vão para o disco e vão para memória. É uma troca entre o disco e a memória dai o nome SWAP. Uma coisa importante é a questão dos endereços. O processo 2 dois originalmente estava na memória no lugar do processo 5. Ele foi para o disco e precisou voltar. O SO trouxe de volta, mas não no mesmo endereço. O SWAP de processo tem um problema que é o mesmo processo ter que ficar em lugares diferentes na memória. Nem sempre é possível durante a execução do processo colocar ele em outro lugar da memória. Esse é o mesmo problema que já vimos na aula passada que é o da compactação. Nem sempre é possível a mesma coisa que acontece aqui acontece na compactação também. Na compactação você desloca o processo da memória não chega ir para o disco, mas o efeito final é um dano na parte da memória do processo. O processo 2 estava no endereço a partir do 20000 agora está a partir de 40000. Conforme mostra a Figura 16. Então estou deslocando o processo. Resultadofinal do SWAP na memória é deslocar o processo 2 na memória. Nem sempre isso é possível por causa dos endereços que o processo utiliza. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 24 Se o processo 2 mudar de endereço da memória. Se o processo 2 usar endereço absoluto a partir do zero. O processo 2 chama um rotina CALL 22000. Este tipo de endereçamento a partir do zero não dá para ser usado nunca com o SWAP de processos. E não é nem por causa do CALL. Esse CALL tenho como resolver. Tenho como fazer a correção desse endereço e corrigir o valor dele. Por exemplo, de CALL 22000 para CALL 42000. Então a rotina que estava em 22000 na hora que rodei o SWAP ela foi lá para cima. Ela vai estar onde no final das contas? Ela vai tá no 42000. No caso dessa instrução dá para mudar. Com relação ao endereço absoluto o SO consegue fazer a correção no código dos endereços que o código utiliza. O problema não vai acontecer ai. Vai acontecer nos endereços das variáveis ponteiros. Então quando têm na memória variáveis ponteiros. O que é a variável ponteiro? Ela guarda o endereço. Então a variável ponteiro ela vai dá o endereço que faz referencia ao valor original no código que o processo estava. Essa variável ponteiro P. Ela faz parte do processo que já entrou em execução que aponta para um variável dinâmica. E ao contrario do endereço da instrução o SO não sabe em que parte da memória você tem variáveis ponteiros. Então esse cara que era 28000 tem que virar 48000, mas como o SO não sabe onde está a variável ponteiro ele não tem condições de corrigir. Como ele não consegui corrigir ele coloca em lugar errado e não vai funcionar. O problema é igual na compactação. O problema é você ter variáveis ponteiros que vão apontar no endereço original que o processo estava na memória. Se eu descolo o processo na memória e não corrigir o valor de P. Ele apontará para o lugar errado. E ai não vai funcionar. Então nesse caso em que o código tem um endereço absoluto a partir do zero. O Swap do processo não consegue ser feito porque não dá para corrigir todos os endereços que o processo faça uso. O SO não permite que o SWAP aconteça nesse caso. Então em que caso o SO permite quando não se usa endereço absoluto. Uma solução que permite que o SWAP aconteça é o registrador de base. Para o registrador de base o endereço que a SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 25 instrução contém não é um endereço absoluto. É relativo a base. Então qual é a base original do processo 2? Era 20000. Então a rotina do endereço 22000. A chamada dela não vai ser CALL 22000. Vai ser CALL 2000. Durante a execução do processo o SO coloca os valores do registrador de base na base do processo. Então originalmente o processo 2 está no endereço 20000. Na hora de executar a instrução o que o Hardware vai fazer? Ele vai somar o endereço contido na instrução com o valor contido no registrador de base, 20000+2000=22000. Vai chamar a subrotina no endereço 22000. Isto vale tanto para endereços de chamadas a sub-rotinas quanto para endereços de variáveis ponteiros. Então o endereço que vou ter não é mais 22000. Com o registrador de base o endereço do ponteiro conta a partir da base do processo. Como o processo está aqui embaixo. Vou fazer o SWAP e depois volto o processo 2 para o 40000. Quando vai para o 40000 o que tem que fazer o SO? Colocar a nova base do processo 2 que é 40000. Então quando for executar o código do processo 2. O que vai acontecer? Vai acontecer que em qualquer endereço que o processo utilize vai somar o endereço com a base. Então 40000+2000 = 42000. Quando for chamar a subrotina. Depois colocar o ponteiro 8000+40000= 48000. Então vai utilizar a variável dinâmica aqui. Conforme mostra a Figura 17. Então se fosse usar o registrador de base é possível fazer o SWAP de processo desde que o SO mude o valor da base. O sistema operacional fica com todo o trabalho. Se tentar executar um processo maior que tamanho da memória da máquina, o sistema operacional tira um processo da memória e o coloca em disco para que outro processo solicitado pelo usuário seja executado. Por exemplo, será executado um processo 5 que não cabe na memória, o sistema operacional tira um processo da memória e o coloca em disco liberando uma espaço na memória para o processo 5. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 26 O grande problema desta solução é qual o processo o sistema operacional deve escolher para retirar da memória. O importante é escolher um processo que não traga nenhum prejuízo para o usuário. Sabemos que os processos podem estar nos seguintes estados: 1) Executando: é aquele que está na CPU sendo executado; 2) Pronto: não está executando, está esperando a vez para executar; 3) Bloqueado: está esperando que alguma coisa aconteça, por exemplo, término de operação de I/O para que possa voltar a executar, ou seja, vá para a fila de pronto esperando a sua vez de executar; 4) Bloqueado em Disco: É o processo bloqueado na memória e está agora no disco devido ao swap de processo. 5) Pronto em Disco: É o processo que já concluiu a operação e está aguardando ir para fila de prontos na memória para em seguida continuar execução. Um processo executando não seria o escolhido pelo sistema operacional. Um processo pronto estará executando em um curto espaço de tempo, então este processo não seria o mais indicado para que o sistema operacional retire-o da memória e o coloque no disco. Assim, o mais indicado para que o sistema operacional retire da memória seria o processo em estado bloqueado, que não tem perspectiva de ser desbloqueado em um espaço curto de tempo. Por exemplo, processos bloqueados a mais de 10 segundos seria um bom critério de escolha pelo sistema operacional. Um processo bloqueado devido uma leitura em disco não são os mais indicados, pois uma leitura em disco dura um curto espaço de tempo. Desta forma, processos bloqueados por algum tempo são os mais indicados para sofrem swap para disco. Quando isto acontece teremos um novo estado para o processo que seria o estado bloqueado em disco. Agora quando um processo que sofreu swap (ou seja, está em disco) se desbloqueia então o sistema operacional terá que escolher um outro processo bloqueado para que este passe para memória, ficando no estado de pronto, esperando a sua vez para ser executado. Por exemplo, se o processo P1 que está bloqueado se desbloqueia, então o sistema operacional fará a transição inversa, vai escolher outro processo bloqueado, o processo P3, para colocar este processo em disco, para pode trazer o P1 de volta. Irá demorar um pouco para que o usuário veja o resultado do processo que foi desbloqueado até a sua execução. Essa demora é o prejuízo que existe, essa perda de desempenho, pois o sistema operacional tem que trazer o processo de disco para memória. O benefício existente é poder executar mais processos do que cabe na memória. Transição entre os estados: 1) Um processo passa do estado pronto para executando quando ele é escalonado.; 2) Um processo passa do estado bloqueado para pronto quando a causa pela qual fez o processo ficar bloqueado foi concluída. Exemplo: um clique do mouse, quando o usuário clica o processo passa para o estado de pronto; 3) Um processo passa do estado executando para bloqueado quando o mesmo solicita alguma coisa ao sistema operacional, e este fica aguardando uma resposta desta solicitação. Exemplo: uma solicitação de leitura em disco; 4) Um processo passa do estado executando para pronto: a) em um sistema preemptivo: quando ocorre o fim do timelive do processo que está em execução ou a chegada de um processo com mais prioridade. Na preempção o sistema operacional tira o processo de execução pelo dois motivos descritos acima, sem que oprocesso tenha pedido nada ao sistema operacional, o processo sai involutariamente; b) em um sistema operacional não SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 27 preemptivo: existe uma chamada que o processo (principalmente, os processos que usam muito a CPU – CPU bound) sede o lugar para outro processo. Não é preempção, pois o processo sede o seu lugar na CPU voluntariamente. Este tipo de sistema operacional é chamado de sistema operacional cooperativo. Este tipo de mecanismo que o processo sede sua vez na CPU para um outro processo existe hoje no Windows e é chamado de yield, em sistema operacionais antigos era chamado de liberação de CPU. 5) Um processo passa do estado bloqueado em memória para bloqueado em disco quando um outro processo é solicitado pelo usuário e não tem espaço em memória para carregar este processo então o sistema operacional faz um swap para disco de um processo bloqueado à algum tempo na memória, e este fica bloqueado em disco. 6) Um processo passa do estado bloqueado em disco para pronto em disco quando a operação que este processo estava aguardando termina então vai para fila de prontos em disco. Ou seja, quando a causa do que o colocou em estado bloqueado não existe mais. 7) Um processo passa do estado pronto em disco para pronto em memória quando libera espaço em memória. Isto pode ocorre quando um processo libera a memória por ir para o estado de executando ou o sistema operacional pode escolher outro processo bloqueado para fazer o swap e liberar espaço para este processo pronto em disco. Observação: 1) Pergunta: Faz sentido existir o caminho de pronto para bloqueado? Resposta: Não, porque a causa para ele bloquear um processo é ele solicitar alguma coisa ao sistema operacional. E para que o processo solicite alguma coisa o mesmo tem que está em execução. 2) Pergunta: Faz sentido existir o caminho de executando para pronto? Resposta: Sim, porque pode ter acabado o timelive. Mas, o término do timelive não é a única causa. Outra causa seria a saída do processo devido a um outro processo de alta prioridade entrando na fila de prontos, assim o sistema operacional irá retirar o processo de baixa prioridade de execução e colocará o de alta prioridade para executar. 3) Pergunta: Como o sistema operacional sabe que acabou o timelive? Resposta: É uma interrupção que ocorre de tempos em tempos. Executando Pronto Bloqueado Bloqueado em Disco Pronto em Disco SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 28 4) Dentro do Windows tem uma chamada ao sistema operacional que é chamada de GetMessage, o sistema operacional bloqueia o processo até que o usuário responda esta chamada e aí o sistema operacional responde ao processo. A biblioteca Dephi esconde esta chamada, ele tem um case(swith) interno, condição, prevendo cada ação que o usuário vai fazer, em C o programador é obrigado a fazer esta chamada, este swith em C é o programador que faz. Conclusão: O swap de processos é utilizado como solução da falta de memória. Exemplo: Passo 1) Depois de uma solicitação de execução do processo P5 pelo usuário, o sistema operacional verifica a falta de memória para carregamento deste processo, este então retira processo P1 da memória, por está bloqueado à algum tempo e o coloca em disco, ocorre então o swap do processo P1. Com isso, se abre espaço em memória para o processo P5. Passo 2) Quando o que o processo P1 estava aguardando termina ele vai para fila de prontos em disco. Caso a memória não seja liberada devido a um processo que passou de pronto para executando, o sistema operacional escolhe outro processo para sofrer swap, neste exemplo, o processo P3, liberando espaço para que o P1 vá para fila de prontos em memória. Aí ele poderá ser escalonado para rodar. Memória SO P4 P3 P2 P1 P1 Passo 1 Memória SO P4 P3 P2 P5 Passo 2 P1 P2 Memória SO P4 P1 P2 P5 Disco Disco SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 29 Nessa solução precisa de solução de software e um pouco de hardware, que é o carregamento de processos em diferentes endereços de memória. Esta solução só por software é muito difícil. Por hardware é fácil dar suporte ao programa voltar para a memória, porque, ele usa o registrador de base para controlar os endereços diferentes na memória. A grande vantagem é que o programa não precisa fazer nada, fica tudo na responsabilidade do sistema operacional. O programa não se preocupa o problema da falta de memória. Não permite que um processo com tamanho maior que a memória seja executado. Permite que vários processos estejam ao mesmo tempo na memória. Suponha que em determinado momento existam na memória 4 processos: P1, P2, P3 e P4, o SO e uma pequena área livre. SO P 4 P 3 P 2 P 1 Como é feita a escolha? O SO escolhe preferencialmente processos que já estão bloqueados há algum tempo (pois provavelmente continuarão bloqueados por mais algum tempo) aguardando uma operação (leitura em disco, recepção de um pacote pela rede, resposta de um usuário etc.). Se a operação aguardada por esse processo que foi colocado em disco foi concluída, o SO deverá escolher um ou mais processos que estejam bloqueados na memória para serem colocados no disco a fim de liberar espaço na memória para esse processo que teve uma operação concluída. O Unix utiliza essa solução, que necessita de pouco suporte do HW. Basicamente o HW faz o carregamento dos processos em diferentes áreas da memória. O swap utiliza alguns estados a mais do que o diagrama de processos comum. 0 2000 4000 8000 10000 20000 25000 Suponha que um processo 5 precisa ser colocado na memória. Caso a área livre existente seja menor do que a área necessária para a alocação do processo 5, o SO deverá escolher um ou mais processos que estão na memória e colocá-los no disco, liberando espaço para o processo 5. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 30 Sem Swap Aguardand o operação de E/S Escalonado para executar Preempção (time- out ou substituição por um processo com prioridade maior) Executando Pronto Bloqueado Término da operação de E/S SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 31 Com Swap Surgimento de espaço suficiente para o processo ser alocado na MP Término da longa operação que causava o bloqueio do processo Término da operação de E/S Aguardan do operação de E/S Escalonado para executar Preempção (time- out ou substituição por um processo com prioridade maior) Executando Pronto Bloqueado Bloqueado em Disco Pronto em Disco Swap SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 32 20) Lembrando SO I I Qual é o critério que o SO usa para tirar um processo da memória? Vamos relembrar os estados de um processo. Conforme mostra a Figura 18. O estado mais importante do processo é o estado executando. Nesse estado a CPU está executando a instrução de um processo que está nesse estado. Este estado é o mais importante porque é um estado em que o processo faz alguma coisa. O processo só é útil quando é executado por isso o estado mais importante. Em uma maquina que tem uma CPU só. Quantos processos você pode executar. Um só de cada vez. Na máquina com duas CPUs. Hoje em dia são dois núcleos. Quantos processo eu posso ter nesse estado? Dois podemestar executando. Em uma máquina com 4 núcleos quantos processo eu posso executar? Quatro. Por que essa coisa de chamar núcleo e CPU? É uma questão de disposição física. Alguns anos atrás não tinha essa historia de núcleo. Então uma máquina com mais de uma CPU ela tinha mais de um chip de CPU. Cada CPU estava em um único chip. Cada chip tinha uma única CPU. Antigamente era assim uns 10 anos atrás. Com a evolução da capacidade de construir chip foi possível para o fabricante colocar mais de uma CPU no mesmo chip. Então os caras chamavam isso de núcleo. Mas, no fundo e uma CPU com mais de um chip. Algumas coisas são compartilhadas como a cache de memória, mas o grosso ele é individual é um separado para cada CPU. Quando você fala de um chip com 4 núcleos são quatro CPUs que estão dentro daquele mesmo chip. O processo não fica executando o tempo todo ele precisa de informações que não estão na memória ainda. Por exemplo, o usuário ainda não digitou o nome e o salário ainda. Então SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 33 enquanto o usuário digita. O SO muda o estado do processo para implementar esta espera que o processo tem que ter pela ligação com o usuário. Existe outro estado que é o estado bloqueado que é quando o processo tem que esperar alguma coisa acontecer para poder voltar a executar. Tem uma tela esperando o usuário digitar alguma coisa o usuário não digitou nada então o processo não tem o que fazer. Ele está parado, bloqueado. Bloqueado pelo o que? Está esperando o usuário digitar. Outro exemplo menos usual você tem um processo que é um servidor web. E esse processo roda em uma máquina servidora. O que ele faz? Ele recebe pedidos de enviar páginas html. Então tem o protocolo que é http. E os browser enviam pela rede um pedido de acesso a página html que está no servidor. Em resposta a este pedido o SO devolve também pela rede o html daquela página. Então enquanto um browser pede página nenhuma html o que o servidor faz? Nada. Ele espera que algum browser mande pela rede um pedido de página. O processo servidor que não recebe nenhum pedido de página hmtl. Ele ficará bloqueado até que venha um pedido ele possa executar esse pedido de html. Um terceiro exemplo de bloqueio é um exemplo menos obvio mais importante que o processo de leitura de um arquivo. O processo pedi para ler um arquivo. Isso para gente é uma coisa muito rápida. O tempo que demora um disco conseguir ler um arquivo nesse tempo a CPU já conseguiu executar milhões de instruções. Então não é interessante deixar a CPU sem fazer nada enquanto o processo manda ler um arquivo. Então quando um processo manda ler um arquivo. O que acontece? Esse processo que mandou ler o arquivo. Fez uma chamada ao SO para ler o arquivo. Ele muda de estado para bloqueado porque dessa forma um outro processo pode entrar em execução e fazer uma coisa útil. Mesmo que para gente o tempo para ler um arquivo seja curto é muito importante bloquear o arquivo. Porque nesse tempo que o arquivo está sendo lido o SO pode colocar outros processos executando e esse processo pode executar milhões de instruções. De forma geral a transição de executando para bloqueado ela ocorre quando o processo pedi para ter alguma coisa que não está disponível ainda. Pode ser qualquer coisa. O SO bloqueia o processo sempre que o processo pediu alguma coisa que não está disponível no momento. Aquela coisa que o processo queria e que não estava disponível passa a estar disponível. Por exemplo, o usuário digitou alguma coisa então vai desbloquear o processo. Ou, então, algum browser manda um pedido de páginas html isso vai desbloquear o processo. O arquivo acaba de ser lido e isto desbloqueai o processo. Toda da vez que a trava do bloqueio deixa de existir, o que se esperava está disponível. Isto desbloqueia o processo. Então tem que ter outro lugar para o processo esperar para poder executar. Tem outro estado que é chamado de Pronto. Neste estado tem uma fila de processos, pois pode ter mais de um processo neste estado. A fila funciona por ordem de chegada e conforme o processo vai saindo de execução o primeiro da fila passa a executar. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 34 Quando um processo parou de executar por que foi bloqueado o SO escalona o processo que está pronto para executar. A escolha que o SO faz para pegar um processo da fila de pronto geralmente é pegar o primeiro da fila. O ciclo mostrado na Figura 18 é o ciclo básico dos processos. Um processo está em um desses estados. Mas tem uma questão que precisa ser resolvida ainda estes três estados não são o suficiente para deixar uma máquina amigável para o usuário. Figura 18 Por quê? Porque um processo que está executando vai deixar de executar quando? Quando ele pedi uma coisa que não está disponível ainda. Mas, se o processo não pedir nada ele continua executando. Então que processo executa sem pedir nada, não é muito comum, geralmente o processo interage com o usuário. Quando pedem que o usuário impute alguma informação. Ou, então pede para ler um arquivo do disco. Não é comum ter um processo que não peça nada, mas existe. São processos que executam cálculos demorados. Por exemplo, um processo que esteja em loop fazendo uma determinada conta complicada. Enquanto o processo está fazendo este cálculo ele não está pedindo nada. Então, ele não sairá da CPU até que tenha acabado este calculo. Só que isto não é bom porque quando tem um processo neste estado a CPU não consegue executar outros. Por exemplo, se o usuário quiser abrir outra janela ele não conseguiria pelo fato deste processo está utilizando a CPU. Este processo impede outro processo de executar. Isto em uma maquina que tem uma CPU só seu eu colocar para rodar um processo que faz uma conta muito demorada este processo vai “travar” a máquina, pois enquanto ele estiver calculando nenhum outro processo pode executar. Qualquer coisa que se tente fazer em outra janela não vai ter resposta de outro processo e isto é ruim. Numa máquina que tem mais de uma CPU isto não é tão importante porque eu tenho um processo em uma CPU fazendo um cálculo demorado, mas eu tenho outro CPU que pode ser utilizada. Mas podemos ter vários processos calculando e ai é complicado. Neste caso, a máquina também fica travada. Na verdade não fica travada hoje em dia porque existe uma solução para este problema que é retirar da execução um processo de forma involuntária. Que dizer o processo não cede nada o SO 2 1 4 3 Escalonador escolhe um processo na fila de Pronto. Exemplos de Processos bloqueados: Servidor, Leitura de Arquivo etc. SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 35 decide retirar este processo de execução. Para que? Para dar a chance de outro processo passar a executar. A retirada involuntária do processo de execução cria uma nova situação. O processo não é bloqueado, pois não pediu nada. Ele volta para o estado de pronto, pois o SO retirou ele de execução para dar a chance para outro executar. Essa retirada involuntária do processo que está em execução é chamada de preempção. Retirada voluntaria é quando o processo pedi alguma coisa e ele sai da CPU. Quando ocorre a preempção? Preempção ocorre tipicamente em duas situações: - Término do intervalo máximo de execução (time slice) tipicamente 0,1s; - Existência de processo de maior prioridade no estado de pronto. Mesmo que o processo não tenha terminado o seu time slice se existir um processo de prioridade mais alta que ele na fila de prontos. Este processo é retirado pelo SO da CPU e o processo de prioridade alta é colocado na CPU. Com a preempção está pronta você tem uma máquina boa de usar porque tudo se comporta bem para o usuário. Quando entraem execução o SO não é uma interrupção pode até haver interrupção. Por exemplo, apertar uma tecla gera interrupção. A interrupção será uma rotina do SO que pega o conteúdo da tecla digitada e guarda em um lugar onde será acumulado até ser salvo. A partir do momento que a interrupção copiou as teclas que foram digitadas ela acaba e o processo que estava executando volta para CPU. Tem interrupções que não vão provocar preempção, mas outras vão. Por exemplo, tem uma interrupção que ocorre com frequência que é a interrupção de relógio. Então ela tem prioridade. Ela ocorre 100 vezes por segundo. Ela vai manter o horário da maquina. Tem varias coisas que são feitas na execução da interrupção do relógio. O relógio também é responsável pelo time slice. Quando o relógio executou 10 vezes (0,1 s) é o mesmo processo está na CPU ele sofre preempção. Expliquei tudo isto para informar qual é o critério que o SO tem que usar para salvar o processo em disco Um identificador importante para uma maquina muito ocupada é quantos processos ela possui no estado de pronto. No Windows este indicador pode ser visto pelo Uso da CPU que mostra quanto a CPU executou código útil em um determinado intervalo de tempo. Se a CPU executou durante 1s metade desse tempo com instruções do SO e a outra metade com instruções de código de processos do usuário. A CPU está com o uso de 50%. Um uso de 100% obviamente é uso elevado e não é uma coisa necessariamente ruim. É porque um processo que faz um cálculo demorado leva a maquina a uso de 100%, mas isto não quer dizer que esta ruim de usar. Um indicador mais solido do que a maquina está muito ocupada é a quantidade de processos esperando para serem executados. Não é razoável ter muito processos esperando para serem SISTEMA OPERACIONAL II – PARTE 3 Elaborado por Luciana SA Amancio Página 36 executados. Quando isso ocorre normalmente a máquina está com muita carga. É o melhor indicador para saber se uma maquina esta sobrecarregada quantos processos tem na fila de prontos. De 1 até 14 processo esperando para serem executados tudo bem, mas se tiver mais de 15 processos a máquina esta sobrecarregada. A máquina está com muito uso e lenta para processar. O Sistema Operacional utiliza como critério para salvar o processo em disco os processos que estão no estado de bloqueados e com o status de bloqueio longo. Por exemplo, o processo que esta bloqueado esperando o usuário digitar alguma coisa, ele será salvo em disco. No UNIX que implementa o Swap de Processos é criado dos novos estados. Conforme mostra a Figura 19. Quando o bloqueio em disco acaba o processo precisa ser desbloqueado só que ele não está na memória esta no disco. Então ele é salvo no estado Pronto em disco e fica esperando voltar para memória. Se a memória estiver ainda cheia. O SO tem que escolher outro processo para salvar em disco para poder retornar com o processo pronto em disco na memória. Quanto este processo volta para memória ele muda o estado para pronto. Isto não tem no Windows porque no Windows não tem estado de processos. Figura 19 3 4 1 2 7 5 6 Novos Estados no Unix para o SWAP de Processos.
Compartilhar