quarta-feira, 24 de junho de 2009

Introdução aos Sistemas Distribuídos

Segundo a definição de Andrew Tanenbaum um sistema distribuído é uma "coleção de computadores independentes que se apresenta ao usuário como um sistema único e consistente". Ou seja, é uma coleção de computadores autônomos interligados através de uma rede de computadores e equipados com software distribuído que permita o compartilhamento dos recursos do sistema: hardware, software e dados.

Características:

· Concorrência: permitir que recursos compartilhados sejam utilizados por diversos processos. Quando programas necessitam cooperar eles coordenam
suas ações por troca de mensagens.

· Compartilhamento de recursos:

o Hardware: discos, impressoras.

o Informações: arquivos, bases de dados,objetos.

· Transparência: a aplicação opera sob um ponto de vista lógico como se os dados fossem gerenciados por um único SGBD, funcionando em uma única máquina com apenas um sistema operacional.

· Escalabilidade: habilidade de funcionar bem quando o número de usuários aumenta.

· Tolerância a falhas: cada componente do sistema pode falhar independentemente, deixando os outros ainda rodando.

Assim, a computação distribuída consiste em adicionar o poder computacional de diversos computadores interligados por uma rede de computadores ou mais de um processador trabalhando em conjunto no mesmo computador, para processar colaborativamente determinada tarefa de forma coerente e transparente, ou seja, como se apenas um único e centralizado computador estivesse executando a tarefa. A união desses diversos computadores com o objetivo de compartilhar a execução de tarefas, é conhecida como sistema distribuído.

Avanços tecnológicos na miniatuarização de dispositivos e redes sem fio têm conduzido a uma crescente integração de pequenos e portáveis dispositivos de computação, tais como:

· computadores laptop;

· Dispositivos handheld: personal digital assistants (PDA),

· telefones móveis,

· cameras digitais.

A portabilidade junto com a habilidade para se conectar convenientemente a redes em diferentes lugares, torna possível a Computação Móvel.

Sistema Operacional Distribuído

Um SO Distribuído parece ao usuário como um sistema centralizado comum, mas executa em múltiplas unidades de processamento independentes onde:

  • o uso de múltiplos processadores deve ser invisível (transparente) para o usuário;
  • o usuário vê o sistema como um uniprocessador virtual, não como uma coleção de máquinas distintas conectadas por um subsistema de comunicação.

Como principais características têm-se um mecanismo de comunicação global único entre processos, proteção global e gerenciamento homogêneo de processos. O objetivo é fornecer transparência no acesso aos recursos, mas, de fato, não existe um sistema 100% transparente.

Assim, o SO Distribuído deve:

  • controlar a alocação de recursos da rede para permitir seu uso no modo mais eficiente;
  • prover ao usuário com um computador virtual conveniente que serve como um ambiente de programação de alto nível;
  • esconder a distribuição dos recursos;
  • prover mecanismos para proteção dos recursos do sistema contra acesso por usuários não autorizados;
  • prover comunicação segura.

Threads

Thread

Thread é uma forma de um processo dividir a si mesmo em duas ou mais tarefas que podem ser executadas simultaneamente. O suporte à thread é fornecido pelo próprio sistema operacional (SO), no caso da Kernel-Level Thread, ou implementada através de uma biblioteca de uma determinada linguagem, no caso de um usuario nivel thread.
Uma linha de execução permite que o usuário de programa, por exemplo, utilize uma funcionalidade do ambiente enquanto outras linhas de execução realizam outros cálculos e operações.
Em hardwares equipados com uma única CPU, cada linha de execução(Thread) é processada de forma aparentemente simultânea, pois a mudança entre uma linha e outra é feita de forma tão rápida que para o usuário isso está acontecendo paralelamente. Em hardwares com multiplos CPUs ou multi-cores as linhas de execução(Threads) podem ser realizadas realmente de forma simultânea;
Os sistemas que suportam apenas uma única linha de execução são chamados de monothread e aqueles sistemas que suportam múltiplas linhas de execução são chamados de multithread.

Exemplo

Um exemplo simples pode ser expressado através de um jogo onde o mesmo pode ser modelado com linhas de execução diferentes, sendo uma para desenho de imagem e outra para áudio; Neste caso, há um thread para tratar rotinas de desenho e outro thread para tratar áudio; No ponto de vista do usuário, a imagem é desenhada ao mesmo tempo em que o áudio é emitido pelos auto-falantes; Porém, para sistemas com uma única CPU, cada linha de execução é processada por vez;
No navegador como por exemplo: internet explorer ou firefox é outro modo facil de perceber threads. Quando abre o navegador foi executado um processo mas dentro desse processo voce pode abrir varias abas que mesmo assim vai continuar com um processo,ou seja, as abas sao threads.

Peculiaridades

Cada linha de execução tem o mesmo contexto de software e compartilha o mesmo espaço de memória (endereçado a um mesmo processo pai), porém o contexto de hardware é diferente. Sendo assim o overhead causado pelo escalonamento de linha de execução é muito menor do que o escalonamento de processos, entretanto, não há acesso protegido a memória nativamente (sua implementação fica a cargo do programador) devido ao compartilhamento do espaço de memória.
Um benefício do uso das linhas de execução advém do fato do processo poder ser dividido em mais de uma linha de tarefas; quando uma linha está esperando determinado dispositivo de E/S ou qualquer outro recurso do sistema, o processo como um todo não fica parado, pois quando uma linha de execução entra no estado de bloqueio uma outra thread aguarda na fila de prontos para executar.
Uma linha de execução possui um conjunto de comportamentos padrão, normalmente encontrados em qualquer implementação ou sistema operacional.
Uma linha de execução pode:
· criar outra da mesma forma que um processo, tal advento é conhecido como thread-create, onde a thread retorna um ID ao primeiro como primeiro argumento, como resultado da função de criação.
· esperar outra para se "juntar" (sincronizar), tal advento é conhecido como join.
· voluntariamente "desistir" da CPU, por não ser preciso mais o processamento proposto por ela ou pela vontade do usuário, tal advento é conhecido como thread-yield.
· replicar-se sem a necessidade de duplicar todo o processo, economizando assim memória, processamento da CPU e aproveitando o contexto (variáveis, descritores, dispositivos de E/S).

