brenns10
brenns10

Reputation: 3369

Platform independent way to set or clear a bit in Linux Kernel

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

Answers (1)

CL.
CL.

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

Related Questions