algumas noções importantes -...

40
2. Principais conceitos Neste capítulo serão abordados diversos tópicos centrais em sistemas operacionais, a saber: o que é um processo, como a memória é tratada pelo S.O. e o que são arquivos. Outro elemento importante apresentado é o shell. Vamos investigar também as funconalidades e a estrutura de sistemas operacionais, bem como discutir um elemento relativamente recente no cenário computacional, a máquina virtual. Algumas noções importantes Processos Um processo é um programa em execução, e este é constituído por diversos elementos, entre eles o seu código executável, os dados utilizados por este código, a pilha de execução, o valor dos registradores, manipuladores (handlers) de arquivos abertos por este processo, etc. O sistema operacional mantém internamente uma tabela dos processos em execução. Isto permite que o núcleo do S.O. possa empregar políticas de escalonamento de processos para permitir que diversos processos possam compartilhar da uma mesma CPU, dando ao usuário a ilusão de que estes diversos processos estão todos sendo executados simultanemente. Um processo pode criar mais processos, chamados de processos filhos, e que podem por sua vez também criar seus processos filhos. Tipicamente um S.O. oferece diretivas que permitem ao desenvolvedor programar um processo de tal modo que ele em um determinado momento crie novos processos. Outro aspecto importante é a capacidade dos processos de poderem trocar dados entre sí. Esta capacidade é implementada pelo núcleo através de um conjunto de rotinas específicas para este fim. Por último, quando estão sendo executados, dois ou mais processos podem entrar em uma situação de disputa por necessitarem acessar um mesmo recurso. Este tipo de situação pode levar a impasses que podem comprometer até a estabilidade do sistema como um todo. O sistema

Upload: ngodieu

Post on 17-Dec-2018

212 views

Category:

Documents


0 download

TRANSCRIPT

2. Principais conceitos

Neste capítulo serão abordados diversos tópicos centrais em sistemas operacionais, a saber:

o que é um processo, como a memória é tratada pelo S.O. e o que são arquivos. Outro elemento

importante apresentado é o shell. Vamos investigar também as funconalidades e a estrutura de

sistemas operacionais, bem como discutir um elemento relativamente recente no cenário

computacional, a máquina virtual.

Algumas noções importantes

Processos

Um processo é um programa em execução, e este é constituído por diversos elementos, entre

eles o seu código executável, os dados utilizados por este código, a pilha de execução, o valor dos

registradores, manipuladores (handlers) de arquivos abertos por este processo, etc.

O sistema operacional mantém internamente uma tabela dos processos em execução. Isto

permite que o núcleo do S.O. possa empregar políticas de escalonamento de processos para permitir

que diversos processos possam compartilhar da uma mesma CPU, dando ao usuário a ilusão de que

estes diversos processos estão todos sendo executados simultanemente.

Um processo pode criar mais processos, chamados de processos filhos, e que podem por sua

vez também criar seus processos filhos. Tipicamente um S.O. oferece diretivas que permitem ao

desenvolvedor programar um processo de tal modo que ele em um determinado momento crie

novos processos.

Outro aspecto importante é a capacidade dos processos de poderem trocar dados entre sí.

Esta capacidade é implementada pelo núcleo através de um conjunto de rotinas específicas para este

fim.

Por último, quando estão sendo executados, dois ou mais processos podem entrar em uma

situação de disputa por necessitarem acessar um mesmo recurso. Este tipo de situação pode levar a

impasses que podem comprometer até a estabilidade do sistema como um todo. O sistema

operacional deve implementar mecanismos de controle de acesso a recursos que impeçam e

resolvam situações de impasse desta natureza.

Memória

Em sistemas operacionais mais primitivos, como o MS-DOS, somente um processo por vez

poderia residir na memória. Já em sistemas operacionais modernos vários programas podem residir

na memória principal simultaneamente. Em função disto, mecanismos para proteger o acesso a

memória devem ser implementados no S.O., para impedir, por exemplo, que um processo possa

modificar o conteúdo de posições de memória pertencentes a outro processo.

A alocação da memória também é uma das atribuições do sistema operacional. Quanto de

memória cada processo vai ganhar e onde na memória estes processos vão ser efetivamente

colocados são decisões exclusivas do S.O.

Um mecanismo importante implementado por quase todos os sistemas modernos é o de

memória virtual que permite que parte da memória secundária (parte da área disponível no disco

rígido, por exemplo) possa ser usada como uma extensão da memória principal. Para os processos

este ganho extra de memória é transparente, e todas as questões envolvidas são gerenciadas pelo

núcleo do sistema.

Arquivos

A persistência dos dados é obtida até os dias atuais através do armazenamentos dos dados (e

também dos programas) em dispositivos de armazenamento secundário. O sistema operacional

costuma oferecer uma interface amigável para que estes dados possam ser organizados, nomeados e

acessados nestes dispostivos de memória de massa. O conceito de arquivo é resultado do

mapeamento de um conjunto de dados (que pode ser um programa) para esta unidade de

armazenamento secundário.

Dentro deste contexto, o conjunto de rotinas que oferece estas funcionalidades faz parte de

um módulo do kernel denominado sistema de arquivos. Como exemplo, pode-se tomar o NTFS,

que é a denominação do sistema de arquivos do sistema operacional Windows NT, 2000, XP, Vista

e Windows 7.

A organização dos arquivos é alcançada através da implementação no dispositivo de massa,

por parte do sistema de arquivos, de uma árvore de diretórios, permitindo o arranjo hierárquico

destes dados. Um diretório (ou pasta) é um elemento que identifica um conjunto de arquivos e/ou

diretórios.

Resumidamente, as rotinas de um sistema de arquivos devem permitir:

criar e apagar arquivos

criar e apagar diretórios

permitir a manipulação de arquivos e diretórios

permitir mapear arquivos em armazenamento secundário

oferecer rotinas para backup e manutenção do volume

As funcionalidades básicas de um sistema operacional

As principais funcionalidades oferecidas por um sistema operacional moderno são:

gerência do processador

gerência da memória

gerência de E/S

sistema de arquivos

gerência de segurança

Cada uma destas funcionalidades será abordada em capítulos subsequentes deste livro.

Entretanto, um pequeno resumo sobre cada uma delas é apresentado a seguir.

Gerência do processador

Esta funcionalidade tem como objetivo distribuir o tempo do processador entre os diversos

processos em execução.

Esta distribuição não é igualitária, pois tipicamente os processos possuem prioridades de

execução diferentes, o que faz com que um processo possa receber uma fatia maior de tempo da

CPU em detrimento de outros processos que possuam prioridade menor.

Outro aspecto importante é que o sistema operacional deve prover a ilusão de que existe um

processador independente para cada processo, simplifando a programação das aplicações.

A sincronização dos processos, de tal modo que situações de disputa por recursos sejam

resolvidas, e a comunicação entre os processos, para permitir a troca de dados entre estes, também

são mecanismos que devem ser providos pelo módulo de gerência do processador.

Gerência de memória Para cada processo deve ser provida uma região de memória própria, autônoma e

independente de outros processos. Isto gera um grande aumento na estabilidade e segurança do

sistema como um todo, porque não permite que processos possam se interferir uns aos outros.

O gerente de memória tem ainda como atribuição a reserva (ou alocação) de memória aos

processos. A medida que um processo executa, sua demanda por memória pode aumentar ou

diminuir. Isto faz com que novas porções de memória livre (não utilizada por outros processos)

tenham que ser encontradas e associadas ao processo ou então que este tenha deixado de usar

regiões de memória que agora podem ser liberadas (desalocadas).

Caso a memória RAM disponível não seja suficiente para a execução dos processos, o

sistema operacional pode “aumentá-la” de maneira transparente recorrendo ao espaço disponível em

memória de massa (como o disponível em um HD, por exemplo). O mecanismo que responde a este

tipo de funcionalidade é denominado de memória virtual.

Gerência de E/S

Cada dispositivo de E/S (periférico) possui características bem particulares no que diz

respeito a forma como deve ser acessado. Em função disto, a maneira como é realizado o acesso ao

dispositivo X pode ser completamente diferente da forma como deve ser feito o acesso ao

dispositivo Y. Mesmo assim, há várias questões comuns em relação ao acesso aos periféricos. Um

grupo de dispositivos pode ter em comum o fato de terem de suportar operações de escrita e leitura,

que são implementadas de formas diferentes para cada um deles através de seus drivers específicos.

Em linhas gerais, o papel do gerente de E/S é implementar a comunicação com cada

dispositivo através destes drivers de dispositivo.

Sistema de arquivos

O sistema de arquivos trabalha em conjunto com o gerente de E/S e tem como meta

possibilitar a criação e o manuseio de arquivos e diretórios, definindo uma interface única de

acesso.

A forma como os arquivos e diretórios são organizados no volume (ou partição) do

dispositivo de memória de massa também é uma das principais responsabilidades do sistema de

arquivos. Além disso, este módulo pode oferecer diversos outras funcionalidades extras, como o

ciframento automático dos dados, mecanismos de auditoria, compactação dos dados e assim por

diante.

Gerência de segurança

O objetivo da gerência de segurança é proteger os recursos do sistema contra acessos

maliciosos e indevidos. Para alcançar esta meta, diversos mecanismos devem ser implementados

para permitir que o sistema possa saber quais usuários estão conectados, o que cada um deles pode

acessar dentro do sistema e de que modo este acesso pode ocorrer e além disso manter um histórico

de tudo aquilo que é realizado pelo usuário enquanto este estiver conectado ao sistema.

Algumas funcionalidades adicionais

Pode-se citar como funcionalidades adicionais aquelas que não são imprescindíveis para que

os usuários possam usar o sistema e executar programas. Entretanto, diversas funções foram

surgindo ao longo da evolução dos sistermas operacionais e hoje são parte integrante da maioria dos

sistemas modernos. Entre estas funções cabe destacar:

o suporte a comunicação de dados (rede)

interface gráfica do usuário (GUI – Graphical User Interface)

recursos extras de segurança, como firewalls e anti-vírus

gerência de energia

suporte a contéudo multimídia

suporte a navegação na web

A estrutura de um sistema operacional

Um sistema operacional é composto de vários componentes com objetivos e funcionalidades

complementares. Alguns dos elementos mais importantes de um sistema operacional são:

Núcleo (ou kernel)

Este é o principal módulo do sistema operacional, pois é responsável pela gerência dos

recursos do hardware usados pelos programas. No núcleo normalmente estão implementadas as

rotinas responsáveis pela gerência do processador, pela gerência de memória, controle de acessos,

etc.

Drivers de dispositivo

Os drivers de dispositivo controlam e viabilizam o acesso aos dispositivos físicos.

Tipicamente há um driver para cada tipo de dispositivo e este é desenvolvido pelo fabricante do

hardware e fornecido para ser conectado ao restante do sistema operacional.

Bibliotecas do sistema

As bibliotecas do sistema são compostas por conjuntos de rotinas pre-compilados e que

podem ser usados por programas desenvolvidos pelo usuário, por exemplo. \possuem tipicamente a

extensão .lib ou .dll (no windows).

Shell ou interpretador de comandos

É através deste software que o usuário pode emititr comandos para o sistema operacional. O

interpretador de comandos é um programa que analisa aquilo que foi digitado pelo usuário e em

funçaõ do resultado desta analise executa alguma ação específica.

Nos S.O. modernos, o ambiente de janelas disponibilizado através da interface gráfica do

usuário permite que o usuário empregue a abordagem de apontar e clicar (com o mouse) para

invocar serviços do sistema operacional, ao invés de ter que digitá-los.

Programas utilitários

Estes programas facilitam a execução de atividades rotineiras, além de implementarem

diversas funcionalidades de administração do sistema, como cadastro de usuários, formatação de

memória de massa, etc.

Figura 6: a estrutura de um sistema operacional

Principais arquiteturas de sistemas operacionais

Ao longo da evolução dos sistemas operacionais surgiram três diferentes tipos de

arquiteturas que se tornam mais populares e que merecem destaque, a saber: a arquitetura

monolítica, a arquitetura em camadas e a arquitetura de micro-núcleo. Cada uma destas arquiteturas

é discutida a seguir.

Arquitetura monolítica

Neste tipo de arquitetura, os componentes do núcleo podem todos se intercomunicar se

barreiras de nenhum tipo. Todos os elementos do kernel tem acesso irrestrito a todos os recursos

oferecidos pelo hardware. O ponto positivo desta abordagem aparentemente simples é o baixo custo

de execução, propiciando desta forma um bom desempenho. Esta comunicação direta entre

componentes torna os sistemas monolíticos bastante enxutos.

Entretanto estes sistemas apresentam duas desvantagens, que são a falta de estabilidade e a

complexidade no seu desenvolvimento. A falta de estabilidade é devida ao fato de que se todos

componentes podem se comunicar livremente, e são na prática fortemente acoplados

(interdependentes), quando um componente falhar vários outros componentes serão afetados, o que

irá comprometer a execução do sistema como um todo.

Como a tendência neste tipo de arquitetura é os componentes do núcleo exibiram um alto

grau de interdependência, quando um novo componente é projetado ou um antigo é modificado, isto

pode afetar todos outros componentes, o que provavelmente irá exigir altereções nestes outros

componentes.

Os primeiros sistemas operacionais eram completamente monolíticos. Atualmente esta

tendência está superada, só permanecendo significativa nos sistemas operacionais de tempo real e

voltados para sistemas embarcados.

Arquitetura em camadas

Para contornar os problemas apresentados pela arquitetura monolítica, um sistema

operacional pode fazer uso de uma estrutura em camadas.

O nível mais baixo é responsável pela interface com o hardware (é a camada inferior). As

camadas intermediárias fornecem os serviços de gerência, enquanto que na camada superior estão

definidas as interfaces para as aplicações. Estas interfaces são provem o suporte às chamadas de

sistema (system calls). Uma chamada de sistema é tipicamente uma solicitação de recurso por parte

de um processo.

Pode-se apontar algumas desvantagens nesta abordagem. Por exemplo, uma requisição de

um processo demora mais tempo para chegar até o dispositivo periférico ou ao recurso a ser

acessado, deteriorando o desempenho do sistema. Além disto a definição de quais serviços irão

pertencer a quais camadas também pode ser uma questão bastante complexa.

É muito comum a implementação de uma camada inferior de abstração do hardware para

interagir com os dispositivos de E/S. Esta camada é mais conhecida como HAL (Hardware

Abstraction Layer).

Arquitetura de micro-núcleo

Outra forma de estruturação é manter no núcleo somente o código de baixo nível necessário

para a interação com os dispositivos e manter o código de alto nível, onde estão implementados os

gerentes de recurso, fora do kernel, como se fossem processos que se comunicam utilizando as

primitivas fornecidas pelo kernel.

A decorrência natural desta abordagem foi o surgimento dos micro-kernels, que implementa

somente a noção de atividade, de espaços de memória protegidos e de comunicação entre

atividades. Os sistemas Mach e Chorus são exemplos dessa abordagem.

Máquina Virtual

É utilizada uma cópia fiel do hardware de tal modo que se possa ter um ambiente completo

para execução do programa. É possível executar mais de uma máquina virtual em um mesmo

hardware ou então criar diferentes máquinas para hardware distintos mantendo acima dela uma

única interface.

Um exemplo de máquina virtual muito empregado hoje em dia é a JVM (Java Virtual

Machine), desenvolvida pela empresa Sun MicroSystems na década de 90.

3. Gerência de Processos

Serão explorados neste capítulo tópicos relativos à gerência de processos, abarcando as

políticas de escalonamento de processos (os principais algoritmos e estudos de caso) bem como o

uso de semáforos, monitores, etc. São também abordados alguns problemas clássicos como o do

jantar de filósofos e do produtor/consumidor.

A evolução da gerência de processos

O processador deve executar todos os processos disparados pelos usuários. Estes processos

tem desempenho, duração de execução e prioridades diferentes entre si. É responsabilidade do

sistema operacional organizar os processos de tal forma a executá-los da melhor forma possível,

otimizando o uso do processador e da memória. Iremos explorar a organização básica do sistema de

gerência de processos e um pouco de sua evolução.

Sistemas mono-tarefa

Os primeiros ambientes computacionais executavam apenas um processo de cada vez. Um

exemplo de sistema mono-tarefa é o sistema operacional MS-DOS, que equipou a primeira geração

de computadores pessoais da IBM. Nestes sistemas, cada processo era lido do disco para a memória

principal e executado até sua conclusão. Os dados de entrada eram lidos na memória junto com o

processo e os resultados da computação eram gravados de volta no disco durante e após a execução

do processo.

Sistemas multi-tarefa

Sistemas que suportam a execução de mais de um processo concorrentemente são

denominados multi-tarefa. Esta característica implica na implementação de diversos mecanismos

como um escalonador de processos e gerência de memória.

Num sistema multi-tarefa deve ser possível permitir ao processador suspender a execução de

um processo para passar a executar um outro processso. Além disso deve ser possível para o kernel

reativar um processo suspenso, a partir do ponto onde foi interrompido. Retirar do processo o

acesso a um é denominado de preempção. Isto bloqueia ou suspende um processo. Sistemas

operacionais que implementam este mecanismo são chamados de sistemas preemptivos.

Estados de um processo

Os estados e transições do ciclo de vida de um processo possuem os seguintes significado:

Novo : o processo está sendo criado; as suas áreas (text, data, stack e heap) em memória

estão sendo montadas.;

Pronto : o processo está na memória, pronto para executar (ou para prosseguir sua

execução), esperando a disponibilidade do processador. Todas processos prontos são

organizados em uma fila gerenciada por algum algoritmo de escalonamento;

Executando : a CPU está executando o processo;.

Bloqueado ou Suspenso : o processo não pode executar porque depende de dados ainda não

disponíveis (do disco ou da rede, por exemplo), ou então espera por sincronização (o fim de

um processo ou a liberação de algum recurso compartilhado);

Terminado : A execução do processo foi encerrada e este será removido da memória.

terminar

criar

novo executando

preemptar

bloquear r

d

pronto

continususpender

lPronto e suspenso

Figura 7: estad

Observações importantes sobre pr

Os sistemas operacionais modernos

corresponde à execução de um programa seqüe

do processo. Desta forma o processo deve

empregados por uma ou mais tarefas para sua

mecanismos de proteção providos pelo hardwar

criados e destruídos e estas operações são oferec

A criação de processos no S.O. UNIX g

medida que processos são criados, é gerada uma

Cada fluxo de execução do sistema, no

denominado thread. Threads executando den

executa

esbloquear bloqueado

continuar suspenderar

iberar Bloqueado e

suspenso

os de um processo

ocessos

associam uma tarefa a cada processo, o que

ncial, ou seja, um fluxo único de instruções dentro

ser encarado como um repositório de recursos

execução. Os processos são isolados entre si pelos

e e pelo gerente de processos. Processos podem ser

idas aos aplicativos através de system calls.

era um esquema hierarquico entre os processos. À

árvore de processos.

interior do kernel ou associado a um processo é

tro de um processo são chamados de threads de

usuário (user-level threads) enquanto que threads gerenciadas pelo kernel são denominadas de

threads de núcleo (kernel-level threads).

Escalonamento de processos

Este componente do kernel decide a ordem de execução dos processos prontos. O algoritmo

utilizado no escalonador caracteriza o comportamento do sistema operacional.

Os principais fatores a serem levados em conta na escolha ou projeto de um escalonador de

processos são:

Percentual de utilização do processador

Throughput, que é a quantidade de processos completados por unidade de tempo

Turnaround, tempo total de execução de um processo, desde sua criação até seu término

Tempo de espera de um processo na fila de processos prontos para execução

Tempo de resposta, que é o tempo que o processo leva para produzir resposta a uma

determinada requisição

O escalonador de um sistema operacional pode ser preemptivo ou não-preemptivo. Num

escalonador preemptivo um processo pode perder o processador caso termine seu quantum (sua

fatia) de tempo, ou então execute alguma system call ou se ocorrer uma interrupção que redispare

um processo de maior prioridade. Num escalonador não-preemptivo, o processo execução

permanece com a CPU enquanto precisar, somente a abandonando caso termine de executar ou

então requisite uma operação de entrada/saída ou libere explicitamente o processador, voltando

para a fila de processos prontos.

Os principais algoritmos de escalonamento de processos são:

FCFS (First-Come, First Served) : atende os processos em seqüência, à medida em que estes

se tornam prontos.

SJF (Shortest Job First) : gera os menores tempos médios de execução e de espera; consiste

em atribuir a CPU à menor (mais curta) tarefa da fila de tarefas prontas. Mas fica o

problema de como estimar a duração de um processo. Por causa disto, este algoritmo é

pouco utilizado. No entanto, ao associado à preempção por tempo, esse algoritmo pode ser

de grande ajuda.

Escalonamento com prioridade : no escalonamento por prioridades, cada processo é

associado a uma prioridade, geralmente um número inteiro. Os valores de prioridade são

então usados na escolha da próxima tarefa a receber a CPU, a cada troca de contexto.

Mecanismos de comunicação

As formas mais usuais de comunicação inter- processos são:

compartilhamento de memória: dois ou mais processos compartilhando a mesma variável,

por exemplo;

mail boxes (caixas postais): processos depositam e retiram mensagens de um determinado

tipo de dados; processo é suspenso se tenta depositar uma mensagem num mailbox cheio ou

tenta retirar mensagem de uma mail box vazia;

passagem de mensagens

chamada remota de procedures

Exemplos de diferentes formas de comunicação entre processos:

No UNIX (pipeline): C1 | C2 ( a saída de C1 é a entrada de C2)

Ex.: ls -la | grep joao

C1 e C2 são executados concorrentemente

