forked from monnerat/BUT2FI_2026_R3.05
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 395466253c | |||
| 6060731cf2 | |||
| 0e4adccee3 | |||
| 8eb907bd53 | |||
| c13ee818c1 | |||
| 4ac7949d37 | |||
| 45e6551299 | |||
| 639ac7a377 | |||
| adf329244a | |||
| 1dfd3bac50 | |||
| cc001183fd | |||
| 381e2457cd | |||
| 14ff1042a2 | |||
| f468577abb | |||
| d08ab67f27 | |||
| ea823c58e3 | |||
| a7de23f530 | |||
| 50b005b860 | |||
| 6e5b811702 | |||
| fd10550932 | |||
| 4548e82ec8 | |||
| b478c41adc | |||
| 2a483e0f4b | |||
| c0ba99e291 | |||
| d95de5f45e | |||
| 30398d72c9 | |||
| 35bdc4fcd4 | |||
| 3cce780526 | |||
| de9994fe3a | |||
| 93ef7aa105 | |||
| 60816fac42 |
@@ -18,7 +18,25 @@ R3.05 (Programmation système).
|
||||
|
||||
Merci de lire les [quelques recommandations](./misc/CODE.md) sur les bonnes pratiques d'écriture de code.
|
||||
|
||||
#### Semaine 1 (01/09 - 05/09)
|
||||
#### Semaine 1 (31/08 - 04/09)
|
||||
Rappels sur la gestion de la [mémoire](cours/memoire.pdf), [td1](td/td1/td1.pdf), [tp1](tp/tp1/).
|
||||
|
||||
#### Semaine 2 (07/09 - 11/09)
|
||||
[Système de fichiers et api E/S](cours/fichier.pdf), [td2](td/td2/td2.pdf), [tp2](tp/tp2).
|
||||
|
||||
#### Semaine 3 (14/09 - 18/09)
|
||||
[Processus](cours/processus.pdf), [interruption/ordonnancement](cours/interruption_ordoanncement.pdf), [td3](td/td3/td3.pdf), [tp3](tp/tp3).
|
||||
|
||||
#### Semaine 4 (21/09 - 25/09)
|
||||
[interruption/ordonnancement](cours/interruption_ordoanncement.pdf), [td4](td/td4/td4.pdf), [tp4](tp/tp4).
|
||||
|
||||
#### Semaine 5 (28/09 - 02-10)
|
||||
[Signaux](cours/signaux.pdf), [td5](td/td5/td5.pdf), [tp5](tp/tp5).
|
||||
|
||||
### Semaine 6 (05/10 - 09/10)
|
||||
[Tubes, redirections](cours/pipe.pdf), [td6](td/td6/td6.pdf), [tp6](tp/tp6).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -0,0 +1,74 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
void seq(int n)
|
||||
{
|
||||
for(int i = 2; i <= n; i++)
|
||||
write(STDOUT_FILENO, &i, sizeof i);
|
||||
exit(0);
|
||||
}
|
||||
void filtre(int prime)
|
||||
{
|
||||
while(1){
|
||||
int n;
|
||||
ssize_t nb_read = read(STDIN_FILENO, &n, sizeof n);
|
||||
if (nb_read <= 0)
|
||||
break;
|
||||
if ((n%prime) != 0)
|
||||
write(STDOUT_FILENO, &n, sizeof n);
|
||||
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
pid_t p;
|
||||
int fd[2];
|
||||
struct sigaction sa = {0};
|
||||
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigaction(SIGCHLD, &sa, NULL);
|
||||
|
||||
int N = strtol(argv[1], NULL, 0);
|
||||
assert(pipe(fd) == 0);
|
||||
|
||||
p = fork();
|
||||
|
||||
if (p == 0){
|
||||
close(fd[0]);
|
||||
dup2(fd[1],STDOUT_FILENO);
|
||||
close(fd[1]);
|
||||
seq(N);
|
||||
}
|
||||
close(fd[1]);
|
||||
dup2(fd[0],STDIN_FILENO);
|
||||
close(fd[0]);
|
||||
|
||||
while(1){
|
||||
int prime;
|
||||
int fdd[2];
|
||||
ssize_t nb_read = read(STDIN_FILENO, &prime, sizeof prime);
|
||||
if (nb_read <= 0)
|
||||
break;
|
||||
printf("%d\n",prime);
|
||||
assert(pipe(fdd) == 0);
|
||||
p = fork();
|
||||
if (p == 0){
|
||||
close(fdd[0]);
|
||||
dup2(fdd[1],STDOUT_FILENO);
|
||||
close(fdd[1]);
|
||||
filtre(prime);
|
||||
}
|
||||
close(fdd[1]);
|
||||
dup2(fdd[0], STDIN_FILENO);
|
||||
close(fdd[0]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
pid_t p1,p2;
|
||||
int fd[2];
|
||||
|
||||
assert(pipe(fd) == 0);
|
||||
|
||||
p1 = fork();
|
||||
if (p1 == 0){
|
||||
close(fd[0]);
|
||||
dup2(fd[1],STDOUT_FILENO);
|
||||
close(fd[1]);
|
||||
execlp("ls","ls",NULL);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
|
||||
p2 = fork();
|
||||
if (p2 == 0){
|
||||
int out = open("output.txt",O_CREAT|O_WRONLY|O_APPEND,0644);
|
||||
dup2(out,STDOUT_FILENO);
|
||||
close(out);
|
||||
close(fd[1]);
|
||||
dup2(fd[0],STDIN_FILENO);
|
||||
close(fd[0]);
|
||||
execlp("wc","wc",NULL);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
wait(NULL);
|
||||
wait(NULL);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
3 3 23
|
||||
3 3 23
|
||||
@@ -0,0 +1,236 @@
|
||||
2378899 execve("/usr/bin/bash", ["bash", "-c", "wc"], 0x7ffd19ff1e48 /* 37 vars */) = 0
|
||||
2378899 brk(NULL) = 0x556d8430c000
|
||||
2378899 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd22d4fc000
|
||||
2378899 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/opt/pin/intel64/runtime/glibc-hwcaps/x86-64-v4/libreadline.so.8", O_RDONLY|O_CLOEXEC) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 newfstatat(AT_FDCWD, "/opt/pin/intel64/runtime/glibc-hwcaps/x86-64-v4/", 0x7fff64be3e20, 0) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/opt/pin/intel64/runtime/glibc-hwcaps/x86-64-v3/libreadline.so.8", O_RDONLY|O_CLOEXEC) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 newfstatat(AT_FDCWD, "/opt/pin/intel64/runtime/glibc-hwcaps/x86-64-v3/", 0x7fff64be3e20, 0) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/opt/pin/intel64/runtime/glibc-hwcaps/x86-64-v2/libreadline.so.8", O_RDONLY|O_CLOEXEC) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 newfstatat(AT_FDCWD, "/opt/pin/intel64/runtime/glibc-hwcaps/x86-64-v2/", 0x7fff64be3e20, 0) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/opt/pin/intel64/runtime/libreadline.so.8", O_RDONLY|O_CLOEXEC) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 newfstatat(AT_FDCWD, "/opt/pin/intel64/runtime/", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
|
||||
2378899 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
|
||||
2378899 fstat(3, {st_mode=S_IFREG|0644, st_size=245911, ...}) = 0
|
||||
2378899 mmap(NULL, 245911, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fd22d4bf000
|
||||
2378899 close(3) = 0
|
||||
2378899 openat(AT_FDCWD, "/usr/lib/libreadline.so.8", O_RDONLY|O_CLOEXEC) = 3
|
||||
2378899 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
|
||||
2378899 fstat(3, {st_mode=S_IFREG|0755, st_size=367640, ...}) = 0
|
||||
2378899 mmap(NULL, 371816, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fd22d464000
|
||||
2378899 mmap(0x7fd22d47a000, 204800, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16000) = 0x7fd22d47a000
|
||||
2378899 mmap(0x7fd22d4ac000, 36864, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x48000) = 0x7fd22d4ac000
|
||||
2378899 mmap(0x7fd22d4b5000, 36864, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x51000) = 0x7fd22d4b5000
|
||||
2378899 mmap(0x7fd22d4be000, 3176, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fd22d4be000
|
||||
2378899 close(3) = 0
|
||||
2378899 openat(AT_FDCWD, "/opt/pin/intel64/runtime/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
|
||||
2378899 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\200y\2\0\0\0\0\0"..., 832) = 832
|
||||
2378899 pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 896, 64) = 896
|
||||
2378899 fstat(3, {st_mode=S_IFREG|0755, st_size=2186528, ...}) = 0
|
||||
2378899 pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 896, 64) = 896
|
||||
2378899 mmap(NULL, 2210672, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fd22d200000
|
||||
2378899 mmap(0x7fd22d224000, 1527808, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x24000) = 0x7fd22d224000
|
||||
2378899 mmap(0x7fd22d399000, 479232, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x199000) = 0x7fd22d399000
|
||||
2378899 mmap(0x7fd22d40e000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x20d000) = 0x7fd22d40e000
|
||||
2378899 mmap(0x7fd22d414000, 31600, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fd22d414000
|
||||
2378899 close(3) = 0
|
||||
2378899 openat(AT_FDCWD, "/opt/pin/intel64/runtime/libncursesw.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/usr/lib/libncursesw.so.6", O_RDONLY|O_CLOEXEC) = 3
|
||||
2378899 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
|
||||
2378899 fstat(3, {st_mode=S_IFREG|0755, st_size=457936, ...}) = 0
|
||||
2378899 mmap(NULL, 461920, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fd22d18f000
|
||||
2378899 mmap(0x7fd22d19c000, 294912, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xd000) = 0x7fd22d19c000
|
||||
2378899 mmap(0x7fd22d1e4000, 90112, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x55000) = 0x7fd22d1e4000
|
||||
2378899 mmap(0x7fd22d1fa000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6a000) = 0x7fd22d1fa000
|
||||
2378899 close(3) = 0
|
||||
2378899 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd22d462000
|
||||
2378899 arch_prctl(ARCH_SET_FS, 0x7fd22d462b80) = 0
|
||||
2378899 set_tid_address(0x7fd22d4631a8) = 2378899
|
||||
2378899 set_robust_list(0x7fd22d462e60, 24) = 0
|
||||
2378899 rseq({cpu_id_start=0, cpu_id=RSEQ_CPU_ID_UNINITIALIZED, rseq_cs=NULL, flags=0, node_id=0, mm_cid=0, slice_ctrl={request=0, granted=0, __reserved=0}, __reserved=0}, 33, 0, 0x53053053) = 0
|
||||
2378899 mprotect(0x7fd22d40e000, 16384, PROT_READ) = 0
|
||||
2378899 mprotect(0x7fd22d1fa000, 20480, PROT_READ) = 0
|
||||
2378899 mprotect(0x7fd22d4b5000, 12288, PROT_READ) = 0
|
||||
2378899 mprotect(0x556d658de000, 12288, PROT_READ) = 0
|
||||
2378899 mprotect(0x7fd22d540000, 8192, PROT_READ) = 0
|
||||
2378899 prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
|
||||
2378899 getrandom("\xda\xea\x89\xee\xf0\xee\xf2\x49", 8, GRND_NONBLOCK) = 8
|
||||
2378899 munmap(0x7fd22d4bf000, 245911) = 0
|
||||
2378899 openat(AT_FDCWD, "/dev/tty", O_RDWR|O_NONBLOCK) = 3
|
||||
2378899 close(3) = 0
|
||||
2378899 brk(NULL) = 0x556d8430c000
|
||||
2378899 brk(0x556d8432d000) = 0x556d8432d000
|
||||
2378899 openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
|
||||
2378899 fstat(3, {st_mode=S_IFREG|0644, st_size=3064416, ...}) = 0
|
||||
2378899 mmap(NULL, 3064416, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fd22ce00000
|
||||
2378899 close(3) = 0
|
||||
2378899 openat(AT_FDCWD, "/usr/lib/gconv/gconv-modules.cache", O_RDONLY|O_CLOEXEC) = 3
|
||||
2378899 fstat(3, {st_mode=S_IFREG|0644, st_size=27010, ...}) = 0
|
||||
2378899 mmap(NULL, 27010, PROT_READ, MAP_SHARED, 3, 0) = 0x7fd22d4f5000
|
||||
2378899 close(3) = 0
|
||||
2378899 futex(0x7fd22d4136ec, FUTEX_WAKE_PRIVATE, 2147483647) = 0
|
||||
2378899 getresuid([1000], [1000], [1000]) = 0
|
||||
2378899 getresgid([984], [984], [984]) = 0
|
||||
2378899 rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
|
||||
2378899 rt_sigaction(SIGCHLD, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7fd22d23e270}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
|
||||
2378899 rt_sigaction(SIGCHLD, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7fd22d23e270}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7fd22d23e270}, 8) = 0
|
||||
2378899 rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
|
||||
2378899 rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, 8) = 0
|
||||
2378899 rt_sigaction(SIGQUIT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
|
||||
2378899 rt_sigaction(SIGQUIT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, 8) = 0
|
||||
2378899 rt_sigaction(SIGTSTP, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
|
||||
2378899 rt_sigaction(SIGTSTP, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, 8) = 0
|
||||
2378899 rt_sigaction(SIGTTIN, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
|
||||
2378899 rt_sigaction(SIGTTIN, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, 8) = 0
|
||||
2378899 rt_sigaction(SIGTTOU, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
|
||||
2378899 rt_sigaction(SIGTTOU, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, 8) = 0
|
||||
2378899 rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
|
||||
2378899 rt_sigaction(SIGQUIT, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, 8) = 0
|
||||
2378899 uname({sysname="Linux", nodename="portabledenis", ...}) = 0
|
||||
2378899 newfstatat(AT_FDCWD, "/home/denis/GIT/2026/BUT2FI_2026_R3.05/td/td6/correction2", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
|
||||
2378899 newfstatat(AT_FDCWD, ".", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
|
||||
2378899 newfstatat(AT_FDCWD, "/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
|
||||
2378899 newfstatat(AT_FDCWD, "/home/denis", {st_mode=S_IFDIR|0711, st_size=20480, ...}, 0) = 0
|
||||
2378899 newfstatat(AT_FDCWD, "/home/denis/GIT", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
|
||||
2378899 newfstatat(AT_FDCWD, "/home/denis/GIT/2026", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
|
||||
2378899 newfstatat(AT_FDCWD, "/home/denis/GIT/2026/BUT2FI_2026_R3.05", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
|
||||
2378899 newfstatat(AT_FDCWD, "/home/denis/GIT/2026/BUT2FI_2026_R3.05/td", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
|
||||
2378899 newfstatat(AT_FDCWD, "/home/denis/GIT/2026/BUT2FI_2026_R3.05/td/td6", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
|
||||
2378899 newfstatat(AT_FDCWD, "/home/denis/GIT/2026/BUT2FI_2026_R3.05/td/td6/correction2", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
|
||||
2378899 newfstatat(AT_FDCWD, "/home/denis/GIT/2026/BUT2FI_2026_R3.05/td/td6", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
|
||||
2378899 getpid() = 2378899
|
||||
2378899 getppid() = 2378897
|
||||
2378899 newfstatat(AT_FDCWD, ".", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
|
||||
2378899 newfstatat(AT_FDCWD, "/usr/local/sbin/bash", 0x7fff64be4670, 0) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 newfstatat(AT_FDCWD, "/usr/local/bin/bash", 0x7fff64be4670, 0) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 newfstatat(AT_FDCWD, "/usr/bin/bash", {st_mode=S_IFREG|0755, st_size=1195144, ...}, 0) = 0
|
||||
2378899 newfstatat(AT_FDCWD, "/usr/bin/bash", {st_mode=S_IFREG|0755, st_size=1195144, ...}, 0) = 0
|
||||
2378899 geteuid() = 1000
|
||||
2378899 getegid() = 984
|
||||
2378899 getuid() = 1000
|
||||
2378899 getgid() = 984
|
||||
2378899 access("/usr/bin/bash", X_OK) = 0
|
||||
2378899 newfstatat(AT_FDCWD, "/usr/bin/bash", {st_mode=S_IFREG|0755, st_size=1195144, ...}, 0) = 0
|
||||
2378899 geteuid() = 1000
|
||||
2378899 getegid() = 984
|
||||
2378899 getuid() = 1000
|
||||
2378899 getgid() = 984
|
||||
2378899 access("/usr/bin/bash", R_OK) = 0
|
||||
2378899 getpid() = 2378899
|
||||
2378899 getppid() = 2378897
|
||||
2378899 getpid() = 2378899
|
||||
2378899 getppid() = 2378897
|
||||
2378899 getpgrp() = 2378897
|
||||
2378899 ioctl(2, TIOCGPGRP, [2378897]) = 0
|
||||
2378899 rt_sigaction(SIGCHLD, {sa_handler=0x556d65821240, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7fd22d23e270}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7fd22d23e270}, 8) = 0
|
||||
2378899 prlimit64(0, RLIMIT_NPROC, NULL, {rlim_cur=127118, rlim_max=127118}) = 0
|
||||
2378899 openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
|
||||
2378899 fstat(3, {st_mode=S_IFREG|0644, st_size=2998, ...}) = 0
|
||||
2378899 read(3, "# Locale name alias data base.\n#"..., 4096) = 2998
|
||||
2378899 read(3, "", 4096) = 0
|
||||
2378899 close(3) = 0
|
||||
2378899 openat(AT_FDCWD, "/usr/share/locale/fr_FR.UTF-8/LC_MESSAGES/bash.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/usr/share/locale/fr_FR.utf8/LC_MESSAGES/bash.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/usr/share/locale/fr_FR/LC_MESSAGES/bash.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/usr/share/locale/fr.UTF-8/LC_MESSAGES/bash.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/usr/share/locale/fr.utf8/LC_MESSAGES/bash.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/usr/share/locale/fr/LC_MESSAGES/bash.mo", O_RDONLY) = 3
|
||||
2378899 fstat(3, {st_mode=S_IFREG|0644, st_size=197028, ...}) = 0
|
||||
2378899 mmap(NULL, 197028, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fd22d4c4000
|
||||
2378899 close(3) = 0
|
||||
2378899 rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
|
||||
2378899 rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
|
||||
2378899 newfstatat(AT_FDCWD, ".", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
|
||||
2378899 newfstatat(AT_FDCWD, "/usr/local/sbin/wc", 0x7fff64be4480, 0) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 newfstatat(AT_FDCWD, "/usr/local/bin/wc", 0x7fff64be4480, 0) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 newfstatat(AT_FDCWD, "/usr/bin/wc", {st_mode=S_IFREG|0755, st_size=71992, ...}, 0) = 0
|
||||
2378899 newfstatat(AT_FDCWD, "/usr/bin/wc", {st_mode=S_IFREG|0755, st_size=71992, ...}, 0) = 0
|
||||
2378899 geteuid() = 1000
|
||||
2378899 getegid() = 984
|
||||
2378899 getuid() = 1000
|
||||
2378899 getgid() = 984
|
||||
2378899 access("/usr/bin/wc", X_OK) = 0
|
||||
2378899 newfstatat(AT_FDCWD, "/usr/bin/wc", {st_mode=S_IFREG|0755, st_size=71992, ...}, 0) = 0
|
||||
2378899 geteuid() = 1000
|
||||
2378899 getegid() = 984
|
||||
2378899 getuid() = 1000
|
||||
2378899 getgid() = 984
|
||||
2378899 access("/usr/bin/wc", R_OK) = 0
|
||||
2378899 rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, 8) = 0
|
||||
2378899 rt_sigaction(SIGQUIT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fd22d23e270}, 8) = 0
|
||||
2378899 rt_sigaction(SIGCHLD, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7fd22d23e270}, {sa_handler=0x556d65821240, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7fd22d23e270}, 8) = 0
|
||||
2378899 execve("/usr/bin/wc", ["wc"], 0x556d8431a480 /* 37 vars */) = 0
|
||||
2378899 brk(NULL) = 0x5562f073b000
|
||||
2378899 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7efc486cf000
|
||||
2378899 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/opt/pin/intel64/runtime/glibc-hwcaps/x86-64-v4/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 newfstatat(AT_FDCWD, "/opt/pin/intel64/runtime/glibc-hwcaps/x86-64-v4/", 0x7ffc2b110e50, 0) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/opt/pin/intel64/runtime/glibc-hwcaps/x86-64-v3/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 newfstatat(AT_FDCWD, "/opt/pin/intel64/runtime/glibc-hwcaps/x86-64-v3/", 0x7ffc2b110e50, 0) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/opt/pin/intel64/runtime/glibc-hwcaps/x86-64-v2/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 newfstatat(AT_FDCWD, "/opt/pin/intel64/runtime/glibc-hwcaps/x86-64-v2/", 0x7ffc2b110e50, 0) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/opt/pin/intel64/runtime/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 newfstatat(AT_FDCWD, "/opt/pin/intel64/runtime/", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
|
||||
2378899 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
|
||||
2378899 fstat(3, {st_mode=S_IFREG|0644, st_size=245911, ...}) = 0
|
||||
2378899 mmap(NULL, 245911, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7efc48692000
|
||||
2378899 close(3) = 0
|
||||
2378899 openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
|
||||
2378899 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\200y\2\0\0\0\0\0"..., 832) = 832
|
||||
2378899 pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 896, 64) = 896
|
||||
2378899 fstat(3, {st_mode=S_IFREG|0755, st_size=2186528, ...}) = 0
|
||||
2378899 pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 896, 64) = 896
|
||||
2378899 mmap(NULL, 2210672, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7efc48400000
|
||||
2378899 mmap(0x7efc48424000, 1527808, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x24000) = 0x7efc48424000
|
||||
2378899 mmap(0x7efc48599000, 479232, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x199000) = 0x7efc48599000
|
||||
2378899 mmap(0x7efc4860e000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x20d000) = 0x7efc4860e000
|
||||
2378899 mmap(0x7efc48614000, 31600, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7efc48614000
|
||||
2378899 close(3) = 0
|
||||
2378899 mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7efc4868f000
|
||||
2378899 arch_prctl(ARCH_SET_FS, 0x7efc4868f740) = 0
|
||||
2378899 set_tid_address(0x7efc4868fd68) = 2378899
|
||||
2378899 set_robust_list(0x7efc4868fa20, 24) = 0
|
||||
2378899 rseq({cpu_id_start=0, cpu_id=RSEQ_CPU_ID_UNINITIALIZED, rseq_cs=NULL, flags=0, node_id=0, mm_cid=0, slice_ctrl={request=0, granted=0, __reserved=0}, __reserved=0}, 33, 0, 0x53053053) = 0
|
||||
2378899 mprotect(0x7efc4860e000, 16384, PROT_READ) = 0
|
||||
2378899 mprotect(0x5562b5f0e000, 4096, PROT_READ) = 0
|
||||
2378899 mprotect(0x7efc48713000, 8192, PROT_READ) = 0
|
||||
2378899 prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
|
||||
2378899 getrandom("\xe1\x24\x5e\x49\x58\x85\x91\x93", 8, GRND_NONBLOCK) = 8
|
||||
2378899 munmap(0x7efc48692000, 245911) = 0
|
||||
2378899 brk(NULL) = 0x5562f073b000
|
||||
2378899 brk(0x5562f075c000) = 0x5562f075c000
|
||||
2378899 openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
|
||||
2378899 fstat(3, {st_mode=S_IFREG|0644, st_size=3064416, ...}) = 0
|
||||
2378899 mmap(NULL, 3064416, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7efc48000000
|
||||
2378899 close(3) = 0
|
||||
2378899 fstat(0, {st_mode=S_IFREG|0644, st_size=636, ...}) = 0
|
||||
2378899 openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
|
||||
2378899 fstat(3, {st_mode=S_IFREG|0644, st_size=2998, ...}) = 0
|
||||
2378899 read(3, "# Locale name alias data base.\n#"..., 4096) = 2998
|
||||
2378899 read(3, "", 4096) = 0
|
||||
2378899 close(3) = 0
|
||||
2378899 openat(AT_FDCWD, "/usr/share/locale/fr_FR.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/usr/share/locale/fr_FR.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/usr/share/locale/fr_FR/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/usr/share/locale/fr.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/usr/share/locale/fr.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
|
||||
2378899 openat(AT_FDCWD, "/usr/share/locale/fr/LC_MESSAGES/coreutils.mo", O_RDONLY) = 3
|
||||
2378899 fstat(3, {st_mode=S_IFREG|0644, st_size=399390, ...}) = 0
|
||||
2378899 mmap(NULL, 399390, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7efc4862d000
|
||||
2378899 close(3) = 0
|
||||
2378899 openat(AT_FDCWD, "/usr/lib/gconv/gconv-modules.cache", O_RDONLY|O_CLOEXEC) = 3
|
||||
2378899 fstat(3, {st_mode=S_IFREG|0644, st_size=27010, ...}) = 0
|
||||
2378899 mmap(NULL, 27010, PROT_READ, MAP_SHARED, 3, 0) = 0x7efc486c8000
|
||||
2378899 close(3) = 0
|
||||
2378899 futex(0x7efc486136ec, FUTEX_WAKE_PRIVATE, 2147483647) = 0
|
||||
2378899 fadvise64(0, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
|
||||
2378899 read(0, "#include <stdio.h>\n#include <uni"..., 262144) = 636
|
||||
2378899 read(0, "", 262144) = 0
|
||||
2378899 fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(0x88, 0xd), ...}) = 0
|
||||
2378899 write(1, " 41 64 636\n", 12) = 12
|
||||
2378899 close(0) = 0
|
||||
2378899 close(1) = 0
|
||||
2378899 close(2) = 0
|
||||
2378899 exit_group(0) = ?
|
||||
2378899 +++ exited with 0 +++
|
||||
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
@@ -16,7 +16,7 @@ void clean(size_t b)
|
||||
{
|
||||
for (; b > 0; b -= 1 KB)
|
||||
// calloc(1 KB, sizeof(char));
|
||||
malloc(1 KB);
|
||||
malloc(1 KB);
|
||||
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,117 @@
|
||||
# Processus
|
||||
|
||||
#### Ex1
|
||||
Compilez et exécutez [ex1-stdio.c](src/ex1-stdio.c) et [ex1-syscall.c](src/ex1-syscall.c).
|
||||
Expliquez.
|
||||
|
||||
#### Ex2
|
||||
Compilez et exécutez [fork_and_fd1.c](src/fork_and_fd1.c) et [fork_and_fd2.c](src/fork_and_fd2.c).
|
||||
Expliquez.
|
||||
|
||||
#### Ex3
|
||||
Que fait le programme [copy1byte.c](src/copy1byte.c) ?
|
||||
Décommentez la ligne du `fork`. Expliquez ce qui se passe.
|
||||
|
||||
#### Ex4
|
||||
Compilez et exécutez [copy_on_write.c](src/copy_on_write.c). En utilisant l'interface `/proc/pid/smaps`, vérifiez
|
||||
la technique du copy on write utilisé par le système.
|
||||
|
||||
#### Ex5
|
||||
Ecrire un programme qui crée un processus fils.
|
||||
|
||||
Dans le fils :
|
||||
|
||||
* imprimer le retour de `fork()`, `getpid()`, `getppid()`.
|
||||
* bloquer 4 secondes (`sleep`).
|
||||
* se terminer avec `exit(2)`.
|
||||
|
||||
Dans le père :
|
||||
|
||||
* imprimer le retour de `fork()`, `getpid()`, `getppid()`.
|
||||
* attendre la fin de son fils (`wait()`), et imprimer son code de retour.
|
||||
* afficher alors la liste de tous les processus actifs (`execl()` avec
|
||||
`ps -ef`).
|
||||
|
||||
|
||||
#### Ex6
|
||||
|
||||
Le but de l'exercice est de détecter la présence d'un zéro dans un
|
||||
tableau `unsigned char` de taille `SIZE` en découpant le travail entre
|
||||
plusieurs processus. On part du programme source suivant :
|
||||
|
||||
```c
|
||||
#define SIZE 1000
|
||||
int search(const unsigned char * t,int start,int end)
|
||||
{
|
||||
/* renvoie 1 s'il y a un 0 dans la tranche du tableau,
|
||||
* 0 sinon */
|
||||
|
||||
}
|
||||
|
||||
int main(int argc , char * argv[])
|
||||
{
|
||||
int i;
|
||||
unsigned char arr[SIZE];
|
||||
|
||||
srandom(time(NULL));
|
||||
|
||||
for (i = 0; i < SIZE; i++)
|
||||
arr[i] = (unsigned char) (random() % 255) + 1;
|
||||
|
||||
printf("Enter a number between 0 and %d: ", SIZE);
|
||||
scanf(" %d", &i);
|
||||
if (i >= 0 && i < SIZE) arr[i] = 0;
|
||||
|
||||
if (search(arr,0,SIZE-1))
|
||||
printf("Found !\n");
|
||||
else
|
||||
printf("Not found !\n");
|
||||
return EXIT_SUCCES;
|
||||
}
|
||||
```
|
||||
|
||||
Combien y-at-il de 0 au plus dans le tableau ? Complétez la fonction
|
||||
`search`, et testez.
|
||||
|
||||
1. Première version. Modifiez le programme pour que le processus crée
|
||||
un fils. Le fils et le père cherche chacun le zéro dans une moitié
|
||||
du tableau. Le fils communique le résultat à son père. Celui-ci, à
|
||||
l'aide de son propre travail, donnera la réponse.
|
||||
|
||||
2. Deuxième version. Votre programme accepte sur la ligne de commande
|
||||
un entier n entre 1 et 100. Le programme crée n fils
|
||||
qui cherche chacun dans une partie du tableau. Le père attend la fin
|
||||
de chacun de ses fils, récupère leur résultat et affiche la réponse.
|
||||
|
||||
3. Troisième version. On améliore la version précédente. Lorsque qu'un
|
||||
fils trouve le 0 dans le tableau, et que le père en est averti,
|
||||
faites en sorte que les autres fils vivants se terminent. On
|
||||
utilisera la primitive `kill()` qui perment d'envoyer le signal de
|
||||
terminaison (`SIGTERM`) à tout un groupe.
|
||||
|
||||
|
||||
#### Ex7
|
||||
Exécutez le programme [session.c](src/session.c) et interprétez avec `ps`
|
||||
les informations `pid,ppid,pgid,sess,tpgid` des processus créés.
|
||||
|
||||
#### Ex8
|
||||
Écrire un programme qui pour `n>0` donné sur la ligne de commande, engendre l'arbre généalogique :
|
||||
```
|
||||
0|
|
||||
|\ 1
|
||||
| \
|
||||
| |\ 2
|
||||
| | \
|
||||
| | |\ ...
|
||||
| | | \
|
||||
| | | |\ n
|
||||
x x x x x
|
||||
```
|
||||
|
||||
Chaque processus choisit un nombre au hasard entre 0 et 127. Le processus 0 affichera la plus grande valeur choisie par tous
|
||||
les processus.
|
||||
|
||||
Remarque : on pourra modifier la séquence de nombres aléatoires en utilisant srand dans chaque processus créé. (pourquoi ?)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include<stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include<assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#define msg1 "je suis le pere"
|
||||
#define msg2 "je suis le fils !!!"
|
||||
|
||||
int main(int argc,char * argv[]){
|
||||
|
||||
int infd,outfd;
|
||||
ssize_t nbread;
|
||||
char buf[1];
|
||||
pid_t p;
|
||||
|
||||
if (argc != 3){
|
||||
|
||||
printf("%s infile outfile\n",argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
infd = open(argv[1],O_RDONLY);
|
||||
assert(infd >= 0);
|
||||
outfd = open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0644);
|
||||
assert(outfd >= 0);
|
||||
|
||||
//p=fork(); // <- decommentez cette ligne
|
||||
|
||||
while(1){
|
||||
|
||||
nbread=read(infd,buf,sizeof(buf));
|
||||
if (nbread <=0 ) break;
|
||||
write(outfd,buf,sizeof(buf));
|
||||
|
||||
}
|
||||
|
||||
|
||||
close(infd);
|
||||
close(outfd);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#define N 8*1024*1024
|
||||
|
||||
char tab[N];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
for (int i = 0; i < N; i++)
|
||||
tab[i] = (char)i;
|
||||
|
||||
printf("Avant fork : tab = %p\n", (void *)tab);
|
||||
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
perror("fork");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
printf("Fils : tab = %p, tab[5000] = %d\n",
|
||||
(void *)(tab+5000), tab[5000]);
|
||||
printf("FILS PID = %d\n", getpid());
|
||||
getchar();
|
||||
|
||||
tab[5000] = 42;
|
||||
printf("-> modification\n");
|
||||
getchar();
|
||||
|
||||
printf("Fils après modification : tab[5000] = %d\n",
|
||||
tab[5000]);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
else {
|
||||
sleep(1);
|
||||
|
||||
printf("Père : tab = %p, tab[5000] = %d\n",
|
||||
(void *)tab, tab[5000]);
|
||||
|
||||
wait(NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
int main(){
|
||||
|
||||
printf("NON");
|
||||
if (fork()) {
|
||||
printf("OUI\n");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
int main(){
|
||||
|
||||
//printf("NON");
|
||||
write(STDOUT_FILENO,"NON",3);
|
||||
if (fork()) {
|
||||
//printf("OUI\n");
|
||||
write(STDOUT_FILENO,"OUI\n",4);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <sys/wait.h>
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
pid_t p;
|
||||
int status;
|
||||
p = fork();
|
||||
assert( p >= 0);
|
||||
|
||||
if ( p == 0){
|
||||
printf("@retour de fork = %d pid = %d ppid = %d\n",p,getpid(),getppid());
|
||||
sleep(4);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
printf("@retour de fork = %d pid = %d ppid = %d\n",p,getpid(),getppid());
|
||||
|
||||
assert( wait(&status) >= 0);
|
||||
|
||||
if (WIFEXITED(status))
|
||||
printf("code retour fils = %d\n",WEXITSTATUS(status));
|
||||
|
||||
execlp("ls","totototo","-l","/",NULL);
|
||||
|
||||
/* code ici */
|
||||
assert(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include<stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include<assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#define msg1 "je suis le pere"
|
||||
#define msg2 "je suis le fils !!!"
|
||||
|
||||
int main(int argc,char * argv[]){
|
||||
|
||||
int outfd;
|
||||
pid_t p;
|
||||
|
||||
if (argc != 2){
|
||||
|
||||
printf("%s file\n",argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//p=fork();
|
||||
outfd = open(argv[1],O_WRONLY|O_CREAT,0644);
|
||||
assert(outfd >= 0);
|
||||
p=fork();
|
||||
switch(p){
|
||||
case (pid_t)-1 :
|
||||
perror(NULL);
|
||||
exit(2);
|
||||
|
||||
case (pid_t)0 :
|
||||
write(outfd,msg2,strlen(msg2));
|
||||
break;
|
||||
default :
|
||||
write (outfd,msg1,strlen(msg1));
|
||||
break;
|
||||
}
|
||||
getchar();
|
||||
close(outfd);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include<stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include<assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#define msg1 "je suis le pere"
|
||||
#define msg2 "je suis le fils !!!"
|
||||
|
||||
int main(int argc,char * argv[]){
|
||||
|
||||
int outfd;
|
||||
pid_t p;
|
||||
|
||||
if (argc != 2){
|
||||
|
||||
printf("%s file\n",argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
p=fork();
|
||||
outfd = open(argv[1],O_WRONLY|O_CREAT,0644);
|
||||
assert(outfd >= 0);
|
||||
//p=fork();
|
||||
switch(p){
|
||||
case (pid_t)-1 :
|
||||
perror(NULL);
|
||||
exit(2);
|
||||
|
||||
case (pid_t)0 :
|
||||
write(outfd,msg2,strlen(msg2));
|
||||
break;
|
||||
default :
|
||||
write (outfd,msg1,strlen(msg1));
|
||||
break;
|
||||
}
|
||||
getchar();
|
||||
close(outfd);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (fork()){
|
||||
printf("session = %d\n",getsid(getpid()));
|
||||
while(1);
|
||||
} else {
|
||||
setsid();
|
||||
printf("session = %d\n",getsid(getpid()));
|
||||
while(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# Interruptions - Ordonnancement
|
||||
|
||||
- partie 1 : [interruptions](interruptions.md)
|
||||
- partie 2 : [Ordonnamcement](ordonnancement.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned long long i = 0;
|
||||
|
||||
while (1)
|
||||
i++;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void (fonction) (void)
|
||||
{
|
||||
asm volatile (".byte 255, 255, 255, 255");
|
||||
// asm volatile ("ud2");
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
fprintf(stderr, "J'execute la fonction avec le code invalide...\n");
|
||||
fonction();
|
||||
fprintf(stderr, "Et me voici de retour\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
# Interruptions - Ordonnancement
|
||||
|
||||
- partie 1 : [interruptions](interruptions.md)
|
||||
- partie 2 : [Ordonnamcement](ordonnancement.md)
|
||||
|
||||
#### Ex1 :
|
||||
Linux fournit les compteurs d'interruptions dans :
|
||||
|
||||
```bash
|
||||
cat /proc/interrupts
|
||||
```
|
||||
|
||||
Exécutez :
|
||||
|
||||
```bash
|
||||
cat /proc/interrupts
|
||||
```
|
||||
|
||||
Vous devriez obtenir un tableau comportant notamment une colonne par CPU.
|
||||
|
||||
Pour connaître le nombre de processeurs logiques :
|
||||
|
||||
```bash
|
||||
nproc
|
||||
```
|
||||
|
||||
Vous pouvez également utiliser :
|
||||
|
||||
```bash
|
||||
lscpu
|
||||
```
|
||||
|
||||
1. Combien de processeurs logiques possède votre machine ?
|
||||
2. Combien de colonnes correspondant aux CPU observez-vous dans `/proc/interrupts` ?
|
||||
3. À quoi correspond chaque ligne du tableau ?
|
||||
4. Pourquoi les compteurs sont-ils différents selon les CPU ?
|
||||
|
||||
#### Ex2
|
||||
Une interruption matérielle peut être générée lorsqu'un périphérique demande l'attention du processeur.
|
||||
Sur un PC traditionnel, le clavier est associé à l'IRQ 1.
|
||||
Recherchez les informations relatives au clavier :
|
||||
|
||||
```bash
|
||||
grep -i keyboard /proc/interrupts
|
||||
```
|
||||
|
||||
Vous pouvez également rechercher le contrôleur `i8042` :
|
||||
|
||||
```bash
|
||||
grep i8042 /proc/interrupts
|
||||
```
|
||||
|
||||
Sur de nombreuses machines, vous observerez une ligne semblable à :
|
||||
|
||||
```text
|
||||
1: ... IR-IO-APIC 1-edge i8042
|
||||
```
|
||||
|
||||
Le numéro `1` est le numéro d'IRQ.
|
||||
|
||||
Le suffixe :
|
||||
|
||||
```text
|
||||
1-edge
|
||||
```
|
||||
|
||||
indique que cette interruption est configurée en mode déclenché sur front (*edge-triggered*).
|
||||
|
||||
|
||||
Dans un terminal, lancez :
|
||||
|
||||
```bash
|
||||
watch -n 1 'grep "^ *1:" /proc/interrupts'
|
||||
```
|
||||
|
||||
Puis appuyez plusieurs fois sur des touches.
|
||||
|
||||
1. Le compteur de l'IRQ 1 augmente-t-il lorsque vous utilisez le clavier ?
|
||||
2. Sur quel CPU le compteur augmente-t-il ?
|
||||
3. Pourquoi le clavier n'a-t-il pas besoin d'être interrogé en permanence par le processeur ?
|
||||
4. Quelle différence faites-vous entre :
|
||||
- une interruption ;
|
||||
- une interrogation périodique (*polling*) ?
|
||||
|
||||
#### Ex3
|
||||
|
||||
Linux permet de contrôler les processeurs auxquels une IRQ peut être distribuée.
|
||||
|
||||
Pour l'IRQ 1 :
|
||||
|
||||
```bash
|
||||
cat /proc/irq/1/smp_affinity
|
||||
```
|
||||
|
||||
Vous pouvez également utiliser :
|
||||
|
||||
```bash
|
||||
cat /proc/irq/1/effective_affinity
|
||||
```
|
||||
|
||||
et :
|
||||
|
||||
```bash
|
||||
cat /proc/irq/1/effective_affinity_list
|
||||
```
|
||||
|
||||
1. Quel est le masque d'affinité pour l'IRQ 1 sur votre machine ?
|
||||
2. Quel(s) CPU(s) est(sont) séléctionné(s) pour la gérer ?
|
||||
3. Y-a-t-il un interêt à la gérer toujours sur le même cpu ?
|
||||
|
||||
#### Ex4
|
||||
Sur une machine multicœur, un processeur peut avoir besoin de demander une action à un autre processeur.
|
||||
|
||||
Linux utilise alors des **IPI** (*Inter-Processor Interrupts*).
|
||||
|
||||
Examinez :
|
||||
|
||||
```bash
|
||||
cat /proc/interrupts
|
||||
```
|
||||
|
||||
Recherchez notamment les lignes :
|
||||
|
||||
```text
|
||||
LOC
|
||||
RES
|
||||
CAL
|
||||
TLB
|
||||
```
|
||||
|
||||
Les significations importantes sont :
|
||||
|
||||
- `LOC` : interruptions du timer local ;
|
||||
- `RES` : demandes de réordonnancement ;
|
||||
- `CAL` : appels de fonctions entre CPU ;
|
||||
- `TLB` : invalidations de TLB entre CPU.
|
||||
|
||||
|
||||
##### `LOC` : timer local
|
||||
|
||||
`LOC` correspond aux interruptions du timer local de chaque CPU.
|
||||
|
||||
Elles permettent notamment au noyau d'effectuer certaines opérations liées :
|
||||
|
||||
- à la gestion du temps ;
|
||||
- à la comptabilisation du temps CPU ;
|
||||
- à l'ordonnancement.
|
||||
|
||||
|
||||
1. Pourquoi chaque CPU possède-t-il son propre compteur `LOC` ?
|
||||
|
||||
|
||||
##### `RES` : rescheduling
|
||||
|
||||
Une ligne `RES` correspond à des demandes de réordonnancement transmises entre CPU.
|
||||
|
||||
Par exemple, un CPU peut devoir signaler à un autre CPU qu'il doit réévaluer le processus actuellement exécuté.
|
||||
|
||||
|
||||
1. Pourquoi un CPU peut-il avoir besoin de demander à un autre CPU de réévaluer son ordonnancement ?
|
||||
|
||||
|
||||
##### `TLB` — TLB shootdown
|
||||
|
||||
Le TLB (*Translation Lookaside Buffer*) contient des traductions récentes :
|
||||
|
||||
```text
|
||||
adresse virtuelle → adresse physique
|
||||
```
|
||||
|
||||
Supposons qu'un CPU modifie les tables de pages d'un processus.
|
||||
|
||||
Un autre CPU peut encore posséder dans son TLB une ancienne traduction.
|
||||
|
||||
Linux doit alors demander à ce CPU d'invalider l'entrée correspondante.
|
||||
|
||||
Il peut utiliser une IPI.
|
||||
|
||||
Le mécanisme est souvent appelé :
|
||||
|
||||
> **TLB shootdown**
|
||||
|
||||
|
||||
1. Pourquoi une modification des tables de pages peut-elle nécessiter une action sur un autre CPU ?
|
||||
2. Pourquoi le TLB doit-il être invalidé ?
|
||||
3. Une IPI TLB provient-elle d'un périphérique matériel externe ?
|
||||
|
||||
#### Ex4
|
||||
|
||||
Pour déclencher l’exception `Illegal instruction` , il faut exécuter du code
|
||||
invalide pour le processeur employé. C’est difficile avec les architectures
|
||||
actuelles car les pages de code sont verrouillées en lecture seule (donc
|
||||
impossible de modifier des fonctions existantes) et les pages de données ne sont
|
||||
pas exécutables (donc impossible d’y dérouter l’exécution).
|
||||
|
||||
La solution consiste à générer un code assembleur invalide et à l’insérer
|
||||
manuellement dans un programme C, comme c’est fait dans le fichier
|
||||
illegal.c (les instructions sont invalides pour un processeur x86, il
|
||||
faudra peut-être changer les valeurs si on le teste sur une autre architecture).
|
||||
|
||||
1. Observez l'effet avec
|
||||
```bash
|
||||
strace ./illegal
|
||||
```
|
||||
Comment l'exception s'est traduite au niveau du processus fautif ?
|
||||
|
||||
@@ -0,0 +1,399 @@
|
||||
# Interruptions - Ordonnancement
|
||||
|
||||
- partie 1 : [interruptions](interruptions.md)
|
||||
- partie 2 : [Ordonnamcement](ordonnancement.md)
|
||||
|
||||
|
||||
#### Ex1 1
|
||||
|
||||
Ouvrez un terminal et exécutez :
|
||||
|
||||
```bash
|
||||
ps
|
||||
```
|
||||
|
||||
Puis :
|
||||
|
||||
```bash
|
||||
ps -f
|
||||
```
|
||||
|
||||
et :
|
||||
|
||||
```bash
|
||||
ps -eo pid,ppid,stat,ni,pri,psr,comm
|
||||
```
|
||||
|
||||
Cette dernière commande affiche notamment :
|
||||
|
||||
- `PID` : identifiant du processus ;
|
||||
- `PPID` : identifiant du processus père ;
|
||||
- `STAT` : état du processus ;
|
||||
- `NI` : valeur de nice ;
|
||||
- `PRI` : priorité affichée par Linux ;
|
||||
- `PSR` : numéro du processeur sur lequel le processus s'est exécuté ;
|
||||
- `COMMAND` : nom du programme.
|
||||
|
||||
### Questions
|
||||
|
||||
1. Quelle est la valeur de `nice` d'un processus nouvellement créé ?
|
||||
2. Quelles valeurs peut prendre `nice` ?
|
||||
3. Que signifie une valeur de `nice` élevée ?
|
||||
4. Que signifie l'état `R` ?
|
||||
5. Que signifie l'état `S` ?
|
||||
6. Pourquoi le champ `PSR` peut-il changer au cours du temps ?
|
||||
|
||||
|
||||
#### Ex2.
|
||||
|
||||
Nous allons créer un programme très simple qui consomme du temps processeur.
|
||||
|
||||
Créez le fichier `cpu.c` :
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned long long i = 0;
|
||||
|
||||
while (1)
|
||||
i++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Compilez-le :
|
||||
|
||||
```bash
|
||||
gcc -O2 -o cpu cpu.c
|
||||
```
|
||||
|
||||
Lancez-le :
|
||||
|
||||
```bash
|
||||
./cpu
|
||||
```
|
||||
|
||||
Dans un autre terminal :
|
||||
|
||||
```bash
|
||||
top
|
||||
```
|
||||
|
||||
### Questions
|
||||
7. Quel pourcentage de CPU utilise le processus `cpu` ?
|
||||
8. Observez le champ `NI`.
|
||||
9. Observez le champ `PR`.
|
||||
10. Sur quel processeur le processus s'exécute-t-il ?
|
||||
|
||||
Utilisez :
|
||||
|
||||
```bash
|
||||
watch -n 0.1 ps -C cpu -o pid,ni,pri,psr,comm
|
||||
```
|
||||
|
||||
11. Appuyez sur `1` dans `top`. Que constatez-vous concernant les différents processeurs ?
|
||||
|
||||
Pour arrêter le programme :
|
||||
|
||||
```bash
|
||||
killall cpu
|
||||
```
|
||||
|
||||
#### Ex3
|
||||
|
||||
Lancez maintenant **deux** instances :
|
||||
|
||||
```bash
|
||||
./cpu &
|
||||
./cpu &
|
||||
```
|
||||
|
||||
Puis :
|
||||
|
||||
```bash
|
||||
watch -n 0.1 ps -C cpu -o pid,ni,pri,psr,pcpu,comm
|
||||
```
|
||||
|
||||
et observez avec :
|
||||
|
||||
```bash
|
||||
top
|
||||
```
|
||||
|
||||
### Questions
|
||||
|
||||
12. Si votre machine possède plusieurs processeurs logiques, les deux processus utilisent-ils nécessairement le même processeur ?
|
||||
13. Lancez quatre processus :
|
||||
|
||||
```bash
|
||||
./cpu &
|
||||
./cpu &
|
||||
./cpu &
|
||||
./cpu &
|
||||
```
|
||||
|
||||
Observez leur utilisation CPU.
|
||||
|
||||
14. Que se passe-t-il si vous lancez davantage de processus que votre machine ne possède de processeurs logiques ?
|
||||
15. Pourquoi un processus CPU-bound finit-il malgré tout par laisser le processeur à un autre processus ?
|
||||
|
||||
|
||||
#### Ex4
|
||||
|
||||
La commande `nice` permet de lancer un processus avec une valeur de `nice` particulière.
|
||||
|
||||
Lancez :
|
||||
|
||||
```bash
|
||||
nice -n 10 ./cpu &
|
||||
```
|
||||
|
||||
Puis :
|
||||
|
||||
```bash
|
||||
watch -n 0.1 ps -C cpu -o pid,ni,pri,pcpu,comm
|
||||
```
|
||||
|
||||
Comparez avec un processus lancé normalement :
|
||||
|
||||
```bash
|
||||
./cpu &
|
||||
```
|
||||
|
||||
### Questions
|
||||
|
||||
16. Quelle est la valeur de `nice` des deux processus ?
|
||||
17. Leur valeur de `PRI` est-elle identique ?
|
||||
18. Que signifie concrètement `nice = 10` ?
|
||||
19. Est-ce que `nice` signifie que le processus est exécuté « moins souvent » au sens strict ?
|
||||
|
||||
|
||||
#### Ex5
|
||||
|
||||
Lancez deux processus :
|
||||
|
||||
```bash
|
||||
./cpu &
|
||||
./cpu &
|
||||
```
|
||||
|
||||
Repérez leurs PID :
|
||||
|
||||
```bash
|
||||
pgrep cpu
|
||||
```
|
||||
|
||||
Choisissez l'un des deux PID et modifiez sa valeur de nice :
|
||||
|
||||
```bash
|
||||
renice 10 -p PID
|
||||
```
|
||||
|
||||
par exemple :
|
||||
|
||||
```bash
|
||||
renice 10 -p 12345
|
||||
```
|
||||
|
||||
Observez :
|
||||
|
||||
```bash
|
||||
ps -p 12345 -o pid,ni,pri,pcpu,comm
|
||||
```
|
||||
|
||||
### Expérience
|
||||
|
||||
Essayez de faire tourner simultanément deux processus `cpu` :
|
||||
|
||||
- l'un avec `nice = 0` ;
|
||||
- l'autre avec `nice = 10`.
|
||||
|
||||
Observez leur consommation CPU pendant plusieurs secondes.
|
||||
|
||||
### Questions
|
||||
|
||||
20. Le processus avec `nice = 10` reçoit-il toujours du CPU ?
|
||||
21. Que constatez-vous lorsque les deux processus se disputent le même processeur ?
|
||||
22. Si les deux processus peuvent s'exécuter simultanément sur deux processeurs différents, l'effet de `nice` est-il aussi visible ?
|
||||
23. Expliquez pourquoi.
|
||||
|
||||
> **Attention :** `nice` modifie la priorité relative d'un processus, mais ne lui réserve pas une quantité fixe du processeur.
|
||||
|
||||
|
||||
#### Ex6
|
||||
|
||||
Linux permet de restreindre les processeurs sur lesquels un processus peut s'exécuter.
|
||||
|
||||
Utilisez :
|
||||
|
||||
```bash
|
||||
nproc
|
||||
```
|
||||
|
||||
pour connaître le nombre de processeurs logiques disponibles.
|
||||
|
||||
Lancez :
|
||||
|
||||
```bash
|
||||
taskset -c 0 ./cpu &
|
||||
```
|
||||
|
||||
Puis :
|
||||
|
||||
```bash
|
||||
ps -C cpu -o pid,psr,pcpu,comm
|
||||
```
|
||||
|
||||
Vous pouvez également consulter directement l'affinité :
|
||||
|
||||
```bash
|
||||
taskset -p PID
|
||||
```
|
||||
|
||||
### Questions
|
||||
|
||||
24. Sur quel processeur le processus est-il autorisé à s'exécuter ?
|
||||
25. Pourquoi le champ `PSR` reste-t-il normalement égal à `0` ?
|
||||
26. Quelle différence faites-vous entre :
|
||||
|
||||
```text
|
||||
nice
|
||||
```
|
||||
|
||||
et :
|
||||
|
||||
```text
|
||||
taskset
|
||||
```
|
||||
|
||||
|
||||
#### Ex7
|
||||
|
||||
Nous allons maintenant forcer deux processus à utiliser **le même processeur**.
|
||||
|
||||
Lancez :
|
||||
|
||||
```bash
|
||||
taskset -c 0 ./cpu &
|
||||
taskset -c 0 ./cpu &
|
||||
```
|
||||
|
||||
Observez :
|
||||
|
||||
```bash
|
||||
top
|
||||
```
|
||||
|
||||
Puis :
|
||||
|
||||
```bash
|
||||
ps -C cpu -o pid,ni,pri,psr,pcpu,comm
|
||||
```
|
||||
|
||||
### Questions
|
||||
|
||||
27. Les deux processus peuvent-ils s'exécuter simultanément sur le CPU 0 ?
|
||||
28. Quelle proportion approximative du temps processeur reçoit chaque processus ?
|
||||
|
||||
Modifiez maintenant la priorité du premier processus :
|
||||
|
||||
```bash
|
||||
renice 10 -p PID1
|
||||
```
|
||||
|
||||
et laissez le second avec :
|
||||
|
||||
```text
|
||||
nice = 0
|
||||
```
|
||||
|
||||
29. Observez à nouveau `top`.
|
||||
30. Expliquez qualitativement l'effet de `nice` lorsque deux processus CPU-bound sont contraints de partager le même processeur.
|
||||
|
||||
#### Ex8
|
||||
|
||||
Linux fournit de nombreuses informations sur chaque processus dans :
|
||||
|
||||
```text
|
||||
/proc/PID/
|
||||
```
|
||||
|
||||
Pour un processus `cpu`, examinez :
|
||||
|
||||
```bash
|
||||
cat /proc/PID/status
|
||||
```
|
||||
|
||||
puis :
|
||||
|
||||
```bash
|
||||
cat /proc/PID/sched
|
||||
```
|
||||
|
||||
Dans `sched`, recherchez notamment :
|
||||
|
||||
```text
|
||||
se.sum_exec_runtime
|
||||
nr_switches
|
||||
nr_voluntary_switches
|
||||
nr_involuntary_switches
|
||||
```
|
||||
|
||||
### Questions
|
||||
|
||||
31. Que représente `se.sum_exec_runtime` ?
|
||||
32. Quelle différence faites-vous entre :
|
||||
|
||||
- changement de contexte volontaire ;
|
||||
- changement de contexte involontaire ?
|
||||
|
||||
33. Pourquoi un processus `cpu` devrait-il avoir relativement peu de changements de contexte volontaires ?
|
||||
|
||||
|
||||
#### Ex9
|
||||
|
||||
Nous allons mettre en place l'expérience suivante :
|
||||
|
||||
- deux processus `cpu` ;
|
||||
- tous deux limités au CPU 0 ;
|
||||
- processus A : `nice = 0` ;
|
||||
- processus B : `nice = 15`.
|
||||
|
||||
Lancez-les :
|
||||
|
||||
```bash
|
||||
taskset -c 0 ./cpu &
|
||||
```
|
||||
|
||||
et :
|
||||
|
||||
```bash
|
||||
taskset -c 0 nice -n 15 ./cpu &
|
||||
```
|
||||
|
||||
Notez leurs PID.
|
||||
|
||||
Après environ 30 secondes, récupérez :
|
||||
|
||||
```bash
|
||||
cat /proc/PID_A/sched
|
||||
cat /proc/PID_B/sched
|
||||
```
|
||||
|
||||
Relevez notamment :
|
||||
|
||||
```text
|
||||
se.sum_exec_runtime
|
||||
nr_switches
|
||||
```
|
||||
|
||||
### Questions
|
||||
|
||||
34. Le temps CPU obtenu par A et B est-il identique ?
|
||||
35. Comparez les valeurs de `se.sum_exec_runtime`.
|
||||
36. Quelle conclusion pouvez-vous tirer sur l'influence de `nice` ?
|
||||
37. Pourquoi cette expérience est-elle plus significative lorsque les deux processus sont attachés au **même CPU** ?
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# Signaux
|
||||
|
||||
- partie 1 : [Parallèlisme avec processus](parallelisme.md)
|
||||
- partie 2 : [Signaux](signaux.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
# Signaux
|
||||
|
||||
- partie 1 : [Parallèlisme avec processus](parallelisme.md)
|
||||
- partie 2 : [Signaux](ordonnancement.md)
|
||||
|
||||
|
||||
#### Ex1
|
||||
On veut écrire un programme calculant la somme des entiers
|
||||
de `1` à `N` à l’aide de `K` processus enfants. Chaque fils calculera la somme
|
||||
d’un sous-ensemble de ces entiers et la somme globale sera obtenue en
|
||||
calculant la somme des résultats intermédiaires de chaque fils. Pour que le pére puisse collecter
|
||||
les résultats de ses fils, il créera avec mmap un espace partagé avec ses fils :
|
||||
|
||||
```c
|
||||
uint64_t *resultats = (uint64_t*)mmap(NULL, K * sizeof(uint64_t), PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
```
|
||||
> pourquoi est-ce nécessaire ?
|
||||
|
||||
Les entiers sont répartis uniformément entre les fils comme suit (exemple avec K=3) :
|
||||
|
||||
- Fils 1 : 1, 4, 7, ...
|
||||
- Fils 2 : 2, 5, 8, ...
|
||||
- Fils 3 : 3, 6, 9, ...
|
||||
|
||||
Bien que les résultats soient connus d'avance (cf votre cours de mathématiques sur les suites arithmétiques), le but
|
||||
est de faire effectivement les calculs pour comparer les gains (?) de la parallèlisation.
|
||||
|
||||
1. Écrique une fonction
|
||||
```C
|
||||
void slice(uint64_t *res, uint64_t start, uint64_t end,uint64_t step);
|
||||
```
|
||||
qui calcule la somme d'une tranche d'entiers, et place le résultat dans `*res`.
|
||||
|
||||
2. Complétez le main pour :
|
||||
1. Créer les `K` fils
|
||||
2. Chaque fils exécute la fonction précedente, avec les bons paramètres.
|
||||
3. Le pére attend la fin des fils, collecte leurs résultats intermédiaires, et en
|
||||
fait la somme.
|
||||
|
||||
3. Pour une limite `N` assez grande, faites varier le nombre de processus, et construire un graphe
|
||||
qui affiche le temps de calcul en fonction du nombre de processus.
|
||||
Qu'observez-vous ?
|
||||
4. Lancez le processus sur un seul coeur avec `taskset`. Commentaire ?
|
||||
|
||||
4. De manière volontaire, faites en sorte que la fonction slice n'utilise pas une variable locale pour
|
||||
faire la somme, mais la référence `res`. Recommencez la question 3. Qu'observez-vous ? Pourquoi ?
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
# Signaux
|
||||
|
||||
- partie 1 : [Parallèlisme avec processus](parallelisme.md)
|
||||
- partie 2 : [Signaux](ordonnancement.md)
|
||||
|
||||
#### Ex0
|
||||
Faites le dernier exercice du td5.
|
||||
|
||||
#### Ex1
|
||||
Le programme [prime.c](src/) permet de générer le n-ième nombre premier.
|
||||
Le but est d'afficher une barre de progression pendant le calcul.
|
||||
|
||||
Complétez le programme en utilisant le signal `SIGALARM` et la fonction `setitimer` pour afficher la
|
||||
barre de progression.
|
||||
|
||||
#### Ex2
|
||||
Pour calculer le nombre $\pi$, on utilise la méthode de Monte-Carlo.
|
||||
On tire aléatoirement des couples $(x,y)$ de nombres de
|
||||
$[0,1]\times[0,1]$. La probabilité qu'il tombe dans le disque de
|
||||
rayon 1 est exactement de $\frac{\pi}{4}$. On procède à plusieurs
|
||||
tirages pour estimer la probabilité correspondante.
|
||||
|
||||
```c
|
||||
uint64_t shots_in=0,shots=0;
|
||||
double x,y;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
shots_in = 0;
|
||||
shots = 0;
|
||||
for (;;){
|
||||
x = rand()/(RAND_MAX*1.0);
|
||||
y = rand()/(RAND_MAX*1.0);
|
||||
shots ++;
|
||||
if ((x*x+y*y)<=1){
|
||||
shots_in ++;
|
||||
}
|
||||
}
|
||||
/* la probabilité vaut tirsIn/tirs,
|
||||
Elle converge lentement vers pi/4*/
|
||||
}
|
||||
```
|
||||
|
||||
En utilisant les signaux, mettre en place :
|
||||
|
||||
- avec `SIGALRM`, toutes les 5 secondes, l'affichage de la valeur
|
||||
de pi en cours et le nombre de tirs effectués.
|
||||
- avec `SIGINT` l'arrêt du programme (après la demande d'une
|
||||
confirmation), avec l'affichage du temps écoulé depuis son
|
||||
lancement, quand on fait `ctrl+C` au terminal.
|
||||
- avec `SIGQUIT` la réinitialisation du calcul avec `ctrl+\`
|
||||
depuis le terminal. (faites en sorte que toutes les valeurs restent cohérentes)
|
||||
|
||||
Dans chaque handler, les 2 autres signaux seront bloqués.
|
||||
|
||||
|
||||
#### Ex3
|
||||
|
||||
Le but est de protéger un morceau de code (**section critique**) d'un éventuellement
|
||||
déroutement à cause de la prise en compte d'un signal.
|
||||
|
||||
```c
|
||||
int x=2,y=3;
|
||||
int swap(int *x,int *y){
|
||||
int tmp=*x;
|
||||
*x=*y;
|
||||
*y=tmp;
|
||||
}
|
||||
|
||||
void sig_handler(int signo){
|
||||
switch(signo){
|
||||
case SIGQUIT :
|
||||
printf("x=%d y=%d\n",x,y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc,char * argv[]){
|
||||
|
||||
assert(set_signal_handler(SIGQUIT,sig_handler)==0);
|
||||
while(1){
|
||||
swap(&x,&y);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
1. Lancez le programme, et envoyez (depuis le terminal) le signal SIGQUIT souvent. La fonction
|
||||
`swap` est-elle interrompue ? comment le voyez-vous ?
|
||||
2. Ajoutez le code nécessaire pour assurer que `swap` ne soit jamais interrompue par `SIGQUIT`.
|
||||
|
||||
## Pour ceux/celles qui ont **tout** fait
|
||||
#### Ex4
|
||||
On va simuler un match de **ping-pong** entre un père et son fils, en utilisant le signal `SIGUSR1`.
|
||||
- Le père commence à jouer.
|
||||
- On simule 10 échanges. À chaque coup, le père affiche Ping, le fils Pong. L'envoie de la balle
|
||||
consiste à envoyer le signal `SIGUSR1` à son adversaire.
|
||||
|
||||
La difficulté consiste à synchroniser correctement les échanges.
|
||||
|
||||
Voici un premier code naïf :
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define N 10
|
||||
void sig_hand(int sig) {}
|
||||
|
||||
sigset_t saveMask, blockMask;
|
||||
|
||||
void player_wait(){
|
||||
pause();
|
||||
}
|
||||
void child_process()
|
||||
{
|
||||
int x = 0;
|
||||
while(x < N)
|
||||
{
|
||||
player_wait();
|
||||
printf("\tPong %d!\n", ++x);
|
||||
kill(getppid(), SIGUSR1);
|
||||
}
|
||||
return ;
|
||||
}
|
||||
|
||||
void parent_process(pid_t pid)
|
||||
{
|
||||
int y = 0;
|
||||
while (y < N)
|
||||
{
|
||||
printf("Ping %d!\n", ++y);
|
||||
kill(pid, SIGUSR1);
|
||||
player_wait();
|
||||
}
|
||||
return ;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
//set up signal handler for parent & child
|
||||
struct sigaction sa;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_handler = sig_hand;
|
||||
|
||||
assert (sigaction(SIGUSR1, &sa, NULL) != -1);
|
||||
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == 0)
|
||||
child_process();
|
||||
else
|
||||
parent_process(pid);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
1. Expliquez pourquoi ce code n'est pas correct (Faites varier `N`).
|
||||
2. Proposez une solution.
|
||||
@@ -0,0 +1,59 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include "helpers.h"
|
||||
#include <stdint.h>
|
||||
size_t entier_vers_chaine(long valeur, char *tampon)
|
||||
{
|
||||
char chiffres[24];
|
||||
int i = 0;
|
||||
unsigned long v = (unsigned long)valeur;
|
||||
if (v == 0) chiffres[i++] = '0';
|
||||
while (v > 0) { chiffres[i++] = (char)('0' + (v % 10)); v /= 10; }
|
||||
size_t pos = 0;
|
||||
while (i > 0) tampon[pos++] = chiffres[--i];
|
||||
return pos;
|
||||
}
|
||||
|
||||
void dessiner_barre(long p, long dp,long cible,long width) {
|
||||
char ligne[128];
|
||||
size_t pos = 0;
|
||||
|
||||
long pourcent = (p * 100) / cible;
|
||||
long rempli = (p * width) / cible;
|
||||
|
||||
ligne[pos++] = '\r';
|
||||
ligne[pos++] = '[';
|
||||
for (long i = 0; i < width; i++)
|
||||
ligne[pos++] = (i < rempli) ? '#' : '-';
|
||||
ligne[pos++] = ']';
|
||||
ligne[pos++] = ' ';
|
||||
pos += entier_vers_chaine(pourcent, ligne + pos);
|
||||
ligne[pos++] = '%';
|
||||
ligne[pos++] = ' ';
|
||||
ligne[pos++] = '(';
|
||||
pos += entier_vers_chaine(p, ligne + pos);
|
||||
ligne[pos++] = '/';
|
||||
pos += entier_vers_chaine(cible, ligne + pos);
|
||||
ligne[pos++] = ')';
|
||||
ligne[pos++] = ' ';
|
||||
ligne[pos++] = 'd';
|
||||
ligne[pos++] = 'e';
|
||||
ligne[pos++] = 'r';
|
||||
ligne[pos++] = ':';
|
||||
ligne[pos++] = ' ';
|
||||
pos += entier_vers_chaine(dp, ligne + pos);
|
||||
ligne[pos++] = ' '; /* espace final : efface un residu si la ligne raccourcit */
|
||||
|
||||
ssize_t r = write(STDOUT_FILENO, ligne, pos);
|
||||
(void)r;
|
||||
}
|
||||
|
||||
int est_premier(uint64_t n) {
|
||||
if (n < 2) return 0;
|
||||
if (n % 2 == 0) return n == 2;
|
||||
for (uint64_t d = 3; d * d <= n; d += 2)
|
||||
if (n % d == 0) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef _HELPERS_H
|
||||
#define _HELPERS_H
|
||||
#include <stdint.h>
|
||||
size_t entier_vers_chaine(long valeur, char *tampon);
|
||||
int est_premier(uint64_t n);
|
||||
void dessiner_barre(long p, long dp,long cible,long width);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
#include<unistd.h>
|
||||
#include<stdio.h>
|
||||
#include<stdlib.h>
|
||||
#include<signal.h>
|
||||
#include<stdint.h>
|
||||
#include<assert.h>
|
||||
#include <time.h>
|
||||
double tstamp(void) {
|
||||
struct timespec tv;
|
||||
clock_gettime(CLOCK_REALTIME, &tv);
|
||||
return tv.tv_sec + tv.tv_nsec * 1.0e-9;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint64_t shots = 0,
|
||||
shots_in = 0;
|
||||
|
||||
double pi = 0,
|
||||
t1;
|
||||
|
||||
int main(int argc,char * argv[])
|
||||
{
|
||||
double x,y;
|
||||
t1 = tstamp();
|
||||
|
||||
alarm(5);
|
||||
|
||||
while(1){
|
||||
x = ((double)rand())/(double)RAND_MAX;
|
||||
y = ((double)rand())/(double)RAND_MAX;
|
||||
shots ++;
|
||||
|
||||
if ((x*x+y*y) <= 1)
|
||||
shots_in ++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdint.h>
|
||||
#include "helpers.h"
|
||||
|
||||
#define N_CIBLE 1000000UL /* on cherche le N_CIBLE-ieme nombre premier */
|
||||
#define LARGEUR_BARRE 50
|
||||
|
||||
static volatile sig_atomic_t compte_trouve = 0;
|
||||
static volatile sig_atomic_t dernier_premier = 0;
|
||||
|
||||
static void handler_alarm(int sig)
|
||||
{
|
||||
dessiner_barre(compte_trouve, dernier_premier,N_CIBLE,LARGEUR_BARRE);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct sigaction sa;
|
||||
struct itimerval it;
|
||||
uint64_t candidat = 1, compte = 0;
|
||||
|
||||
while (compte < N_CIBLE) {
|
||||
candidat++;
|
||||
if (est_premier(candidat)) {
|
||||
compte++;
|
||||
compte_trouve = (sig_atomic_t)compte;
|
||||
dernier_premier = (sig_atomic_t)candidat;
|
||||
}
|
||||
}
|
||||
dessiner_barre((long)compte, (long)candidat,N_CIBLE,LARGEUR_BARRE);
|
||||
printf("\nLe %lu-ieme nombre premier est %lu.\n", (unsigned long)N_CIBLE, (unsigned long)candidat);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
# Redirections, tubes, synchronisation
|
||||
|
||||
#### Ex1
|
||||
Soit le graphe de processus suivant (un tube est établi entre Pf2 et
|
||||
Pf1f1)
|
||||
|
||||
```bash
|
||||
| P
|
||||
|____
|
||||
| \ Pf1
|
||||
| \
|
||||
| \
|
||||
|\Pf2 |\
|
||||
| \ | \Pf1f1
|
||||
| \ | \
|
||||
O O O O
|
||||
()-->--()
|
||||
```
|
||||
|
||||
1. Ecrivez un programme pipe-ex.c qui implante le graphe ci-dessus
|
||||
(y compris le tube) et tel que :
|
||||
- Pf2 écrive en permanence toutes les 3 secondes son PID dans
|
||||
le tube en affichant ce qu'il écrit
|
||||
- Pf1f1 lise en permanence chaque seconde depuis tube
|
||||
`sizeof(pid_t)` en affichant ce qu'il lit
|
||||
|
||||
Vérifiez que le programme fonctionne comme prévu, i.e il affiche
|
||||
:
|
||||
|
||||
```bash
|
||||
16411 sent 16411
|
||||
16412 received 16411
|
||||
16411 sent 16411
|
||||
16412 received 16411
|
||||
.....
|
||||
|
||||
```
|
||||
|
||||
2. Lancez le programme ci-dessus et faites les essais suivants
|
||||
(relancez le programme après chaque essai). Expliquez à chaque
|
||||
fois vos observations.
|
||||
1. Envoyez le signal `SIGSTOP` à Pf2, puis le signal SIGCONT à
|
||||
Pf2.
|
||||
2. Envoyez le signal `SIGSTOP` à Pf1f1, puis le signal SIGCONT à
|
||||
Pf1f1.
|
||||
3. Envoyez le signal `SIGTERM` à Pf2.
|
||||
4. Envoyez le signal `SIGTERM` à Pf1f1.
|
||||
3. Modifiez le programme pipe-ex.c en assurant que tous les
|
||||
processus ferment les descripteurs du tube non utilisés. Faites
|
||||
les mêmes essais que ci-dessus et expliquez ce que vous
|
||||
observez.
|
||||
4. Modifiez encore une fois le programme pipe-ex.c pour que les
|
||||
deux processus Pf1, Pf2 écrivent dans le tube simultanement et
|
||||
que seul Pf1f1 le lise. Qu'observez-vous ?
|
||||
|
||||
#### Ex2
|
||||
Reprendre l'[exercice 1](../tp5/parallelisme.md) du tp précédent. Vous devez utiliser comme
|
||||
seul moyen de communication, entre les fils et le pere, des tubes (plus de `mmap`).
|
||||
Les processus fils, à la création, ne savent pas quelle tranche ils doivent sommer.
|
||||
|
||||
1. De combien de tubes a-t-on besoin ?
|
||||
2. On rappelle que l'écriture dans un tube est atomique jusqu'à `PIPE_BUF`.
|
||||
3. Écrire le programme correspondant.
|
||||
|
||||
#### Ex3
|
||||
Testez le programme de l'exercice 3 du td6 (Ératosthène + pipe)
|
||||
|
||||
#### Ex4
|
||||
Il s'agit d'un [exercice](./src/billes.c) classique de synchronisation. Des billes, dans une zone rectangulaire, se déplacent en rebodissant
|
||||
sur les parois et les unes sur les autres. Chaque bille est un processus. L'état global est une zone partagée, protégée
|
||||
en écriture par un sémaphore (cf cours).
|
||||
|
||||
L'affichage graphique est géré par le processus père (superviseur). Chaque bille, après mise à jour de sa position,
|
||||
envoie un message au superviseur par un tube pour rafraîchir la fenêtre d'affichage. **Seule cette partie est à compléter**.
|
||||
|
||||
<div align="center">
|
||||
<img src="billes.png">
|
||||
</div>
|
||||
|
||||
```bash
|
||||
gcc -o billes billes.c -lX11 -lm
|
||||
```
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 816 B |
@@ -0,0 +1,175 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mman.h>
|
||||
#include <semaphore.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#define NB_BILLES 20
|
||||
#define LARGEUR 640
|
||||
#define HAUTEUR 480
|
||||
#define RAYON 12
|
||||
#define FPS_DELAY_US 16000
|
||||
|
||||
/* =========================================================
|
||||
* ÉTAT D'UNE BILLE + MESSAGE D'AFFICHAGE + ZONE PARTAGÉE
|
||||
* ========================================================= */
|
||||
|
||||
typedef struct {
|
||||
float x, y, vx, vy; /* position + vitesse */
|
||||
} etat_bille_t;
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
float x, y; /* position sur la grille */
|
||||
} msg_bille_t;
|
||||
|
||||
typedef struct {
|
||||
etat_bille_t billes[NB_BILLES];
|
||||
sem_t sem_shm; /* protège billes[] */
|
||||
} zone_partagee_t;
|
||||
|
||||
/* =========================================================
|
||||
* PROCESSUS "BILLE" (fils)
|
||||
* ========================================================= */
|
||||
|
||||
void processus_bille(int id, int fd_ecriture, zone_partagee_t *zone) {
|
||||
while (1) {
|
||||
sem_wait(&zone->sem_shm);
|
||||
etat_bille_t *b = &zone->billes[id];
|
||||
|
||||
b->x += b->vx;
|
||||
b->y += b->vy;
|
||||
|
||||
if (b->x - RAYON < 0) { b->x = RAYON; b->vx = -b->vx; }
|
||||
if (b->x + RAYON > LARGEUR) { b->x = LARGEUR - RAYON; b->vx = -b->vx; }
|
||||
if (b->y - RAYON < 0) { b->y = RAYON; b->vy = -b->vy; }
|
||||
if (b->y + RAYON > HAUTEUR) { b->y = HAUTEUR - RAYON; b->vy = -b->vy; }
|
||||
|
||||
for (int j = id + 1; j < NB_BILLES; j++) {
|
||||
etat_bille_t *autre = &zone->billes[j];
|
||||
float dx = autre->x - b->x;
|
||||
float dy = autre->y - b->y;
|
||||
float dist = sqrtf(dx * dx + dy * dy);
|
||||
|
||||
if (dist > 0.0f && dist < 2.0f * RAYON) {
|
||||
float nx = dx / dist, ny = dy / dist;
|
||||
float overlap = 2.0f * RAYON - dist;
|
||||
|
||||
b->x -= nx * overlap / 2.0f;
|
||||
b->y -= ny * overlap / 2.0f;
|
||||
autre->x += nx * overlap / 2.0f;
|
||||
autre->y += ny * overlap / 2.0f;
|
||||
|
||||
float v1n = b->vx * nx + b->vy * ny;
|
||||
float v2n = autre->vx * nx + autre->vy * ny;
|
||||
float diff = v2n - v1n;
|
||||
|
||||
b->vx += diff * nx;
|
||||
b->vy += diff * ny;
|
||||
autre->vx -= diff * nx;
|
||||
autre->vy -= diff * ny;
|
||||
}
|
||||
}
|
||||
|
||||
msg_bille_t m = ; /* <- TODO */
|
||||
sem_post(&zone->sem_shm);
|
||||
|
||||
write(); /* <- TODO */
|
||||
|
||||
usleep(FPS_DELAY_US);
|
||||
}
|
||||
}
|
||||
|
||||
/* =========================================================
|
||||
* PROCESSUS SUPERVISEUR (parent)
|
||||
* ========================================================= */
|
||||
|
||||
void processus_superviseur(int fd_lecture) {
|
||||
Display *dpy = XOpenDisplay(NULL);
|
||||
|
||||
assert(dpy != 0);
|
||||
|
||||
int screen = DefaultScreen(dpy);
|
||||
Window win = XCreateSimpleWindow(dpy, RootWindow(dpy, screen),
|
||||
0, 0, LARGEUR, HAUTEUR, 1,
|
||||
BlackPixel(dpy, screen), WhitePixel(dpy, screen));
|
||||
XSelectInput(dpy, win, ExposureMask | KeyPressMask);
|
||||
XMapWindow(dpy, win);
|
||||
GC gc = XCreateGC(dpy, win, 0, NULL);
|
||||
|
||||
float px[NB_BILLES] = {0}, py[NB_BILLES] = {0};
|
||||
|
||||
msg_bille_t m;
|
||||
|
||||
while (read(fd_lecture, &m, sizeof(m)) == (ssize_t)sizeof(m)) {
|
||||
if (m.id >= 0 && m.id < NB_BILLES) {
|
||||
px[m.id] = m.x;
|
||||
py[m.id] = m.y;
|
||||
}
|
||||
|
||||
XClearWindow(dpy, win);
|
||||
for (int i = 0; i < NB_BILLES; i++) {
|
||||
XFillArc(dpy, win, gc,
|
||||
(int)px[i] - RAYON, (int)py[i] - RAYON,
|
||||
RAYON * 2, RAYON * 2, 0, 360 * 64);
|
||||
}
|
||||
XFlush(dpy);
|
||||
}
|
||||
|
||||
XFreeGC(dpy, gc);
|
||||
XCloseDisplay(dpy);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd[2]; /* --- tube : billes -> superviseur --- */
|
||||
|
||||
assert(pipe(fd) != -1);
|
||||
|
||||
/* --- zone partagée : billes + sémaphore, créée AVANT les fork() --- */
|
||||
|
||||
zone_partagee_t *zone = mmap(NULL, sizeof(zone_partagee_t),
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
assert(zone != MAP_FAILED);
|
||||
assert(sem_init(&zone->sem_shm, 1 , 1) != -1); /* --- semaphore --> section critique --- */
|
||||
|
||||
srand(time(NULL));
|
||||
for (int i = 0; i < NB_BILLES; i++) {
|
||||
zone->billes[i].x = RAYON + rand() % (LARGEUR - 2 * RAYON);
|
||||
zone->billes[i].y = RAYON + rand() % (HAUTEUR - 2 * RAYON);
|
||||
zone->billes[i].vx = (rand() % 5 + 2) * (rand() % 2 ? 1 : -1);
|
||||
zone->billes[i].vy = (rand() % 5 + 2) * (rand() % 2 ? 1 : -1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < NB_BILLES; i++) {
|
||||
pid_t pid = fork();
|
||||
|
||||
assert(pid >= 0);
|
||||
|
||||
if (pid == 0) {
|
||||
close(fd[0]); /* le fils ne lit pas le tube */
|
||||
processus_bille(i, fd[1], zone);
|
||||
close(fd[1]);
|
||||
munmap(zone, sizeof(zone_partagee_t));
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd[1]); /* le parent n'écrit pas le tube */
|
||||
processus_superviseur(fd[0]);
|
||||
close(fd[0]);
|
||||
|
||||
for (int i = 0; i < NB_BILLES; i++) wait(NULL);
|
||||
|
||||
sem_destroy(&zone->sem_shm);
|
||||
munmap(zone, sizeof(zone_partagee_t));
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user