xref: /libuv/src/unix/netbsd.c (revision 988d225c)
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 
uv__platform_loop_init(uv_loop_t * loop)44 int uv__platform_loop_init(uv_loop_t* loop) {
45   return uv__kqueue_init(loop);
46 }
47 
48 
uv__platform_loop_delete(uv_loop_t * loop)49 void uv__platform_loop_delete(uv_loop_t* loop) {
50 }
51 
52 
uv_loadavg(double avg[3])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 
uv_exepath(char * buffer,size_t * size)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 
uv_get_free_memory(void)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 0;
107 
108   return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
109 }
110 
111 
uv_get_total_memory(void)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 0;
124 
125   return (uint64_t) info;
126 }
127 
128 
uv_get_constrained_memory(void)129 uint64_t uv_get_constrained_memory(void) {
130   return 0;  /* Memory constraints are unknown. */
131 }
132 
133 
uv_get_available_memory(void)134 uint64_t uv_get_available_memory(void) {
135   return uv_get_free_memory();
136 }
137 
138 
uv_resident_set_memory(size_t * rss)139 int uv_resident_set_memory(size_t* rss) {
140   kvm_t *kd = NULL;
141   struct kinfo_proc2 *kinfo = NULL;
142   pid_t pid;
143   int nprocs;
144   int max_size = sizeof(struct kinfo_proc2);
145   int page_size;
146 
147   page_size = getpagesize();
148   pid = getpid();
149 
150   kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");
151 
152   if (kd == NULL) goto error;
153 
154   kinfo = kvm_getproc2(kd, KERN_PROC_PID, pid, max_size, &nprocs);
155   if (kinfo == NULL) goto error;
156 
157   *rss = kinfo->p_vm_rssize * page_size;
158 
159   kvm_close(kd);
160 
161   return 0;
162 
163 error:
164   if (kd) kvm_close(kd);
165   return UV_EPERM;
166 }
167 
168 
uv_uptime(double * uptime)169 int uv_uptime(double* uptime) {
170   time_t now;
171   struct timeval info;
172   size_t size = sizeof(info);
173   static int which[] = {CTL_KERN, KERN_BOOTTIME};
174 
175   if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
176     return UV__ERR(errno);
177 
178   now = time(NULL);
179 
180   *uptime = (double)(now - info.tv_sec);
181   return 0;
182 }
183 
184 
uv_cpu_info(uv_cpu_info_t ** cpu_infos,int * count)185 int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
186   unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK);
187   unsigned int multiplier = ((uint64_t)1000L / ticks);
188   unsigned int cur = 0;
189   uv_cpu_info_t* cpu_info;
190   u_int64_t* cp_times;
191   char model[512];
192   u_int64_t cpuspeed;
193   int numcpus;
194   size_t size;
195   int i;
196 
197   size = sizeof(model);
198   if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) &&
199       sysctlbyname("hw.model", &model, &size, NULL, 0)) {
200     return UV__ERR(errno);
201   }
202 
203   size = sizeof(numcpus);
204   if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
205     return UV__ERR(errno);
206   *count = numcpus;
207 
208   /* Only i386 and amd64 have machdep.tsc_freq */
209   size = sizeof(cpuspeed);
210   if (sysctlbyname("machdep.tsc_freq", &cpuspeed, &size, NULL, 0))
211     cpuspeed = 0;
212 
213   size = numcpus * CPUSTATES * sizeof(*cp_times);
214   cp_times = uv__malloc(size);
215   if (cp_times == NULL)
216     return UV_ENOMEM;
217 
218   if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0))
219     return UV__ERR(errno);
220 
221   *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
222   if (!(*cpu_infos)) {
223     uv__free(cp_times);
224     uv__free(*cpu_infos);
225     return UV_ENOMEM;
226   }
227 
228   for (i = 0; i < numcpus; i++) {
229     cpu_info = &(*cpu_infos)[i];
230     cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
231     cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
232     cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
233     cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
234     cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
235     cpu_info->model = uv__strdup(model);
236     cpu_info->speed = (int)(cpuspeed/(uint64_t) 1e6);
237     cur += CPUSTATES;
238   }
239   uv__free(cp_times);
240   return 0;
241 }
242 
uv__random_sysctl(void * buf,size_t len)243 int uv__random_sysctl(void* buf, size_t len) {
244   static int name[] = {CTL_KERN, KERN_ARND};
245   size_t count, req;
246   unsigned char* p;
247 
248   p = buf;
249   while (len) {
250     req = len < 32 ? len : 32;
251     count = req;
252 
253     if (sysctl(name, ARRAY_SIZE(name), p, &count, NULL, 0) == -1)
254       return UV__ERR(errno);
255 
256     if (count != req)
257       return UV_EIO;  /* Can't happen. */
258 
259     p += count;
260     len -= count;
261   }
262 
263   return 0;
264 }
265