【原创】libevent2中锁相关代码

bufferevent-internal.h

bufferevent的锁操作函数

/** Internal: Given a bufferevent, return its corresponding bufferevent_private. */
// 内部使用宏
// 通过 bufferevent 结构获取其所属的 bufferevent_private 结构
#define BEV_UPCAST(b) EVUTIL_UPCAST((b), struct bufferevent_private, bev)

#ifdef _EVENT_DISABLE_THREAD_SUPPORT
    #define BEV_LOCK(b) _EVUTIL_NIL_STMT
    #define BEV_UNLOCK(b) _EVUTIL_NIL_STMT
#else
/** Internal: Grab the lock (if any) on a bufferevent */
// 内部使用宏
// 对 bufferevent 上锁
#define BEV_LOCK(b) do {	    struct bufferevent_private *locking =  BEV_UPCAST(b);	    EVLOCK_LOCK(locking->lock, 0);	} while (0)

/** Internal: Release the lock (if any) on a bufferevent */
// 内部使用宏
// 对 bufferevent 解锁
#define BEV_UNLOCK(b) do {	    struct bufferevent_private *locking =  BEV_UPCAST(b);	    EVLOCK_UNLOCK(locking->lock, 0);	} while (0)

#endif

bufferevent.c

bufferevent的锁使能

// 为 bufferevent_private 创建 bufferevent 并初始化内部各结构
int
bufferevent_init_common(struct bufferevent_private *bufev_private,
    struct event_base *base, const struct bufferevent_ops *ops, enum bufferevent_options options)
{
...
#ifndef _EVENT_DISABLE_THREAD_SUPPORT	// 如果编译时使能了线程支持
    if (options & BEV_OPT_THREADSAFE) {	// 并且 bufferevent 也使能了线程支持
        if (bufferevent_enable_locking(bufev, NULL) < 0) {
            /* cleanup */
            evbuffer_free(bufev->input);
            evbuffer_free(bufev->output);
            bufev->input = NULL;
            bufev->output = NULL;
            return -1;
        }
    }
#endif
...
}

【bufferevent的锁设置】

// 为与 bufferevent 相关的各结构设置 lock
// NOTE: 所有结构都共用 lock
int
bufferevent_enable_locking(struct bufferevent *bufev, void *lock)
{
#ifdef _EVENT_DISABLE_THREAD_SUPPORT
    return -1;
#else
    struct bufferevent *underlying;

    // 首先要确保 bufev 所属的 bufferevent_private 中没有 lock
    if (BEV_UPCAST(bufev)->lock)
        return -1;
    // 若为 socket 或 pair 类型的 bufferevent 则返回 NULL
    underlying = bufferevent_get_underlying(bufev);

    // 若外部未提供 lock ,但 bufev 含有底层 bufferevent
    // 并且该底层 bufferevent 所属 bufferevent_private 中存在 lock 变量
    // 则直接使用该 lock 做为 bufferevent 的锁
    if (!lock && underlying && BEV_UPCAST(underlying)->lock) {
        lock = BEV_UPCAST(underlying)->lock;
        BEV_UPCAST(bufev)->lock = lock;
        BEV_UPCAST(bufev)->own_lock = 0;
    } else if (!lock) {	// 外部未提供 lock 且底层也无可用锁
        // 则自行分配 lock 做为 bufferevent 的锁
        EVTHREAD_ALLOC_LOCK(lock, EVTHREAD_LOCKTYPE_RECURSIVE);
        if (!lock)
            return -1;
        BEV_UPCAST(bufev)->lock = lock;
        BEV_UPCAST(bufev)->own_lock = 1;
    } else {	// 外部提供 lock 供直接使用
        BEV_UPCAST(bufev)->lock = lock;
        BEV_UPCAST(bufev)->own_lock = 0;
    }
    // 为 input 和 output 缓冲区设置锁
    evbuffer_enable_locking(bufev->input, lock);
    evbuffer_enable_locking(bufev->output, lock);

    if (underlying && !BEV_UPCAST(underlying)->lock)
        bufferevent_enable_locking(underlying, lock);

    return 0;
#endif
}

buffer.c

【evbuffer的锁设置】

// 为 evbuffer 设置 lock
int
evbuffer_enable_locking(struct evbuffer *buf, void *lock)
{
#ifdef _EVENT_DISABLE_THREAD_SUPPORT
    return -1;
#else
    // 若 evbuffer 内部已存在 lock 则直接返回
    if (buf->lock)
        return -1;

    if (!lock) {
        EVTHREAD_ALLOC_LOCK(lock, EVTHREAD_LOCKTYPE_RECURSIVE);
        if (!lock)
            return -1;
        buf->lock = lock;
        buf->own_lock = 1;
    } else {
        buf->lock = lock;
        buf->own_lock = 0;
    }

    return 0;

#endif
}

