libuv学习笔记(14)

libuv学习笔记(14)

uv_pipe_t数据结构以及相关函数(1)

数据结构

typedef struct uv_pipe_s uv_pipe_t;

struct uv_pipe_s {
  UV_HANDLE_FIELDS//uv_handle_t的成员
  UV_STREAM_FIELDS//uv_stream_t的相关成员
  int ipc; 
  //UV_PIPE_PRIVATE_FIELDS展开:
  HANDLE handle;                                                              
  WCHAR* name;                                                               
  union {                                                                    
    struct { //接受用到   服务端相关功能
      int pending_instances;                                               
      uv_pipe_accept_t* accept_reqs;                                          
      uv_pipe_accept_t* pending_accepts;
    } serv;                                 
    struct { //连接用到   客户端相关功能
      uv_timer_t* eof_timer;                                                     
      uv_write_t ipc_header_write_req;                                          
      int ipc_pid;                                                               
      uint64_t remaining_ipc_rawdata_bytes;                                       
      struct {                                                                    
        void* queue[2];                                                           
        int queue_len;                                                          
      } pending_ipc_info;                                                      
      uv_write_t* non_overlapped_writes_tail;                                 
      uv_mutex_t readfile_mutex;                                              
      volatile HANDLE readfile_thread;
    }  conn;                             
  } pipe;

};

相关函数

初始化。导出函数,uv.h中声明,pipe.c中定义
int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) 
{
  //流初始化。pipe也是流的一种实现
  uv_stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
  handle->reqs_pending = 0;
  handle->handle = INVALID_HANDLE_VALUE;
  handle->name = NULL;
  handle->pipe.conn.ipc_pid = 0;
  handle->pipe.conn.remaining_ipc_rawdata_bytes = 0;
  QUEUE_INIT(&handle->pipe.conn.pending_ipc_info.queue);
  handle->pipe.conn.pending_ipc_info.queue_len = 0;
  handle->ipc = ipc;
  handle->pipe.conn.non_overlapped_writes_tail = NULL;
  handle->pipe.conn.readfile_thread = NULL;
  //写请求初始化
  uv_req_init(loop, (uv_req_t*) &handle->pipe.conn.ipc_header_write_req);
  return 0;
}
打开一个文件描述符作为uv_pipe_t.导出函数,uv.h中声明,pipe.c中定义
int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
  HANDLE os_handle = uv__get_osfhandle(file);
  NTSTATUS nt_status;
  IO_STATUS_BLOCK io_status;
  FILE_ACCESS_INFORMATION access;
  DWORD duplex_flags = 0;

  if (os_handle == INVALID_HANDLE_VALUE)
    return UV_EBADF;

  //为了避免关闭stdio的文件描述符0-2,使用复制的文件描述符
  if (file <= 2) {
    if (!DuplicateHandle(INVALID_HANDLE_VALUE,
                         os_handle,
                         INVALID_HANDLE_VALUE,
                         &os_handle,
                         0,
                         FALSE,
                         DUPLICATE_SAME_ACCESS))
      return uv_translate_sys_error(GetLastError());
    file = -1;
  }
  //确定句柄权限。
  nt_status = pNtQueryInformationFile(os_handle,
                                      &io_status,
                                      &access,
                                      sizeof(access),
                                      FileAccessInformation);
  if (nt_status != STATUS_SUCCESS)
    return UV_EINVAL;

  if (pipe->ipc) {//跨进程的管道,必须可写 可读
    if (!(access.AccessFlags & FILE_WRITE_DATA) ||
        !(access.AccessFlags & FILE_READ_DATA)) {
      return UV_EINVAL;
    }
  }
  if (access.AccessFlags & FILE_WRITE_DATA)
    duplex_flags |= UV_HANDLE_WRITABLE;
  if (access.AccessFlags & FILE_READ_DATA)
    duplex_flags |= UV_HANDLE_READABLE;
  //设置pipe的句柄
  if (os_handle == INVALID_HANDLE_VALUE ||
      uv_set_pipe_handle(pipe->loop,
                         pipe,
                         os_handle,
                         file,
                         duplex_flags) == -1) {
    return UV_EINVAL;
  }
  //以链接模式初始化pipe
  uv_pipe_connection_init(pipe);

  if (pipe->ipc) {
    assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
    pipe->pipe.conn.ipc_pid = uv_parent_pid();
    assert(pipe->pipe.conn.ipc_pid != -1);
  }
  return 0;
}

