1 /*
2 * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #include "jni.h"
27 #include "jni_util.h"
28 #include "jlong.h"
29 #include "jvm.h"
30 #include "management_ext.h"
31 #include "com_sun_management_internal_OperatingSystemImpl.h"
32
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #if defined(_ALLBSD_SOURCE)
36 #include <sys/sysctl.h>
37 #ifdef __APPLE__
38 #include <sys/param.h>
39 #include <sys/mount.h>
40 #include <mach/mach.h>
41 #include <sys/proc_info.h>
42 #include <libproc.h>
43 #endif
44 #elif !defined(_AIX)
45 #include <sys/swap.h>
46 #endif
47 #include <sys/resource.h>
48 #include <sys/times.h>
49 #ifndef _ALLBSD_SOURCE
50 #include <sys/sysinfo.h>
51 #endif
52 #include <ctype.h>
53 #include <dirent.h>
54 #include <errno.h>
55 #include <fcntl.h>
56 #include <limits.h>
57 #include <stdlib.h>
58 #include <unistd.h>
59
60 #if defined(__FreeBSD__) || defined(__DragonFly__)
61 #include <vm/vm_param.h>
62 #endif
63
64 #if defined(_AIX)
65 #include <libperfstat.h>
66 #endif
67
68 static jlong page_size = 0;
69
70 #if defined(_ALLBSD_SOURCE) || defined(_AIX)
71 #define MB (1024UL * 1024UL)
72 #else
73
74 /* This gets us the new structured proc interfaces of 5.6 & later */
75 /* - see comment in <sys/procfs.h> */
76 #define _STRUCTURED_PROC 1
77 #include <sys/procfs.h>
78
79 #endif /* _ALLBSD_SOURCE */
80
81 #if defined(_ALLBSD_SOURCE)
82 #define dirent64 dirent
83 #define readdir64 readdir
84 #endif
85
86 // true = get available swap in bytes
87 // false = get total swap in bytes
get_total_or_available_swap_space_size(JNIEnv * env,jboolean available)88 static jlong get_total_or_available_swap_space_size(JNIEnv* env, jboolean available) {
89 #ifdef __solaris__
90 long total, avail;
91 int nswap, i, count;
92 swaptbl_t *stbl;
93 char *strtab;
94
95 // First get the number of swap resource entries
96 if ((nswap = swapctl(SC_GETNSWP, NULL)) == -1) {
97 throw_internal_error(env, "swapctl failed to get nswap");
98 return -1;
99 }
100 if (nswap == 0) {
101 return 0;
102 }
103
104 // Allocate storage for resource entries
105 stbl = (swaptbl_t*) malloc(nswap * sizeof(swapent_t) +
106 sizeof(struct swaptable));
107 if (stbl == NULL) {
108 JNU_ThrowOutOfMemoryError(env, 0);
109 return -1;
110 }
111
112 // Allocate storage for the table
113 strtab = (char*) malloc((nswap + 1) * MAXPATHLEN);
114 if (strtab == NULL) {
115 free(stbl);
116 JNU_ThrowOutOfMemoryError(env, 0);
117 return -1;
118 }
119
120 for (i = 0; i < (nswap + 1); i++) {
121 stbl->swt_ent[i].ste_path = strtab + (i * MAXPATHLEN);
122 }
123 stbl->swt_n = nswap + 1;
124
125 // Get the entries
126 if ((count = swapctl(SC_LIST, stbl)) < 0) {
127 free(stbl);
128 free(strtab);
129 throw_internal_error(env, "swapctl failed to get swap list");
130 return -1;
131 }
132
133 // Sum the entries to get total and free swap
134 total = 0;
135 avail = 0;
136 for (i = 0; i < count; i++) {
137 total += stbl->swt_ent[i].ste_pages;
138 avail += stbl->swt_ent[i].ste_free;
139 }
140
141 free(stbl);
142 free(strtab);
143 return available ? ((jlong)avail * page_size) :
144 ((jlong)total * page_size);
145 #elif defined(__linux__)
146 int ret;
147 FILE *fp;
148 jlong total = 0, avail = 0;
149
150 struct sysinfo si;
151 ret = sysinfo(&si);
152 if (ret != 0) {
153 throw_internal_error(env, "sysinfo failed to get swap size");
154 }
155 total = (jlong)si.totalswap * si.mem_unit;
156 avail = (jlong)si.freeswap * si.mem_unit;
157
158 return available ? avail : total;
159 #elif defined(__APPLE__)
160 struct xsw_usage vmusage;
161 size_t size = sizeof(vmusage);
162 if (sysctlbyname("vm.swapusage", &vmusage, &size, NULL, 0) != 0) {
163 throw_internal_error(env, "sysctlbyname failed");
164 }
165 return available ? (jlong)vmusage.xsu_avail : (jlong)vmusage.xsu_total;
166 #elif defined(__FreeBSD__)
167 struct xswdev xsw;
168 size_t mibsize, size;
169 jlong npages;
170 int mib[16], n;
171
172 mibsize = sizeof(mib) / sizeof(mib[0]);
173 if (sysctlnametomib("vm.swap_info", mib, &mibsize) == -1)
174 return (0);
175 for (n = 0, npages = 0; ; n++) {
176 mib[mibsize] = n;
177 size = sizeof(xsw);
178 if (sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1)
179 break;
180 npages += xsw.xsw_nblks;
181 if (available)
182 npages -= xsw.xsw_used;
183 }
184 return (npages * page_size);
185 #else /* _ALLBSD_SOURCE */
186 /*
187 * XXXBSD: there's no way available to get swap info in
188 * FreeBSD. Usage of libkvm is not an option here
189 */
190 // throw_internal_error(env, "Unimplemented in FreeBSD");
191 return (0);
192 #endif
193 }
194
195 JNIEXPORT void JNICALL
Java_com_sun_management_internal_OperatingSystemImpl_initialize0(JNIEnv * env,jclass cls)196 Java_com_sun_management_internal_OperatingSystemImpl_initialize0
197 (JNIEnv *env, jclass cls)
198 {
199 page_size = sysconf(_SC_PAGESIZE);
200 }
201
202 JNIEXPORT jlong JNICALL
Java_com_sun_management_internal_OperatingSystemImpl_getCommittedVirtualMemorySize0(JNIEnv * env,jobject mbean)203 Java_com_sun_management_internal_OperatingSystemImpl_getCommittedVirtualMemorySize0
204 (JNIEnv *env, jobject mbean)
205 {
206 #ifdef __solaris__
207 psinfo_t psinfo;
208 ssize_t result;
209 size_t remaining;
210 char* addr;
211 int fd;
212
213 fd = open64("/proc/self/psinfo", O_RDONLY, 0);
214 if (fd < 0) {
215 throw_internal_error(env, "Unable to open /proc/self/psinfo");
216 return -1;
217 }
218
219 addr = (char *)&psinfo;
220 for (remaining = sizeof(psinfo_t); remaining > 0;) {
221 result = read(fd, addr, remaining);
222 if (result < 0) {
223 if (errno != EINTR) {
224 close(fd);
225 throw_internal_error(env, "Unable to read /proc/self/psinfo");
226 return -1;
227 }
228 } else {
229 remaining -= result;
230 addr += result;
231 }
232 }
233
234 close(fd);
235 return (jlong) psinfo.pr_size * 1024;
236 #elif defined(__linux__)
237 FILE *fp;
238 unsigned long vsize = 0;
239
240 if ((fp = fopen("/proc/self/stat", "r")) == NULL) {
241 throw_internal_error(env, "Unable to open /proc/self/stat");
242 return -1;
243 }
244
245 // Ignore everything except the vsize entry
246 if (fscanf(fp, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %*d %*d %*d %*d %*d %*d %*u %*u %*d %lu %*[^\n]\n", &vsize) == EOF) {
247 throw_internal_error(env, "Unable to get virtual memory usage");
248 fclose(fp);
249 return -1;
250 }
251
252 fclose(fp);
253 return (jlong)vsize;
254 #elif defined(__APPLE__)
255 struct task_basic_info t_info;
256 mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
257
258 kern_return_t res = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
259 if (res != KERN_SUCCESS) {
260 throw_internal_error(env, "task_info failed");
261 }
262 return t_info.virtual_size;
263 #elif defined(__FreeBSD__) || defined(__DragonFly__)
264 FILE *fp;
265 unsigned long end, start;
266 jlong total = 0;
267
268 if ((fp = fopen("/proc/curproc/map", "r")) == NULL) {
269 throw_internal_error(env, "Unable to open /proc/curproc/map");
270 return -1;
271 }
272
273 for (;;) {
274 // Ignore everything except start and end entries
275 if (fscanf(fp, "0x%lx 0x%lx %*[^\n]\n", &start, &end) != 2 || start > end)
276 break;
277 total += end - start;
278 }
279
280 fclose(fp);
281 return total;
282 #else /* _ALLBSD_SOURCE */
283 /*
284 * XXXBSD: there's no way available to do it in FreeBSD, AFAIK.
285 */
286 // throw_internal_error(env, "Unimplemented in FreeBSD");
287 return (64 * MB);
288 #endif
289 }
290
291 JNIEXPORT jlong JNICALL
Java_com_sun_management_internal_OperatingSystemImpl_getTotalSwapSpaceSize0(JNIEnv * env,jobject mbean)292 Java_com_sun_management_internal_OperatingSystemImpl_getTotalSwapSpaceSize0
293 (JNIEnv *env, jobject mbean)
294 {
295 return get_total_or_available_swap_space_size(env, JNI_FALSE);
296 }
297
298 JNIEXPORT jlong JNICALL
Java_com_sun_management_internal_OperatingSystemImpl_getFreeSwapSpaceSize0(JNIEnv * env,jobject mbean)299 Java_com_sun_management_internal_OperatingSystemImpl_getFreeSwapSpaceSize0
300 (JNIEnv *env, jobject mbean)
301 {
302 return get_total_or_available_swap_space_size(env, JNI_TRUE);
303 }
304
305 JNIEXPORT jlong JNICALL
Java_com_sun_management_internal_OperatingSystemImpl_getProcessCpuTime0(JNIEnv * env,jobject mbean)306 Java_com_sun_management_internal_OperatingSystemImpl_getProcessCpuTime0
307 (JNIEnv *env, jobject mbean)
308 {
309 #ifdef __APPLE__
310 struct rusage usage;
311 if (getrusage(RUSAGE_SELF, &usage) != 0) {
312 throw_internal_error(env, "getrusage failed");
313 return -1;
314 }
315 jlong microsecs =
316 usage.ru_utime.tv_sec * 1000 * 1000 + usage.ru_utime.tv_usec +
317 usage.ru_stime.tv_sec * 1000 * 1000 + usage.ru_stime.tv_usec;
318 return microsecs * 1000;
319 #else
320 jlong clk_tck, ns_per_clock_tick;
321 jlong cpu_time_ns;
322 struct tms time;
323
324 /*
325 * BSDNOTE: FreeBSD implements _SC_CLK_TCK since FreeBSD 5, so
326 * add a magic to handle it
327 */
328 #if defined(__solaris__) || defined(_SC_CLK_TCK)
329 clk_tck = (jlong) sysconf(_SC_CLK_TCK);
330 #elif defined(__linux__) || defined(_ALLBSD_SOURCE)
331 clk_tck = 100;
332 #endif
333 if (clk_tck == -1) {
334 throw_internal_error(env,
335 "sysconf failed - not able to get clock tick");
336 return -1;
337 }
338
339 times(&time);
340 ns_per_clock_tick = (jlong) 1000 * 1000 * 1000 / (jlong) clk_tck;
341 cpu_time_ns = ((jlong)time.tms_utime + (jlong) time.tms_stime) *
342 ns_per_clock_tick;
343 return cpu_time_ns;
344 #endif
345 }
346
347 JNIEXPORT jlong JNICALL
Java_com_sun_management_internal_OperatingSystemImpl_getFreePhysicalMemorySize0(JNIEnv * env,jobject mbean)348 Java_com_sun_management_internal_OperatingSystemImpl_getFreePhysicalMemorySize0
349 (JNIEnv *env, jobject mbean)
350 {
351 #ifdef __APPLE__
352 mach_msg_type_number_t count;
353 vm_statistics_data_t vm_stats;
354 kern_return_t res;
355
356 count = HOST_VM_INFO_COUNT;
357 res = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vm_stats, &count);
358 if (res != KERN_SUCCESS) {
359 throw_internal_error(env, "host_statistics failed");
360 return -1;
361 }
362 return (jlong)vm_stats.free_count * page_size;
363 #elif defined(__FreeBSD__) || defined(__DragonFly__)
364 static const char *vm_stats[] = {
365 "vm.stats.vm.v_free_count",
366 "vm.stats.vm.v_cache_count",
367 /* "vm.stats.vm.v_inactive_count", */
368 NULL
369 };
370 size_t size;
371 jlong free_pages;
372 #ifdef __DragonFly__
373 u_long i, npages;
374 #else
375 u_int i, npages;
376 #endif
377 for (i = 0, free_pages = 0, size = sizeof(npages); vm_stats[i] != NULL; i++) {
378 if (sysctlbyname(vm_stats[i], &npages, &size, NULL, 0) == -1)
379 return 0;
380 free_pages += npages;
381 }
382 return (free_pages * page_size);
383 #elif defined(_ALLBSD_SOURCE)
384 /*
385 * XXBSDL no way to do it in FreeBSD
386 */
387 // throw_internal_error(env, "unimplemented in FreeBSD")
388 return (128 * MB);
389 #elif defined(_AIX)
390 perfstat_memory_total_t memory_info;
391 if (-1 != perfstat_memory_total(NULL, &memory_info, sizeof(perfstat_memory_total_t), 1)) {
392 return (jlong)(memory_info.real_free * 4L * 1024L);
393 }
394 return -1;
395 #else // solaris / linux
396 jlong num_avail_physical_pages = sysconf(_SC_AVPHYS_PAGES);
397 return (num_avail_physical_pages * page_size);
398 #endif
399 }
400
401 JNIEXPORT jlong JNICALL
Java_com_sun_management_internal_OperatingSystemImpl_getTotalPhysicalMemorySize0(JNIEnv * env,jobject mbean)402 Java_com_sun_management_internal_OperatingSystemImpl_getTotalPhysicalMemorySize0
403 (JNIEnv *env, jobject mbean)
404 {
405 #ifdef _ALLBSD_SOURCE
406 int mib[2];
407 size_t rlen;
408 #if defined (HW_MEMSIZE) // Apple
409 uint64_t result = 0;
410 #define MEMMIB HW_MEMSIZE;
411 #elif defined(HW_PHYSMEM64) // OpenBSD & NetBSD
412 int64_t result = 0;
413 #define MEMMIB HW_PHYSMEM64;
414 #elif defined(HW_PHYSMEM) // FreeBSD
415 unsigned long result = 0;
416 #define MEMMIB HW_PHYSMEM;
417 #else
418 #error No ways to get physmem
419 #endif
420
421 mib[0] = CTL_HW;
422 mib[1] = MEMMIB;
423
424 rlen = sizeof(result);
425 if (sysctl(mib, 2, &result, &rlen, NULL, 0) != 0) {
426 throw_internal_error(env, "sysctl failed");
427 return -1;
428 }
429 return result;
430 #elif defined(_AIX)
431 perfstat_memory_total_t memory_info;
432 if (-1 != perfstat_memory_total(NULL, &memory_info, sizeof(perfstat_memory_total_t), 1)) {
433 return (jlong)(memory_info.real_total * 4L * 1024L);
434 }
435 return -1;
436 #else // solaris / linux
437 jlong num_physical_pages = sysconf(_SC_PHYS_PAGES);
438 return (num_physical_pages * page_size);
439 #endif
440 }
441
442
443
444 JNIEXPORT jlong JNICALL
Java_com_sun_management_internal_OperatingSystemImpl_getOpenFileDescriptorCount0(JNIEnv * env,jobject mbean)445 Java_com_sun_management_internal_OperatingSystemImpl_getOpenFileDescriptorCount0
446 (JNIEnv *env, jobject mbean)
447 {
448 #ifdef __APPLE__
449 // This code is influenced by the darwin lsof source
450 pid_t my_pid;
451 struct proc_bsdinfo bsdinfo;
452 struct proc_fdinfo *fds;
453 int nfiles;
454 kern_return_t kres;
455 int res;
456 size_t fds_size;
457
458 kres = pid_for_task(mach_task_self(), &my_pid);
459 if (kres != KERN_SUCCESS) {
460 throw_internal_error(env, "pid_for_task failed");
461 return -1;
462 }
463
464 // get the maximum number of file descriptors
465 res = proc_pidinfo(my_pid, PROC_PIDTBSDINFO, 0, &bsdinfo, PROC_PIDTBSDINFO_SIZE);
466 if (res <= 0) {
467 throw_internal_error(env, "proc_pidinfo with PROC_PIDTBSDINFO failed");
468 return -1;
469 }
470
471 // allocate memory to hold the fd information (we don't acutally use this information
472 // but need it to get the number of open files)
473 fds_size = bsdinfo.pbi_nfiles * sizeof(struct proc_fdinfo);
474 fds = malloc(fds_size);
475 if (fds == NULL) {
476 JNU_ThrowOutOfMemoryError(env, "could not allocate space for file descriptors");
477 return -1;
478 }
479
480 // get the list of open files - the return value is the number of bytes
481 // proc_pidinfo filled in
482 res = proc_pidinfo(my_pid, PROC_PIDLISTFDS, 0, fds, fds_size);
483 if (res <= 0) {
484 free(fds);
485 throw_internal_error(env, "proc_pidinfo failed for PROC_PIDLISTFDS");
486 return -1;
487 }
488 nfiles = res / sizeof(struct proc_fdinfo);
489 free(fds);
490
491 return nfiles;
492 #elif defined(__OpenBSD__)
493 return getdtablecount();
494 #else /* solaris/linux */
495 DIR *dirp;
496 struct dirent64* dentp;
497 jlong fds = 0;
498
499 #if defined(_AIX)
500 /* AIX does not understand '/proc/self' - it requires the real process ID */
501 #define FD_DIR aix_fd_dir
502 char aix_fd_dir[32]; /* the pid has at most 19 digits */
503 snprintf(aix_fd_dir, 32, "/proc/%d/fd", getpid());
504 #elif defined(_ALLBSD_SOURCE)
505 #define FD_DIR "/dev/fd"
506 #else
507 #define FD_DIR "/proc/self/fd"
508 #endif
509
510 dirp = opendir(FD_DIR);
511 if (dirp == NULL) {
512 throw_internal_error(env, "Unable to open directory /proc/self/fd");
513 return -1;
514 }
515
516 // iterate through directory entries, skipping '.' and '..'
517 // each entry represents an open file descriptor.
518 while ((dentp = readdir64(dirp)) != NULL) {
519 if (isdigit(dentp->d_name[0])) {
520 fds++;
521 }
522 }
523
524 closedir(dirp);
525 // subtract by 1 which was the fd open for this implementation
526 return (fds - 1);
527 #endif
528 }
529
530 JNIEXPORT jlong JNICALL
Java_com_sun_management_internal_OperatingSystemImpl_getMaxFileDescriptorCount0(JNIEnv * env,jobject mbean)531 Java_com_sun_management_internal_OperatingSystemImpl_getMaxFileDescriptorCount0
532 (JNIEnv *env, jobject mbean)
533 {
534 struct rlimit rlp;
535
536 if (getrlimit(RLIMIT_NOFILE, &rlp) == -1) {
537 throw_internal_error(env, "getrlimit failed");
538 return -1;
539 }
540 return (jlong) rlp.rlim_cur;
541 }
542