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源码分析——从libuv说开来
- tinyweb: C语言 + libuv 开发的最精简的WebServer (附源码)
- 移植 libuv 到 Visual C++ 6.0 并支持在 Windows XP 系统下编译
- 基于libuv的最精简Web服务器:tinyweb v1 v2 v3 (C语言源码)
- libuv库学习笔记(1)
- libuv学习笔记(2)
- libuv学习笔记(3)
- libuv学习笔记(4)
- libuv学习笔记(5)
- libuv学习笔记(6)
- libuv学习笔记(7)
- 网络通讯和网络协议
- libuv入门(一)
- libuv网络库的TCP服务端与客户端
- libuv库TCP echo-server
- libuv库定时器的使用
- libuv的编译
- 开启core dump文件生成模式