Skip to content

Commit 6a78741

Browse files
committed
aula16
1 parent 19ec064 commit 6a78741

7 files changed

Lines changed: 534 additions & 340 deletions

File tree

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// gcc copy_file.c -o copy_file
2+
#include <unistd.h>
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <sys/types.h>
6+
#include <sys/stat.h>
7+
#include <fcntl.h>
8+
9+
10+
int main(int argc, char *argv[]) {
11+
int source, dest;
12+
char buf;
13+
if( argc != 3){
14+
printf("./copy_file: numero de argumentos errados.\n");
15+
printf("use: ./copy_file arquivo_origem.txt arquivo_destino.txt\n");
16+
return 1;
17+
}
18+
source = open(argv[1], O_RDONLY);
19+
dest = open(argv[2], O_WRONLY | O_CREAT, 0700);
20+
21+
int bytes_read = 1;
22+
do {
23+
bytes_read = read(source, &buf, 1);
24+
if (bytes_read > 0) write(dest, &buf, 1);
25+
} while (bytes_read > 0);
26+
27+
close(source);
28+
close(dest);
29+
30+
return 0;
31+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//gcc ex1_slide.c -o ex1
2+
//man 7 signal
3+
#include <stdio.h>
4+
int main() {
5+
int *px = (int*) 0x01010101;
6+
*px = 0;
7+
printf("fim do programa.\n");
8+
return 0;
9+
}
10+
11+

content/aulas/16-sinais-I/index.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# 16 - Enviando sinais
2+
3+
!!! pdf
4+
![](slides.pdf)
5+
6+
<br>
7+
8+
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.
9+
10+
## Recuperando informações de erros usando `wait`
11+
12+
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`.
13+
14+
```C
15+
int wstatus;
16+
17+
wait(&wstatus);
18+
printf("Filho acabou\n");
19+
20+
// Utiliza macro para ler um "pedaço" (um ou mais bits) de wstatus
21+
printf("Terminou normal?: %d\n", WIFEXITED(wstatus)); // lê 0 ou 1
22+
23+
// se terminou normalmente
24+
if (WIFEXITED(wstatus)) {
25+
// lê o byte menos significativo do return do filho
26+
printf("Valor de retorno: %d\n", WEXITSTATUS(wstatus));
27+
}
28+
```
29+
30+
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)`.
31+
32+
!!! exercise text short
33+
Leia o arquivo *parte1.c*. O que ele faz? Quantos processos são criados (conte o original)?
34+
35+
!!! answer "Resposta"
36+
O programa original cria um processo filho, que faz uma divisão por zero. São dois processos, portanto.
37+
38+
!!! example
39+
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`).
40+
41+
!!! example
42+
No proceso pai, após o `wait` mostre no terminal as seguintes expressões:
43+
44+
* `WIFEXITED(status)`
45+
* `WIFSIGNALED(status)`
46+
* `WTERMSIG(status)`
47+
48+
49+
!!! example "To-Do"
50+
Mostrar o número do sinal não é muito útil. Pesquise sobre a chamada `strsignal` (`man strsignal`) e use-a para mostrar uma mensagem descritiva de qual sinal foi recebido no exercício acima.
51+
52+
!!! tip
53+
Após cada modificação no código, compile e execute para conferir os resultados!
54+
55+
## Envio de sinais via terminal
56+
57+
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.
58+
59+
60+
!!! example
61+
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.
62+
63+
Claramente **nem o pai nem o filho terminam** no exemplo acima, para ver isso use no terminal o comando `ps -C parte2`, ele mostrará os processos em execução. 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).
64+
65+
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.
66+
67+
!!! example
68+
Abra dois terminais e coloque um ao lado do outro. No primeiro, execute o programa *parte2.c*.
69+
70+
!!! example
71+
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`.
72+
73+
!!! exercise text short
74+
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`?
75+
76+
!!! answer "Resposta"
77+
Execute `man 7 signal`e procure por **Signal numbering for standard signals**
78+
79+
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:
80+
81+
!!! example
82+
Envie o sinal `SIGINT` para seu processo filho e verifique que o processo pai mostra o número correto.
83+
84+
## Envio de sinais em um programa
85+
86+
O programa `kill` é apenas um casquinha em volta de sua chamada de sistema.
87+
88+
!!! example
89+
Veja a documentação da chamada de sistema (em C) no manual `man 2 kill`
90+
91+
!!! example
92+
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.
93+
94+
!!! exercise text short
95+
Agora os dois processos acabam? As informações de finalização no pai condizem com o sinal enviado?
96+
97+
!!! answer "Resposta"
98+
Se restarem dúvidas, confira com o professor!
99+
100+
### Extra
101+
102+
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.
103+
104+
!!! example
105+
Pesquise no manual pela flag `WNOHANG` da chamada `waitpid`.
106+
107+
!!! example
108+
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*
109+

content/aulas/16-sinais-I/parte1.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <unistd.h>
2+
#include <stdio.h>
3+
#include <sys/types.h>
4+
5+
int main() {
6+
pid_t filho;
7+
8+
filho = fork();
9+
if (filho == 0) {
10+
int i = 1/0;
11+
printf("Divisão por zero!\n");
12+
}
13+
else{
14+
15+
wait(NULL);
16+
17+
}
18+
19+
return 0;
20+
}
374 KB
Binary file not shown.

0 commit comments

Comments
 (0)