se há + de 1 CPU : multiprocessamento (C1 na CPU1 e C2 na CPU2)

com 1 CPU: multiprogramação

No MS-DOS : C1 | C2 ( a saída de C1 é a entrada de C2, mas 1o é executado C1, então a

saída vai para um arquivo temporário, só então inicia a execução de C2, lendo este arquivo

temporário).

Equivale a:

C1 > f

C2 < f comandos seqüenciais; não há concorrência

4. Gerência de Entrada e Saída

Neste capítulo são apresentados os recursos que um sistema operacional deve oferecer para

gerenciar a entrada e saída de dados do computador. Neste aspecto, um tópico de interesse abordado

é o da políticas de escalonamento de acesso, e neste contexto é examinado o caso particular do

escalonamento de acesso em discos rígidos.

Os dispositivos de entrada permitem ao computador acessar informações do mundo externo

que são por sua vez codificadas para poderem ser processadas pela CPU. Uma das

responsabilidades do sistema operacional é gerenciar o acesso aos periféricos por parte de processos

que estão sendo executados no computador. Isto é obtido através de um conjunto de rotinas e

métodos de acesso implementados e oferecidos pelo sistema operacional.

Um periférico é um elemento de hardware conectado através de um barramento de E/S ao

computador. O barramento permite que dados possam trafegar entre o computador e o periférico.

Existe uma gama bastante variada de periféricos, desde aqueles especializados em capturar

informações externas, como o movimento do usuário, por exemplo, até aqueles que representam a

informação para o usuário num formato específico, como um monitor de vídeo, passando por

aqueles periféricos que simplesmente armazenam as informações de forma persistente, como discos

rígidos.

Foram desenvolvidas até hoje algumas formas diferentes para que periféricos se

comuniquem com o computador. Diferentes periféricos tipicamente irão empregar diferentes

métodos de comunicação.

Dois elementos merecem destaque quando se aborda um esquema de comunicação

computador-periférico. São a interface de comunicação e o controlador do dispositivo.

A interface é a parte do periférico que se conecta diretamente ao barramento de E/S. Um

componente associado a interface é o controlador, que geralmente é um processador especializado

no controle do dispositivo específico. A comunicação com o controlador se dá através de um

conjunto de registradores (espaços de memória) empregados para armazenar informações enviadas

de ou para a CPU. Como exemplo, a CPU coloca nos registradores do controlador os comandos que

este deve realizar junto ao dispositivo.

Existem dois tipos principais de interfaces: a serial e a paralela. A interface serial trabalha

com somente uma linha de transmissão da informação, e um dado é transmitido então sempre um

bit a cada vez. A interface paralela possui várias linhas de transmissão, possibilitando que vários

bits sejam transmitidos simultaneamente.

O acesso aos registradores do controlador pode-se dar por meio de duas formas: ou a E/S é

mapeada em espaço de E/S ou então ela é mapeada em memória.

Com mapeamento em espaço de E/S, a CPU emprega instruções especiais para manipular os

registradores dos periféricos. Neste caso, existem 2 espaços de endereçamento: o espaço que

corresponde a memória principal e o espaço de E/S, que corresponde aos registradores dos

dispositivos. No mapeamento em memória só há um espaço de endereçamento, sendo que alguns

endereços específicos irão corresponder a registradores dos periféricos.

Existem basicamente três maneiras da comunicação ser implementada entre a CPU e os

dispositivos, não importando o tipo de mapeamento empregado.

O primeiro tipo é a E/S programada, onde toda troca de dados é de responsabilidade do

processo, devendo portanto ser implementada pelo programador, de modo que o programa em

execução transmita comandos para o dispositivo e em seguida aguarde o término da operação por

parte deste.

A desvantagem desta abordagem é que o processo pode ter que ficar esperando muito tempo

pelo dispositivo, resultando num desperdício. Uma alternativa seria de tempos em tempos verificar

se o dispositivo concluiu suas operações, abordagem denominada de polling.

O segundo tipo é a comunicação através de interrupções, que são geradas pelo dispositivo

para avisar a CPU de que as operações requisitadas foram concluídas. Neste modo, a CPU não

precisa realizar polling, ficando liberada para outras tarefas.

Quando implementadas em harware, um controlador de interrupção (como o PIC-

Programmable Interrupt Controller) pode estabelecer a via de comunicação entre o dispositivo que

gera a interrupçaõ e a CPU, permitindo o roteamento (isto é, a multiplexação) das interrupções

causadas por diversos dispositivos para uma única CPU, por exemplo. Se as interrupções forem

implementadas como parte do gerenciador de memória, elas podem ser então mapeadas para dentro

do espaço de endereçamento de memória do sistema.

Uma interrupção é denominada mascarável quando se trata de uma interrupção de hardware

que pode ser ignorada pelo processador (se isso for coveniente para um processo em específico). As

interrupt requests (IRQs) são interrupções deste tipo. Interrupções não-mascaráveis (NMI) nunca

podem ser ignoradas pelo processador, sendo empregadas na implementação de temporizadores, por

exemplo.

Já uma interrupção de software é gerada a partir de uma instrução pertencente a um

processo. As chamadas do sistema (system calls) são implementadas através de interrupções de

software. Uma chamada do sistema desvia a execução para o início da rotina que trata aquela

interrupção em particular.

O último tipo é o Acesso Direto à Memória, conhecido pela sigla DMA, quando a interface

do dispositivo consegue transferir os dados diretamente para a memória, não havendo envolvimento

direto da CPU.

Um dos principais módulos do sistema operacional é o subsistema de E/S, responsável pelo

gerenciamento da comunicação com os diversos periféricos conectados ao computador. Este

módulo é estruturado em diversas camadas. A camada inferior realiza a interação com o hardware

dos dispositivos através dos drivers de dispositivo, empregando mecanismos como interrupções e

DMA, por exemplo.

Esta organização em camadas permite que o restante do sistema operacional não se

preocupe com os detalhes da interação com os diferentes tipos de dispositivos existentes. Esta

camada inferior fornece às camadas superiores uma série de serviços que padronizam o acesso aos

periféricos.

Esta padronização levou a classificação dos dispositivos em função da forma como os dados

são transmitidos. Temos dois principais grupos de dispositivos:

dispositivos orientados a caracter

dispositivos orientados a bloco

Os dispositivos orientados a caracter realizam a transmissão caracter a caracter, transmitindo

um byte por vez, enquanto que os dispositivos orientados a bloco transmitem um conjunto de bytes

de tamanho fixo.

Figura 8: tipos de dispositivo

A camada imediatamente acima usa os serviços disponibilizados pelos drivers e pode ser

considerada “independente de dispositivo”. Esta camada implementa funções genéricas (pois

servem para qualquer periférico) e serviços gerais de E/S, importantes para o funcionamento do

sistema.

Alguns destes serviços são:

gerência de buffer: quando é necessário controlar um buffer onde dados serão

armazenados temporariamente pois o dispositivo não consegue lidar toda a informação se

esta for enviada de uma só vez.

cache de dados: gerência do armazenamento na memória daqueles dados mais

freqüentemente acessados.

alocação de dispositivo: alguns periféricos (como a impressora, por exemplo)

admitem somente um usuário por vez. Esse controle é feito através da técnica de spooling,

que consiste em seqüencializar os pedidos de acesso e atendê-los um por um. Os pedidos de

