欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 创投人物 > libevent - Macro function

libevent - Macro function

2025/10/21 12:53:41 来源:https://blog.csdn.net/m0_72703340/article/details/142600738  浏览:    关键词:libevent - Macro function

TAILQ_INIT

/** Tail queue functions.* 尾队列的头结点初始化为空队列。*/
#define	TAILQ_INIT(head) do {						\(head)->tqh_first = NULL;					\(head)->tqh_last = &(head)->tqh_first;				\
} while (/*CONSTCOND*/0)

TAILQ_INIT 宏是一个用于初始化尾队列头部的工具,它通过将 tqh_first 设置为 NULL 并将 tqh_last 设置为指向 tqh_first 的地址,确保队列可以从空状态正确地过渡到非空状态。这个设计使用了二级指针的概念,使得尾部插入操作更为高效和直接。这种结构广泛应用于需要动态管理链表的系统编程场景中。
do { ... } while (0)

  • 这种结构确保了宏在使用时会像一个普通的语句一样执行,而不会引起语法错误。例如,用户可以安全地在 if 语句中使用这个宏,而不会因为缺少大括号导致错误

  • (head)->tqh_first = NULL;

    • 初始化 tqh_firstNULL,表示队列当前没有任何元素,是空的。
  • (head)->tqh_last = &(head)->tqh_first;

    • 初始化 tqh_last 使其指向 tqh_first 的地址。这样做的目的是为了方便在队列末尾进行插入操作。具体来说,如果队列是空的,tqh_last 会指向 tqh_first,这意味着下一次插入的元素将成为新的第一个元素

EVUTIL_ASSERT

#define EVUTIL_ASSERT(cond)						\do {								\if (EVUTIL_UNLIKELY(!(cond))) {				\event_errx(EVENT_ERR_ABORT_,			\"%s:%d: Assertion %s failed in %s",		\__FILE__,__LINE__,#cond,__func__);		\/* In case a user-supplied handler tries to */	\/* return control to us, log and abort here. */	\(void)fprintf(stderr,				\"%s:%d: Assertion %s failed in %s",		\__FILE__,__LINE__,#cond,__func__);		\abort();					\}							\} while (0)

EVUTIL_ASSERT 是一个用于断言条件的宏,在条件不满足时会中止程序运行,并打印相关的调试信息。