Estados de uma linha de execução

Basicamente uma linha de execução pode assumir os seguintes estados:
· criação. Neste estado, o processo pai está criando a thread que é levada a fila de prontos;
· execução. Neste estado a linha de execução está usando a CPU;
· pronto. Neste estado a linha de execução avisa a CPU que pode entrar no estado de execução e entra na fila de prontos;
· bloqueado. Neste estado, por algum motivo, a CPU bloqueia a linha de execução, geralmente enquanto aguarda algum dispositivo de E/S;
· término. Neste estado são desativados os contextos de hardware e a pilha é deslocada.
multithread Vários fluxos em execuções(várias threads), associado a um unico processo. Processo pode se dividir em duas ou mais taréfas, que podem ser executadas simultaneamente (programação concorrente).

Criação

Basicamente uma linha de execução pode dividir uma linha de execução em duas, depois estas linhas(threads) executam simultaneamente, a thread criadora é a thread pai e a thread criada é a thread filho. Threads incluidas na função main quando executadas pode criar threads filho no diagrama a seguir a thread A executa inicialmente. Mais tarde é criada a thread B indicada no ponto amarelo. Depois de criadas, a thread A e thread B executam simultaneamente. Em seguida a thread A pode criar uma ou mais threads (thread C). Depois de criada a thread C, há três threads executando simultaneamente e todas disputam o uso da CPU. Entretanto, a thread que pode ser executada a qualquer momento não é de conhecimento da CPU.

Término

Para maioria dos casos as threads não são criadas e executadas eternamente. Depois de terminado seu trabalho, a thread termina. No fato, a thread que criou estas duas threads filho terminam também porque sua tarefa atribuída se completa. Na matrix de multiplicação (matrix multiplication), uma vez que o valor de C[i,j] é computado a thread correspondente termina. Em geral quando a tarefa atribuída a thread completa, a thread pode ser terminada. Além disso, se a thread pai terminar, todas as threads filho terminam também. Porque isso é importante? Isso é importante porque as threads filho compartilham recursos com a thread pai, incluindo variáveis. Quando a thread pai termina, todas as variáveis são perdidas e a thread filho não poderá acessar os recursos que a thread pai possui. Assim, se a thread pai termina mais cedo que a thread filho haverá um problema. Uma thread pode terminar das seguintes maneiras:
· Retornando da sua rotina mais externa, a thread criadora.
· Quando termina a rotina em que foi começada.
· Chamando pthread_exit, fornecendo um estado de saída.
· Terminando através da função pthread_cancel

Junção

Imagine a seguinte situação: Você está estudando para uma prova. Então você pede o seu irmão mais novo para comprar uma pizza. Neste caso você é a thread principal e seu irmão a thread filha. Uma vez que você deu a ordem você e seu irmão começam a "executar uma tarefa" simultaneamente. Agora há dois casos a se considerar: Primeiro: Seu irmão traz a pizza e termina enquanto você estuda. Nesse caso você pode parar de estudar e comer a pizza. Segundo: Você acaba de estudar mais cedo e dorme e depois a pizza chegará.
A junção de threads (thread join) é destinada para resolver este problema. A thread pode executar o thread join e aguardar até a outra thread terminar. No caso acima você é a thread principal (thread main) e deve executar o thread join aguardando o seu irmão (thread filho) terminar. Em geral o thread join é utilizado para a thread pai juntar com uma das threads filhas.

Rendimento da thread

Suponha que você executa um certo número de programas o tempo todo no computador. Isso é possível devido a CPU destruir pouco a pouco outros ciclos de CPU, assim outros programas podem ser executados. Isso pode ser um problema de política de planejamento do sistema operacional. Entretanto, quando nós escrevemos nossos programas com múltiplas threads, nós temos que fazer certo para que algumas threads não ocupem a CPU eternamente, ou por um tempo muito longo sem abandoná-lo. Senão terminará na situação acima quando uma ou duas threads executam enquanto outras simplesmente esperam para retornar. Liberamos espaço na memória graças a thread yield. Quando a thread executa o thread yield, a execução da thread é suspensa e a CPU passa para uma outra thread em execução. Essa thread aguardará até a CPU tornar-se disponível novamente.

Comparação entre linha de execução e Processo

Um sistema baseado em linha de execução é diferente de um sistema operacional multi-tarefa tradicional, em que processos são tipicamente independentes, carregam considerável estado da informação, tem endereço de memória separado e interagem somente através de mecanismos de inter-processos de comunicação. As threads, por outro lado, compartilham o estado da informação de processos únicos, e compartilham memória e outros recursos diretamente.
A troca de contexto através de linha de execução num mesmo processo é tipicamente mais rápida que a troca de contexto entre processos diferentes. Sistemas como o Windows NT e o OS/2 são feitos para ter linha de execução "baratas" e processos "caros", enquanto em outros sistemas operacionais não há grandes diferenças.
O multithreading é um modelo de programação popular que permite a execução de múltiplas linha de execução dentro de um contexto simples, compartilhando recursos do processo, e capazes de executar de forma independente. O modelo de programação em linha de execução fornece ao desenvolvedor uma execução simultânea. Entretanto, a aplicação mais interessante da tecnologia ocorre quando ela é utilizada em um processo simples permitindo uma execução paralela em sistemas multi-processados.
Um sistema multi-threaded possui um melhor desempenho que um sistema de computadores com múltiplas CPUs e com múltiplos núcleos, ou que um cluster de máquinas. Isto acontece porque a linha de execução empresta a ela mesmo uma execução simultânea. Em alguns casos, o programador precisa ter cuidado em evitar condições de concorrência e outros comportamentos inesperados.
Para um dado ser manipulado corretamente, as linhas de execução freqüentemente precisarão ser sincronizadas, para que os dados sejam processados na ordem correta. As linha de execução podem também executar operações atômicas (freqüentemente implementadas usando semáforos) com intuito de prevenir que dados comuns sejam simultaneamente modificados ou lidos enquanto o processo esta sendo modificado.
Os sistemas operacionais implementam as linhas de execução de duas formas: preempção multithreading ou multithreading cooperativa. A preempção multithreading é geralmente considerada uma implementação superior, porque permite ao sistema determinar quando uma troca de contexto pode acontecer. A multithreading cooperativa, por outro lado, confia nas threads para ceder o controle, uma vez que elas estão paradas em um ponto. Isto pode criar um problema se a linha de execução estiver esperando um recurso tornar-se disponível. A desvantagem da preempção multithread é que o sistema pode fazer uma troca em um tempo inapropriado, causando uma inversão de prioridade ou outros efeitos ruins que podem ser evitados por uma multithreading cooperativa.
Em geral:
· Criar um processo pode ser caro em termos de tempo, memória, e sincronização entre processos.
· As linhas de execução podem ser criadas sem a replicação do processo inteiro.
· O trabalho de criar uma linha de execução pode ser feito no espaço do usuário.
· Como as linhas de execução partilham o espaço de endereçamento a comunicação entre elas é mais rápida.
· O tempo gasto para troca de linha de execução é menor, em parte por que não há necessidade de troca de espaço de endereçamento.