acesso são registrados em uma fila especial (chamada fila de spool), que é acessada por um

tipo específico de processo chamado de daemon e que atende as requisições de E/S.

controle de acesso: Nem todos os usuários podem acessar os dispositivos da mesma

forma e é reposabilidade do SO garantir essa proteção.

escalonamento de E/S: para dispositivos compartilhados por vários processos (como

HDs), visando melhorar seu desempenho .

tratamento de erros: O software de E/S deve ser capaz de tratar erros, informando à

camada superior o sucesso ou o fracasso das operações de E/S.

Para o usuário, o acesso a operações de entrada e saída é disponibilizado através das rotinas

existentes nas linguagens de programação empregadas na implementação dos programas.

O programador utiliza comandos de E/S de alto nível (por exemplo, a função printf ( ) ou

scanf ( ) da linguagem C para E/S formatada de dados), que são traduzidos para um código que

contém chamadas para rotinas de uma biblioteca de E/S padrão implementadas pelos fabricantes do

compilador da linguagem.

Estudo de caso: o disco rígido

Vamos ver agora as particularidades dos mecanismos de E/S de um periférico muito

importante num computador pessoal: o HD ou disco rígido.

Os discos rígidos são meios de armazenamento de memória em massa, sendo constituídos

por uma parte mecânica e uma parte eletrônica. Os dados são armazenados em um ou mais discos

magnéticos rígidos.

Os principais componentes de um HD são o disco mecânico, a cache e a interface de

comunicação.

Figura 9: a estrutura básica de um disco rígido

Um HD pode ser composto por uma série de pratos sobrepostos. Cada prato possui duas faces

graváveis. Em cada face os dados são gravados numa série de trilhas concêntricas. Cada trilha é

dividida em blocos denominados setores, capazes de armazenar 512 bytes.

A cache é um buffer de memória que existe dentro do HD e sua função é armazenar

temporariamente os dados provenientes do computador.

A interface é a parte do HD responsável pela conexão com o barramento do sistema, e

associada ao controlador.

Do ponto de vista do sistema operacional, um aspecto relevante é o chamado

escalonamento do disco, que é a rotina do núcleo do sistema operacional que busca determinar

quais pedidos de leitura e escrita serão atendidos e em que ordem.

Vários processos podem estar realizando ao mesmo tempo pedidos de operações de E/S e

sendo consequentemente bloqueados até que a operação solicitada seja realizada. O problema do

escalonador do disco é ordenar e atender estes pedidos de E/S, buscando minimizar o tempo em que

processos permanecem bloqueados.

Numa operação de E/S em disco, um fator importante a ser levado em consideração é o

tempo de seek, que é o tempo despendido pelo dispositivo para posicionar o cabeçote de leitura e

gravação no ponto inicial no prato onde deverá ocorrer a operação de gravação ou leitura.

Existem diversos algoritmos de escalonamento. A maioria tem como principal objetivo

minimizar o tempo de seek da operação. Dentre estes, alguns merecem destaque:

FCFS (First Come First Served): É o algoritmo de escalonamento mais simples. As

solicitações de acesso são atendidas na ordem em que os pedidos são realizados.

SSTF (Shortest Seek Time First): O próximo pedido de E/S a ser atendido é aquele

que se refere a trilha mais próxima da trilha atual, isto é, aquele que envolve a menor

movimentação do cabeçote de leitura/gravação.

SCAN: Esse algoritmo é uma variação do SSTF. Ele se diferencia por manter um

sentido preferencial para o movimento do cabeçote, como por exemplo, da trilha mais

externa para a mais interna.

Em relação a discos rígidos, com o passar do tempo os controladores foram evoluíndo e

diversas padronizações foram surgindo. Dentre as mais importantes cabe destacar:

MFM, RLL: Padrões antigos, não mais em uso.

IDE: Interface simples, faz uso do barramento ISA, possuia baixa taxa de

transferência, tipicamente voltada para discos menores que 528MB.

EIDE: Melhorias do IDE, faz uso do barramento PCI, suportando discos de até 8.5

GB, com controlador na placa mãe; gerenciava até quatro discos.

SCSI - Controlador para sistemas com altas velocidades e grande capacidade.

Suporta grande quantidade de discos de grande capacidade.

5. Gerência de memória

Neste capítulo é abordada a gerência de memória, explorando-se temas como memória

virtual e paginação. Uma boa gerência de memória é fundamental para o bom desempenho do

sistema computacional, daí a importância do tema.

A memória principal (ou RAM) é um dos elementos mais importantes em um ambiente

computacional. Nesta memória irão residir os processos (isto é, os aplicativos em execução), bem

como rotinas do próprio kernel do sistema operacional.

Se o espaço de memória RAM não for suficiente para abarcar todos processos que precisam

ser executados, então é importante lançar mão de mecanismos como a memória virtual, que permite

que a memória principal seja expandida de forma transparente para os processos, empregrando

espaço livre nos dispositivos de memória de massa, usualmente nos discos rígidos.

Um processo é gerenciado pelo kernel como um elemento independente, residindo em uma

área de memória própria na memória principal. Essa área de memória contém as informações

necessárias à execução desse processo, particionada da seguinte forma:

Área HEAP : é empregada para armazenar dados através de alocação dinâmica. Esta área

possui tamanho variável, podendo aumentar e diminuir conforme forem ocorrendo as

alocações e liberações de memória realizadas pelo processo. Com o tempo esta área pode

ficar fragmentada.

Área DATA (ou de DADOS) : contém os dados estáticos empregados pelo processo

(variáveis globais e locais, arrays, etc); tem tamanho fixo.

Área TEXT : é onde o código (o conjunto de instruções a ser executado pelo processo) está

armazenado; esta área possui tamanho fixo, calculado durante a compilação.

Área STACK (ou PILHA): é empregada para gerenciar a pilha de execução do processo,

que é a estrutura através da qual é feito o gerenciamento do fluxo de execução nas chamadas

de rotinas e de seus argumentos (parâmetros); normalmente esta área começa em endereços

altos de memória e cresce em direção aos endereços menores. No caso de aplicativos que

possuam múltiplas threads (linhas de execução ou processos leves), esta área irá possuir

somente a pilha do processo principal. Normalmente a pilha de execução de uma thread é

mantida e alocada no heap.

Mecanismos de alocação de memória

O tipo mais simples de alocação de memória consiste em dividir a memória em partições

fixas, de tamanhos iguais. Em cada partição pode ser carregado um processo. Essa abordagem é

muito simples, mas possui muitas desvantagens: os processos podem ter tamanhos diferentes dos

tamanhos das partições, o que gera em regiões sem uso no final de cada partição; o número máximo

de processos na memória é limitado pelo número de partições e processos maiores que o tamanho

da maior partição não vão poder ser carregados na memória, mesmo se todas as partições estiverem

livres.

Uma opção bem mais flexível é se cada partição puder ter seu tamanho ajustado para cada

processo, ou seja, a memória é dividida em partições de tamanho variável.

Na alocação contígua, os espaços de memória alocados devem formar áreas contíguas, isto

é, sem descontinuidade. Apesar de simples, é uma estratégia pouco flexível e sujeita à

fragmentação. Já na alocação segmentada, o espaço de memória de um processo é dividido em

regiões, ou segmentos, que são alocados separadamente na memória. Além das quatro áreas básicas

