-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1993c24
commit 66ba569
Showing
8 changed files
with
258 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#include <stdio.h> | ||
int b=0; | ||
int main() | ||
{ | ||
int i = 3/b; | ||
printf("fim do programa.\n"); | ||
return 0; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
|
||
#include <stdio.h> | ||
|
||
int main() { | ||
int *px = (int*) 0x01010101; | ||
*px = 0; | ||
printf("fim do programa.\n"); | ||
return 0; | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
# 16 - Enviando sinais | ||
|
||
Na aula de hoje falamos sobre sinais e vimos que grande parte deles indica que algo excepcional aconteceu. Veremos neste handout as chamadas usadas para consultar o status de um processo quando ele acaba com erro e como enviar sinais para outros processos. | ||
|
||
## Recuperando informações de erros usando `wait` | ||
|
||
Anteriormente vimos que ao chamar `wait(&status);` guardamos informações sobre o fim do processo filho na variável `status`. Nos outros exercícios olhamos para os casos em que `WIFEXITED(status) == 1`. | ||
|
||
```C | ||
int wstatus; | ||
|
||
wait(&wstatus); | ||
printf("Filho acabou\n"); | ||
|
||
// Utiliza macro para ler um "pedaço" (um ou mais bits) de wstatus | ||
printf("Terminou normal?: %d\n", WIFEXITED(wstatus)); // lê 0 ou 1 | ||
|
||
// se terminou normalmente | ||
if (WIFEXITED(wstatus)) { | ||
// lê o byte menos significativo do return do filho | ||
printf("Valor de retorno: %d\n", WEXITSTATUS(wstatus)); | ||
} | ||
``` | ||
Todo término inesperado de um programa em execução (processo) é feito usando um sinal. Ao acessar informações em um local de memória não mapeado para o nosso processo ele recebe o sinal `SIGSEGV`. Ao executar uma divisão por zero ele receberá o sinal `SIGFPE`. Logo, nestes casos é verdade que `WIFSIGNALED(status) == 1`, então podemos pegar o número do sinal usando a macro `WTERMSIG(status)`. | ||
!!! exercise text short | ||
Leia o arquivo *parte1.c*. O que ele faz? Quantos processos são criados (conte o original)? | ||
!!! answer "Resposta" | ||
O programa original cria um processo filho, que faz uma divisão por zero. São dois processos, portanto. | ||
!!! example | ||
Modifique *parte1.c* para o processo pai esperar o fim do filho e mostrar uma mensagem com o `pid` do filho que acabou (pegue isto via `wait`). | ||
!!! example | ||
No proceso pai, após o `wait` mostre no terminal as seguintes expressões: | ||
* `WIFEXITED(status)` | ||
* `WIFSIGNALED(status)` | ||
* `WTERMSIG(status)` | ||
!!! example "To-Do" | ||
Mostrar o número do sinal não é muito útil. Pesquise sobre a chamada `strsignal` e use-a para mostrar uma mensagem descritiva de qual sinal foi recebido no exercício acima. | ||
!!! tip | ||
Após cada modificação no código, compile e execute para conferir os resultados! | ||
## Envio de sinais via terminal | ||
Além de erros e exceções, sinais também são usados para avisar de mudanças no sistema, sejam elas iniciadas pelo usuário ou por outros processos. A sequência de exercícios abaixo é um experimento de envio de sinais. | ||
!!! example | ||
Faça uma cópia do arquivo *parte1.c* e salve como *parte2.c*. No novo arquivo, altere para que o processo filho mostre seu pid e entre em loop infinito. | ||
Claramente nem o pai nem o filho terminam no exemplo acima. Porém, se o filho terminar o pai termina também! O sinal **SIGKILL** é usado para terminar forçadamente um processo e ele pode ser enviado por qualquer outro processo do mesmo usuário (ou o *root*, que pode mandar sinais para qualquer processo do sistema). | ||
O envio de sinais é feito usando a chamada `kill`. Assim como outras chamadas de sistema, `kill` possui também um programa de linha de comando. | ||
!!! example | ||
Abra dois terminais e coloque um ao lado do outro. No primeiro, execute o programa *parte2.c*. | ||
!!! example | ||
No segundo terminal, use a ferramenta de linha de comando `kill` para enviar o sinal **SIGKILL** para o processo filho. Se precisar, consulte a documentação usando `man 1 kill`. | ||
!!! exercise text short | ||
Use `man 7 signal` para ver a lista de sinais disponíveis e seus números. Qual seria o número para o sinal `SIGINT`? | ||
!!! answer "Resposta" | ||
Execute `man 7 signal`e procure por **Signal numbering for standard signals** | ||
Isto deve ter feito o pai finalizar e mostrar a informação de que o processo filho foi finalizado. Note que o pai tem direito a saber o sinal usado para finalizar um filho: | ||
!!! example | ||
Envie o sinal `SIGINT` para seu processo filho e verifique que o processo pai mostra o número correto. | ||
## Envio de sinais em um programa | ||
O programa `kill` é apenas um casquinha em volta de sua chamada de sistema. | ||
!!! example | ||
Veja a documentação da chamada de sistema (em C) no manual `man 2 kill` | ||
!!! example | ||
Faça uma cópia do arquivo *parte2.c* e salve como *parte3.c*. Modifique o novo arquivo para que o processo pai espere 10 segundos e envie um **SIGKILL** para o filho. | ||
!!! exercise text short | ||
Agora os dois processos acabam? As informações de finalização no pai condizem com o sinal enviado? | ||
!!! answer "Resposta" | ||
Se restarem dúvidas, confira com o professor! | ||
### Extra | ||
Até o momento usamos a chamada `wait` para esperar um processo filho acabar. Porém, não sabemos ainda checar **se** um processo filho acabou (um processo filho específico, sem necessariamente deixar a chamada `wait` travada)! Podemos fazer isso com a função `waitpid`, que recebe o `pid_t` do processo filho, e permite esperar ou não pela finalização dele. | ||
!!! example | ||
Pesquise no manual pela flag `WNOHANG` da chamada `waitpid`. | ||
!!! example | ||
Faça uma cópia do arquivo *parte3.c* e salve como *parte4.c*. Modifique o novo arquivo para que o processo pai só envie o sinal se o processo filho ainda estiver executando. Salve como *parte4.c* | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#include <unistd.h> | ||
#include <stdio.h> | ||
#include <sys/types.h> | ||
|
||
int main() { | ||
pid_t filho; | ||
|
||
filho = fork(); | ||
if (filho == 0) { | ||
int i = 1/0; | ||
printf("Divisão por zero!\n"); | ||
} | ||
|
||
return 0; | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
# Lab de Processos | ||
|
||
Nesse lab iremos trabalhar com bibliotecas, integração entre processos e multiprocessamento para a criação de um programa similar ao [`wget`](https://www.gnu.org/software/wget/). Nosso programa, chamado de `web_downloader`, fará o download de arquivos referênciados por uma URL, para tanto, utilizaremos a ferramenta `cURLInsper`. | ||
|
||
A ferramenta `cURLInsper` é um executável de linha de comando que transfere dados de um servidor usando o protocolo HTTP. Para fazermos o download de uma URL podemos executar o `cURLInsper` no terminal, por exemplo: | ||
|
||
`./cURLInsper https://insper.github.io/SistemasHardwareSoftware/index.html index.txt` | ||
|
||
No exemplo, estamos tentando fazer o download da página `https://insper.github.io/SistemasHardwareSoftware/index.html/` e armazenando o arquivo `index.html` no arquivo `index.txt`. | ||
|
||
O executável `cURLInsper` pode ter os seguintes retornos (return) em sua execução: | ||
|
||
* Quando a **quantidade de parâmetros está incorreta**, o programa **retorna -1**; | ||
|
||
* Quando um **download** é bem sucedido, o programa **retorna 0**; e | ||
|
||
* Quando a URL não existe ou ocorre uma **falha no download**, o programa **retorna 1**. | ||
|
||
Ultimament o executável `cURLInsper` está um pouco instável com um comportamento estranho (culpa talvez do último programador que deu manutenção no código), essa manutenção fez com que, as vezes, a ferramenta demore um tempo excessivo para realizar o download ou até mesmo falhe durante ele de forma inexplicável. | ||
|
||
O programador que fez o última manutenção disse que quando o download falhar, o usuário pode executar novamente a ferramenta informando o número da tentiva, incrementando esse número a cada nova tentativa, até que o download seja bem sucedido, e acreditem, essa gambiarra funciona. Para o exemplo abaixo temos um erro de download. | ||
|
||
`./cURLInsper https://insper.github.io/SistemasHardwareSoftware/index.html index.html` | ||
|
||
Mas se passar o número da tentativa igual a `1` no último parâmetro da chamada do `cURLInsper`, o download funciona: | ||
|
||
`./cURLInsper https://insper.github.io/SistemasHardwareSoftware/index.html index.html 1` | ||
|
||
## Restrições | ||
|
||
Este exercício serve como avaliação dos conceitos vistos na disciplina. Portanto, algumas restrições serão aplicadas ao código de vocês: | ||
|
||
- todo trabalho com arquivos deverá ser feito usando as APIs POSIX vistas em aula. **Não é permitido o uso de funções da** `Standard I/O` para manipulação de arquivos, como por exemplo `fopen()`, `fread()` e `fclose()`. | ||
- se você usar algum trecho de código da documentação (ou de outra fonte), coloque uma atribuição em um comentário no código. | ||
- Fica proibido o uso de ferramentas de geração de código automático por IA, como por exemplo o ChatGPT. | ||
|
||
## Entrega | ||
|
||
Você deverá colocar sua entrega na pasta `lab/02-lab-processos` em seu repositório de atividades, na branch principal. Não precisa soltar release/tag. Além disso, grave um vídeo mostrando a tela do funcionamento do seu programa apresentando cada uma das fases desenvolvidas, e por fim, **preencha o arquivo `README.md` informando até qual fase você conseguiu chegar e o link do vídeo do funcionamento da sua entrega**. Lembre-se de se atentar ao prazo de entrega definido [aqui!](../../sobre). | ||
|
||
## Avaliação | ||
|
||
O programa será avaliado de forma manual usando uma rubrica que descreve as funcionalidades implementadas. Quanto maior o número de funcionalidades maior será a nota. | ||
|
||
### **Fase 0** | ||
|
||
- O programa não compila | ||
- Não preencheu o arquivo `README.md` | ||
- O programa não implementa algum dos requisitos da rubrica da fase **1**. | ||
|
||
**NOTA desta fase**: 0.0 | ||
|
||
### **Fase 1** | ||
|
||
- O programa compila com warnings. | ||
- O programa roda na linha de comando como abaixo: | ||
|
||
`./web_downloader http://exemplo.com/pagina.html` | ||
|
||
- A página acima deve ser salva em um arquivo com o seguinte formato: `exemplo_com_pagina.html`, ou seja, ignorando `http://` e `https://`, substituindo todas barras e pontos (exceto o último) por `_`. | ||
|
||
- Para fazer o download da URL informada o seu programa `web_downloader` deve fazer uma chamada do excutável `cURLInsper` utilizando a função `exec` conforme visto em aula, você não pode, por exemplo, usar a chamada da função **system**. | ||
- Ao terminar de baixar uma página, caso tenha sucesso, você deverá mostrar a mensagem `{url} baixada com sucesso!`. Exemplo: `{https://insper.github.io/SistemasHardwareSoftware/index.html} baixada com sucesso!` | ||
- Se o download falhar o seu programa deverá mostrar a mensagem `{url} não pode ser baixada.`. Exemplo: `{https://insper.github.io/SistemasHardwareSoftware/index.html} não pode ser baixada.` | ||
|
||
**NOTA desta fase**: 2.0 | ||
|
||
### **Fase 2** | ||
|
||
- O programa compila sem warnings. | ||
- Não entregou o video explicando o funcionamento do programa. | ||
- O programa recebe uma flag `-f` seguida pelo nome de um arquivo. Seu programa deverá ler o arquivo e fazer o download de cada url dentro do arquivo. Você pode supor que cada linha do arquivo contém exatamente uma URL. As regras para o nome do arquivo correspondente são as mesmas do item anterior. | ||
- Nessa fase cada download das URLs do arquivo informado por linha de comando pode ser realizada de forma sequencial, abaixo um exemplo da chamada do seu programa `web_downloader` com o flat `-f`. | ||
|
||
`./web_downloader -f lista_download.txt` | ||
|
||
**NOTA desta fase**: 4.0 | ||
|
||
### **Fase 3** | ||
- Video explicando e mostrando a execução do programa em paralelo. | ||
- O download de cada URL é feito em um processo separado e em paralelo. | ||
- Se o download falhar, por alguma razão, o seu programa deve realizar pelo menos mais duas tentativas de chamadas do executável `cURLInsper`, informando o número da tentativa na chamada do `cURLInsper`. A cada tentativa deve ser informado se conseguiu ou não baixar a URL. | ||
|
||
**NOTA desta fase**: 6.0 | ||
|
||
### **Fase 4** | ||
|
||
- O processo principal só termina depois que todos os arquivos foram baixados. | ||
- Programa roda **sem erros no valgrind**. | ||
- O programa abre até `N` processos em paralelo. Se houver mais que `N` urls então os processos deverão sempre existir no máximo `N+1` processos (`N` para fazer download mais o original). Esse valor é passado pela linha de comando via flag `-N`, conforme abaixo: | ||
|
||
`./web_downloader -f lista_download.txt -N 2` | ||
|
||
Se nada for passado assuma `N=4`, por exemplo: | ||
|
||
`./web_downloader -f lista_download.txt -N` | ||
|
||
|
||
**NOTA desta fase**: 8.0 | ||
|
||
### **Fase 5** | ||
|
||
- As mensagens de finalização de baixar uma página são mostradas sem estarem embaralhadas, mesmo caso vários processos terminarem ao mesmo tempo. | ||
- Ao apertar Ctrl+C todas as transferências são paradas e os arquivos que não foram baixados até o fim são deletados e os processos filhos são encerrados. | ||
|
||
|
||
**NOTA desta fase**: 10.0 | ||
|
||
**IMPORTANTE:** Considere as **fases como cumulativas**, ou seja, cada versão deve **manter as funcionalidades da fase anterior** e acrescentar novas. Por exemplo, a versão da **Fase 2**, além de ler o arquivo com várias URL, também deve funcionar com download direto passando apenas a URL (sem `-f arquivo`). | ||
|
||
Caso você não implemente alguma funcionalidade de uma determinada fase a nota atribuída será a da fase anterior. | ||
|
||
|
||
### Prazo: | ||
|
||
[Clique aqui!](../../sobre). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters