您的位置:首页 > 其它

libuv学习笔记(9)

2016-06-14 11:41 288 查看

libuv学习笔记(9)

uv_signal_t数据结构与相关函数

uv_signal_t数据结构

typedef struct uv_signal_s uv_signal_t;
struct uv_signal_s {
UV_HANDLE_FIELDS//uv_handle_t的成员,此处不再展开
uv_signal_cb signal_cb;//回调函数
int signum;//信号
//UV_SIGNAL_PRIVATE_FIELDS宏展开:
RB_ENTRY(uv_signal_s) tree_entry;//红黑树节点
struct uv_req_s signal_req;//请求
unsigned long pending_signum;
};


相关函数

1.初始化,导出函数,在uv.h中声明,signal.c中定义

int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle)
{
uv_req_t* req;
//初始化handle,添加到loop的handle列表,改变状态为引用状态
uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
handle->pending_signum = 0;
handle->signum = 0;
handle->signal_cb = NULL;

req = &handle->signal_req;

uv_req_init(loop, req);//初始化请求
req->type = UV_SIGNAL_REQ;//设置请求类型
req->data = handle;

return 0;
}


2.开始。导出函数,在uv.h中声明,signal.c中定义

int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
int err;

//将信号值设为0,直接返回错误
//如果signum是无效值,那么uv__signal_register会检测出来
if (signum == 0) {
return UV_EINVAL;
}

//如果已经监控了这个信号,不会进入注销与注册流程。
if (signum == handle->signum) {
handle->signal_cb = signal_cb;
return 0;
}

//如果已经开始监控了,先停止
if (handle->signum != 0) {
int r = uv_signal_stop(handle);
/* uv_signal_stop is infallible. */
assert(r == 0);
}
//进入临界区
EnterCriticalSection(&uv__signal_lock);//此临界区是全局的

err = uv__signal_register(signum);//注册信号
if (err) {
/* Uh-oh, didn't work. */
LeaveCriticalSection(&uv__signal_lock);
return uv_translate_sys_error(err);
}

handle->signum = signum;
//将信号插入红黑树,key的比较函数为uv__signal_compare
RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);

LeaveCriticalSection(&uv__signal_lock);

handle->signal_cb = signal_cb;
uv__handle_start(handle);//状态变为UV__HANDLE_ACTIVE,loop活动handle计数加一

return 0;
}


uv__signal_register

static int uv__signal_register(int signum)
{
switch (signum) {
//控制台相关的信号,通过安装控制台钩子来实现
case SIGINT:
case SIGBREAK:
case SIGHUP:
return uv__signal_register_control_handler();

case SIGWINCH:
/* SIGWINCH is generated in tty.c. No need to register anything. */
return 0;

case SIGILL:
case SIGABRT_COMPAT:
case SIGFPE:
case SIGSEGV:
case SIGTERM:
case SIGABRT:
/* Signal is never raised. */
return 0;

default:
/* Invalid signal. */
return ERROR_INVALID_PARAMETER;
}
}


uv__signal_register_control_handler(),安装控制台事件钩子处理控制台事件

static int uv__signal_register_control_handler() {
//调用本函数时,uv__signal_lock必须锁定

//如果已经添加了钩子,那么只用递增引用计数
if (uv__signal_control_handler_refs > 0) {
uv__signal_control_handler_refs++;
return 0;
}
//安装控制台事件钩子处理控制台程序事件
//回调函数会通过uv__signal_dispatch分发处理信号
if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
return GetLastError();
uv__signal_control_handler_refs++;
return 0;
}


uv__signal_dispatch分发处理信号

int uv__signal_dispatch(int signum)
{
uv_signal_t lookup;
uv_signal_t* handle;
int dispatched = 0;
EnterCriticalSection(&uv__signal_lock);
lookup.signum = signum;
lookup.loop = NULL;
//遍历信号红黑树处理
//先找到第一个,然后依次比较下一个,直到信号值不相等
for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup);
handle != NULL && handle->signum == signum;
handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) {
unsigned long previous = InterlockedExchange(
(volatile LONG*) &handle->pending_signum, signum);
//没有正在处理的信号,向iocp端口发送事件通知,以便uv_run捕获处理,也就是说,有可能收到了多次信号,
//但是可能只处理了一次
if (!previous) {
POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req);
}
dispatched = 1;
}
LeaveCriticalSection(&uv__signal_lock);
return dispatched;
}


在uv_run的io轮询中会获取uv__signal_dispatch发送的通知,并通过lpOverlapped获取对应的uv_req_t请求,接着在下一个迭代中通过uv_process_reqs处理这个请求

对于uv_signal_req类型的请求,最终会调用uv_process_signal_req

void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
uv_req_t* req)
{
long dispatched_signum;

assert(handle->type == UV_SIGNAL);
assert(req->type == UV_SIGNAL_REQ);
//将uv_signal_t的等待处理的信号设为0
dispatched_signum = InterlockedExchange(
(volatile LONG*) &handle->pending_signum, 0);
assert(dispatched_signum != 0);

//信号相同,调用回调函数
if (dispatched_signum == handle->signum)
handle->signal_cb(handle, dispatched_signum);
//如果正在关闭,就添加到loop的关闭列表,比如在收到了信号但是还未处理的情况下调用了uv_close
if (handle->flags & UV__HANDLE_CLOSING) {
/* When it is closing, it must be stopped at this point. */
assert(handle->signum == 0);
uv_want_endgame(loop, (uv_handle_t*) handle);
}
}


3.停止监控。导出函数,在uv.h中声明,signal.c中定义

int uv_signal_stop(uv_signal_t* handle)
{
uv_signal_t* removed_handle;

//如果没有开始监控,直接返回
if (handle->signum == 0)
return 0;
//进入临界区
EnterCriticalSection(&uv__signal_lock);
//注销监控,递减引用计数,如果为0,卸载控制台程序钩子
uv__signal_unregister(handle->signum);
//从红黑树去掉
removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle);
assert(removed_handle == handle);

LeaveCriticalSection(&uv__signal_lock);

handle->signum = 0;
//
uv__handle_stop(handle);

return 0;
}


通过uv_close关闭

最终会调用

void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle)
{
uv_signal_stop(handle);//先停止
uv__handle_closing(handle);//handle状态变为UV_HANDLE_CLOSING

if (handle->pending_signum == 0) {
//如果没有等待处理的信号了,那么直接添加到loop的关闭handle队列,否则就需要在处理信号时添加到关闭队列
//了,参考uv_process_signal_req
uv_want_endgame(loop, (uv_handle_t*) handle);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  libuv uv-signal