Introdução

O que é um sistema operacional?
• • •

um provedor de abstrações um coordenador de recursos um mágico: faz com que seu sistema pareça mais do que na realidade ele é (mais de um processador, memória maior)

A principal tarefa do SO é "adaptar" o hardware. Exemplos: MS-DOS/Windows, MacOS, UNIX. O que vem incluído em um SO? Já que pouquíssimas pessoas projetam e escrevem sistemas operacionais, para que estudá-los?

conceitos de sistemas operacionais são relevantes em toda ciência da computação. Um entendimento dos conceitos de sistemas operacionais fornece uma excelente base para a construção de sistemas de software complexos entender o SO é fundamental para um entendimento profundo de um sistema de computação. Isto é útil mesmo que você nunca vá escrever um SO.

Uma História Social de Sistemas Operacionais
Fase 0: Computadores são uma ciência experimental e exótica: não precisa de sistema operacional
• • • •

computador programado através de "plugs" no painel usuário presente todo o tempo; toda atividade é sequencial: nenhuma sobreposição entre computação, E/S e tempo de pensar do usuário conjuntos de cartões manualmente carregados para executar os programas eventualmente foram desenvolvidas bibliotecas, utilizadas por todos (... precursoras dos sistemas operacionais)

Problema: muita espera.
• • •

usuário tem que esperar pela máquina máquina tem que esperar pelo usuário todos têm que esperar pela leitora de cartões

Fase 1: Computadores são caros; pessoas são baratas
• •

torna utilização do computador mais eficiente, desacoplando as atividades das pessoas das atividades do computador SO funciona como um monitor batch, continuamente carregando um job, executando e continuando com o próximo job. Se o programa falhasse, o SO

• •

salvava uma cópia do conteúdo de memória para o programador depurar (19551965) melhor utilização do hardware; bem difícil para depurar! "canais de E/S" e interrupções: sobrepõe E/S e computação o uso de "buffers" e gerenciamento de interrupções feito pelo SO o "spool" de jobs para o tambor magnético

Problemas:
• • •

só um usuário de cada vez na máquina usuário tem que esperar pela máquina um SO para cada máquina

Técnicas de hardware: adiciona proteção à memória e relocação
• • •

multiprogramação: muitos usuários podem compartilhar o sistema jobs pequenos podem completar rapidamente SO passa a ter que gerenciar interação entre jobs concorrentes

IBM OS/360: primeiro SO projetado para uma família de computadores
• • •

utilizar o mesmo SO em todas as máquinas, da mais simples à mais complexa SO passa a ser um assunto de estudo em ciência da computação SOs passaram a ser estudados porque eles não funcionavam. OS/360 é um exemplo: anunciado em 1963, só funcionou realmente em 1968

Novos problemas:
• • •

SOs extremamente complicados todo escrito em assembler, milhares de linhas (e de erros) usuários ainda esperando pela máquina; isso motivou a fase 2

Fase 2: Computadores são rápidos; pessoas são lentas; ambos são caros. Necessário tornar as pessoas mais produtivas. "Timesharing" interativo: permitir que vários usuários utilizem a mesma máquina simultaneamente
• • •

um terminal para cada usuário manter os dados "on-line": utilização de sistemas de arquivos estruturados prover tempo de resposta razoável

Fase 3: Computadores são baratos; pessoas são caras. Dar um computador para cada pessoa.

workstation pessoal: o SUN (Stanford University Network) o Xerox Alto Apple II

• •

IBM PC MacIntosh

Fase 4: Computadores Pessoais (PCs) invadem o planeta
• • • •

fornecedores de software produzem programas para uso individual de alta qualidade com suporte limitado para funções de SO proteção e segurança são de importância secundária redes possibilitam aparecimento de novas aplicações importantes: e-mail, bboards, newsgroups, WWW. Aparecimento de arquiteturas cliente-servidor. máquinas servidoras motivam mais avanços na tecnologia de SOs

Problemas:
• • •

as pessoas ainda continuam esperando por computadores viruses e worms hackers

História Técnica de Sistemas Operacionais
Sistemas Timesharing CTSS (1962):
• • •

MIT um dos primeiros sistemas timesharing motivou o desenvolvimento do MULTICS

MULTICS (1965):
• • • •

