/** 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_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 相关的各结构设置 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 }
// 为 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 }
struct evbuffer { ... #ifndef _EVENT_DISABLE_THREAD_SUPPORT /** A lock used to mediate access to this buffer. */ void *lock; #endif ... }
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 ... };
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 ... }
#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 */
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.