libuv学习笔记(9)

来源:互联网 发布:pdg转pdf软件 编辑:程序博客网 时间:2024/05/16 23:33

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);  }}
0 0