14.03.2015 Views

EP01 – Mini-Shell - Rede Linux IME-USP

EP01 – Mini-Shell - Rede Linux IME-USP

EP01 – Mini-Shell - Rede Linux IME-USP

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

<strong>EP01</strong> <strong>–</strong> <strong>Mini</strong>-<strong>Shell</strong><br />

MAC0422 - Sistemas Operacionais <strong>–</strong> 2o. Sem./2006<br />

Carlos Duarte do Nascimento (Nº <strong>USP</strong> 3099351)<br />

Willian Gigliotti (Nº <strong>USP</strong> 4963454)<br />

Introdução<br />

Este documento descreve a implementação do <strong>EP01</strong> (“<strong>Mini</strong>-<strong>Shell</strong>”), que consiste na<br />

implementação de um interpretador simplificado de comandos simplificado, conforme enunciado<br />

disponibilizado no sistema Paca/Moodle, acrescido de dois comandos extras (por ser entregue em<br />

dupla) e da execução de processos em background (comando “&”).<br />

Metodologia<br />

Separamos o projeto em unidades funcionais, atribuindo cada uma a um código-fonte (e, a cada<br />

um deles, um arquivo de header de mesmo nome, além do arquivo comum comando.h). Estes<br />

arquivos são os seguintes:<br />

●<br />

●<br />

●<br />

●<br />

main.c: funcionamento central do shell (leitura da linha de comando, fork, etc.);<br />

interpretador.c: parsing da linha de comando;<br />

cst.c: interface (e tabela de símbolos) para os comandos customizados (internos);<br />

comandos.c: implementação dos comandos customizados.<br />

O mais importante foi separar o shell em si (main.c) do interpretador de comandos<br />

(interpretador.c). A codificação foi feita usando ferramentas tradicionais (vi, gcc, make), e a<br />

depuração foi feita inicialmente no interpretador, e para cada comando à medida em que era<br />

implementado.<br />

Sendo o EP em dupla, optamos por implementar os comandos ps e chmod. Este último foi feito<br />

através das chamadas stat e chmod, enquanto que o primeiro foi feito através da leitura do<br />

pseudo-sistema de arquivos /proc 1 , selecionando um subconjunto apropriado das informações, e<br />

listando todos os processos visíveis.<br />

Durante os testes, acabamos fazendo a execução de múltiplas tarefas em background (para<br />

observar o comportamento dos dados coletados por getrusage. Isto acabou nos levando a<br />

implementar, logo nos primeiros estágios, a opção “&”, que permite a execução de tarefas em<br />

background.<br />

1 Nossa preferência era por utilizar chamadas de sistema nesta implementação, tendo em vista o objetivo da atividade<br />

proposta. Entretanto, a única alternativa que encontramos neste sentido foi o uso de um driver de kernel como o devps,<br />

mas, por se tratar de uma alternativa não-padronizada (e possivelmente não disponível), optamos pelo parse do /proc.


Análise<br />

Os resultados obtidos (via getrusage) foram consistentes com o exposto em sala de aula, e o<br />

shell se mostrou capaz de executar comandos interativos e não-interativos como shells<br />

tradicionais.<br />

Dentre as facilidades que um shell mais completo possui, podemos citar:<br />

●<br />

●<br />

●<br />

●<br />

Expansão automática de wildcards em parâmetros (que permite, por exemplo, digitar vi *.txt e<br />

editar todos os arquivos .txt);<br />

Autocomplete (funcionlidade que, ao ser acionada por uma tecla, ex.: Tab, faz com que o shell<br />

procure um arquivo cujo nome se inicie pelo trecho que já foi digitado)<br />

Reconhecimento de uma linguagem script (através da implementação de conceitos como<br />

variáveis e estruturas de fluxo, e da possibilidade de receber como parâmetro um arquivo de<br />

comandos);<br />

Pipelines (que permitem a execução de múltiplos processos de forma a encadear a saída de um<br />

na entrada de outro <strong>–</strong> boa parte da operação de sistemas Unix-like consiste neste tipo de<br />

agregação, normalmente suportada por um shell e sua linguagem script).<br />

As informações que getrusage oferece (na struct rusage) são interessantes para um<br />

diagnóstico pontual do processo, mas seria útil obter, por exemplo, dados históricos de utilização<br />

dos recursos (ex.: “picos” das informações de memória nos campos ru_i?rss) 2 .<br />

Quando encontradas, as discrepâncias entre os tempos medidos por getrusage e gettimeofday<br />

se dão pelo fato de que o uso da primeira acaba mensurando o tempo total decorrido durante a<br />

execução do processo (incluindo aí o tempo gasto por outros processos em execução), enquanto<br />

que a segunda usa a “contabilidade” interna do kernel para obter apenas o tempo gasto com o<br />

processo executado 3 .<br />

Sobre o comando “&”, este foi efetivamente implementado. A maior mudança foi capacitar o<br />

parser a interpretá-lo, além de fazer a “espera” pelo processo-filho ser condicional à execução em<br />

foreground ou background. Vale lembrar que as estatísticas foram omitidas para processos em<br />

background.<br />

2 Por outro lado, este tipo de bookkeeping pode comprometer a performance. De qualquer forma, bibliotecas como<br />

PerfSuite (http://perfsuite.ncsa.uiuc.edu/) oferecem a funcionalidade desejada.<br />

3 Podem haver outras discrepâncias causadas pela “resolução” com que cada uma das informações é capturada pelas<br />

respectivas implementações destas funções no S.O. em questão, mas julgamos esta causa menos relevantes em um<br />

sistema multitarefa típico do que a causa efetivamente relatada.


Conclusão<br />

Em resumo, implementamos um shell com as características pedidas, e, como exercício extra, a<br />

execução de comandos em background (“&”), o que possibilitou fixar o conceito de fork, as<br />

chamadas de sistema apresentadas e a visão geral do agendamento de processos e outros detalhes<br />

interessantes do funcionamento de um S.O. baseado em Unix como o <strong>Linux</strong>.<br />

Um dos maiores limitantes ao uso do shell é, de fato, a já mencionada ausência da expansão de<br />

wildcards nos parämetros (indispensável já que, sob o <strong>Linux</strong>, as aplicações não tomam para si<br />

esta responsabilidade, como ocorre me outros sistemas) e também a inexistência de pipelining.<br />

Havendo mais tempo, poderíamos trabalhar o aspecto acima, e a expansão de parâmetros para os<br />

comandos em si também deveria ser melhorada. A implementação de processos em background<br />

(&) poderia também se beneficiar da exibição de dados getrusage (de forma que eles não<br />

atrapalhassem a execução e medição de outros comandos <strong>–</strong> razão que nos levou a suspender a<br />

exibição da estatística neste caso). O I/O para processos em background também deve ser<br />

cuidado, particularmente se um processo interativo for (acidentalmente) lançado em background.<br />

A proposta do projeto é bastante válida para um primeiro EP, pois é um meio-termo interessante<br />

entre “baixo nível” (manipulação de processos, chamadas do sistema, etc.) e a segurança e<br />

praticidade de uma aplicação rodando em user-mode. Desta forma, tanto alunos com mais<br />

experiência em programação quanto iniciantes conseguem se beneficiar.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!