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"
230e552da7Schristos
240e552da7Schristos #include <stdio.h>
250e552da7Schristos #include <stdint.h>
260e552da7Schristos #include <stdlib.h>
270e552da7Schristos #include <string.h>
280e552da7Schristos #include <assert.h>
290e552da7Schristos #include <errno.h>
300e552da7Schristos
310e552da7Schristos #ifndef SUNOS_NO_IFADDRS
320e552da7Schristos # include <ifaddrs.h>
330e552da7Schristos #endif
340e552da7Schristos #include <net/if.h>
350e552da7Schristos #include <net/if_dl.h>
360e552da7Schristos #include <net/if_arp.h>
370e552da7Schristos #include <sys/sockio.h>
380e552da7Schristos
390e552da7Schristos #include <sys/loadavg.h>
400e552da7Schristos #include <sys/time.h>
410e552da7Schristos #include <unistd.h>
420e552da7Schristos #include <kstat.h>
430e552da7Schristos #include <fcntl.h>
440e552da7Schristos
450e552da7Schristos #include <sys/port.h>
460e552da7Schristos #include <port.h>
470e552da7Schristos
480e552da7Schristos #define PORT_FIRED 0x69
490e552da7Schristos #define PORT_UNUSED 0x0
500e552da7Schristos #define PORT_LOADED 0x99
510e552da7Schristos #define PORT_DELETED -1
520e552da7Schristos
530e552da7Schristos #if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
540e552da7Schristos #define PROCFS_FILE_OFFSET_BITS_HACK 1
550e552da7Schristos #undef _FILE_OFFSET_BITS
560e552da7Schristos #else
570e552da7Schristos #define PROCFS_FILE_OFFSET_BITS_HACK 0
580e552da7Schristos #endif
590e552da7Schristos
600e552da7Schristos #include <procfs.h>
610e552da7Schristos
620e552da7Schristos #if (PROCFS_FILE_OFFSET_BITS_HACK - 0 == 1)
630e552da7Schristos #define _FILE_OFFSET_BITS 64
640e552da7Schristos #endif
650e552da7Schristos
660e552da7Schristos
uv__platform_loop_init(uv_loop_t * loop)670e552da7Schristos int uv__platform_loop_init(uv_loop_t* loop) {
680e552da7Schristos int err;
690e552da7Schristos int fd;
700e552da7Schristos
710e552da7Schristos loop->fs_fd = -1;
720e552da7Schristos loop->backend_fd = -1;
730e552da7Schristos
740e552da7Schristos fd = port_create();
750e552da7Schristos if (fd == -1)
760e552da7Schristos return UV__ERR(errno);
770e552da7Schristos
780e552da7Schristos err = uv__cloexec(fd, 1);
790e552da7Schristos if (err) {
800e552da7Schristos uv__close(fd);
810e552da7Schristos return err;
820e552da7Schristos }
830e552da7Schristos loop->backend_fd = fd;
840e552da7Schristos
850e552da7Schristos return 0;
860e552da7Schristos }
870e552da7Schristos
880e552da7Schristos
uv__platform_loop_delete(uv_loop_t * loop)890e552da7Schristos void uv__platform_loop_delete(uv_loop_t* loop) {
900e552da7Schristos if (loop->fs_fd != -1) {
910e552da7Schristos uv__close(loop->fs_fd);
920e552da7Schristos loop->fs_fd = -1;
930e552da7Schristos }
940e552da7Schristos
950e552da7Schristos if (loop->backend_fd != -1) {
960e552da7Schristos uv__close(loop->backend_fd);
970e552da7Schristos loop->backend_fd = -1;
980e552da7Schristos }
990e552da7Schristos }
1000e552da7Schristos
1010e552da7Schristos
uv__io_fork(uv_loop_t * loop)1020e552da7Schristos int uv__io_fork(uv_loop_t* loop) {
1030e552da7Schristos #if defined(PORT_SOURCE_FILE)
1040e552da7Schristos if (loop->fs_fd != -1) {
1050e552da7Schristos /* stop the watcher before we blow away its fileno */
1060e552da7Schristos uv__io_stop(loop, &loop->fs_event_watcher, POLLIN);
1070e552da7Schristos }
1080e552da7Schristos #endif
1090e552da7Schristos uv__platform_loop_delete(loop);
1100e552da7Schristos return uv__platform_loop_init(loop);
1110e552da7Schristos }
1120e552da7Schristos
1130e552da7Schristos
uv__platform_invalidate_fd(uv_loop_t * loop,int fd)1140e552da7Schristos void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
1150e552da7Schristos struct port_event* events;
1160e552da7Schristos uintptr_t i;
1170e552da7Schristos uintptr_t nfds;
1180e552da7Schristos
1190e552da7Schristos assert(loop->watchers != NULL);
1200e552da7Schristos assert(fd >= 0);
1210e552da7Schristos
1220e552da7Schristos events = (struct port_event*) loop->watchers[loop->nwatchers];
1230e552da7Schristos nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
1240e552da7Schristos if (events == NULL)
1250e552da7Schristos return;
1260e552da7Schristos
1270e552da7Schristos /* Invalidate events with same file descriptor */
1280e552da7Schristos for (i = 0; i < nfds; i++)
1290e552da7Schristos if ((int) events[i].portev_object == fd)
1300e552da7Schristos events[i].portev_object = -1;
1310e552da7Schristos }
1320e552da7Schristos
1330e552da7Schristos
uv__io_check_fd(uv_loop_t * loop,int fd)1340e552da7Schristos int uv__io_check_fd(uv_loop_t* loop, int fd) {
1350e552da7Schristos if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0))
1360e552da7Schristos return UV__ERR(errno);
1370e552da7Schristos
1380e552da7Schristos if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) {
1390e552da7Schristos perror("(libuv) port_dissociate()");
1400e552da7Schristos abort();
1410e552da7Schristos }
1420e552da7Schristos
1430e552da7Schristos return 0;
1440e552da7Schristos }
1450e552da7Schristos
1460e552da7Schristos
uv__io_poll(uv_loop_t * loop,int timeout)1470e552da7Schristos void uv__io_poll(uv_loop_t* loop, int timeout) {
1480e552da7Schristos struct port_event events[1024];
1490e552da7Schristos struct port_event* pe;
1500e552da7Schristos struct timespec spec;
1510e552da7Schristos QUEUE* q;
1520e552da7Schristos uv__io_t* w;
1530e552da7Schristos sigset_t* pset;
1540e552da7Schristos sigset_t set;
1550e552da7Schristos uint64_t base;
1560e552da7Schristos uint64_t diff;
1570e552da7Schristos unsigned int nfds;
1580e552da7Schristos unsigned int i;
1590e552da7Schristos int saved_errno;
1600e552da7Schristos int have_signals;
1610e552da7Schristos int nevents;
1620e552da7Schristos int count;
1630e552da7Schristos int err;
1640e552da7Schristos int fd;
165*5f2f4271Schristos int user_timeout;
166*5f2f4271Schristos int reset_timeout;
1670e552da7Schristos
1680e552da7Schristos if (loop->nfds == 0) {
1690e552da7Schristos assert(QUEUE_EMPTY(&loop->watcher_queue));
1700e552da7Schristos return;
1710e552da7Schristos }
1720e552da7Schristos
1730e552da7Schristos while (!QUEUE_EMPTY(&loop->watcher_queue)) {
1740e552da7Schristos q = QUEUE_HEAD(&loop->watcher_queue);
1750e552da7Schristos QUEUE_REMOVE(q);
1760e552da7Schristos QUEUE_INIT(q);
1770e552da7Schristos
1780e552da7Schristos w = QUEUE_DATA(q, uv__io_t, watcher_queue);
1790e552da7Schristos assert(w->pevents != 0);
1800e552da7Schristos
1810e552da7Schristos if (port_associate(loop->backend_fd,
1820e552da7Schristos PORT_SOURCE_FD,
1830e552da7Schristos w->fd,
1840e552da7Schristos w->pevents,
1850e552da7Schristos 0)) {
1860e552da7Schristos perror("(libuv) port_associate()");
1870e552da7Schristos abort();
1880e552da7Schristos }
1890e552da7Schristos
1900e552da7Schristos w->events = w->pevents;
1910e552da7Schristos }
1920e552da7Schristos
1930e552da7Schristos pset = NULL;
1940e552da7Schristos if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
1950e552da7Schristos pset = &set;
1960e552da7Schristos sigemptyset(pset);
1970e552da7Schristos sigaddset(pset, SIGPROF);
1980e552da7Schristos }
1990e552da7Schristos
2000e552da7Schristos assert(timeout >= -1);
2010e552da7Schristos base = loop->time;
2020e552da7Schristos count = 48; /* Benchmarks suggest this gives the best throughput. */
2030e552da7Schristos
204*5f2f4271Schristos if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
205*5f2f4271Schristos reset_timeout = 1;
206*5f2f4271Schristos user_timeout = timeout;
207*5f2f4271Schristos timeout = 0;
208*5f2f4271Schristos } else {
209*5f2f4271Schristos reset_timeout = 0;
210*5f2f4271Schristos }
211*5f2f4271Schristos
2120e552da7Schristos for (;;) {
213*5f2f4271Schristos /* Only need to set the provider_entry_time if timeout != 0. The function
214*5f2f4271Schristos * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
215*5f2f4271Schristos */
216*5f2f4271Schristos if (timeout != 0)
217*5f2f4271Schristos uv__metrics_set_provider_entry_time(loop);
218*5f2f4271Schristos
2190e552da7Schristos if (timeout != -1) {
2200e552da7Schristos spec.tv_sec = timeout / 1000;
2210e552da7Schristos spec.tv_nsec = (timeout % 1000) * 1000000;
2220e552da7Schristos }
2230e552da7Schristos
2240e552da7Schristos /* Work around a kernel bug where nfds is not updated. */
2250e552da7Schristos events[0].portev_source = 0;
2260e552da7Schristos
2270e552da7Schristos nfds = 1;
2280e552da7Schristos saved_errno = 0;
2290e552da7Schristos
2300e552da7Schristos if (pset != NULL)
2310e552da7Schristos pthread_sigmask(SIG_BLOCK, pset, NULL);
2320e552da7Schristos
2330e552da7Schristos err = port_getn(loop->backend_fd,
2340e552da7Schristos events,
2350e552da7Schristos ARRAY_SIZE(events),
2360e552da7Schristos &nfds,
2370e552da7Schristos timeout == -1 ? NULL : &spec);
2380e552da7Schristos
2390e552da7Schristos if (pset != NULL)
2400e552da7Schristos pthread_sigmask(SIG_UNBLOCK, pset, NULL);
2410e552da7Schristos
2420e552da7Schristos if (err) {
2430e552da7Schristos /* Work around another kernel bug: port_getn() may return events even
2440e552da7Schristos * on error.
2450e552da7Schristos */
2460e552da7Schristos if (errno == EINTR || errno == ETIME) {
2470e552da7Schristos saved_errno = errno;
2480e552da7Schristos } else {
2490e552da7Schristos perror("(libuv) port_getn()");
2500e552da7Schristos abort();
2510e552da7Schristos }
2520e552da7Schristos }
2530e552da7Schristos
2540e552da7Schristos /* Update loop->time unconditionally. It's tempting to skip the update when
2550e552da7Schristos * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
2560e552da7Schristos * operating system didn't reschedule our process while in the syscall.
2570e552da7Schristos */
2580e552da7Schristos SAVE_ERRNO(uv__update_time(loop));
2590e552da7Schristos
2600e552da7Schristos if (events[0].portev_source == 0) {
261*5f2f4271Schristos if (reset_timeout != 0) {
262*5f2f4271Schristos timeout = user_timeout;
263*5f2f4271Schristos reset_timeout = 0;
264*5f2f4271Schristos }
265*5f2f4271Schristos
2660e552da7Schristos if (timeout == 0)
2670e552da7Schristos return;
2680e552da7Schristos
2690e552da7Schristos if (timeout == -1)
2700e552da7Schristos continue;
2710e552da7Schristos
2720e552da7Schristos goto update_timeout;
2730e552da7Schristos }
2740e552da7Schristos
2750e552da7Schristos if (nfds == 0) {
2760e552da7Schristos assert(timeout != -1);
2770e552da7Schristos return;
2780e552da7Schristos }
2790e552da7Schristos
2800e552da7Schristos have_signals = 0;
2810e552da7Schristos nevents = 0;
2820e552da7Schristos
2830e552da7Schristos assert(loop->watchers != NULL);
2840e552da7Schristos loop->watchers[loop->nwatchers] = (void*) events;
2850e552da7Schristos loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
2860e552da7Schristos for (i = 0; i < nfds; i++) {
2870e552da7Schristos pe = events + i;
2880e552da7Schristos fd = pe->portev_object;
2890e552da7Schristos
2900e552da7Schristos /* Skip invalidated events, see uv__platform_invalidate_fd */
2910e552da7Schristos if (fd == -1)
2920e552da7Schristos continue;
2930e552da7Schristos
2940e552da7Schristos assert(fd >= 0);
2950e552da7Schristos assert((unsigned) fd < loop->nwatchers);
2960e552da7Schristos
2970e552da7Schristos w = loop->watchers[fd];
2980e552da7Schristos
2990e552da7Schristos /* File descriptor that we've stopped watching, ignore. */
3000e552da7Schristos if (w == NULL)
3010e552da7Schristos continue;
3020e552da7Schristos
3030e552da7Schristos /* Run signal watchers last. This also affects child process watchers
3040e552da7Schristos * because those are implemented in terms of signal watchers.
3050e552da7Schristos */
306*5f2f4271Schristos if (w == &loop->signal_io_watcher) {
3070e552da7Schristos have_signals = 1;
308*5f2f4271Schristos } else {
309*5f2f4271Schristos uv__metrics_update_idle_time(loop);
3100e552da7Schristos w->cb(loop, w, pe->portev_events);
311*5f2f4271Schristos }
3120e552da7Schristos
3130e552da7Schristos nevents++;
3140e552da7Schristos
3150e552da7Schristos if (w != loop->watchers[fd])
3160e552da7Schristos continue; /* Disabled by callback. */
3170e552da7Schristos
3180e552da7Schristos /* Events Ports operates in oneshot mode, rearm timer on next run. */
3190e552da7Schristos if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue))
3200e552da7Schristos QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
3210e552da7Schristos }
3220e552da7Schristos
323*5f2f4271Schristos if (reset_timeout != 0) {
324*5f2f4271Schristos timeout = user_timeout;
325*5f2f4271Schristos reset_timeout = 0;
326*5f2f4271Schristos }
327*5f2f4271Schristos
328*5f2f4271Schristos if (have_signals != 0) {
329*5f2f4271Schristos uv__metrics_update_idle_time(loop);
3300e552da7Schristos loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
331*5f2f4271Schristos }
3320e552da7Schristos
3330e552da7Schristos loop->watchers[loop->nwatchers] = NULL;
3340e552da7Schristos loop->watchers[loop->nwatchers + 1] = NULL;
3350e552da7Schristos
3360e552da7Schristos if (have_signals != 0)
3370e552da7Schristos return; /* Event loop should cycle now so don't poll again. */
3380e552da7Schristos
3390e552da7Schristos if (nevents != 0) {
3400e552da7Schristos if (nfds == ARRAY_SIZE(events) && --count != 0) {
3410e552da7Schristos /* Poll for more events but don't block this time. */
3420e552da7Schristos timeout = 0;
3430e552da7Schristos continue;
3440e552da7Schristos }
3450e552da7Schristos return;
3460e552da7Schristos }
3470e552da7Schristos
3480e552da7Schristos if (saved_errno == ETIME) {
3490e552da7Schristos assert(timeout != -1);
3500e552da7Schristos return;
3510e552da7Schristos }
3520e552da7Schristos
3530e552da7Schristos if (timeout == 0)
3540e552da7Schristos return;
3550e552da7Schristos
3560e552da7Schristos if (timeout == -1)
3570e552da7Schristos continue;
3580e552da7Schristos
3590e552da7Schristos update_timeout:
3600e552da7Schristos assert(timeout > 0);
3610e552da7Schristos
3620e552da7Schristos diff = loop->time - base;
3630e552da7Schristos if (diff >= (uint64_t) timeout)
3640e552da7Schristos return;
3650e552da7Schristos
3660e552da7Schristos timeout -= diff;
3670e552da7Schristos }
3680e552da7Schristos }
3690e552da7Schristos
3700e552da7Schristos
uv__hrtime(uv_clocktype_t type)3710e552da7Schristos uint64_t uv__hrtime(uv_clocktype_t type) {
3720e552da7Schristos return gethrtime();
3730e552da7Schristos }
3740e552da7Schristos
3750e552da7Schristos
3760e552da7Schristos /*
3770e552da7Schristos * We could use a static buffer for the path manipulations that we need outside
3780e552da7Schristos * of the function, but this function could be called by multiple consumers and
3790e552da7Schristos * we don't want to potentially create a race condition in the use of snprintf.
3800e552da7Schristos */
uv_exepath(char * buffer,size_t * size)3810e552da7Schristos int uv_exepath(char* buffer, size_t* size) {
3820e552da7Schristos ssize_t res;
3830e552da7Schristos char buf[128];
3840e552da7Schristos
3850e552da7Schristos if (buffer == NULL || size == NULL || *size == 0)
3860e552da7Schristos return UV_EINVAL;
3870e552da7Schristos
3880e552da7Schristos snprintf(buf, sizeof(buf), "/proc/%lu/path/a.out", (unsigned long) getpid());
3890e552da7Schristos
3900e552da7Schristos res = *size - 1;
3910e552da7Schristos if (res > 0)
3920e552da7Schristos res = readlink(buf, buffer, res);
3930e552da7Schristos
3940e552da7Schristos if (res == -1)
3950e552da7Schristos return UV__ERR(errno);
3960e552da7Schristos
3970e552da7Schristos buffer[res] = '\0';
3980e552da7Schristos *size = res;
3990e552da7Schristos return 0;
4000e552da7Schristos }
4010e552da7Schristos
4020e552da7Schristos
uv_get_free_memory(void)4030e552da7Schristos uint64_t uv_get_free_memory(void) {
4040e552da7Schristos return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
4050e552da7Schristos }
4060e552da7Schristos
4070e552da7Schristos
uv_get_total_memory(void)4080e552da7Schristos uint64_t uv_get_total_memory(void) {
4090e552da7Schristos return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
4100e552da7Schristos }
4110e552da7Schristos
4120e552da7Schristos
uv_get_constrained_memory(void)4130e552da7Schristos uint64_t uv_get_constrained_memory(void) {
4140e552da7Schristos return 0; /* Memory constraints are unknown. */
4150e552da7Schristos }
4160e552da7Schristos
4170e552da7Schristos
uv_loadavg(double avg[3])4180e552da7Schristos void uv_loadavg(double avg[3]) {
4190e552da7Schristos (void) getloadavg(avg, 3);
4200e552da7Schristos }
4210e552da7Schristos
4220e552da7Schristos
4230e552da7Schristos #if defined(PORT_SOURCE_FILE)
4240e552da7Schristos
uv__fs_event_rearm(uv_fs_event_t * handle)4250e552da7Schristos static int uv__fs_event_rearm(uv_fs_event_t *handle) {
426*5f2f4271Schristos if (handle->fd == PORT_DELETED)
4270e552da7Schristos return UV_EBADF;
4280e552da7Schristos
4290e552da7Schristos if (port_associate(handle->loop->fs_fd,
4300e552da7Schristos PORT_SOURCE_FILE,
4310e552da7Schristos (uintptr_t) &handle->fo,
4320e552da7Schristos FILE_ATTRIB | FILE_MODIFIED,
4330e552da7Schristos handle) == -1) {
4340e552da7Schristos return UV__ERR(errno);
4350e552da7Schristos }
4360e552da7Schristos handle->fd = PORT_LOADED;
4370e552da7Schristos
4380e552da7Schristos return 0;
4390e552da7Schristos }
4400e552da7Schristos
4410e552da7Schristos
uv__fs_event_read(uv_loop_t * loop,uv__io_t * w,unsigned int revents)4420e552da7Schristos static void uv__fs_event_read(uv_loop_t* loop,
4430e552da7Schristos uv__io_t* w,
4440e552da7Schristos unsigned int revents) {
4450e552da7Schristos uv_fs_event_t *handle = NULL;
4460e552da7Schristos timespec_t timeout;
4470e552da7Schristos port_event_t pe;
4480e552da7Schristos int events;
4490e552da7Schristos int r;
4500e552da7Schristos
4510e552da7Schristos (void) w;
4520e552da7Schristos (void) revents;
4530e552da7Schristos
4540e552da7Schristos do {
4550e552da7Schristos uint_t n = 1;
4560e552da7Schristos
4570e552da7Schristos /*
4580e552da7Schristos * Note that our use of port_getn() here (and not port_get()) is deliberate:
4590e552da7Schristos * there is a bug in event ports (Sun bug 6456558) whereby a zeroed timeout
4600e552da7Schristos * causes port_get() to return success instead of ETIME when there aren't
4610e552da7Schristos * actually any events (!); by using port_getn() in lieu of port_get(),
4620e552da7Schristos * we can at least workaround the bug by checking for zero returned events
4630e552da7Schristos * and treating it as we would ETIME.
4640e552da7Schristos */
4650e552da7Schristos do {
4660e552da7Schristos memset(&timeout, 0, sizeof timeout);
4670e552da7Schristos r = port_getn(loop->fs_fd, &pe, 1, &n, &timeout);
4680e552da7Schristos }
4690e552da7Schristos while (r == -1 && errno == EINTR);
4700e552da7Schristos
4710e552da7Schristos if ((r == -1 && errno == ETIME) || n == 0)
4720e552da7Schristos break;
4730e552da7Schristos
4740e552da7Schristos handle = (uv_fs_event_t*) pe.portev_user;
4750e552da7Schristos assert((r == 0) && "unexpected port_get() error");
4760e552da7Schristos
477*5f2f4271Schristos if (uv__is_closing(handle)) {
478*5f2f4271Schristos uv__handle_stop(handle);
479*5f2f4271Schristos uv__make_close_pending((uv_handle_t*) handle);
480*5f2f4271Schristos break;
481*5f2f4271Schristos }
482*5f2f4271Schristos
4830e552da7Schristos events = 0;
4840e552da7Schristos if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED))
4850e552da7Schristos events |= UV_CHANGE;
4860e552da7Schristos if (pe.portev_events & ~(FILE_ATTRIB | FILE_MODIFIED))
4870e552da7Schristos events |= UV_RENAME;
4880e552da7Schristos assert(events != 0);
4890e552da7Schristos handle->fd = PORT_FIRED;
4900e552da7Schristos handle->cb(handle, NULL, events, 0);
4910e552da7Schristos
4920e552da7Schristos if (handle->fd != PORT_DELETED) {
4930e552da7Schristos r = uv__fs_event_rearm(handle);
4940e552da7Schristos if (r != 0)
4950e552da7Schristos handle->cb(handle, NULL, 0, r);
4960e552da7Schristos }
4970e552da7Schristos }
4980e552da7Schristos while (handle->fd != PORT_DELETED);
4990e552da7Schristos }
5000e552da7Schristos
5010e552da7Schristos
uv_fs_event_init(uv_loop_t * loop,uv_fs_event_t * handle)5020e552da7Schristos int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
5030e552da7Schristos uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
5040e552da7Schristos return 0;
5050e552da7Schristos }
5060e552da7Schristos
5070e552da7Schristos
uv_fs_event_start(uv_fs_event_t * handle,uv_fs_event_cb cb,const char * path,unsigned int flags)5080e552da7Schristos int uv_fs_event_start(uv_fs_event_t* handle,
5090e552da7Schristos uv_fs_event_cb cb,
5100e552da7Schristos const char* path,
5110e552da7Schristos unsigned int flags) {
5120e552da7Schristos int portfd;
5130e552da7Schristos int first_run;
5140e552da7Schristos int err;
5150e552da7Schristos
5160e552da7Schristos if (uv__is_active(handle))
5170e552da7Schristos return UV_EINVAL;
5180e552da7Schristos
5190e552da7Schristos first_run = 0;
5200e552da7Schristos if (handle->loop->fs_fd == -1) {
5210e552da7Schristos portfd = port_create();
5220e552da7Schristos if (portfd == -1)
5230e552da7Schristos return UV__ERR(errno);
5240e552da7Schristos handle->loop->fs_fd = portfd;
5250e552da7Schristos first_run = 1;
5260e552da7Schristos }
5270e552da7Schristos
5280e552da7Schristos uv__handle_start(handle);
5290e552da7Schristos handle->path = uv__strdup(path);
5300e552da7Schristos handle->fd = PORT_UNUSED;
5310e552da7Schristos handle->cb = cb;
5320e552da7Schristos
5330e552da7Schristos memset(&handle->fo, 0, sizeof handle->fo);
5340e552da7Schristos handle->fo.fo_name = handle->path;
5350e552da7Schristos err = uv__fs_event_rearm(handle);
5360e552da7Schristos if (err != 0) {
5370e552da7Schristos uv_fs_event_stop(handle);
5380e552da7Schristos return err;
5390e552da7Schristos }
5400e552da7Schristos
5410e552da7Schristos if (first_run) {
5420e552da7Schristos uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd);
5430e552da7Schristos uv__io_start(handle->loop, &handle->loop->fs_event_watcher, POLLIN);
5440e552da7Schristos }
5450e552da7Schristos
5460e552da7Schristos return 0;
5470e552da7Schristos }
5480e552da7Schristos
5490e552da7Schristos
uv__fs_event_stop(uv_fs_event_t * handle)550*5f2f4271Schristos static int uv__fs_event_stop(uv_fs_event_t* handle) {
551*5f2f4271Schristos int ret = 0;
552*5f2f4271Schristos
5530e552da7Schristos if (!uv__is_active(handle))
5540e552da7Schristos return 0;
5550e552da7Schristos
556*5f2f4271Schristos if (handle->fd == PORT_LOADED) {
557*5f2f4271Schristos ret = port_dissociate(handle->loop->fs_fd,
5580e552da7Schristos PORT_SOURCE_FILE,
5590e552da7Schristos (uintptr_t) &handle->fo);
5600e552da7Schristos }
5610e552da7Schristos
5620e552da7Schristos handle->fd = PORT_DELETED;
5630e552da7Schristos uv__free(handle->path);
5640e552da7Schristos handle->path = NULL;
5650e552da7Schristos handle->fo.fo_name = NULL;
566*5f2f4271Schristos if (ret == 0)
5670e552da7Schristos uv__handle_stop(handle);
5680e552da7Schristos
569*5f2f4271Schristos return ret;
570*5f2f4271Schristos }
571*5f2f4271Schristos
uv_fs_event_stop(uv_fs_event_t * handle)572*5f2f4271Schristos int uv_fs_event_stop(uv_fs_event_t* handle) {
573*5f2f4271Schristos (void) uv__fs_event_stop(handle);
5740e552da7Schristos return 0;
5750e552da7Schristos }
5760e552da7Schristos
uv__fs_event_close(uv_fs_event_t * handle)5770e552da7Schristos void uv__fs_event_close(uv_fs_event_t* handle) {
578*5f2f4271Schristos /*
579*5f2f4271Schristos * If we were unable to dissociate the port here, then it is most likely
580*5f2f4271Schristos * that there is a pending queued event. When this happens, we don't want
581*5f2f4271Schristos * to complete the close as it will free the underlying memory for the
582*5f2f4271Schristos * handle, causing a use-after-free problem when the event is processed.
583*5f2f4271Schristos * We defer the final cleanup until after the event is consumed in
584*5f2f4271Schristos * uv__fs_event_read().
585*5f2f4271Schristos */
586*5f2f4271Schristos if (uv__fs_event_stop(handle) == 0)
587*5f2f4271Schristos uv__make_close_pending((uv_handle_t*) handle);
5880e552da7Schristos }
5890e552da7Schristos
5900e552da7Schristos #else /* !defined(PORT_SOURCE_FILE) */
5910e552da7Schristos
uv_fs_event_init(uv_loop_t * loop,uv_fs_event_t * handle)5920e552da7Schristos int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
5930e552da7Schristos return UV_ENOSYS;
5940e552da7Schristos }
5950e552da7Schristos
5960e552da7Schristos
uv_fs_event_start(uv_fs_event_t * handle,uv_fs_event_cb cb,const char * filename,unsigned int flags)5970e552da7Schristos int uv_fs_event_start(uv_fs_event_t* handle,
5980e552da7Schristos uv_fs_event_cb cb,
5990e552da7Schristos const char* filename,
6000e552da7Schristos unsigned int flags) {
6010e552da7Schristos return UV_ENOSYS;
6020e552da7Schristos }
6030e552da7Schristos
6040e552da7Schristos
uv_fs_event_stop(uv_fs_event_t * handle)6050e552da7Schristos int uv_fs_event_stop(uv_fs_event_t* handle) {
6060e552da7Schristos return UV_ENOSYS;
6070e552da7Schristos }
6080e552da7Schristos
6090e552da7Schristos
uv__fs_event_close(uv_fs_event_t * handle)6100e552da7Schristos void uv__fs_event_close(uv_fs_event_t* handle) {
6110e552da7Schristos UNREACHABLE();
6120e552da7Schristos }
6130e552da7Schristos
6140e552da7Schristos #endif /* defined(PORT_SOURCE_FILE) */
6150e552da7Schristos
6160e552da7Schristos
uv_resident_set_memory(size_t * rss)6170e552da7Schristos int uv_resident_set_memory(size_t* rss) {
6180e552da7Schristos psinfo_t psinfo;
6190e552da7Schristos int err;
6200e552da7Schristos int fd;
6210e552da7Schristos
6220e552da7Schristos fd = open("/proc/self/psinfo", O_RDONLY);
6230e552da7Schristos if (fd == -1)
6240e552da7Schristos return UV__ERR(errno);
6250e552da7Schristos
6260e552da7Schristos /* FIXME(bnoordhuis) Handle EINTR. */
6270e552da7Schristos err = UV_EINVAL;
6280e552da7Schristos if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
6290e552da7Schristos *rss = (size_t)psinfo.pr_rssize * 1024;
6300e552da7Schristos err = 0;
6310e552da7Schristos }
6320e552da7Schristos uv__close(fd);
6330e552da7Schristos
6340e552da7Schristos return err;
6350e552da7Schristos }
6360e552da7Schristos
6370e552da7Schristos
uv_uptime(double * uptime)6380e552da7Schristos int uv_uptime(double* uptime) {
6390e552da7Schristos kstat_ctl_t *kc;
6400e552da7Schristos kstat_t *ksp;
6410e552da7Schristos kstat_named_t *knp;
6420e552da7Schristos
6430e552da7Schristos long hz = sysconf(_SC_CLK_TCK);
6440e552da7Schristos
6450e552da7Schristos kc = kstat_open();
6460e552da7Schristos if (kc == NULL)
6470e552da7Schristos return UV_EPERM;
6480e552da7Schristos
6490e552da7Schristos ksp = kstat_lookup(kc, (char*) "unix", 0, (char*) "system_misc");
6500e552da7Schristos if (kstat_read(kc, ksp, NULL) == -1) {
6510e552da7Schristos *uptime = -1;
6520e552da7Schristos } else {
6530e552da7Schristos knp = (kstat_named_t*) kstat_data_lookup(ksp, (char*) "clk_intr");
6540e552da7Schristos *uptime = knp->value.ul / hz;
6550e552da7Schristos }
6560e552da7Schristos kstat_close(kc);
6570e552da7Schristos
6580e552da7Schristos return 0;
6590e552da7Schristos }
6600e552da7Schristos
6610e552da7Schristos
uv_cpu_info(uv_cpu_info_t ** cpu_infos,int * count)6620e552da7Schristos int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
6630e552da7Schristos int lookup_instance;
6640e552da7Schristos kstat_ctl_t *kc;
6650e552da7Schristos kstat_t *ksp;
6660e552da7Schristos kstat_named_t *knp;
6670e552da7Schristos uv_cpu_info_t* cpu_info;
6680e552da7Schristos
6690e552da7Schristos kc = kstat_open();
6700e552da7Schristos if (kc == NULL)
6710e552da7Schristos return UV_EPERM;
6720e552da7Schristos
6730e552da7Schristos /* Get count of cpus */
6740e552da7Schristos lookup_instance = 0;
6750e552da7Schristos while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
6760e552da7Schristos lookup_instance++;
6770e552da7Schristos }
6780e552da7Schristos
6790e552da7Schristos *cpu_infos = uv__malloc(lookup_instance * sizeof(**cpu_infos));
6800e552da7Schristos if (!(*cpu_infos)) {
6810e552da7Schristos kstat_close(kc);
6820e552da7Schristos return UV_ENOMEM;
6830e552da7Schristos }
6840e552da7Schristos
6850e552da7Schristos *count = lookup_instance;
6860e552da7Schristos
6870e552da7Schristos cpu_info = *cpu_infos;
6880e552da7Schristos lookup_instance = 0;
6890e552da7Schristos while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
6900e552da7Schristos if (kstat_read(kc, ksp, NULL) == -1) {
6910e552da7Schristos cpu_info->speed = 0;
6920e552da7Schristos cpu_info->model = NULL;
6930e552da7Schristos } else {
6940e552da7Schristos knp = kstat_data_lookup(ksp, (char*) "clock_MHz");
6950e552da7Schristos assert(knp->data_type == KSTAT_DATA_INT32 ||
6960e552da7Schristos knp->data_type == KSTAT_DATA_INT64);
6970e552da7Schristos cpu_info->speed = (knp->data_type == KSTAT_DATA_INT32) ? knp->value.i32
6980e552da7Schristos : knp->value.i64;
6990e552da7Schristos
7000e552da7Schristos knp = kstat_data_lookup(ksp, (char*) "brand");
7010e552da7Schristos assert(knp->data_type == KSTAT_DATA_STRING);
7020e552da7Schristos cpu_info->model = uv__strdup(KSTAT_NAMED_STR_PTR(knp));
7030e552da7Schristos }
7040e552da7Schristos
7050e552da7Schristos lookup_instance++;
7060e552da7Schristos cpu_info++;
7070e552da7Schristos }
7080e552da7Schristos
7090e552da7Schristos cpu_info = *cpu_infos;
7100e552da7Schristos lookup_instance = 0;
7110e552da7Schristos for (;;) {
7120e552da7Schristos ksp = kstat_lookup(kc, (char*) "cpu", lookup_instance, (char*) "sys");
7130e552da7Schristos
7140e552da7Schristos if (ksp == NULL)
7150e552da7Schristos break;
7160e552da7Schristos
7170e552da7Schristos if (kstat_read(kc, ksp, NULL) == -1) {
7180e552da7Schristos cpu_info->cpu_times.user = 0;
7190e552da7Schristos cpu_info->cpu_times.nice = 0;
7200e552da7Schristos cpu_info->cpu_times.sys = 0;
7210e552da7Schristos cpu_info->cpu_times.idle = 0;
7220e552da7Schristos cpu_info->cpu_times.irq = 0;
7230e552da7Schristos } else {
7240e552da7Schristos knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_user");
7250e552da7Schristos assert(knp->data_type == KSTAT_DATA_UINT64);
7260e552da7Schristos cpu_info->cpu_times.user = knp->value.ui64;
7270e552da7Schristos
7280e552da7Schristos knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_kernel");
7290e552da7Schristos assert(knp->data_type == KSTAT_DATA_UINT64);
7300e552da7Schristos cpu_info->cpu_times.sys = knp->value.ui64;
7310e552da7Schristos
7320e552da7Schristos knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_idle");
7330e552da7Schristos assert(knp->data_type == KSTAT_DATA_UINT64);
7340e552da7Schristos cpu_info->cpu_times.idle = knp->value.ui64;
7350e552da7Schristos
7360e552da7Schristos knp = kstat_data_lookup(ksp, (char*) "intr");
7370e552da7Schristos assert(knp->data_type == KSTAT_DATA_UINT64);
7380e552da7Schristos cpu_info->cpu_times.irq = knp->value.ui64;
7390e552da7Schristos cpu_info->cpu_times.nice = 0;
7400e552da7Schristos }
7410e552da7Schristos
7420e552da7Schristos lookup_instance++;
7430e552da7Schristos cpu_info++;
7440e552da7Schristos }
7450e552da7Schristos
7460e552da7Schristos kstat_close(kc);
7470e552da7Schristos
7480e552da7Schristos return 0;
7490e552da7Schristos }
7500e552da7Schristos
7510e552da7Schristos
7520e552da7Schristos #ifdef SUNOS_NO_IFADDRS
uv_interface_addresses(uv_interface_address_t ** addresses,int * count)7530e552da7Schristos int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
7540e552da7Schristos *count = 0;
7550e552da7Schristos *addresses = NULL;
7560e552da7Schristos return UV_ENOSYS;
7570e552da7Schristos }
7580e552da7Schristos #else /* SUNOS_NO_IFADDRS */
7590e552da7Schristos /*
7600e552da7Schristos * Inspired By:
7610e552da7Schristos * https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris
7620e552da7Schristos * http://www.pauliesworld.org/project/getmac.c
7630e552da7Schristos */
uv__set_phys_addr(uv_interface_address_t * address,struct ifaddrs * ent)7640e552da7Schristos static int uv__set_phys_addr(uv_interface_address_t* address,
7650e552da7Schristos struct ifaddrs* ent) {
7660e552da7Schristos
7670e552da7Schristos struct sockaddr_dl* sa_addr;
7680e552da7Schristos int sockfd;
7690e552da7Schristos size_t i;
7700e552da7Schristos struct arpreq arpreq;
7710e552da7Schristos
7720e552da7Schristos /* This appears to only work as root */
7730e552da7Schristos sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
7740e552da7Schristos memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
7750e552da7Schristos for (i = 0; i < sizeof(address->phys_addr); i++) {
7760e552da7Schristos /* Check that all bytes of phys_addr are zero. */
7770e552da7Schristos if (address->phys_addr[i] != 0)
7780e552da7Schristos return 0;
7790e552da7Schristos }
7800e552da7Schristos memset(&arpreq, 0, sizeof(arpreq));
7810e552da7Schristos if (address->address.address4.sin_family == AF_INET) {
7820e552da7Schristos struct sockaddr_in* sin = ((struct sockaddr_in*)&arpreq.arp_pa);
7830e552da7Schristos sin->sin_addr.s_addr = address->address.address4.sin_addr.s_addr;
7840e552da7Schristos } else if (address->address.address4.sin_family == AF_INET6) {
7850e552da7Schristos struct sockaddr_in6* sin = ((struct sockaddr_in6*)&arpreq.arp_pa);
7860e552da7Schristos memcpy(sin->sin6_addr.s6_addr,
7870e552da7Schristos address->address.address6.sin6_addr.s6_addr,
7880e552da7Schristos sizeof(address->address.address6.sin6_addr.s6_addr));
7890e552da7Schristos } else {
7900e552da7Schristos return 0;
7910e552da7Schristos }
7920e552da7Schristos
7930e552da7Schristos sockfd = socket(AF_INET, SOCK_DGRAM, 0);
7940e552da7Schristos if (sockfd < 0)
7950e552da7Schristos return UV__ERR(errno);
7960e552da7Schristos
7970e552da7Schristos if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) {
7980e552da7Schristos uv__close(sockfd);
7990e552da7Schristos return UV__ERR(errno);
8000e552da7Schristos }
8010e552da7Schristos memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr));
8020e552da7Schristos uv__close(sockfd);
8030e552da7Schristos return 0;
8040e552da7Schristos }
8050e552da7Schristos
8060e552da7Schristos
uv__ifaddr_exclude(struct ifaddrs * ent)8070e552da7Schristos static int uv__ifaddr_exclude(struct ifaddrs *ent) {
8080e552da7Schristos if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
8090e552da7Schristos return 1;
8100e552da7Schristos if (ent->ifa_addr == NULL)
8110e552da7Schristos return 1;
8120e552da7Schristos if (ent->ifa_addr->sa_family != AF_INET &&
8130e552da7Schristos ent->ifa_addr->sa_family != AF_INET6)
8140e552da7Schristos return 1;
8150e552da7Schristos return 0;
8160e552da7Schristos }
8170e552da7Schristos
uv_interface_addresses(uv_interface_address_t ** addresses,int * count)8180e552da7Schristos int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
8190e552da7Schristos uv_interface_address_t* address;
8200e552da7Schristos struct ifaddrs* addrs;
8210e552da7Schristos struct ifaddrs* ent;
8220e552da7Schristos
8230e552da7Schristos *count = 0;
8240e552da7Schristos *addresses = NULL;
8250e552da7Schristos
8260e552da7Schristos if (getifaddrs(&addrs))
8270e552da7Schristos return UV__ERR(errno);
8280e552da7Schristos
8290e552da7Schristos /* Count the number of interfaces */
8300e552da7Schristos for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
8310e552da7Schristos if (uv__ifaddr_exclude(ent))
8320e552da7Schristos continue;
8330e552da7Schristos (*count)++;
8340e552da7Schristos }
8350e552da7Schristos
8360e552da7Schristos if (*count == 0) {
8370e552da7Schristos freeifaddrs(addrs);
8380e552da7Schristos return 0;
8390e552da7Schristos }
8400e552da7Schristos
8410e552da7Schristos *addresses = uv__malloc(*count * sizeof(**addresses));
8420e552da7Schristos if (!(*addresses)) {
8430e552da7Schristos freeifaddrs(addrs);
8440e552da7Schristos return UV_ENOMEM;
8450e552da7Schristos }
8460e552da7Schristos
8470e552da7Schristos address = *addresses;
8480e552da7Schristos
8490e552da7Schristos for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
8500e552da7Schristos if (uv__ifaddr_exclude(ent))
8510e552da7Schristos continue;
8520e552da7Schristos
8530e552da7Schristos address->name = uv__strdup(ent->ifa_name);
8540e552da7Schristos
8550e552da7Schristos if (ent->ifa_addr->sa_family == AF_INET6) {
8560e552da7Schristos address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
8570e552da7Schristos } else {
8580e552da7Schristos address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
8590e552da7Schristos }
8600e552da7Schristos
8610e552da7Schristos if (ent->ifa_netmask->sa_family == AF_INET6) {
8620e552da7Schristos address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
8630e552da7Schristos } else {
8640e552da7Schristos address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
8650e552da7Schristos }
8660e552da7Schristos
8670e552da7Schristos address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) ||
8680e552da7Schristos (ent->ifa_flags & IFF_LOOPBACK));
8690e552da7Schristos
8700e552da7Schristos uv__set_phys_addr(address, ent);
8710e552da7Schristos address++;
8720e552da7Schristos }
8730e552da7Schristos
8740e552da7Schristos freeifaddrs(addrs);
8750e552da7Schristos
8760e552da7Schristos return 0;
8770e552da7Schristos }
8780e552da7Schristos #endif /* SUNOS_NO_IFADDRS */
8790e552da7Schristos
uv_free_interface_addresses(uv_interface_address_t * addresses,int count)8800e552da7Schristos void uv_free_interface_addresses(uv_interface_address_t* addresses,
8810e552da7Schristos int count) {
8820e552da7Schristos int i;
8830e552da7Schristos
8840e552da7Schristos for (i = 0; i < count; i++) {
8850e552da7Schristos uv__free(addresses[i].name);
8860e552da7Schristos }
8870e552da7Schristos
8880e552da7Schristos uv__free(addresses);
8890e552da7Schristos }
890*5f2f4271Schristos
891*5f2f4271Schristos
892*5f2f4271Schristos #if !defined(_POSIX_VERSION) || _POSIX_VERSION < 200809L
strnlen(const char * s,size_t maxlen)893*5f2f4271Schristos size_t strnlen(const char* s, size_t maxlen) {
894*5f2f4271Schristos const char* end;
895*5f2f4271Schristos end = memchr(s, '\0', maxlen);
896*5f2f4271Schristos if (end == NULL)
897*5f2f4271Schristos return maxlen;
898*5f2f4271Schristos return end - s;
899*5f2f4271Schristos }
900*5f2f4271Schristos #endif
901