Beneficios.

Os beneficios da programaçao multithread podem ser divididos em quatro categorias pricipais:
1. Reponsabilidade: O uso de multithreads em uma aplicaçao interativa pode pemitir que um programa continue funcionando mesmo que parte dele esteja bloqueado ou realizando uma operaçao longa, aumentando assim a responsabilidade ao usuario.
2. Compatilhamento de recursos: Como padrao, as threads compartilham memoria e o recursos do processo ao qual pertencem.

3. Economia: A alocaçao de memoria e recursos para a criaçao de processos é dispediosa. Como as threads compartilham recursos do processos ao qual pertencem, é mais eonomico criar e trocar o contexto das threads.

4. Utilizaçao de arquiteturas multiprocessadas: Os beneficios do uso de multithreads podem ser muito maiores em uma arquitetura multiprocessada, na qual as threads podem ser executadas em paralelo nos diferentes processadores. Um processo dotado de unica thread so pode ser executado em uma cpu, não importa quantos estejam a disposiçao. O uso de multiplas threads em uma maquina de multiplas CPUs aumenta a concorrencia.

Modelos de múltiplas threads

1. Modelo muitos para um: Associa muitas threads no nivel do usuaio a uma thread de kernel. O gerenciamento de thread é feito pela biblioteca threads no espaço do usuario, de modo que é eficiente; mas o processo inteiro sera bloqueado se uma thread fizer uma chamada de sistema bloqueante. Alem disso, como somente uma thread pode acessar o kernel por vez, varias threads nao podem ser executadas em paralelo em multiprocessadores.

2. Modelo um para um: Associa a thread de cada usuario a uma thread de kernel. Ele prove maior concorrencia do que o modelo muitos para um, permitindo que outra thread seja executada quando uma thread faz uma chamada de sistema bloqueante; eles tambem permite que varias threads sejam executadas em paralelo em multiprocessadores. A unica desvantegem desse modelo é que a criaçao de uma thread de usuario requer a criaçao de uma thread de kernel correspondente. Como o custo adicional da criaçao de thread do kernel pode prejudicar o desempenho de uma aplicaçao a maioria das implementaçoes desse modelo restringe o numero de threads admitidos pelo sistema.

3. Modelo muito para muitos: Multiplexa muitas threads no nivel do usuario para um numero menor ou igual de threads de kernel. O numero de threads de kernel pode ser especifico a determinada aplicaçao ou a determinada maquina. Enquanto o modelo muitos para um permite que o desenvolvedor crie quantas threads de usuario desejar, a verdadeira concorrencia nao é obtida poruqe o kernel so pode escalonar uma thread de cada vez. P modelo um para um permite maior concorrencia, mas o desenvolvedor presisa ter cuidado de nao criar muitas threads dentro de uma aplicaçao. O modelo muitos para muitos nao sofre de nenhuma desssas limitaçoes: os desenvolvedores podem criar quantas threads forem necessarias, e as threads de kernel correspondente podem ser executadas paralelamente em um sistema multiprocessado. Alem disso, quando uma thread realiza uma chamada de sistema bloqueante, o kernel pode escalonar outra thread.


Proteção

Objetivos da Proteção

. Manter a integridade do SO;
. Proteger de usuários incompetentes;
. Aumenta confiabilidade detectando erros de interface.

Domínios de Proteção

Computador: uma coleção de objetos. e.g. CPU, arquivo, impressora, semáforos, etc.
Cada objeto tem um tipo de acesso diferente: tipo abstrato de dados. O Processo deve ter acesso somente aos objetos que precisa na hora em que for preciso. Um domínio de proteção especifica quais objetos um processo pode acessar:

É uma coleção de pares ordenados

Domínios de Proteção podem ter sobreposição.

Podem ser atribuídos:

Estaticamente
Dinamicamente.

Tipos de domínios:

Usuário: e.g. diretório, impressora, etc.

Processo: e.g. espaço de endereçamento

Procedimento: e.g. variáveis locais.

Exemplos de Domínios de Proteção

Unix:
Domínio é por usuário;
Quando é necessário acessar objetos com permissões diferentes, troca-se o usuário: SETUID.
Mas se não puder trocar o usuário o sistema fica restritivo demais.

Exemplos de Domínios de Proteção

Multics:

Anéis de proteção:
Cada anel é um domínio de proteção
Anéis vão de 0 a 7, 0 tem maior acesso
Anéis maiores são contidos em anéis menores.
Modelo simplificado: dois anéis, 0: modo superusuário; 1: modo usuário.
Sistema segmentado: cada segmento pertence a um anel.
Além disto, cada segmento tem 3 bits rwx.
Troca de domínio acontece quando um processo executando em um anel chama outro em um anel diferente.

Exemplos de Domínios de Proteção

Multics:
Para garantir proteção o segmento inclui:
Acess bracket: [b1, b2], Limite: b3
Lista de portas de acesso limitado.

Se um processo no anel i chama outro no anel j:

Se i <>

Design e Implementação de Microdrivers - Fernandes

Drivers


