• Aucun résultat trouvé

Socket : communication par connexion

3. la libération de la ressource, la rendant disponible pour les autres programmes

12.3 L’allocation de ressources – les sémaphores

12.3.3 Les sémaphores sous Linux

Comme nous l’avons vu dans les chapitres précédents, les sémaphores sont implémentés sous Linux sous la forme d’IPC.

De plus, les IPC de sémaphores introduisent une nouvelle notion en plus des fonctions P() et V() : il s’agit de la fonction ATT(), qui bloque un processus dans l’attente que le sémaphore soit nul (mais sans décrémenter la valeur du sémaphore).

La création d’un ensemble de sémaphore se fait à l’aide de la fonction semget() :

<<

SYNOPSIS

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

int semget(key_t key, int nsems, int semflg);

DESCRIPTION

Cette fonction retourne l’identifiant de l’ensemble de sémaphores associé à la valeur de clé key. Un nouvel ensemble contenant nsems sémaphores est créé si key a la valeur IPC_PRIVATE ou si aucun ensemble n’est associé à key, et si l’option IPC_CREAT est présente dans semflg.

Si semflg contient à la fois IPC_CREAT et IPC_EXCL et qu’un ensemble de sémaphores existe déjà pour la clé key, semget() échoue et errno vaut EEXIST (ceci est analogue à l’effet de la combinaison O_CREAT | O_EXCL pour open(2).)

Pendant la création, les 9 bits de poids faibles de

l’argument semflg définissent les permissions d’accès (pour le propriétaire, le groupe et les autres) au jeu de

sémaphores, en utilisant le même format et la même signification que les droits d’accès dans open(2). Les permissions d’exécution ne sont pas utilisées par le

système, et pour un jeu de sémaphores, l’autorisation d’écriture signifie autorisation de modification.

Les valeurs des sémaphores dans un ensemble qui vient d’être créé sont indéterminées (POSIX.1-2001 est explicite sur ce point). Même si Linux, comme de nombreuses autres

implémentations, initialise les valeurs des sémaphores à 0, une application portable ne peut pas compter sur cette initialisation : elle doit initialiser explicitement les sémaphores à la valeur souhaitée.

Durant la création, la structure de données semid_ds (voir semctl(2)) contrôlant le jeu de sémaphores est initialisée ainsi :

sem_perm.cuid et sem_perm.uid contiennent l’UID effectif du processus appelant.

sem_perm.cgid et sem_perm.gid contiennent le GID effectif du processus appelant.

Les 9 bits de poids faibles de sem_perm.mode

contiennent les 9 bits de poids faibles de semflg.

sem_nsems reçoit la valeur nsems.

sem_otime est mis à 0.

sem_ctime est rempli avec l’heure actuelle.

L’argument nsems peut valoir 0 (ignore) si l’appel

système n’est pas une création d’ensemble de sémaphores.

Autrement nsems doit être supérieur à 0 et inférieur ou égal au nombre maximal de sémaphores par ensemble (SEMMSL).

Si le jeu de sémaphores existe déjà, les permissions d’accès sont contrôlées.

VALEUR RENVOYÉE

Si l’appel réussit, il renvoie l’identifiant de l’ensemble (un entier positif), sinon il renvoie -1 et errno contient le code d’erreur.

ERREURS

En cas d’erreur, errno prend l’une des valeurs suivantes :

EACCES Le jeu de sémaphore associé à key existe, mais le processus n’a aucun droit d’accès sur lui et n’a pas la capacité CAP_IPC_OWNER.

EEXIST Le jeu de sémaphore associé a key existe mais l’argument semflg précise à la fois IPC_CREAT et IPC_EXCL.

EINVAL nsems est inférieur à zéro ou supérieur à la limite sur le nombre de sémaphores par ensemble, (SEMMSL), ou l’ensemble de sémaphores

identifié par key existe déjà, et nsems est plus grand que le nombre de sémaphores par ensemble.

