Instituto de Computação - UNICAMP

MC514 - Gabarito da Prova 2

Islene Calciolari Garcia


Questão 1

Qual é a principal diferença entre modo usuário e modo kernel? Quando um processo ou thread deixa de executar em modo usuário para executar em modo kernel?

Resposta esperada: No modo kernel é possível o acesso irrestrito ao conjunto de instruções da máquina. Um processo deixa de executar em modo usuário e passa a executar em modo kernel quando executa uma chamada de sistema.

Observações: Não bastava dizer que o modo kernel tem acesso irrestrito aos dados do sistema operacional. Para passar do modo usuário ao modo kernel, não é suficiente que um processo precise ou queira fazer acesso priveligiado ao hardware. É necessário que ele execute uma chamada de sistema.

Questão 2

Analise o código abaixo.
#include 

int v1[10];

void f() {
  int i;
  for (i = 0; i < 100; i++)
    v1[i] = i;
}

void g() {
  int v2[10];
  int i;

  for (i = 0; i < 100; i++)
    v2[i] = i;
}

int main() {
  if (rand() % 2) f();
  else g();
  return 0;
}

Questão 2a

Descreva o erro que pode ocorrer após a execução da função f(). Em quais condições o programa não acusaria erro? Justifique.

Resposta esperada: O acesso à posição v[11] está fora da área reservada para este vetor, podendo causar uma falha de segmentação (SEGMENTATION FAULT). O programa terminaria corretamente caso as posições v[11] a v[99] estivessem dentro do segmento de dados.

Questão 2b

Descreva o erro que pode ocorrer após a execução da função g(). Caso a função g() seja executada, existe alguma possibilidade de o programa terminar corretamente? Justifique.

Resposta esperada: Após o acesso às posições mais altas do vetor, a pilha de execução, que contém o endereço de retorno da função, será corrompida. Desta forma, não há possibilidade do programa terminar corretamente.

Observações: Para responder esta questão, você deveria ter em mente o seguinte esquema para o espaço de endereçamento virtual do processo:

+-------------+
|    Pilha    |  || 
|             |  \/ 
+-------------+
|    Gap      |
|             |
+-------------+
|             |  
|    Dados    |
+-------------+
|    Texto    |
+-------------+
Note que o Gap é um espaço de endereçamento virtual não mapeado. Alguns alunos erraram ao dizer que o acesso a v1[99] poderia corromper memória de outros processos.

Questão 3

Um programador estava escrevendo um tratador para um sinal assíncrono (SIGUSR1) que deveria fazer acesso a uma estrutura de dados também utilizada por uma função f() do programa. Preocupado com possíveis erros de consistência, este programador pensou em utilizar locks, da maneira como está esquematizado abaixo. Esta técnica resolve o problema? Justifique.
/* Tratador invocado quando um sinal tipo SIGUSR1 é recebido */
void trata_SIGUSR1(int signum) {
  pthread_mutex_lock(&mutex);
  /* Acesso a dados */
  pthread_mutex_unlock(&mutex);
}
/* Função do programa */
void f() {
  pthread_mutex_lock(&mutex);
  /* Acesso a dados */
  pthread_mutex_unlock(&mutex);  
}
Resposta esperada: O tratador do sinal SIGUSR1 pode ser invocado dentro da região crítica da função f(). Neste caso, o programa entraria em deadlock.

Observações: O que ocorre é que o mesmo fluxo de execução é interrompido para a execução do tratador. Alguns alunos justificaram erros considerando vários fluxos de execução, inclusive de outros processos, o que não faz sentido, pois estes não teriam acesso ao mutex.

Questão 4

É possível criar um link simbólico para um arquivo que não existe? E um hard link? Justifique sua resposta.

Resposta esperada: Sim, é possível criar um link simbólico para um arquivo que não existe, visto que este link é apenas um caminho, válido ou não, para outro arquivo.

Um hard link é uma referência para um i-node e não é possível criar uma referência para um i-node inválido.

Observações: Todas as referências para i-nodes no sistema são hard links. Desta forma, ao criarmos um arquivo, criamos o primeiro hard link para ele.

Questão 5

Questão 5a

A figura (a) apresenta dois arquivos armazenados na forma de uma lista ligada de blocos em disco. A figura (b) apresenta estes mesmos arquivos em uma tabela de alocação em memória (tipo FAT - File Allocation Table).

Resposta esperada: Na lista ligada, parte dos blocos de dados é utilizada para armazenar os apontadores, enquanto que com o uso da FAT os blocos dos arquivos são ocupados integralmente com dados.

Com a FAT, para se fazer acesso a um bloco específico de um arquivo, basta percorrer a lista em memória, que é mais rápido do que percorrer a lista no disco.

Observações: Muitos alunos responderam que a FAT permitia acesso direto aos blocos no disco, mas, em ambos os casos é necessário percorrer a lista.

Na FAT, a identificação de blocos livres também pode ser mais simples, pois basta percorrer a tabela e procurar por blocos que estejam marcados como livres.

Questão 5b

Comente vantagens da utilização de i-nodes, como o representado na figura abaixo, sobre o uso das tabelas em memória.

Resposta esperada: Com o uso de i-nodes, não é necessário colocar informações sobre o disco como um todo na memória. Apenas quando um arquivo é aberto, é feita a leitura dos blocos que o compõem.

O acesso a um bloco específico de um arquivo é mais eficiente com o uso de i-nodes, pois não é necessário percorrer uma lista (no caso dos primeiros blocos, o acesso é direto e nos demais, pode-se ter de percorrer uma árvore de poucos níveis).

Observações: Para obter os pontos referentes a esta questão era importante fazer uma comparação entre os dois modelos; não bastava comentar características dos i-nodes.

Questão 6

Considerando os projetos feitos com o código fonte do Linux, comente como a implementação de um sistema de arquivos pode substituir a especificação de novas chamadas de sistema. Quais são as vantagens desta abordagem?

Resposta esperada: Atribuindo funções específicas para as operações de escrita e leitura em um arquivo de um dado sistema de arquivos, é possível adicionar novas funcionalidades ao kernel ou modificar outras já existentes. Isto é mais vantajoso do que especificar uma nova chamada por razões de compatibilidade entre várias versões do sistema.

Observações: Alguns alunos falaram da possibilidade de se implementar otimizações em sistemas de arquivos via implementações específicas, o que não era o foco da questão.

No trabalho 2 do Linux, foi solicitada a implementação de chamadas modificadas de clone e fork via sistema de arquivos.

Questão 7

Por que utilizar um pipe é mais vantajoso do que utilizar arquivos intermediários?

Resposta esperada: A principal vantagem é que a comunicação pode ser feita em memória, sem ser necessária a criação de um arquivo em disco. Além disso, o processo leitor do pipe (consumidor) poderá iniciar o seu processamento antes do escritor no pipe (produtor) terminar sua execução, sendo que a sincronização será feita automaticamente pelo sistema.