LEIC/LETI 2015/2016

Sistemas Operativos

Aula 1

Introdução ao Ambiente Unix


Objectivo

Material de Apoio

Introdução

Estude o ciclo de desenvolvimento de aplicações em linguagem C no ambiente Unix (slide).

Copie o ficheiro aula1-eg1.tgz para a sua área de trabalho e descomprima o seu conteúdo com o comando:

tar -zxvf aula1-eg1.tgz

1. Geração do executável (slide)

  1. Visualize e compreenda o conteúdo dos ficheiros.
  2. Compile os ficheiros. Verifique depois que os ficheiros objecto foram criados usando o comando "ls" através da interface operacional (shell).
    gcc -g -c list.c main.c
  3. Faça a ligação dos ficheiros objecto de modo a produzir o executável denominado main.
    gcc -o main list.o main.o
  4. Execute a aplicação main e compreenda o resultado.
    ./main

2. Utilização do debugger gdb

  1. Execute a aplicação no debugger gdb:
    gdb main
  2. Coloque um breakpoint na primeira instrução da função insert_new_process (ficheiro list.c e linha 36):
    b list.c:36
  3. Execute a aplicação usando o comando run:
    r
    A aplicação executa-se até ao breakpoint.
  4. Pode agora ver o valor das variáveis que estão no scope da função usando o comando print:
    p item
    ou
    p *item
    Qual a diferença entre estes dois comandos?
  5. Pode agora executar a aplicação utilizando o comando de step para executar a próxima instrução entrando dentro das funções:
    s
    ou o comando de next para executar a próxima instrução sem entrar dentro das funções:
    n
  6. Enquanto executa os comandos next ou step pode ir executando o comando print para mostrar o valor das variáveis ou executar apenas uma vez o comando display:
    display *item
  7. Altere agora o ficheiro list.c: Descomente o comentário da linha 61 e comente a linha 62.
  8. Execute o seguinte comando fora do gdb para colocar o limite do tamanho do ficheiro core com o valor de 10Mb:
    ulimit -c 10000000
  9. Gere o executável e execute o programa fora do gdb. O erro de segmentation fault irá ocorrer.
  10. O gdb é uma muita boa ferramenta para saber o que aconteceu. Para isso, comece por listar os ficheiros que estão na diretoria:
    ls
    Que observa?
  11. Use em seguida o gdb para saber onde ocorreu o erro executando:
    gdb main <ficheiro core>
  12. O gdb irá ficar parado na instrução onde ocorreu o erro. Para saber qual a instrução onde o erro ocorreu execute o comando backtrace:
    bt
  13. O gdb mostra-lhe assim a função em que ocorreu o erro e todas as funções que chamaram essa até ao nível da função main. Algumas dessas funções são de sistema, mas há duas que podemos reconhecer: lst_print e main. O primeiro número em cada linha indica o nível em que essa função está. Para observar as variáveis que estão no nível da função lst_print deve mudar para esse nível executando o comando frame seguido do nível. Por exemplo:
    frame 2
  14. Pode agora ver o conteúdo das variáveis que estão no scope da função lst_print:
    p item
    Pode assim ver que o erro ocorreu porque a variável item é NULL. A partir daqui poderia colocar um breakpoint no início do ciclo while, correr o programa de novo e seguir depois passo a passo, enquanto vai observando os valores das variáveis, até descobrir o que gerou o segmentation fault.

3. Utilização da ferramenta make (slide)

  1. Copie o ficheiro Makefile para a sua área de trabalho e execute make. O que aconteceu?
  2. Apague o ficheiro list.o. Re-execute make. Interprete o sucedido.
  3. Simule uma alteração ao ficheiro main.c com o comando seguinte e re-execute make. Compreenda o resultado.
    touch main.c
  4. Simule a alteração do ficheiro list.h e execute make. Porque razão todos os ficheiros foram gerados?
  5. Simule a alteração do ficheiro list.o. O que acontece quando faz make list.o? E se agora fizer make?
  6. Retire a dependência do ficheiro list.h da regra list.o da Makefile. Repita procedimento da alínea d). Explique a diferença no resultado?
  7. Adicione a regra seguinte no fim do ficheiro. O que descreve esta regra? Identifique: o alvo, as dependências e o comando. Tenha em atenção que os espaços inicias em cada linha são tabs.
    clean:
    rm -f *.o main
  8. Execute make clean. O que aconteceu? Porque razão o comando é executado sempre que esta regra é invocada explicitamente?

Outros exercícios

  1. Implemente a função update_terminated_process. A função update_terminated_process recebe uma lista, um valor de pid e um tempo de fim, procura pelo elemento com esse valor de pid e atualiza esse elemento com o tempo de fim.
  2. Gestor de tarefas pessoais
    Construa uma aplicação de organização pessoal que permite gerir as tarefas pendentes de uma pessoa. Cada tarefa: A aplicação tem os seguintes comandos: Sugestão: usar tantas listas quanto níveis de prioridade.