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
uv__platform_loop_init(uv_loop_t * loop)51 int uv__platform_loop_init(uv_loop_t* loop) {
52 return uv__kqueue_init(loop);
53 }
54
55
uv__platform_loop_delete(uv_loop_t * loop)56 void uv__platform_loop_delete(uv_loop_t* loop) {
57 }
58
59
60 #ifdef __DragonFly__
uv_exepath(char * buffer,size_t * size)61 int uv_exepath(char* buffer, size_t* size) {
62 char abspath[PATH_MAX * 2 + 1];
63 ssize_t abspath_size;
64
65 if (buffer == NULL || size == NULL || *size == 0)
66 return UV_EINVAL;
67
68 abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath));
69 if (abspath_size < 0)
70 return UV__ERR(errno);
71
72 assert(abspath_size > 0);
73 *size -= 1;
74
75 if (*size > abspath_size)
76 *size = abspath_size;
77
78 memcpy(buffer, abspath, *size);
79 buffer[*size] = '\0';
80
81 return 0;
82 }
83 #else
uv_exepath(char * buffer,size_t * size)84 int uv_exepath(char* buffer, size_t* size) {
85 char abspath[PATH_MAX * 2 + 1];
86 int mib[4];
87 size_t abspath_size;
88
89 if (buffer == NULL || size == NULL || *size == 0)
90 return UV_EINVAL;
91
92 mib[0] = CTL_KERN;
93 mib[1] = KERN_PROC;
94 mib[2] = KERN_PROC_PATHNAME;
95 mib[3] = -1;
96
97 abspath_size = sizeof abspath;
98 if (sysctl(mib, ARRAY_SIZE(mib), abspath, &abspath_size, NULL, 0))
99 return UV__ERR(errno);
100
101 assert(abspath_size > 0);
102 abspath_size -= 1;
103 *size -= 1;
104
105 if (*size > abspath_size)
106 *size = abspath_size;
107
108 memcpy(buffer, abspath, *size);
109 buffer[*size] = '\0';
110
111 return 0;
112 }
113 #endif
114
uv_get_free_memory(void)115 uint64_t uv_get_free_memory(void) {
116 int freecount;
117 size_t size = sizeof(freecount);
118
119 if (sysctlbyname("vm.stats.vm.v_free_count", &freecount, &size, NULL, 0))
120 return UV__ERR(errno);
121
122 return (uint64_t) freecount * sysconf(_SC_PAGESIZE);
123
124 }
125
126
uv_get_total_memory(void)127 uint64_t uv_get_total_memory(void) {
128 unsigned long info;
129 int which[] = {CTL_HW, HW_PHYSMEM};
130
131 size_t size = sizeof(info);
132
133 if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
134 return UV__ERR(errno);
135
136 return (uint64_t) info;
137 }
138
139
uv_get_constrained_memory(void)140 uint64_t uv_get_constrained_memory(void) {
141 return 0; /* Memory constraints are unknown. */
142 }
143
144
uv_loadavg(double avg[3])145 void uv_loadavg(double avg[3]) {
146 struct loadavg info;
147 size_t size = sizeof(info);
148 int which[] = {CTL_VM, VM_LOADAVG};
149
150 if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) < 0) return;
151
152 avg[0] = (double) info.ldavg[0] / info.fscale;
153 avg[1] = (double) info.ldavg[1] / info.fscale;
154 avg[2] = (double) info.ldavg[2] / info.fscale;
155 }
156
157
uv_resident_set_memory(size_t * rss)158 int uv_resident_set_memory(size_t* rss) {
159 struct kinfo_proc kinfo;
160 size_t page_size;
161 size_t kinfo_size;
162 int mib[4];
163
164 mib[0] = CTL_KERN;
165 mib[1] = KERN_PROC;
166 mib[2] = KERN_PROC_PID;
167 mib[3] = getpid();
168
169 kinfo_size = sizeof(kinfo);
170
171 if (sysctl(mib, ARRAY_SIZE(mib), &kinfo, &kinfo_size, NULL, 0))
172 return UV__ERR(errno);
173
174 page_size = getpagesize();
175
176 #ifdef __DragonFly__
177 *rss = kinfo.kp_vm_rssize * page_size;
178 #else
179 *rss = kinfo.ki_rssize * page_size;
180 #endif
181
182 return 0;
183 }
184
185
uv_uptime(double * uptime)186 int uv_uptime(double* uptime) {
187 int r;
188 struct timespec sp;
189 r = clock_gettime(CLOCK_MONOTONIC, &sp);
190 if (r)
191 return UV__ERR(errno);
192
193 *uptime = sp.tv_sec;
194 return 0;
195 }
196
197
uv_cpu_info(uv_cpu_info_t ** cpu_infos,int * count)198 int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
199 unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
200 multiplier = ((uint64_t)1000L / ticks), cpuspeed, maxcpus,
201 cur = 0;
202 uv_cpu_info_t* cpu_info;
203 const char* maxcpus_key;
204 const char* cptimes_key;
205 const char* model_key;
206 char model[512];
207 long* cp_times;
208 int numcpus;
209 size_t size;
210 int i;
211
212 #if defined(__DragonFly__)
213 /* This is not quite correct but DragonFlyBSD doesn't seem to have anything
214 * comparable to kern.smp.maxcpus or kern.cp_times (kern.cp_time is a total,
215 * not per CPU). At least this stops uv_cpu_info() from failing completely.
216 */
217 maxcpus_key = "hw.ncpu";
218 cptimes_key = "kern.cp_time";
219 #else
220 maxcpus_key = "kern.smp.maxcpus";
221 cptimes_key = "kern.cp_times";
222 #endif
223
224 #if defined(__arm__) || defined(__aarch64__)
225 /* The key hw.model and hw.clockrate are not available on FreeBSD ARM. */
226 model_key = "hw.machine";
227 cpuspeed = 0;
228 #else
229 model_key = "hw.model";
230
231 size = sizeof(cpuspeed);
232 if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0))
233 return -errno;
234 #endif
235
236 size = sizeof(model);
237 if (sysctlbyname(model_key, &model, &size, NULL, 0))
238 return UV__ERR(errno);
239
240 size = sizeof(numcpus);
241 if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
242 return UV__ERR(errno);
243
244 *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
245 if (!(*cpu_infos))
246 return UV_ENOMEM;
247
248 *count = numcpus;
249
250 /* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of
251 * ncpu.
252 */
253 size = sizeof(maxcpus);
254 if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) {
255 uv__free(*cpu_infos);
256 return UV__ERR(errno);
257 }
258
259 size = maxcpus * CPUSTATES * sizeof(long);
260
261 cp_times = uv__malloc(size);
262 if (cp_times == NULL) {
263 uv__free(*cpu_infos);
264 return UV_ENOMEM;
265 }
266
267 if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) {
268 uv__free(cp_times);
269 uv__free(*cpu_infos);
270 return UV__ERR(errno);
271 }
272
273 for (i = 0; i < numcpus; i++) {
274 cpu_info = &(*cpu_infos)[i];
275
276 cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
277 cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
278 cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
279 cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
280 cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
281
282 cpu_info->model = uv__strdup(model);
283 cpu_info->speed = cpuspeed;
284
285 cur+=CPUSTATES;
286 }
287
288 uv__free(cp_times);
289 return 0;
290 }
291
292
uv__sendmmsg(int fd,struct uv__mmsghdr * mmsg,unsigned int vlen,unsigned int flags)293 int uv__sendmmsg(int fd,
294 struct uv__mmsghdr* mmsg,
295 unsigned int vlen,
296 unsigned int flags) {
297 #if __FreeBSD__ >= 11
298 return sendmmsg(fd, mmsg, vlen, flags);
299 #else
300 return errno = ENOSYS, -1;
301 #endif
302 }
303
304
uv__recvmmsg(int fd,struct uv__mmsghdr * mmsg,unsigned int vlen,unsigned int flags,struct timespec * timeout)305 int uv__recvmmsg(int fd,
306 struct uv__mmsghdr* mmsg,
307 unsigned int vlen,
308 unsigned int flags,
309 struct timespec* timeout) {
310 #if __FreeBSD__ >= 11
311 return recvmmsg(fd, mmsg, vlen, flags, timeout);
312 #else
313 return errno = ENOSYS, -1;
314 #endif
315 }
316