.\" -*- coding: UTF-8 -*- .\" Copyright 2015-2017 Mathieu Desnoyers .\" .\" %%%LICENSE_START(VERBATIM) .\" Permission is granted to make and distribute verbatim copies of this .\" manual provided the copyright notice and this permission notice are .\" preserved on all copies. .\" .\" Permission is granted to copy and distribute modified versions of this .\" manual under the conditions for verbatim copying, provided that the .\" entire resulting derived work is distributed under the terms of a .\" permission notice identical to this one. .\" .\" Since the Linux kernel and libraries are constantly changing, this .\" manual page may be incorrect or out-of-date. The author(s) assume no .\" responsibility for errors or omissions, or for damages resulting from .\" the use of the information contained herein. The author(s) may not .\" have taken the same level of care in the production of this manual, .\" which is licensed free of charge, as they might when working .\" professionally. .\" .\" Formatted or processed versions of this manual, if unaccompanied by .\" the source, must acknowledge the copyright and authors of this work. .\" %%%LICENSE_END .\" .\"******************************************************************* .\" .\" This file was generated with po4a. Translate the source file. .\" .\"******************************************************************* .TH MEMBARRIER 2 "1 novembre 2020" Linux "Manuel du programmeur Linux" .SH NOM membarrier \- Poser des barrières mémoire sur un ensemble de threads .SH SYNOPSIS .nf .PP \fB#include \fP .PP \fBint membarrier(int \fP\fIcmd\fP\fB, unsigned int \fP\fIflags\fP\fB, int \fP\fIcpu_id\fP\fB);\fP .fi .PP \fINote\fP\ : il n'existe pas d'enveloppe pour cet appel système dans la glibc\ ; voir NOTES. .SH DESCRIPTION L'appel système \fBmembarrier\fP() aide à réduire le temps\-système des instructions de barrières mémoire nécessaire pour organiser les accès à la mémoire sur des systèmes à plusieurs cœurs. Cependant, cet appel système est plus lourd qu'une barrière mémoire, donc l'utiliser efficacement «\fI\ n'est pas\ \fP» aussi simple que de remplacer une barrière mémoire par cet appel système, mais nécessite de comprendre les détails ci\-dessous. .PP L'utilisation de barrières mémoire doit se faire en tenant compte du fait qu'elles doivent soit être associées avec leurs homologues, ou que le modèle de mémoire de l'architecture n'a pas besoin de barrières associées. .PP Dans certains cas, une face des barrières associées (qu'on appellera la «\ face rapide\ ») est sollicitée beaucoup plus souvent que l'autre (qu'on appellera la «\ face lente\ »). C'est le motif principal pour utiliser \fBmembarrier\fP(). L'idée clé est de remplacer, pour ces barrières associées, les barrières mémoire de la face rapide par de simples barrières du compilateur, par exemple\ : .PP .in +4n .EX asm volatile ("" : : : "memory") .EE .in .PP et de remplacer les barrières mémoire de la face lente par des appels à \fBmembarrier\fP(). .PP Cela ajoutera du temps\-système à la face lente et en supprimera de la face rapide, d'où une augmentation globale de performances tant que la face lente est si peu utilisée que le temps\-système d'appels \fBmembarrier\fP() ne l’emporte pas sur le gain de performance de la face rapide. .PP Le paramètre \fIcmd\fP est l'un des suivants : .TP \fBMEMBARRIER_CMD_QUERY\fP (depuis Linux 4.3) Rechercher l'ensemble des commandes prises en charge. Le code de retour de l'appel est un masque de bits des commandes prises en charge. \fBMEMBARRIER_CMD_QUERY\fP, dont la valeur est \fB0\fP, n'est pas inclus dans ce masque de bits. Cette commande est toujours prise en charge (sur les noyaux où \fBmembarrier\fP() est fourni). .TP \fBMEMBARRIER_CMD_GLOBAL\fP (depuis Linux 4.16) S'assurer que tous les threads de tous les processus du système passent par un état où tous les accès mémoire aux adresses de l'espace utilisateur correspondent à l'organisation du programme entre l'entrée et le retour de l'appel système \fBmembarrier\fP(). Tous les threads du système sont visés par cette commande. .TP \fBMEMBARRIER_CMD_GLOBAL_EXPEDITED\fP (depuis Linux 4.16) Mettre une barrière mémoire sur tous les threads en cours de tous les processus qui se sont enregistrés précédemment avec \fBMEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED\fP. .IP Lors du retour de l'appel système, le thread appelant a la garantie que tous les threads en cours sont passés par un état où tous les accès mémoire aux adresses de l'espace utilisateur correspondent à l'organisation du programme entre l'entrée et le retour de l'appel système (les threads non en cours sont dans cet état de facto). Cette garantie n'est apportée qu'aux threads des processus qui se sont précédemment enregistrés avec \fBMEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED\fP. .IP Étant donné que l'enregistrement concerne l'intention de recevoir des barrières, il est possible d'appeler \fBMEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED\fP à partir d’un processus qui n’a pas utilisé \fBMEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED\fP. .IP Les commandes «\ accélérées\ » (expedited) se terminent plus vite que celles non accélérées\ ; elles ne se bloquent jamais, mais elles causent aussi un temps\-système supplémentaire. .TP \fBMEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED\fP (depuis Linux 4.16) Enregistrer l'intention du processus de recevoir des barrières mémoire \fBMEMBARRIER_CMD_GLOBAL_EXPEDITED\fP. .TP \fBMEMBARRIER_CMD_PRIVATE_EXPEDITED\fP (depuis Linux 4.14) Poser une barrière mémoire sur chaque thread en cours appartenant au même processus que le thread appelant. .IP Au retour de l'appel système, le thread appelant a la garantie que tous ses homologues en cours passent par un état où tous les accès mémoire aux adresses de l'espace utilisateur correspondent à l'ordre du programme entre l'entrée et le retour de l'appel système (les threads non en cours sont dans cet état de facto). Cette garantie n'est apportée qu'aux threads du même processus que le thread appelant. .IP Les commandes «\ accélérées\ » (expedited) se terminent plus vite que celles non accélérées\ ; elles ne se bloquent jamais, mais elles causent aussi un temps\-système supplémentaire. .IP Un processus doit enregistrer son intention d'utiliser la commande accélérée privée avant de le faire. .TP \fBMEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED\fP (depuis Linux 4.14) Enregistrer l'intention du processus d'utiliser \fBMEMBARRIER_CMD_PRIVATE_EXPEDITED\fP. .TP \fBMEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE\fP (depuis Linux 4.16) Outre les garanties d'organisation de la mémoire décrites dans \fBMEMBARRIER_CMD_PRIVATE_EXPEDITED\fP, lors du retour de l'appel système, le thread appelant a la garantie que tous ses homologues ont exécuté une instruction de sérialisation du cœur. Cette garantie n'est apportée que pour les threads du même processus que celui appelant. .IP Les commandes «\ accélérées\ » se terminent plus vite que celles non accélérées, elles ne se bloquent jamais, mais demandent aussi un temps\-système supplémentaire. .IP Un processus doit enregistrer son intention d'utiliser la commande accélérée privée de synchronisation de cœur avant de le faire. .TP \fBMEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE\fP (depuis Linux 4.16) Enregistrer l'intention du processus d'utiliser \fBMEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE\fP. .TP \fBMEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ\fP (depuis Linux 5.10) Assurer au thread appelant, pendant le retour de l'appel système, que tous ses homologues en cours ont toutes les sections critiques rseq (restartable sequence) en cours redémarrées si le paramètre \fIflags\fP vaut \fB0\fP\ ; s'il vaut \fBMEMBARRIER_CMD_FLAG_CPU\fP, cette opération n'est effectuée que sur le processeur indiqué par \fIcpu_id\fP. Cette garantie n'est apportée qu'aux threads du même processus que le thread appelant. .IP RSEQ membarrier n'est disponible que sous la forme «\ private expedited\ ». .IP Un processus doit enregistrer son intention d'utiliser la commande accélérée privée rseq avant de le faire. .TP \fBMEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ\fP (depuis Linux 5.10) Enregistrer l'intention du processus d'utiliser \fBMEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ\fP. .TP \fBMEMBARRIER_CMD_SHARED\fP (depuis Linux 4.3) Il s'agit d'un alias pour \fBMEMBARRIER_CMD_GLOBAL\fP pour la rétrocompatibilité de l'entête. .PP Le paramètre \fIflags\fP doit être indiqué en tant que \fB0\fP, sauf si la commande est \fBMEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ\fP, auquel cas \fIflags\fP peut être soit \fB0\fP, soit \fBMEMBARRIER_CMD_FLAG_CPU\fP. .PP Le paramètre \fIcpu_id\fP est ignoré sauf si \fIflags\fP est \fBMEMBARRIER_CMD_FLAG_CPU\fP, auquel cas il doit indiquer le processeur ciblé par cette commande membarrier. .PP Tous les accès mémoire effectués dans l'organisation du programme à partir de chaque thread visé sont garantis d'être organisés par rapport à \fBmembarrier\fP(). .PP Si nous utilisons la sémantique \fIbarrier()\fP pour représenter une barrière du compilateur qui force les accès mémoire à s'opérer dans l'ordre du programme le long des barrières, et \fIsmp_mb()\fP pour représenter les barrières explicites de la mémoire qui forcent toute la mémoire à s'organiser le long de la barrière, nous obtenons le tableau d'organisation suivant pour chaque paire de \fIbarrier()\fP, \fBmembarrier\fP() et \fIsmp_mb()\fP. L'organisation de la paire est détaillée ainsi (O\ : organisée, X\ : non organisée)\ : .PP barrier() smp_mb() membarrier() barrier() X X O smp_mb() X O O membarrier() O O O .SH "VALEUR RENVOYÉE" En cas de succès, l'opération \fBMEMBARRIER_CMD_QUERY\fP renvoie un masque de bits des commandes prises en charge, et les opérations \fBMEMBARRIER_CMD_GLOBAL\fP, \fBMEMBARRIER_CMD_GLOBAL_EXPEDITED\fP, \fBMEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED\fP, \fBMEMBARRIER_CMD_PRIVATE_EXPEDITED\fP, \fBMEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED\fP, \fBMEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE\fP et \fBMEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE\fP renvoient \fB0\fP. En cas d'erreur, \fB\-1\fP est renvoyé et \fIerrno\fP est positionné adéquatement. .PP Pour une commande donnée, quand \fIflags\fP est positionné sur \fB0\fP, cet appel système est garanti de renvoyer toujours la même valeur jusqu'au redémarrage. Les appels suivants ayant les mêmes paramètres conduiront au même résultat. Donc, quand \fIflags\fP est positionné sur \fB0\fP, une gestion des erreurs n'est nécessaire que pour le premier appel à \fBmembarrier\fP(). .SH ERREURS .TP \fBEINVAL\fP \fIcmd\fP n'est pas valable ou \fIflags\fP ne vaut pas zéro ou la commande \fBMEMBARRIER_CMD_GLOBAL\fP est désactivée car le paramètre \fInohz_full\fP du processeur a été positionné ou les commandes \fBMEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE\fP et \fBMEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE\fP ne sont pas implémentées par l'architecture. .TP \fBENOSYS\fP L'appel système \fBmembarrier\fP() n'est pas implémenté par ce noyau. .TP \fBEPERM\fP Le processus actuel n'était pas enregistré avant d'utiliser les commandes accélérées privées. .SH VERSIONS L'appel système \fBmembarrier\fP() a été ajouté dans Linux\ 4.3. .PP Avant Linux 5.10, le prototype de \fBmembarrier\fP() était\ : .PP .in +4n .EX \fBint membarrier(int \fP\fIcmd\fP\fB, int \fP\fIflags\fP\fB);\fP .EE .in .SH CONFORMITÉ .\" .SH SEE ALSO .\" FIXME See if the following syscalls make it into Linux 4.15 or later .\" .BR cpu_opv (2), .\" .BR rseq (2) \fBmembarrier\fP() est spécifique à Linux. .SH NOTES Une instruction de barrière mémoire fait partie du jeu d'instructions des architectures ayant des modèles de mémoire faiblement organisés. Elle organise les accès mémoire avant et après la barrière par rapport à celles correspondantes sur les autres cœurs. Par exemple, une barrière de charge peut organiser les charges avant et après elle par rapport aux stockages conservés dans les barrières de stockage. .PP L'organisation du programme est l'ordre dans lequel les instructions sont ordonnées dans le code d'assembleur du programme. .PP Parmi les exemples où \fBmembarrier\fP() peut être utile, figurent les implémentations des bibliothèques Read\-Copy\-Update et des ramasse\-miettes .PP La glibc ne fournit pas de fonction autour de cet appel système\ ; appelez\-le avec \fBsyscall\fP(2). .SH EXEMPLES Supposons une application multithreadée où «\ fast_path()\ » est exécutée très souvent et où «\ slow_path()\ » l'est rarement, alors le code suivant (x86) peut être transformé en utilisant \fBmembarrier\fP()\ : .PP .in +4n .EX #include static volatile int a, b; static void fast_path(int *read_b) { a = 1; asm volatile ("mfence" : : : "memory"); *read_b = b; } static void slow_path(int *read_a) { b = 1; asm volatile ("mfence" : : : "memory"); *read_a = a; } int main(int argc, char **argv) { int read_a, read_b; /* * De vraies applications appelleraient fast_path() et slow_path() * à partir de différents threads. Appel à partir de main() * pour garder cet exemple court. */ slow_path(&read_a); fast_path(&read_b); /* * read_b == 0 implique que read_a == 1 et * read_a == 0 implique que read_b == 1. */ if (read_b == 0 && read_a == 0) abort(); exit(EXIT_SUCCESS); } .EE .in .PP Le code ci\-dessus transformé pour utiliser \fBmembarrier\fP() donne\ : .PP .in +4n .EX #define _GNU_SOURCE #include #include #include #include #include static volatile int a, b; static int membarrier(int cmd, unsigned int flags, int cpu_id) { return syscall(__NR_membarrier, cmd, flags, cpu_id); } static int init_membarrier(void) { int ret; /* Vérifier que membarrier() est pris en charge. */ ret = membarrier(MEMBARRIER_CMD_QUERY, 0, 0); if (ret < 0) { perror("membarrier"); return \-1; } if (!(ret & MEMBARRIER_CMD_GLOBAL)) { fprintf(stderr, "membarrier ne gère pas MEMBARRIER_CMD_GLOBAL\en"); return \-1; } return 0; } static void fast_path(int *read_b) { a = 1; asm volatile ("" : : : "memory"); *read_b = b; } static void slow_path(int *read_a) { b = 1; membarrier(MEMBARRIER_CMD_GLOBAL, 0, 0); *read_a = a; } int main(int argc, char **argv) { int read_a, read_b; if (init_membarrier()) exit(EXIT_FAILURE); /* * De vraies applications appelleraient fast_path() et slow_path() * à partir de différents threads. Appel à partir de main() * pour garder cet exemple court. */ slow_path(&read_a); fast_path(&read_b); /* * read_b == 0 implique que read_a == 1 et * read_a == 0 implique que read_b == 1. */ if (read_b == 0 && read_a == 0) abort(); exit(EXIT_SUCCESS); } .EE .in .SH COLOPHON Cette page fait partie de la publication\ 5.10 du projet \fIman\-pages\fP Linux. Une description du projet et des instructions pour signaler des anomalies et la dernière version de cette page peuvent être trouvées à l'adresse \%https://www.kernel.org/doc/man\-pages/. .PP .SH TRADUCTION La traduction française de cette page de manuel a été créée par Christophe Blaess , Stéphan Rafin , Thierry Vignaud , François Micaux, Alain Portal , Jean-Philippe Guérard , Jean-Luc Coulon (f5ibh) , Julien Cristau , Thomas Huriaux , Nicolas François , Florentin Duneau , Simon Paillard , Denis Barbier , David Prévot et Jean-Philippe MENGUAL . .PP Cette traduction est une documentation libre ; veuillez vous reporter à la .UR https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License version 3 .UE concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE. .PP Si vous découvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message à .MT debian-l10n-french@lists.debian.org .ME .