Baixe o app para aproveitar ainda mais
Prévia do material em texto
T164s Tanenbaum, Andrewa S. Sistemas operacionais [recurso eletrônico] : projeto e implementação / Andrew S. Tanenbaum, Albert S. Woodhull ; tradução João Tortello. – 3. ed. – Dados eletrônicos. – Porto Alegre : Bookman, 2008. Editado também como livro impresso em 2008. ISBN 978-85-7780-285-2 1. Sistemas operacionais. I. Woodhull, Albert S. II. Título. CDU 004.4 Catalogação na publicação: Mônica Ballejo Canto – CRB 10/1023 2 PROCESSOS Agora, estamos prestes a entrar em um estudo detalhado sobre como os sistemas operacionais em geral (e o MINIX 3 em particular) são projetados e construídos. O conceito central em qualquer sistema operacional é o de processo: uma abstração de um programa em execução. Tudo mais depende desse conceito e é importante que o projetista de sistema operacional (e o estudante) o entenda bem. 2.1 INTRODUÇÃO Todos os computadores modernos podem fazer várias coisas ao mesmo tempo. Enquanto exe- cuta um programa do usuário, um computador também pode estar lendo um disco e gerando saída de texto em uma tela ou impressora. Em um sistema com multiprogramação, a CPU também alterna de um programa para outro, executando cada um deles por dezenas ou cen- tenas de milissegundos. Rigorosamente falando, a qualquer momento, enquanto a CPU está executando apenas um programa, durante 1 segundo ela pode trabalhar em vários programas, dando aos usuários a ilusão de paralelismo. Às vezes, as pessoas falam de pseudoparalelis- mo nesse contexto, para contrastar com o verdadeiro paralelismo de hardware dos sistemas multiprocessadores (que têm duas ou mais CPUs compartilhando a mesma memória física). É difícil para as pessoas acompanhar múltiplas atividades paralelas. Assim, com o passar dos anos, os projetistas de sistemas operacionais desenvolveram um modelo conceitual (os processos seqüenciais) que torna mais fácil tratar com o paralelismo. Esse modelo, suas apli- cações e algumas de suas conseqüências são o assunto deste capítulo. 2.1.1 O modelo de processo Neste modelo, todo o software executável no computador, às vezes incluindo o sistema opera- cional, é organizado em diversos processos seqüenciais ou, para simplifi car, apenas proces- sos. Um processo é simplesmente um programa em execução, incluindo os valores correntes do contador de programa, dos registradores e das variáveis. Conceitualmente, cada processo tem sua própria CPU virtual. É claro que, na verdade, a CPU alterna de um processo para outro, mas para entender o sistema é muito mais fácil pensar em um conjunto de processos executados em (pseudo) paralelo do que tentar acompanhar o modo como a CPU troca de um programa para outro. Essa rápida alternância é chamada de multiprogramação, como vimos no Capítulo 1. 70 SISTEMAS OPERACIONAIS Na Figura 2-1(a), vemos um computador multiprogramado com quatro programas em memória. Na Figura 2-1(b), vemos quatro processos, cada um com seu próprio fl uxo de con- trole (isto é, seu próprio contador de programa) e cada um executando independentemente dos outros. É claro que existe apenas um contador de programa físico, de modo que, quando cada processo é executado, seu contador de programa lógico é carregado no contador de programa físico. Quando ele termina, o contador de programa físico é salvo no contador de programa lógico do processo, em memória. Na Figura 2-1(c), vemos que, observados por um intervalo de tempo sufi cientemente longo, todos os processos fi zeram progresso, mas em um dado instante apenas um está sendo executado. A B C D D C B A Alternância de processos Um contador de programa Quatro contadores de programa P ro ce ss o Tempo B C DA (a) (b) (c) Figura 2-1 (a) Multiprogramação de quatro programas. (b) Modelo conceitual de quatro processos seqüenciais independentes. (c) Apenas um programa está ativo em dado instante. Com a CPU alternando entre os processos, a velocidade com que um processo faz sua computação não será uniforme e, provavelmente, nem mesmo poderá ser reproduzida se os mesmos processos forem executados novamente. Assim, os processos não devem ser pro- gramados com suposições sobre temporização estabelecidas. Considere, por exemplo, um processo de E/S que inicializa uma fi ta streamer para restaurar o backup de arquivos, executa um laço de espera 10.000 vezes para permitir que ela atinja a velocidade correta e, depois, executa um comando para ler o primeiro registro. Se a CPU decidir trocar para outro processo durante o laço de espera, o processo da fi ta poderá não ser executado novamente até que o pri- meiro registro tenha passado pelo cabeçote de leitura. Quando um processo tem requisitos de tempo real críticos como esse (isto é, eventos particulares devem ocorrer dentro de um tempo específi co), medidas especiais devem ser tomadas para garantir que eles sejam cumpridos. Normalmente, entretanto, a maioria dos processos não é afetada pela multiprogramação da CPU, nem pelas velocidades relativas dos diferentes processos. A diferença entre um processo e um programa é sutil, mas decisiva. Uma analogia pode ajudar a esclarecer esse ponto. Considere um profi ssional de computação com dotes culiná- rios que está assando um bolo de aniversário para sua fi lha. Ele tem uma receita de bolo e uma cozinha bem-equipada, com os ingredientes necessários: farinha, ovos, açúcar, essência de baunilha etc. Nessa analogia, a receita é o programa (isto é, um algoritmo expresso em alguma notação conveniente), o profi ssional de computação é o processador (CPU) e os in- gredientes do bolo são os dados de entrada. O processo é a atividade que consiste em nosso confeiteiro ler a receita, buscar os ingredientes e assar o bolo. Agora, imagine que o fi lho do profi ssional de computação apareça chorando, dizendo que foi picado por uma abelha. O profi ssional de computação memoriza o ponto onde estava na receita (o estado do processo atual é salvo), procura um manual de primeiros socorros e começa a seguir as orientações. Vemos aqui o processador alternando de um processo (assar) para outro de prioridade mais alta (prestar cuidados médicos), cada um tendo um programa CAPÍTULO 2 • PROCESSOS 71 diferente (receita versus manual de primeiros socorros). Quando a picada de abelha tiver sido tratada, o profi ssional de computação volta para seu bolo, continuando a partir do ponto onde estava. A idéia-chave aqui é que um processo é um tipo de atividade. Ele tem um programa, entrada, saída e um estado. Um único processador pode ser compartilhado entre vários pro- cessos, com algum algoritmo de escalonamento sendo utilizado para determinar quando deve interromper o trabalho em um processo e atender outro. 2.1.2 Criação de processos Os sistemas operacionais precisam de alguma maneira de garantir que todos os processos necessários existam. Em sistemas muito simples, ou em sistemas projetados para executar um único aplicativo (por exemplo, controlar um dispositivo em tempo real), é possível ter todos os processos que serão necessários presentes quando o sistema inicia. Contudo, nos sistemas de propósito geral, é necessário alguma maneira de criar e terminar processos durante a ope- ração. Veremos agora alguns dos problemas. Existem quatro eventos principais que acarretam a criação de processos: 1. Inicialização do sistema. 2. Realização de uma chamada de sistema por um processo em execução para criação de processo. 3. Um pedido de usuário para criar um novo processo. 4. Início de uma tarefa em lote. Quando um sistema operacional é inicializado, freqüentemente vários processos são criados. Alguns deles são processos de primeiro plano (foreground); isto é, processos que interagem com os usuários (humanos) e executam trabalho para eles. Outros são processos de segundo plano (background), os quais não são associados a usuários em particular, mas, em vez disso, têm alguma função específi ca. Por exemplo, um processo de segundo plano pode ser projetado para aceitar pedidos depáginas web contidas nessa máquina, sendo acionado quando chega um pedido para ser atendido. Os processos que fi cam em segundo plano para executar alguma atividade, como buscar páginas web, impressão etc., são chamados de da- emons. Os sistemas grandes normalmente têm dezenas deles. No MINIX 3, o programa ps pode ser usado para listar os processos que estão em execução. Além dos processos criados no momento da inicialização, novos processos também po- dem ser criados depois. Freqüentemente, um processo em execução fará chamadas de sistema para criar um ou mais processos novos, para ajudá-lo a fazer seu trabalho. A criação de novos processos é particularmente útil quando o trabalho a ser feito pode ser facilmente formulado em termos de vários processos relacionados que estão interagindo, mas que são independen- tes. Por exemplo, ao se compilar um programa grande, o programa make ativa o compilador C para converter arquivos fonte em código objeto e depois ativa o programa install para copiar o programa em seu destino, confi gurar o proprietário e as permissões etc. No MINIX 3, o com- pilador C em si é, na realidade, composto por vários programas diferentes, os quais trabalham em conjunto. Isso inclui um pré-processador, um analisador sintático da linguagem C, um gerador de código em linguagem assembly, um montador e um ligador (linker). Nos sistemas interativos, os usuários podem iniciar um programa digitando um coman- do. No MINIX 3, consoles virtuais permitem que um usuário inicie um programa, digamos, um compilador, e depois troque para um console alternativo e inicie outro programa, talvez para editar a documentação, enquanto o compilador está em execução. 72 SISTEMAS OPERACIONAIS A última situação em que processos são criados se aplica apenas aos sistemas de lote encontrados nos computadores de grande porte. Aqui, os usuários podem submeter tarefas de lote para o sistema (possivelmente de forma remota). Quando o sistema operacional decide que tem recursos sufi cientes para executar outra tarefa, ele cria um novo processo e executa a próxima tarefa de sua fi la de entrada. Tecnicamente, em todos esses casos, um novo processo é criado fazendo-se com que um processo existente execute uma chamada de sistema para criação de processo. Esse pro- cesso pode ser um processo de usuário em execução, um processo de sistema ativado a partir do teclado ou mouse, ou ainda um processo do gerenciador de lotes. O que esse processo faz é executar uma chamada de sistema para criar o novo processo. Essa chamada de sistema instrui o sistema operacional a criar um novo processo e indica, direta ou indiretamente, qual programa deve ser executado. No MINIX 3, existe apenas uma chamada de sistema para criar um novo processo: fork. Essa chamada cria um clone exato do processo que fez a chamada. Após a chamada de fork, os dois processos, o pai e o fi lho, têm a mesma imagem da memória, as mesmas strings de ambiente e os mesmos arquivos abertos. Isso é tudo. Normalmente, o processo fi lho executa então execve ou uma chamada de sistema similar, para alterar sua imagem da memória e executar um outro programa. Por exemplo, quando um usuário digita um comando, digamos, sort, no shell, este cria um processo fi lho e o fi lho executa sort. O motivo desse processo de duas etapas é permitir que o fi lho manipule seus descritores de arquivo após a chamada de fork, mas antes de execve, para fazer o redirecionamento da entrada padrão, da saída padrão e do erro padrão. No MINIX 3 e no UNIX, depois que um processo é criado, tanto o pai quanto o fi lho têm seus próprios espaços de endereçamento distintos. Se um dos processos alterar uma pala- vra em seu espaço de endereçamento, ela não será visível para o outro processo. O espaço de endereçamento inicial do fi lho é uma cópia do espaço de endereçamento do pai, mas existem dois espaços de endereçamento distintos envolvidos; nenhuma porção de memória passível de ser escrita é compartilhada (assim como em algumas implementações de UNIX, o MINIX 3 pode compartilhar o texto do programa entre os dois, desde que não possa ser modifi cado). Entretanto, é possível que um processo recentemente criado compartilhe alguns outros recur- sos de seu criador, como os arquivos abertos. 2.1.3 Término de processos Após um processo ser criado, ele começa a ser executado e faz seu trabalho, seja qual for. En- tretanto, nada dura para sempre, nem mesmo os processos. Mais cedo ou mais tarde, o novo processo terminará, normalmente devido a uma das seguintes condições: 1. Término normal (voluntário) 2. Término por erro (voluntário) 3. Erro fatal (involuntário) 4. Eliminado por outro processo (involuntário) A maioria dos processos termina porque já fez seu trabalho. Quando um compilador tiver compilado o programa recebido, ele executa uma chamada de sistema para dizer ao sis- tema operacional que terminou. No MINIX 3, essa chamada é a exit. Os programas também aceitam término voluntário. Por exemplo, os editores sempre têm uma combinação de teclas que o usuário pode utilizar para instruir o processo a salvar o arquivo de trabalho, remover os arquivos temporários que estão abertos e terminar. CAPÍTULO 2 • PROCESSOS 73 O segundo motivo de término é o fato de o processo descobrir um erro fatal. Por exem- plo, se um usuário digitar o comando cc foo.c para compilar o programa foo.c e esse arquivo não existir, o compilador simplesmente en- cerrará. O terceiro motivo para o término é um erro causado pelo processo, talvez devido a um erro no programa. Exemplos incluem a execução de uma instrução inválida, referência à memória inexistente ou divisão por zero. No MINIX 3, um processo pode dizer ao sistema operacional que deseja tratar de certos erros sozinho, no caso em que o processo é sinalizado (interrompido), em vez de terminar quando um dos erros ocorre. O quarto motivo pelo qual um processo poderia terminar é o fato de executar uma chamada de sistema instruindo o sistema operacional a eliminar algum outro processo. No MINIX 3, essa chamada é a kill. É claro que o processo que vai eliminar o outro deve ter a au- torização necessária para isso. Em alguns sistemas, quando um processo termina, voluntaria- mente ou não, todos os processos que criou também são eliminados imediatamente. Contudo, o MINIX 3 não funciona assim. 2.1.4 Hierarquia de processos Em alguns sistemas, quando um processo cria outro, o pai e o fi lho continuam associados de certas maneiras. O próprio fi lho pode criar mais processos, formando uma hierarquia de processos. Ao contrário das plantas e dos animais, que usam reprodução sexual, um processo tem apenas um pai (mas zero, um, dois ou mais fi lhos). No MINIX 3, um processo, seus fi lhos e outros descendentes podem, juntos, formar um grupo de processos. Quando um usuário envia um sinal do teclado, o sinal pode ser enviado para todos os membros do grupo de processos correntemente associados ao teclado (nor- malmente, todos os processos que foram criados na janela corrente). Isso é a dependência de sinal. Se um sinal é enviado para um grupo, cada processo pode capturá-lo, ignorá-lo ou executar a ação padrão, que é ser eliminado pelo sinal. Como um exemplo simples de como as árvores de processos são utilizadas, vamos ver como o MINIX 3 se inicializa. Dois processos especiais, o servidor de reencarnação e init estão presentes na imagem de boot. A tarefa do servidor de reencarnação é (re)iniciar drivers e servidores. Ele começa bloqueado, a espera de mensagens que o instrua sobre o que criar. Em contraste, init executa o script /etc/rc, que o faz enviar comandos para o servidor de reencarnação para iniciar os drivers e servidores ausentes na imagem de boot. Esse procedi- mento torna os drivers e os servidores fi lhos do servidor de reencarnação, de modo que, se qualquer um deles terminar, o servidor de reencarnação será informado e poderá reiniciá-los (isto é, reencarná-los) novamente. Esse mecanismo se destinaa permitir que o MINIX 3 tole- re uma falha de driver ou de servidor, pois um novo driver ou servidor será iniciado automa- ticamente. Contudo, na prática, substituir um driver é muito mais fácil do que substituir um servidor, pois há menos repercussão em outras partes do sistema. (E não podemos dizer que isso sempre funciona perfeitamente; ainda há trabalho em andamento.) Quando init tiver terminado de fazer isso, ele lê um arquivo de confi guração (/etc/ttytab) para ver quais terminais reais e virtuais existem. Init cria (com fork) um processo getty para cada um deles, exibe um prompt de login e depois espera pela entrada. Quando um nome é digitado, getty executa (com exec) um processo login tendo o nome como seu argumento. Se o usuário tiver êxito na conexão, login executará (com exec) o shell do usuário. Portanto, o shell é um fi lho de init. Comandos do usuário criam fi lhos do shell, os quais são netos de 74 SISTEMAS OPERACIONAIS init. Essa seqüência de eventos é um exemplo de como as árvores de processos são usadas. Contudo, os códigos do servidor de reencarnação e de init não estão listados neste livro; o shell também não está. A linha tinha de ser traçada em algum lugar. Mas agora você tem a idéia básica. 2.1.5 Estados de um processo Embora cada processo seja uma entidade independente, com seu próprio contador de pro- grama, registradores, pilha, arquivos abertos, alarmes e outros estados internos, os processos freqüentemente precisam interagir, se comunicar e se sincronizar com outros processos. Por exemplo, um processo pode gerar uma saída que outro processo utiliza como entrada. Nesse caso, os dados precisam ser movidos entre os processos. No comando de shell cat chapter1 chapter2 chapter3 | grep tree o primeiro processo, executando cat, concatena três arquivos e produz uma saída. O segundo processo, executando grep, seleciona todas as linhas que contêm a palavra “tree”. Depen- dendo das velocidades relativas dos dois processos (que dependem da complexidade relativa dos programas e de quanto tempo da CPU cada um recebeu), pode acontecer que grep esteja pronto para executar, mas não haja nenhuma entrada esperando por ele. Então, ele deve ser bloqueado até que a entrada esteja disponível. Quando um processo é bloqueado, isso acontece porque logicamente ele não pode con- tinuar, normalmente, porque está esperando uma entrada que ainda não está disponível. Tam- bém é possível que um processo que esteja conceitualmente pronto e capaz de executar, seja interrompido porque o sistema operacional decidiu alocar a CPU temporariamente para outro processo. Essas duas condições são completamente diferentes. No primeiro caso, a suspensão é inerente ao problema (você não pode processar a linha de comando do usuário até que ele a tenha digitado). No segundo caso, trata-se de um aspecto técnico do sistema (falta de CPUs sufi cientes para dar a cada processo seu próprio processador). Na Figura 2-2, vemos um dia- grama de estados mostrando os três estados em que um processo pode estar: 1. Executando (realmente utilizando a CPU nesse instante) 2. Pronto (executável; temporariamente parado para permitir que outro processo seja executado) 3. Bloqueado (incapaz de executar até que algum evento externo aconteça) Logicamente, os dois primeiros estados são semelhantes. Nos dois casos, o processo está pronto para executar, só que no segundo não há nenhuma CPU disponível para ele, tem- porariamente. O terceiro estado é diferente dos dois primeiros porque o processo não pode executar, mesmo que a CPU não tenha mais nada a fazer. 1 23 4Bloqueado Executando Pronto 1. O processo é bloqueado para entrada 2. O escalonador seleciona outro processo 3. O escalonador seleciona esse processo 4. A entrada torna-se disponível Figura 2-2 Um processo pode estar em execução, bloqueado ou pronto. As transições entre esses estados são como mostradas. CAPÍTULO 2 • PROCESSOS 75 Conforme mostrado, são possíveis quatro transições entre esses três estados. A tran- sição 1 ocorre quando um processo descobre que não pode continuar. Em alguns sistemas, o processo precisa executar uma chamada de sistema, block ou pause, para entrar no estado bloqueado. Em outros sistemas, incluindo o MINIX 3, quando um processo lê um pipe ou um arquivo especial (por exemplo, um terminal) e não há nenhuma entrada disponível, ele muda automaticamente do estado em execução para o estado bloqueado. As transições 2 e 3 são causadas pelo escalonador, que faz parte do sistema operacional, sem que o processo nem mesmo saiba a respeito delas. A transição 2 ocorre quando o escalo- nador decide que o processo em execução atuou por tempo sufi ciente e é hora de outro pro- cesso receber algum tempo da CPU. A transição 3 ocorre quando todos os outros processos já tiveram sua justa parte e é hora de o primeiro deles receber a CPU para executar novamente. O escalonamento – decidir qual processo deve ser executado, quando e por quanto tempo – é um assunto importante. Muitos algoritmos têm sido projetados para tentar equilibrar as demandas de efi ciência concorrentes para o sistema como um todo e a imparcialidade para os processos individuais. Veremos o escalonamento e estudaremos alguns desses algoritmos posteriormente neste capítulo. A transição 4 ocorre quando o evento externo pelo qual um processo estava esperando acontece (por exemplo, a chegada de alguma entrada). Se nenhum outro processo estiver sen- do executado nesse instante, a transição 3 será ativada imediatamente e o processo começará a executar. Caso contrário, talvez ele tenha de esperar no estado pronto por alguns instantes, até que a CPU esteja disponível. Usando o modelo de processos, torna-se muito mais fácil pensar no que está ocorrendo dentro do sistema. Alguns processos executam programas que executam comandos digitados por um usuário. Outros processos fazem parte do sistema e executam tarefas como fazer re- quisições de serviços de arquivo ou gerenciar os detalhes da operação de um disco ou de uma unidade de fi ta. Quando ocorre uma interrupção de disco, o sistema pode tomar a decisão de parar de executar o processo corrente e executar o processo de disco, que estava bloqueado esperando essa interrupção. Dissemos “pode tomar a decisão”, porque isso depende das prio- ridades relativas do processo em execução e do processo do driver de disco. Mas a questão é que, em vez de pensar sobre interrupções, podemos pensar em processos de usuário, pro- cessos de disco, processos de terminal etc., que são bloqueados quando estão esperando algo acontecer. Quando o bloco de disco for lido ou o caractere digitado, o processo que estava esperando por isso é desbloqueado e é fi ca pronto para executar novamente. Essa visão dá origem ao modelo mostrado na Figura 2-3. Aqui, o nível mais baixo do sistema operacional é o escalonador, com uma variedade de processos sobre ele. Todo o tra- tamento de interrupção e os detalhes sobre como realmente iniciar e parar processos fi cam ocultos no escalonador, que na verdade é bem pequeno. O restante do sistema operacional é estruturado elegantemente na forma de processos. O modelo da Figura 2-3 é utilizado no MI- 0 1 n – 2 n – 1 Escalonador Processos Figura 2-3 A camada inferior de um sistema operacional estruturado em processos trata das interrupções e do escalonamento. Acima dessa camada estão os processos seqüenciais. 76 SISTEMAS OPERACIONAIS NIX 3. É claro que o “escalonador” não é o único elemento na camada inferior; também há suporte para tratamento de interrupções e para comunicação entre processos. Contudo, para uma primeira abordagem, isso serve para mostrar a estrutura básica. 2.1.6 Implementação de processos Para implementar o modelo de processos, o sistema operacional mantém uma tabela (um array de estruturas), chamada tabela de processos, com uma entrada por processo. (Alguns autores chamam essas entradas de bloco de controle de processo.) Essa entrada contém in- formaçõessobre o estado do processo, sobre seu contador de programa, sobre o ponteiro da pilha, sobre a alocação de memória, sobre o status de seus arquivos abertos, suas informações de contabilidade e de escalonamento, alarmes e outros sinais, e tudo mais sobre o processo, as quais devem ser salvas quando o processo muda do estado em execução para pronto, a fi m de que ele possa ser reiniciado posteriormente como se nunca tivesse sido interrompido. No MINIX 3, a comunicação entre processos, o gerenciamento da memória e o geren- ciamento de arquivos são tratados por módulos separados dentro do sistema, de modo que a tabela de processos é subdividida, com cada módulo mantendo os campos de que precisa. A Figura 2-4 mostra alguns dos campos mais importantes. Os campos da primeira coluna são os únicos relevantes para este capítulo. As outras duas colunas são fornecidas apenas para dar uma idéia das informações necessárias para outras partes no sistema. Núcleo Registradores Contador de programa Palavra de status do programa Ponteiro da pilha Estado do processo Prioridade de escalonamento corrente Prioridade máxima da escalonamento Tiques de escalonamento restantes Tamanho do quantum Tempo de CPU usado Ponteiros da fi la de mensagens Bits de sinais pendentes Bits de fl ag Nome do processo Gerenciamento de processos Ponteiro para o segmento de texto Ponteiro para o segmento de dados Ponteiro para o segmento bss Status de saída Status de sinal ID do processo Processo pai Grupo do processo Tempo de CPU dos fi lhos UID real UID efetivo GID real GID efetivo Informações de arquivo para compartilhar texto Mapas de bits de sinais Vários bits de fl ag Nome do processo Gerenciamento de arquivos Máscara UMASK Diretório raiz Diretório de trabalho Descritores de arquivo Id real UID efetivo GID real GID efetivo tty de controle Área de salvamento para leitura/escrita Parâmetros da chamada de sistema Bits de fl ag Figura 2-4 Alguns campos da tabela de processos do MINIX 3. Os campos são distribuídos pelo núcleo, pelo gerenciador de processos e pelo sistema de arquivos. Agora que já vimos a tabela de processos, é possível explicar um pouco mais como a ilusão de múltiplos processos seqüenciais é mantida em uma máquina com uma única CPU e muitos dispositivos de E/S. Tecnicamente, o texto a seguir é uma descrição de como o escalonador da Figura 2-3 funciona no MINIX 3, mas a maioria dos sistemas operacionais
Compartilhar