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 <kvm.h> 29 #include <paths.h> 30 #include <unistd.h> 31 #include <time.h> 32 #include <stdlib.h> 33 #include <fcntl.h> 34 35 #include <sys/resource.h> 36 #include <sys/types.h> 37 #include <sys/sysctl.h> 38 #include <uvm/uvm_extern.h> 39 40 #include <unistd.h> 41 #include <time.h> 42 43 44 int uv__platform_loop_init(uv_loop_t* loop) { 45 return uv__kqueue_init(loop); 46 } 47 48 49 void uv__platform_loop_delete(uv_loop_t* loop) { 50 } 51 52 53 void uv_loadavg(double avg[3]) { 54 struct loadavg info; 55 size_t size = sizeof(info); 56 int which[] = {CTL_VM, VM_LOADAVG}; 57 58 if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) == -1) return; 59 60 avg[0] = (double) info.ldavg[0] / info.fscale; 61 avg[1] = (double) info.ldavg[1] / info.fscale; 62 avg[2] = (double) info.ldavg[2] / info.fscale; 63 } 64 65 66 int uv_exepath(char* buffer, size_t* size) { 67 /* Intermediate buffer, retrieving partial path name does not work 68 * As of NetBSD-8(beta), vnode->path translator does not handle files 69 * with longer names than 31 characters. 70 */ 71 char int_buf[PATH_MAX]; 72 size_t int_size; 73 int mib[4]; 74 75 if (buffer == NULL || size == NULL || *size == 0) 76 return UV_EINVAL; 77 78 mib[0] = CTL_KERN; 79 mib[1] = KERN_PROC_ARGS; 80 mib[2] = -1; 81 mib[3] = KERN_PROC_PATHNAME; 82 int_size = ARRAY_SIZE(int_buf); 83 84 if (sysctl(mib, 4, int_buf, &int_size, NULL, 0)) 85 return UV__ERR(errno); 86 87 /* Copy string from the intermediate buffer to outer one with appropriate 88 * length. 89 */ 90 /* TODO(bnoordhuis) Check uv__strscpy() return value. */ 91 uv__strscpy(buffer, int_buf, *size); 92 93 /* Set new size. */ 94 *size = strlen(buffer); 95 96 return 0; 97 } 98 99 100 uint64_t uv_get_free_memory(void) { 101 struct uvmexp info; 102 size_t size = sizeof(info); 103 int which[] = {CTL_VM, VM_UVMEXP}; 104 105 if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0)) 106 return UV__ERR(errno); 107 108 return (uint64_t) info.free * sysconf(_SC_PAGESIZE); 109 } 110 111 112 uint64_t uv_get_total_memory(void) { 113 #if defined(HW_PHYSMEM64) 114 uint64_t info; 115 int which[] = {CTL_HW, HW_PHYSMEM64}; 116 #else 117 unsigned int info; 118 int which[] = {CTL_HW, HW_PHYSMEM}; 119 #endif 120 size_t size = sizeof(info); 121 122 if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0)) 123 return UV__ERR(errno); 124 125 return (uint64_t) info; 126 } 127 128 129 uint64_t uv_get_constrained_memory(void) { 130 return 0; /* Memory constraints are unknown. */ 131 } 132 133 134 int uv_resident_set_memory(size_t* rss) { 135 kvm_t *kd = NULL; 136 struct kinfo_proc2 *kinfo = NULL; 137 pid_t pid; 138 int nprocs; 139 int max_size = sizeof(struct kinfo_proc2); 140 int page_size; 141 142 page_size = getpagesize(); 143 pid = getpid(); 144 145 kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open"); 146 147 if (kd == NULL) goto error; 148 149 kinfo = kvm_getproc2(kd, KERN_PROC_PID, pid, max_size, &nprocs); 150 if (kinfo == NULL) goto error; 151 152 *rss = kinfo->p_vm_rssize * page_size; 153 154 kvm_close(kd); 155 156 return 0; 157 158 error: 159 if (kd) kvm_close(kd); 160 return UV_EPERM; 161 } 162 163 164 int uv_uptime(double* uptime) { 165 time_t now; 166 struct timeval info; 167 size_t size = sizeof(info); 168 static int which[] = {CTL_KERN, KERN_BOOTTIME}; 169 170 if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0)) 171 return UV__ERR(errno); 172 173 now = time(NULL); 174 175 *uptime = (double)(now - info.tv_sec); 176 return 0; 177 } 178 179 180 int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { 181 unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK); 182 unsigned int multiplier = ((uint64_t)1000L / ticks); 183 unsigned int cur = 0; 184 uv_cpu_info_t* cpu_info; 185 u_int64_t* cp_times; 186 char model[512]; 187 u_int64_t cpuspeed; 188 int numcpus; 189 size_t size; 190 int i; 191 192 size = sizeof(model); 193 if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) && 194 sysctlbyname("hw.model", &model, &size, NULL, 0)) { 195 return UV__ERR(errno); 196 } 197 198 size = sizeof(numcpus); 199 if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) 200 return UV__ERR(errno); 201 *count = numcpus; 202 203 /* Only i386 and amd64 have machdep.tsc_freq */ 204 size = sizeof(cpuspeed); 205 if (sysctlbyname("machdep.tsc_freq", &cpuspeed, &size, NULL, 0)) 206 cpuspeed = 0; 207 208 size = numcpus * CPUSTATES * sizeof(*cp_times); 209 cp_times = uv__malloc(size); 210 if (cp_times == NULL) 211 return UV_ENOMEM; 212 213 if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0)) 214 return UV__ERR(errno); 215 216 *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); 217 if (!(*cpu_infos)) { 218 uv__free(cp_times); 219 uv__free(*cpu_infos); 220 return UV_ENOMEM; 221 } 222 223 for (i = 0; i < numcpus; i++) { 224 cpu_info = &(*cpu_infos)[i]; 225 cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier; 226 cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier; 227 cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier; 228 cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier; 229 cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier; 230 cpu_info->model = uv__strdup(model); 231 cpu_info->speed = (int)(cpuspeed/(uint64_t) 1e6); 232 cur += CPUSTATES; 233 } 234 uv__free(cp_times); 235 return 0; 236 } 237 238 int uv__random_sysctl(void* buf, size_t len) { 239 static int name[] = {CTL_KERN, KERN_ARND}; 240 size_t count, req; 241 unsigned char* p; 242 243 p = buf; 244 while (len) { 245 req = len < 32 ? len : 32; 246 count = req; 247 248 if (sysctl(name, ARRAY_SIZE(name), p, &count, NULL, 0) == -1) 249 return UV__ERR(errno); 250 251 if (count != req) 252 return UV_EIO; /* Can't happen. */ 253 254 p += count; 255 len -= count; 256 } 257 258 return 0; 259 } 260