evbuffer-internal.h

【evbuffer中的锁定义】

struct evbuffer {
...
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
/** A lock used to mediate access to this buffer. */
    void *lock;
#endif
...
}

event-internal.h

【event_base的锁定义】

struct event_base {
...
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
    /* threading support */
    /** The thread currently running the event_loop for this base */
    unsigned long th_owner_id;
    /** A lock to prevent conflicting accesses to this event_base */
    // 用于防止针对当前 event_base 冲突性访问的锁
    void *th_base_lock;
    /** The event whose callback is executing right now */
    struct event *current_event;
    /** A condition that gets signalled when we‘re done processing an
     * event with waiters on it. */
    void *current_event_cond;
    /** Number of threads blocking on current_event_cond. */
    int current_event_waiters;
#endif
...
};

event.c

【event_base的锁使能】

struct event_base *
event_base_new_with_config(const struct event_config *cfg)
{
...
#ifndef _EVENT_DISABLE_THREAD_SUPPORT  // 如果支持多线程锁
    if (EVTHREAD_LOCKING_ENABLED() &&  // 测试是否锁函数为 NULL ,即 libevent 是否初始化为支持多线程
        (!cfg || !(cfg->flags & EVENT_BASE_FLAG_NOLOCK))) { // 判定当前配置是否支持锁
        int r;
        // 申请递归锁
        EVTHREAD_ALLOC_LOCK(base->th_base_lock, EVTHREAD_LOCKTYPE_RECURSIVE);
        base->defer_queue.lock = base->th_base_lock;
        // 申请条件变量
        EVTHREAD_ALLOC_COND(base->current_event_cond);
        r = evthread_make_base_notifiable(base);
        if (r<0) {
            event_warnx("%s: Unable to make base notifiable.", __func__);
            event_base_free(base);
            return NULL;
        }
    }
#endif
...
}

evthread-internal.h

【平台和多线程相关锁定义】

#ifndef WIN32  // 非 Windows 平台
/* On Windows, the way we currently make DLLs, it‘s not allowed for us to
 * have shared global structures.  Thus, we only do the direct-call-to-function
 * code path if we know that the local shared library system supports it.
 */
#define EVTHREAD_EXPOSE_STRUCTS
#endif

#if ! defined(_EVENT_DISABLE_THREAD_SUPPORT) && defined(EVTHREAD_EXPOSE_STRUCTS) // 多线程支持+非WIN平台
...
#elif ! defined(_EVENT_DISABLE_THREAD_SUPPORT)  // 多线程支持+WIN平台
...
#else /* _EVENT_DISABLE_THREAD_SUPPORT */  // 不支持多线程
...
#endif

【event_base锁函数】

#if ! defined(_EVENT_DISABLE_THREAD_SUPPORT) && defined(EVTHREAD_EXPOSE_STRUCTS) // 多线程支持+非WIN平台
...
/** Acquire a lock. */
// 获取锁
#define EVLOCK_LOCK(lockvar,mode)	do {	    if (lockvar)	    _evthread_lock_fns.lock(mode, lockvar);	} while (0)

/** Release a lock */
#define EVLOCK_UNLOCK(lockvar,mode)	do {	    if (lockvar)	    _evthread_lock_fns.unlock(mode, lockvar);	} while (0)
...
/** Lock an event_base, if it is set up for locking.  Acquires the lock
    in the base structure whose field is named ‘lockvar‘. */
// 锁定 event_base ,如果该 event_base 确实支持锁
// 获取 base 结构中的锁,锁名由 lockvar 指定
#define EVBASE_ACQUIRE_LOCK(base, lockvar) do {	    EVLOCK_LOCK((base)->lockvar, 0);	} while (0)

/** Unlock an event_base, if it is set up for locking. */
#define EVBASE_RELEASE_LOCK(base, lockvar) do {	    EVLOCK_UNLOCK((base)->lockvar, 0);	} while (0)
...
#elif ! defined(_EVENT_DISABLE_THREAD_SUPPORT)  // 多线程支持+WIN平台
...

thread.h

#if !defined(_EVENT_DISABLE_THREAD_SUPPORT) || defined(_EVENT_IN_DOXYGEN)

#define EVTHREAD_LOCK_API_VERSION 1

/**
   @name Types of locks
         锁类型

   其实这里包含第三种锁类型,即 0 值代表 普通锁

   @{*/
/** A recursive lock is one that can be acquired multiple times at once by the
 * same thread.  No other process can allocate the lock until the thread that
 * has been holding it has unlocked it as many times as it locked it. */
