Estaba leyendo un código del núcleo, y en un lugar he visto una expresión dentro de una if
declaración como
if (value == (SPINLOCK_SHARED | 1) - 1) {
............
}
donde SPINLOCK_SHARED = 0x80000000
es una constante predefinida
Me pregunto por qué necesitamos (SPINLOCK_SHARED | 1) - 1
, para fines de conversión de tipos. el resultado de la expresión sería 80000000-- igual que 0x80000000, ¿no es así? sin embargo, ¿por qué importa ORing 1 y Resta 1?
Tengo la sensación de que me falta conseguir algo ...
c
bit-manipulation
RaGa__M
fuente
fuente
if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED|0, 1))
.Respuestas:
Simplemente se hizo así para mayor claridad, eso es todo. Es porque atomic_fetchadd_int () (por ejemplo, en sys / spinlock2.h) devuelve el valor ANTES de la suma / resta, y ese valor se pasa a _spin_lock_contested ()
Tenga en cuenta que el compilador de C calcula previamente todas las expresiones constantes. De hecho, el compilador puede incluso optimizar el código en línea basado en condicionales que usan argumentos de procedimiento pasados cuando los procedimientos son constantes pasados en esos argumentos. Es por eso que lockmgr () en línea en sys / lock.h tiene una declaración de caso ... porque toda la declaración de caso se optimizará y se convertirá en una llamada directa a la función apropiada.
Además, en todas estas funciones de bloqueo, la sobrecarga de las operaciones atómicas eclipsa todos los demás cálculos en dos o tres órdenes de magnitud.
-Mate
fuente
El código se encuentra en
_spin_lock_contested
, que se llama_spin_lock_quick
cuando alguien más intenta obtener el bloqueo:Si no hay concurso, entonces
count
(el valor anterior) debería serlo0
, pero no lo es. Estecount
valor se pasa como parámetro a_spin_lock_contested
comovalue
parámetro. Estovalue
luego se verifica conif
el OP:Teniendo en cuenta que ese
value
es el valor anterior despin->counta
, y este último ya se ha incrementado en 1, esperamosspin->counta
que sea igualvalue + 1
(a menos que algo haya cambiado mientras tanto).Por lo tanto, verificar si
spin->counta == SPINLOCK_SHARED | 1
(la condición previa deatomic_cmpset_int
) corresponde a verificar sivalue + 1 == SPINLOCK_SHARED | 1
, que puede reescribirse comovalue == (SPINLOCK_SHARED | 1) - 1
(nuevamente, si nada ha cambiado mientras tanto).Si bien
value == (SPINLOCK_SHARED | 1) - 1
podría reescribirse comovalue == SPINLOCK_SHARED
, se deja como está, para aclarar la intención de la comparación (es decir, comparar el valor anterior incrementado con el valor de la prueba).O iow. la respuesta parece ser: por claridad y consistencia del código.
fuente
(SPINLOCK_SHARED | 1) - 1
parte, es comprensible y tambiénvalue == SPINLOCK_SHARED
lo creo, porque estamos verificando si el valor anterior tiene un conjunto de marcas compartidas. Si es así, convierta el bloqueo en exclusivo .........if
verificación es verificar sivalue + 1
(que debería ser el mismo valor quespin->counta
si nada ha cambiado mientras tanto) es igualSPINLOCK_SHARED | 1
. Si escribe elif
cheque comovalue == SPINLOCK_SHARED
, esta intención no está clara, y sería mucho más difícil averiguar qué significa el cheque. Mantener ambosSPINLOCK_SHARED | 1
y- 1
explícitamente en elif
cheque es intencional.if (value + 1 == (SPINLOCK_SHARED | 1) )
?value & SPINLOCK_SHARED
que es más legible.Creo que el objetivo es probablemente ignorar el bit significativo más bajo:
habría sido quizás más claro usar una expresión de máscara de bits?
fuente
El efecto de
es garantizar que el bit de orden inferior del resultado se borre antes de la comparación con
value
. Estoy de acuerdo en que parece bastante inútil, pero aparentemente el bit de bajo orden tiene un uso o significado particular que no es aparente en este código, y creo que debemos suponer que los desarrolladores tenían una buena razón para hacerlo. Una pregunta interesante sería: ¿se| 1) -1
usa este mismo patrón ( ) en toda la base de código que está viendo?fuente
Es una forma ofuscada de escribir una máscara de bits. Versión legible:
value == (SPINLOCK_SHARED & ~1u)
.fuente
SPINLOCK_SHARED
es una constante conocida. Si simplemente están probandoSPINLOCK_SHARED
estar presentes en una máscara, ¿por qué noif (value & SPINLOCK_SHARED)
?value == (SPINLOCK_SHARED & ~1u)
no es equivalente porquevalue == (SPINLOCK_SHARED | 1) - 1
funciona incluso si el tipo deSPINLOCK_SHARED
es más ancho queunsigned
.& ~1u
sea más claro. Pensé en sugerir& 0xFFFFFFFE
en mi respuesta, pero me di cuenta de que eso tampoco está realmente claro. Sin embargo, su sugerencia tiene la ventaja de la brevedad. :-)0x80000000
. OP ha declarado que está definido con#define SPINLOCK_SHARED 0x80000000
, pero eso podría estar dentro#if…#endif
y se usa una definición diferente en otras circunstancias, o el autor de este código podría haber pensado que funcionara incluso si la definición se edita o el código se compila con otros encabezados que definirlo de manera diferente. En cualquier caso, las dos piezas de código no son equivalentes por sí mismas.La mayoría de esto se hace para manejar varios casos adicionales. Por ejemplo, en este caso, decimos que
SPINLOCK_SHARED
no puede ser 1:fuente
SPINLOCK_SHARED
es una constante definida y la variable probada lo esvalue
. En este caso el misterio permanece.| 1) - 1
parte aunque, cuando SPINLOCK_SHARED sostuvo0x80000000
¿cuál sería el impacto| 1) - 1
?SPINLOCK_SHARED
ser cambiados en el futuro. Pero no está nada claro. Escribiría en los desarrolladores del núcleo y pediría que se hiciera un comentario de aclaración o que la expresión se reorganice para que se documente.