Je lisais un code du noyau, et à un endroit, j'ai vu une expression à l'intérieur d'une if
déclaration comme
if (value == (SPINLOCK_SHARED | 1) - 1) {
............
}
où SPINLOCK_SHARED = 0x80000000
est une constante prédéfinie.
Je me demande pourquoi avons-nous besoin (SPINLOCK_SHARED | 1) - 1
- à des fins de conversion de type? le résultat de l'expression serait 80000000-- identique à 0x80000000, n'est-ce pas? pourtant, pourquoi ORing 1 et Soustraire 1 sont importants?
J'ai le sentiment que je manque pour obtenir quelque chose ..
c
bit-manipulation
RaGa__M
la source
la source
if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED|0, 1))
.Réponses:
Cela a été fait de cette façon pour plus de clarté, c'est tout. C'est parce que atomic_fetchadd_int () (par exemple sys / spinlock2.h) renvoie la valeur PRIOR à l'addition / soustraction, et cette valeur est passée à _spin_lock_contested ()
Notez que le compilateur C pré-calcule complètement toutes les expressions constantes. En fait, le compilateur peut même optimiser le code en ligne basé sur des conditions qui utilisent des arguments de procédure transmis lorsque les procédures reçoivent des constantes dans ces arguments. C'est pourquoi l'inline lockmgr () dans sys / lock.h a une instruction case .... car cette instruction case entière sera optimisée et transformée en un appel direct à la fonction appropriée.
De plus, dans toutes ces fonctions de verrouillage, les frais généraux des opérations atomiques éclipsent tous les autres calculs de deux ou trois ordres de grandeur.
-Mat
la source
Le code se trouve dans
_spin_lock_contested
, qui est appelé à partir du_spin_lock_quick
moment où quelqu'un d'autre tente d'obtenir le verrou:S'il n'y a pas de concours, alors
count
(la valeur précédente) devrait l'être0
, mais ce n'est pas le cas. Cettecount
valeur est transmise en tant que paramètre à en_spin_lock_contested
tant quevalue
paramètre. Cecivalue
est ensuite vérifié avecif
l'OP:En gardant à l'esprit que
value
c'est la valeur précédente despin->counta
, et que celle-ci a déjà été incrémentée de 1, nous nous attendonsspin->counta
à égalervalue + 1
(sauf si quelque chose a changé entre-temps).Donc, vérifier si
spin->counta == SPINLOCK_SHARED | 1
(la condition préalable deatomic_cmpset_int
) correspond à vérifier sivalue + 1 == SPINLOCK_SHARED | 1
, qui peut être réécrit commevalue == (SPINLOCK_SHARED | 1) - 1
(encore une fois, si rien n'a changé entre-temps).Bien qu'il
value == (SPINLOCK_SHARED | 1) - 1
puisse être réécrit telvalue == SPINLOCK_SHARED
quel, il reste tel quel, pour clarifier l'intention de la comparaison (c'est-à-dire comparer la valeur précédente incrémentée avec la valeur de test).Ou iow. la réponse semble être: pour la clarté et la cohérence du code.
la source
(SPINLOCK_SHARED | 1) - 1
partie est compréhensible etvalue == SPINLOCK_SHARED
c'est ma pensée aussi, car nous vérifions si la valeur précédente a un indicateur partagé.si oui, transformez le verrou en exclusif .........if
vérification est de vérifier sivalue + 1
(ce qui devrait être la même valeur quespin->counta
si rien n'a changé entre-temps) est égalSPINLOCK_SHARED | 1
. Si vous écrivez leif
chèque en tant quevalue == SPINLOCK_SHARED
, cette intention n'est pas claire et il serait beaucoup plus difficile de comprendre ce que signifie le chèque. Garder les deuxSPINLOCK_SHARED | 1
et- 1
explicitement dans leif
chèque est intentionnel.if (value + 1 == (SPINLOCK_SHARED | 1) )
?value & SPINLOCK_SHARED
plus lisible.Je pense que l'objectif est probablement d'ignorer le bit significatif le plus bas:
aurait peut-être été plus clair d'utiliser une expression de masque de bits?
la source
L'effet de
est de s'assurer que le bit de poids faible du résultat est effacé avant la comparaison avec
value
. Je suis d'accord qu'il semble plutôt inutile, mais apparemment le bit de poids faible a une utilisation ou une signification particulière qui n'est pas apparente dans ce code, et je pense que nous devons supposer que les développeurs avaient une bonne raison de le faire. Une question intéressante serait - ce même modèle (| 1) -1
) est-il utilisé dans toute la base de code que vous regardez?la source
C'est une façon obscure d'écrire un petit masque. Version Lisible:
value == (SPINLOCK_SHARED & ~1u)
.la source
SPINLOCK_SHARED
s'agit d'une constante connue. S'ils testent simplementSPINLOCK_SHARED
leur présence dans un masque, pourquoi pasif (value & SPINLOCK_SHARED)
?value == (SPINLOCK_SHARED & ~1u)
n'est pas équivalent carvalue == (SPINLOCK_SHARED | 1) - 1
fonctionne même si le type deSPINLOCK_SHARED
est plus large queunsigned
.& ~1u
soit plus clair. J'ai pensé à suggérer& 0xFFFFFFFE
dans ma réponse mais j'ai réalisé que ce n'était pas vraiment clair non plus. Votre suggestion a cependant l'avantage d'être concise. :-)0x80000000
. OP a déclaré qu'il est défini avec#define SPINLOCK_SHARED 0x80000000
, mais cela pourrait être à l'intérieur#if…#endif
et une définition différente est utilisée dans d'autres circonstances, ou l'auteur de ce code aurait pu le faire fonctionner même si la définition est modifiée ou le code est compilé avec d'autres en-têtes qui le définir différemment. Quoi qu'il en soit, les deux morceaux de code ne sont pas équivalents en eux-mêmes.La plupart comme cela est fait pour gérer plusieurs cas supplémentaires. Par exemple, dans ce cas, nous disons que
SPINLOCK_SHARED
ne peut pas être 1:la source
SPINLOCK_SHARED
une constante définie et à la variable testéevalue
. Dans ce cas, le mystère demeure.| 1) - 1
partie, alors que SPINLOCK_SHARED tient0x80000000
quel serait l'impact de| 1) - 1
?SPINLOCK_SHARED
changer à l'avenir. Mais ce n'est pas du tout clair. J'écrirais aux développeurs du noyau et demanderais qu'un commentaire de clarification soit fait ou que l'expression soit réorganisée pour qu'elle se documente d'elle-même.