设置pipe句柄

static int uv_set_pipe_handle(uv_loop_t* loop,
                              uv_pipe_t* handle,
                              HANDLE pipeHandle,
                              int fd,
                              DWORD duplex_flags) {
  NTSTATUS nt_status;
  IO_STATUS_BLOCK io_status;
  FILE_MODE_INFORMATION mode_info;
  DWORD mode = PIPE_READMODE_BYTE | PIPE_WAIT;
  DWORD current_mode = 0;
  DWORD err = 0;

  if (!(handle->flags & UV_HANDLE_PIPESERVER) &&//非服务端模式
      handle->handle != INVALID_HANDLE_VALUE)//句柄不为空
    return UV_EBUSY;

  if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
    err = GetLastError();
    if (err == ERROR_ACCESS_DENIED) {
      /*
       * SetNamedPipeHandleState can fail if the handle doesn't have either
       * GENERIC_WRITE  or FILE_WRITE_ATTRIBUTES.
       * But if the handle already has the desired wait and blocking modes
       * we can continue.
       */
      if (!GetNamedPipeHandleState(pipeHandle, &current_mode, NULL, NULL,
                                   NULL, NULL, 0)) {
        return -1;
      } else if (current_mode & PIPE_NOWAIT) {
        SetLastError(ERROR_ACCESS_DENIED);
        return -1;
      }
    } else {
      /* If this returns ERROR_INVALID_PARAMETER we probably opened
       * something that is not a pipe. */
      if (err == ERROR_INVALID_PARAMETER) {
        SetLastError(WSAENOTSOCK);
      }
      return -1;
    }
  }

  /* Check if the pipe was created with FILE_FLAG_OVERLAPPED. */
  nt_status = pNtQueryInformationFile(pipeHandle,
                                      &io_status,
                                      &mode_info,
                                      sizeof(mode_info),
                                      FileModeInformation);
  if (nt_status != STATUS_SUCCESS) {
    return -1;
  }

  if (mode_info.Mode & FILE_SYNCHRONOUS_IO_ALERT ||
      mode_info.Mode & FILE_SYNCHRONOUS_IO_NONALERT) {
    /* Non-overlapped pipe. */
    handle->flags |= UV_HANDLE_NON_OVERLAPPED_PIPE;
  } else {
    /* Overlapped pipe.  Try to associate with IOCP. */
    if (CreateIoCompletionPort(pipeHandle,
                               loop->iocp,
                               (ULONG_PTR)handle,
                               0) == NULL) {
      handle->flags |= UV_HANDLE_EMULATE_IOCP;
    }
  }

  handle->handle = pipeHandle;
  handle->u.fd = fd;
  handle->flags |= duplex_flags;
  return 0;
}
绑定

创建一个pipe服务端

int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
  uv_loop_t* loop = handle->loop;
  int i, err, nameSize;
  uv_pipe_accept_t* req;
  if (handle->flags & UV_HANDLE_BOUND) {
    return UV_EINVAL;
  }
  if (!name) {
    return UV_EINVAL;
  }
  if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
    handle->pipe.serv.pending_instances = default_pending_pipe_instances;
  }
  //根据pending_instances 申请内部accept请求的内存
  handle->pipe.serv.accept_reqs = (uv_pipe_accept_t*)
    uv__malloc(sizeof(uv_pipe_accept_t) * handle->pipe.serv.pending_instances);
  if (!handle->pipe.serv.accept_reqs) {
    uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
  }
  //初始化内部accept
  for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
    req = &handle->pipe.serv.accept_reqs[i];
    uv_req_init(loop, (uv_req_t*) req);
    req->type = UV_ACCEPT;
    req->data = handle;
    req->pipeHandle = INVALID_HANDLE_VALUE;
    req->next_pending = NULL;
  }
  //将名字从utf8转到utf16
  nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR);
  handle->name = (WCHAR*)uv__malloc(nameSize);
  if (!handle->name) {
    uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
  }
  if (!MultiByteToWideChar(CP_UTF8,
                           0,
                           name,
                           -1,
                           handle->name,
                           nameSize / sizeof(WCHAR))) {
    err = GetLastError();
    goto error;
  }
  //通过FILE_FLAG_FIRST_PIPE_INSTANCE标记创建管道,如果失败,说明管道已经存在
  handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
      PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
      FILE_FLAG_FIRST_PIPE_INSTANCE,
      PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
      PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);

  if (handle->pipe.serv.accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) {
    err = GetLastError();
    if (err == ERROR_ACCESS_DENIED) {
      err = WSAEADDRINUSE;  /* Translates to UV_EADDRINUSE. */
    } else if (err == ERROR_PATH_NOT_FOUND || err == ERROR_INVALID_NAME) {
      err = WSAEACCES;  /* Translates to UV_EACCES. */
    }
    goto error;
  }
  //将新建的管道与uv_pipe_t联系起来
  if (uv_set_pipe_handle(loop,
                         handle,
                         handle->pipe.serv.accept_reqs[0].pipeHandle,
                         -1,
                         0)) {
    err = GetLastError();
    goto error;
  }

  handle->pipe.serv.pending_accepts = NULL;
  handle->flags |= UV_HANDLE_PIPESERVER;
  handle->flags |= UV_HANDLE_BOUND;

  return 0;

