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, ¤t_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);
}