do processo (text, data, stack e heap), também podem haver segmentos para elementos como

bibliotecas, pilhas de threads, buffers, etc. Ao estruturar a memória em segmentos, o espaço de

memória de cada processo não é mais encarado como uma seqüência linear de endereços lógicos,

mas sim como uma coleção de segmentos de tamanhos diferentes.

Durante a execução dos processos, áreas de memória desalocadas por processos podem

gerar áreas livres de memória entre os processos, o que é chamado de fragmentação externa. Esse

problema afeta somente os mecanismos de alocação que trabalham com blocos de tamanho

variável, como a alocação contígua e a alocação segmentada. A alocação paginada manipula blocos

de mesmo tamanho, sendo por isso imune à este problema. A fragmentação é danosa porque limita

a capacidade de alocação de memória no sistema.

Para minimizar a ocorrência de fragmentação cada requisição de alocação deve ser

primeiramente analisada para que o gerente de memória encontre a melhor área de memória livre

para cada caso. Os principais critérios a serem levados em consideração para esta escolha são:

best-fit : escolha da menor área possível que atenda a reuisição de alocação. Assim, as áreas

livres são usadas de forma otimizada, mas eventuais resíduos podem ser pequenos demais

para serem usados em seguida, nas próximas requisições, o que é ruim.

worst-fit : consiste em escolher a maior área livre, de forma que áreas restantes sejam

grandes e possam ser usadas em outras alocações.

first-fit : escolha da primeira área livre que satisfaça o pedido de alocação; é rápida, ainda

mais se a lista de áreas livres for muito longa.

next-fit : é uma variação da first-fit, e consiste em percorrer a lista de áreas livres a partir da

última área alocada ou liberada, para que o uso das áreas livres seja distribuído da maneira

mais homogênea possível.

Memória virtual

O uso de um armazenamento externo como extensão da memória RAM é chamado de

memória virtual; este mecanismo deve ser implementado de forma eficiente e transparente para

processos.

Quando processos inteiros são transferidos da memória para o disco rígido este

procedimento é chamado de troca ou swapping. Entretanto, geralmente as transferências são feitas

por páginas ou grupos de páginas, através de um mecanismo chamado de paginação. As páginas

possuem um tamanho fixo, o que simplifica os algoritmos de escolha de páginas a serem

removidas, bem como os mecanismos de transferência para o dispositivo. A idéia é transferir para o

disco as páginas de memória pouco usadas (isto é, acessadas).

Os principais algoritmos para troca de páginas são:

FIFO: Um critério é o tempo em que os dados estão na memória. Páginas mais antigas

podem ser removidas para dar lugar a novas. Esse algoritmo é bastamte simples: as páginas

são dispostas numa fila de números de páginas com política FIFO (First In, First Out). Os

números das páginas recém carregadas na memória são registrados no final da lista (ou fila).

Ótimo: a melhor página a remover da memória é aquela que irá ficar mais tempo sem ser

usada pelos processos. Mas como o comportamento futuro dos processos não pode ser

previsto, este algoritmo não é implementável.

LRU (Least Recently Used): é uma aproximação implementável do algoritmo ótimo. São

escolhidas as páginas que estão na memória há mais tempo sem serem acessadas. As

páginas antigas e menos usadas são as escolhas preferenciais

NRU (Not Recently Used): leva em consideração o momento da última modificação da

página; opta por aquleas que não foram recentemente modificadas (ou usadas).

Em linhas gerais pode-se pensar nos principais critérios a serem usados para a escolha das

páginas: a idade da página (que depende de há quanto tempo a página está na memória), a

freqüência de acessos à página, a data ou hora do último acesso e a prioridade do processo ao qual

a página pertence.

6. Sistemas de Arquivos

Neste capítulo são apresentados os conceitos relativos a sistemas de arquivos, sua estrutura e

funcionalidades, apresentando também as principais características de alguns dos sistemas de

arquivos mais significativos.

Principais conceitos

O principal conceito quando se trata de armazenamento e manipulação de dados em

memória de massa é o de arquivo. Um arquivo é basicamente um conjunto de dados armazenados

em um dispositivo de armazenamento secundário e que é identificado com um nome único.

Para facilitar a organização de uma grande quantidade de arquivos, outro conceito

importante é o de diretório (ou pasta), que permite o arranjo de modo hierárquico de todos

arquivos armazenados.

Cada sistema operacional possui seu próprio sistema de arquivos. A seguir estão listados

alguns dos principais sistemas de arquivos em uso hoje em dia:

FAT : nos sistemas MS-DOS e Windows 3.1 até Windows 98 SE e Millenium; empregada

também em pendrives, por exemplo.

NTFS: nos sistemas Windows 2000 até Windows 7.

Ext2 e Ext3: Linux.

Cada arquivo é caracterizado por um conjunto de atributos, que podem variar de acordo com o

sistema de arquivos utilizado. Os atributos mais comuns são o nome do arquivo, seu tipo (que pode

indicar a natureza do dado armazenado no arquivo), data e hora de criação e última modificação ou

acesso, seu tamanho, o indicação de quem criou o arquivo, etc.

O uso dos arquivos é realizado por meio de um conjunto de operações implementadas através

de system calls (as chamadas de sistema) e funções de bibliotecas. As principais operações que

podem ser realizadas com arquivos são:

Criação do arquivo

Leitura dos dados do arquivo

Gravação de dados no arquivo

Alteração do valor de atributos do arquivo

Deleção do arquivo

O programa-exemplo (codificado em linguagem C) a seguir ilustra o processo de leitura de um

arquivo byte a byte. Cada byte lido é mostrado na tela do computador. O nome do arquivo a ser lido

deve ser passado como parâmetro na linha de comando do terminal, no momento em que este

programa for ser executado.

#include <stdio.h> #include <stdlib.h> void main(int argc, char *argv[]) { FILE *fp; //fp É UMA VARIÁVEL QUE REFERENCIA O HANDLER char ch; if(argc!=2) { printf("numero insuficiente de argumentos para o main\n"); exit(1); } if((fp=fopen(argv[1],"r"))==NULL) // ABRE O ARQUIVO PARA LEITURA { printf("O arquivo nao pode ser aberto\n"); exit(1); } ch=fgetc(fp); // LÊ UM CARACTER (BYTE) DO ARQUIVO while(ch!=EOF) { putchar(ch); // ESCREVE CARACTER NA TELA ch=fgetc(fp); // LÊ PRÓXIMO CARACTER (BYTE) DO ARQUIVO } fclose(fp); // FECHA ARQUIVO }

Para poder ler ou escrever dados em um arquivo, um processo precisa primeiro abrir o

arquivo. A abertura de um arquivo consiste em preparar as estruturas de memória necessárias para

acessar os dados do arquivo. Assim, para abrir um arquivo, o kernel deve localizar o arquivo no

dispositivo de memória de massa (através do seu nome), checar se o processo pode (tem permissão

para) acessar aquele arquivo, criar as estruturas de dados para representar o arquivo aberto, colocar

uma referência (handler) para esta estrutura na lista de arquivos abertos mantida pelo sistema e

finalmente retornar para o processo a referência a esta estrutura.

As duas formas mais comuns de se acessar os dados que estão armazenados em um arquivo

são o acesso sequencial dos dados e o acesso direto. No acesso seqüencial, os dados são sempre

lidos ou gravados sequencialmente, do início para o fim do arquivo. No modo de acesso direto,

