Conceitos básicos

Propaganda
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
executando
novo
preemptar
bloquear
executar
desbloquear
criar
bloqueado
pronto
suspender
continuar
Pronto e
suspenso
suspender
liberar
continuar
Bloqueado e
suspenso
Figura 7: estados de um processo
Observações importantes sobre processos
Os sistemas operacionais modernos
associam uma tarefa a cada processo, o que
corresponde à execução de um programa seqüencial, ou seja, um fluxo único de instruções dentro
do processo. Desta forma o processo deve ser encarado como um repositório de recursos
empregados por uma ou mais tarefas para sua execução. Os processos são isolados entre si pelos
mecanismos de proteção providos pelo hardware e pelo gerente de processos. Processos podem ser
criados e destruídos e estas operações são oferecidas aos aplicativos através de system calls.
A criação de processos no S.O. UNIX gera um esquema hierarquico entre os processos. À
medida que processos são criados, é gerada uma árvore de processos.
Cada fluxo de execução do sistema, no interior do kernel ou associado a um processo é
denominado thread. Threads executando dentro 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 PICProgrammable 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
BOOT
setor 0
(FAT 12)
1 setor = 1 cluster = 512 bytes
FAT
Cópia da FAT
setores 1 a 9
setores 10 a 18
Diretório Raíz
Dados
setores 19 a 32 setor 33 em diante
No primeiro setor estão armazenadas diversas informações importante sobre o volume de
dados armazenado no disco. Por exemplo:
™ 1o,2o,3o bytes : instrução (assembly) de salto para rotina de boot
™ do 4o ao 11o byte : nome e versão do DOS (ex.: MSWIN4.0)
™ 12o,13o : número de bytes por setor (512 ; no disco fica 00 02 )
™ 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íz) (112 ou 224)
™ 20o,21o : número total de setores no disco (0B 40 em um disco de 3.5)
™ 22o : byte descritor do meio -> F0 (disco 3.5) , F8 (HD) , FC (5.25)
™ 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
™ 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):
nome
ext
8
atribut
3
reservado
1
hora
data
2
2
10
1o clust.
2
tam
4
Quanto ao byte de atributo, cada bit possui um significado:
- Ex: 0
volume subdiret arquivo sistema
0
1
0
1
0
não usados
Quanto ao cálculo do campo data, este fica:
hidden read-only
0
0 = 0010 1000 =28
dia + 32 * mês + 512 * (ano – 1980)
(dec) = 22 A1 (hexa)
Ex: 01/05/97 B 1 + 32*5 + 512*(1997-1980) = 8865
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
bin
Função (classe de arquivos armazenados)
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
Bibliotecas compartilhadas (shared libraries)
lib
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)
Dados variáveis; incluem arquivos de spool, arquivos de log e
var
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
X11R6
X386
bin
Função (classe de arquivos armazenados)
X Window System versão 11 release 6
X Window System versão 11 release 5 para plataforma x86
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
adm
catman
lib
Função (classe de arquivos armazenados)
(obsoleto); link simbólico para /var/log
Manual pages formatadas localmente
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
named
nis
preserve
run
Arquivos de log
Arquivos usados pelo servidor de nomes Internet (named)
Arquivos do Network Information Service (NIS)
Arquivos salvos após crash no vi e ex
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
Bit de Tipo:
- : arquivo
d : diretório
b : dispositivo de bloco
c : dispositivo caracter
l : link
s : socket
rwx rwx
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
Download