error:
  if (handle->name) {
    uv__free(handle->name);
    handle->name = NULL;
  }

  if (handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) {
    CloseHandle(handle->pipe.serv.accept_reqs[0].pipeHandle);
    handle->pipe.serv.accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE;
  }

  return uv_translate_sys_error(err);
}
链接命名管道

连接一个命名管道

void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
    const char* name, uv_connect_cb cb) {
  uv_loop_t* loop = handle->loop;
  int err, nameSize;
  HANDLE pipeHandle = INVALID_HANDLE_VALUE;
  DWORD duplex_flags;
  //初始化请求
  uv_req_init(loop, (uv_req_t*) req);
  req->type = UV_CONNECT;
  req->handle = (uv_stream_t*) handle;
  req->cb = cb;
  //utf8转为utf16
  nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR);
  handle->name = (WCHAR*)uv__malloc(nameSize);
  if (!handle->name) {
    uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
  }
  if (!MultiByteToWideChar(CP_UTF8,
                           0,
                           name,
                           -1,
                           handle->name,
                           nameSize / sizeof(WCHAR))) {
    err = GetLastError();
    goto error;
  }
  //打开已存在的管道
  pipeHandle = open_named_pipe(handle->name, &duplex_flags);
  if (pipeHandle == INVALID_HANDLE_VALUE) {
    if (GetLastError() == ERROR_PIPE_BUSY) {
      //管道存在,但是没有可用实例,向线程池注册一个任务,等待管道可用
      if (!QueueUserWorkItem(&pipe_connect_thread_proc,
                             req,
                             WT_EXECUTELONGFUNCTION)) {
        err = GetLastError();
        goto error;
      }
      REGISTER_HANDLE_REQ(loop, handle, req);
      handle->reqs_pending++;
      return;
    }
    err = GetLastError();
    goto error;
  }
  assert(pipeHandle != INVALID_HANDLE_VALUE);
  //将获取的管道与uv_pipe_t联系起来
  if (uv_set_pipe_handle(loop,
                         (uv_pipe_t*) req->handle,
                         pipeHandle,
                         -1,
                         duplex_flags)) {
    err = GetLastError();
    goto error;
  }
  SET_REQ_SUCCESS(req);
  //将请求添加到loop的请求队列
  uv_insert_pending_req(loop, (uv_req_t*) req);
  handle->reqs_pending++;
  REGISTER_HANDLE_REQ(loop, handle, req);
  return;

error:
  if (handle->name) {
    uv__free(handle->name);
    handle->name = NULL;
  }

  if (pipeHandle != INVALID_HANDLE_VALUE) {
    CloseHandle(pipeHandle);
  }

  /* Make this req pending reporting an error. */
  SET_REQ_ERROR(req, err);
  uv_insert_pending_req(loop, (uv_req_t*) req);
  handle->reqs_pending++;
  REGISTER_HANDLE_REQ(loop, handle, req);
  return;
}

uv_process_req中队connect请求的处理,最终会调用

void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
    uv_connect_t* req) {
  int err;
  assert(handle->type == UV_NAMED_PIPE);
  //取消请求注册
  UNREGISTER_HANDLE_REQ(loop, handle, req);
  //调用回调函数
  if (req->cb) {
    err = 0;
    if (REQ_SUCCESS(req)) {
      uv_pipe_connection_init(handle);
    } else {
      err = GET_REQ_ERROR(req);
    }
    req->cb(req, uv_translate_sys_error(err));
  }

  DECREASE_PENDING_REQ_COUNT(handle);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值