Drivers são programas escritos para fazer a comunicação do sistema operacional com seu hardware de máquina, essa comunicação é independente de dispositivo, que o software cuida para que a solicitação seja executada, permitindo que o software interaja com o dispositivo desejado. Um driver não é um processo ou tarefa gerado pelo sistema, mas sim um conjunto de tabelas contendo informações sobre cada periférico, bem como os fluxos de informação circulante entre o computador e o periférico, pode ser visto em alguns casos como parte do processo que esta em execução.



Vantagens


Os drivers que são executados no modo usuário provém vários benefícios importantes para os usuários do sistema operacaional; como o uso de bibliotecas do sistema operacional e um ótimos sistema de depuração avançado, e claro faz o isolamento entre o sistema operacional e o kernel, esse isolamento é para que futuras falhas no driver no modo usuário não afete totalmente o sistema.



Desvantagens


Segundo a Microsft 89% dos erros reportados pelos usuários, são causados pelos drivers; esses erros são devido à falta de profissionais eficientes em programação de drivers e a grande quantidade de drivers diversos disponibilizados por fabricantes para o mesmo disposistivo.



Drivers acoplados ao kernel


Versões inferiores do Linux, o kernel já vinha com a maioria dos drivers mais usados pelos usuários acoplados ao seu kernel, quando o usuário necessitasse de um novo dispositivo, seu driver era inserido no kernel, sendo assim necessário fazer todas às vezes a sua recompilaçao. Devido ao grande trabalho de recompilar o kernel, e o tamanho do kernel que crescia exageradamente mudaram se esse critério, esse trabalho geralmente não é mais usado, agora podemos usar a arquitetura de microdrivers.



Microdrivers


Microdrivers é um driver de dispositivo que está dividido em uma camada de kernel, chamado de k-driver, e uma camada no modo usuário, chamda de u-driver.

O uso de Mircodrivers é ter uma melhor funcionalidade de um dispositivo e maximizar o seu desempelho. Veja abaixo como um microdriver, com as suas funcionalidade é dividido (split) entre o componente do modo kernel e o componente de modo usuário.

O que demostra neste estudo é que a seção critica do código dos dispositivos de drivers é que mais de 70% contém funcionalidades não criticas.



Arquitetura do Microdriver


Um microdriver consiste de um componente do modo kernel que implementa as funcionalidades criticas do modo usuário e um processo que implementa as funcionalidades não criticas.



Implementação de microdrivers no Linux


No sistema operacional Linux o microdrivers foi implementado no kernel a partir da versão kernel 2.6.18.1, para que fosse feita uma demonstração de viabilidade e a possibilidade de uma melhor performacance do sistema. Onde esta implementação consiste em sei partes:

  • k-driver;
  • kernel runtime;
  • usuário runtime;
  • u-driver;
  • usuário stubs;
  • kernel stub.



Vantagens


A arquitetura Microdrivers oferece três vantagens:

1. A capacidade de desenvolver código de driver ao nível de usuário, com sofisticadas ferramentas de programação;

2. A redução na quantidade de código escrito a mão no kernel, gerando uma melhor viabilidade;

3. Melhoria da confiabilidade, isolando o kernel a partir de bugs no código em nível de usuário.



Performance


Os testes apresentados neste artigo foram medidos o desempenho (throughput e como a utilização da CPU) dos drivers, o de rede foi utilizado o utilitário netperf. E como esperado, estes resultados demonstraram o caso comum. E que experimentos demostram que se 65% do código do driver for removido do kernel, a performance não será afetada.

Contudo os microdrivers são uma grande alternativa tanto pra uma maior segurança do sistema operacional, como pra os dispositivos de drivers.



Os artigos podem ser obtidos em:


The Design and Implementation of Microdrivers

http://www.cs.rutgers.edu/~vinodg/papers/asplos2008/asplos2008.pdf

http://portal.acm.org/citation.cfm?id=1346303



Complemento:


Microdrivers - A New Architecture for Device Drivers

http://pages.cs.wisc.edu/~arinib/hotos2007.pdf

terça-feira, 23 de junho de 2009

1 - Chamadas ao Sistema - Camilla

Olá pessoal!

Bom, nesta matéria nós vamos abordar diversos assuntos, que servirão de base para estudos mais aprofundados, a CHAMADAS AO SISTEMA.
A interação entre processos dos usuários e o sistema operacional é feita por meio de chamadas ao sistema (system calls). Essas chamadas estão geralmente disponíveis na forma de instruções em linguagem de montagem e fazem parte usualmente de listagens contidas em manuais usados por programadores de linguagens de montagem.
Diversas linguagens como C, Bliss, BCPL, PL/360 e PERL- foram definidas para substituir as linguagens de montagem na programação de sistemas.
Três métodos gerais de passagem de parâmetros ao sistema operacional são usados. A abordagem mais simples é a passagem de parâmetros em registradores, entretanto, podem existir mais parâmetros do que registradores, dos parâmetros são geralmente armazenados em um bloco ou em uma tabela na memória e o endereço da tabela é passado em um registrador. Os valores dos parâmetros podem também ser colocados, ou retirados, na pilha (ou empilhados) pelo programa e desempilhados pelo sistema operacional. As chamadas ao sistema podem ser agrupadas de maneira geral em cinco categorias principais: controle de processos, manipulação de arquivos, manipulação de dispositivos, manutenção de informações e comunicações.


Tipos de Chamadas de Sistema:
1) Controle de Serviços e Processos;
2) Manipulação de Arquivos;
3) Gerenciamento de Dispositivos;
4) Armazenamento e Transferência de Dados;
5) Comunicações.

1) Controle de Serviços e Processos

