La Compréhension Du Noyau Linux Tampon Circulaire
Il y a un article à: http://lwn.net/Articles/378262/ qui décrit les noyaux Linux tampon circulaire de mise en œuvre. J'ai quelques questions:
Ici est le "producteur":
spin_lock(&producer_lock);
unsigned long head = buffer->head;
unsigned long tail = ACCESS_ONCE(buffer->tail);
if (CIRC_SPACE(head, tail, buffer->size) >= 1) {
/* insert one item into the buffer */
struct item *item = buffer[head];
produce_item(item);
smp_wmb(); /* commit the item before incrementing the head */
buffer->head = (head + 1) & (buffer->size - 1);
/* wake_up() will make sure that the head is committed before
* waking anyone up */
wake_up(consumer);
}
spin_unlock(&producer_lock);
Questions:
- Étant donné que ce code traite explicitement de la mémoire de la commande et de l'atomicité quel est le point de la spin_lock()?
- Pour l'instant, ma compréhension est que ACCESS_ONCE s'arrête compilateur réorganisation, vrai?
- Ne produce_item(item), il suffit de problème de toutes les écritures associées à l'élément?
- Je crois smp_wmb() garantit que toutes les écritures dans produce_item(item) complète AVANT de la "publication" d'écriture qui la suit. vrai?
- Le commentaire sur la page où j'ai eu ce code semble impliquer qu'un smp_wmb()
normalement nécessaire après la mise à jour la tête de l'indice, mais wake_up(de consommation) est-ce que, donc, il n'est pas nécessaire. Est-ce vrai? Si oui, pourquoi?
Ici est le "consommateur":
spin_lock(&consumer_lock);
unsigned long head = ACCESS_ONCE(buffer->head);
unsigned long tail = buffer->tail;
if (CIRC_CNT(head, tail, buffer->size) >= 1) {
/* read index before reading contents at that index */
smp_read_barrier_depends();
/* extract one item from the buffer */
struct item *item = buffer[tail];
consume_item(item);
smp_mb(); /* finish reading descriptor before incrementing tail */
buffer->tail = (tail + 1) & (buffer->size - 1);
}
spin_unlock(&consumer_lock);
Questions spécifiques à la "consommateurs":
- Ce n'smp_read_barrier_depends ()? À partir de quelques commentaires dans un forum, il semble que vous pourriez avoir émis un smp_rmb() ici, mais sur certaines architectures, c'est inutile (x86) et trop cher, donc smp_read_barrier_depends() a été créé pour ce faire éventuellement... cela dit, je ne comprends vraiment pas pourquoi smp_rmb() est toujours nécessaire!
- Est le smp_mb() afin de garantir que toutes les lectures avant de terminer avant de l'écrire après?
OriginalL'auteur dicroce | 2013-01-17
Vous devez vous connecter pour publier un commentaire.
Pour le producteur:
spin_lock()
ici est d'éviter que deux producteurs de la tentative de modifier la file d'attente en même temps.ACCESS_ONCE
empêche de réorganisation, il empêche également le compilateur à partir de rechargement de la valeur plus tard. (Il y a un article surACCESS_ONCE
sur LWN qui s'étend sur plus en profondeur)head
valeur.Consommateur:
smp_read_barrier_depends()
est une dépendance de données de la barrière, qui est une forme plus faible de lecture de la barrière (voir Deux). L'effet dans ce cas est de s'assurer quebuffer->tail
est lu avant de l'utiliser comme un tableau d'index dansbuffer[tail]
.smp_mb()
voici une barrière de mémoire, en assurant toutes les lectures et écritures sont commis par ce point.Autres références:
(Note: je ne suis pas entièrement sûr de mes réponses à 5 dans le producteur et 1 pour le consommateur, mais je crois qu'ils sont juste un rapprochement des faits. Je recommande fortement la lecture de la page de documentation sur les barrières de la mémoire, car il est plus complet que tout ce que je pourrais écrire ici.)
OriginalL'auteur Hasturkun