Sémaphores
semget()
semctl()
semop()
type struct semMémoires partagées
type struct semid_ds
type struct sembuf
shmget()Files de messages
shmctl()
shmat()
shmdt()
msgget()
msgctl()
msgrcv()
semget - permet d'utiliser un ensemble de sémaphores.Syntaxe
#include <sys/types.h> // contient la définition de key_t
#include <sys/sem.h> // contient le profil de semget() int semget (key_t key, int nsems, int semflg); |
Description
La fonction semget() permet d'utiliser l'ensemble de sémaphores de clé key et de nsems (<= SEMMSL) sémaphores. Les valeurs possibles de semflg sont :
Si l'ensemble de sémaphores existe déjà, la valeur de nsems est ignorée. Elle doit cependant être inférieure ou égale au nombre de sémaphores de l'ensemble déjà créé.
Valeur retournée
La fonction semget() retourne l'identificateur (voir la commande ipcs) de l'ensemble de sémaphores de clé key (voir famille xxxget()).
Diagnostic d'erreur
La fonction semget() retourne -1 en cas d'erreur et positionne la variable globale errno. Parmi les erreurs possibles :
semctl - contrôles d'un ensemble de sémaphores.Syntaxe
#include <sys/sem.h> // contient le profil de semctl()
// et la déclaration de struct semid_ds int semctl (int semid, int semnum, int cmd, union semun arg); [2] |
Description
La fonction semctl() permet d'effectuer des commandes sur l'ensemble de sémaphores d'identificateur semid.
La signification des paramètres arg et semnum dépend de la valeur du paramètre cmd qui permet un nombre de contrôles beaucoup plus important que pour les autres I.P.C.s.
Cette fonction permet entre autre d'initialiser un ou tous les sémaphores d'un ensemble, de connaître la valeur de tous les sémaphores d'un ensemble, etc.
Le dernier paramètre, arg, est une union qui n'est pas obligatoirement déclarée dans les fichiers .h inclus, et qui peut devoir être ajoutée par l'utilisateur.
Voici un extrait du fichier /usr/include/bits/sem.h :
/* The user should define a union like the following to
use it for arguments
for `semctl'. union semun
Previous versions of this file used to define this
union but this is
#define _SEM_SEMUN_UNDEFINED 1 |
Le xman de la fonction semctl()
indique pour sa part comment faire la déclaration :
#if defined(__GNU_LIBRARY__)&& !defined (_SEM_SEMUN_UNDEFINED)
/* union is defined by including <sys/sem.h> */ #else /* according to X/OPEN we have to define it ourselves */ union semun { int val; // <= value for SETVAL struct semid_ds *buf; // <= buffer for IPC_STAT & IPC_SET unsigned short int *array; // <= array for GETALL & SETALL struct seminfo *__buf; // <= buffer for IPC_INFO }; #endif |
Comme l'indiquent les commentaires, la donnée membre qui doit être initialisée et qui sera utilisée par la fonction dépend de la valeur du paramètre cmd, décrit plus loin.
On rappelle qu'un sémaphore n-aire peut être considéré comme une valeur à laquelle on associe une file d'attente. Chaque sémaphore d'un ensemble est représenté par une structure struct sem (fichier /usr/include/sys/sem.h) qui est définie de la façon suivante :
struct sem {
ushort_t semval; // valeur du sémaphore [3] pid_t sempid; // le pid du dernier processus à avoir manipulé le // sémaphore ushort_t semncnt; // le nombre de processus en attente d'une // augmentation de la valeur semval, ushort_t semzcnt; // le nombre de processus en attente de la valeur 0 // dans semval. }; |
Un ensemble de sémaphores est représenté par la structure struct semid_ds :
struct semid_ds {
struct ipc_perm sem_perm; /* operation permission struct */ struct sem *sem_base; /* ptr to first semaphore in set*/ ushort_t sem_nsems; /* # of semaphores in set */ time_t sem_otime; /* last semop time */ time_t sem_ctime; /* last change time */ }; |
où sem_base peut être considéré comme un tableau de sem_nsems sémaphores puisque c’est l’adresse du premier sémaphore de l’ensemble.
Les valeurs possibles de cmd sont :
La fonction semctl() renvoie 0 ou le nombre demandé en cas de succès.
Diagnostic d'erreur
La fonction semctl() renvoie -1 en cas d'erreur et positionne la variable globale errno.
semop - exécution d'un ensemble d'opérations sur un ensemble de sémaphores..Syntaxe
#include <sys/sem.h> // contient le profil de la fonction semop()
// et la déclaration de struct sembuf int semop (int semid, struct sembuf *sops, unsigned nsops); |
Description
La fonction semop() permet d'effectuer l'ensemble de nsops opérations décrites chacune dans le struct sembuf correspondant du tableau pointé par sops sur l’ensemble de sémaphores d’identificateur semid. Le paramètre sops est un pointeur vers un tableau de nsops opérations. Chaque opération est décrite par un struct sembuf dont voici la forme:
struct sembuf [4]{
unsigned short int sem_num; // numéro (dans l'ensemble) du sémaphore // concerné par l'opération short sem_op; // opération à effectuer (décrite plus bas) short sem_flg; // on ne se servira que de IPC_NOWAIT, pour rendre // non bloquante une opération qui l'aurait été }; |
Si aucune des opérations (sem_op) ne bloque ou n'aurait dû bloquer le processus qui exécute semop(), toutes les opérations sont exécutée en une seule fois (de façon atomique) dans l'ordre croissant des indices de sops.
Si une au moins des opérations entraîne un blocage du processus qui exécute cette fonction semop(), aucune opération n'est réalisée et le processus se bloque jusqu'à ce qu'une opération débloquante ait été effectuée par un autre processus. A ce moment là tous les processus, bloqués sur le ou les sémaphores de l'ensemble concerné par cette dernière opération, sont réveillés et le système essaie à nouveau d'exécuter toutes les opérations pour chaque processus dans l'ordre de leur date de blocage. Si l'une de ces opérations est à nouveau bloquante, aucune n'est exécutée et le processus concerné se bloque à nouveau.
Si au moins une des opérations aurait dû entraîner le blocage du processus, et si la donnée-membre sem_flg du sembuf correspondant à cette opération contient l'option IPC_NOWAIT [6], aucune des opérations n'est réalisée, semop() renvoie -1 et errno prend la valeur EAGAIN.
Voici les opérations réalisées suivant la valeur de sem_op :
La fonction semop() renvoie 0 en cas de succès.
Diagnostic d'erreur
La fonction semop() renvoie -1 en cas d'erreur et positionne la variable globale errno. Si l'I.P.C. est détruite alors qu'elle bloque un processus, celui-ci est débloqué et la fonction semop() renvoie -1.
shmget - permet d'utiliser un segment de mémoire partagée.Syntaxe
#include <cstddef> // contient la définition de size_t
#include <sys/types.h> // contient la définition de key_t
int shmget (key_t key, size_t size, int shmflg); |
Description
La fonction shmget() permet d'utiliser le segment de mémoire partagée de clé key et de taille size en nombre d'octets. Les shmflgs possibles sont :
Valeur retournée
La fonction shmget() retourne l'identificateur du segment de mémoire partagée de clé key (voir famille get).
Diagnostic d'erreur
La fonction shmget() retourne -1 en cas d'erreur et positionne la variable globale errno.
shmctl - contrôles d'un segment de mémoire partagée.Syntaxe
#include <sys/shm.h> // contient le profil de la fonction shmctl()
// et permet d'atteindre la définition de shmid_ds int shmctl (int shmid, int cmd, struct shmid_ds *buf); |
Description
La fonction shmctl() permet d'effectuer des commandes sur le segment de mémoire partagée d'identificateur shmid.
Trois commandes sont possibles:
Valeur retournée
La fonction shmctl() renvoie 0 en cas de succès.
Diagnostic d'erreur
La fonction shmctl() renvoie -1 en cas d'erreur et positionne la variable globale errno.
shmat - attachement à un segment de mémoire partagée.Syntaxe
#include <sys/shm.h> // contient le profil de la fonction shmat()
void * shmat (int shmid, const void * shmaddr, int shmflg)[5]; |
Description
La fonction shmat() permet d'attacher une adresse virtuelle au segment de mémoire partagée shmid. L'adresse shmaddr, passée en paramètre, permet au système de calculer l'adresse virtuelle d'attachement à ce segment. Il faut la choisir avec précaution pour éviter, par exemple, qu'elle ne vienne à un endroit déjà utilisé ou pire, interdit. Pour raison de sécurité, il est donc préférable de laisser totalement au système le choix de cette adresse. Cette solution permet en outre d'éviter d'énormes problèmes de portabilité. On laisse ce choix total au système en passant pour valeur de shmaddr l'adresse 0.
Si l'on utilise l'option SHM_RDONLY on attache le segment de mémoire partagée en lecture seulement. Toute tentative d'écriture dans le segment provoque l'envoi du signal SIGSEGV (segmentation fault (core dumped)). Si l'option 0 est utilisée, l’accès au segment est autorisé en lecture et en écriture.
Si un processus acquiert un segment de mémoire partagée à l'aide de la primitive shmget(), il ne peut rien en faire tant qu'il ne dispose pas de son adresse. La primitive shmat() permet donc à un processus, en renvoyant l'adresse virtuelle du début du segment, de travailler avec un segment de mémoire partagée comme avec une adresse quelconque (un pointeur quelconque).
Valeur retournée
La fonction shmat() renvoie l'adresse virtuelle du segment de mémoire partagée. Deux processus différents seront attachés au même segment de mémoire partagée, le plus probablement, à des adresses virtuelles différentes.
Diagnostic d'erreur
La fonction shmat() renvoie -1 en cas d'erreur et positionne la variable globale errno.
shmdt - détachement d'un segment de mémoire partagée.Syntaxe
#include <sys/shm.h> // contient le profil de la fonction shmdt()
int shmdt (const void *addr); |
Description
La fonction shmdt() permet de se détacher du segment de mémoire partagée préalablement attaché à l'adresse addr par l'appel à la primitive shmat(). Cette adresse devient donc une adresse illégale du processus.
Valeur retournée
La fonction shmdt() renvoie 0 en cas de succès.
Diagnostic d'erreur
La fonction shmdt() renvoie -1 en cas d'erreur et positionne la variable globale errno.
msgget - permet d'utiliser une file de messages.Syntaxe
#include <sys/types.h> // contient la définition de key_t
#include <sys/msg.h> // contient le profil de la fonction msgget() int msgget (key_t key, int flags); |
Description
Valeur retournéeIPC_CREAT [6] pour créer la file de messages si elle n'existe pas déjà. Attention, il faut dans ce cas faire un ou binaire avec les droits accordés. IPC_EXCL combinée avec IPC_CREAT (IPC_CREAT | IPC_EXCL | droits d'accès) permet de s'assurer de la création de la file de messages. Si la file existe déjà, msgget() retourne -1. 0 permet d'utiliser une file de messages qui existe déjà (erreur si ce n'est pas le cas).
La fonction msgget() retourne l'identificateur (voir ipcs -q, colonne ID) de la queue de messages de clé key (voir famille get).
Diagnostic d'erreur
La fonction msgget() retourne -1 en cas d'erreur et positionne la variable globale errno.
msgctl - contrôles d'une file de messages.Syntaxe
#include <sys/msg.h> // contient le profil de msgctl()
// et la déclaration de struct msqid_ds int msgctl (int msqid, int cmd, struct msqid_ds *buf); |
Description
La fonction msgctl() permet d'effectuer des commandes sur la file de messages d'identificateur msqid. Trois commandes sont possibles :
La fonction msgctl() renvoie 0 en cas de succès.
Diagnostic d'erreur
La fonction msgctl() renvoie -1 en cas d'erreur et positionne la variable globale errno.
msgrcv - réception d'une trame dans une file de message.Syntaxe
#include <cstddef> // contient la définition de size_t
#include <sys/msg.h> // contient le profil de la fonction msgrcv() int msgrcv (int msqid, void * msgp, size_t msgsz, long msgtyp, int msgflg); |
Description
La fonction msgrcv() permet de recevoir une trame (voir msgsnd()), à l'endroit mémoire pointé par msgp, sur la file de messages msqid suivant la valeur du paramètre msgtyp. Le paramètre msgsz est la taille maximale admise du message contenu dans la trame. Si aucun message correspondant au type msgtyp n'est disponible dans la file, le processus récepteur se bloque jusqu'à ce qu'un message satisfaisant la demande soit disponible.
Pour éviter d'être bloqué, msgflg doit contenir IPC_NOWAIT (voir msgsnd()). Si un message correspondant au type msgtyp est disponible dans la file mais que sa taille est supérieur à msgsz, msgrcv() retourne -1 et positionne errno à E2BIG, à moins que l'option msgflg ne contienne MSG_NOERROR, auquel cas le message est extrait (dans sa totalité) mais tronqué à la taille msgsz.
Le paramètre msgtyp indique la trame à extraire :
La fonction msgrcv() renvoie la taille du message effectivement retiré.
Diagnostic d'erreur
La fonction msgrcv() renvoie -1 en cas d'erreur et positionne la variable globale errno.
msgsnd - envoi d'une trame dans une file de messages.Syntaxe
#include <cstddef> // contient la définition de size_t
#include <sys/msg.h> // contient le profil de la fonction msgsnd() int msgsnd (int msqid, void * msgp, size_t msgsz, int msgflg); |
Description
La fonction msgsnd() permet d'envoyer la trame pointée par msgp, dont le message est de longueur msgsz, sur la file de messages msqid avec les options msgflg.
Le type void, qui est celui prévu pour la trame peut porter n'importe quel nom et est à définir par l'utilisateur de la façon suivante:
Pour éviter ce problème de blocage, on peut utiliser l'option IPC_NOWAIT, auquel cas, si le processus émetteur aurait dû être bloqué, la fonction retourne -1 et errno est positionné à EAGAIN (selon le man et peut-être ENOMSG).
Valeur retournée
La fonction msgsnd() renvoie 0 en cas de succès.
Diagnostic d'erreur
La fonction msgsnd() renvoie -1 en cas d'erreur et positionne la variable globale errno.
[2] En réalité, la véritable définition de la fonction, extraite du fichier /usr/include/sys/sem.h, est la suivante :
int semctl (int semid, int semnum, int cmd, ...);
(voir remarque [2] sur la fonction fcntl() concernant le paramètre ...).
La commande man correspondante donne encore un autre profil, mais qui est incomplet car ne comprend pas la version à trois paramètres
typedef unsigned short int ushort_t; |
[4]
structure décrite dans /usr/include/linux/sem.h
[5]
déclaration conforme au fichier <sys/shm.h> mais différente dans le man
[6]
définie dans le fichier /usr/include/sys/ipc.h
[7]
accessible par le fichier /usr/include/sys/sem.h