projeto conjunto entre MIT, Bell Labs e General Eletric objetivo era um "distribuidor" de serviços de computação. As pessoas iriam comprar esses serviços do mesmo modo que compram eletricidade introduziu várias idéias fundamentais: anéis de proteção, sistema de arquivos estruturado em árvore e outros construir foi mais difícil do que era esperado

UNIX (1970):
• • • • • • •

Ken Thompson (do projeto MULTICS) descobriu um PDP-7 sem utilização no Bell Labs ele e Dennis Ritchie construiram um sistema projetado por programadores para programadores primeira versão em assembler, depois em C código fonte foi disponibilizado para Universidades Berkeley adicionou suporte para memória virtual UNIX se tornou um SO comercial idéias importantes popularizadas pelo UNIX: o SO escrito numa linguagem de alto nível

o o o

SO portável sistema de arquivos estruturado em árvore várias outras

PCs e Workstations
• • • •

CP/M: primeiro SO para PCs IBM precisava de software para seu novo PC; liberação do CP/M estava atrasada IBM contrata Microsoft (Bill Gates, BASIC) para construir um SO objetivo principal: terminar rápido e ser compatível com CP/M

Hoje: redes
• •

sistemas de computação são compostos de recursos pessoais e recursos compartilhados pessoas não querem compartilhar CPU e memória, mas querem compartilhar correio eletrônico, bancos de dados, programas e outros

Sistemas Operacionais Hoje
Os SOs atuais são:

Enormes: o se o kernel do seu SO ocupa menos que 1 Mbyte, ele é considerado pequeno o tipicamente centenas de milhares de linhas de código o 100-1000 homens-ano de esforço de desenvolvimento Complexos: o assíncronos o idiossincrasias de hardware (tem que executar em qualquer plataforma) o classes diferentes de usuários apresentam diferentes demandas o performance é crucial Mal compreendidos: o os sistemas duram mais que seus criadores o muito grandes para uma só pessoa compreender o nunca estão completamente livres de erros (OS/360 foi liberado com 1000 "bugs") o comportamento é difícil de prever; ajustes de performance feitos, em geral, baseados em intuição; intuição quase sempre está errada

Conceitos em SOs:
• • •

system calls (chamadas de sistema) processos interrupções

Funcionalidade de SOs

Concorrência: usuário compartilha memória, dispositivos de E/S e processadores; no entanto cada usuário imagina que tem sua própria máquina
• • •

um usuário pode executar múltiplas atividades SO utiliza a abstração processo para gerenciar as interações SO deve evitar que os processos interajam de maneira errônea ou nãointencional

Suporte a E/S: dispositivos de E/S são lentos; é desejável que a CPU não fique ociosa durante operações de E/S. Motivação para interrupções.
• • • • • •

dispositivos operam independentemente CPU fornece os comandos para os dispositivos e vai executar outra coisa quando a operação completa, o dispositivo interrompe a CPU CPU interrompe o que estava fazendo, trata a interrupção, e depois continua com o que estava fazendo SO deve garantir que interrupções não pertubem o estado corrente da máquina em algumas situações deve-se gerenciar interrupções múltiplas

Memória: usuários/processos têm que compartilhar uma quantidade limitada de memória.
• • •

SO tem que coordenar esse compartilhamento disponibiliza memória real quando um processo está executando, através de paginação ou segmentação programas são escritos como se a máquina tivesse uma memória muito maior

Sistema de Arquivos: arquivos não podem desaparecer e são pessoais
• •

SO tem que alocar espaço em discos e fitas SO tem que prover proteção

Redes: usuários podem se comunicar com outras máquinas ou podem utilizar outras máquinas
• •

SO tem que suportar protocolos de comunicação, naming, transparência na rede, sistemas de arquivos remotos SO tem que fazer um sistema distribuído se parecer com um sistema centralizado

O SO apresenta ilusões aos usuários:
• • • •

cada programa executa na sua própria máquina existe mais memória do que você jamais vai precisar eventos podem acontecer simultaneamente (... quase sempre o SO é bem sucedido)

Processos (Tanenbaum 2.1)
Em sistemas operacionais modernos, vários programas executam concorrentemente. A abstração ``processo'' ajuda a manter o sistema organizado. O que é um Processo? Um processo é uma abstração utilizada para representar um programa em execução. Um processo contem toda informação necessária para completar uma computação. Em alguns sistemas processos são chamados de tarefas (``tasks''). Um processo é a mesma coisa que um programa? Não. Um processo é, ao mesmo tempo, mais e menos que um programa.

