uint32_t expected = 0;
uint32_t desired = 1;
uint32_t old;
asm volatile("lock cmpxchgl %2, %1"
: "=a"(old), "+m"(lock->lock)
: "r"(desired), "0"(expected)
: "memory", "cc");
if (old == 0) { return; }
cmpxchg uses EAX/RAX as the expected value input and returns the previous value in EAX. The constraints here are non-standard-looking: old is output in =a, and expected is tied to operand 0 via "0"(expected).
This might work, but it’s brittle. If the compiler decides to treat old purely as output and doesn’t initialise EAX from expected correctly under some optimisation, you get incorrect behaviour. In kernel code, “brittle inline asm constraints” is a common source of heisenbugs and lockups.
Even if it’s correct today, it’s a miscompile risk.
cmpxchg uses EAX/RAX as the expected value input and returns the previous value in EAX. The constraints here are non-standard-looking: old is output in =a, and expected is tied to operand 0 via "0"(expected).
This might work, but it’s brittle. If the compiler decides to treat old purely as output and doesn’t initialise EAX from expected correctly under some optimisation, you get incorrect behaviour. In kernel code, “brittle inline asm constraints” is a common source of heisenbugs and lockups.
Even if it’s correct today, it’s a miscompile risk.