转载请注明出处:http://blog.csdn.net/luotuo44/article/details/39325447
锁操作:
//buffer.c文件
int//参数可以是一个锁变量也可以是NULL
evbuffer_enable_locking(struct evbuffer *buf, void *lock)
{
#ifdef _EVENT_DISABLE_THREAD_SUPPORT
return -1;
#else
if (buf->lock)
return -1;
if (!lock) {
//自己分配锁变量
EVTHREAD_ALLOC_LOCK(lock, EVTHREAD_LOCKTYPE_RECURSIVE);
if (!lock)
return -1;
buf->lock = lock;
//该evbuffer拥有锁,到时需要释放锁内存
buf->own_lock = 1;
} else {
buf->lock = lock;//使用参数提供的锁
buf->own_lock = 0;//自己没有拥有锁。不需要释放锁内存
}
return 0;
#endif
}
可以看到,第二个参数可以为NULL。此时函数内部会申请一个锁。明显如果要让evbuffer能使用锁,就必须在一开始就调用evthread_use_windows_threads()或者evthread_use_pthreads(),关于这个可以参考一篇博文。
因为用户操控这个evbuffer,所以Libevent提供了加锁和解锁接口给用户使用。
//buffer.c文件
void
evbuffer_lock(struct evbuffer *buf)
{
EVBUFFER_LOCK(buf);
}
void
evbuffer_unlock(struct evbuffer *buf)
{
EVBUFFER_UNLOCK(buf);
}
//evbuffer-internal.h文件
#define EVBUFFER_LOCK(buffer) \
do { \
EVLOCK_LOCK((buffer)->lock, 0); \
} while (0)
#define EVBUFFER_UNLOCK(buffer) \
do { \
EVLOCK_UNLOCK((buffer)->lock, 0); \
} while (0)
在Libevent内部,一般不会使用这个两个接口,而是直接使用EVBUFFER_LOCK(buf)和EVBUFFER_UNLOCK(buf)。
查找操作:
下图展示了evbuffer的一些查找操作以及调用关系。
查找结构体:
对于一个数组或者一个文件,只需一个下标或者偏移量就可以定位查找了。但对于evbuffer来说,它的数据是由一个个的evbuffer_chain用链表连在一起的。所以在evbuffer中定位,不仅仅要有一个偏移量,还要指明是哪个evbuffer_chain,甚至是在evbuffer_chain中的偏移量。因此Libevent定义了一个查找(定位)结构体:
//buffer.h文件
struct evbuffer_ptr {
ev_ssize_t pos;//总偏移量,相对于数据的开始位置
/* Do not alter the values of fields. */
struct {
void *chain;//指明是哪个evbuffer_chain
size_t pos_in_chain; //在evbuffer_chain中的偏移量
} _internal;
};
有一点要注意,pos_in_chain是从misalign这个错开空间之后计算的,也就是说其实际偏移量为:chain->buffer+ chain->misalign + pos_in_chain。
定位结构体有一个对应的操作函数evbuffer_ptr_set,该函数就像fseek函数那样,可以设置或者移动偏移量,并且可以绝对和相对地移动。
//buffer.h文件
enum evbuffer_ptr_how {
EVBUFFER_PTR_SET, //偏移量是一个绝对位置
EVBUFFER_PTR_ADD //偏移量是一个相对位置
};
//buffer.c文件
//设置evbuffer_ptr。evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET)
//将这个pos指向链表的开头
//position指明移动的偏移量,how指明该偏移量是绝对偏移量还是相对当前位置的偏移量。
int//这个函数的作用就像C语言中的fseek,设置文件指针的偏移量
evbuffer_ptr_set(struct evbuffer *buf, struct evbuffer_ptr *pos,
size_t position, enum evbuffer_ptr_how how)
{
size_t left = position;
struct evbuffer_chain *chain = NULL;
EVBUFFER_LOCK(buf);
//这个switch的作用就是给pos设置新的总偏移量值。
switch (how) {
case EVBUFFER_PTR_SET://绝对位置
chain = buf->first;//从第一个evbuffer_chain算起
pos->pos = position; //设置总偏移量
position = 0;
break;
case EVBUFFER_PTR_ADD://相对位置
chain = pos->_internal.chain;//从当前evbuffer_chain算起
pos->pos += position;//加上相对偏移量
position = pos->_internal.pos_in_chain;
break;
}
//这个偏移量跨了evbuffer_chain。可能不止跨一个chain。
while (chain && position + left >= chain->off) {
left -= chain->off - position;
chain = chain->next;
position = 0;
}
if (chain) {//设置evbuffer_chain内的偏移量
pos->_internal.chain = chain;
pos->_internal.pos_in_chain = position + left;
} else {//跨过了所有的节点
pos->_internal.chain = NULL;
pos->pos = -1;
}
EVBUFFER_UNLOCK(buf);
return chain != NULL ? 0 : -1;
}
可以看到,该函数只考虑了向后面的chain移动定位指针,不能向。当然如果参数position小于0,并且移动时并不会跨越当前的chain,还是可以的。不过最好不要这样做。如果确实想移回头,那么可以考虑下面的操作。
pos.position -= 20;//移回头20个字节。
evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET);
查找一个字符:
有下面代码的前一个函数是可以用来查找一个字符的,第二个函数则是获取对于位置的字符。static inline ev_ssize_t
evbuffer_strchr(struct evbuffer_ptr *it, const char chr);
static inline char//获取对应位置的字符
evbuffer_getchr(struct evbuffer_ptr *it);
static inline int
evbuffer_strspn(struct evbuffer_ptr *ptr, const char *chrset);
函数evbuffer_strchr是从it指向的evbuffer_chain开始查找,会往后面的链表查找。it是一个值-结果参数,如果查找到了,那么it将会指明被查找字符的位置,并返回相对于evbuffer的总偏移量(即it->pos)。如果没有找到,就返回-1。由于实现都是一般的字符比较,所以就不列出代码了。函数evbuffer_getchr很容易理解也不列出代码了。
第三个函数evbuffer_strspn的参数chrset虽然是一个字符串,其实内部也是比较字符的。该函数所做的操作和C语言标准库里面的strspn函数是一样的。这里也不多说了。关于strspn函数的理解可以查看 这里。
查找一个字符串:
字符串的查找函数有evbuffer_search_range和evbuffer_search,后者调用前者完成查找。
在讲查找前,先看一个字符串比较函数evbuffer_ptr_memcmp。该函数是比较某一个字符串和从evbuffer中某个位置开始的字符是否相等。明显比较的时候需要考虑到跨evbuffer_chain的问题。static int //匹配成功会返回0
evbuffer_ptr_memcmp(const struct evbuffer *buf, const struct evbuffer_ptr *pos,
const char *mem, size_t len)
{
struct evbuffer_chain *chain;
size_t position;
int r;
//链表数据不够
if (pos->pos + len > buf->total_len)
return -1;
//需要考虑这个要匹配的字符串被分散在两个evbuffer_chain中