LRM Prof. Mantovani ← Aulas da disciplina

meushell

Um shell que cresce o semestre inteiro — e que, a cada entrega, enxerga mais do sistema. Começa criando um processo e termina medindo o próprio escalonador e a própria memória virtual. Não é um shell pelo shell: é a bancada pela qual vocês vão observar, com as próprias mãos, o que a teoria descreve.

👥 grupos de até 3🧪 4 entregas + apresentação🐧 C e Linux🎯 6,0
🐧
Precisa de Linux com gcc e make. Se o computador de vocês complicar, o Google Cloud Shell já vem com tudo, é gratuito, não pede cartão — e é o ambiente da correção. Aqui a linguagem não é escolha de estilo: fork, execvp e dup2 são a matéria.
🚦
A primeira verificação é vermelha — isso é o enunciado, não um defeito. O shell compila e responde à linha de comando, mas as partes que importam estão vazias. O vermelho é o ponto de partida, e vai virando verde conforme vocês preenchem src/.

O que vocês vão escrever

Um programa que lê uma linha, cria um processo, liga descritores e espera. Cinquenta linhas de C que contêm metade da ementa desta disciplina.

/* o coração de tudo: aqui existe UM processo; depois do fork existem DOIS */ pid_t pid = fork(); if (pid == 0) { /* o FILHO troca de programa e não volta mais */ execvp(v[0], v); /* se chegou aqui, o execvp FALHOU — é onde nasce o código 127 */ } else { /* o PAI espera, e guarda como o filho terminou */ waitpid(pid, &status, 0); }

Antes da primeira entrega

✅
Você já clonou o laboratório neste navegador. Não clone de novo — abra o terminal e digite cd ~/so-lab. O mesmo comando também atualiza, sem duplicar nada.

Uma vez só, e vale o semestre inteiro. Todo comando desta página serve sozinho: cada um começa clonando o laboratório se ele ainda não existir. Não há ordem obrigatória, e rodar de novo nunca duplica nem apaga nada.

▶ Abrir o Cloud Shell (gratuito, sem cartão)

[ -d ~/so-lab ] || git clone https://github.com/LuizRMSilva1973/so-lab ~/so-lab; cd ~/so-lab && make verificar E=1
📖
Dois documentos mandam no trabalho. CONTRATOS.md diz como o shell conversa com o mundo — a linha de comando, as saídas, os códigos; e entregas/ traz o enunciado de cada uma. Quando a intuição de vocês discordar deles, é o arquivo que vale.

As quatro entregas

1Criar processos02/10 · 0,8▾

Fazer o shell executar um comando: criar o processo com fork, trocar o programa com execvp, esperar com waitpid e guardar o código de saída.

O que prova: cinco roteiros com saída exata, o comando inexistente devolvendo 127, e o shell continuando vivo depois de qualquer falha.

As três armadilhas

  • execvp que volta é execvp que falhou. Quando dá certo ele não retorna nunca — o programa foi substituído. Se a linha seguinte executou, o comando não existia. É ali que nasce o 127.
  • _exit, não exit, no filho. O filho herdou os buffers do pai; exit esvazia esses buffers de novo e o que o pai ainda não imprimiu sai duplicado.
  • O filho precisa reagir ao Ctrl-C. O shell ignora o SIGINT para não morrer junto — e o filho herda esse ignorar. Só é cobrado na Entrega 3, mas o lugar de resolver é aqui.
Verificação verde num clone limpo0,4
Os cinco roteiros da entrega0,2
Árvore de processos desenhada no README0,2
make verificar E=1
2Descritores: redirecionamento e cano16/10 · 1,2▾

Fazer >, >>, < e | funcionarem. É a entrega em que o descritor de arquivo deixa de ser um número abstrato e vira um recurso do processo.

O que prova — e aqui a saída não basta: dá para produzir a saída certa de um cano gravando um arquivo temporário no meio. O verificador lê o /proc/<pid>/fd/1 do processo da esquerda e exige pipe:[...]. Testei: o arquivo temporário passa nos dez roteiros com saída byte a byte idêntica — e a entrega reprova. A tarefa não era produzir os bytes; era ligar dois processos por um cano.
🪤
A regra dos canos que todo mundo esquece: feche as duas pontas que você não usa, no filho e no pai. O leitor só vê o fim dos dados quando todas as pontas de escrita estiverem fechadas. Se o pai esquecer a dele aberta, o wc -l espera para sempre. Quando o seu shell congelar num cano, é isso.
Verificação verde (Entregas 1 e 2)0,6
O cano é um cano de verdade0,3
Tabela de descritores no README0,3
make verificar E=2
3Sinais e segundo plano30/10 · 1,4▾

O &, o jobs, e o Ctrl-C que mata o comando sem matar o shell. É aqui que o sinal aparece pelo que ele é: uma interrupção de software entregue ao processo.

O que prova: zumbi zero — o verificador conta processos em estado Z cujo pai é o seu shell, enquanto ele ainda vive. E o Ctrl-C é cobrado nas duas metades: o filho morreu (código 130, que é 128 + 2) e o shell continuou lendo. Conferir só uma delas seria um teste que não sabe dizer o lado.

O zumbi transitório — e por que o bash não tem esse problema