pode-se indicar a posição no arquivo onde a leitura ou gravação deve acontecer.

Um disco rígido (ou HD) pode ser encarado como uma grande sequencia de blocos de

bytes, também chamados de setores, e que possuem um tamanho fixo de 512 bytes. Usualmente o

sistema de arquivos acessa as informações no HD lendo ou escrevendo conjuntos de setores a cada

vez. Estes grupos de setores são denominados de blocos de alocação (ou clusters). O tamanho do

bloco de alocação é determinado via de regra pelo próprio sistema de arquivos, e usualmente fica

entre um a oito setores (isto é, um cluster possui entre 512 a 4 KB de tamanho físico).

Versões antigas de sistemas de arquivos como a FAT poderiam empregar clusters de até

16KB de tamanho, o que ocasionava um grande disperdício de espaço em disco. Isto se deve ao

fato de que um arquivo gravado em disco vai ser representado por um conjunto de clusters (todos

eles com o mesmo tamanho). Se por exemplo o tamanho do arquivo for de 13 KB e o tamanho do

cluster empregado por este sistema de arquivos for de 2KB, então serão usados para este arquivo

sete clusters, sendo que o final do arquivo residirá em um cluster que não estará completamente

cheio, e sim estará sendo usado pela metade. Isto se deve também ao fato de que um cluster só pode

estar associado a um único arquivo, não podendo ser compartilhado por dois ou mais arquivos.

Exemplo de organização de um sistema de arquivos: o caso da FAT 12

Quando se trata da forma como um sistema operacional organiza os dados em um volume

(ou partição) um exemplo interessante de ser estudado em maior profundidade é o da FAT 12, dada

sua simplicidade. Esta versão do sistema de arquivos FAT é a que era empregada em disquetes.

A estrutura geral de u volume formatado como FAT 12 é o que aparece na figura abaixo:

Estrutura de um disquete (FAT 12) 1 setor = 1 cluster = 512 bytes

Diretório Raíz Cópia da FAT FAT BOOT

setor 0 setores 1 a 9 setores 10 a 18 setores 19 a 32 s

No primeiro setor estão armazenadas diversas informações i

dados armazenado no disco. Por exemplo:

1o,2o,3o bytes : instrução (assembly) de salto para rot

do 4o ao 11o byte : nome e versão do DOS (ex.: MS

12o,13o : número de bytes por setor (512 ; no disco fi

14o : número de setores por cluster

15o,16o : número de setores reservados

17o : número de FATs (2)

18o,19o : número máximo de entradas no diretório (ra

20o,21o : número total de setores no disco (0B 40 e

22o : byte descritor do meio -> F0 (disco 3.5) , F8

23o, 24o : número de setores usados por uma FAT

25o,26o : número de setores por trilha

27o , 28o : número de cabeças

29o , 30o : número de setores escondidos

Dados

etor 33 em diante

mportante sobre o volume de

ina de boot

WIN4.0)

ca 00 02 )

íz) (112 ou 224)

m um disco de 3.5)

(HD) , FC (5.25)

40o a 43o : número de série do disco

a partir do 44o : nome do volume

a partir do 55o : FAT12 ou FAT16

últimos 2 bytes deste setor : 55 AA

Estrutura de um arquivo de diretório FAT12

Um diretório no sistema de arquivos FAT é uma seqüência de entradas de 32 bytes cada,

onde cada entrada corresponde a um arquivo (FAT12 e FAT16 convencionais). Na FAT

empregada pelo Windows 95 (que é chamada de VFAT), para cada arquivo podem ser usadas

mais de uma entrada de diretório, onde uma entrada segue o formato tradicional e as demais

armazenam o nome do arquivo usando codificação UNICODE (2 bytes por caracter).

Então, o formato de uma entrada de diretório FAT 12 fica (tamanho em bytes indicado

abaixo de cada campo):

tam 1o clust. datahorareservadoatributext nome

8 3 1 10 2 2 2 4 Quanto ao byte de atributo, cada bit possui um significado: - - volume subdiret arquivo sistema hidden read-only Ex: 0 0 1 0 1 0 0 0 = 0010 1000 =28 não usados Quanto ao cálculo do campo data, este fica:

dia + 32 * mês + 512 * (ano – 1980) Ex: 01/05/97 1 + 32*5 + 512*(1997-1980) = 8865 (dec) = 22 A1 (hexa) Obs.: o campo dia usa 5 bits, o mês os 4 próximos bits e o ano os bits restantes Quanto ao cálculo do campo hora, este fica: segundos/2 + 32 * minutos + 1024 * horas Obs.: o campo segundos usa 5 bits, minutos usa 6 bits e horas os bits restantes Quanto a tabela da FAT 12

Cada entrada da FAT12 emprega 12 bits ou 1 byte e meio. Logo, em 3 bytes consecutivos

temos 2 entradas.

Exemplo (como mostrado pelo DiskEdit): F0 FF 02 54 00 32 . . .

Se temos setores de 512 bytes, então cabem 341,33 entradas de FAT por setor.

Observação: entrada com valor FFF = fim de encadeamento e FF7 = setor ruim

Quanto a tabela da FAT 16

Cada entrada da FAT 16 emprega 16 bits ou 2 bytes . Se temos setores de 512 bytes, então

em 1 setor cabem 256 entradas.

Observação: entrada com valor FFFF = fim de encadeamento e FFF7 = setor ruim

As duas primeiras entradas da FAT são reservadas (não usadas); isto vale para FAT12 e

FAT16.

A expressão a seguir fornece um valor que corresponde a uma projeção (uma aproximação)

de quanto espaço em disco está sendo desperdiçado pelos arquivos gravados no disco. Este

desperdício diz respeito a espaço no disco que já está alocado (associado a um arquivo) e que

conseqüentemente não pode ser usado pelo sistema de arquivos (FAT) para armazenar novos

arquivos, por exemplo.

Espaço desperdiçado = quantidade de arquivos * metade do tamanho do cluster

Exemplo:

Se numa partição FAT temos 1800 arquivos gravados e o tamanho do cluster (ou bloco) é de

8 KB, então:

Espaço desperdiçado = 1800 * 4KB = 7200 KB = 7.03 MB de espaço em disco que está

locado mas não pode ser usado para armazenar novos arquivos.

A árvore de diretórios: o caso do S.O. Linux

A estrutura do sistema de arquivos apresentada aqui é a definida na versão 1.2 de 28 de março

de 1995 do Linux Filesystem Structure Standard (FSSTND).

O diretório raiz ( / ) é normalmente organizado (subdividido) em uma coleção de

subdiretórios. Cada um destes subdiretórios armazena uma classe específica de arquivos, como

pode ser visto na tabela a seguir:

subdiretório Função (classe de arquivos armazenados)

bin Executáveis essenciais (comandos); ex: cat, chmod, cp, date, dd,

df, ed, kill, login, ls, mkdir, more, mount, mv, ps, pwd, rm, rmdir,

umount,...

boot Arquivos estáticos do carregador de boot (boot loader)

dev Arquivos de dispositivos

etc Arquivos e scripts para configuração do sistema; ex: csh.login,

fstab, group, inittab, lilo.conf, passwd, profile, exports, hosts,

networks, protocols, ...

home Diretórios para usuários

lib Bibliotecas compartilhadas (shared libraries)

