【原创】libevent2中锁相关代码

简介:

在 bufferevent-internal.h 中  
bufferevent的锁操作函数  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/** 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的锁使能  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 为 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的锁设置  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 为与 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的锁设置  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 为 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中的锁定义  
?
1
2
3
4
5
6
7
8
struct evbuffer {
...
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
/** A lock used to mediate access to this buffer. */
     void *lock;
#endif
...
}

在 event-internal.h 中  
event_base的锁定义  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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的锁使能  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 中  
平台和多线程相关锁定义  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#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锁函数  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#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 中

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#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 中  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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.


目录
相关文章
composer.lock 文件是干什么的?底层原理是什么?
composer.lock 文件是干什么的?底层原理是什么?
289 0
|
Java
《Java并发库系列三》一newSingleThreadScheduledExecutor
newSingleThreadScheduledExecutor:产生一个ScheduledExecutorService对象,这个对象的线程池大小为1,如果任务多于一个,任务将按先后顺序执行。
684 0
|
9月前
|
Java
详解JDK锁02:万字文!结合实战案例,手撕AQS源码!
详解JDK锁02:万字文!结合实战案例,手撕AQS源码!
|
4月前
|
Linux Go 调度
谈谈对 GMP 的简单认识
谈谈对 GMP 的简单认识
|
8月前
|
存储 Java
【一文读懂】 Java并发 - 锁升级原理
Java对象头,锁升级的原因,重量级锁、轻量级锁、偏向锁的原理
187 0
【一文读懂】 Java并发 - 锁升级原理
|
9月前
|
Java C++
详解JDK锁01:结合源码一文弄懂Lock接口!
详解JDK锁01:结合源码一文弄懂Lock接口!
PHP如何进行异步I/O操作?底层原理是什么?
PHP如何进行异步I/O操作?底层原理是什么?
112 0
|
存储 缓存 安全
锁的原理随笔
synchronized, NSLock, 递归锁, 条件锁
141 0
|
Java
Java并发编程笔记之StampedLock锁源码探究
StampedLock是JUC并发包里面JDK1.8版本新增的一个锁,该锁提供了三种模式的读写控制,当调用获取锁的系列函数的时候,会返回一个long 型的变量,该变量被称为戳记(stamp),这个戳记代表了锁的状态。
3162 0
|
Java 程序员 vr&ar
Java并发编程 -- Atomic包
Java从JDK1.5开始提供了java.util.concurrent.atomic包,方便程序员在多线程环境下,无锁的进行原子操作。原子变量的底层使用了处理器提供的原子指令,但是不同的CPU架构可能提供的原子指令不一样,也有可能需要某种形式的内部锁,所以该方法不能绝对保证线程不被阻塞。
864 0