一起读读libevent的源代码:Libevent 第一章 设置libevent (2)

调试 lock 的用法:

使用这个方法,我们能够捕获以下两种的lock的错误:

  • unlocking a lock that we don’t actually hold

  • re-locking a non-recursive lock

在之前的分析,我们知道它的其中一部分是通过 evthread_lock_debugging_enabled_ 这变量来进行的。但具体怎么样,来一起深挖一下 

Interface
void evthread_enable_lock_debugging(void);
#define evthread_enable_lock_debuging() evthread_enable_lock_debugging()

 

// /evthread.c
0317 void
0318 evthread_enable_lock_debugging(void)
0319 {
0320     struct evthread_lock_callbacks cbs = {
0321         EVTHREAD_LOCK_API_VERSION,
0322         EVTHREAD_LOCKTYPE_RECURSIVE,
0323         debug_lock_alloc,
0324         debug_lock_free,
0325         debug_lock_lock,
0326         debug_lock_unlock
0327     };
0328     if (evthread_lock_debugging_enabled_)
0329         return;
0330     memcpy(&original_lock_fns_, &evthread_lock_fns_,
0331         sizeof(struct evthread_lock_callbacks));
0332     memcpy(&evthread_lock_fns_, &cbs,
0333         sizeof(struct evthread_lock_callbacks));
0334 
0335     memcpy(&original_cond_fns_, &evthread_cond_fns_,
0336         sizeof(struct evthread_condition_callbacks));
0337     evthread_cond_fns_.wait_condition = debug_cond_wait;
0338     evthread_lock_debugging_enabled_ = 1;
0339 
0340     /* XXX return value should get checked. */
0341     event_global_setup_locks_(0);
0342 }

这里首先是要设置 cbs 这个 struct evthread_lock_callbacks 结构, 然后就分开三步,将evthread_lock_fns_ 复制到 original_lock_fns_ , 将 cbs 复制到evthread_lock_fns_ ,然后再将 evthread_cond_fns_ 复制到 original_cond_fns_ 。 

我想,这里为什么要这么复制,是因为函数 evthread_get_lock_callbacks() 和 evthread_get_condition_callbacks() 函数,都会需要判断 evthread_lock_debugging_enabled_,然后取决于使用 original_* 和 evthread_* 这两个结构。evthread_lock_debugging_enabled_ 为真的时候,就会使用 original_* 的这个变量。至于,为什么这么做,我还不知道。

另外一个知识:

  struct evthread_lock_callbacks 是用于记录ethread_lock_callbacks 来记录锁的分配函数等等。

  在文件/event.c 里面,用于保存锁的变量是:static void *event_debug_map_lock_,分配给它的锁,是ethread里面的evthread_setup_global_lock_来进行分配的

  在文件/signal.c 里面,用于保存锁的变量是:static void *evsig_base_lock, 分配锁给它的evthread_setup_global_lock_。

  同理,/evutil.c 里面,保存锁的变量就是 :static void *windows_socket_errors_lock_,  分配锁的也是同一个函数。

  但/evutil_rand.c 里面,暂时没有锁的变量,虽然上面的代码也写了分配。

从这上面的理解,就可以知道了,其实ethread的是一个分配锁的机构,因为会有不同的线程访问event, signal,evutil等。所以需要这些锁来进行同步。


Debugging event usage

有一些在使用events的常见的错误,Libevent可以检测并且向你报告。这些错误包括:

将一个未初始化的event结构,当成是已经初始化的

尝试再初始化一个挂起的event结构体

接口如下:

Interface
void event_enable_debug_mode(void);
This function must only be called before any event_base is created.

函数的代码如下:

0529 void
0530 event_enable_debug_mode(void)
0531 {
0532 #ifndef EVENT__DISABLE_DEBUG_MODE
0533     if (event_debug_mode_on_)
0534         event_errx(1, "%s was called twice!", __func__);
0535     if (event_debug_mode_too_late)
0536         event_errx(1, "%s must be called *before* creating any events "
0537             "or event_bases",__func__);
0538 
0539     event_debug_mode_on_ = 1;
0540 
0541     HT_INIT(event_debug_map, &global_debug_map);
0542 #endif
0543 }

