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 <sys/types.h> 25#include <sys/param.h> 26#include <sys/resource.h> 27#include <sys/sched.h> 28#include <sys/time.h> 29#include <sys/sysctl.h> 30 31#include <errno.h> 32#include <fcntl.h> 33#include <paths.h> 34#include <stdlib.h> 35#include <string.h> 36#include <unistd.h> 37 38 39int uv__platform_loop_init(uv_loop_t* loop) { 40 return uv__kqueue_init(loop); 41} 42 43 44void uv__platform_loop_delete(uv_loop_t* loop) { 45} 46 47 48void uv_loadavg(double avg[3]) { 49 struct loadavg info; 50 size_t size = sizeof(info); 51 int which[] = {CTL_VM, VM_LOADAVG}; 52 53 if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) < 0) return; 54 55 avg[0] = (double) info.ldavg[0] / info.fscale; 56 avg[1] = (double) info.ldavg[1] / info.fscale; 57 avg[2] = (double) info.ldavg[2] / info.fscale; 58} 59 60 61int uv_exepath(char* buffer, size_t* size) { 62 int mib[4]; 63 char **argsbuf = NULL; 64 size_t argsbuf_size = 100U; 65 size_t exepath_size; 66 pid_t mypid; 67 int err; 68 69 if (buffer == NULL || size == NULL || *size == 0) 70 return UV_EINVAL; 71 72 mypid = getpid(); 73 for (;;) { 74 err = UV_ENOMEM; 75 argsbuf = uv__reallocf(argsbuf, argsbuf_size); 76 if (argsbuf == NULL) 77 goto out; 78 mib[0] = CTL_KERN; 79 mib[1] = KERN_PROC_ARGS; 80 mib[2] = mypid; 81 mib[3] = KERN_PROC_ARGV; 82 if (sysctl(mib, ARRAY_SIZE(mib), argsbuf, &argsbuf_size, NULL, 0) == 0) { 83 break; 84 } 85 if (errno != ENOMEM) { 86 err = UV__ERR(errno); 87 goto out; 88 } 89 argsbuf_size *= 2U; 90 } 91 92 if (argsbuf[0] == NULL) { 93 err = UV_EINVAL; /* FIXME(bnoordhuis) More appropriate error. */ 94 goto out; 95 } 96 97 *size -= 1; 98 exepath_size = strlen(argsbuf[0]); 99 if (*size > exepath_size) 100 *size = exepath_size; 101 102 memcpy(buffer, argsbuf[0], *size); 103 buffer[*size] = '\0'; 104 err = 0; 105 106out: 107 uv__free(argsbuf); 108 109 return err; 110} 111 112 113uint64_t uv_get_free_memory(void) { 114 struct uvmexp info; 115 size_t size = sizeof(info); 116 int which[] = {CTL_VM, VM_UVMEXP}; 117 118 if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0)) 119 return 0; 120 121 return (uint64_t) info.free * sysconf(_SC_PAGESIZE); 122} 123 124 125uint64_t uv_get_total_memory(void) { 126 uint64_t info; 127 int which[] = {CTL_HW, HW_PHYSMEM64}; 128 size_t size = sizeof(info); 129 130 if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0)) 131 return 0; 132 133 return (uint64_t) info; 134} 135 136 137uint64_t uv_get_constrained_memory(void) { 138 return 0; /* Memory constraints are unknown. */ 139} 140 141 142uint64_t uv_get_available_memory(void) { 143 return uv_get_free_memory(); 144} 145 146 147int uv_resident_set_memory(size_t* rss) { 148 struct kinfo_proc kinfo; 149 size_t page_size = getpagesize(); 150 size_t size = sizeof(struct kinfo_proc); 151 int mib[6]; 152 153 mib[0] = CTL_KERN; 154 mib[1] = KERN_PROC; 155 mib[2] = KERN_PROC_PID; 156 mib[3] = getpid(); 157 mib[4] = sizeof(struct kinfo_proc); 158 mib[5] = 1; 159 160 if (sysctl(mib, ARRAY_SIZE(mib), &kinfo, &size, NULL, 0) < 0) 161 return UV__ERR(errno); 162 163 *rss = kinfo.p_vm_rssize * page_size; 164 return 0; 165} 166 167 168int uv_uptime(double* uptime) { 169 time_t now; 170 struct timeval info; 171 size_t size = sizeof(info); 172 static int which[] = {CTL_KERN, KERN_BOOTTIME}; 173 174 if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0)) 175 return UV__ERR(errno); 176 177 now = time(NULL); 178 179 *uptime = (double)(now - info.tv_sec); 180 return 0; 181} 182 183 184int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { 185 unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), 186 multiplier = ((uint64_t)1000L / ticks), cpuspeed; 187 uint64_t info[CPUSTATES]; 188 char model[512]; 189 int numcpus = 1; 190 int which[] = {CTL_HW,HW_MODEL}; 191 int percpu[] = {CTL_KERN,KERN_CPTIME2,0}; 192 size_t size; 193 int i, j; 194 uv_cpu_info_t* cpu_info; 195 196 size = sizeof(model); 197 if (sysctl(which, ARRAY_SIZE(which), &model, &size, NULL, 0)) 198 return UV__ERR(errno); 199 200 which[1] = HW_NCPUONLINE; 201 size = sizeof(numcpus); 202 if (sysctl(which, ARRAY_SIZE(which), &numcpus, &size, NULL, 0)) 203 return UV__ERR(errno); 204 205 *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); 206 if (!(*cpu_infos)) 207 return UV_ENOMEM; 208 209 i = 0; 210 *count = numcpus; 211 212 which[1] = HW_CPUSPEED; 213 size = sizeof(cpuspeed); 214 if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0)) 215 goto error; 216 217 size = sizeof(info); 218 for (i = 0; i < numcpus; i++) { 219 percpu[2] = i; 220 if (sysctl(percpu, ARRAY_SIZE(percpu), &info, &size, NULL, 0)) 221 goto error; 222 223 cpu_info = &(*cpu_infos)[i]; 224 225 cpu_info->cpu_times.user = (uint64_t)(info[CP_USER]) * multiplier; 226 cpu_info->cpu_times.nice = (uint64_t)(info[CP_NICE]) * multiplier; 227 cpu_info->cpu_times.sys = (uint64_t)(info[CP_SYS]) * multiplier; 228 cpu_info->cpu_times.idle = (uint64_t)(info[CP_IDLE]) * multiplier; 229 cpu_info->cpu_times.irq = (uint64_t)(info[CP_INTR]) * multiplier; 230 231 cpu_info->model = uv__strdup(model); 232 cpu_info->speed = cpuspeed; 233 } 234 235 return 0; 236 237error: 238 *count = 0; 239 for (j = 0; j < i; j++) 240 uv__free((*cpu_infos)[j].model); 241 242 uv__free(*cpu_infos); 243 *cpu_infos = NULL; 244 return UV__ERR(errno); 245} 246