Mais: o programa é apenas parte do estado. Se duas pessoas estão executando o programa ls , elas estão usando apenas um programa, mas existem dois processos. Menos: programas podem gerar vários processos. Por exemplo, quando você executa um make , são executados um compilador, um assembler, um carregador, entre outras coisas.

Que informações são necessárias para o sistema gerenciar um processo?
• • • • •

a sequência de instruções que compõe o programa o valores correntes dos dados do programa o endereço da instrução que está sendo executada os arquivos que estão abertos Exemplo: o Unix utiliza, entre outras, as estruturas proc e user para manter o estado de um processo

Porque duas estruturas? A estrutura proc é utilizada para manter informações que têm que ficar na memória durante toda a vida do processo. A estrutura user contem o restante do estado do processo, e pode ser paginada para o disco. Uniprogramação e Multiprogramação
• •

sistemas uniprogramados permitem a execução de apenas um processo por vez. Exemplo: MS/DOS. sistemas multiprogramados (ou multitarefa) permitem mais de um processo. Exemplos: Unix, Windows NT.

• • •

algumas vezes a distinção não é clara. Exemplos: MacOS, Windows. escrever um SO uniprogramado é muito mais fácil; não é necessário se preocupar com interação entre múltiplos processos multiprogramação permite melhor utilização dos recursos da máquina, além de permitir a execução de mais de um programa ao mesmo tempo

Estruturas de dados para a gerência de processos As estruturas user e proc mantêm estado de software independente da máquina. O sistema tem que manter também estado de hardware dependente da máquina. Por exemplo, o Unix utiliza uma estrutura chamada process control block (pcb). Ela pode ser encontrada, tipicamente, em /usr/include/machine/pcb.h. Veja abaixo o arquivo pcb.h da máquina topazio (rodando SunOS 4.1.2):
/* @(#)pcb.h 1.2 90/08/06 SMI */

/* * Copyright (c) 1985 by Sun Microsystems, Inc. */ #ifndef _sun4m_pcb_h #define _sun4m_pcb_h /* * Sun software process control block */ #include #define MAXWIN supported */ 12 /* max number of windows currently

/* * The system actually supports one more than the above number. * There is always one window reserved for trap handlers that * never has to be saved into the pcb struct. */ #ifndef LOCORE #include struct pcb { /* this struct label_t int int struct */ char int */ int coprocessors */ struct int int

struct MUST be 1K aligned -- checked for in assym.s */ l1pt pcb_l1pt; /* level 1 page table */ pcb_regs; /* saved pc and sp */ pcb_psr; /* processor status word */ pcb_uwm; /* user window mask */ rwindow pcb_wbuf[MAXWIN]; /* user window save buffer *pcb_spbuf[MAXWIN]; /* sp's for each wbuf */ pcb_wbcnt; /* number of saved windows in pcb_wbuf *pcb_psrp; /* psr pointer to en/disable

fpu *pcb_fpctxp;/* pointer to fpu state */ pcb_fpflags; /* fpu enable flags */ *pcb_cpctxp; /* pointer to coprocessor state */

int int int int }; #define pcb_pc #define pcb_sp #define aston() #define astoff() #endif !LOCORE

pcb_cpflags; pcb_flags; pcb_wocnt; pcb_wucnt;

/* coprocessor enable flags */ /* various state flags */ /* window overflow count */ /* window underflow count */

pcb_regs.val[0] pcb_regs.val[1] {u.u_pcb.pcb_flags |= AST_SCHED;} {u.u_pcb.pcb_flags &= ~AST_SCHED;}

/* pcb_flags */ #define AST_SCHED #define AST_CLR #define PME_CLR #define AST_NONE /* pcb_flags */ #define CLEAN_WINDOWS #define FIX_ALIGNMENT #endif /*!_sun4m_pcb_h*/

0x80000000 0x80000000 0 0 0x1 0x2

/* force a reschedule */

/* keep user regs clean */ /* fix unaligned references */

Como vários processos podem compartilhar uma única CPU? O SO tem que assegurar que os processos não interfiram uns com os outros. Isto significa:
• •

garantir que todos os processos tenham acesso aos recursos, como memória e CPU: escalonamento controlar o estado dos processos, de tal modo que um processo não possa modificar arbitrariamente o estado de outro processo: proteção

Estados de um processo A qualquer instante, um processo pode estar em um dos seguintes estados (Fig. 2-2):
• • •

