Skip to main content

2. 源码一览

一、概述 Libuv 采用了异步 (asynchronous), 事件驱动( event-driven ) 的编程风格, 其核心任务是为开人员提供了一套事件循环和基于 I/O (或其他活动)通知的回调函数, Libuv 提供了一套核心的工具集, 例如定时器, 非阻塞网络编程的支持, 异步访问文件系统, 子进程以及其他功能。

一、概述

Libuv 采用了异步 (asynchronous), 事件驱动( event-driven ) 的编程风格, 其核心任务是为开人员提供了一套事件循环和基于 I/O (或其他活动)通知的回调函数, Libuv 提供了一套核心的工具集, 例如定时器, 非阻塞网络编程的支持, 异步访问文件系统, 子进程以及其他功能。

二、I/O 复用机制和线程池

对于网络 I/O ,Libuv 根据将不同的操作系统提供的 I/O 多路复用机制进行了封装;对于文件 I/O、域名解析等,使用了线程池 (在 Libuv 0.10, Windows 上使用的是 QueueUserWorkItem 。但在 1.0 也采用和 UNIX 一样的线程池实现。)。当然,用户代码也可以使用 Libuv 提供的线程池。 Libuv 子系统

三、跨平台

Libuv 支持 Windows、Linux(Android)、AIX、SunOS(Solaris)、Darwin(macOS/iOS)、BSD(DragonFly、FreeBSD、OpenBSD、NetBSD),最近打算新增对 OS/390 的支持。 Libuv 支持的操作系统

Windows 和 UNIX/Linux 是两个” 敌对” 阵营,二者在 API 上就有较大差异; Linux 和 UNIX 之间,及 UNIX 实现之间,一些 API 、系统限制和选项也不尽相同。下表作出了部分对比:

OSI/O 多路复用线程Socketextern
WindowsIOCPWidows Threadwinsock动态库导入导出函数、数据、类 (Libuv 中主要是函数) 需:
__declspec(dllexport),
__declspec(dllimport),
直接使用源码当然不需要。
LinuxepollPOSIX Threadsocket"如果使用 GCC (使用 __GNUC__测试宏) 编译需:
__attribute__((visibility(""default"")))"
AIXIOCP ?同 Linux同 Linux同 Linux
SunOSevent ports同 Linux同 Linux同 Linux
BSDkqueue同 Linux同 Linux同 Linux
Darwin同 BSD同 Linux同 Linux同 Linux
OS/390----

四、第三方源码


Libuv 使用了少量的第三方源码。

源码目的作用备注
tree.h数据结构和算法提供伸展树 (Splay Tree) 和红黑树 ( R-B Tree ) 的数据结构宏。macOS 中的 Kernel.framework 也有该源码。
Libuv 只使用了红黑树。
inet.c可移植性提供 IP 地址转换函数。Linux/UNIX 对应的函数声明位于 /usr/lib/arpa/inet.h
Windows 虽然有 InetPton 和 InetNtop 等函数可用,也有 LibC for Windows ——不如直接使用一套源码省事。
stdint-msvc2008.h可移植性C 标准库的整数类型别名定义。"对于 Windows ,_MSC_VER 1600 (MS VC++ 10.0

五、代码风格

1、函数、结构和枚举的命名规则

uv_ 开头: 公开的函数、结构和枚举都以 uv_ (一个下划线) 开头的。 uv__ 开头: 内部使用的函数、结构和枚举,部分是以 uv__ (两个下划线) 开头的。 _cb 结尾: 函数指针。 _s 结尾: 结构声明。 _t 结尾: 使用 typedef 为结构体取的别名。

2、错误处理

一般情况下,Libuv 0.10 函数返回 0 表示成功, -1 表示失败,通过 uv_last_error 函数获取错误码。在 1.0 ,函数返回 0 表示成功,负数表示失败并对应 UV__E* 错误码; uv_last_error 函数已经在 1.0 被删除。 这里说的函数只要指部分以 int uv_* 格式命名的导出函数;详细的错误号定义见 uv-errno.h 文件;错误号到错误消息的转换、获取错误号对应的错误名分别见 uv_strerroruv_err_name 函数。

3、指针类型星号 (*) 的位置

这是一个要引起争论的问题。不吵。 Libuv 在定义指针类型变量、声明形参等时,将 * 放在类型后,这样比将 * 挨着变量名头在语义上更贴切。如:

uv_handle_t* h;

这需要注意不要在一行定义多个变量 (Libuv 中基本不会),否则代码就恶心了:

uv_handle_t* h1, *h2;

参考资料