Eu estava lendo um código do kernel e, em um lugar, vi uma expressão dentro de uma if
instrução como
if (value == (SPINLOCK_SHARED | 1) - 1) {
............
}
onde SPINLOCK_SHARED = 0x80000000
é uma constante predefinida.
Gostaria de saber por que precisamos (SPINLOCK_SHARED | 1) - 1
- para fins de conversão de tipo? o resultado da expressão seria 80000000-- o mesmo que 0x80000000, não é? ainda, por que ORing 1 e Subtração 1 são importantes?
Tenho a sensação de que estou sentindo falta de algo ..
c
bit-manipulation
RaGa__M
fonte
fonte
if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED|0, 1))
.Respostas:
Foi assim feito para maior clareza, só isso. Isso ocorre porque atomic_fetchadd_int () (por exemplo, sys / spinlock2.h) retorna o valor ANTES da adição / subtração, e esse valor é passado para _spin_lock_contested ()
Observe que o compilador C pré-calcula completamente todas as expressões constantes. De fato, o compilador pode até otimizar o código embutido com base em condicionais que usam argumentos de procedimentos passados quando os procedimentos são passados constantes nesses argumentos. É por isso que o lockmgr () inline em sys / lock.h possui uma instrução de caso .... porque toda a instrução de caso será otimizada e evoluirá para uma chamada direta para a função apropriada.
Além disso, em todas essas funções de bloqueio, a sobrecarga das operações atômicas diminui todos os outros cálculos em duas ou três ordens de magnitude.
-Matt
fonte
O código é encontrado em
_spin_lock_contested
, que é chamado_spin_lock_quick
quando outra pessoa está tentando obter o bloqueio:Se não houver concurso,
count
o valor anterior deve ser0
, mas não é. Estecount
valor é passado como parâmetro para_spin_lock_contested
como ovalue
parâmetro. Issovalue
é verificado com oif
do OP:Tendo em mente que
value
é o valor anterior despin->counta
, e o último já foi incrementado em 1, esperamosspin->counta
ser iguaisvalue + 1
(a menos que algo tenha mudado nesse meio tempo).Portanto, verificar se
spin->counta == SPINLOCK_SHARED | 1
(a pré-condição deatomic_cmpset_int
) corresponde a verificar sevalue + 1 == SPINLOCK_SHARED | 1
, que pode ser reescrito comovalue == (SPINLOCK_SHARED | 1) - 1
(novamente, se nada mudou nesse meio tempo).Embora
value == (SPINLOCK_SHARED | 1) - 1
possa ser reescrito comovalue == SPINLOCK_SHARED
, é deixado como está para esclarecer a intenção da comparação (ou seja, comparar o valor anterior incrementado com o valor do teste).Ou uau. a resposta parece ser: para maior clareza e consistência do código.
fonte
(SPINLOCK_SHARED | 1) - 1
parte é compreensível evalue == SPINLOCK_SHARED
é o meu pensamento também, porque estamos verificando-bandeira compartilhada se o valor anterior set.if sim, ativar o bloqueio em exclusivo .........if
verificação é verificar sevalue + 1
(que deve ter o mesmo valor comospin->counta
se nada tivesse mudado nesse meio tempo) é igualSPINLOCK_SHARED | 1
. Se você escrever aif
verificação comovalue == SPINLOCK_SHARED
, essa intenção não é clara e seria muito mais difícil descobrir o que a verificação significa. Manter ambosSPINLOCK_SHARED | 1
e- 1
explicitamente sobif
controle é intencional.if (value + 1 == (SPINLOCK_SHARED | 1) )
?value & SPINLOCK_SHARED
que é mais legível.Eu acho que o objetivo é provavelmente ignorar o bit mais baixo e significativo:
teria sido talvez mais claro usar uma expressão de máscara de bits?
fonte
O efeito de
é garantir que o bit de baixa ordem do resultado seja limpo antes da comparação com
value
. Concordo que parece inútil, mas aparentemente o bit de ordem inferior tem um uso ou significado específico que não é aparente neste código, e acho que devemos assumir que os desenvolvedores tiveram uma boa razão para fazer isso. Uma pergunta interessante seria - esse mesmo padrão (| 1) -1
) é usado em toda a base de código que você está vendo?fonte
É uma maneira ofuscada de escrever um pouco de máscara. Versão legível:
value == (SPINLOCK_SHARED & ~1u)
.fonte
SPINLOCK_SHARED
for uma constante conhecida. Se eles estão simplesmente testando aSPINLOCK_SHARED
presença de uma máscara, por que nãoif (value & SPINLOCK_SHARED)
?value == (SPINLOCK_SHARED & ~1u)
não é equivalente porquevalue == (SPINLOCK_SHARED | 1) - 1
funciona mesmo se o tipo deSPINLOCK_SHARED
for maior queunsigned
.& ~1u
é mais claro. Pensei em sugerir& 0xFFFFFFFE
minha resposta, mas percebi que isso também não é muito claro. Sua sugestão tem a vantagem da brevidade, no entanto. :-)0x80000000
. O OP declarou que está definido com#define SPINLOCK_SHARED 0x80000000
, mas que poderia estar dentro#if…#endif
e uma definição diferente é usada em outras circunstâncias, ou o autor deste código poderia ter pretendido que funcionasse mesmo se a definição fosse editada ou o código compilado com outros cabeçalhos que defina-o de maneira diferente. Independentemente disso, os dois pedaços de código não são equivalentes por si mesmos.A maioria é feita para lidar com vários casos adicionais. Por exemplo, neste caso, dizemos que
SPINLOCK_SHARED
não pode ser 1:fonte
SPINLOCK_SHARED
é uma constante definida e a variável testadavalue
. Nesse caso, o mistério permanece.| 1) - 1
parte, quando SPINLOCK_SHARED segurando0x80000000
qual seria o impacto| 1) - 1
?SPINLOCK_SHARED
mudanças no futuro. Mas não está nada claro. Eu escrevia nos desenvolvedores do kernel e solicitava um comentário de esclarecimento ou a expressão a ser reorganizada para que ela se autodocumentasse.