/* the actual thread entrypoint passed to pthread_create() */ static void *uv__thread_run(void *arg) { /* synchronously get the entrypoint and call it */ uv_thread_shared_t *hnd = (uv_thread_shared_t *)arg; pthread_mutex_lock(&hnd->mtx); uv_thread_run thread_run = hnd->options->thread_run; void *thread_arg = hnd->options->thread_arg; /* ... any other processing depending on thread or options here ... */ pthread_cond_signal(&hnd->cond); pthread_mutex_unlock(&hnd->mtx); void *result = (*thread_run)(hnd, thread_arg); /* close any pipes created */ if(hnd->stdin_fd != -1) uv__close(hnd->stdin_fd); if(hnd->stdout_fd != -1) uv__close(hnd->stdout_fd); if(hnd->stderr_fd != -1) uv__close(hnd->stderr_fd); /* synchronously notify exit to the client event loop */ pthread_mutex_lock(&hnd->mtx); uv_thread_t *thread = hnd->thread_handle; if(thread) { /* copy these before they disappear ... */ thread->exit_status = hnd->exit_status; thread->term_signal = hnd->term_signal; ev_async_send(thread->loop->ev, &thread->thread_watcher); } hnd->thread_id = 0; pthread_mutex_unlock(&hnd->mtx); /* if the handle had gone already, delete shared handle */ if(!thread) uv__thread_shared_delete(hnd); return result; }
void uv__stream_close(uv_stream_t* handle) { unsigned int i; uv__stream_queued_fds_t* queued_fds; uv__io_close(handle->loop, &handle->io_watcher); uv_read_stop(handle); uv__handle_stop(handle); if (handle->io_watcher.fd != -1) { /* Don't close stdio file descriptors. Nothing good comes from it. */ if (handle->io_watcher.fd > STDERR_FILENO) uv__close(handle->io_watcher.fd); handle->io_watcher.fd = -1; } if (handle->accepted_fd != -1) { uv__close(handle->accepted_fd); handle->accepted_fd = -1; } /* Close all queued fds */ if (handle->queued_fds != NULL) { queued_fds = (uv__stream_queued_fds_t*)handle->queued_fds; for (i = 0; i < queued_fds->offset; i++) { uv__close(queued_fds->fds[i]); } free(handle->queued_fds); handle->queued_fds = NULL; } assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT)); }
void uv__platform_loop_delete(uv_loop_t* loop) { if (loop->fs_fd != -1) { uv__close(loop->fs_fd); loop->fs_fd = -1; } if (loop->backend_fd != -1) { uv__close(loop->backend_fd); loop->backend_fd = -1; } }
void uv__async_stop(uv_loop_t* loop, struct uv__async* wa) { if (wa->io_watcher.fd == -1) return; if (wa->wfd != -1) { if (wa->wfd != wa->io_watcher.fd) uv__close(wa->wfd); wa->wfd = -1; } uv__io_stop(loop, &wa->io_watcher, POLLIN); uv__close(wa->io_watcher.fd); wa->io_watcher.fd = -1; }
void uv__async_stop(uv_loop_t* loop) { if (loop->async_io_watcher.fd == -1) return; if (loop->async_wfd != -1) { if (loop->async_wfd != loop->async_io_watcher.fd) uv__close(loop->async_wfd); loop->async_wfd = -1; } uv__io_stop(loop, &loop->async_io_watcher, POLLIN); uv__close(loop->async_io_watcher.fd); loop->async_io_watcher.fd = -1; }
void uv__udp_destroy(uv_udp_t* handle) { uv_udp_send_t* req; ngx_queue_t* q; uv__udp_run_completed(handle); while (!ngx_queue_empty(&handle->write_queue)) { q = ngx_queue_head(&handle->write_queue); ngx_queue_remove(q); req = ngx_queue_data(q, uv_udp_send_t, queue); if (req->send_cb) { /* FIXME proper error code like UV_EABORTED */ uv__set_artificial_error(handle->loop, UV_EINTR); req->send_cb(req, -1); } } /* Now tear down the handle. */ handle->flags = 0; handle->recv_cb = NULL; handle->alloc_cb = NULL; /* but _do not_ touch close_cb */ if (handle->fd != -1) { uv__close(handle->fd); handle->fd = -1; } uv__udp_watcher_stop(handle, &handle->read_watcher); uv__udp_watcher_stop(handle, &handle->write_watcher); }
static int new_inotify_fd(void) { int err; int fd; fd = uv__inotify_init1(UV__IN_NONBLOCK | UV__IN_CLOEXEC); if (fd != -1) return fd; if (errno != ENOSYS) return -errno; fd = uv__inotify_init(); if (fd == -1) return -errno; err = uv__cloexec(fd, 1); if (err == 0) err = uv__nonblock(fd, 1); if (err) { uv__close(fd); return err; } return fd; }
/* Open a socket in non-blocking close-on-exec mode, atomically if possible. */ int uv__socket(int domain, int type, int protocol) { int sockfd; int err; #if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC) sockfd = socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); if (sockfd != -1) return sockfd; if (errno != EINVAL) return -errno; #endif sockfd = socket(domain, type, protocol); if (sockfd == -1) return -errno; err = uv__nonblock(sockfd, 1); if (err == 0) err = uv__cloexec(sockfd, 1); if (err) { uv__close(sockfd); return err; } #if defined(SO_NOSIGPIPE) { int on = 1; setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on)); } #endif return sockfd; }
int uv__open_cloexec(const char* path, int flags) { int err; int fd; #if defined(UV__O_CLOEXEC) static int no_cloexec; if (!no_cloexec) { fd = open(path, flags | UV__O_CLOEXEC); if (fd != -1) return fd; if (errno != EINVAL) return -errno; /* O_CLOEXEC not supported. */ no_cloexec = 1; } #endif fd = open(path, flags); if (fd == -1) return -errno; err = uv__cloexec(fd, 1); if (err) { uv__close(fd); return err; } return fd; }
/* Open a socket in non-blocking close-on-exec mode, atomically if possible. */ int uv__socket(int domain, int type, int protocol) { int sockfd; #if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC) sockfd = socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); if (sockfd != -1) goto out; if (errno != EINVAL) goto out; #endif sockfd = socket(domain, type, protocol); if (sockfd == -1) goto out; if (uv__nonblock(sockfd, 1) || uv__cloexec(sockfd, 1)) { uv__close(sockfd); sockfd = -1; } out: return sockfd; }
static int uv__process_open_stream(uv_stdio_container_t* container, int pipefds[2], int writable) { int flags; if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0) return 0; if (uv__close(pipefds[1])) if (errno != EINTR && errno != EINPROGRESS) abort(); pipefds[1] = -1; uv__nonblock(pipefds[0], 1); if (container->data.stream->type == UV_NAMED_PIPE && ((uv_pipe_t*)container->data.stream)->ipc) flags = UV_STREAM_READABLE | UV_STREAM_WRITABLE; else if (writable) flags = UV_STREAM_WRITABLE; else flags = UV_STREAM_READABLE; return uv__stream_open(container->data.stream, pipefds[0], flags); }
int uv_fs_event_stop(uv_fs_event_t* handle) { if (!uv__is_active(handle)) return 0; uv__handle_stop(handle); #if defined(__APPLE__) if (uv__fsevents_close(handle)) #endif /* defined(__APPLE__) */ { uv__io_close(handle->loop, &handle->event_watcher); } uv__free(handle->path); handle->path = NULL; if (handle->event_watcher.fd != -1) { /* When FSEvents is used, we don't use the event_watcher's fd under certain * confitions. (see uv_fs_event_start) */ uv__close(handle->event_watcher.fd); handle->event_watcher.fd = -1; } return 0; }
int uv__udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int addrlen, unsigned int flags) { int err; int yes; int fd; /* Check for bad flags. */ if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR)) return -EINVAL; /* Cannot set IPv6-only mode on non-IPv6 socket. */ if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) return -EINVAL; fd = handle->io_watcher.fd; if (fd == -1) { err = uv__socket(addr->sa_family, SOCK_DGRAM, 0); if (err < 0) return err; fd = err; handle->io_watcher.fd = fd; } if (flags & UV_UDP_REUSEADDR) { err = uv__set_reuse(fd); if (err) goto out; } if (flags & UV_UDP_IPV6ONLY) { #ifdef IPV6_V6ONLY yes = 1; if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) { err = -errno; goto out; } #else err = -ENOTSUP; goto out; #endif } if (bind(fd, addr, addrlen)) { err = -errno; goto out; } if (addr->sa_family == AF_INET6) handle->flags |= UV_HANDLE_IPV6; return 0; out: uv__close(handle->io_watcher.fd); handle->io_watcher.fd = -1; return err; }
void uv__fs_event_destroy(uv_fs_event_t* handle) { ev_ref(handle->loop->ev); ev_io_stop(handle->loop->ev, &handle->read_watcher); uv__close(handle->fd); handle->fd = -1; free(handle->filename); handle->filename = NULL; }
int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) { int pipefd[2]; int err; if (wa->io_watcher.fd != -1) return 0; err = uv__async_eventfd(); if (err >= 0) { pipefd[0] = err; pipefd[1] = -1; } else if (err == -ENOSYS) { err = uv__make_pipe(pipefd, UV__F_NONBLOCK); #if defined(__linux__) /* Save a file descriptor by opening one of the pipe descriptors as * read/write through the procfs. That file descriptor can then * function as both ends of the pipe. */ if (err == 0) { char buf[32]; int fd; snprintf(buf, sizeof(buf), "/proc/self/fd/%d", pipefd[0]); fd = uv__open_cloexec(buf, O_RDWR); if (fd >= 0) { uv__close(pipefd[0]); uv__close(pipefd[1]); pipefd[0] = fd; pipefd[1] = fd; } } #endif } if (err < 0) return err; uv__io_init(&wa->io_watcher, uv__async_io, pipefd[0]); uv__io_start(loop, &wa->io_watcher, POLLIN); wa->wfd = pipefd[1]; wa->cb = cb; return 0; }
void uv__udp_close(uv_udp_t* handle) { uv__io_close(handle->loop, &handle->io_watcher); uv__handle_stop(handle); if (handle->io_watcher.fd != -1) { uv__close(handle->io_watcher.fd); handle->io_watcher.fd = -1; } }
int uv_resident_set_memory(size_t* rss) { char buf[1024]; const char* s; ssize_t n; long val; int fd; int i; do fd = open("/proc/self/stat", O_RDONLY); while (fd == -1 && errno == EINTR); if (fd == -1) return -errno; do n = read(fd, buf, sizeof(buf) - 1); while (n == -1 && errno == EINTR); uv__close(fd); if (n == -1) return -errno; buf[n] = '\0'; s = strchr(buf, ' '); if (s == NULL) goto err; s += 1; if (*s != '(') goto err; s = strchr(s, ')'); if (s == NULL) goto err; for (i = 1; i <= 22; i++) { s = strchr(s + 1, ' '); if (s == NULL) goto err; } errno = 0; val = strtol(s, NULL, 10); if (errno != 0) goto err; if (val < 0) goto err; *rss = val * getpagesize(); return 0; err: return -EINVAL; }
int uv_pipe_bind(uv_pipe_t* handle, const char* name) { struct sockaddr_un saddr; const char* pipe_fname; int sockfd; int err; size_t name_len; pipe_fname = NULL; sockfd = -1; name_len = strlen(name); if (name_len > sizeof(saddr.sun_path) - 1) return -ENAMETOOLONG; /* Already bound? */ if (uv__stream_fd(handle) >= 0) return -EINVAL; /* Make a copy of the file name, it outlives this function's scope. */ pipe_fname = uv__strdup(name); if (pipe_fname == NULL) return -ENOMEM; /* We've got a copy, don't touch the original any more. */ name = NULL; err = uv__socket(AF_UNIX, SOCK_STREAM, 0); if (err < 0) goto err_socket; sockfd = err; memset(&saddr, 0, sizeof saddr); memcpy(saddr.sun_path, pipe_fname, name_len); saddr.sun_family = AF_UNIX; if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) { err = -errno; /* Convert ENOENT to EACCES for compatibility with Windows. */ if (err == -ENOENT) err = -EACCES; uv__close(sockfd); goto err_socket; } /* Success. */ handle->flags |= UV_HANDLE_BOUND; handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */ handle->io_watcher.fd = sockfd; return 0; err_socket: uv__free((void*)pipe_fname); return err; }
int uv__dup2_cloexec(int oldfd, int newfd) { int r; #if defined(__FreeBSD__) && __FreeBSD__ >= 10 do r = dup3(oldfd, newfd, O_CLOEXEC); while (r == -1 && errno == EINTR); if (r == -1) return -errno; return r; #elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC) do r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd); while (r == -1 && errno == EINTR); if (r != -1) return r; if (errno != EINVAL) return -errno; /* Fall through. */ #elif defined(__linux__) static int no_dup3; if (!no_dup3) { do r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC); while (r == -1 && (errno == EINTR || errno == EBUSY)); if (r != -1) return r; if (errno != ENOSYS) return -errno; /* Fall through. */ no_dup3 = 1; } #endif { int err; do r = dup2(oldfd, newfd); #if defined(__linux__) while (r == -1 && (errno == EINTR || errno == EBUSY)); #else while (r == -1 && errno == EINTR); #endif if (r == -1) return -errno; err = uv__cloexec(newfd, 1); if (err) { uv__close(newfd); return err; } return r; } }
/* This function is not execve-safe, there is a race window * between the call to dup() and fcntl(FD_CLOEXEC). */ int uv__dup(int fd) { fd = dup(fd); if (fd == -1) return -1; if (uv__cloexec(fd, 1)) { SAVE_ERRNO(uv__close(fd)); return -1; } return fd; }
int uv__accept(int sockfd) { int peerfd; int err; assert(sockfd >= 0); while (1) { #if defined(__linux__) || \ (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \ defined(__NetBSD__) static int no_accept4; if (no_accept4) goto skip; peerfd = uv__accept4(sockfd, NULL, NULL, UV__SOCK_NONBLOCK|UV__SOCK_CLOEXEC); if (peerfd != -1) return peerfd; if (errno == EINTR) continue; if (errno != ENOSYS) return UV__ERR(errno); no_accept4 = 1; skip: #endif peerfd = accept(sockfd, NULL, NULL); if (peerfd == -1) { if (errno == EINTR) continue; return UV__ERR(errno); } err = uv__cloexec(peerfd, 1); if (err == 0) err = uv__nonblock(peerfd, 1); if (err) { uv__close(peerfd); return err; } return peerfd; } }
/* get a file pointer to a file in read-only and close-on-exec mode */ FILE* uv__open_file(const char* path) { int fd; FILE* fp; fd = uv__open_cloexec(path, O_RDONLY); if (fd < 0) return NULL; fp = fdopen(fd, "r"); if (fp == NULL) uv__close(fd); return fp; }
void uv__loop_close(uv_loop_t* loop) { uv__signal_loop_cleanup(loop); uv__platform_loop_delete(loop); uv__async_stop(loop); if (loop->emfile_fd != -1) { uv__close(loop->emfile_fd); loop->emfile_fd = -1; } if (loop->backend_fd != -1) { uv__close(loop->backend_fd); loop->backend_fd = -1; } uv_mutex_lock(&loop->wq_mutex); assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!"); assert(!uv__has_active_reqs(loop)); uv_mutex_unlock(&loop->wq_mutex); uv_mutex_destroy(&loop->wq_mutex); /* * Note that all thread pool stuff is finished at this point and * it is safe to just destroy rw lock */ uv_rwlock_destroy(&loop->cloexec_lock); #if 0 assert(QUEUE_EMPTY(&loop->pending_queue)); assert(QUEUE_EMPTY(&loop->watcher_queue)); assert(loop->nfds == 0); #endif uv__free(loop->watchers); loop->watchers = NULL; loop->nwatchers = 0; }
int uv__accept(int sockfd) { int peerfd; int err; assert(sockfd >= 0); while (1) { #if defined(__linux__) static int no_accept4; no_accept4 = 1; /* accept4 doesn't work on QNAP */ if (no_accept4) goto skip; peerfd = uv__accept4(sockfd, NULL, NULL, UV__SOCK_NONBLOCK|UV__SOCK_CLOEXEC); if (peerfd != -1) return peerfd; if (errno == EINTR) continue; if (errno != ENOSYS) return -errno; no_accept4 = 1; skip: #endif peerfd = accept(sockfd, NULL, NULL); if (peerfd == -1) { if (errno == EINTR) continue; return -errno; } err = uv__cloexec(peerfd, 1); if (err == 0) err = uv__nonblock(peerfd, 1); if (err) { uv__close(peerfd); return err; } return peerfd; } }
static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { struct sockaddr_storage saddr; socklen_t slen; int sockfd; int err; err = uv__socket(domain, SOCK_STREAM, 0); if (err < 0) return err; sockfd = err; err = uv__stream_open((uv_stream_t*) handle, sockfd, flags); if (err) { uv__close(sockfd); return err; } if (flags & UV_HANDLE_BOUND) { /* Bind this new socket to an arbitrary port */ slen = sizeof(saddr); memset(&saddr, 0, sizeof(saddr)); err = getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen); if (err) { uv__close(sockfd); return err; } err = bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen); if (err) { uv__close(sockfd); return err; } } return 0; }
int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* path, unsigned int flags) { #if defined(__APPLE__) struct stat statbuf; #endif /* defined(__APPLE__) */ int fd; if (uv__is_active(handle)) return -EINVAL; /* TODO open asynchronously - but how do we report back errors? */ fd = open(path, O_RDONLY); if (fd == -1) return -errno; uv__handle_start(handle); uv__io_init(&handle->event_watcher, uv__fs_event, fd); handle->path = uv__strdup(path); handle->cb = cb; #if defined(__APPLE__) /* Nullify field to perform checks later */ handle->cf_cb = NULL; handle->realpath = NULL; handle->realpath_len = 0; handle->cf_flags = flags; if (fstat(fd, &statbuf)) goto fallback; /* FSEvents works only with directories */ if (!(statbuf.st_mode & S_IFDIR)) goto fallback; /* The fallback fd is no longer needed */ uv__close(fd); handle->event_watcher.fd = -1; return uv__fsevents_init(handle); fallback: #endif /* defined(__APPLE__) */ uv__io_start(handle->loop, &handle->event_watcher, POLLIN); return 0; }
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle, const char* filename, uv_fs_event_cb cb, int flags) { int events; int fd; loop->counters.fs_event_init++; /* We don't support any flags yet. */ assert(!flags); /* * TODO share a single inotify fd across the event loop? * We'll run into fs.inotify.max_user_instances if we * keep creating new inotify fds. */ if ((fd = new_inotify_fd()) == -1) { uv__set_sys_error(loop, errno); return -1; } events = IN_ATTRIB | IN_CREATE | IN_MODIFY | IN_DELETE | IN_DELETE_SELF | IN_MOVED_FROM | IN_MOVED_TO; if (inotify_add_watch(fd, filename, events) == -1) { uv__set_sys_error(loop, errno); uv__close(fd); return -1; } uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); handle->filename = strdup(filename); /* this should go! */ handle->cb = cb; handle->fd = fd; ev_io_init(&handle->read_watcher, uv__inotify_read, fd, EV_READ); ev_io_start(loop->ev, &handle->read_watcher); ev_unref(loop->ev); return 0; }
int uv__io_fork(uv_loop_t* loop) { int err; void* old_watchers; old_watchers = loop->inotify_watchers; uv__close(loop->backend_fd); loop->backend_fd = -1; uv__platform_loop_delete(loop); err = uv__platform_loop_init(loop); if (err) return err; return uv__inotify_fork(loop, old_watchers); }
/* This function is not execve-safe, there is a race window * between the call to dup() and fcntl(FD_CLOEXEC). */ int uv__dup(int fd) { int err; fd = dup(fd); if (fd == -1) return -errno; err = uv__cloexec(fd, 1); if (err) { uv__close(fd); return err; } return fd; }
static int new_inotify_fd(void) { #if HAVE_INOTIFY_INIT1 return inotify_init1(IN_NONBLOCK | IN_CLOEXEC); #else int fd; if ((fd = inotify_init()) == -1) return -1; if (uv__cloexec(fd, 1) || uv__nonblock(fd, 1)) { SAVE_ERRNO(uv__close(fd)); fd = -1; } return fd; #endif }