Reputation: 3369
I'm currently reading through Robert Love's Linux Kernel Development, Third Edition and I encountered an odd statement after a section explaining the set_bit()
, clear_bit()
atomic functions and their non-atomic siblings, __set_bit()
and __clear_bit()
:
Unlike the atomic integer operations, code typically has no choice whether to use the bitwise operations—they are the only portable way to set a specific bit.
-p. 183 (emphasis my own)
I understand that these operations can be implemented in a single platform-specific assembly instruction, which is why these inline functions exist. But I'm curious as to why the author said that these are the only portable ways to do these things. For instance, I believe I could non-atomically set bit nr
in unsigned long x
by doing this in plain C:
x |= 1UL << nr;
Similarly I can non-atomically clear bit nr
in unsigned long x
by doing this:
x &= ~(1UL << nr);
Of course, depending on the sophistication of the compiler, these may compile to several instructions, and so they may not be as nice as the __set_bit()
and __clear_bit()
functions.
Am I missing something here? Was this phrase just a slightly lazy simplification, or is there something unportable about the ways I've presented above for setting and clearing bits?
Edit: It appears that, although GCC is pretty sophisticated, it still performs the bit shifts instead of using a single instruction like the __set_bit()
function does, even on -O3
(version 6.2.1). As an example:
stephen at greed in ~/code
$ gcc -g -c set.c -O3
stephen at greed in ~/code
$ objdump -d -M intel -S set.o
set.o: file format elf64-x86-64
Disassembly of section .text.startup:
0000000000000000 <main>:
#include<stdio.h>
int main(int argc, char *argv)
{
unsigned long x = 0;
x |= (1UL << argc);
0: 89 f9 mov ecx,edi
2: be 01 00 00 00 mov esi,0x1
7: 48 83 ec 08 sub rsp,0x8
b: 48 d3 e6 shl rsi,cl
e: bf 00 00 00 00 mov edi,0x0
13: 31 c0 xor eax,eax
15: e8 00 00 00 00 call 1a <main+0x1a>
{
1a: 31 c0 xor eax,eax
x |= (1UL << argc);
1c: 48 83 c4 08 add rsp,0x8
printf("x=%x\n", x);
20: c3 ret
Upvotes: 2
Views: 2186
Reputation: 180172
In the context of atomic integer operations, "bitwise operations" also means the atomic ones.
There is nothing special about the non-atomic bitwise operations (except that they support numbers larger than BITS_PER_LONG), so the generic implementation is always correct, and architecture-specific implementations would be needed only to optimize performance.
Upvotes: 1