executando: utilizando a CPU de fato pronto (``ready''): executável; temporariamente parado enquanto outro processo executa bloqueado: não-executável até que um evento externo aconteça

O SO deve gerenciar as transições dos processos entre esses estados: escalonador (scheduler ou dispatcher). De onde surgem os processos? De outros processos. O sistema Unix tem uma primitiva (system call) fork que cria uma cópia do processo existente. Por exemplo, um shell Unix cria uma cópia dele mesmo

cada vez que você quer executar um programa. Uma cópia espera enquanto a outra executa o comando. Como o fork funciona:
• • • • •

garante que o processo que executou o fork não está executando garante que todo o estado do processo que executou o fork foi salvo faz uma cópia do código, dados e pilha copia o PCB do processo original no processo novo torna o novo processo conhecido para o escalonador

Problema: os dois processos são idênticos. Como fazer para executar um programa diferente?

exec : troca a imagem do programa corrente com o código e dados do novo programa

Um probleminha adicional: como é que tudo isso começa? No início não existe nenhum processo, portanto não é possível executar um fork .

Threads e Espaços de Endereçamento
Computações múltiplas compartilham um processador único através de processos. A abstração ``processo'' tem dois objetivos gerais: 1. permitir ao SO organizar e controlar múltiplas computações 2. prevenir processos de interferir uns com os outros Um processo pode ser imaginado como tendo dois componentes, cada um correspondendo a uma das necessidades acima: 1. Thread 2. Espaço de Endereçamento Ou seja, o componente Espaço de Endereçamento é utilizado para implementar isolamento, e o componente Thread é utilizado para implementar controle. O componente Espaço de Endereçamento inclui:
• •

a memória utilizada pelo programa; isto inclui o código e grande parte dos dados arquivos abertos

O componente Thread inclui:
• • • •

contador de programa registradores dados alocados na pilha (na maioria variáveis locais) endereços de retorno dos procedimentos ativos

Se olharmos o pcb :

o Espaço de Endereçamento é representado pela tabela de páginas (pcb_l1pt)

o estado da Thread é representado pelo resto

A maioria das estruturas proc e user são consideradas parte do Espaço de Endereçamento. Um processo "normal" (por exemplo ls ou cat em Unix) consiste de uma Thread e de um Espaço de Endereçamento. Threads múltiplas em um único Espaço de Endereçamento podem ser utilizadas para implementar concorrência dentro de um processo. Imagine que você tem um processo que serve requisições de I/O (por exemplo, um servidor de arquivos ou um sistema de bancos de dados):
• • •

quando uma thread solicita uma leitura, ela fica bloqueada até que os dados fiquem disponíveis um único processo com uma única thread não pode executar nada de útil enquanto o disco está sendo acessado com threads múltiplas, uma thread pode continuar a executar enquanto a outra espera pelo I/O

Threads compartilham:
• • •

memória arquivos abertos variáveis globais

Threads mantêm cópias privadas de:
• • •

pilhas contador de programa estado do processador

Threads são também chamadas de processos leves (lightweight processes), porque:
• • •

criação de threads é mais barato que criação de processos threads têm menos estado que processos, podendo ser gerenciadas de maneira mais eficiente comunicação entre threads é mais rápida/fácil do que comunicação entre processos

Diferentes sistemas operacionais apresentam diferentes modelos:
• • • •

um espaço de endereçamento, uma thread um espaço de endereçamento, múltiplas threads múltiplos espaços de endereçamento, uma thread por espaço de endereçamento múltiplos espaços de endereçamento, múltiplas threads por espaço de endereçamento

Escalonamento de Processos
(Tanenbaum 2.4) Estados de um Processo
• • • •

running blocked ready rever Fig. 2-2

Recursos
• • •

entidades ("objetos") sobre as quais processos operam ex.: tempo de CPU, espaço em disco podem ser: o preemptáveis o não-preemptáveis decisões sobre recursos o alocação o escalonamento

Escalonamento: aspectos de projeto
• •

escalonador e algoritmo de escalonamento critérios a satisfazer: o "fairness" (justiça) o eficiência o minimizar tempo de resposta o minimizar "turnaround" o maximizar "throughput" escalonamento preemptivo vs. não-preemptivo

FIFO (First-In-First-Out)
• • • •

processos executam até o fim resulta (geralmente) em uniprogramação alto grau de justiça problemas?

