10e552da7Schristos /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
20e552da7Schristos * Permission is hereby granted, free of charge, to any person obtaining a copy
30e552da7Schristos * of this software and associated documentation files (the "Software"), to
40e552da7Schristos * deal in the Software without restriction, including without limitation the
50e552da7Schristos * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
60e552da7Schristos * sell copies of the Software, and to permit persons to whom the Software is
70e552da7Schristos * furnished to do so, subject to the following conditions:
80e552da7Schristos *
90e552da7Schristos * The above copyright notice and this permission notice shall be included in
100e552da7Schristos * all copies or substantial portions of the Software.
110e552da7Schristos *
120e552da7Schristos * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
130e552da7Schristos * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
140e552da7Schristos * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
150e552da7Schristos * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
160e552da7Schristos * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
170e552da7Schristos * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
180e552da7Schristos * IN THE SOFTWARE.
190e552da7Schristos */
200e552da7Schristos
210e552da7Schristos #include "uv.h"
220e552da7Schristos #include "internal.h"
23*5f2f4271Schristos #include "strtok.h"
240e552da7Schristos
250e552da7Schristos #include <stddef.h> /* NULL */
260e552da7Schristos #include <stdio.h> /* printf */
270e552da7Schristos #include <stdlib.h>
280e552da7Schristos #include <string.h> /* strerror */
290e552da7Schristos #include <errno.h>
300e552da7Schristos #include <assert.h>
310e552da7Schristos #include <unistd.h>
320e552da7Schristos #include <sys/types.h>
330e552da7Schristos #include <sys/stat.h>
340e552da7Schristos #include <fcntl.h> /* O_CLOEXEC */
350e552da7Schristos #include <sys/ioctl.h>
360e552da7Schristos #include <sys/socket.h>
370e552da7Schristos #include <sys/un.h>
380e552da7Schristos #include <netinet/in.h>
390e552da7Schristos #include <arpa/inet.h>
400e552da7Schristos #include <limits.h> /* INT_MAX, PATH_MAX, IOV_MAX */
410e552da7Schristos #include <sys/uio.h> /* writev */
420e552da7Schristos #include <sys/resource.h> /* getrusage */
430e552da7Schristos #include <pwd.h>
440e552da7Schristos #include <sys/utsname.h>
450e552da7Schristos #include <sys/time.h>
460e552da7Schristos
470e552da7Schristos #ifdef __sun
480e552da7Schristos # include <sys/filio.h>
490e552da7Schristos # include <sys/types.h>
500e552da7Schristos # include <sys/wait.h>
510e552da7Schristos #endif
520e552da7Schristos
530e552da7Schristos #if defined(__APPLE__)
540e552da7Schristos # include <sys/filio.h>
550e552da7Schristos # endif /* defined(__APPLE__) */
560e552da7Schristos
570e552da7Schristos
580e552da7Schristos #if defined(__APPLE__) && !TARGET_OS_IPHONE
590e552da7Schristos # include <crt_externs.h>
600e552da7Schristos # include <mach-o/dyld.h> /* _NSGetExecutablePath */
610e552da7Schristos # define environ (*_NSGetEnviron())
620e552da7Schristos #else /* defined(__APPLE__) && !TARGET_OS_IPHONE */
630e552da7Schristos extern char** environ;
640e552da7Schristos #endif /* !(defined(__APPLE__) && !TARGET_OS_IPHONE) */
650e552da7Schristos
660e552da7Schristos
670e552da7Schristos #if defined(__DragonFly__) || \
680e552da7Schristos defined(__FreeBSD__) || \
690e552da7Schristos defined(__FreeBSD_kernel__) || \
700e552da7Schristos defined(__NetBSD__) || \
710e552da7Schristos defined(__OpenBSD__)
720e552da7Schristos # include <sys/sysctl.h>
730e552da7Schristos # include <sys/filio.h>
740e552da7Schristos # include <sys/wait.h>
750e552da7Schristos # if defined(__FreeBSD__)
760e552da7Schristos # define uv__accept4 accept4
770e552da7Schristos # endif
780e552da7Schristos # if defined(__NetBSD__)
790e552da7Schristos # define uv__accept4(a, b, c, d) paccept((a), (b), (c), NULL, (d))
800e552da7Schristos # endif
810e552da7Schristos #endif
820e552da7Schristos
830e552da7Schristos #if defined(__MVS__)
840e552da7Schristos # include <sys/ioctl.h>
85*5f2f4271Schristos # include "zos-sys-info.h"
860e552da7Schristos #endif
870e552da7Schristos
880e552da7Schristos #if defined(__linux__)
89*5f2f4271Schristos # include <sched.h>
900e552da7Schristos # include <sys/syscall.h>
910e552da7Schristos # define uv__accept4 accept4
920e552da7Schristos #endif
930e552da7Schristos
94*5f2f4271Schristos #if defined(__linux__) && defined(__SANITIZE_THREAD__) && defined(__clang__)
95*5f2f4271Schristos # include <sanitizer/linux_syscall_hooks.h>
96*5f2f4271Schristos #endif
97*5f2f4271Schristos
98*5f2f4271Schristos static void uv__run_pending(uv_loop_t* loop);
990e552da7Schristos
1000e552da7Schristos /* Verify that uv_buf_t is ABI-compatible with struct iovec. */
1010e552da7Schristos STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec));
102*5f2f4271Schristos STATIC_ASSERT(sizeof(((uv_buf_t*) 0)->base) ==
1030e552da7Schristos sizeof(((struct iovec*) 0)->iov_base));
104*5f2f4271Schristos STATIC_ASSERT(sizeof(((uv_buf_t*) 0)->len) ==
1050e552da7Schristos sizeof(((struct iovec*) 0)->iov_len));
1060e552da7Schristos STATIC_ASSERT(offsetof(uv_buf_t, base) == offsetof(struct iovec, iov_base));
1070e552da7Schristos STATIC_ASSERT(offsetof(uv_buf_t, len) == offsetof(struct iovec, iov_len));
1080e552da7Schristos
1090e552da7Schristos
uv_hrtime(void)1100e552da7Schristos uint64_t uv_hrtime(void) {
1110e552da7Schristos return uv__hrtime(UV_CLOCK_PRECISE);
1120e552da7Schristos }
1130e552da7Schristos
1140e552da7Schristos
uv_close(uv_handle_t * handle,uv_close_cb close_cb)1150e552da7Schristos void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
1160e552da7Schristos assert(!uv__is_closing(handle));
1170e552da7Schristos
1180e552da7Schristos handle->flags |= UV_HANDLE_CLOSING;
1190e552da7Schristos handle->close_cb = close_cb;
1200e552da7Schristos
1210e552da7Schristos switch (handle->type) {
1220e552da7Schristos case UV_NAMED_PIPE:
1230e552da7Schristos uv__pipe_close((uv_pipe_t*)handle);
1240e552da7Schristos break;
1250e552da7Schristos
1260e552da7Schristos case UV_TTY:
1270e552da7Schristos uv__stream_close((uv_stream_t*)handle);
1280e552da7Schristos break;
1290e552da7Schristos
1300e552da7Schristos case UV_TCP:
1310e552da7Schristos uv__tcp_close((uv_tcp_t*)handle);
1320e552da7Schristos break;
1330e552da7Schristos
1340e552da7Schristos case UV_UDP:
1350e552da7Schristos uv__udp_close((uv_udp_t*)handle);
1360e552da7Schristos break;
1370e552da7Schristos
1380e552da7Schristos case UV_PREPARE:
1390e552da7Schristos uv__prepare_close((uv_prepare_t*)handle);
1400e552da7Schristos break;
1410e552da7Schristos
1420e552da7Schristos case UV_CHECK:
1430e552da7Schristos uv__check_close((uv_check_t*)handle);
1440e552da7Schristos break;
1450e552da7Schristos
1460e552da7Schristos case UV_IDLE:
1470e552da7Schristos uv__idle_close((uv_idle_t*)handle);
1480e552da7Schristos break;
1490e552da7Schristos
1500e552da7Schristos case UV_ASYNC:
1510e552da7Schristos uv__async_close((uv_async_t*)handle);
1520e552da7Schristos break;
1530e552da7Schristos
1540e552da7Schristos case UV_TIMER:
1550e552da7Schristos uv__timer_close((uv_timer_t*)handle);
1560e552da7Schristos break;
1570e552da7Schristos
1580e552da7Schristos case UV_PROCESS:
1590e552da7Schristos uv__process_close((uv_process_t*)handle);
1600e552da7Schristos break;
1610e552da7Schristos
1620e552da7Schristos case UV_FS_EVENT:
1630e552da7Schristos uv__fs_event_close((uv_fs_event_t*)handle);
164*5f2f4271Schristos #if defined(__sun) || defined(__MVS__)
165*5f2f4271Schristos /*
166*5f2f4271Schristos * On Solaris, illumos, and z/OS we will not be able to dissociate the
167*5f2f4271Schristos * watcher for an event which is pending delivery, so we cannot always call
168*5f2f4271Schristos * uv__make_close_pending() straight away. The backend will call the
169*5f2f4271Schristos * function once the event has cleared.
170*5f2f4271Schristos */
171*5f2f4271Schristos return;
172*5f2f4271Schristos #endif
1730e552da7Schristos break;
1740e552da7Schristos
1750e552da7Schristos case UV_POLL:
1760e552da7Schristos uv__poll_close((uv_poll_t*)handle);
1770e552da7Schristos break;
1780e552da7Schristos
1790e552da7Schristos case UV_FS_POLL:
1800e552da7Schristos uv__fs_poll_close((uv_fs_poll_t*)handle);
1810e552da7Schristos /* Poll handles use file system requests, and one of them may still be
1820e552da7Schristos * running. The poll code will call uv__make_close_pending() for us. */
1830e552da7Schristos return;
1840e552da7Schristos
1850e552da7Schristos case UV_SIGNAL:
1860e552da7Schristos uv__signal_close((uv_signal_t*) handle);
1870e552da7Schristos break;
1880e552da7Schristos
1890e552da7Schristos default:
1900e552da7Schristos assert(0);
1910e552da7Schristos }
1920e552da7Schristos
1930e552da7Schristos uv__make_close_pending(handle);
1940e552da7Schristos }
1950e552da7Schristos
uv__socket_sockopt(uv_handle_t * handle,int optname,int * value)1960e552da7Schristos int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
1970e552da7Schristos int r;
1980e552da7Schristos int fd;
1990e552da7Schristos socklen_t len;
2000e552da7Schristos
2010e552da7Schristos if (handle == NULL || value == NULL)
2020e552da7Schristos return UV_EINVAL;
2030e552da7Schristos
2040e552da7Schristos if (handle->type == UV_TCP || handle->type == UV_NAMED_PIPE)
2050e552da7Schristos fd = uv__stream_fd((uv_stream_t*) handle);
2060e552da7Schristos else if (handle->type == UV_UDP)
2070e552da7Schristos fd = ((uv_udp_t *) handle)->io_watcher.fd;
2080e552da7Schristos else
2090e552da7Schristos return UV_ENOTSUP;
2100e552da7Schristos
2110e552da7Schristos len = sizeof(*value);
2120e552da7Schristos
2130e552da7Schristos if (*value == 0)
2140e552da7Schristos r = getsockopt(fd, SOL_SOCKET, optname, value, &len);
2150e552da7Schristos else
2160e552da7Schristos r = setsockopt(fd, SOL_SOCKET, optname, (const void*) value, len);
2170e552da7Schristos
2180e552da7Schristos if (r < 0)
2190e552da7Schristos return UV__ERR(errno);
2200e552da7Schristos
2210e552da7Schristos return 0;
2220e552da7Schristos }
2230e552da7Schristos
uv__make_close_pending(uv_handle_t * handle)2240e552da7Schristos void uv__make_close_pending(uv_handle_t* handle) {
2250e552da7Schristos assert(handle->flags & UV_HANDLE_CLOSING);
2260e552da7Schristos assert(!(handle->flags & UV_HANDLE_CLOSED));
2270e552da7Schristos handle->next_closing = handle->loop->closing_handles;
2280e552da7Schristos handle->loop->closing_handles = handle;
2290e552da7Schristos }
2300e552da7Schristos
uv__getiovmax(void)2310e552da7Schristos int uv__getiovmax(void) {
2320e552da7Schristos #if defined(IOV_MAX)
2330e552da7Schristos return IOV_MAX;
2340e552da7Schristos #elif defined(_SC_IOV_MAX)
235*5f2f4271Schristos static int iovmax_cached = -1;
236*5f2f4271Schristos int iovmax;
237*5f2f4271Schristos
238*5f2f4271Schristos iovmax = uv__load_relaxed(&iovmax_cached);
239*5f2f4271Schristos if (iovmax != -1)
240*5f2f4271Schristos return iovmax;
241*5f2f4271Schristos
2420e552da7Schristos /* On some embedded devices (arm-linux-uclibc based ip camera),
2430e552da7Schristos * sysconf(_SC_IOV_MAX) can not get the correct value. The return
2440e552da7Schristos * value is -1 and the errno is EINPROGRESS. Degrade the value to 1.
2450e552da7Schristos */
246*5f2f4271Schristos iovmax = sysconf(_SC_IOV_MAX);
247*5f2f4271Schristos if (iovmax == -1)
248*5f2f4271Schristos iovmax = 1;
249*5f2f4271Schristos
250*5f2f4271Schristos uv__store_relaxed(&iovmax_cached, iovmax);
251*5f2f4271Schristos
2520e552da7Schristos return iovmax;
2530e552da7Schristos #else
2540e552da7Schristos return 1024;
2550e552da7Schristos #endif
2560e552da7Schristos }
2570e552da7Schristos
2580e552da7Schristos
uv__finish_close(uv_handle_t * handle)2590e552da7Schristos static void uv__finish_close(uv_handle_t* handle) {
2600e552da7Schristos uv_signal_t* sh;
2610e552da7Schristos
2620e552da7Schristos /* Note: while the handle is in the UV_HANDLE_CLOSING state now, it's still
2630e552da7Schristos * possible for it to be active in the sense that uv__is_active() returns
2640e552da7Schristos * true.
2650e552da7Schristos *
2660e552da7Schristos * A good example is when the user calls uv_shutdown(), immediately followed
2670e552da7Schristos * by uv_close(). The handle is considered active at this point because the
2680e552da7Schristos * completion of the shutdown req is still pending.
2690e552da7Schristos */
2700e552da7Schristos assert(handle->flags & UV_HANDLE_CLOSING);
2710e552da7Schristos assert(!(handle->flags & UV_HANDLE_CLOSED));
2720e552da7Schristos handle->flags |= UV_HANDLE_CLOSED;
2730e552da7Schristos
2740e552da7Schristos switch (handle->type) {
2750e552da7Schristos case UV_PREPARE:
2760e552da7Schristos case UV_CHECK:
2770e552da7Schristos case UV_IDLE:
2780e552da7Schristos case UV_ASYNC:
2790e552da7Schristos case UV_TIMER:
2800e552da7Schristos case UV_PROCESS:
2810e552da7Schristos case UV_FS_EVENT:
2820e552da7Schristos case UV_FS_POLL:
2830e552da7Schristos case UV_POLL:
2840e552da7Schristos break;
2850e552da7Schristos
2860e552da7Schristos case UV_SIGNAL:
2870e552da7Schristos /* If there are any caught signals "trapped" in the signal pipe,
2880e552da7Schristos * we can't call the close callback yet. Reinserting the handle
2890e552da7Schristos * into the closing queue makes the event loop spin but that's
2900e552da7Schristos * okay because we only need to deliver the pending events.
2910e552da7Schristos */
2920e552da7Schristos sh = (uv_signal_t*) handle;
2930e552da7Schristos if (sh->caught_signals > sh->dispatched_signals) {
2940e552da7Schristos handle->flags ^= UV_HANDLE_CLOSED;
2950e552da7Schristos uv__make_close_pending(handle); /* Back into the queue. */
2960e552da7Schristos return;
2970e552da7Schristos }
2980e552da7Schristos break;
2990e552da7Schristos
3000e552da7Schristos case UV_NAMED_PIPE:
3010e552da7Schristos case UV_TCP:
3020e552da7Schristos case UV_TTY:
3030e552da7Schristos uv__stream_destroy((uv_stream_t*)handle);
3040e552da7Schristos break;
3050e552da7Schristos
3060e552da7Schristos case UV_UDP:
3070e552da7Schristos uv__udp_finish_close((uv_udp_t*)handle);
3080e552da7Schristos break;
3090e552da7Schristos
3100e552da7Schristos default:
3110e552da7Schristos assert(0);
3120e552da7Schristos break;
3130e552da7Schristos }
3140e552da7Schristos
3150e552da7Schristos uv__handle_unref(handle);
3160e552da7Schristos QUEUE_REMOVE(&handle->handle_queue);
3170e552da7Schristos
3180e552da7Schristos if (handle->close_cb) {
3190e552da7Schristos handle->close_cb(handle);
3200e552da7Schristos }
3210e552da7Schristos }
3220e552da7Schristos
3230e552da7Schristos
uv__run_closing_handles(uv_loop_t * loop)3240e552da7Schristos static void uv__run_closing_handles(uv_loop_t* loop) {
3250e552da7Schristos uv_handle_t* p;
3260e552da7Schristos uv_handle_t* q;
3270e552da7Schristos
3280e552da7Schristos p = loop->closing_handles;
3290e552da7Schristos loop->closing_handles = NULL;
3300e552da7Schristos
3310e552da7Schristos while (p) {
3320e552da7Schristos q = p->next_closing;
3330e552da7Schristos uv__finish_close(p);
3340e552da7Schristos p = q;
3350e552da7Schristos }
3360e552da7Schristos }
3370e552da7Schristos
3380e552da7Schristos
uv_is_closing(const uv_handle_t * handle)3390e552da7Schristos int uv_is_closing(const uv_handle_t* handle) {
3400e552da7Schristos return uv__is_closing(handle);
3410e552da7Schristos }
3420e552da7Schristos
3430e552da7Schristos
uv_backend_fd(const uv_loop_t * loop)3440e552da7Schristos int uv_backend_fd(const uv_loop_t* loop) {
3450e552da7Schristos return loop->backend_fd;
3460e552da7Schristos }
3470e552da7Schristos
3480e552da7Schristos
uv__loop_alive(const uv_loop_t * loop)3490e552da7Schristos static int uv__loop_alive(const uv_loop_t* loop) {
3500e552da7Schristos return uv__has_active_handles(loop) ||
3510e552da7Schristos uv__has_active_reqs(loop) ||
352*5f2f4271Schristos !QUEUE_EMPTY(&loop->pending_queue) ||
3530e552da7Schristos loop->closing_handles != NULL;
3540e552da7Schristos }
3550e552da7Schristos
3560e552da7Schristos
uv__backend_timeout(const uv_loop_t * loop)357*5f2f4271Schristos static int uv__backend_timeout(const uv_loop_t* loop) {
358*5f2f4271Schristos if (loop->stop_flag == 0 &&
359*5f2f4271Schristos /* uv__loop_alive(loop) && */
360*5f2f4271Schristos (uv__has_active_handles(loop) || uv__has_active_reqs(loop)) &&
361*5f2f4271Schristos QUEUE_EMPTY(&loop->pending_queue) &&
362*5f2f4271Schristos QUEUE_EMPTY(&loop->idle_handles) &&
363*5f2f4271Schristos loop->closing_handles == NULL)
364*5f2f4271Schristos return uv__next_timeout(loop);
365*5f2f4271Schristos return 0;
366*5f2f4271Schristos }
367*5f2f4271Schristos
368*5f2f4271Schristos
uv_backend_timeout(const uv_loop_t * loop)369*5f2f4271Schristos int uv_backend_timeout(const uv_loop_t* loop) {
370*5f2f4271Schristos if (QUEUE_EMPTY(&loop->watcher_queue))
371*5f2f4271Schristos return uv__backend_timeout(loop);
372*5f2f4271Schristos /* Need to call uv_run to update the backend fd state. */
373*5f2f4271Schristos return 0;
374*5f2f4271Schristos }
375*5f2f4271Schristos
376*5f2f4271Schristos
uv_loop_alive(const uv_loop_t * loop)3770e552da7Schristos int uv_loop_alive(const uv_loop_t* loop) {
3780e552da7Schristos return uv__loop_alive(loop);
3790e552da7Schristos }
3800e552da7Schristos
3810e552da7Schristos
uv_run(uv_loop_t * loop,uv_run_mode mode)3820e552da7Schristos int uv_run(uv_loop_t* loop, uv_run_mode mode) {
3830e552da7Schristos int timeout;
3840e552da7Schristos int r;
385*5f2f4271Schristos int can_sleep;
3860e552da7Schristos
3870e552da7Schristos r = uv__loop_alive(loop);
3880e552da7Schristos if (!r)
3890e552da7Schristos uv__update_time(loop);
3900e552da7Schristos
3910e552da7Schristos while (r != 0 && loop->stop_flag == 0) {
3920e552da7Schristos uv__update_time(loop);
3930e552da7Schristos uv__run_timers(loop);
394*5f2f4271Schristos
395*5f2f4271Schristos can_sleep =
396*5f2f4271Schristos QUEUE_EMPTY(&loop->pending_queue) && QUEUE_EMPTY(&loop->idle_handles);
397*5f2f4271Schristos
398*5f2f4271Schristos uv__run_pending(loop);
3990e552da7Schristos uv__run_idle(loop);
4000e552da7Schristos uv__run_prepare(loop);
4010e552da7Schristos
4020e552da7Schristos timeout = 0;
403*5f2f4271Schristos if ((mode == UV_RUN_ONCE && can_sleep) || mode == UV_RUN_DEFAULT)
404*5f2f4271Schristos timeout = uv__backend_timeout(loop);
4050e552da7Schristos
4060e552da7Schristos uv__io_poll(loop, timeout);
407*5f2f4271Schristos
408*5f2f4271Schristos /* Process immediate callbacks (e.g. write_cb) a small fixed number of
409*5f2f4271Schristos * times to avoid loop starvation.*/
410*5f2f4271Schristos for (r = 0; r < 8 && !QUEUE_EMPTY(&loop->pending_queue); r++)
411*5f2f4271Schristos uv__run_pending(loop);
412*5f2f4271Schristos
413*5f2f4271Schristos /* Run one final update on the provider_idle_time in case uv__io_poll
414*5f2f4271Schristos * returned because the timeout expired, but no events were received. This
415*5f2f4271Schristos * call will be ignored if the provider_entry_time was either never set (if
416*5f2f4271Schristos * the timeout == 0) or was already updated b/c an event was received.
417*5f2f4271Schristos */
418*5f2f4271Schristos uv__metrics_update_idle_time(loop);
419*5f2f4271Schristos
4200e552da7Schristos uv__run_check(loop);
4210e552da7Schristos uv__run_closing_handles(loop);
4220e552da7Schristos
4230e552da7Schristos if (mode == UV_RUN_ONCE) {
4240e552da7Schristos /* UV_RUN_ONCE implies forward progress: at least one callback must have
4250e552da7Schristos * been invoked when it returns. uv__io_poll() can return without doing
4260e552da7Schristos * I/O (meaning: no callbacks) when its timeout expires - which means we
4270e552da7Schristos * have pending timers that satisfy the forward progress constraint.
4280e552da7Schristos *
4290e552da7Schristos * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
4300e552da7Schristos * the check.
4310e552da7Schristos */
4320e552da7Schristos uv__update_time(loop);
4330e552da7Schristos uv__run_timers(loop);
4340e552da7Schristos }
4350e552da7Schristos
4360e552da7Schristos r = uv__loop_alive(loop);
4370e552da7Schristos if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
4380e552da7Schristos break;
4390e552da7Schristos }
4400e552da7Schristos
4410e552da7Schristos /* The if statement lets gcc compile it to a conditional store. Avoids
4420e552da7Schristos * dirtying a cache line.
4430e552da7Schristos */
4440e552da7Schristos if (loop->stop_flag != 0)
4450e552da7Schristos loop->stop_flag = 0;
4460e552da7Schristos
4470e552da7Schristos return r;
4480e552da7Schristos }
4490e552da7Schristos
4500e552da7Schristos
uv_update_time(uv_loop_t * loop)4510e552da7Schristos void uv_update_time(uv_loop_t* loop) {
4520e552da7Schristos uv__update_time(loop);
4530e552da7Schristos }
4540e552da7Schristos
4550e552da7Schristos
uv_is_active(const uv_handle_t * handle)4560e552da7Schristos int uv_is_active(const uv_handle_t* handle) {
4570e552da7Schristos return uv__is_active(handle);
4580e552da7Schristos }
4590e552da7Schristos
4600e552da7Schristos
4610e552da7Schristos /* Open a socket in non-blocking close-on-exec mode, atomically if possible. */
uv__socket(int domain,int type,int protocol)4620e552da7Schristos int uv__socket(int domain, int type, int protocol) {
4630e552da7Schristos int sockfd;
4640e552da7Schristos int err;
4650e552da7Schristos
4660e552da7Schristos #if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
4670e552da7Schristos sockfd = socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
4680e552da7Schristos if (sockfd != -1)
4690e552da7Schristos return sockfd;
4700e552da7Schristos
4710e552da7Schristos if (errno != EINVAL)
4720e552da7Schristos return UV__ERR(errno);
4730e552da7Schristos #endif
4740e552da7Schristos
4750e552da7Schristos sockfd = socket(domain, type, protocol);
4760e552da7Schristos if (sockfd == -1)
4770e552da7Schristos return UV__ERR(errno);
4780e552da7Schristos
4790e552da7Schristos err = uv__nonblock(sockfd, 1);
4800e552da7Schristos if (err == 0)
4810e552da7Schristos err = uv__cloexec(sockfd, 1);
4820e552da7Schristos
4830e552da7Schristos if (err) {
4840e552da7Schristos uv__close(sockfd);
4850e552da7Schristos return err;
4860e552da7Schristos }
4870e552da7Schristos
4880e552da7Schristos #if defined(SO_NOSIGPIPE)
4890e552da7Schristos {
4900e552da7Schristos int on = 1;
4910e552da7Schristos setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
4920e552da7Schristos }
4930e552da7Schristos #endif
4940e552da7Schristos
4950e552da7Schristos return sockfd;
4960e552da7Schristos }
4970e552da7Schristos
4980e552da7Schristos /* get a file pointer to a file in read-only and close-on-exec mode */
uv__open_file(const char * path)4990e552da7Schristos FILE* uv__open_file(const char* path) {
5000e552da7Schristos int fd;
5010e552da7Schristos FILE* fp;
5020e552da7Schristos
5030e552da7Schristos fd = uv__open_cloexec(path, O_RDONLY);
5040e552da7Schristos if (fd < 0)
5050e552da7Schristos return NULL;
5060e552da7Schristos
5070e552da7Schristos fp = fdopen(fd, "r");
5080e552da7Schristos if (fp == NULL)
5090e552da7Schristos uv__close(fd);
5100e552da7Schristos
5110e552da7Schristos return fp;
5120e552da7Schristos }
5130e552da7Schristos
5140e552da7Schristos
uv__accept(int sockfd)5150e552da7Schristos int uv__accept(int sockfd) {
5160e552da7Schristos int peerfd;
5170e552da7Schristos int err;
5180e552da7Schristos
5190e552da7Schristos (void) &err;
5200e552da7Schristos assert(sockfd >= 0);
5210e552da7Schristos
5220e552da7Schristos do
5230e552da7Schristos #ifdef uv__accept4
5240e552da7Schristos peerfd = uv__accept4(sockfd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
5250e552da7Schristos #else
5260e552da7Schristos peerfd = accept(sockfd, NULL, NULL);
5270e552da7Schristos #endif
5280e552da7Schristos while (peerfd == -1 && errno == EINTR);
5290e552da7Schristos
5300e552da7Schristos if (peerfd == -1)
5310e552da7Schristos return UV__ERR(errno);
5320e552da7Schristos
5330e552da7Schristos #ifndef uv__accept4
5340e552da7Schristos err = uv__cloexec(peerfd, 1);
5350e552da7Schristos if (err == 0)
5360e552da7Schristos err = uv__nonblock(peerfd, 1);
5370e552da7Schristos
5380e552da7Schristos if (err != 0) {
5390e552da7Schristos uv__close(peerfd);
5400e552da7Schristos return err;
5410e552da7Schristos }
5420e552da7Schristos #endif
5430e552da7Schristos
5440e552da7Schristos return peerfd;
5450e552da7Schristos }
5460e552da7Schristos
5470e552da7Schristos
5480e552da7Schristos /* close() on macos has the "interesting" quirk that it fails with EINTR
5490e552da7Schristos * without closing the file descriptor when a thread is in the cancel state.
5500e552da7Schristos * That's why libuv calls close$NOCANCEL() instead.
5510e552da7Schristos *
5520e552da7Schristos * glibc on linux has a similar issue: close() is a cancellation point and
5530e552da7Schristos * will unwind the thread when it's in the cancel state. Work around that
5540e552da7Schristos * by making the system call directly. Musl libc is unaffected.
5550e552da7Schristos */
uv__close_nocancel(int fd)5560e552da7Schristos int uv__close_nocancel(int fd) {
5570e552da7Schristos #if defined(__APPLE__)
5580e552da7Schristos #pragma GCC diagnostic push
5590e552da7Schristos #pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
5600e552da7Schristos #if defined(__LP64__) || TARGET_OS_IPHONE
5610e552da7Schristos extern int close$NOCANCEL(int);
5620e552da7Schristos return close$NOCANCEL(fd);
5630e552da7Schristos #else
5640e552da7Schristos extern int close$NOCANCEL$UNIX2003(int);
5650e552da7Schristos return close$NOCANCEL$UNIX2003(fd);
5660e552da7Schristos #endif
5670e552da7Schristos #pragma GCC diagnostic pop
568*5f2f4271Schristos #elif defined(__linux__) && defined(__SANITIZE_THREAD__) && defined(__clang__)
569*5f2f4271Schristos long rc;
570*5f2f4271Schristos __sanitizer_syscall_pre_close(fd);
571*5f2f4271Schristos rc = syscall(SYS_close, fd);
572*5f2f4271Schristos __sanitizer_syscall_post_close(rc, fd);
573*5f2f4271Schristos return rc;
574*5f2f4271Schristos #elif defined(__linux__) && !defined(__SANITIZE_THREAD__)
5750e552da7Schristos return syscall(SYS_close, fd);
5760e552da7Schristos #else
5770e552da7Schristos return close(fd);
5780e552da7Schristos #endif
5790e552da7Schristos }
5800e552da7Schristos
5810e552da7Schristos
uv__close_nocheckstdio(int fd)5820e552da7Schristos int uv__close_nocheckstdio(int fd) {
5830e552da7Schristos int saved_errno;
5840e552da7Schristos int rc;
5850e552da7Schristos
5860e552da7Schristos assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */
5870e552da7Schristos
5880e552da7Schristos saved_errno = errno;
5890e552da7Schristos rc = uv__close_nocancel(fd);
5900e552da7Schristos if (rc == -1) {
5910e552da7Schristos rc = UV__ERR(errno);
5920e552da7Schristos if (rc == UV_EINTR || rc == UV__ERR(EINPROGRESS))
5930e552da7Schristos rc = 0; /* The close is in progress, not an error. */
5940e552da7Schristos errno = saved_errno;
5950e552da7Schristos }
5960e552da7Schristos
5970e552da7Schristos return rc;
5980e552da7Schristos }
5990e552da7Schristos
6000e552da7Schristos
uv__close(int fd)6010e552da7Schristos int uv__close(int fd) {
6020e552da7Schristos assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */
6030e552da7Schristos #if defined(__MVS__)
6040e552da7Schristos SAVE_ERRNO(epoll_file_close(fd));
6050e552da7Schristos #endif
6060e552da7Schristos return uv__close_nocheckstdio(fd);
6070e552da7Schristos }
6080e552da7Schristos
609*5f2f4271Schristos #if UV__NONBLOCK_IS_IOCTL
uv__nonblock_ioctl(int fd,int set)6100e552da7Schristos int uv__nonblock_ioctl(int fd, int set) {
6110e552da7Schristos int r;
6120e552da7Schristos
6130e552da7Schristos do
6140e552da7Schristos r = ioctl(fd, FIONBIO, &set);
6150e552da7Schristos while (r == -1 && errno == EINTR);
6160e552da7Schristos
6170e552da7Schristos if (r)
6180e552da7Schristos return UV__ERR(errno);
6190e552da7Schristos
6200e552da7Schristos return 0;
6210e552da7Schristos }
6220e552da7Schristos #endif
6230e552da7Schristos
6240e552da7Schristos
uv__nonblock_fcntl(int fd,int set)6250e552da7Schristos int uv__nonblock_fcntl(int fd, int set) {
6260e552da7Schristos int flags;
6270e552da7Schristos int r;
6280e552da7Schristos
6290e552da7Schristos do
6300e552da7Schristos r = fcntl(fd, F_GETFL);
6310e552da7Schristos while (r == -1 && errno == EINTR);
6320e552da7Schristos
6330e552da7Schristos if (r == -1)
6340e552da7Schristos return UV__ERR(errno);
6350e552da7Schristos
6360e552da7Schristos /* Bail out now if already set/clear. */
6370e552da7Schristos if (!!(r & O_NONBLOCK) == !!set)
6380e552da7Schristos return 0;
6390e552da7Schristos
6400e552da7Schristos if (set)
6410e552da7Schristos flags = r | O_NONBLOCK;
6420e552da7Schristos else
6430e552da7Schristos flags = r & ~O_NONBLOCK;
6440e552da7Schristos
6450e552da7Schristos do
6460e552da7Schristos r = fcntl(fd, F_SETFL, flags);
6470e552da7Schristos while (r == -1 && errno == EINTR);
6480e552da7Schristos
6490e552da7Schristos if (r)
6500e552da7Schristos return UV__ERR(errno);
6510e552da7Schristos
6520e552da7Schristos return 0;
6530e552da7Schristos }
6540e552da7Schristos
6550e552da7Schristos
uv__cloexec(int fd,int set)656*5f2f4271Schristos int uv__cloexec(int fd, int set) {
6570e552da7Schristos int flags;
6580e552da7Schristos int r;
6590e552da7Schristos
660*5f2f4271Schristos flags = 0;
6610e552da7Schristos if (set)
662*5f2f4271Schristos flags = FD_CLOEXEC;
6630e552da7Schristos
6640e552da7Schristos do
6650e552da7Schristos r = fcntl(fd, F_SETFD, flags);
6660e552da7Schristos while (r == -1 && errno == EINTR);
6670e552da7Schristos
6680e552da7Schristos if (r)
6690e552da7Schristos return UV__ERR(errno);
6700e552da7Schristos
6710e552da7Schristos return 0;
6720e552da7Schristos }
6730e552da7Schristos
6740e552da7Schristos
uv__recvmsg(int fd,struct msghdr * msg,int flags)6750e552da7Schristos ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
676*5f2f4271Schristos #if defined(__ANDROID__) || \
677*5f2f4271Schristos defined(__DragonFly__) || \
678*5f2f4271Schristos defined(__FreeBSD__) || \
679*5f2f4271Schristos defined(__NetBSD__) || \
680*5f2f4271Schristos defined(__OpenBSD__) || \
681*5f2f4271Schristos defined(__linux__)
6820e552da7Schristos ssize_t rc;
683*5f2f4271Schristos rc = recvmsg(fd, msg, flags | MSG_CMSG_CLOEXEC);
6840e552da7Schristos if (rc == -1)
6850e552da7Schristos return UV__ERR(errno);
686*5f2f4271Schristos return rc;
6870e552da7Schristos #else
688*5f2f4271Schristos struct cmsghdr* cmsg;
689*5f2f4271Schristos int* pfd;
690*5f2f4271Schristos int* end;
691*5f2f4271Schristos ssize_t rc;
6920e552da7Schristos rc = recvmsg(fd, msg, flags);
6930e552da7Schristos if (rc == -1)
6940e552da7Schristos return UV__ERR(errno);
6950e552da7Schristos if (msg->msg_controllen == 0)
6960e552da7Schristos return rc;
6970e552da7Schristos for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg))
6980e552da7Schristos if (cmsg->cmsg_type == SCM_RIGHTS)
6990e552da7Schristos for (pfd = (int*) CMSG_DATA(cmsg),
7000e552da7Schristos end = (int*) ((char*) cmsg + cmsg->cmsg_len);
7010e552da7Schristos pfd < end;
7020e552da7Schristos pfd += 1)
7030e552da7Schristos uv__cloexec(*pfd, 1);
7040e552da7Schristos return rc;
705*5f2f4271Schristos #endif
7060e552da7Schristos }
7070e552da7Schristos
7080e552da7Schristos
uv_cwd(char * buffer,size_t * size)7090e552da7Schristos int uv_cwd(char* buffer, size_t* size) {
7100e552da7Schristos char scratch[1 + UV__PATH_MAX];
7110e552da7Schristos
7120e552da7Schristos if (buffer == NULL || size == NULL)
7130e552da7Schristos return UV_EINVAL;
7140e552da7Schristos
7150e552da7Schristos /* Try to read directly into the user's buffer first... */
7160e552da7Schristos if (getcwd(buffer, *size) != NULL)
7170e552da7Schristos goto fixup;
7180e552da7Schristos
7190e552da7Schristos if (errno != ERANGE)
7200e552da7Schristos return UV__ERR(errno);
7210e552da7Schristos
7220e552da7Schristos /* ...or into scratch space if the user's buffer is too small
7230e552da7Schristos * so we can report how much space to provide on the next try.
7240e552da7Schristos */
7250e552da7Schristos if (getcwd(scratch, sizeof(scratch)) == NULL)
7260e552da7Schristos return UV__ERR(errno);
7270e552da7Schristos
7280e552da7Schristos buffer = scratch;
7290e552da7Schristos
7300e552da7Schristos fixup:
7310e552da7Schristos
7320e552da7Schristos *size = strlen(buffer);
7330e552da7Schristos
7340e552da7Schristos if (*size > 1 && buffer[*size - 1] == '/') {
7350e552da7Schristos *size -= 1;
7360e552da7Schristos buffer[*size] = '\0';
7370e552da7Schristos }
7380e552da7Schristos
7390e552da7Schristos if (buffer == scratch) {
7400e552da7Schristos *size += 1;
7410e552da7Schristos return UV_ENOBUFS;
7420e552da7Schristos }
7430e552da7Schristos
7440e552da7Schristos return 0;
7450e552da7Schristos }
7460e552da7Schristos
7470e552da7Schristos
uv_chdir(const char * dir)7480e552da7Schristos int uv_chdir(const char* dir) {
7490e552da7Schristos if (chdir(dir))
7500e552da7Schristos return UV__ERR(errno);
7510e552da7Schristos
7520e552da7Schristos return 0;
7530e552da7Schristos }
7540e552da7Schristos
7550e552da7Schristos
uv_disable_stdio_inheritance(void)7560e552da7Schristos void uv_disable_stdio_inheritance(void) {
7570e552da7Schristos int fd;
7580e552da7Schristos
7590e552da7Schristos /* Set the CLOEXEC flag on all open descriptors. Unconditionally try the
7600e552da7Schristos * first 16 file descriptors. After that, bail out after the first error.
7610e552da7Schristos */
7620e552da7Schristos for (fd = 0; ; fd++)
7630e552da7Schristos if (uv__cloexec(fd, 1) && fd > 15)
7640e552da7Schristos break;
7650e552da7Schristos }
7660e552da7Schristos
7670e552da7Schristos
uv_fileno(const uv_handle_t * handle,uv_os_fd_t * fd)7680e552da7Schristos int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
7690e552da7Schristos int fd_out;
7700e552da7Schristos
7710e552da7Schristos switch (handle->type) {
7720e552da7Schristos case UV_TCP:
7730e552da7Schristos case UV_NAMED_PIPE:
7740e552da7Schristos case UV_TTY:
7750e552da7Schristos fd_out = uv__stream_fd((uv_stream_t*) handle);
7760e552da7Schristos break;
7770e552da7Schristos
7780e552da7Schristos case UV_UDP:
7790e552da7Schristos fd_out = ((uv_udp_t *) handle)->io_watcher.fd;
7800e552da7Schristos break;
7810e552da7Schristos
7820e552da7Schristos case UV_POLL:
7830e552da7Schristos fd_out = ((uv_poll_t *) handle)->io_watcher.fd;
7840e552da7Schristos break;
7850e552da7Schristos
7860e552da7Schristos default:
7870e552da7Schristos return UV_EINVAL;
7880e552da7Schristos }
7890e552da7Schristos
7900e552da7Schristos if (uv__is_closing(handle) || fd_out == -1)
7910e552da7Schristos return UV_EBADF;
7920e552da7Schristos
7930e552da7Schristos *fd = fd_out;
7940e552da7Schristos return 0;
7950e552da7Schristos }
7960e552da7Schristos
7970e552da7Schristos
uv__run_pending(uv_loop_t * loop)798*5f2f4271Schristos static void uv__run_pending(uv_loop_t* loop) {
7990e552da7Schristos QUEUE* q;
8000e552da7Schristos QUEUE pq;
8010e552da7Schristos uv__io_t* w;
8020e552da7Schristos
8030e552da7Schristos QUEUE_MOVE(&loop->pending_queue, &pq);
8040e552da7Schristos
8050e552da7Schristos while (!QUEUE_EMPTY(&pq)) {
8060e552da7Schristos q = QUEUE_HEAD(&pq);
8070e552da7Schristos QUEUE_REMOVE(q);
8080e552da7Schristos QUEUE_INIT(q);
8090e552da7Schristos w = QUEUE_DATA(q, uv__io_t, pending_queue);
8100e552da7Schristos w->cb(loop, w, POLLOUT);
8110e552da7Schristos }
8120e552da7Schristos }
8130e552da7Schristos
8140e552da7Schristos
next_power_of_two(unsigned int val)8150e552da7Schristos static unsigned int next_power_of_two(unsigned int val) {
8160e552da7Schristos val -= 1;
8170e552da7Schristos val |= val >> 1;
8180e552da7Schristos val |= val >> 2;
8190e552da7Schristos val |= val >> 4;
8200e552da7Schristos val |= val >> 8;
8210e552da7Schristos val |= val >> 16;
8220e552da7Schristos val += 1;
8230e552da7Schristos return val;
8240e552da7Schristos }
8250e552da7Schristos
maybe_resize(uv_loop_t * loop,unsigned int len)8260e552da7Schristos static void maybe_resize(uv_loop_t* loop, unsigned int len) {
8270e552da7Schristos uv__io_t** watchers;
8280e552da7Schristos void* fake_watcher_list;
8290e552da7Schristos void* fake_watcher_count;
8300e552da7Schristos unsigned int nwatchers;
8310e552da7Schristos unsigned int i;
8320e552da7Schristos
8330e552da7Schristos if (len <= loop->nwatchers)
8340e552da7Schristos return;
8350e552da7Schristos
8360e552da7Schristos /* Preserve fake watcher list and count at the end of the watchers */
8370e552da7Schristos if (loop->watchers != NULL) {
8380e552da7Schristos fake_watcher_list = loop->watchers[loop->nwatchers];
8390e552da7Schristos fake_watcher_count = loop->watchers[loop->nwatchers + 1];
8400e552da7Schristos } else {
8410e552da7Schristos fake_watcher_list = NULL;
8420e552da7Schristos fake_watcher_count = NULL;
8430e552da7Schristos }
8440e552da7Schristos
8450e552da7Schristos nwatchers = next_power_of_two(len + 2) - 2;
8460e552da7Schristos watchers = uv__reallocf(loop->watchers,
8470e552da7Schristos (nwatchers + 2) * sizeof(loop->watchers[0]));
8480e552da7Schristos
8490e552da7Schristos if (watchers == NULL)
8500e552da7Schristos abort();
8510e552da7Schristos for (i = loop->nwatchers; i < nwatchers; i++)
8520e552da7Schristos watchers[i] = NULL;
8530e552da7Schristos watchers[nwatchers] = fake_watcher_list;
8540e552da7Schristos watchers[nwatchers + 1] = fake_watcher_count;
8550e552da7Schristos
8560e552da7Schristos loop->watchers = watchers;
8570e552da7Schristos loop->nwatchers = nwatchers;
8580e552da7Schristos }
8590e552da7Schristos
8600e552da7Schristos
uv__io_init(uv__io_t * w,uv__io_cb cb,int fd)8610e552da7Schristos void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) {
8620e552da7Schristos assert(cb != NULL);
8630e552da7Schristos assert(fd >= -1);
8640e552da7Schristos QUEUE_INIT(&w->pending_queue);
8650e552da7Schristos QUEUE_INIT(&w->watcher_queue);
8660e552da7Schristos w->cb = cb;
8670e552da7Schristos w->fd = fd;
8680e552da7Schristos w->events = 0;
8690e552da7Schristos w->pevents = 0;
8700e552da7Schristos
8710e552da7Schristos #if defined(UV_HAVE_KQUEUE)
8720e552da7Schristos w->rcount = 0;
8730e552da7Schristos w->wcount = 0;
8740e552da7Schristos #endif /* defined(UV_HAVE_KQUEUE) */
8750e552da7Schristos }
8760e552da7Schristos
8770e552da7Schristos
uv__io_start(uv_loop_t * loop,uv__io_t * w,unsigned int events)8780e552da7Schristos void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
8790e552da7Schristos assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
8800e552da7Schristos assert(0 != events);
8810e552da7Schristos assert(w->fd >= 0);
8820e552da7Schristos assert(w->fd < INT_MAX);
8830e552da7Schristos
8840e552da7Schristos w->pevents |= events;
8850e552da7Schristos maybe_resize(loop, w->fd + 1);
8860e552da7Schristos
8870e552da7Schristos #if !defined(__sun)
8880e552da7Schristos /* The event ports backend needs to rearm all file descriptors on each and
8890e552da7Schristos * every tick of the event loop but the other backends allow us to
8900e552da7Schristos * short-circuit here if the event mask is unchanged.
8910e552da7Schristos */
8920e552da7Schristos if (w->events == w->pevents)
8930e552da7Schristos return;
8940e552da7Schristos #endif
8950e552da7Schristos
8960e552da7Schristos if (QUEUE_EMPTY(&w->watcher_queue))
8970e552da7Schristos QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
8980e552da7Schristos
8990e552da7Schristos if (loop->watchers[w->fd] == NULL) {
9000e552da7Schristos loop->watchers[w->fd] = w;
9010e552da7Schristos loop->nfds++;
9020e552da7Schristos }
9030e552da7Schristos }
9040e552da7Schristos
9050e552da7Schristos
uv__io_stop(uv_loop_t * loop,uv__io_t * w,unsigned int events)9060e552da7Schristos void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
9070e552da7Schristos assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
9080e552da7Schristos assert(0 != events);
9090e552da7Schristos
9100e552da7Schristos if (w->fd == -1)
9110e552da7Schristos return;
9120e552da7Schristos
9130e552da7Schristos assert(w->fd >= 0);
9140e552da7Schristos
9150e552da7Schristos /* Happens when uv__io_stop() is called on a handle that was never started. */
9160e552da7Schristos if ((unsigned) w->fd >= loop->nwatchers)
9170e552da7Schristos return;
9180e552da7Schristos
9190e552da7Schristos w->pevents &= ~events;
9200e552da7Schristos
9210e552da7Schristos if (w->pevents == 0) {
9220e552da7Schristos QUEUE_REMOVE(&w->watcher_queue);
9230e552da7Schristos QUEUE_INIT(&w->watcher_queue);
924*5f2f4271Schristos w->events = 0;
9250e552da7Schristos
926*5f2f4271Schristos if (w == loop->watchers[w->fd]) {
9270e552da7Schristos assert(loop->nfds > 0);
9280e552da7Schristos loop->watchers[w->fd] = NULL;
9290e552da7Schristos loop->nfds--;
9300e552da7Schristos }
9310e552da7Schristos }
9320e552da7Schristos else if (QUEUE_EMPTY(&w->watcher_queue))
9330e552da7Schristos QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
9340e552da7Schristos }
9350e552da7Schristos
9360e552da7Schristos
uv__io_close(uv_loop_t * loop,uv__io_t * w)9370e552da7Schristos void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
9380e552da7Schristos uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
9390e552da7Schristos QUEUE_REMOVE(&w->pending_queue);
9400e552da7Schristos
9410e552da7Schristos /* Remove stale events for this file descriptor */
9420e552da7Schristos if (w->fd != -1)
9430e552da7Schristos uv__platform_invalidate_fd(loop, w->fd);
9440e552da7Schristos }
9450e552da7Schristos
9460e552da7Schristos
uv__io_feed(uv_loop_t * loop,uv__io_t * w)9470e552da7Schristos void uv__io_feed(uv_loop_t* loop, uv__io_t* w) {
9480e552da7Schristos if (QUEUE_EMPTY(&w->pending_queue))
9490e552da7Schristos QUEUE_INSERT_TAIL(&loop->pending_queue, &w->pending_queue);
9500e552da7Schristos }
9510e552da7Schristos
9520e552da7Schristos
uv__io_active(const uv__io_t * w,unsigned int events)9530e552da7Schristos int uv__io_active(const uv__io_t* w, unsigned int events) {
9540e552da7Schristos assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
9550e552da7Schristos assert(0 != events);
9560e552da7Schristos return 0 != (w->pevents & events);
9570e552da7Schristos }
9580e552da7Schristos
9590e552da7Schristos
uv__fd_exists(uv_loop_t * loop,int fd)9600e552da7Schristos int uv__fd_exists(uv_loop_t* loop, int fd) {
9610e552da7Schristos return (unsigned) fd < loop->nwatchers && loop->watchers[fd] != NULL;
9620e552da7Schristos }
9630e552da7Schristos
9640e552da7Schristos
uv_getrusage(uv_rusage_t * rusage)9650e552da7Schristos int uv_getrusage(uv_rusage_t* rusage) {
9660e552da7Schristos struct rusage usage;
9670e552da7Schristos
9680e552da7Schristos if (getrusage(RUSAGE_SELF, &usage))
9690e552da7Schristos return UV__ERR(errno);
9700e552da7Schristos
9710e552da7Schristos rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec;
9720e552da7Schristos rusage->ru_utime.tv_usec = usage.ru_utime.tv_usec;
9730e552da7Schristos
9740e552da7Schristos rusage->ru_stime.tv_sec = usage.ru_stime.tv_sec;
9750e552da7Schristos rusage->ru_stime.tv_usec = usage.ru_stime.tv_usec;
9760e552da7Schristos
9770e552da7Schristos #if !defined(__MVS__) && !defined(__HAIKU__)
9780e552da7Schristos rusage->ru_maxrss = usage.ru_maxrss;
9790e552da7Schristos rusage->ru_ixrss = usage.ru_ixrss;
9800e552da7Schristos rusage->ru_idrss = usage.ru_idrss;
9810e552da7Schristos rusage->ru_isrss = usage.ru_isrss;
9820e552da7Schristos rusage->ru_minflt = usage.ru_minflt;
9830e552da7Schristos rusage->ru_majflt = usage.ru_majflt;
9840e552da7Schristos rusage->ru_nswap = usage.ru_nswap;
9850e552da7Schristos rusage->ru_inblock = usage.ru_inblock;
9860e552da7Schristos rusage->ru_oublock = usage.ru_oublock;
9870e552da7Schristos rusage->ru_msgsnd = usage.ru_msgsnd;
9880e552da7Schristos rusage->ru_msgrcv = usage.ru_msgrcv;
9890e552da7Schristos rusage->ru_nsignals = usage.ru_nsignals;
9900e552da7Schristos rusage->ru_nvcsw = usage.ru_nvcsw;
9910e552da7Schristos rusage->ru_nivcsw = usage.ru_nivcsw;
9920e552da7Schristos #endif
9930e552da7Schristos
9940e552da7Schristos return 0;
9950e552da7Schristos }
9960e552da7Schristos
9970e552da7Schristos
uv__open_cloexec(const char * path,int flags)9980e552da7Schristos int uv__open_cloexec(const char* path, int flags) {
9990e552da7Schristos #if defined(O_CLOEXEC)
10000e552da7Schristos int fd;
10010e552da7Schristos
10020e552da7Schristos fd = open(path, flags | O_CLOEXEC);
10030e552da7Schristos if (fd == -1)
10040e552da7Schristos return UV__ERR(errno);
10050e552da7Schristos
10060e552da7Schristos return fd;
10070e552da7Schristos #else /* O_CLOEXEC */
10080e552da7Schristos int err;
10090e552da7Schristos int fd;
10100e552da7Schristos
10110e552da7Schristos fd = open(path, flags);
10120e552da7Schristos if (fd == -1)
10130e552da7Schristos return UV__ERR(errno);
10140e552da7Schristos
10150e552da7Schristos err = uv__cloexec(fd, 1);
10160e552da7Schristos if (err) {
10170e552da7Schristos uv__close(fd);
10180e552da7Schristos return err;
10190e552da7Schristos }
10200e552da7Schristos
10210e552da7Schristos return fd;
10220e552da7Schristos #endif /* O_CLOEXEC */
10230e552da7Schristos }
10240e552da7Schristos
10250e552da7Schristos
uv__slurp(const char * filename,char * buf,size_t len)1026*5f2f4271Schristos int uv__slurp(const char* filename, char* buf, size_t len) {
1027*5f2f4271Schristos ssize_t n;
1028*5f2f4271Schristos int fd;
1029*5f2f4271Schristos
1030*5f2f4271Schristos assert(len > 0);
1031*5f2f4271Schristos
1032*5f2f4271Schristos fd = uv__open_cloexec(filename, O_RDONLY);
1033*5f2f4271Schristos if (fd < 0)
1034*5f2f4271Schristos return fd;
1035*5f2f4271Schristos
1036*5f2f4271Schristos do
1037*5f2f4271Schristos n = read(fd, buf, len - 1);
1038*5f2f4271Schristos while (n == -1 && errno == EINTR);
1039*5f2f4271Schristos
1040*5f2f4271Schristos if (uv__close_nocheckstdio(fd))
1041*5f2f4271Schristos abort();
1042*5f2f4271Schristos
1043*5f2f4271Schristos if (n < 0)
1044*5f2f4271Schristos return UV__ERR(errno);
1045*5f2f4271Schristos
1046*5f2f4271Schristos buf[n] = '\0';
1047*5f2f4271Schristos
1048*5f2f4271Schristos return 0;
1049*5f2f4271Schristos }
1050*5f2f4271Schristos
1051*5f2f4271Schristos
uv__dup2_cloexec(int oldfd,int newfd)10520e552da7Schristos int uv__dup2_cloexec(int oldfd, int newfd) {
10530e552da7Schristos #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__linux__)
10540e552da7Schristos int r;
10550e552da7Schristos
10560e552da7Schristos r = dup3(oldfd, newfd, O_CLOEXEC);
10570e552da7Schristos if (r == -1)
10580e552da7Schristos return UV__ERR(errno);
10590e552da7Schristos
10600e552da7Schristos return r;
10610e552da7Schristos #else
10620e552da7Schristos int err;
10630e552da7Schristos int r;
10640e552da7Schristos
10650e552da7Schristos r = dup2(oldfd, newfd); /* Never retry. */
10660e552da7Schristos if (r == -1)
10670e552da7Schristos return UV__ERR(errno);
10680e552da7Schristos
10690e552da7Schristos err = uv__cloexec(newfd, 1);
10700e552da7Schristos if (err != 0) {
10710e552da7Schristos uv__close(newfd);
10720e552da7Schristos return err;
10730e552da7Schristos }
10740e552da7Schristos
10750e552da7Schristos return r;
10760e552da7Schristos #endif
10770e552da7Schristos }
10780e552da7Schristos
10790e552da7Schristos
uv_os_homedir(char * buffer,size_t * size)10800e552da7Schristos int uv_os_homedir(char* buffer, size_t* size) {
10810e552da7Schristos uv_passwd_t pwd;
10820e552da7Schristos size_t len;
10830e552da7Schristos int r;
10840e552da7Schristos
10850e552da7Schristos /* Check if the HOME environment variable is set first. The task of
10860e552da7Schristos performing input validation on buffer and size is taken care of by
10870e552da7Schristos uv_os_getenv(). */
10880e552da7Schristos r = uv_os_getenv("HOME", buffer, size);
10890e552da7Schristos
10900e552da7Schristos if (r != UV_ENOENT)
10910e552da7Schristos return r;
10920e552da7Schristos
10930e552da7Schristos /* HOME is not set, so call uv__getpwuid_r() */
10940e552da7Schristos r = uv__getpwuid_r(&pwd);
10950e552da7Schristos
10960e552da7Schristos if (r != 0) {
10970e552da7Schristos return r;
10980e552da7Schristos }
10990e552da7Schristos
11000e552da7Schristos len = strlen(pwd.homedir);
11010e552da7Schristos
11020e552da7Schristos if (len >= *size) {
11030e552da7Schristos *size = len + 1;
11040e552da7Schristos uv_os_free_passwd(&pwd);
11050e552da7Schristos return UV_ENOBUFS;
11060e552da7Schristos }
11070e552da7Schristos
11080e552da7Schristos memcpy(buffer, pwd.homedir, len + 1);
11090e552da7Schristos *size = len;
11100e552da7Schristos uv_os_free_passwd(&pwd);
11110e552da7Schristos
11120e552da7Schristos return 0;
11130e552da7Schristos }
11140e552da7Schristos
11150e552da7Schristos
uv_os_tmpdir(char * buffer,size_t * size)11160e552da7Schristos int uv_os_tmpdir(char* buffer, size_t* size) {
11170e552da7Schristos const char* buf;
11180e552da7Schristos size_t len;
11190e552da7Schristos
11200e552da7Schristos if (buffer == NULL || size == NULL || *size == 0)
11210e552da7Schristos return UV_EINVAL;
11220e552da7Schristos
11230e552da7Schristos #define CHECK_ENV_VAR(name) \
11240e552da7Schristos do { \
11250e552da7Schristos buf = getenv(name); \
11260e552da7Schristos if (buf != NULL) \
11270e552da7Schristos goto return_buffer; \
11280e552da7Schristos } \
11290e552da7Schristos while (0)
11300e552da7Schristos
11310e552da7Schristos /* Check the TMPDIR, TMP, TEMP, and TEMPDIR environment variables in order */
11320e552da7Schristos CHECK_ENV_VAR("TMPDIR");
11330e552da7Schristos CHECK_ENV_VAR("TMP");
11340e552da7Schristos CHECK_ENV_VAR("TEMP");
11350e552da7Schristos CHECK_ENV_VAR("TEMPDIR");
11360e552da7Schristos
11370e552da7Schristos #undef CHECK_ENV_VAR
11380e552da7Schristos
11390e552da7Schristos /* No temp environment variables defined */
11400e552da7Schristos #if defined(__ANDROID__)
11410e552da7Schristos buf = "/data/local/tmp";
11420e552da7Schristos #else
11430e552da7Schristos buf = "/tmp";
11440e552da7Schristos #endif
11450e552da7Schristos
11460e552da7Schristos return_buffer:
11470e552da7Schristos len = strlen(buf);
11480e552da7Schristos
11490e552da7Schristos if (len >= *size) {
11500e552da7Schristos *size = len + 1;
11510e552da7Schristos return UV_ENOBUFS;
11520e552da7Schristos }
11530e552da7Schristos
11540e552da7Schristos /* The returned directory should not have a trailing slash. */
11550e552da7Schristos if (len > 1 && buf[len - 1] == '/') {
11560e552da7Schristos len--;
11570e552da7Schristos }
11580e552da7Schristos
11590e552da7Schristos memcpy(buffer, buf, len + 1);
11600e552da7Schristos buffer[len] = '\0';
11610e552da7Schristos *size = len;
11620e552da7Schristos
11630e552da7Schristos return 0;
11640e552da7Schristos }
11650e552da7Schristos
11660e552da7Schristos
uv__getpwuid_r(uv_passwd_t * pwd)11670e552da7Schristos int uv__getpwuid_r(uv_passwd_t* pwd) {
11680e552da7Schristos struct passwd pw;
11690e552da7Schristos struct passwd* result;
11700e552da7Schristos char* buf;
11710e552da7Schristos uid_t uid;
11720e552da7Schristos size_t bufsize;
11730e552da7Schristos size_t name_size;
11740e552da7Schristos size_t homedir_size;
11750e552da7Schristos size_t shell_size;
11760e552da7Schristos int r;
11770e552da7Schristos
11780e552da7Schristos if (pwd == NULL)
11790e552da7Schristos return UV_EINVAL;
11800e552da7Schristos
11810e552da7Schristos uid = geteuid();
11820e552da7Schristos
1183*5f2f4271Schristos /* Calling sysconf(_SC_GETPW_R_SIZE_MAX) would get the suggested size, but it
1184*5f2f4271Schristos * is frequently 1024 or 4096, so we can just use that directly. The pwent
1185*5f2f4271Schristos * will not usually be large. */
1186*5f2f4271Schristos for (bufsize = 2000;; bufsize *= 2) {
11870e552da7Schristos buf = uv__malloc(bufsize);
11880e552da7Schristos
11890e552da7Schristos if (buf == NULL)
11900e552da7Schristos return UV_ENOMEM;
11910e552da7Schristos
1192*5f2f4271Schristos do
11930e552da7Schristos r = getpwuid_r(uid, &pw, buf, bufsize, &result);
1194*5f2f4271Schristos while (r == EINTR);
1195*5f2f4271Schristos
1196*5f2f4271Schristos if (r != 0 || result == NULL)
1197*5f2f4271Schristos uv__free(buf);
11980e552da7Schristos
11990e552da7Schristos if (r != ERANGE)
12000e552da7Schristos break;
12010e552da7Schristos }
12020e552da7Schristos
1203*5f2f4271Schristos if (r != 0)
1204*5f2f4271Schristos return UV__ERR(r);
12050e552da7Schristos
1206*5f2f4271Schristos if (result == NULL)
12070e552da7Schristos return UV_ENOENT;
12080e552da7Schristos
12090e552da7Schristos /* Allocate memory for the username, shell, and home directory */
12100e552da7Schristos name_size = strlen(pw.pw_name) + 1;
12110e552da7Schristos homedir_size = strlen(pw.pw_dir) + 1;
12120e552da7Schristos shell_size = strlen(pw.pw_shell) + 1;
12130e552da7Schristos pwd->username = uv__malloc(name_size + homedir_size + shell_size);
12140e552da7Schristos
12150e552da7Schristos if (pwd->username == NULL) {
12160e552da7Schristos uv__free(buf);
12170e552da7Schristos return UV_ENOMEM;
12180e552da7Schristos }
12190e552da7Schristos
12200e552da7Schristos /* Copy the username */
12210e552da7Schristos memcpy(pwd->username, pw.pw_name, name_size);
12220e552da7Schristos
12230e552da7Schristos /* Copy the home directory */
12240e552da7Schristos pwd->homedir = pwd->username + name_size;
12250e552da7Schristos memcpy(pwd->homedir, pw.pw_dir, homedir_size);
12260e552da7Schristos
12270e552da7Schristos /* Copy the shell */
12280e552da7Schristos pwd->shell = pwd->homedir + homedir_size;
12290e552da7Schristos memcpy(pwd->shell, pw.pw_shell, shell_size);
12300e552da7Schristos
12310e552da7Schristos /* Copy the uid and gid */
12320e552da7Schristos pwd->uid = pw.pw_uid;
12330e552da7Schristos pwd->gid = pw.pw_gid;
12340e552da7Schristos
12350e552da7Schristos uv__free(buf);
12360e552da7Schristos
12370e552da7Schristos return 0;
12380e552da7Schristos }
12390e552da7Schristos
12400e552da7Schristos
uv_os_free_passwd(uv_passwd_t * pwd)12410e552da7Schristos void uv_os_free_passwd(uv_passwd_t* pwd) {
12420e552da7Schristos if (pwd == NULL)
12430e552da7Schristos return;
12440e552da7Schristos
12450e552da7Schristos /*
12460e552da7Schristos The memory for name, shell, and homedir are allocated in a single
12470e552da7Schristos uv__malloc() call. The base of the pointer is stored in pwd->username, so
12480e552da7Schristos that is the field that needs to be freed.
12490e552da7Schristos */
12500e552da7Schristos uv__free(pwd->username);
12510e552da7Schristos pwd->username = NULL;
12520e552da7Schristos pwd->shell = NULL;
12530e552da7Schristos pwd->homedir = NULL;
12540e552da7Schristos }
12550e552da7Schristos
12560e552da7Schristos
uv_os_get_passwd(uv_passwd_t * pwd)12570e552da7Schristos int uv_os_get_passwd(uv_passwd_t* pwd) {
12580e552da7Schristos return uv__getpwuid_r(pwd);
12590e552da7Schristos }
12600e552da7Schristos
12610e552da7Schristos
uv_translate_sys_error(int sys_errno)12620e552da7Schristos int uv_translate_sys_error(int sys_errno) {
12630e552da7Schristos /* If < 0 then it's already a libuv error. */
12640e552da7Schristos return sys_errno <= 0 ? sys_errno : -sys_errno;
12650e552da7Schristos }
12660e552da7Schristos
12670e552da7Schristos
uv_os_environ(uv_env_item_t ** envitems,int * count)12680e552da7Schristos int uv_os_environ(uv_env_item_t** envitems, int* count) {
12690e552da7Schristos int i, j, cnt;
12700e552da7Schristos uv_env_item_t* envitem;
12710e552da7Schristos
12720e552da7Schristos *envitems = NULL;
12730e552da7Schristos *count = 0;
12740e552da7Schristos
12750e552da7Schristos for (i = 0; environ[i] != NULL; i++);
12760e552da7Schristos
12770e552da7Schristos *envitems = uv__calloc(i, sizeof(**envitems));
12780e552da7Schristos
12790e552da7Schristos if (*envitems == NULL)
12800e552da7Schristos return UV_ENOMEM;
12810e552da7Schristos
12820e552da7Schristos for (j = 0, cnt = 0; j < i; j++) {
12830e552da7Schristos char* buf;
12840e552da7Schristos char* ptr;
12850e552da7Schristos
12860e552da7Schristos if (environ[j] == NULL)
12870e552da7Schristos break;
12880e552da7Schristos
12890e552da7Schristos buf = uv__strdup(environ[j]);
12900e552da7Schristos if (buf == NULL)
12910e552da7Schristos goto fail;
12920e552da7Schristos
12930e552da7Schristos ptr = strchr(buf, '=');
12940e552da7Schristos if (ptr == NULL) {
12950e552da7Schristos uv__free(buf);
12960e552da7Schristos continue;
12970e552da7Schristos }
12980e552da7Schristos
12990e552da7Schristos *ptr = '\0';
13000e552da7Schristos
13010e552da7Schristos envitem = &(*envitems)[cnt];
13020e552da7Schristos envitem->name = buf;
13030e552da7Schristos envitem->value = ptr + 1;
13040e552da7Schristos
13050e552da7Schristos cnt++;
13060e552da7Schristos }
13070e552da7Schristos
13080e552da7Schristos *count = cnt;
13090e552da7Schristos return 0;
13100e552da7Schristos
13110e552da7Schristos fail:
13120e552da7Schristos for (i = 0; i < cnt; i++) {
13130e552da7Schristos envitem = &(*envitems)[cnt];
13140e552da7Schristos uv__free(envitem->name);
13150e552da7Schristos }
13160e552da7Schristos uv__free(*envitems);
13170e552da7Schristos
13180e552da7Schristos *envitems = NULL;
13190e552da7Schristos *count = 0;
13200e552da7Schristos return UV_ENOMEM;
13210e552da7Schristos }
13220e552da7Schristos
13230e552da7Schristos
uv_os_getenv(const char * name,char * buffer,size_t * size)13240e552da7Schristos int uv_os_getenv(const char* name, char* buffer, size_t* size) {
13250e552da7Schristos char* var;
13260e552da7Schristos size_t len;
13270e552da7Schristos
13280e552da7Schristos if (name == NULL || buffer == NULL || size == NULL || *size == 0)
13290e552da7Schristos return UV_EINVAL;
13300e552da7Schristos
13310e552da7Schristos var = getenv(name);
13320e552da7Schristos
13330e552da7Schristos if (var == NULL)
13340e552da7Schristos return UV_ENOENT;
13350e552da7Schristos
13360e552da7Schristos len = strlen(var);
13370e552da7Schristos
13380e552da7Schristos if (len >= *size) {
13390e552da7Schristos *size = len + 1;
13400e552da7Schristos return UV_ENOBUFS;
13410e552da7Schristos }
13420e552da7Schristos
13430e552da7Schristos memcpy(buffer, var, len + 1);
13440e552da7Schristos *size = len;
13450e552da7Schristos
13460e552da7Schristos return 0;
13470e552da7Schristos }
13480e552da7Schristos
13490e552da7Schristos
uv_os_setenv(const char * name,const char * value)13500e552da7Schristos int uv_os_setenv(const char* name, const char* value) {
13510e552da7Schristos if (name == NULL || value == NULL)
13520e552da7Schristos return UV_EINVAL;
13530e552da7Schristos
13540e552da7Schristos if (setenv(name, value, 1) != 0)
13550e552da7Schristos return UV__ERR(errno);
13560e552da7Schristos
13570e552da7Schristos return 0;
13580e552da7Schristos }
13590e552da7Schristos
13600e552da7Schristos
uv_os_unsetenv(const char * name)13610e552da7Schristos int uv_os_unsetenv(const char* name) {
13620e552da7Schristos if (name == NULL)
13630e552da7Schristos return UV_EINVAL;
13640e552da7Schristos
13650e552da7Schristos if (unsetenv(name) != 0)
13660e552da7Schristos return UV__ERR(errno);
13670e552da7Schristos
13680e552da7Schristos return 0;
13690e552da7Schristos }
13700e552da7Schristos
13710e552da7Schristos
uv_os_gethostname(char * buffer,size_t * size)13720e552da7Schristos int uv_os_gethostname(char* buffer, size_t* size) {
13730e552da7Schristos /*
13740e552da7Schristos On some platforms, if the input buffer is not large enough, gethostname()
13750e552da7Schristos succeeds, but truncates the result. libuv can detect this and return ENOBUFS
13760e552da7Schristos instead by creating a large enough buffer and comparing the hostname length
13770e552da7Schristos to the size input.
13780e552da7Schristos */
13790e552da7Schristos char buf[UV_MAXHOSTNAMESIZE];
13800e552da7Schristos size_t len;
13810e552da7Schristos
13820e552da7Schristos if (buffer == NULL || size == NULL || *size == 0)
13830e552da7Schristos return UV_EINVAL;
13840e552da7Schristos
13850e552da7Schristos if (gethostname(buf, sizeof(buf)) != 0)
13860e552da7Schristos return UV__ERR(errno);
13870e552da7Schristos
13880e552da7Schristos buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */
13890e552da7Schristos len = strlen(buf);
13900e552da7Schristos
13910e552da7Schristos if (len >= *size) {
13920e552da7Schristos *size = len + 1;
13930e552da7Schristos return UV_ENOBUFS;
13940e552da7Schristos }
13950e552da7Schristos
13960e552da7Schristos memcpy(buffer, buf, len + 1);
13970e552da7Schristos *size = len;
13980e552da7Schristos return 0;
13990e552da7Schristos }
14000e552da7Schristos
14010e552da7Schristos
uv_get_osfhandle(int fd)14020e552da7Schristos uv_os_fd_t uv_get_osfhandle(int fd) {
14030e552da7Schristos return fd;
14040e552da7Schristos }
14050e552da7Schristos
uv_open_osfhandle(uv_os_fd_t os_fd)14060e552da7Schristos int uv_open_osfhandle(uv_os_fd_t os_fd) {
14070e552da7Schristos return os_fd;
14080e552da7Schristos }
14090e552da7Schristos
uv_os_getpid(void)14100e552da7Schristos uv_pid_t uv_os_getpid(void) {
14110e552da7Schristos return getpid();
14120e552da7Schristos }
14130e552da7Schristos
14140e552da7Schristos
uv_os_getppid(void)14150e552da7Schristos uv_pid_t uv_os_getppid(void) {
14160e552da7Schristos return getppid();
14170e552da7Schristos }
14180e552da7Schristos
14190e552da7Schristos
uv_os_getpriority(uv_pid_t pid,int * priority)14200e552da7Schristos int uv_os_getpriority(uv_pid_t pid, int* priority) {
14210e552da7Schristos int r;
14220e552da7Schristos
14230e552da7Schristos if (priority == NULL)
14240e552da7Schristos return UV_EINVAL;
14250e552da7Schristos
14260e552da7Schristos errno = 0;
14270e552da7Schristos r = getpriority(PRIO_PROCESS, (int) pid);
14280e552da7Schristos
14290e552da7Schristos if (r == -1 && errno != 0)
14300e552da7Schristos return UV__ERR(errno);
14310e552da7Schristos
14320e552da7Schristos *priority = r;
14330e552da7Schristos return 0;
14340e552da7Schristos }
14350e552da7Schristos
14360e552da7Schristos
uv_os_setpriority(uv_pid_t pid,int priority)14370e552da7Schristos int uv_os_setpriority(uv_pid_t pid, int priority) {
14380e552da7Schristos if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
14390e552da7Schristos return UV_EINVAL;
14400e552da7Schristos
14410e552da7Schristos if (setpriority(PRIO_PROCESS, (int) pid, priority) != 0)
14420e552da7Schristos return UV__ERR(errno);
14430e552da7Schristos
14440e552da7Schristos return 0;
14450e552da7Schristos }
14460e552da7Schristos
14470e552da7Schristos
uv_os_uname(uv_utsname_t * buffer)14480e552da7Schristos int uv_os_uname(uv_utsname_t* buffer) {
14490e552da7Schristos struct utsname buf;
14500e552da7Schristos int r;
14510e552da7Schristos
14520e552da7Schristos if (buffer == NULL)
14530e552da7Schristos return UV_EINVAL;
14540e552da7Schristos
14550e552da7Schristos if (uname(&buf) == -1) {
14560e552da7Schristos r = UV__ERR(errno);
14570e552da7Schristos goto error;
14580e552da7Schristos }
14590e552da7Schristos
14600e552da7Schristos r = uv__strscpy(buffer->sysname, buf.sysname, sizeof(buffer->sysname));
14610e552da7Schristos if (r == UV_E2BIG)
14620e552da7Schristos goto error;
14630e552da7Schristos
14640e552da7Schristos #ifdef _AIX
14650e552da7Schristos r = snprintf(buffer->release,
14660e552da7Schristos sizeof(buffer->release),
14670e552da7Schristos "%s.%s",
14680e552da7Schristos buf.version,
14690e552da7Schristos buf.release);
14700e552da7Schristos if (r >= sizeof(buffer->release)) {
14710e552da7Schristos r = UV_E2BIG;
14720e552da7Schristos goto error;
14730e552da7Schristos }
14740e552da7Schristos #else
14750e552da7Schristos r = uv__strscpy(buffer->release, buf.release, sizeof(buffer->release));
14760e552da7Schristos if (r == UV_E2BIG)
14770e552da7Schristos goto error;
14780e552da7Schristos #endif
14790e552da7Schristos
14800e552da7Schristos r = uv__strscpy(buffer->version, buf.version, sizeof(buffer->version));
14810e552da7Schristos if (r == UV_E2BIG)
14820e552da7Schristos goto error;
14830e552da7Schristos
14840e552da7Schristos #if defined(_AIX) || defined(__PASE__)
14850e552da7Schristos r = uv__strscpy(buffer->machine, "ppc64", sizeof(buffer->machine));
14860e552da7Schristos #else
14870e552da7Schristos r = uv__strscpy(buffer->machine, buf.machine, sizeof(buffer->machine));
14880e552da7Schristos #endif
14890e552da7Schristos
14900e552da7Schristos if (r == UV_E2BIG)
14910e552da7Schristos goto error;
14920e552da7Schristos
14930e552da7Schristos return 0;
14940e552da7Schristos
14950e552da7Schristos error:
14960e552da7Schristos buffer->sysname[0] = '\0';
14970e552da7Schristos buffer->release[0] = '\0';
14980e552da7Schristos buffer->version[0] = '\0';
14990e552da7Schristos buffer->machine[0] = '\0';
15000e552da7Schristos return r;
15010e552da7Schristos }
15020e552da7Schristos
uv__getsockpeername(const uv_handle_t * handle,uv__peersockfunc func,struct sockaddr * name,int * namelen)15030e552da7Schristos int uv__getsockpeername(const uv_handle_t* handle,
15040e552da7Schristos uv__peersockfunc func,
15050e552da7Schristos struct sockaddr* name,
15060e552da7Schristos int* namelen) {
15070e552da7Schristos socklen_t socklen;
15080e552da7Schristos uv_os_fd_t fd;
15090e552da7Schristos int r;
15100e552da7Schristos
15110e552da7Schristos r = uv_fileno(handle, &fd);
15120e552da7Schristos if (r < 0)
15130e552da7Schristos return r;
15140e552da7Schristos
15150e552da7Schristos /* sizeof(socklen_t) != sizeof(int) on some systems. */
15160e552da7Schristos socklen = (socklen_t) *namelen;
15170e552da7Schristos
15180e552da7Schristos if (func(fd, name, &socklen))
15190e552da7Schristos return UV__ERR(errno);
15200e552da7Schristos
15210e552da7Schristos *namelen = (int) socklen;
15220e552da7Schristos return 0;
15230e552da7Schristos }
15240e552da7Schristos
uv_gettimeofday(uv_timeval64_t * tv)15250e552da7Schristos int uv_gettimeofday(uv_timeval64_t* tv) {
15260e552da7Schristos struct timeval time;
15270e552da7Schristos
15280e552da7Schristos if (tv == NULL)
15290e552da7Schristos return UV_EINVAL;
15300e552da7Schristos
15310e552da7Schristos if (gettimeofday(&time, NULL) != 0)
15320e552da7Schristos return UV__ERR(errno);
15330e552da7Schristos
15340e552da7Schristos tv->tv_sec = (int64_t) time.tv_sec;
15350e552da7Schristos tv->tv_usec = (int32_t) time.tv_usec;
15360e552da7Schristos return 0;
15370e552da7Schristos }
15380e552da7Schristos
uv_sleep(unsigned int msec)15390e552da7Schristos void uv_sleep(unsigned int msec) {
15400e552da7Schristos struct timespec timeout;
15410e552da7Schristos int rc;
15420e552da7Schristos
15430e552da7Schristos timeout.tv_sec = msec / 1000;
15440e552da7Schristos timeout.tv_nsec = (msec % 1000) * 1000 * 1000;
15450e552da7Schristos
15460e552da7Schristos do
15470e552da7Schristos rc = nanosleep(&timeout, &timeout);
15480e552da7Schristos while (rc == -1 && errno == EINTR);
15490e552da7Schristos
15500e552da7Schristos assert(rc == 0);
15510e552da7Schristos }
1552*5f2f4271Schristos
uv__search_path(const char * prog,char * buf,size_t * buflen)1553*5f2f4271Schristos int uv__search_path(const char* prog, char* buf, size_t* buflen) {
1554*5f2f4271Schristos char abspath[UV__PATH_MAX];
1555*5f2f4271Schristos size_t abspath_size;
1556*5f2f4271Schristos char trypath[UV__PATH_MAX];
1557*5f2f4271Schristos char* cloned_path;
1558*5f2f4271Schristos char* path_env;
1559*5f2f4271Schristos char* token;
1560*5f2f4271Schristos char* itr;
1561*5f2f4271Schristos
1562*5f2f4271Schristos if (buf == NULL || buflen == NULL || *buflen == 0)
1563*5f2f4271Schristos return UV_EINVAL;
1564*5f2f4271Schristos
1565*5f2f4271Schristos /*
1566*5f2f4271Schristos * Possibilities for prog:
1567*5f2f4271Schristos * i) an absolute path such as: /home/user/myprojects/nodejs/node
1568*5f2f4271Schristos * ii) a relative path such as: ./node or ../myprojects/nodejs/node
1569*5f2f4271Schristos * iii) a bare filename such as "node", after exporting PATH variable
1570*5f2f4271Schristos * to its location.
1571*5f2f4271Schristos */
1572*5f2f4271Schristos
1573*5f2f4271Schristos /* Case i) and ii) absolute or relative paths */
1574*5f2f4271Schristos if (strchr(prog, '/') != NULL) {
1575*5f2f4271Schristos if (realpath(prog, abspath) != abspath)
1576*5f2f4271Schristos return UV__ERR(errno);
1577*5f2f4271Schristos
1578*5f2f4271Schristos abspath_size = strlen(abspath);
1579*5f2f4271Schristos
1580*5f2f4271Schristos *buflen -= 1;
1581*5f2f4271Schristos if (*buflen > abspath_size)
1582*5f2f4271Schristos *buflen = abspath_size;
1583*5f2f4271Schristos
1584*5f2f4271Schristos memcpy(buf, abspath, *buflen);
1585*5f2f4271Schristos buf[*buflen] = '\0';
1586*5f2f4271Schristos
1587*5f2f4271Schristos return 0;
1588*5f2f4271Schristos }
1589*5f2f4271Schristos
1590*5f2f4271Schristos /* Case iii). Search PATH environment variable */
1591*5f2f4271Schristos cloned_path = NULL;
1592*5f2f4271Schristos token = NULL;
1593*5f2f4271Schristos path_env = getenv("PATH");
1594*5f2f4271Schristos
1595*5f2f4271Schristos if (path_env == NULL)
1596*5f2f4271Schristos return UV_EINVAL;
1597*5f2f4271Schristos
1598*5f2f4271Schristos cloned_path = uv__strdup(path_env);
1599*5f2f4271Schristos if (cloned_path == NULL)
1600*5f2f4271Schristos return UV_ENOMEM;
1601*5f2f4271Schristos
1602*5f2f4271Schristos token = uv__strtok(cloned_path, ":", &itr);
1603*5f2f4271Schristos while (token != NULL) {
1604*5f2f4271Schristos snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, prog);
1605*5f2f4271Schristos if (realpath(trypath, abspath) == abspath) {
1606*5f2f4271Schristos /* Check the match is executable */
1607*5f2f4271Schristos if (access(abspath, X_OK) == 0) {
1608*5f2f4271Schristos abspath_size = strlen(abspath);
1609*5f2f4271Schristos
1610*5f2f4271Schristos *buflen -= 1;
1611*5f2f4271Schristos if (*buflen > abspath_size)
1612*5f2f4271Schristos *buflen = abspath_size;
1613*5f2f4271Schristos
1614*5f2f4271Schristos memcpy(buf, abspath, *buflen);
1615*5f2f4271Schristos buf[*buflen] = '\0';
1616*5f2f4271Schristos
1617*5f2f4271Schristos uv__free(cloned_path);
1618*5f2f4271Schristos return 0;
1619*5f2f4271Schristos }
1620*5f2f4271Schristos }
1621*5f2f4271Schristos token = uv__strtok(NULL, ":", &itr);
1622*5f2f4271Schristos }
1623*5f2f4271Schristos uv__free(cloned_path);
1624*5f2f4271Schristos
1625*5f2f4271Schristos /* Out of tokens (path entries), and no match found */
1626*5f2f4271Schristos return UV_EINVAL;
1627*5f2f4271Schristos }
1628*5f2f4271Schristos
1629*5f2f4271Schristos
uv_available_parallelism(void)1630*5f2f4271Schristos unsigned int uv_available_parallelism(void) {
1631*5f2f4271Schristos #ifdef __linux__
1632*5f2f4271Schristos cpu_set_t set;
1633*5f2f4271Schristos long rc;
1634*5f2f4271Schristos
1635*5f2f4271Schristos memset(&set, 0, sizeof(set));
1636*5f2f4271Schristos
1637*5f2f4271Schristos /* sysconf(_SC_NPROCESSORS_ONLN) in musl calls sched_getaffinity() but in
1638*5f2f4271Schristos * glibc it's... complicated... so for consistency try sched_getaffinity()
1639*5f2f4271Schristos * before falling back to sysconf(_SC_NPROCESSORS_ONLN).
1640*5f2f4271Schristos */
1641*5f2f4271Schristos if (0 == sched_getaffinity(0, sizeof(set), &set))
1642*5f2f4271Schristos rc = CPU_COUNT(&set);
1643*5f2f4271Schristos else
1644*5f2f4271Schristos rc = sysconf(_SC_NPROCESSORS_ONLN);
1645*5f2f4271Schristos
1646*5f2f4271Schristos if (rc < 1)
1647*5f2f4271Schristos rc = 1;
1648*5f2f4271Schristos
1649*5f2f4271Schristos return (unsigned) rc;
1650*5f2f4271Schristos #elif defined(__MVS__)
1651*5f2f4271Schristos int rc;
1652*5f2f4271Schristos
1653*5f2f4271Schristos rc = __get_num_online_cpus();
1654*5f2f4271Schristos if (rc < 1)
1655*5f2f4271Schristos rc = 1;
1656*5f2f4271Schristos
1657*5f2f4271Schristos return (unsigned) rc;
1658*5f2f4271Schristos #else /* __linux__ */
1659*5f2f4271Schristos long rc;
1660*5f2f4271Schristos
1661*5f2f4271Schristos rc = sysconf(_SC_NPROCESSORS_ONLN);
1662*5f2f4271Schristos if (rc < 1)
1663*5f2f4271Schristos rc = 1;
1664*5f2f4271Schristos
1665*5f2f4271Schristos return (unsigned) rc;
1666*5f2f4271Schristos #endif /* __linux__ */
1667*5f2f4271Schristos }
1668