libuv学习笔记(18)

libuv学习笔记(18)

uv_fs_poll_t数据结构与相关函数

数据结构

typedef struct uv_fs_poll_s uv_fs_poll_t;

struct uv_fs_poll_s {
  UV_HANDLE_FIELDS//uv_handle_t成员
  /* Private, don't touch. */
  void* poll_ctx;
};
//内部数据结构
struct poll_ctx {
  uv_fs_poll_t* parent_handle; /* NULL if parent has been stopped or closed */
  int busy_polling;
  unsigned int interval;
  uint64_t start_time;
  uv_loop_t* loop;
  uv_fs_poll_cb poll_cb;
  uv_timer_t timer_handle;//定时器
  uv_fs_t fs_req; /* TODO(bnoordhuis) mark fs_req internal */
  uv_stat_t statbuf;
  char path[1]; /* variable length */
};

相关函数

初始化
int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle) {
  //简单的初始化handle
  uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_POLL);
  return 0;
}
开始监听
int uv_fs_poll_start(uv_fs_poll_t* handle,
                     uv_fs_poll_cb cb,
                     const char* path,
                     unsigned int interval) {
  struct poll_ctx* ctx;
  uv_loop_t* loop;
  size_t len;
  int err;
  if (uv__is_active(handle))
    return 0;
  loop = handle->loop;
  len = strlen(path);
  ctx = uv__calloc(1, sizeof(*ctx) + len);//分配内存,大小为结构体大小加上字符串长度
  if (ctx == NULL)
    return UV_ENOMEM;
  ctx->loop = loop;
  ctx->poll_cb = cb;
  ctx->interval = interval ? interval : 1;//设置间隔
  ctx->start_time = uv_now(loop);//记录起始时间
  ctx->parent_handle = handle;//与uv_fs_poll_t联系起来
  memcpy(ctx->path, path, len + 1);//路径
  //初始化定时器
  err = uv_timer_init(loop, &ctx->timer_handle);
  if (err < 0)
    goto error;
  ctx->timer_handle.flags |= UV__HANDLE_INTERNAL;//内部使用handle
  uv__handle_unref(&ctx->timer_handle);

  err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb);
  if (err < 0)
    goto error;
  handle->poll_ctx = ctx;
  uv__handle_start(handle);

  return 0;
error:
  uv__free(ctx);
  return err;
}
int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
  int err;
  //初始化请求
  uv_fs_req_init(loop, req, UV_FS_STAT, cb);

  err = fs__capture_path(req, path, NULL, cb != NULL);
  if (err) {
    return uv_translate_sys_error(err);
  }

  if (cb) {
    //QUEUE_FS_TP_JOB(loop, req);展开如下:
    do {                                                                   
      uv__req_register(loop, req); 
      //将uv__fs_work添加到线程池,uv__fs_work中会查询文件状态,uv__fs_done会调用poll_cb,其中会比较上一次与本次的文件状态,若状态改变会调用start的回调函数。poll_cb最终会再次开启定时器
      uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done);   
    } while (0)
    return 0;
  } else {
    fs__stat(req);
    return req->result;
  }
}
停止监听
int uv_fs_poll_stop(uv_fs_poll_t* handle) {
  struct poll_ctx* ctx;

  if (!uv__is_active(handle))
    return 0;

  ctx = handle->poll_ctx;
  assert(ctx != NULL);
  assert(ctx->parent_handle != NULL);
  ctx->parent_handle = NULL;
  handle->poll_ctx = NULL;

  //如果定时器为激活状态,那么关闭它
  if (uv__is_active(&ctx->timer_handle))
    uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
  uv__handle_stop(handle);
  return 0;
}

整个文件状态轮询是通过线程池与定时器实现的
1.首先向线程池注册一个任务uv__fs_work,在这个任务中会查询对应文件的状态,结果保存在uv_fs_t的statbuf中。
2.uv__fs_work完成之后,会通过loop的wq_async向loop发送异步唤醒请求,此处通过uv_mutex_lock来达到线程同步
3.在loop所在线程中,处理唤醒请求,调用uv__fs_done
4.uv__fs_done最终调用poll_cb,在poll_cb中会判断上一次的文件状态(存在poll_ctx的statbuf中)与本次文件状态是否有区别,如果有区别,就会调用用户的回调函数,并将statbuf赋值给poll_ctx的statbuf。poll_cb最终会再次激活定时器
5.定时器的回调函数timer_cb会调用uv_fs_stat再次重复上面的流程

uv_fs_poll_t所用的定时器是没有设置重复间隔的,所以只会执行一次,每次执行完之后,会再次激活。
只有uv__fs_work函数也就是查询文件状态的函数会在线程池中执行,其他的回调函数都在loop所在的线程池中执行,以此来达到线程池安全。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值