Round-Robin
• •

cada processo tem um quantum de tempo para executar fatores a considerar o tamanho do quantum o troca de contexto problemas?

Escalonamento com Prioridade
• • •

atribuição de prioridades diferentes a cada processo processo mais prioritário roda primeiro atribuição de prioridades pode ser: o estática o dinâmica problemas?

Filas Múltiplas
• •

classses de prioridades objetivos: o aumentar a eficiência o tratar diferentes tipos de processos, cada qual com suas necessidades problemas?

Shortest Job First
• • •

projetado para sistemas nos quais tempos de execução são conhecidos a priori minimiza tempo de resposta médio problemas?

Escalonamento Garantido
• • • • • • • • • • •

procura garantir um nível de performance mínimo para o usuário objetivo: dar a todos processos a mesma quantidade de CPU se existem N processos, cada um recebe 1/N de tempo da CPU tem que manter história de utilização da CPU para cada processo se um processo utilizou menos que sua parte, sua prioridade é aumentada se um processo utilizou mais que sua parte, sua prioridade é diminuida dá uma prioridade maior aos processos que utilizaram menos CPU num passado recente "jobs" altamente interativos (ex.: editor de textos) utilizam pouca CPU, portanto ganham alta prioridade "jobs CPU-bound" (ex.: simulações científicas) ficam com prioridade baixa formas alternativas de escalonamento garantido são necessárias em sistemas de tempo real problemas?

Escalonamento em Dois Níveis
• • • •

utilizado quando é necessário mover processos (executáveis) entre memória e disco nível mais alto decide quais processos ficam na memória e quais vão para o disco nível mais baixo decide qual processo, dentre os que estão na memória, vai utilizar a CPU problemas?

Política vs. Mecanismo
• • •

necessidade de separar os mecanismos de escalonamento das políticas de escalonamento algoritmo de escalonamento é parametrizado de alguma maneira processos dos usuários definem os parâmetros

Sumário

• •

algoritmos de escalonamento têm um grande impacto no "overhead" do sistema, na sua eficiência e no tempo de resposta de processos interativos os melhores esquemas são adaptativos; para ser ótimo é necessário prever o futuro os melhores algoritmos de escalonamento tendem a dar maior prioridade aos processos que utilizam menos recursos

Memória: Utilização e Alocação

Utilização da Memória
Informação armazenada na memória pode ser classificada de várias maneiras. Alguns exemplos:

Papel em linguagens de programação:
• • •

instruções: especificam as operações a serem executadas e seus operandos variáveis: a informação que muda à medida que o programa executa: locais, globais, parâmetros de procedimentos, memória dinâmica constantes: informação que é utilizada como operando, mas nunca muda; exemplo: pi, printf("esse string e constante\n");

Proteção:
• •

modificável leitura-apenas ("read-only")

executável

Inicialização

Endereço ou Dado Tempo de Ligação ("Binding Time"):
• • •

em que momento o espaço é alocado? em que momento deve-se decidir sobre o que vai aonde? existem duas alternativas: o alocação estática: decisões são tomadas uma vez, e para sempre, antes do programa começar a executar. Pode acontecer em tempo de compilação, tempo de ligação ("link time") ou tempo de carga ("load time") o alocação dinâmica: decisões não podem ser tomadas antes do tempo de execução ("run time"), e podem mudar

Note que as classificações podem se sobrepor: por exemplo, variáveis podem ser estáticas ou dinâmicas; código pode ser "read-only" ou "readwrite".

Quando um processo está executando, qual é o aspecto da memória?
• •

memória é dividida em áreas chamadas segmentos no UNIX, cada processo tem três segmentos: o código (chamdado "text" na gíria UNIX) o dados o pilha

Questões:
• •

como fazer se existe mais de um processo? aonde vai ficar o sistema operacional?

Segmentos

Porque distinguir entre segmentos diferentes?
• •

podemos querer alguns "read-only", outros "read-write" alguns são conhecidos em tempo de compilação, outros crescem ou diminuem à medida que o programa executa (dados estáticos vs. pilha)

Alocando memória aos segmentos

Divisão de responsabilidades entre várias partes do sistema:

Compilador: gera um arquivo-objeto para cada arquivo-fonte o cria os segmentos de código e dados para o arquivo-fonte o informação nesse arquivo-objeto está incompleta (porque?)

