Rôles d’un système d’exploitation:
Cloisonnement entre le mode utilisateur et le mode noyau
User mode
Kernel mode
2 méthodes:
Lorsqu’une interruption est reçue, le processeur suspend l’exécution du thread, bascule en mode noyau, et appelle la routine traitant l’interruption. Lorsque la routine se termine, le processeur rebascule en mode utilisateur est reprend l’exécution du thread.
Un appel système consiste à appeler une fonction exécuté en mode
noyau. Le passage du mode utilisateur au mode noyau peut se faire en
générant une interruption logicielle particulière (par exemple sur les
processeurs ARM ou les processeurs x86 32 bits), ou en exécutant une
instruction particulière (par exemple, l’instruction
syscall
sur les processeurs x86 64 bits) qui a un effet
équivalent. Le kernel exécute alors la fonction correspondant au numéro
de l’appel système demandé. Lorsque l’appel système se termine, on sort
du traitant d’interruption, et le processeur rebascule en mode
utilisateur.
La commande strace
intercepte et affiche les appels
systèmes d’un programme:
$ strace echo "coucou"
execve("/bin/echo", ["echo", "coucou"], [/* 54 vars */]) = 0
brk(NULL) = 0x25d2000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f619cc01000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
[...]
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
write(1, "coucou\n", 7coucou
) = 7
close(1) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++
Certains cadres de pages sont référencés par plusieurs processus.
Cela est possible par exemple si les processus ne font que des accès en
lecture à la page. Il s’agit typiquement du code des bibliothèques
partagées (libc.so
par exemple) qui peuvent être chargées
par plusieurs processus.
Sémaphore:
sem_open("/CLE", O_CREAT, S_IRWXU, nb_jetons);
sem_t*
/
sem_open("/CLE", 0);
sem_t
sem_unlink(const char *name)
sem_wait(sem_t* sem)
sem_post(sem_t* sem)
L’opération sem_wait
est bloquante tant qu’il n’y a pas
de jeton. L’opération sem_post
est, elle, non-bloquante, et
permet de débloquer un des processus en attente d’un jeton.
Voici un exemple d’utilisation d’un sémaphore. Le progamme
exemple_sem_init
crée un sémaphore, qui peut ensuite être
utilisé par le programme exemple_sem
. Le programme
exemple_sem_unlink
détruit un sémaphore.
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/stat.h>
int main(int argc, char**argv) {
*sem;
sem_t
if (argc != 3) {
(stderr, "USAGE = %s cle valeur\n", argv[0]);
fprintf(EXIT_FAILURE);
exit}
char*cle=argv[1];
int valeur = atoi(argv[2]);
/* Creation et initialisation du semaphore */
= sem_open(cle, O_CREAT, S_IRWXU, valeur);
sem if (sem == SEM_FAILED) {
("sem_open failed");
perror(EXIT_FAILURE);
exit}
("Initialisation OK\n");
printfint sval = -1;
/* recupere le nombre de jetons */
if(sem_getvalue(sem, &sval) <0) {
("sem_getvalue failed");
perror(EXIT_FAILURE);
exit}
("sval = %d\n", sval);
printf
return EXIT_SUCCESS;
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>
int main(int argc, char**argv) {
*sem;
sem_t
if (argc != 2) {
(stderr, "USAGE = %s cle\n", argv[0]);
fprintf(EXIT_FAILURE);
exit}
char*cle=argv[1];
/* Creation et initialisation du semaphore */
= sem_open(cle, 0);
sem if (sem == SEM_FAILED) {
("sem_open");
perror(EXIT_FAILURE);
exit}
("Ouverture OK\n");
printf
("On prend un jeton...\n");
printf(sem);
sem_wait("Jeton obtenu.\n");
printf(5);
sleep
("On relache le jeton\n");
printf(sem);
sem_post("Jeton relache\n");
printf
return EXIT_SUCCESS;
}
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/stat.h>
int main(int argc, char**argv) {
*sem;
sem_t
if (argc != 2) {
(stderr, "USAGE = %s cle\n", argv[0]);
fprintf(EXIT_FAILURE);
exit}
char*cle=argv[1];
if(sem_unlink(cle) < 0){
("sem unlink failed");
perror();
abort}
return EXIT_SUCCESS;
}