Linux模式设计5-位图操作

1850阅读 0评论2014-05-19 wangbaolin719
分类:LINUX

-------------------------------------------
本文系作者原创, 欢迎大家转载!
转载请注明出处:netwalker.blog.chinaunix.net
-------------------------------------------
 
通过位图提供的两种状态可以在非常节约内存的情况下表示开关变量,并且同类这类变量可以紧凑而高效的统一进行处理。有很多内核子系统都需要位图的支持,但是不同的情况又需要不同的位图个数,比如SMP系统上的CPU位图cpumask的位数位NR_CPUS,而内存管理区的位图数为MAX_ZONES_PER_ZONELIST。但是所有的位图都要转换为基本的数据类型,比如int,short等,Linux将定义位图的功能集中到一个名为DECLARE_BITMAP的宏。
  1. include/linux/types.h
  2. #define DECLARE_BITMAP(name,bits) \
  3.     unsigned long name[BITS_TO_LONGS(bits)]

这里可以看到DECLARE_BITMAP的作用是尝试定义一个类型为unsigned long,名字为name的数组。而数组的维度由位图中的位数通过BITS_TO_LONGS计算而得。

  1. include/linux/bitops.h
  2. #define BITS_PER_BYTE        8
  3. #define BITS_TO_LONGS(nr)    DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))

BITS_TO_LONGS通过DIV_ROUND_UP宏完成。DIV_ROUND_UP根据nr参数计算至少需要几个long型才能满足当前位图的需求。不知道为什么Linux不使用char型,这样不是更节约内存吗?显然DECLARE_BITMAP的引入的根本目的并不是用来节约内存,而是方便对长位图的操作,而通常8位位图的定义并不通过它来定义,而是直接定义位掩码,比如对文件权限的定义。

图 4. 基于无符号长整型的位图表示

基于无符号长整型的位图表示


内核定义了一系列的宏和函数来对DECLARE_BITMAP定义的位图进行操作,它们分别位于bitmap.h和bitmap.c中。这些宏和函数的操作思想是一致的。

  1. /arch/arm/include/asm/types.h
  2. #define BITS_PER_LONG 32

  3. include/linux/bitmap.h
  4. static inline void bitmap_zero(unsigned long *dst, int nbits)
  5. {
  6.     if (nbits <= BITS_PER_LONG)
  7.         *dst = 0UL;
  8.     else {
  9.         int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
  10.         memset(dst, 0, len);
  11.     }
  12. }

尽管在特定体系的代码中BITS_PER_LONG被定义为32以增加运算速度,但是它更应该通过sizeof(long) * BITS_PER_BYTE来定义。bitmap_zero用来清空所有的位图。分析它发现,它首先判断是否超过一个long型,如果没有那么直接对它赋值0UL即可。否则就要通过memset对整个数组进行操作。其他函数亦同。一些常用的位图操作函数如下所示:

上一篇:Linux VDSO机制
下一篇:Linux RCU机制详解