Um programa em execução pode interromper sua execução normalmente (termine) ou não (abortar). Se uma chamada ao sistema é feita para terminar a execução de um programa anormalmente ou se ocorre algum erro sem possibilidade de tratamento durante a execução de um programa, o conteúdo de toda a memória é às vezes impresso e uma mensagem de erro é gerada. Esse dump é feito em disco e pode ser examinado por um depurador para determinar a causa do problema. Em circunstâncias normais ou anormais, o controle deve ser transferido para o interpretador de comandos, pelo sistema operacional. O interpretador de comandos lê então o próximo comando. Em um sistema batch, o interpretador de comandos normalmente termina o processamento do serviço como um todo e passa a processar o próximo serviço.
Um programa em execução pode carregar outro programa (carregar) e iniciar a sua execução (executar). Essa característica permite que o interpretador de comandos execute um novo programa a partir de um comando especificado por algum usuário ou de um comando para processamento em ´segundo plano´ (backgroud) ou quando um usuário pressiona um botão do mouse. Uma questão interessante é determinar para onde retornar o controle quando um programa carregado por outro termina sua execução.
Após criar novos serviços e processos, podemos ter de esperar que eles terminem sua execução. Podemos querer esperar por certo período de tempo (esperar tempo); mais provavelmente, podemos querer esperar que um determinado evento ocorra (esperar evento). Os serviços ou processos devem então indicar a ocorrência desse evento (sinalizar evento). Chamadas ao sistema desse tipo, que tratam da coordenação de processos concorrentes.


2) Manipulação de Arquivos

Devemos primeiro ser capazes de criar e remover arquivos. Ambas as camadas requerem o nome de um arquivo e talvez alguns atributos. Podemos também ler, gravar ou reposicionar (ir para o inicio ou para o fim de um arquivo, por exemplo). Finalmente, precisamos fechar o arquivo, para indicar que não estamos mais usando. Podemos precisar desse mesmo conjunto de operações para diretórios, se tivermos um sistema de arquivos que usa uma estrutura de diretórios para organização dos arquivos. Além disso, tanto para arquivos quanto para diretórios, precisamos poder determinar os valores de vários atributos, e talvez modificá-los, se necessário. O nome e o tipo do arquivo, os códigos de proteção, as informações sobre o uso do arquivo e assim por diante podem ser atributos de um arquivo. São necessárias para essa finalidade no mínimo duas camadas, obter atributo de arquivo e definir atributo de arquivo. Em alguns sistemas operacionais existem muitas outros.

3) Gerenciamento de Dispositivos

Um programa em execução pode precisar de recursos adicionais para que possa continuar o processamento. Esses recursos podem ser mais espaço em memória, unidades de fita, acesso aos arquivos e assim por diante. Se os recursos necessários estão disponíveis, eles podem ser alocados e o controle pode retornar ao programa do usuário; caso contrário, o programa terra de esperar ate que recursos suficientes estejam disponíveis.
Os arquivos podem ser vistos como dispositivos virtuais ou abstratos. Portanto, muitas chamadas ao sistema usadas para arquivos são também necessárias para dispositivos. Em um sistema multiusuario, no entanto, devemos primeiro requisitar o uso de um dispositivo para assegurar seu uso exclusivo. Quando terminarmos de usá-lo, devemos liberá-lo. Essas chamadas ao sistema são similares ás de abrir e fechar arquivos. Depois de requisitar um dispositivo ( e depois de ele ter sido alocado para nosso uso), podemos ler, gravar e (possivelmente) reposicionar esse dispositivo, da mesma maneira como acontece com arquivos comuns. A semelhança entre dispositivo de E/S e arquivos é tanta que muitos sistemas operacionais, incluindo o Unix e o MS-DOS, combinam os dois em uma única estrutura nesse caso, dispositivos de E/S são identificados por nomes de arquivos especiais.


4) Armazenamento e Transferência de Dados

Muitas chamadas ao sistema têm como único objeto transferir dados entre os programas dos usuários e o sistema operacional. Por exemplo, a maioria dos sistemas fornece uma chamada ao sistema para retornar a hora e data atuais. Outras chamadas são usadas para fornecer informações sobre o sistema, como o número atual de usuários, o numero da versão do sistema operacional que está sendo usada, a quantidade de espaço livre na memória e em disco e assim por diante.
Além disso, o sistema operacional mantém informações sobre todos os processos e existem chamadas ao sistema para acesso e essas informações. Em geral, existem também chamadas para modificar o valor de atributos de processos (obter atributos de processo e definir atributos de processo).

5) Comunicações

Existem dois modelos de comunicação comumente usados. No modelo de troca de mensagens, as informações são trocadas por intermédio de mecanismos de comunicação possa ser realizada, é preciso que seja estabelecida uma conexão. O nome do processo com o qual será estabelecida a comunicação deve ser conhecido, quer ele esteja em execução na mesma CPU quer esteja em outro computador conectado através de uma rede de comunicações. Cada computador em uma rede possui um nome pelo qual é comumente conhecido. Da mesma forma, cada processo possui um nome, que é traduzido para uma identificação equivalente, pelo sistema operacional a ele se refere. Existem chamadas ao sistema para obter identificações de um computador e de um processo que fazem essa tradução. Essas identificações são passadas para chamadas ao sistema de propósito geral (abrir e fechar) ou então para chamadas ao sistema específicas (do tipo abrir conexão e fechar conexão), dependendo do modelo de comunicações usado. O processo que recebe a comunicação deve usualmente enviar uma concordância com a comunicação, por meio de uma chamada para aceitar conexão.
A maioria dos processos que em geral recebem mensagens é especial, desenvolvidos com esse propósito específico, chamados de daemons que recebe a comunicação, conhecido como servidor, passam então a trocar mensagens por meio de chamadas ao sistema para ler mensagem e gravar mensagem. Por fim, é chamada para fechar conexão.
Em um modelo de memória compartilhada, os processos usam ao sistema para mapear memória de forma a obter acesso a regiões da memória reservadas a outros processos.








Principais dispositivos

Os principais dispositivos de entrada de informações são:

- teclado,
- mouse,
- drive de CD / DVD-ROM,
- pen drive,
- scanner,
- microfone,
- joystick,
- câmera filmadora,
- câmera digital,
- tela sensível ao toque,
- mesa gráfica,
- caneta ótica.

Já os dispositivos de saída são:
- monitor de vídeo,
- drive de CD-ROM,
- caixa de som,
- impressora,
- sensores (movimento, temperatura etc)
- óculos (para realidade virtual).

E os principais dispositivos tanto de entrada como de saída de informações são:
- modem,
- drive de disquete,
- gravador de CD / DVD,
- disco rígido.

8 - Memória Virtual - Linux

Olá pessoal,
Neste Tópico iremos abordar um conceito muito importante e fundamental para os Sistemas Operacionais, a MEMÓRIA VIRTUAL.