mnt Diretório para montagem de sistemas de arquivos temporários

proc Pseudo sistema de arquivos (armazena informações de processos)

root Diretório do administrador do sistema (root user)

sbin Executáveis essenciais (para administração do sistema); ex: clock,

getty, init, mkswap, swapon, swapoff, shutdown, fdisk, fsck,

mkfs, badblocks, dumpe2fs, e2fsck, lilo, ifconfig, route, ...

tmp Arquivos temporários

usr É a 2a maior porção do sistema de arquivos; armazena arquivos

compartilháveis, geralmente read-only (tabela a seguir)

var Dados variáveis; incluem arquivos de spool, arquivos de log e

arquivos temporários; não pode ser uma partição separada

O diretório /usr comtém uma hierarquica bastante grande de subdiretórios e merece

uma descrição detalhada:

subdiretório Função (classe de arquivos armazenados)

X11R6 X Window System versão 11 release 6

X386 X Window System versão 11 release 5 para plataforma x86

bin Comandos de usuário

dict Lista de palavras (para spell checkers)

doc documentação

etc Arquivos de configuração não-locais

games jogos

include Arquivos .h (header files para programas em C)

info GNU info system

lib bibliotecas

local Hierarquia local; usada pelo administrador do sistema quando

instala software localmente

man Man pages; subdiretórios man1 (programas de usuário), man2

(chamadas do sistema), man3 (funções de bibliotecas), man4

(dispositivos), man5 (formatos de arquivos), man6 (jogos),

man7 (miscelânea), man8 (administração do sistema), man9

(funções e variáveis internas do kernel)

sbin Executáveis não-essenciais

share Dados dependentes de arquitetura

src Código-fonte do sistema operacional

O diretório /var também contém uma hierarquia de diretórios merecedora de uma análise

mais detida. Sua estrutura é apresentada logo abaixo:

subdiretório Função (classe de arquivos armazenados)

adm (obsoleto); link simbólico para /var/log

catman Manual pages formatadas localmente

lib Subdiretórios para arquivos temporários e de log para

aplicativos (emacs, games, ...)

local Dados variáveis de software de /usr/local

lock Arquivos de lock

log Arquivos de log

named Arquivos usados pelo servidor de nomes Internet (named)

nis Arquivos do Network Information Service (NIS)

preserve Arquivos salvos após crash no vi e ex

run Contém arquivos com informações sobre o sistema desde o

momento do boot

spool Diretórios de spool (lpd – diretório de spool da impressora;

mail – arquivos de mailbox; cron – arquivos cron; ...)

tmp Arquivos temporários

Algumas observações sobre o shell do Linux

O shell é a camada do sistema operacional que interpreta os comandos do usuários e dispara

os processos adequados para atender aos seus objetivos . Do ponto de vista do usuário, um shell é

representado por uma janela de terminal na qual é possível digitar comandos e receber respostas do

sistema operacional. O universo Linux oferece um número considerável de shells, mas a versão

mais usada atualmente é chamada de bash (Bourne Again Shell). Entre as outras versões

disponíveis destacam-se ainda o sh (Bourne shell original), o csh (C shell), o ksh (Korn shell), o

tcsh (Enhanced C shell) e o zsh (Z shell).

Redirecionamento de Entrada/Saída e Dutos (pipes)

O Linux permite que a entrada de dados para um arquivo não precise ser necessariamente

feita via teclado, caso esta seja a única forma de leitura adotada pelo programa. Uma forma

alternativa é redirecionar a entrada de dados a partir de um arquivo, como no exemplo abaixo:

ordena < lista

Neste exemplo, o processo ordena coleta os dados a serem processados a partir do arquivo lista.

Uma outra situação possível é redirecionar a saída de um processo para um arquivo, como no

exemplo a seguir.

classifica > resultado

Aqui, o processo classifica gera dados de saída que são armazenados em um arquivo chamado

resultado. Pode-se também fazer com que a saída de um processo saja adicionada ao final de um

arquivo já existente (append), como no exemplo abaixo:

classifica >> novo

É possível ainda fazer com que a saída de um processo alimente com dados a entrada de um

segundo processo. Este mecanismo é chamada de dutos ou pipes. O exemplo a seguir ilustra este

tipo de situação:

classifica | ordena

Neste caso, os dados gerados pelo processo classifica são usados como entrada de dados para

o processo ordena.

Filtros do Linux

Filtros são utilitários geralmente de pequeno tamanho mas muito poderosos, sendo seu uso

bastante difundido na comunidade de usuários UNIX/Linux.

cat : mostra, cria e concatena arquivos

sort : ordena arquivos

grep : procura padrão em arquivos

wc : conta o número de linhas, palavras e caracteres de um arquivo

head : imprime as n 1as linhas de um arquivo

tail : imprime as n últimas linhas de um arquivo

split : divide um arquivo em arquivos menores

diff : compara arquivos e mostra diferenças

O uso de caracteres especiais (meta-caracteres) Alguns caracteres possuem emprego especial, como por exemplo o caracter asterisco e o

caracter ponto de interrrogação.

O caracter especial asterisco:

* substitui qualquer string

Exemplo: ls a* (lista todos arquivos que começam por “a” )

rm * (remove todos arquivos do diretório corrente)

O caracter especial ponto de interrogação:

? substitui um caracter

Exemplo: ls a? (lista todos arquivos que começam com “a” e possuem só 2 caracteres)

ls ?b? (lista todos arquivos de 3 caracteres que tenham “b” como 2a letra)

Segurança e Permissões de acesso

Permissões de acesso indicam quais tipos de operações um determinado usuário poderá

realizar sobre um arquivo. Todos arquivos tem suas permissões de acesso divididas em 3 grupos:

permissões de acesso do próprio usuário (daquele que criou o arquivo), permissões de acesso dos

usuários que pertencem ao mesmo grupo deste usuário e por último as permissões de acesso de

todos outros usuários da rede.

As permissões de acesso são visíveis quando se utiliza o comando ls –l .

Figura 10: as permissões de acesso de 3 arquivos .

A estrutura do campo de permissão de acesso é a seguinte:

- rwx rwx rwx

Bit de Tipo: - : arquivo d : diretório b : dispositivo de bloco c : dispositivo caracter l : link s : socket

User Group Others

As permissões de acesso de um arquivo podem ser ajustadas através do comando chmod. Por

exemplo:

chmod ugo + rwx nomearquivo → adiciona permissão de leitura ( r ), escrita (w) e

execução (x) para o próprio usuário proprietário (criador) do arquivo (u), para usuários do seu

grupo (g) e para todos outros usuários cadastrados (o).

Outra maneira de usar o chmod é empregando o modo absoluto, cujo funcionamento pode ser

resumido através dos valores constantes da seguinte tabela:

usuário permissão valor U r 400

U w 200

U x 100

G r 040

G w 020

G x 010

O r 004

O w 002

O x 001

Por exemplo: chmod 755 nomearquivo → dá permissões pra u,g,o de r,w,x (root).

Outro comando importante é o chown, que permite alterar o dono de um determinado

arquivo. Por exemplo:

chown mateus casa.doc → o arquivo casa.doc agora é do usuário mateus

Pode-se alterar ainda o grupo ao qual um arquivo pertence; para isto emprega-se o comando

chgrp. Por exemplo:

chgrp projetos casa.doc → o arquivo casa.doc agora pertence ao grupo projetos