这里的作用,就是设置一个变量为1,并且初始化了一个hash_table。并且初始化了一个 event_debug_map。那么这么一个变量event_debug_mode_on_ 会被用到哪里呢?我们可以看到一下的函数:

/* Macro: record that ev is now setup (that is, ready for an add) */
event_debug_note_setup_(ev)

/* Macro: record that ev is no longer setup */
event_debug_note_teardown_(ev)

/* Macro: record that ev is now added */
event_debug_note_add_(ev)

/* Macro: record that ev is no longer added */
event_debug_note_del_(ev)

/* Macro: assert that ev is setup (i.e., okay to add or inspect) */
event_debug_assert_is_setup_(ev)

/* Macro: assert that ev is not added (i.e., okay to tear down or set 
* up again) */
event_debug_assert_not_added_(ev)

函数 : event_disable_debug_mode(void)

在说明中,有这么一句话,如果使用debug mode,你可能会run out of memory。因为是使用了event_assign(),而不是event_new()。这是因为Libevent没有办法区分event 是使用event_assign() 创建,并且不再使用。但是event_new()是可以区分的,因为你使用event_free()来进行释放它。同样的,必须要使用以igehanshu,来告诉Libevent这样的一个事件,不再被看看作是assigned的。

Interface
void event_debug_unassign(struct event *ev);

函数的源代码是:

2186 void
2187 event_debug_unassign(struct event *ev)
2188 {
2189     event_debug_assert_not_added_(ev);
2190     event_debug_note_teardown_(ev);
2191 
2192     ev->ev_flags &= ~EVLIST_INIT;
2193 }

这里面,挺多每搞懂的。先放着。看其他的先。



Detailed event debugging 只能用这样一种方法来进行开启,编译的时候添加如此的标志:-DUSE_DEBUG
会包含下面的信息,event的添加,event的删除,平台指定的通知信息。




Detecting the version of Libevent:

可以用下面的接口来检测Libevent的版本信息。

Interface
#define LIBEVENT_VERSION_NUMBER 0x02000300
#define LIBEVENT_VERSION "2.0.3-alpha"
const char *event_get_version(void);
ev_uint32_t event_get_version_number(void);

这里面有不同的:宏是再编译的时候,确定了Libevent的库;函数返回的是运行时的版本。注意,如果你有动态链接你的程序到Libevent,这些版本可能是不同的。

3404 const char *
3405 event_get_version(void)
3406 {
3407     return (EVENT__VERSION);
3408 }

0333 /* Version number of package */
0334 #define EVENT__VERSION "2.1.8-stable"

另外一个的源代码是:

3411 event_get_version_number(void)
3412 {
3413     return (EVENT__NUMERIC_VERSION);
3414 }

0276 /* Numeric representation of the version */
0277 #define EVENT__NUMERIC_VERSION 0x02010800

Freeing global Libevent structures:

接口:

Interface
void libevent_global_shutdown(void);
3851 void
3852 libevent_global_shutdown(void)
3853 {
3854     event_disable_debug_mode();
3855     event_free_globals();
3856 }

首先 event_disable_debug_mode() 会释放调锁由Hash_table上面的锁由的事件入口:

0545 void
0546 event_disable_debug_mode(void)
0547 {
0548 #ifndef EVENT__DISABLE_DEBUG_MODE
0549     struct event_debug_entry **ent, *victim;
0550 
0551     EVLOCK_LOCK(event_debug_map_lock_, 0);
0552     for (ent = HT_START(event_debug_map, &global_debug_map); ent; ) {
0553         victim = *ent;
0554         ent = HT_NEXT_RMV(event_debug_map, &global_debug_map, ent);
0555         mm_free(victim);
0556     }
0557     HT_CLEAR(event_debug_map, &global_debug_map);
0558     EVLOCK_UNLOCK(event_debug_map_lock_ , 0);
0559 
0560     event_debug_mode_on_  = 0;
0561 #endif
0562 }

然后使用event_free_globals()函数进行释放

3843 static void
3844 event_free_globals(void)
3845 {
3846     event_free_debug_globals();
3847     event_free_evsig_globals();
3848     event_free_evutil_globals();
3849 }

这三个函数,最主要的都是释放三个模块当中锁包含的全局的锁的结构。

 

原文地址:https://www.cnblogs.com/hwy89289709/p/6977692.html