Tanto no Linux quanto no Windows o conceito de memória virtual está presente. A memória virtual foi criada porque, obrigatoriamente, um programa necessita passar pela memória principal para ser executado, e como quase sempre não é possível ter memória RAM suficiente para executar todo o programa da memória, é necessário executar esse programa em partes.

A memória virtual é uma área de troca de dados que serve como uma extensão da memória principal, ou seja, a memória RAM. Por exemplo, se você possui 64 mb de RAM livre e quer rodar um programa que ocupa 70 mb de RAM, deverá carregar os primeiros 64 mb para rodar o início do programa e os 6 mb restantes serão armazenados na memória virtual, para depois serem copiados para a memória principal a fim de serem executados. Isso ocorre, é claro, à medida que a execução do programa for se desenrolando e o programa em questão (ou outros programas) liberarem a memória que ocupavam para o uso de outro programa. Dessa forma, temos um contínuo fluxo de dados entre o disco rígido (onde se localiza a memória virtual) e a memória RAM.

Como o disco rígido possui uma movimentação mecânica de cabeças de leitura e gravação, ele é considerado lento se comparado à dispositivos de memória, cujo acesso às informações é totalmente eletrônico. É por isso que pouca memória RAM implica em usar muita memória virtual, que por sua vez, implica em usar muita leitura/escrita no disco rígido, que por sua vez implica em lentidão geral no sistema.

A memória virtual foi um recurso introduzido nos PCs para permitir que o sistema use um arquivo dedicado especialmente para a tarefa de armazenar programas que são abertos pelo sistema e, dependendo da taxa de uso de cada um, haver uma troca entre o arquivo e a memória RAM, por este motivo, a memória virtual também é conhecida como “arquivo de troca”, “swap file” ou simplesmente “swap”.

Pouca gente sabe realmente do que se trata a partição Linux-Swap (ou apenas Swap), existindo diversos mitos sobre o seu uso e a quantidade de espaço que deve ser disponibilizada para ela. Neste texto procuraremos definir conceitos de Memória Virtual, Swap e Paginação, para que sirva de consulta ou, no mínimo, um início para alguma pesquisa ou estudo do assunto, além de procurar esclarecer questões sobre o espaço a ser disponibilizado para a partição Linux-Swap bem como recomendar o tamanho deste espaço de acordo com a quantidade de memória RAM que um computador possua, tendo como base uma pesquisa feita na Comunidade Linux Brasil. Caso este seja seu único interesse, passe para a parte final do texto.

Índice
1. A Memória RAM
2. Memória Virtual
3. Swapping ou Paging (Paginação)?
4. No GNU/Linux
5. Qual deve ser o tamanho da partição Linux-Swap?
6. Observações adicionais


1. A Memória RAM
Para que um computador funcione é necessário que os dados que serão trabalhados pelo processador estejam carregados na memória. Esses dados então são passados desta memória (a Memória RAM), para o processador, onde, após processados, serão movidos de volta para a Memória RAM. Assim o usuário pode executar programas e, consequentemente, utilizar a máquina. (Esta informação está correta, porém é superficial; Para mais detalhes ou um aprofundamento melhor consulte bibiliografia espefíca para Introdução à [Ciência da] Computação) Todo esse processo ocorre numa velocidade além da percepção do usuário, mas nem sempre a Memória RAM dá conta de carregar tudo o que está sendo executado em um computador, então se faz necessário o uso da Memória Virtual.

2. Memória Virtual
A Memória Virtual é uma extensão da memória RAM. Quando a Memória RAM está ocupada, não sendo mais possível carregar dados nela, ou existem dados que não estão sendo utilizados por muito tempo, ocupando desnecessariamente a RAM, é utilizada a Memória Virtual, que pode ser um arquivo ou vários arquivos que armazenam dados dos processos carregados, ou seja, utilizando a Memória Secundária (de armazenamento), com uma partição dedicada ou utilizando a mesma partição do sistema, liberando a Memória RAM para que dados possam ser carregados nela. Esses dados carregados na Memória Virtual podem ser carregados na Memória RAM novamente conforme a necessidade de processamento dos mesmos. Então ocorre o processo de "troca" em que os dados ficam alternando entre a Memória RAM e a Virtual a fim de serem processados, executados, ou seja, para que o "programa" funcione, falando grosseiramente. Esse processo de troca é o chamado processo de SWAP e ocorre de modo imperceptível para o usuário, porém não substitui o uso da Memória RAM, pois a leitura do Disco-Rígido é mais lenta (centenas de vezes mais lenta) que a da Memória RAM.

3. Swapping ou Paging (Paginação)?
É comum a confusão entre estes dois termos. O Swapping consiste em, quando necessário, mover o processo inteiro para a memória virtual, o que causa uma perda de performance pois o processo quando está "em espera", fica totalmente na Memória Virtual e quando estiver para ser
executado será totalmente carregado na Memória RAM. Já o Paging (Paginação) foi introduzido como uma otimização para o swapping onde apenas as partes ("pages", páginas) menos utilizadas ou ociosas do processo são movidas para a Memória Virtual, assim quando um processo é executado, apenas essas partes do processo são movidas, diminuindo a troca de dados entre a Memória RAM e a Memória Virtual. As primeiras versões do Unix System V (conhecidos também como SysV) funcionavam apenas com o swapping. Posteriormente (a partir do release 2.0, aparentemente) foi implementado o paging ao Unix System V. Os sistemas operacionais atuais não utilizam o processo de Swapping, apenas o Paging, mas é comum que se utilize apenas o termo Swapping (ou Swap) para a definição deste processo, sem a diferenciação entre os termos Paging e Swapping, tratando-os pelo mesmo nome, exceto quando se estudanda estes processos de maneira específica.