ENOENT Aucun jeu de sémaphore associé a key n’existe et l’argument semflg ne précise pas IPC_CREAT.

ENOMEM Pas assez de mémoire pour créer les structures nécessaires.

ENOSPC Le nombre maximal de jeux de sémaphores sur le système (SEMMNI) est atteint, ou le nombre maximal de sémaphores sur le système est atteint (SEMMNS).

>>

L’initialisation d’un sémaphore sem à une valeur v0 se fait via la fonction semctl() : semctl(sem, 0, SETVAL, v0);

La destruction d’un semaphore sem se fait par l’appel de cette même fonction semctl() : semctl(sem, 0, IPC_RMID, 0);

Lire le manuel de cette function pour plus de details. Enfin, les fonctions P(), V(), et ATT() d’un sémaphore se font à l’aide de la fonction semop() :

<<

SYNOPSIS

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

int semop(int semid, struct sembuf *sops, unsigned nsops);

int semtimedop(int semid, struct sembuf *sops, \

unsigned nsops, struct timespec *timeout);

DESCRIPTION

Chaque sémaphore dans un ensemble de sémaphores se voit associer les valeurs suivantes :

unsigned short semval; /* valeur du sémaphore */

unsigned short semzcnt;/* # Attente pour zéro */

unsigned short semncnt;/* # Attente d’incrément */

pid_t sempid; /* dernier processus agissant */

La fonction semop() effectue des opérations sur les membres de l’ensemble de sémaphores identifié par semid. Chacun des nsops éléments dans le tableau pointé par sops indique une opération à effectuer sur un sémaphore en utilisant une structure struct sembuf contenant les membres suivants : unsigned short sem_num; /* Numéro du sémaphore */

short sem_op; /* Opération sur le sémaphore */

short sem_flg; /* Options pour l’opération */

Les options possibles pour sem_flg sont IPC_NOWAIT et SEM_UNDO. Si une opération indique l’option SEM_UNDO, elle sera annulée lorsque le processus se terminera.

L’ensemble des opérations contenues dans sops est

effectué atomiquement. Les opérations sont toutes réalisées en même temps, et seulement si elle peuvent toutes être effectuées. Le comportement de l’appel système si toutes les opérations ne sont pas réalisables dépend de la présence de l’attribut IPC_NOWAIT dans les champs sem_flg décrits plus haut.

Chaque opération est effectuée sur le sem_num-ième sémaphore de l’ensemble. Le premier sémaphore est le numéro 0. Pour chaque sémaphore, l’opération est l’une des trois décrites ci-dessous.

Si l’argument sem_op est un entier positif, la fonction ajoute cette valeur à semval. De plus si SEM_UNDO est demandé, le système met à jour le compteur « undo » du sémaphore (semadj). Cette opération n’est jamais

bloquante. Le processus appelant doit avoir l’autorisation de modification sur le jeu de sémaphores.

Si sem_op vaut zéro le processus doit avoir l’autorisation de lecture sur l’ensemble de sémaphores. Le processus attend que semval soit nul ; si semval vaut zéro, l’appel

système continue immédiatement. Sinon, si l’on a réclamé IPC_NOWAIT dans sem_flg, l’appel système échoue (en

annulant les actions précédentes) et errno contient le code d’erreur EAGAIN. Autrement semzcnt est incrémenté de 1 et le processus s’endort jusqu’à ce que l’un des

événements suivants se produise :

· semval devient égal à 0, alors semzcnt est décrémenté.

· Le jeu de sémaphores est supprimé. L’appel système échoue et errno contient le code d’erreur EIDRM.

· Le processus reçoit un signal à intercepter, la valeur de semzcnt est décrémentée et l’appel système échoue avec errno contenant le code d’erreur EINTR.

· La limite temporelle indiquée par timeout dans un semtimedop() a expiré : l’appel système échoue avec errno contenant EAGAIN.

