1、說明
事件循環是 libuv 的核心功能,負責 IO 的輪詢和事件回調的調度。
2、數據類型
2.1、uv_loop_t
事件循環數據類型,結構體
uv_loop_t.data 用於傳遞用戶數據,libuv 不會觸碰
2.2、uv_walk_cb
傳遞給 uv_walk() 方法的回調函數類型
void (*uv_walk_cb)(uv_handle_t* handle, void* arg);
3、API
3.1、uv_loop_init
int uv_loop_init(uv_loop_t* loop);
初始化 uv_loop_t 結構體
要注意,調用之前需要先給 uv_loop_t 分配內存資源,否則會崩潰
3.2、uv_loop_configure
int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...);
設置事件循環配置,一般應該在第一次調用 uv_run() 之前執行
返回值: 0表示成功,錯誤則返回一個 UV_E 錯誤碼,UV_ENOSYS 表示平台不支持該事件循環配置
支持選項:
- UV_LOOP_BLOCK_SIGNAL :輪詢新事件時阻塞指定事件,uv_loop_configure 的第二個參數是信號編號;
- UV_METRICS_IDLE_TIME :在事件的提供者的事件循環中收集空閑時間,使用 uv_metrics_idle_time() 方法需要使用這個選項
3.3、uv_loop_close
int uv_loop_close(uv_loop_t* loop);
釋放所有內部循環資源
僅當所有循環完成並且所有打開的句柄和請求都已經關閉的時候才可調用此函數,否則將返回 UV_EBUSY
此函數返回后,用戶可以釋放為循環申請的內存
3.4、uv_default_loop
uv_loop_t* uv_default_loop(void);
返回 libuv 的默認事件循環,如果分配失敗了,可能返回NULL
這個方法是在整個應用程序中進行全局循環的一個便捷的方式,和自定義的事件循環相同
3.5、uv_run
int uv_run(uv_loop_t* loop, uv_run_mode mode);
運行事件循環,mode 指定運行模式,有如下幾種:
- UV_RUN_DEFAULT :運行事件循環,知道沒有活動的和被引用的句柄和請求。如果使用 uv_stop() 方法終止還未停止的循環(仍然有活動的和被引用的句柄和請求),則返回值非0,其他情況下返回0;
- UV_RUN_ONCE :只進行一次 IO 口輪詢,如果沒有需要執行的回調函數,這個方法會阻塞,返回0表示完成(沒有活動的和被引用的句柄和請求),返回非0表示需要進行更多的回調(此時,需要再次進行事件循環);
- UV_RUN_NOWAIT :和 UV_RUN_ONCE 的區別是,不會阻塞;
uv_run() 方法是不可重入的,它不能作為回調函數被調用
3.6、uv_loop_alive
int uv_loop_alive(const uv_loop_t* loop);
判斷事件循環是否還在活動,返回非0表示還在活動
有以下幾種情況之一表示還在活動:
- 有被引用的活動句柄或者活動請求;
- 正在關閉的句柄;
3.7、uv_stop
void uv_stop(uv_loop_t* loop);
停止事件循環,會讓 uv_run() 方法盡快結束
該方法調用之后,下次事件循環迭代之前結束循環,正在進行的事件循環仍然繼續
如果該函數在 IO 阻塞之前執行,則在當前的事件迭代中, IO 不會被阻塞
3.8、uv_loop_size
size_t uv_loop_size(void);
返回 uv_loop_t 結構體 size
3.9、uv_backend_fd
int uv_backend_fd(const uv_loop_t* loop);
獲取后端文件描述符,僅使用於 kqueue、epoll 和 事件端口
該方法可以和 run(loop, UV_RUN_NOWAIT) 一起聯合使用,在一個線程中輪詢 IO 和處理回調
3.10、uv_backend_timeout
int uv_backend_timeout(const uv_loop_t* loop);
獲取 IO 輪詢超時時間,單位為毫秒,沒有超時時返回 -1
3.11、uv_now
uint64_t uv_now(const uv_loop_t* loop);
返回當前的時間戳,單位毫秒
時間戳在事件循環開始時緩存
3.12、uv_update_time
void uv_update_time(uv_loop_t* loop);
更新事件循環的時間戳,會影響 uv_now() 的返回值,libuv 會在事件循環開始時緩存當前時間,以減少系統的時間相關的方法的調用
通常情況下不需要調用此方法,除了事件循環中的某個回調會阻塞相當長的時間,這個所謂的相當長的時間是有些主觀的,可能是一毫秒或者更長
3.13、uv_walk
void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg);
遍歷句柄列表,執行回調
arg 參數會傳遞給回調函數
void (*uv_walk_cb)(uv_handle_t* handle, void* arg);
handle 為遍歷中的某個句柄
3.14、uv_loop_fork
int uv_loop_fork(uv_loop_t* loop);
在調用 fork(2) 之后,如果有必要,在子進程中重新初始化內核狀態
在子進程中以觀察者的身份繼續事件循環
如果你想繼續在子進程中使用事件循環,包括默認的事件循環(盡管不想在父進程中使用它),那么,在每個父進程中創建的事件循環中顯示地調用此方法是很有必要的
該方法必須在 uv_run() ,或者其他想要在子進程中調用其他API之前調用。如果不這樣做,可將將導致一些未知的錯誤,比如事件被重復交給父進程和子進程,或者子進程異常退出
可以的話,最好在子進程中創建一個新的循環,而不是重復使用父進程創建的循環。在 fork 子進程之后,並在子進程中創建的新的循環不應該使用此方法
該方法不適用於windows操作系統,他會返回 UV_ENOSYS
需要注意的是,該方法可能存在BUG
3.15、uv_loop_get_data
void* uv_loop_get_data(const uv_loop_t* loop);
返回 loop->data
3.16、uv_loop_set_data
void* uv_loop_set_data(uv_loop_t* loop, void* data);
設置 loop->data 的值