Ligador ("linker"): combina todos arquivos-objeto para um programa em um único arquivo-objeto, que está completo e auto-suficiente (i.e., todas referências resolvidas) Carregador ("loader"): sistema operacional carrega os arquivos-objeto na memória, permitindo que vários processos diferentes compartilhem a memória ao mesmo tempo. Deve prover recursos para que os processos obtenham mais memória depois que eles tiverem começado a executar Tempo de Execução ("run-time"): o ambiente de tempo de execução funciona junto com o sistema operacional para prover rotinas de alocação dinâmica de memória, tais como malloc e free em C

Ligadores (por exemplo, ld no UNIX) juntam várias partes separadas de um programa e reorganizam a alocação de memória. Em geral são considerados parte do sistema operacional. No UNIX, ld é um programa regular (usualmente invocado pelo compilador, por exemplo, cc).

Ligadores (Linkers)
Funções de um ligador
• •

coletar todos os arquivos e bibliotecas de um programa descobrir um nova organização de memória de tal modo que todas as partes fiquem organizadas juntas (combinar segmentos similares: agrupar segmentos de código; agrupar segmentos de dados) ajusta os endereços, de tal modo que o programa possa executar sob a nova organização de memória

Ligação: desafios

quando o compilador monta um único arquivo-objeto existem vários símbolos que ele não conhece (ex.: printf, sin) o se o compilador não pode identificar o símbolo, assinalar um 0 a ele o deixa a informação para o ligador o essa informação é chamada de cross-reference (referência cruzada) o referências cruzadas descrevem símbolos em outros arquivos o uma referência cruzada tem duas partes:  definição global: um arquivo fornece a variável ou procedimento que pode ser utilizada por outros arquivos  referência externa: um arquivo acessa uma variável ou procedimento que não está presente no arquivo compilador não sabe aonde os objetos que ele está compilando serão colocados na memória o assume que tudo começa no endereço 0 e deixa para o ligador consertar o informação incluída no arquivo-objeto diz ao ligador o que deve ser re-arranjado/consertado o essa informação é chamada de informação de relocação; ela descreve os símbolos no segmento local

Conteúdo dos arquivos-objeto

• •

• •

Cabeçalho do arquivo: para cada segmento, o arquivo-objeto contem o tamanho do segmento e seu endereço inicial quando carregado na memória Múltiplos segmentos, para código, dados inicializados, tabelas de importação etc. Tabela de símbolos: uma tabela com uma entrada para cada símbolo (função, variável etc.) definido no módulo, com informação sobre a definição do objeto de memória correspondente (endereços, tipo, tamanho etc.). Essa informação é utilizada para traduzir do nome para o objeto propriamente dito Informação de relocação: informação sobre referências cruzadas que o ligador tem que consertar: o onde estão as referências cruzadas? o a quais símbolos elas se referem? o como o endereço deve ser arrumado? 1. armazena o endereço do símbolo 2. soma o endereço do símbolo 3. soma a quantia que o símbolo se moveu o símbolos externos: objetos que não são parte do módulo corrente o símbolos internos: o compilador atribuiu um endereço, mas este endereço pode mudar se o ligador mover algum objeto Informação de depuração Para mais informação sobre esse assunto, ver livros sobre os formatos COFF ou PE, ou ler a "man page" do UNIX que descreve o formato do arquivo a.out

Ligador: funcionamento

Tem que dar vários passos; não é possível terminar sem ter lido todos arquivos.

Passo 1 o ler toda informação da tabela de símbolos o decidir como a memória será rearranjada o ler toda informação de relocação o descobrir tudo que for necessário nas bibliotecas Passo 2 o ler os segmentos e informação de relocação o modificar os endereços o escrever o novo módulo com símbolos, segmentos, e relocação

A tabela de símbolos armazena informação sobre os símbolos e, em alguns casos, sobre os segmentos:
• •

segmentos: nome, tamanho, endereço símbolos: nome, segmento que contem o símbolo, deslocamento dentro do segmento

Tipicamente, algum algoritmo de "hashing" é utilizado para associar os nomes às informações.

Ligador: Exemplo
Programa Principal
main () { static float x, val; extern float sin(); extern printf(), scanf(); printf("Type number: "); scanf("%f", &x); val = sin(x); printf("Sine is %f\n", val); }

