void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) { if (handle->flags & UV_HANDLE_READING) { handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(loop, handle); } if (handle->flags & UV_HANDLE_LISTENING) { handle->flags &= ~UV_HANDLE_LISTENING; DECREASE_ACTIVE_COUNT(loop, handle); } uv_pipe_cleanup(loop, handle); if (handle->reqs_pending == 0) { uv_want_endgame(loop, (uv_handle_t*) handle); } handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); uv__handle_closing(handle); }
void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { uv_async_t* async; uv_stream_t* stream; uv_process_t* process; handle->close_cb = close_cb; switch (handle->type) { case UV_NAMED_PIPE: uv_pipe_cleanup((uv_pipe_t*)handle); /* Fall through. */ case UV_TTY: case UV_TCP: stream = (uv_stream_t*)handle; uv_read_stop(stream); ev_io_stop(stream->loop->ev, &stream->write_watcher); uv__close(stream->fd); stream->fd = -1; if (stream->accepted_fd >= 0) { uv__close(stream->accepted_fd); stream->accepted_fd = -1; } assert(!ev_is_active(&stream->read_watcher)); assert(!ev_is_active(&stream->write_watcher)); break; case UV_UDP: uv__udp_start_close((uv_udp_t*)handle); break; case UV_PREPARE: uv_prepare_stop((uv_prepare_t*) handle); break; case UV_CHECK: uv_check_stop((uv_check_t*) handle); break; case UV_IDLE: uv_idle_stop((uv_idle_t*) handle); break; case UV_ASYNC: async = (uv_async_t*)handle; ev_async_stop(async->loop->ev, &async->async_watcher); ev_ref(async->loop->ev); break; case UV_TIMER: uv_timer_stop((uv_timer_t*)handle); break; case UV_PROCESS: process = (uv_process_t*)handle; ev_child_stop(process->loop->ev, &process->child_watcher); break; case UV_FS_EVENT: uv__fs_event_destroy((uv_fs_event_t*)handle); break; default: assert(0); } handle->flags |= UV_CLOSING; /* This is used to call the on_close callback in the next loop. */ ev_idle_start(handle->loop->ev, &handle->next_watcher); ev_feed_event(handle->loop->ev, &handle->next_watcher, EV_IDLE); assert(ev_is_pending(&handle->next_watcher)); }
static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) { char pipe_name[64]; SECURITY_ATTRIBUTES sa; DWORD server_access = 0; DWORD client_access = 0; HANDLE child_pipe = INVALID_HANDLE_VALUE; if (flags & UV_READABLE_PIPE) { server_access |= PIPE_ACCESS_OUTBOUND; client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; } if (flags & UV_WRITABLE_PIPE) { server_access |= PIPE_ACCESS_INBOUND; client_access |= GENERIC_WRITE; } /* Create server pipe handle. */ if (uv_stdio_pipe_server(loop, server_pipe, server_access, pipe_name, sizeof(pipe_name)) < 0) { goto error; } /* Create child pipe handle. */ sa.nLength = sizeof sa; sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; child_pipe = CreateFileA(pipe_name, client_access, 0, &sa, OPEN_EXISTING, server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0, NULL); if (child_pipe == INVALID_HANDLE_VALUE) { uv__set_sys_error(loop, GetLastError()); goto error; } #ifndef NDEBUG /* Validate that the pipe was opened in the right mode. */ { DWORD mode; BOOL r = GetNamedPipeHandleState(child_pipe, &mode, NULL, NULL, NULL, NULL, 0); assert(r == TRUE); assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT)); } #endif /* Do a blocking ConnectNamedPipe. This should not block because we have */ /* both ends of the pipe created. */ if (!ConnectNamedPipe(server_pipe->handle, NULL)) { if (GetLastError() != ERROR_PIPE_CONNECTED) { uv__set_sys_error(loop, GetLastError()); goto error; } } *child_pipe_ptr = child_pipe; return 0; error: if (server_pipe->handle != INVALID_HANDLE_VALUE) { uv_pipe_cleanup(loop, server_pipe); } if (child_pipe != INVALID_HANDLE_VALUE) { CloseHandle(child_pipe); } return -1; }
static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) { char pipe_name[64]; SECURITY_ATTRIBUTES sa; DWORD server_access = 0; DWORD client_access = 0; HANDLE child_pipe = INVALID_HANDLE_VALUE; int err; if (flags & UV_READABLE_PIPE) { /* The server needs inbound access too, otherwise CreateNamedPipe() */ /* won't give us the FILE_READ_ATTRIBUTES permission. We need that to */ /* probe the state of the write buffer when we're trying to shutdown */ /* the pipe. */ server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND; client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; } if (flags & UV_WRITABLE_PIPE) { server_access |= PIPE_ACCESS_INBOUND; client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES; } /* Create server pipe handle. */ err = uv_stdio_pipe_server(loop, server_pipe, server_access, pipe_name, sizeof(pipe_name)); if (err) goto error; /* Create child pipe handle. */ sa.nLength = sizeof sa; sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; child_pipe = CreateFileA(pipe_name, client_access, 0, &sa, OPEN_EXISTING, server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0, NULL); if (child_pipe == INVALID_HANDLE_VALUE) { err = GetLastError(); goto error; } #ifndef NDEBUG /* Validate that the pipe was opened in the right mode. */ { DWORD mode; BOOL r = GetNamedPipeHandleState(child_pipe, &mode, NULL, NULL, NULL, NULL, 0); assert(r == TRUE); assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT)); } #endif /* Do a blocking ConnectNamedPipe. This should not block because we have */ /* both ends of the pipe created. */ if (!ConnectNamedPipe(server_pipe->handle, NULL)) { if (GetLastError() != ERROR_PIPE_CONNECTED) { err = GetLastError(); goto error; } } /* The server end is now readable and/or writable. */ if (flags & UV_READABLE_PIPE) server_pipe->flags |= UV_HANDLE_WRITABLE; if (flags & UV_WRITABLE_PIPE) server_pipe->flags |= UV_HANDLE_READABLE; *child_pipe_ptr = child_pipe; return 0; error: if (server_pipe->handle != INVALID_HANDLE_VALUE) { uv_pipe_cleanup(loop, server_pipe); } if (child_pipe != INVALID_HANDLE_VALUE) { CloseHandle(child_pipe); } return err; }