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 39 int uv__platform_loop_init(uv_loop_t* loop) { 40 return uv__kqueue_init(loop); 41 } 42 43 44 void uv__platform_loop_delete(uv_loop_t* loop) { 45 } 46 47 48 void 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 61 int 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 106 out: 107 uv__free(argsbuf); 108 109 return err; 110 } 111 112 113 uint64_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 UV__ERR(errno); 120 121 return (uint64_t) info.free * sysconf(_SC_PAGESIZE); 122 } 123 124 125 uint64_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 UV__ERR(errno); 132 133 return (uint64_t) info; 134 } 135 136 137 uint64_t uv_get_constrained_memory(void) { 138 return 0; /* Memory constraints are unknown. */ 139 } 140 141 142 int uv_resident_set_memory(size_t* rss) { 143 struct kinfo_proc kinfo; 144 size_t page_size = getpagesize(); 145 size_t size = sizeof(struct kinfo_proc); 146 int mib[6]; 147 148 mib[0] = CTL_KERN; 149 mib[1] = KERN_PROC; 150 mib[2] = KERN_PROC_PID; 151 mib[3] = getpid(); 152 mib[4] = sizeof(struct kinfo_proc); 153 mib[5] = 1; 154 155 if (sysctl(mib, ARRAY_SIZE(mib), &kinfo, &size, NULL, 0) < 0) 156 return UV__ERR(errno); 157 158 *rss = kinfo.p_vm_rssize * page_size; 159 return 0; 160 } 161 162 163 int uv_uptime(double* uptime) { 164 time_t now; 165 struct timeval info; 166 size_t size = sizeof(info); 167 static int which[] = {CTL_KERN, KERN_BOOTTIME}; 168 169 if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0)) 170 return UV__ERR(errno); 171 172 now = time(NULL); 173 174 *uptime = (double)(now - info.tv_sec); 175 return 0; 176 } 177 178 179 int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { 180 unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), 181 multiplier = ((uint64_t)1000L / ticks), cpuspeed; 182 uint64_t info[CPUSTATES]; 183 char model[512]; 184 int numcpus = 1; 185 int which[] = {CTL_HW,HW_MODEL}; 186 int percpu[] = {CTL_KERN,KERN_CPTIME2,0}; 187 size_t size; 188 int i, j; 189 uv_cpu_info_t* cpu_info; 190 191 size = sizeof(model); 192 if (sysctl(which, ARRAY_SIZE(which), &model, &size, NULL, 0)) 193 return UV__ERR(errno); 194 195 which[1] = HW_NCPUONLINE; 196 size = sizeof(numcpus); 197 if (sysctl(which, ARRAY_SIZE(which), &numcpus, &size, NULL, 0)) 198 return UV__ERR(errno); 199 200 *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); 201 if (!(*cpu_infos)) 202 return UV_ENOMEM; 203 204 i = 0; 205 *count = numcpus; 206 207 which[1] = HW_CPUSPEED; 208 size = sizeof(cpuspeed); 209 if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0)) 210 goto error; 211 212 size = sizeof(info); 213 for (i = 0; i < numcpus; i++) { 214 percpu[2] = i; 215 if (sysctl(percpu, ARRAY_SIZE(percpu), &info, &size, NULL, 0)) 216 goto error; 217 218 cpu_info = &(*cpu_infos)[i]; 219 220 cpu_info->cpu_times.user = (uint64_t)(info[CP_USER]) * multiplier; 221 cpu_info->cpu_times.nice = (uint64_t)(info[CP_NICE]) * multiplier; 222 cpu_info->cpu_times.sys = (uint64_t)(info[CP_SYS]) * multiplier; 223 cpu_info->cpu_times.idle = (uint64_t)(info[CP_IDLE]) * multiplier; 224 cpu_info->cpu_times.irq = (uint64_t)(info[CP_INTR]) * multiplier; 225 226 cpu_info->model = uv__strdup(model); 227 cpu_info->speed = cpuspeed; 228 } 229 230 return 0; 231 232 error: 233 *count = 0; 234 for (j = 0; j < i; j++) 235 uv__free((*cpu_infos)[j].model); 236 237 uv__free(*cpu_infos); 238 *cpu_infos = NULL; 239 return UV__ERR(errno); 240 } 241