do { ... } while (0) 结构

  • 这是一个常见的宏包装技巧,用于确保宏在使用时能够像普通语句一样执行,不会因为缺少分号或其他语法问题导致错误。
    if (EVUTIL_UNLIKELY(!(cond))) { ... }

  • EVUTIL_UNLIKELY 是一个宏或函数,通常用于提示编译器某个条件不太可能发生,这可以帮助编译器优化代码。这里的意思是,如果条件 condfalse(即条件不满足),则执行后续代码。
    event_errx(EVENT_ERR_ABORT_, "%s:%d: Assertion %s failed in %s", __FILE__, __LINE__, #cond, __func__);

  • event_errx 是一个函数,用于打印错误信息并终止程序。它会输出文件名(__FILE__)、行号(__LINE__)、断言失败的条件(#cond),以及当前函数的名称(__func__)。

  • #cond 是将 cond 转换为字符串的预处理器操作,这样可以打印出具体的条件表达式。

  • EVENT_ERR_ABORT_ 通常是一个预定义的常量,用于指示错误类型,
    fprintf(stderr, "%s:%d: Assertion %s failed in %s", __FILE__, __LINE__, #cond, __func__);

  • 在调用 event_errx 后,再次使用 fprintf 将相同的错误信息输出到标准错误输出(stderr)。这是为了防止用户自定义的错误处理程序可能试图返回控制权,确保错误信息一定会被输出。
    最后,调用 abort() 函数立即终止程序的执行。abort() 会导致程序异常退出,并生成一个核心转储(如果系统配置允许)


void event_errx(int eval, const char *fmt, ...)
{va_list ap;// 初始化可变参数列表va_start(ap, fmt);// 使用可变参数列表将格式化的错误信息输出到日志event_logv_(EVENT_LOG_ERR, NULL, fmt, ap);va_end(ap);// 结束可变参数处理// 退出程序并返回指定的错误码event_exit(eval);
}

该函数是可变参函数,相关注解见: [[可变参数]]

voidevent_logv_(int severity, const char *errstr, const char *fmt, va_list ap){char buf[1024];size_t len;if (severity == EVENT_LOG_DEBUG && !event_debug_get_logging_mask_())return;if (fmt != NULL)evutil_vsnprintf(buf, sizeof(buf), fmt, ap);elsebuf[0] = '\0';if (errstr) {len = strlen(buf);if (len < sizeof(buf) - 3) {evutil_snprintf(buf + len, sizeof(buf) - len, ": %s", errstr);}}event_log(severity, buf);}

EVBASE_ACQUIRE_LOCK N_ACTIVE_CALLBACKS

/** Lock an event_base, if it is set up for locking.  Acquires the lockin the base structure whose field is named 'lockvar'. */
#define EVBASE_ACQUIRE_LOCK(base, lockvar) do {				\EVLOCK_LOCK((base)->lockvar, 0);			\} while (0)

#define N_ACTIVE_CALLBACKS(base)					\((base)->event_count_active) //最大事件数量
/** Largest number of priorities that Libevent can support. */
#define EVENT_MAX_PRIORITIES 256
  /**Set the number of different event prioritiesBy default Libevent schedules all active events with the same priority.However, some time it is desirable to process some events with a higherpriority than others.  For that reason, Libevent supports strict priorityqueues.  Active events with a lower priority are always processed beforeevents with a higher priority.The number of different priorities can be set initially with theevent_base_priority_init() function.  This function should be calledbefore the first call to event_base_dispatch().  Theevent_priority_set() function can be used to assign a priority to anevent.  By default, Libevent assigns the middle priority to all eventsunless their priority is explicitly set.Note that urgent-priority events can starve less-urgent events: afterrunning all urgent-priority callbacks, Libevent checks for more urgentevents again, before running less-urgent events.  Less-urgent eventswill not have their callbacks run until there are no events more urgentthan them that want to be active.@param eb the event_base structure returned by event_base_new()@param npriorities the maximum number of priorities@return 0 if successful, or -1 if an error occurred@see event_priority_set()

TAILQ_ENTRY

//通过使用 TAILQ_ENTRY 宏,可以为指定的数据类型创建一个双向链表的入口和出口结构体,方便在链表中进行插入、删除和遍历等操作。
#define	_TAILQ_ENTRY(type, qual)					\
struct {								\qual type *tqe_next;		/* next element */		\qual type *qual *tqe_prev;	/* address of previous next element */\
}
#define TAILQ_ENTRY(type)	_TAILQ_ENTRY(struct type,)

qual 用于指定链表结构体成员的修饰符(它可以是 constvolatile 或其他限定符。)

  • tqe_next:指向链表中下一个元素的指针。

  • tqe_prev:指向链表中上一个元素的指针的地址。这里使用了一个指向指针的指针,即二级指针,用于在删除元素时修改前一个元素的 tqe_next 指针。

TAILQ_HEAD

#define TAILQ_HEAD(name, type)          \
struct name {                          \struct type *tqh_first;            /* 指向链表的第一个元素 */ \struct type **tqh_last;            /* 指向链表的最后一个元素的指针的指针 */ \
}

TAILQ_HEAD 是用于定义双向链表头结构的宏,使得管理链表的操作更加简单

  • tqh_first: 指向链表的第一个元素。对于空链表,它是 NULL

  • tqh_last: 指向链表的最后一个元素的指针的指针。在链表的最后一个元素中,tqh_last 指向链表中最后一个元素的指针(也就是指向该元素的指针的指针)。对于空链表,它指向 &tqh_first,即链表头结构中的 tqh_first

EVBASE_NEED_NOTIFY

/** Return true iff we need to notify the base's main thread about changes to* its state, because it's currently running the main loop in another* thread. Requires lock. */#define EVBASE_NEED_NOTIFY(base)             \
(evthread_id_fn_ != NULL &&          \(base)->running_loop &&          \(base)->th_owner_id != evthread_id_fn_())
  • evthread_id_fn_: 一个函数指针,用于获取当前线程的 ID。它用于确定事件循环是否在另一个线程中运行。

  • (base)->running_loop: 表示事件基础是否正在运行主事件循环。如果为 true,表示主循环正在运行中。

  • (base)->th_owner_id: 存储主事件循环线程的 ID。这个 ID 是在事件循环开始时设置的。

  • evthread_id_fn_(): 调用 evthread_id_fn_ 函数来获取当前线程的 ID。


  • evthread_id_fn_ != NULL: 确保线程 ID 函数指针有效,这意味着线程 ID 函数已经设置并可用。

  • (base)->running_loop: 确保事件循环确实在运行中。

  • (base)->th_owner_id != evthread_id_fn_(): 确保当前线程的 ID 与事件循环主线程的 ID 不同,表明主循环在另一个线程中运行。


这个宏的作用是检查是否需要通知主线程关于状态的变化,因为事件基础的主线程可能在不同的线程中运行。如果条件满足(即事件循环在另一个线程中运行且当前线程不是主线程),则返回 true,表示需要通知主线程。否则返回 false

EVBASE_RELEASE_LOCK EVLOCK_UNLOCK

/** 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)
/** Release a lock */#define EVLOCK_UNLOCK(lockvar,mode)                 \
do {                                \if (lockvar)                        \evthread_lock_fns_.unlock(mode, lockvar);   \} while (0)
  • lockvar: 具体的锁变量。这个变量是锁的实际对象,用于加锁和解锁。

  • mode: 解锁模式,这个参数通常用于指定解锁的方式,但在这段代码中它被设置为 0,具体模式取决于锁的实现。

  • evthread_lock_fns_.unlock: 这是一个函数指针,指向实际的解锁函数。evthread_lock_fns_ 是一个结构体,包含了各种锁操作的函数指针(例如加锁、解锁等)。

  • EVBASE_RELEASE_LOCK(base, lockvar): 这是一个高层次的宏,用于释放 event_base 的锁。它通过调用 EVLOCK_UNLOCK 实现具体的解锁操作。

  • EVLOCK_UNLOCK(lockvar, mode): 这是一个底层宏,实际执行解锁操作。它使用 evthread_lock_fns_.unlock 函数指针来解锁。mode 参数通常用于指定解锁的详细模式,但在这段代码中,它被设置为 0

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词