4. No GNU/Linux
O sistema operacional GNU/Linux pode trabalhar de duas formas:
1- Dedicando um ou mais arquivos de SWAP;
2- Dedicando uma ou mais partições inteiras à Memória Virtual, a partição SWAP (ou Linux-Swap). Cada um desses métodos tem uma vantagem: usar uma partição torna o processo de swap mais rápido; utilizar um arquivo torna mais fácil a alteração do tamanho do espaço disponibilizado (é mais fácil alterar o tamanho de um arquivo do que alterar o tamanho de uma partição, por isso é recomendável deixar um tamanho suficiente para a partição swap, garantindo que não faltará memória no computador). Lembrando que é possível usar mais de um arquivo e mais de uma partição, ou a combinação deles (arquivo e partição ao mesmo tempo). Alguns usuários confundem conceitos e tem o mau hábito de dizer que "a partição swap deve ter o dobro do espaço da Memória RAM", o que simplesmente não é verdade. É inviável e inútil que um usuário com 1 GB de RAM, por exemplo, disponibilize 2 GB para "nada", pois com 1 GB de RAM praticamente não se utiliza o swap. Esse usuário estaria jogando fora um espaço onde poderia até mesmo instalar uma outra distribuição. Bem como para uma máquina com 128 MB de RAM 256 MB de SWAP provavelmente será insuficiente. O mais correto a se fazer é experimentar, procurar informações com outros usuários e não ouvir conselhos de qualquer um.

5. Qual deve ser o tamanho da partição Linux-Swap?
Tendo como base uma pesquisa feita neste tópico da Comunidade Linux Brasil foi possível separar algumas situações de Quantidade de Memória RAM x Espaço para SWAP e fazer certas interpretações. Algo que é importante observar é que o uso de memória pode variar entre as distribuições em função dos pacotes, serviços habilitados por padrão, entre outras coisas, e que esses serviços e pacotes podem ser desabilitados ou removidos após a instalação dela tornando-a mais "leve". A primeira recomendação é saber se você estará utilizando uma distribuição "leve", que não requer muita memória quando recém-instalada, ou "pesada", que requer muita memória quando recéminstalada.

1) 128 MB a 256 MB de RAM
Em computadores com 128 MB é mais provável que ocorram problemas por falta de memória, como lentidão ou até mesmo a finalização da execução de aplicações por falta de memória. Para máquinas com 128 MB, por exemplo, a regra do "dobro da RAM" não se aplica, pois pode ser insuficiente e arriscado. Para máquinas com valores no intervalo aproximado de 128 a 256 MB de RAM é comum (e recomendável) o uso de pelo menos 512 MB para a partição swap (falando em números aproximados pois esse número varia de 500 a 600 MB, chegando até a 1 GB em casos mais extremos e de muita dúvida e precaução por parte do usuário, ou seja, raras exceções, chegando a ser um exagero desnecessário)

2) 512 MB a menos de 1 GB de RAM
Para computadores com valores no intervalo acima de 512 MB a abaixo de 1 GB de RAM o uso de 1 GB ou mais de swap é exagerado e desnecessário. Como já existe uma boa quantidade de RAM disponível, são poucos os casos em que se faz necessário o uso de um espaço muito grande pra swap, sendo comum o uso de 384MB de swap, lembrando que este valor é aproximado e varia de 256 a 512 MB, dependendo do uso.

3) Mais de 1 GB de RAM
O que surpreendeu com os dados obtidos foi que a grande parte dos usuários que possui 1 GB ou mais de RAM também disponibilizam um espaço para o swap. É comum que disponibilizem 200 MB do HD para o swap. Isso ocorre pelo fato de que os usuários não querem correr o risco de ter o desempenho comprometido por falta de memória (mesmo sendo pouco provável que ocorra), mas levando em consideração que, hoje em dia, 200 MB de um HD representa uma minúscula parte deste, o que torna viável a disponibilização de espaço para swap em máquinas com mais de 1 GB de RAM.

6. Observações Adicionais
Observação1: Recentemente eu tive um problema com um dos meus pentes de memória, ficando com apenas 512 MB, como eu não disponibilizei nenhuma partição para SWAP, acabei tendo alguns problemas ao compilar programas e utilizar a máquina ao mesmo tempo, sendo necessária a criação de um arquivo de SWAP. Moral da história: Era melhor ter disponibilizado pelo menos uns 256 MB de SWAP, mesmo que mantivesse desativado, sem entrada no fstab.

Observação2: Mesmo que a máquina possua 1 GB de RAM ou mais, pode ser interessante disponibilizar um certo espaço para o SWAP já que essa "tecnologia" acaba, por muitas vezes, otimizando o uso da própria memória RAM, pois partes desnecessárias dos processos não ficam carregados nela e são movidos para o swap, assim a RAM fica com espaço disponível para outras funções (como cache). - Distribuição "leve" ou "pesada"Com base em informações fornecidas por usuários de diversas distribuições é fácil definir se estará usando uma distribuição considerada "leve" ou "pesada". Isso serve também para definir a quantidade de espaço a ser disponibilizada para o swap. Utilizando o esquema acima podemos definir que, caso a escolha seja uma distribuição "leve", podemos manter o mínimo de swap compatível com a Memória RAM da máquina. Caso a distribuição seja pesada, utilizamos a definição de espaço que está logo acima. Por exemplo: - Minha máquina possui 512 de RAM, que se enquadra na opção 2 de swap (em torno de 384 MB), mas eu escolhi uma distribuição considerada "pesada" pelos usuários, então eu devo passar a utilizar a opção 1 de swap (em torno de 500 MB); - Minha máquina possui 256 de RAM, que se enquadra na opção 1 de swap, mas eu escolhi uma distribuição considerada "pesada" pelos usuários, então eu devo considerar utilizar um espaço grande para o swap (em torno de 500 MB).Observação: Estes valores foram definidos com base em uma pesquisa com diversos usuários. É possível que nunca seja requisitado de sua máquina um uso "tão grande" de swap, porém os usuários tendem a aplicar duas regras nesse assunto: 1) É melhor previnir; 2) Atualmente "todo esse espaço" no HD representa uma quantidade insignificante do total deste, então não existem motivos para não disponibilizar se for levado em consideração a regra 1.

Observação3: Existem relatos de que em casos de servidores (com máquinas boas, dignas de serem servidores) e/ou máquinas que são utilizadas basicamente para gerenciamento de banco de dados, pode existir uma perda de desempenho ao utilizar, desnecessariamente, um espaço para SWAP.

11 - Segurança - Wassily

