xref: /netbsd-src/external/mit/libuv/dist/src/unix/sunos.c (revision 5f2f42719cd62ff11fd913b40b7ce19f07c4fd25)
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