// 递归锁类型是指,该锁可以在同一个线程中被获取多次;其他线程无法分配该锁,直到
// 持有该锁的线程对其解锁相同数量的次数
#define EVTHREAD_LOCKTYPE_RECURSIVE 1
/* A read-write lock is one that allows multiple simultaneous readers, but
 * where any one writer excludes all other writers and readers. */
#define EVTHREAD_LOCKTYPE_READWRITE 2
/**@}*/

/** This structure describes the interface a threading library uses for
 * locking.   It‘s used to tell evthread_set_lock_callbacks() how to use
 * locking on this platform.
 */
// 线程锁操作函数指针结构体
// 该结构用于告知 evthread_set_lock_callbacks() 在当前平台上如何使用锁
struct evthread_lock_callbacks {
    /** The current version of the locking API.  Set this to
    * EVTHREAD_LOCK_API_VERSION */
    int lock_api_version;
    /** Which kinds of locks does this version of the locking API
    * support?  A bitfield of EVTHREAD_LOCKTYPE_RECURSIVE and
    * EVTHREAD_LOCKTYPE_READWRITE.
    *
    * (Note that RECURSIVE locks are currently mandatory, and
    * READWRITE locks are not currently used.)
    **/
    unsigned supported_locktypes;
    /** Function to allocate and initialize new lock of type ‘locktype‘.
    * Returns NULL on failure. */
    void *(*alloc)(unsigned locktype);
    /** Function to release all storage held in ‘lock‘, which was created
    * with type ‘locktype‘. */
    void (*free)(void *lock, unsigned locktype);
    /** Acquire an already-allocated lock at ‘lock‘ with mode ‘mode‘.
    * Returns 0 on success, and nonzero on failure. */
    // 以 ‘mode‘ 模式持有由 ‘lock‘ 指向的已经分配的锁;0 为获取成功,非零为失败
    int (*lock)(unsigned mode, void *lock);
    /** Release a lock at ‘lock‘ using mode ‘mode‘.  Returns 0 on success,
    * and nonzero on failure. */
    int (*unlock)(unsigned mode, void *lock);
};

/** Sets a group of functions that Libevent should use for locking.
 * For full information on the required callback API, see the
 * documentation for the individual members of evthread_lock_callbacks.
 *
 * Note that if you‘re using Windows or the Pthreads threading library, you
 * probably shouldn‘t call this function; instead, use
 * evthread_use_windows_threads() or evthread_use_posix_threads() if you can.
 */
int evthread_set_lock_callbacks(const struct evthread_lock_callbacks *);

...

#if (defined(WIN32) && !defined(_EVENT_DISABLE_THREAD_SUPPORT)) || defined(_EVENT_IN_DOXYGEN)
/** Sets up Libevent for use with Windows builtin locking and thread ID
    functions.  Unavailable if Libevent is not built for Windows.

    @return 0 on success, -1 on failure. */
int evthread_use_windows_threads(void);           // windows 上的锁使能
/**
   Defined if Libevent was built with support for evthread_use_windows_threads()
*/
#define EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED 1

#endif

#if defined(_EVENT_HAVE_PTHREADS) || defined(_EVENT_IN_DOXYGEN)
/** Sets up Libevent for use with Pthreads locking and thread ID functions.
    Unavailable if Libevent is not build for use with pthreads.  Requires
    libraries to link against Libevent_pthreads as well as Libevent.
    令 libevent 可以使用 pthread 锁和相应的获取线程 id 的函数
    如果构建 libevent 时候不支持 pthread 则无法使用该函数
    使用时要求链接 libevent_pthreads 库和 libevent 库

    @return 0 on success, -1 on failure. */
int evthread_use_pthreads(void);               // linux 上的锁使能
/** Defined if Libevent was built with support for evthread_use_pthreads() */
#define EVTHREAD_USE_PTHREADS_IMPLEMENTED 1

#endif

/** Enable debugging wrappers around the current lock callbacks.  If Libevent
 * makes one of several common locking errors, exit with an assertion failure.
 *
 * If you‘re going to call this function, you must do so before any locks are
 * allocated.
 **/
void evthread_enable_lock_debuging(void);

#endif /* _EVENT_DISABLE_THREAD_SUPPORT */

whatsnew-2.0.txt

