Le code se trouve dans _spin_lock_contested
qui est appelé à partir de _spin_lock_quick
lorsque quelqu'un d'autre tente d'obtenir la serrure :
count = atomic_fetchadd_int(&spin->counta, 1);
if (__predict_false(count != 0)) {
_spin_lock_contested(spin, ident, count);
}
S'il n'y a pas de concours, alors count
(la valeur précédente) devrait être 0
mais ce n'est pas le cas. Ce n'est pas le cas. count
est transmise en tant que paramètre à _spin_lock_contested
en tant que value
paramètre. Ce paramètre value
est ensuite vérifié avec le if
de l'OP :
/*
* WARNING! Caller has already incremented the lock. We must
* increment the count value (from the inline's fetch-add)
* to match.
*
* Handle the degenerate case where the spinlock is flagged SHARED
* with only our reference. We can convert it to EXCLUSIVE.
*/
if (value == (SPINLOCK_SHARED | 1) - 1) {
if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED | 1, 1))
return;
}
En gardant à l'esprit que value
est la valeur précédente de spin->counta
et que ce dernier a déjà été incrémenté de 1, on s'attend à ce que spin->counta
à égalité value + 1
(à moins que quelque chose n'ait changé entre-temps).
Il s'agit donc de vérifier si spin->counta == SPINLOCK_SHARED | 1
(la condition préalable de la atomic_cmpset_int
) correspond à vérifier si value + 1 == SPINLOCK_SHARED | 1
qui peut être réécrite comme suit value == (SPINLOCK_SHARED | 1) - 1
(encore une fois, si rien n'a changé entre-temps).
Tandis que value == (SPINLOCK_SHARED | 1) - 1
pourrait être réécrite comme suit value == SPINLOCK_SHARED
Il est donc laissé tel quel, afin de clarifier l'intention de la comparaison (c'est-à-dire comparer la valeur précédente incrémentée avec la valeur test).
La réponse semble être : pour la clarté et la cohérence du code.
0 votes
Il y a quelque chose qui n'est pas clair pour moi : est-ce que
SPINLOCK_SHARED
une variable ou une constante définie par #define ?3 votes
define SPINLOCK_SHARED 0x80000000
1 votes
Je pense qu'il n'y a pas de raison. Il s'agit peut-être d'un problème de copier-coller. Pourriez-vous ajouter où vous avez trouvé cela exactement (quelle version de quel noyau, quel fichier, etc.).
2 votes
Toma, github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/kern/
0 votes
Où se trouve
SPINLOCK_SHARED
défini ? Se trouve-t-il dans un code conditionnel, de sorte qu'il puisse être défini par un code différent si des options de compilation différentes sont utilisées ?0 votes
github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/sys/
0 votes
En s'engager ne l'explique pas du tout.
2 votes
Le même fichier de code source contient également
if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED|0, 1))
.0 votes
J'ai copié le git et j'ai cherché
grep '|[[:space:]]*1[[:space:]]*)[[:space:]]*-[[:space:]]*1' -r .
(et similaires). Il s'agit d'une seule instance de|1)-1
dans le code.2 votes
Dans ce cas, je pense qu'il faut demander à l'auteur pourquoi il a été modifié.
1 votes
Le code source contient plusieurs instances de
SPINLOCK_SHARED|0
ySPINLOCK_SHARED|1
ce qui suggère que l'auteur pense au "compteur" du spinlock comme un bit indiquant partagé/exclusif et d'autres bits contenant un décompte (dans lequel 0 et 1 sont des décomptes notables à des fins diverses).1 votes
Sur les autres plates-formes, le bit 0 est défini pour les constantes. La seule hypothèse pour ne pas utiliser SPINLOCK_SHARED & -2 pourrait être la comparaison signé/non signé sur certains processeurs, spinlock | 1 est vérifié à certains endroits.
0 votes
IIRC Le dépassement de capacité des entiers n'est pas défini en C donc assigner un 0x80000000 à un int me semble être un problème.