Os recursos do computador precisam ser protegidos contra acesso não-autorizado, destruição ou alteração maliciosa e introdução acidental a inconsistência.

                    Formas de acesso malicioso


• Leitura não autorizada de dados (ou roubo de informações)
• Modificação não-autorizada de dados
• Impedimento de uso legítimo do sistema (ou negação de serviço)

Para proteção do sistema, é necessario tomar medidas de segurança em 4 níveis:


Físico: Instalações contendo sistemas computadorizados precisam ser fisicamente protegidas contra a entrada armada ou sorrateira de intruosos


Humano: Evitar que usuário tenha a chance de autorizar um usários que podem dar acesso a intrusos.


Rede: A interceptação do enorme fluxo de dados nos sistemas modernos pode ser prejudicial, e a interrupção das comunicações poderia constituir um ataque de negação de serviço (denial of service) remoto, diminuindo o uso dos usuários e a confiança do sistema


Sitesma operacional: Precisa se proteger contra brechas de segurança acidentais ou propositais.

                                               

                    Autentificação do usuário


-Identificar os programas e processos em execução, inicialmente identificando cada usuário do sistema.

Formas:
Senha – se senha fornecida pelo usuário combinar com a senha armazenada no sistema, o sistema considera que o usuário é legítimo. Usadas para proteger objetos no sistema computadorizado, na ausência de esquemas de proteção mais complexos.


Vulnerabilidades da senha – podem ser adivinhadas, expostas de forma acidental, farejadas, ou transferidas de usuários autorizados para não autorizados.


Senhas criptografadas – O sistema contém uma função (algorítmo de criptografia) bem difícil de inverter, mas simples de calcular. A função é encarregada de codificar todas as senhas. Mesmo que a senha seja vista, não poderá ser decodificada a menos que se conheça o código usado na decodificação. Há porém uma falha, já que o sistema não tem mais o controle sobre as senhas. Qualquer um com uma cópia do arquivo de senhas pode executar rápidas rotinas de criptografia contra ela. 

-Novas versões do UNIX armazena as entradas de senha criptografadas em um arquivo que só pode ser lido pelo superusuário
-Muitos sistemas como o próprio UNIX tratam apenas os primeiros caracteres significativos da senha.

Senhas de única vez – Quando a sessão é iniciada, o sistema seleciona aleatoriamente e apresenta uma parte de um par de senhas; o usuário precisa fornecer a outra parte. A senha é diferente em cada ocasião, e qualquer um que capture a senha de uma sessão e tente reutilizá-la em outra sessão falhará. 


Biometria – Leitores de impressão digital lêem os padrões de sulcos do seu dedo e os convertem em uma sequência de números. O software pode então digitalizar um dedo no aparelho e comparar suas características com aquelas sequências armazenadas. 

                    Ameaças ao programa

Cavalo de tróia – em sistemas que permitem que programas escritos por usuários sejam executados por outros usuários, caso os programas sejam executados com direitos de acesso do usuário executando, outros usuários podem abusar desses direitos. Um segmento de código que abusa do seu ambiente é um cavalo de Tróia.


Porta de armadilha – projetista de um programa ou sistema pode deixar um furo no software onde somente ele é capaz de usar.


Estouro de pilha e buffer – o ataque explora um bug de um programa. O atacante envia mais dados do que o programa estava esperando, e por tentativa e erro, ou examinando o código fonte do atacado, determina a vulnerabilidade.

 

                    Ameaças ao sistema

 
Worm – Uso do mecanismo de procriação para arruinar o desempenho do sistema. Verme procria cópias de si mesmo usando os recursos do sistema e talvez vloqueando todos os acessos.


Vírus – Se espalham em outros programas. Fragmentado de código embutido em um programa legítmo. 


Negação de serviço – Visa interromper o uso legítmo de um sistema ou instalação.                            

                   Segurança de sistemas e instalações

-Sondar o sistema periodicamente em busca de furos na segurança.

Detecção de intrusões

Possui grande variedade de técnicas, que variam por diversos eixos:
• Momento em que detecção ocorre
• Tipos de entradas examinadas para detectar a atividade intrusiva
• Intervalo de capacidades de resposta

Auditoria e logging – Elementos relevantes à segurança são registrados em uma trilha de auditoria e depois comparados com assinaturas de ataque ou analisados em busca do comportamento anômalo. 

Tripwire – ferramenta para monitorar os sistemas de arquivos em busca de arquivos acrescentados, excluidos ou alterados, e alertar os administradores de sistemas sobre essas modificações.

Monitoração de chamadas de sistema – Monitora as chamadas de sistema de um processo para detectar, em tempo real, quando um processo está desviando do seu comportamento esperado de chamada de sistema. 

                    CRIPTOGRAFIA
 
- A criptografia é usada para restringir os emissores e receptores em potencial de uma mensagem. É baseada em segredos, chamados chaves, que são distribuidos seletivamente aos computadores em uma rede e usados para processar mensagens. Permite ao destinatário de uma mensagem verificar se a mensagem foi criada por algum computador que possui ou uma certa chave, ou origem da mensagem.

Codificação -É um meio de restringir os possíveis receptores de uma mensagem. Um algorítmo de codificação permite ao emissor de uma mensagem garantir que somente um computador possuindo uma chave certa possa ler a mensagem

                    Classificações da segurança do computador


• A - Nível mais alto, equivalente a B3 arquitetonicamente, mas utiliza especificações de projeto formais e técnicas de verificação, concedendo um alto grau de garantia que a TCB foi implementada de maneira correta.
• B – Todas as características da C2, e rótulo de sensibilidade a cada objeto
• C – Proteção discricionária e contabilidade dos usuários e suas ações
• D – Classificação de nível mais baixo, proteção mínima


Bibliográfia utilizada

SILBERSCHATZ, Abraham - Sistemas Operacionais com Java, 7ª ed. rev. atual. - Rio de Janeiro: Elsevier Campus, 2008



TANENBAUM, Andrew S. - Sistemas Operacionais Modernos, 2ª ed. - São Paulo: Prentice Hall, 2003




STALLINGS, william - Operating Systems: Internals and Design Principles, Sixth Edition, 2009.