2.8. evthread_* functions for thread-safe structures.

  Libevent structures can now be built with locking support.  This code
  makes it safe to add, remove, and activate events on an event base from a
  different thread.  (Previously, if you wanted to write multithreaded code
  with Libevent, you could only an event_base or its events in one thread at
  a time.)

  If you want threading support and you‘re using pthreads, you can just
  call evthread_use_pthreads().  (You‘ll need to link against the
  libevent_pthreads library in addition to libevent_core.  These functions are
  not in libevent_core.)

  If you want threading support and you‘re using Windows, you can just
  call evthread_use_windows_threads().

  If you are using some locking system besides Windows and pthreads, You
  can enable this on a per-event-base level by writing functions to
  implement mutexes, conditions, and thread IDs, and passing them to
  evthread_set_lock_callbacks and related functions in event2/thread.h.

  Once locking functions are enabled, every new event_base is created with a
  lock.  You can prevent a single event_base from being built with a lock
  disabled by using the EVENT_BASE_FLAG_NOLOCK flag in its
  event_config.  If an event_base is created with a lock, it is safe to call
  event_del, event_add, and event_active on its events from any thread.  The
  event callbacks themselves are still all executed from the thread running
  the event loop.

  To make an evbuffer or a bufferevent object threadsafe, call its
  *_enable_locking() function.

  The HTTP api is not currently threadsafe.

  To build Libevent with threading support disabled, pass
  --disable-thread-support to the configure script.
时间: 2024-10-28 19:38:32

【原创】libevent2中锁相关代码的相关文章

实验--使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用(杨光)

使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 攥写人:杨光  学号:20135233 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验要求: 选择一个系统调用(13号系统调用time除外),系统调用列表参见http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/syscalls/sys

[iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之一:OBJ格式分析

[iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之一:OBJ文件格式分析作者:yuezang - iTyran 在iOS的3D开发中常常需要导入通过3DS MAX之类的3D设计软件生成的模型.因为OpenGL ES是不能直接读取这些文件的,所以常常需要开发人员增加接口来导入.通常的做法是在建模软件中建立3D模型之后在OpenGL ES中导入并进行控制.    3DS MAX通常的保存格式有*.max(现在生成的版本的格式),*.3ds(低版本的3ds Max生成的格式)

Latex 中插入 Matlab 代码

这篇文章将介绍如何在 Latex 排版过程中添加 Matlab 代码 功能效果 主要有如下排版功能: 语法高亮 自动添加边框 自动添加行号 先上图,大家感受一下效果 listings 包 首先确保你能使用使用 listings 包 简单快捷的使用方法如下 \usepackage{listings} \lstset{language=Matlab} \begin{lstlisting} % Plot function f(x) = 2*x^3 - x - 2 ezplot('2*x^3-x-2',

[iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之二:lib3ds加载模型

[iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之二:lib3ds加载模型 作者:u0u0 - iTyran 在上一节中,我们分析了OBJ格式.OBJ格式优点是文本形式,可读性好,缺点也很明显,计算机解析文本过程会比解析二进制文件慢很多.OBJ还有个问题是各种3D建模工具导出的布局格式还不太一样,face还有多边形(超过三边形),不利于在OpenGL ES里面加载. .3ds文件是OBJ的二进制形式,并且多很多信息.有一个C语言写的开源库可以用来加.3ds文件,这就是l

ios 网络请求总结加强对中文的处理 问题:URL不允许写中文 在GET请求中,相关代码段打断点以验证。

开发还是需要多多练习的 ,下面是一些常用的步骤: 一.简单说明 创建Get 请求 //    1.设置请求路径 NSString *urlStr=[NSString stringWithFormat:@"http://192.168.1.53:8080/MJServer/login?username=%@&pwd=%@",self.username.text,self.pwd.text]; NSURL *url=[NSURL URLWithString:urlStr]; //

java中的静态代码块、构造代码块、普通代码块和同步代码块总结

java中的4中代码块总结如下: * 加了static的是静态代码块,在类中写了一对{}是构造代码块,在方法中写了一对{}是普通代码块, * java中还有一种代码块是同步代码块,常用在多线程中, synchronized关键字, * 同步代码块格式是:synchronized(同步对象){} * 静态代码块 先于构造代码块 先于构造方法执行 * 静态代码块 先于普通代码块 先于构造方法执行 * 构造代码块和普通代码块按照程序逻辑顺序执行 package 面试题; class HelloA{ p

提取代码中的部分代码字段

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-

使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 选择调用的进程为 24 i386 getuid sys_getuid1647 i386 getgid sys_getgid16 使用库函数API方式 使用C代码中嵌入汇编代码方式

完整java开发中JDBC连接数据库代码和步骤

完整java开发中JDBC连接数据库代码和步骤 JDBC连接数据库 •创建一个以JDBC连接数据库的程序,包含7个步骤: 1.加载JDBC驱动程序: 在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机), 这通过java.lang.Class类的静态方法forName(String  className)实现. 例如: try{ //加载MySql的驱动类 Class.forName("com.mysql.jdbc.Driver") ; }catch(Class