Si sem_op est inférieur à zéro, le processus appelant doit avoir l’autorisation de modification sur le jeu de sémaphores. Si semval est supérieur ou égal à la valeur absolue de sem_op, la valeur absolue de sem_op est

soustraite de semval, et si SEM_UNDO est indiqué, le système met à jour le compteur « undo » du sémaphore (semadj).

Puis l’appel système continue. Si la valeur absolue de sem_op est plus grande que semval, et si l’on a réclamé IPC_NOWAIT dans sem_flg, l’appel système échoue (annulant les actions précédentes) et errno contient le code

d’erreur EAGAIN. Sinon semncnt est incrémenté de un et le processus s’endort jusqu’à ce que l’un des événements

suivants se produise :

· semval devient supérieur ou égal à la valeur absolue de sem_op, alors la valeur semncnt est décrémentée, la valeur absolue de sem_op est soustraite de semval et si SEM_UNDO est demandé le système met à jour le compteur « undo » (semadj) du sémaphore.

· Le jeu de sémaphores est supprimé. L’appel système échoue et errno contient le code d’erreur EIDRM.

· Le processus reçoit un signal à intercepter, la valeur de semncnt est décrémentée et l’appel système échoue avec errno contenant le code d’erreur EINTR.

· La limite temporelle indiqué par timeout dans un semtimedop() a expiré : l’appel système échoue avec errno contenant EAGAIN.

En cas de succès, le membre sempid de chacun des sémaphores indiqués dans le tableau pointé par sops est rempli avec le PID du processus appelant. Enfin sem_otime est fixé à l’heure actuelle.

La fonction semtimedop() se comporte comme semop() sauf que dans le cas où le processus doit dormir, la durée maximale du sommeil est limitée par la valeur spécifiée dans la

structure timespec dont l’adresse est transmise dans le paramètre timeout. Si la limite indiquée a été atteinte, l’appel système échoue avec errno contenant EAGAIN (et

aucune opération de sops n’est réalisée). Si le paramètre timeout est NULL, alors semtimedop() se comporte exactement comme semop().

VALEUR RENVOYÉE

En cas de réussite, semop() et semtimedop() renvoient 0.

Sinon ils renvoient -1 et errno contient le code d’erreur.

ERREURS

En cas d’erreur, errno prend l’une des valeurs suivantes : E2BIG l’argument nsops est supérieur à SEMOPM, le nombre maximal d’opérations par appel système.

EACCES Le processus appelant n’a pas les permissions nécessaires pour effectuer les opérations sur les sémaphores spécifiés et n’a pas la capacité

CAP_IPC_OWNER.

EAGAIN Une opération ne pouvait pas être effectuée immédiatement et IPC_NOWAIT a été indiqué dans l’argument sem_flg, ou la durée limite indiquée dans timeout a expiré.

EFAULT sops ou timeout pointent en dehors de l’espace d’adressage accessible.

EFBIG La valeur de sem_num est inférieure à 0 ou supérieure ou égale au nombre de sémaphores dans l’ensemble.

EIDRM Le jeu de sémaphores a été supprimé.

EINTR Un signal a été reçu pendant l’attente.

EINVAL L’ensemble de sémaphores n’existe pas ou semid est inférieur à zéro, ou nsops n’est pas strictement positive.

ENOMEM L’argument sem_flg de certaines opérations demande SEM_UNDO et le système n’a pas assez de mémoire pour allouer les structures nécessaires.

ERANGE sem_op+semval est supérieur à SEMVMX (la valeur maximale de semval autorisée par l’implémentation) pour l’une des opérations.

NOTES

Les structures sem_undo d’un processus ne sont pas

héritées par ses enfants lors d’un fork(2). Par contre elles sont transmises lors d’un execve(2).

semop() n’est jamais relancé automatiquement après avoir été interrompu par un gestionnaire de signal quelque soit

l’attribut SA_RESTART durant l’installation du gestionnaire.

>>