libuv学习笔记(18)

来源:互联网 发布:mac上pdf软件 编辑:程序博客网 时间:2024/05/16 18:43

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
原创粉丝点击