• 一起读读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 }

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

     

  • 相关阅读:
    NutUI 优秀案例
    前端进阶不可错过的 10 个 Github 仓库
    Oracle Database Appliance ODA开箱视频
    直面ODA(Oracle Database Appliance)RAC一体机
    Ask Maclean论坛礼仪需知及学习oracle的方法论
    My Oracle Support Metalink站点最近将放弃flash界面转而使用ADF HTML
    java设计模式之代理模式
    数学分析原理 定理 6.10
    halcon傅里叶变换
    halconget_system获取HALCON系统参数
  • 原文地址:https://www.cnblogs.com/hwy89289709/p/6977692.html
Copyright © 2020-2023  润新知