Linux C ID分配

参考文章Linux进程PID分配策略 PID位图算法

作者详细分析了PID位图算法,请先阅读原文。


本文修正了两处BUG并进行了功能扩展。

BUGS
1.耗尽PID -> 释放PID X(例如X = 15) -> 申请PID(申请到X) -> 释放PID Y(例如Y = 10) -> 申请PID(申请不到Y)
2.unsigned long *p = ((unsigned long *) addr) + (offset >> (sizeof(unsigned long) + 1)); // 仅在sizeof(unsigned long)等于4时成立
功能扩展

添加了id binding parameter

C代码如下

/*
 * xid.h
 *
 *  Created on: 2013-1-4
 *      Author: edgar
 */

#ifndef XID_H_
#define XID_H_

#include "xdeclare.h"

EXTERN_C_OPENING

/* page size = 2^12 = 4096 = 4K */
#define PAGE_SHIFT                                  12
#define PAGE_SIZE                  (1UL << PAGE_SHIFT)
/* bits per byte = 8 */
#define BITS_PER_BYTE                                8
/* bits per page = 2^15 = 32768 = 32K */
#define BITS_PER_PAGE      (PAGE_SIZE * BITS_PER_BYTE)
/* bits per page mask = 7fff = 0111 1111 1111 1111 */
#define BITS_PER_PAGE_MASK         (BITS_PER_PAGE - 1)
/* invalid id = -1 */
#define ID_INVALID                                  -1
/* max id = 2^15 = 32768 */
#define ID_MAX                           BITS_PER_PAGE
/* is id valid */
#define ID_IS_VALID(ID)   ((ID) >= 0 && (ID) < ID_MAX)
/* is with binding */
#define WITH_BINDING(PRODUCER) \
	(NULL != (PRODUCER)->args)
#define WITH_ARG_AUTO_FREE(PRODUCER) \
	(NULL != (PRODUCER)->arg_auto_free_func)

typedef int (*arg_auto_free)(void *);

struct _idproducer {
	int last_id; /*                      last allocate id */
	unsigned int nfree; /*               number of remainder id */
	unsigned int nshift; /*              right shift number of offset */
	unsigned int ncolumn; /*             number of columns */
	char page[PAGE_SIZE]; /*             see as a table */
	void **args; /*                      id binding */
	arg_auto_free arg_auto_free_func;
};
typedef struct _idproducer * idproducer;

/* If arg1 is TRUE, set arg2 NULL or custom arg_auto_free function.
 * If arg1 is FALSE, set arg2 NULL. */
extern idproducer idproducer_new(int, arg_auto_free);
extern int idproducer_del(idproducer);
/* If id producer is created without binding, set arg2 NULL.
 * If with binding, set arg2 NULL or custom argument. */
extern int idproducer_alloc(idproducer, void *);
/* If id producer is created without binding, set arg3 NULL.
 * If with binding and
 * 1. (arg3 == NULL && arg_auto_free_func == NULL) is true,
 * do nothing with binding(may cause memory leaks).
 * 2. (arg3 == NULL && arg_auto_free_func != NULL) is true,
 * auto free binding.
 * 3. (arg3 != NULL) is true, set *arg3 = binding rather
 * than free it.
 *
 * Note: id must have been returned by an earlier call to idproducer_alloc */
extern int idproducer_free(idproducer, int, void **);

EXTERN_C_CLOSING

#endif /* XID_H_ */
/*
 * xid.c
 *
 *  Created on: 2013-1-4
 *      Author: edgar
 */

#include "xmemory.h"
#include "xlog.h"
#include "xid.h"

#define Row(Offset, Producer) \
	(((unsigned long *) Producer->page) + (Offset >> Producer->nshift))
#define Col(Offset, Producer) \
	(1UL << (Offset & (Producer->ncolumn - 1)))

/* Only find next zero bit between offset and BITS_PER_PAGE, and
 * return BITS_PER_PAGE if no zero bit. */
static int find_next_zero_bit(int offset, idproducer producer) {
	unsigned long *row;
	unsigned long col;

	for (; offset < BITS_PER_PAGE; ++offset) {
		row = Row(offset, producer);
		col = Col(offset, producer);
		if (~(*row) & col)
			break;
	}
	return offset;
}

/* On success, return 0. */
static int test_and_set_bit(int offset, idproducer producer) {
	unsigned long *row = Row(offset, producer);
	unsigned long col = Col(offset, producer);
	unsigned long old = *row;
	*row = old | col;
	return (old & col) != 0;
}

/* On success, return 0. */
static int test_and_clr_bit(int offset, idproducer producer) {
	unsigned long *row = Row(offset, producer);
	unsigned long col = Col(offset, producer);
	unsigned long old = *row;
	*row = old & ~col;
	return (old & col) == 0;
}

idproducer idproducer_new(int binding, arg_auto_free arg_auto_free_func) {
	idproducer producer = (idproducer) XCALLOC(0, sizeof(struct _idproducer));
	producer->last_id = ID_INVALID;
	producer->nfree = ID_MAX;
	producer->ncolumn = sizeof(unsigned long) * BITS_PER_BYTE;
	producer->nshift = __builtin_ctz(~(producer->ncolumn - 1));
	/* because of using calloc in XCALLOC we need not clear
	 * other members in producer here */
	if (TRUE == binding) {
		producer->args = (void **) XCALLOC(0, sizeof(void *) * BITS_PER_PAGE);
		if (NULL == (producer->arg_auto_free_func = arg_auto_free_func))
			WARNING("This is an id producer with binding, no argument "
					"auto free function warning.");
	}
	return producer;
}

int idproducer_del(idproducer producer) {
	unsigned int i;

	do {
		if (!WITH_BINDING(producer))
			break;
		if (WITH_ARG_AUTO_FREE(producer))
			for (i = 0; i < BITS_PER_PAGE; ++i)
				if (NULL != producer->args[i])
					(*producer->arg_auto_free_func)(producer->args[i]);
		XFREE(0, producer->args);
	} while (0);
	XFREE(0, producer);
	return 0;
}

int idproducer_alloc(idproducer producer, void *arg) {
	/* set offset to zero if last_id + 1 equals to BITS_PER_PAGE */
	int offset = (producer->last_id + 1) & BITS_PER_PAGE_MASK;

	while (producer->nfree) {
		offset = find_next_zero_bit(offset, producer);
		if (BITS_PER_PAGE == offset) {
			offset = 0;
			continue;
		}
		if (!test_and_set_bit(offset, producer)) {
			--producer->nfree;
			producer->last_id = offset;
			if (WITH_BINDING(producer))
				producer->args[offset] = arg;
			return offset;
		}
		break;
	}
	return ID_INVALID;
}

int idproducer_free(idproducer producer, int id, void **arg) {
	if (test_and_clr_bit(id & BITS_PER_PAGE_MASK, producer))
		return -1;
	++producer->nfree;
	if (WITH_BINDING(producer)) {
		if (NULL != arg)
			*arg = producer->args[id];
		else if (WITH_ARG_AUTO_FREE(producer) && NULL != producer->args[id])
			(*producer->arg_auto_free_func)(producer->args[id]);
		producer->args[id] = NULL;
	}
	return 0;
}

知识共享许可协议
Linux C ID分配 张向龙 创作,采用 知识共享 署名-非商业性使用-相同方式共享 3.0 中国大陆 许可协议进行许可。
基于 http://blog.chinaunix.net/uid-22566367-id-2845765.html上的作品创作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值