Módulo matemático
float sin(x) float x; { static float tmp1, tmp2, result; // calcula função seno aqui return (result); }

Biblioteca C
printf (...) { ... } scanf (...) { ... }

Sumário

Passo 1:
• •

assinala endereços dos segmentos de entrada para poder completar os segmentos de saída nenhuma informação precisa ser carregada na memória nesse ponto, exceto informações sobre os símbolos

Passo 2:
• • •

lê dados e informação de relocação dos arquivos corrige os endereços escreve o novo arquivo-objeto

Que tipo de mudanças devem ser feitas em tempo de ligação?
• • •

move r1, @X (X é externo) call sin (sin é externo) jmp @X (X no mesmo segmento original)

br x (X no mesmo segmento original, deslocamento curto)

Monoprogramação
Até agora vimos como a memória é vista do ponto de vista do programa do usuário. A partir de agora vamos ver como o S.O. vê (e gerencia) a memória.

Todos os processos são ligados assumindo que o endereço inicial é 0. Como carregá-los na memória? A solução mais simples é utilizar monoprogramação:
• • • • •

• • •

somente um processo por vez na memória colocar o S.O. na parte mais alta da memória, num endereço fixo, conhecido colocar o processo no endereço 0, do mesmo modo como ele é ligado colocar a pilha logo abaixo do S.O. como não existem outros processos na memória, não é possível corrompê-los (mas é possível corromper o S.O.; tudo vai parar de funcionar: reboot) os primeiros "monitores" batch utilizaram esse sistema; alguns PCs ainda usam algo parecido esse esquema não é aceitável para sistemas "time-sharing" aliás, também não é bom para PCs

Então, quais são os objetivos para um bom gerenciamente da memória pelo S.O.?
• • • • •

permitir que vários processos co-existam na memória nenhum processo deve ter conhecimento deste compartilhamento (i.e., o mecanismo deve ser transparente) todos processos devem executar, independente do número e posicionamento dos outros processos na memória processos devem ser impedidos de corromper outros processos (proteção) o compartilhamento da memória deve ser eficiente; nem a performance da CPU, nem a da memória devem degradar em função do compartilhamento (afinal de contas, o objetivo de compartilhar é aumentar a eficiência)

Multiprogramação com Partições Fixas
Ou: Relocação Estática
• •

como antes, colocar o S.O. numa posição fixa da memória (por exemplo, na parte mais alta) do mesmo modo que na compilação, temos o problema de não saber aonde um processo vai residir na memória (se tivermos mais de um processo na memória ao mesmo tempo)

• •

do mesmo modo que na compilação, deixamos para "consertar" os endereços mais tarde quando um processo é carregado, "relocar" ele na memória, de maneira similar ao funcionamento do ligador; todos os endereços ficam relativos a um ponto fixo na memória

Quais são os problemas?
• • • • •

nenhuma proteção (eu posso corromper sua memória) qualquer um pode corromper o S.O. (e isso vai afetar outros processos) processos podem ser movidos depois que começaram a executar? processos podem mudar de tamanho? exemplo: IBM/360 OS/MFT

Processos no Unix

Processos no Unix (Tanenbaum 7.3.1)
• •

• • • •

processos sequenciais com uma única linha (thread) de controle daemons: processos em background que sempre estão executando: o cron o mail o printer o finger FORK: chamada de sistema para criar processos: o processo parent: FORK retorna PID > 0 (PID do filho) o processo child: FORK retorna PID = 0 PID é o identificador do processo arquivos abertos são compatilhados GETPID: retorna o PID do processo chamador uso de FORK pelos filhos possibilita criar uma árvore de processos

Exemplo de uso de FORK e PID:
pid = fork(); if (pid < 0) { /* se o fork tiver sucesso, pid > 0 no pai */

/* fork falhou, em geral por falta de memoria */ } else if (pid > 0) { /* codigo do pai entra aqui */ } else { /* codigo do filho entra aqui */ }

Inicialização do sistema: Figura 7-6 Comunicação entre processos
• •

é implementada através de troca de mensagens (pipes) e de interrupções de software (signal)

Signal
• •

• •

um processo pode enviar um signal para outro processo processo pode informar ao sistema o que fazer se um signal chegar: o ignorar o sinal o capturar o sinal (catch) o deixar o sinal matar o processo (kill) se o processo aceitar o sinal ele tem que prover um procedimento de manipulação do sinal (signal handling procedure) um processo só pode enviar um sinal para processos do seu process group: ascendentes, irmãos e descendentes.