Enquanto o shell espera um comando em primeiro plano, o waitpid daquele pid não colhe nenhum outro filho. Um processo de segundo plano que morra nesse intervalo fica zumbi até a próxima linha. Isso é normal para quem colhe antes de cada comando, e é o que o verificador aceita. O jeito profissional é colher quando o SIGCHLD chega — o núcleo avisando na hora. Fazer assim vale bônus.

Verificação verde (Entregas 1 a 3)0,7
Zumbi zero e Ctrl-C nas duas metades0,4
Por que o cd precisa ser embutido0,3
make verificar E=3
4O shell mede o sistema13/11 · 1,6▾

Três embutidos que rodam um comando e depois contam o que o núcleo registrou sobre ele. É a entrega em que escalonamento e memória virtual param de ser slide e viram número que o programa de vocês imprime.

tempo <cmd> parede=<s> usuario=<s> sistema=<s> trocas <cmd> voluntarias=<n> involuntarias=<n> paginas <cmd> menores=<n> maiores=<n> rss_pico_kb=<n>

A chave é o wait4(): igual ao waitpid, com um quarto argumento struct rusage * que o núcleo preenche. O tempo de parede não está lá — esse é você quem mede.

O que os números dizem

O repositório traz três programas. Estes são os valores que eu medi:

programausuário / paredetrocas voluntáriastrocas involuntárias
girar — só calcula0,166 / 0,16612
esperar — só dorme0,000 / 0,3141510

A diferença entre parede e CPU é o tempo esperando. E a inversão entre as duas colunas de trocas é o escalonamento aparecendo: quem espera cede a CPU cento e cinquenta vezes; quem calcula quase nunca cede, e é o escalonador que a toma dele.

O terceiro programa, comer, toca 60 MB e registra cerca de 15.430 faltas de página menores. Dividam 60 MB por esse número e vocês descobrem o tamanho da página deste sistema — confiram com getconf PAGESIZE.

O que prova: o verificador não compara com números fixos, porque eles mudam a cada execução. Ele compara relações — o girar tem que dar perfil de CPU, o esperar perfil de espera. Uma medição que devolve o mesmo para os dois está morta, e um número que não distingue nada não mede nada.
Verificação verde nas quatro entregas0,8
Tabela com os números medidos pelo grupo0,4
Explicação da inversão das trocas0,2
Tamanho da página deduzido, com a conta0,2
make verificar E=4
5Apresentação: demonstração e defesa04/12 · 1,0▾

Oito minutos por grupo: cinco de demonstração e três de alteração ao vivo.

  • O shell rodando (30 s) — ao vivo, a partir do repositório.
  • Um processo nascendo (1,5 min) — sleep 60 & e, noutro terminal, o processo na árvore: quem é o pai, qual o estado. Depois matem o pai e mostrem o órfão sendo adotado.
  • O cano por dentro (1 min) — ls | wc -l e o /proc/<pid>/fd apontando para pipe:[...].
  • Os números da Entrega 4 (2 min) — a tabela dos três programas e a explicação da inversão. Se souberem dizer por que o esperar cede a CPU 150 vezes e o girar quase nunca, vocês entenderam escalonamento.

Na alteração ao vivo cada grupo recebe uma mudança pequena, sorteada na hora, e tem dez minutos: aceitar 2>, marcar no jobs quem já terminou, aceitar dois canos na mesma linha, um embutido que mostra o pid do último processo, ou colher pelo SIGCHLD. Podem consultar tudo — o que não dá para consultar é saber onde mexer.

A demonstração funciona e o processo é explicado, não só exibido0,4
A alteração ao vivo0,3
Os números da Entrega 4 interpretados0,2
Todos falam, e o tempo é respeitado0,1

Regras do jogo

📦A entrega é o repositório, nunca a máquina de vocês. A correção clona numa máquina limpa e roda make verificar E=n. Antes de entregar, rodem make prova: ele faz isso aqui e pega o defeito mais comum de todos — funciona aqui e não no clone.
🔬O verificador não se contenta com a saída. Ele conta zumbis, lê os descritores em /proc, manda sinal e mede relações. Saída igual com mecanismo errado não é o mesmo trabalho — e há uma prova só para isso.
🎲A correção usa um segundo corpus, que vocês não têm. Mesmas regras, roteiros diferentes. Um shell de verdade passa nos dois sem vocês fazerem nada; um programa que só reproduza as saídas do corpus público passa aqui e reprova lá. Estou dizendo abertamente para ninguém perder tempo pelo caminho errado.
🧾Evidência é obrigatória. make evidencias E=<n> grava a saída da verificação, e é ela que vai anexada no formulário.
🤖Escrever o shell é a tarefa. Usar IA para entender um conceito é bem-vindo, e eu faço isso também. Entregar um shell que vocês não sabem alterar é outra coisa — e é para separar os dois casos que existe a alteração ao vivo.
Mão na massa · colaborativo

Trabalho semestral · meushell

Identifiquem o grupo uma vez — fica salvo neste navegador e serve para as quatro entregas. Escolham qual entrega estão enviando, colem a URL do repositório e anexem a evidência da verificação.

👥 grupos de até 3🔁 4 entregas🧾 protocolo de entrega
Processosfork, exec, wait e códigos de saída
Descritoresredirecionamento e cano
Sinais e mediçãosegundo plano, jobs e /proc
📤 Entrega: link do repositório + evidencias/verificacao-N.txt.