1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 2 * Permission is hereby granted, free of charge, to any person obtaining a copy 3 * of this software and associated documentation files (the "Software"), to 4 * deal in the Software without restriction, including without limitation the 5 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 6 * sell copies of the Software, and to permit persons to whom the Software is 7 * furnished to do so, subject to the following conditions: 8 * 9 * The above copyright notice and this permission notice shall be included in 10 * all copies or substantial portions of the Software. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 18 * IN THE SOFTWARE. 19 */ 20 21 #include "uv.h" 22 #include "internal.h" 23 24 #include <assert.h> 25 #include <string.h> 26 #include <errno.h> 27 28 #include <paths.h> 29 #include <sys/user.h> 30 #include <sys/types.h> 31 #include <sys/resource.h> 32 #include <sys/sysctl.h> 33 #include <vm/vm_param.h> /* VM_LOADAVG */ 34 #include <time.h> 35 #include <stdlib.h> 36 #include <unistd.h> /* sysconf */ 37 #include <fcntl.h> 38 39 #ifndef CPUSTATES 40 # define CPUSTATES 5U 41 #endif 42 #ifndef CP_USER 43 # define CP_USER 0 44 # define CP_NICE 1 45 # define CP_SYS 2 46 # define CP_IDLE 3 47 # define CP_INTR 4 48 #endif 49 50 51 int uv__platform_loop_init(uv_loop_t* loop) { 52 return uv__kqueue_init(loop); 53 } 54 55 56 void uv__platform_loop_delete(uv_loop_t* loop) { 57 } 58 59 int uv_exepath(char* buffer, size_t* size) { 60 char abspath[PATH_MAX * 2 + 1]; 61 int mib[4]; 62 size_t abspath_size; 63 64 if (buffer == NULL || size == NULL || *size == 0) 65 return UV_EINVAL; 66 67 mib[0] = CTL_KERN; 68 mib[1] = KERN_PROC; 69 mib[2] = KERN_PROC_PATHNAME; 70 mib[3] = -1; 71 72 abspath_size = sizeof abspath; 73 if (sysctl(mib, ARRAY_SIZE(mib), abspath, &abspath_size, NULL, 0)) 74 return UV__ERR(errno); 75 76 assert(abspath_size > 0); 77 abspath_size -= 1; 78 *size -= 1; 79 80 if (*size > abspath_size) 81 *size = abspath_size; 82 83 memcpy(buffer, abspath, *size); 84 buffer[*size] = '\0'; 85 86 return 0; 87 } 88 89 uint64_t uv_get_free_memory(void) { 90 int freecount; 91 size_t size = sizeof(freecount); 92 93 if (sysctlbyname("vm.stats.vm.v_free_count", &freecount, &size, NULL, 0)) 94 return UV__ERR(errno); 95 96 return (uint64_t) freecount * sysconf(_SC_PAGESIZE); 97 98 } 99 100 101 uint64_t uv_get_total_memory(void) { 102 unsigned long info; 103 int which[] = {CTL_HW, HW_PHYSMEM}; 104 105 size_t size = sizeof(info); 106 107 if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0)) 108 return UV__ERR(errno); 109 110 return (uint64_t) info; 111 } 112 113 114 uint64_t uv_get_constrained_memory(void) { 115 return 0; /* Memory constraints are unknown. */ 116 } 117 118 119 void uv_loadavg(double avg[3]) { 120 struct loadavg info; 121 size_t size = sizeof(info); 122 int which[] = {CTL_VM, VM_LOADAVG}; 123 124 if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) < 0) return; 125 126 avg[0] = (double) info.ldavg[0] / info.fscale; 127 avg[1] = (double) info.ldavg[1] / info.fscale; 128 avg[2] = (double) info.ldavg[2] / info.fscale; 129 } 130 131 132 int uv_resident_set_memory(size_t* rss) { 133 struct kinfo_proc kinfo; 134 size_t page_size; 135 size_t kinfo_size; 136 int mib[4]; 137 138 mib[0] = CTL_KERN; 139 mib[1] = KERN_PROC; 140 mib[2] = KERN_PROC_PID; 141 mib[3] = getpid(); 142 143 kinfo_size = sizeof(kinfo); 144 145 if (sysctl(mib, ARRAY_SIZE(mib), &kinfo, &kinfo_size, NULL, 0)) 146 return UV__ERR(errno); 147 148 page_size = getpagesize(); 149 150 #ifdef __DragonFly__ 151 *rss = kinfo.kp_vm_rssize * page_size; 152 #else 153 *rss = kinfo.ki_rssize * page_size; 154 #endif 155 156 return 0; 157 } 158 159 160 int uv_uptime(double* uptime) { 161 int r; 162 struct timespec sp; 163 r = clock_gettime(CLOCK_MONOTONIC, &sp); 164 if (r) 165 return UV__ERR(errno); 166 167 *uptime = sp.tv_sec; 168 return 0; 169 } 170 171 172 int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { 173 unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), 174 multiplier = ((uint64_t)1000L / ticks), cpuspeed, maxcpus, 175 cur = 0; 176 uv_cpu_info_t* cpu_info; 177 const char* maxcpus_key; 178 const char* cptimes_key; 179 const char* model_key; 180 char model[512]; 181 long* cp_times; 182 int numcpus; 183 size_t size; 184 int i; 185 186 #if defined(__DragonFly__) 187 /* This is not quite correct but DragonFlyBSD doesn't seem to have anything 188 * comparable to kern.smp.maxcpus or kern.cp_times (kern.cp_time is a total, 189 * not per CPU). At least this stops uv_cpu_info() from failing completely. 190 */ 191 maxcpus_key = "hw.ncpu"; 192 cptimes_key = "kern.cp_time"; 193 #else 194 maxcpus_key = "kern.smp.maxcpus"; 195 cptimes_key = "kern.cp_times"; 196 #endif 197 198 #if defined(__arm__) || defined(__aarch64__) 199 /* The key hw.model and hw.clockrate are not available on FreeBSD ARM. */ 200 model_key = "hw.machine"; 201 cpuspeed = 0; 202 #else 203 model_key = "hw.model"; 204 205 size = sizeof(cpuspeed); 206 if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) 207 return -errno; 208 #endif 209 210 size = sizeof(model); 211 if (sysctlbyname(model_key, &model, &size, NULL, 0)) 212 return UV__ERR(errno); 213 214 size = sizeof(numcpus); 215 if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) 216 return UV__ERR(errno); 217 218 *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); 219 if (!(*cpu_infos)) 220 return UV_ENOMEM; 221 222 *count = numcpus; 223 224 /* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of 225 * ncpu. 226 */ 227 size = sizeof(maxcpus); 228 if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) { 229 uv__free(*cpu_infos); 230 return UV__ERR(errno); 231 } 232 233 size = maxcpus * CPUSTATES * sizeof(long); 234 235 cp_times = uv__malloc(size); 236 if (cp_times == NULL) { 237 uv__free(*cpu_infos); 238 return UV_ENOMEM; 239 } 240 241 if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) { 242 uv__free(cp_times); 243 uv__free(*cpu_infos); 244 return UV__ERR(errno); 245 } 246 247 for (i = 0; i < numcpus; i++) { 248 cpu_info = &(*cpu_infos)[i]; 249 250 cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier; 251 cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier; 252 cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier; 253 cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier; 254 cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier; 255 256 cpu_info->model = uv__strdup(model); 257 cpu_info->speed = cpuspeed; 258 259 cur+=CPUSTATES; 260 } 261 262 uv__free(cp_times); 263 return 0; 264 } 265 266 267 int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { 268 #if __FreeBSD__ >= 11 && !defined(__DragonFly__) 269 return sendmmsg(fd, 270 (struct mmsghdr*) mmsg, 271 vlen, 272 0 /* flags */); 273 #else 274 return errno = ENOSYS, -1; 275 #endif 276 } 277 278 279 int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { 280 #if __FreeBSD__ >= 11 && !defined(__DragonFly__) 281 return recvmmsg(fd, 282 (struct mmsghdr*) mmsg, 283 vlen, 284 0 /* flags */, 285 NULL /* timeout */); 286 #else 287 return errno = ENOSYS, -1; 288 #endif 289 } 290 291 ssize_t 292 uv__fs_copy_file_range(int fd_in, 293 off_t* off_in, 294 int fd_out, 295 off_t* off_out, 296 size_t len, 297 unsigned int flags) 298 { 299 #if __FreeBSD__ >= 13 && !defined(__DragonFly__) 300 return copy_file_range(fd_in, off_in, fd_out, off_out, len, flags); 301 #else 302 return errno = ENOSYS, -1; 303 #endif 304 } 305