最近接触DHCP的开源实现,觉得ISC的实现让我受益匪浅,因此想做一个详细的分析记录,这也是受朋友的读书笔记影响,我也是第一次正式开博,慢慢把自己读到的点点滴滴记录在博客上面;
ISC DHCP是用C语言实现的,但是里面却使用很多面向对象的思想又或者说是设计模式的编程,代码非常值得学习。
当初刚大学毕业没多久,就有幸加入了国内的一家世界500强的IT企业,当时非常懵懂,参加老员工座谈会时,跟我们提到有什么问题可以问那些技术大牛,比如C语言,某某是这方面的大牛,too simple , too naive,
就记下某牛的通信方式,暗暗的把如何对C指针引用计数实现这个问题记下去问某牛,结果人家是一弄硬件的,结果某牛又推荐某牛,某牛又推荐某书。。我那时还是too young 未能自己解决迷惑。
而在阅读DHCP的开源实现的时候,我惊喜的发现多年以前的迷惑在这里得到了完整的实现,真是感慨,多年摸爬滚打,大多靠自学,这如同修真界的散修偶获绝世秘笈一般,可谓喜出望外;
相信下面的代码基本是一看就能明白,引用计数当然不是难题,难的是如何的简单通用的实现。
在没有人指点的时候,源码就是最好的老师。
下面就来看看这个小例子:
struct rc_history_entry { const char *file; int line; void *reference; void *addr; int refcnt; }; #define rc_register(x, l, r, y, z, d, f) do { if (RC_HISTORY_FLAGS & ~(f)) { rc_history [rc_history_index].file = (x); rc_history [rc_history_index].line = (l); rc_history [rc_history_index].reference = (r); rc_history [rc_history_index].addr = (y); rc_history [rc_history_index].refcnt = (z); rc_history_next (d); } } while (0) #define rc_register_mdl(r, y, z, d, f) rc_register (__FILE__, __LINE__, r, y, z, d, f) #else #define rc_register(file, line, reference, addr, refcnt, d, f) #define rc_register_mdl(reference, addr, refcnt, d, f) #endif
isc_result_t omapi_object_reference (omapi_object_t **, omapi_object_t *, const char *, int); isc_result_t omapi_object_dereference (omapi_object_t **, const char *, int);
isc_result_t omapi_object_reference (omapi_object_t **r, omapi_object_t *h, const char *file, int line) { if (!h || !r) return DHCP_R_INVALIDARG; if (*r) { #if defined (POINTER_DEBUG) log_error ("%s(%d): reference store into non-null pointer!", file, line); abort (); #else return DHCP_R_INVALIDARG; #endif } *r = h; h -> refcnt++; rc_register (file, line, r, h, h -> refcnt, 0, h -> type -> rc_flag); return ISC_R_SUCCESS; }
再做一个快捷声明与实现的宏
#define OMAPI_OBJECT_ALLOC(name, stype, type) isc_result_t name##_allocate (stype **p, const char *file, int line) { return omapi_object_allocate ((omapi_object_t **)p, type, 0, file, line); } isc_result_t name##_reference (stype **pptr, stype *ptr, const char *file, int line) { return omapi_object_reference ((omapi_object_t **)pptr, (omapi_object_t *)ptr, file, line); } isc_result_t name##_dereference (stype **ptr, const char *file, int line) { return omapi_object_dereference ((omapi_object_t **)ptr, file, line); } #define OMAPI_OBJECT_ALLOC_DECL(name, stype, type) isc_result_t name##_allocate (stype **p, const char *file, int line); isc_result_t name##_reference (stype **pptr, stype *ptr, const char *file, int line); isc_result_t name##_dereference (stype **ptr, const char *file, int line);
以后在代码里就可很方便的对任何类型的指针引用计数与解引用删除指针了:
if (interfaces) interface_reference (&tmp, interfaces, MDL); while (tmp) { if (next) interface_dereference (&next, MDL);
这是对网卡接口信息指针做了引用计数的一个例子。