libuv学习笔记(9)

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);
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值