Linux代码中很多地方为了对某个资源进行标记使用了BITMAP方式,每个标记位只占用一个bit,如cpumask,它的定义在:
include\linux\bitops.h
#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE)
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(long)) //(nr, 4 * 8 = 32)
#include <uapi/linux/types.h>
#define DECLARE_BITMAP(name,bits) unsigned long name[BITS_TO_LONGS(bits)] // bits个位需要多少个long
typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
//定义一个结构体,成员位一个long数组,其包含的bit数大于NR_CPUS
static inline void cpumask_clear_cpu(int cpu, struct cpumask *dstp)
通过这些宏可以看出,所有的bit都是保存在一个数组中,通过BITS_TO_LONGS计算出数组的大小,随后通过一系列的宏和函数提供bit位的设置,检查和清除操作;如:
- set_bit
- clear_bit
- test_bit
在实际的工作中,可能需要一个数据结构,它可以分配在一个连续范围内不重复的索引,要可以方便的进行分配、释放,快速检查某个索引是否被占用,这里我们可以借用Linux上面这段代码中的方法,定义如下数据结构:
索引池的管理结构:
typedef struct tagINDEX_POOL_S
{
unsigned int count;
unsigned int nr;
unsigned long *bits;
}INDEX_POOL_T;
索引池初始化:
int index_pool_init(int count, INDEX_POOL_T* pstIndexPoolCtr)
{
... ...
pstIndexPoolCtr->nr = (count + sizeof(unsigned long) * 8 - 1) / (sizeof(unsigned long) * 8);
pstIndexPoolCtr->bits = (unsigned long *)malloc(nr * sizeof(unsigned long));
pstIndexPoolCtr->count = count;
return 0;
}
通常索引池需要提供以下操作,分配、释放和检查操作:
// 索引的分配
int indx_pool_alloc_index(unsigned int *index, INDEX_POOL_T* pstIndexPoolCtr)
{
int i = 0;
//有效性检查
......
for ( i = 0; i < pstIndexPoolCtr->nr; ++i)
{
if (pstIndexPoolCtr->bits[i] != 0xffffffff)
{
break;
}
}
if (i == < pstIndexPoolCtr->nr)
{
return -1;
}
for (int b = 0; b < sizeof(unsigned long) * 8; ++b)
{
if ( (1 << b) & pstIndexPoolCtr->bits[i] == 0)
{
*index = i * sizeof(unsigned long) * 8 + b;
return 0;
}
}
return -1;
}
// 索引的释放
int indx_pool_free_index(unsigned int index, INDEX_POOL_T* pstIndexPoolCtr)
{
......
loc = index / (sizeof(unsigned long) * 8);
bits = index % (sizeof(unsigned long) * 8);
......
pstIndexPoolCtr->bits[loc] &= ~(1 << bits);
......
}
// 索引的检查
int indx_pool_test_index(unsigned int index, INDEX_POOL_T* pstIndexPoolCtr)
{
......
loc = index / (sizeof(unsigned long) * 8);
bits = index % (sizeof(unsigned long) * 8);
......
return (pstIndexPoolCtr->bits[loc] & (1 << bits))
}
还可以这个索引池做进一步优化,如为了提高分配速度,可以加一个标记,标记最近释放的或者未分配的bit索引,这样就不需从pstIndexPoolCtr->bits的第一个开始遍历;还有如:要求索引池分配的索引不是从0开始,可以在控制字段中加一个字段表示偏移,如:
typedef struct tagINDEX_POOL_S
{
unsigned int count;
unsigned int nr;
unsigned int offset; // 索引分配便宜,如从100开始分配,这个值在初始化是设置位100
unsigned int last_index; //初始值位0,如果bits的前n个ulong都为全f,则该值设置位n+1,下一次遍历从n+1开始
unsigned long *bits;
}INDEX_POOL_T;
上面分配操作函数页需要做相应的修改,对入参index做相应的修正。