1 /* 2 * Copyright (c) 2003, 2015, 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(_AIX) 61 #include <libperfstat.h> 62 #endif 63 64 static jlong page_size = 0; 65 66 #if defined(_ALLBSD_SOURCE) || defined(_AIX) 67 #define MB (1024UL * 1024UL) 68 #else 69 70 /* This gets us the new structured proc interfaces of 5.6 & later */ 71 /* - see comment in <sys/procfs.h> */ 72 #define _STRUCTURED_PROC 1 73 #include <sys/procfs.h> 74 75 #endif /* _ALLBSD_SOURCE */ 76 77 static struct dirent* read_dir(DIR* dirp, struct dirent* entry) { 78 #ifdef __solaris__ 79 struct dirent* dbuf = readdir(dirp); 80 return dbuf; 81 #else /* __linux__ || _ALLBSD_SOURCE */ 82 struct dirent* p; 83 if (readdir_r(dirp, entry, &p) == 0) { 84 return p; 85 } else { 86 return NULL; 87 } 88 #endif 89 } 90 91 // true = get available swap in bytes 92 // false = get total swap in bytes 93 static jlong get_total_or_available_swap_space_size(JNIEnv* env, jboolean available) { 94 #ifdef __solaris__ 95 long total, avail; 96 int nswap, i, count; 97 swaptbl_t *stbl; 98 char *strtab; 99 100 // First get the number of swap resource entries 101 if ((nswap = swapctl(SC_GETNSWP, NULL)) == -1) { 102 throw_internal_error(env, "swapctl failed to get nswap"); 103 return -1; 104 } 105 if (nswap == 0) { 106 return 0; 107 } 108 109 // Allocate storage for resource entries 110 stbl = (swaptbl_t*) malloc(nswap * sizeof(swapent_t) + 111 sizeof(struct swaptable)); 112 if (stbl == NULL) { 113 JNU_ThrowOutOfMemoryError(env, 0); 114 return -1; 115 } 116 117 // Allocate storage for the table 118 strtab = (char*) malloc((nswap + 1) * MAXPATHLEN); 119 if (strtab == NULL) { 120 free(stbl); 121 JNU_ThrowOutOfMemoryError(env, 0); 122 return -1; 123 } 124 125 for (i = 0; i < (nswap + 1); i++) { 126 stbl->swt_ent[i].ste_path = strtab + (i * MAXPATHLEN); 127 } 128 stbl->swt_n = nswap + 1; 129 130 // Get the entries 131 if ((count = swapctl(SC_LIST, stbl)) < 0) { 132 free(stbl); 133 free(strtab); 134 throw_internal_error(env, "swapctl failed to get swap list"); 135 return -1; 136 } 137 138 // Sum the entries to get total and free swap 139 total = 0; 140 avail = 0; 141 for (i = 0; i < count; i++) { 142 total += stbl->swt_ent[i].ste_pages; 143 avail += stbl->swt_ent[i].ste_free; 144 } 145 146 free(stbl); 147 free(strtab); 148 return available ? ((jlong)avail * page_size) : 149 ((jlong)total * page_size); 150 #elif defined(__linux__) 151 int ret; 152 FILE *fp; 153 jlong total = 0, avail = 0; 154 155 struct sysinfo si; 156 ret = sysinfo(&si); 157 if (ret != 0) { 158 throw_internal_error(env, "sysinfo failed to get swap size"); 159 } 160 total = (jlong)si.totalswap * si.mem_unit; 161 avail = (jlong)si.freeswap * si.mem_unit; 162 163 return available ? avail : total; 164 #elif defined(__APPLE__) 165 struct xsw_usage vmusage; 166 size_t size = sizeof(vmusage); 167 if (sysctlbyname("vm.swapusage", &vmusage, &size, NULL, 0) != 0) { 168 throw_internal_error(env, "sysctlbyname failed"); 169 } 170 return available ? (jlong)vmusage.xsu_avail : (jlong)vmusage.xsu_total; 171 #else /* _ALLBSD_SOURCE */ 172 /* 173 * XXXBSD: there's no way available to get swap info in 174 * FreeBSD. Usage of libkvm is not an option here 175 */ 176 // throw_internal_error(env, "Unimplemented in FreeBSD"); 177 return (0); 178 #endif 179 } 180 181 JNIEXPORT void JNICALL 182 Java_com_sun_management_internal_OperatingSystemImpl_initialize0 183 (JNIEnv *env, jclass cls) 184 { 185 page_size = sysconf(_SC_PAGESIZE); 186 } 187 188 JNIEXPORT jlong JNICALL 189 Java_com_sun_management_internal_OperatingSystemImpl_getCommittedVirtualMemorySize0 190 (JNIEnv *env, jobject mbean) 191 { 192 #ifdef __solaris__ 193 psinfo_t psinfo; 194 ssize_t result; 195 size_t remaining; 196 char* addr; 197 int fd; 198 199 fd = open64("/proc/self/psinfo", O_RDONLY, 0); 200 if (fd < 0) { 201 throw_internal_error(env, "Unable to open /proc/self/psinfo"); 202 return -1; 203 } 204 205 addr = (char *)&psinfo; 206 for (remaining = sizeof(psinfo_t); remaining > 0;) { 207 result = read(fd, addr, remaining); 208 if (result < 0) { 209 if (errno != EINTR) { 210 close(fd); 211 throw_internal_error(env, "Unable to read /proc/self/psinfo"); 212 return -1; 213 } 214 } else { 215 remaining -= result; 216 addr += result; 217 } 218 } 219 220 close(fd); 221 return (jlong) psinfo.pr_size * 1024; 222 #elif defined(__linux__) 223 FILE *fp; 224 unsigned long vsize = 0; 225 226 if ((fp = fopen("/proc/self/stat", "r")) == NULL) { 227 throw_internal_error(env, "Unable to open /proc/self/stat"); 228 return -1; 229 } 230 231 // Ignore everything except the vsize entry 232 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) { 233 throw_internal_error(env, "Unable to get virtual memory usage"); 234 fclose(fp); 235 return -1; 236 } 237 238 fclose(fp); 239 return (jlong)vsize; 240 #elif defined(__APPLE__) 241 struct task_basic_info t_info; 242 mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; 243 244 kern_return_t res = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count); 245 if (res != KERN_SUCCESS) { 246 throw_internal_error(env, "task_info failed"); 247 } 248 return t_info.virtual_size; 249 #else /* _ALLBSD_SOURCE */ 250 /* 251 * XXXBSD: there's no way available to do it in FreeBSD, AFAIK. 252 */ 253 // throw_internal_error(env, "Unimplemented in FreeBSD"); 254 return (64 * MB); 255 #endif 256 } 257 258 JNIEXPORT jlong JNICALL 259 Java_com_sun_management_internal_OperatingSystemImpl_getTotalSwapSpaceSize0 260 (JNIEnv *env, jobject mbean) 261 { 262 return get_total_or_available_swap_space_size(env, JNI_FALSE); 263 } 264 265 JNIEXPORT jlong JNICALL 266 Java_com_sun_management_internal_OperatingSystemImpl_getFreeSwapSpaceSize0 267 (JNIEnv *env, jobject mbean) 268 { 269 return get_total_or_available_swap_space_size(env, JNI_TRUE); 270 } 271 272 JNIEXPORT jlong JNICALL 273 Java_com_sun_management_internal_OperatingSystemImpl_getProcessCpuTime0 274 (JNIEnv *env, jobject mbean) 275 { 276 #ifdef __APPLE__ 277 struct rusage usage; 278 if (getrusage(RUSAGE_SELF, &usage) != 0) { 279 throw_internal_error(env, "getrusage failed"); 280 return -1; 281 } 282 jlong microsecs = 283 usage.ru_utime.tv_sec * 1000 * 1000 + usage.ru_utime.tv_usec + 284 usage.ru_stime.tv_sec * 1000 * 1000 + usage.ru_stime.tv_usec; 285 return microsecs * 1000; 286 #else 287 jlong clk_tck, ns_per_clock_tick; 288 jlong cpu_time_ns; 289 struct tms time; 290 291 /* 292 * BSDNOTE: FreeBSD implements _SC_CLK_TCK since FreeBSD 5, so 293 * add a magic to handle it 294 */ 295 #if defined(__solaris__) || defined(_SC_CLK_TCK) 296 clk_tck = (jlong) sysconf(_SC_CLK_TCK); 297 #elif defined(__linux__) || defined(_ALLBSD_SOURCE) 298 clk_tck = 100; 299 #endif 300 if (clk_tck == -1) { 301 throw_internal_error(env, 302 "sysconf failed - not able to get clock tick"); 303 return -1; 304 } 305 306 times(&time); 307 ns_per_clock_tick = (jlong) 1000 * 1000 * 1000 / (jlong) clk_tck; 308 cpu_time_ns = ((jlong)time.tms_utime + (jlong) time.tms_stime) * 309 ns_per_clock_tick; 310 return cpu_time_ns; 311 #endif 312 } 313 314 JNIEXPORT jlong JNICALL 315 Java_com_sun_management_internal_OperatingSystemImpl_getFreePhysicalMemorySize0 316 (JNIEnv *env, jobject mbean) 317 { 318 #ifdef __APPLE__ 319 mach_msg_type_number_t count; 320 vm_statistics_data_t vm_stats; 321 kern_return_t res; 322 323 count = HOST_VM_INFO_COUNT; 324 res = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vm_stats, &count); 325 if (res != KERN_SUCCESS) { 326 throw_internal_error(env, "host_statistics failed"); 327 return -1; 328 } 329 return (jlong)vm_stats.free_count * page_size; 330 #elif defined(_ALLBSD_SOURCE) 331 /* 332 * XXBSDL no way to do it in FreeBSD 333 */ 334 // throw_internal_error(env, "unimplemented in FreeBSD") 335 return (128 * MB); 336 #elif defined(_AIX) 337 perfstat_memory_total_t memory_info; 338 if (-1 != perfstat_memory_total(NULL, &memory_info, sizeof(perfstat_memory_total_t), 1)) { 339 return (jlong)(memory_info.real_free * 4L * 1024L); 340 } 341 return -1; 342 #else // solaris / linux 343 jlong num_avail_physical_pages = sysconf(_SC_AVPHYS_PAGES); 344 return (num_avail_physical_pages * page_size); 345 #endif 346 } 347 348 JNIEXPORT jlong JNICALL 349 Java_com_sun_management_internal_OperatingSystemImpl_getTotalPhysicalMemorySize0 350 (JNIEnv *env, jobject mbean) 351 { 352 #ifdef _ALLBSD_SOURCE 353 jlong result = 0; 354 int mib[2]; 355 size_t rlen; 356 357 mib[0] = CTL_HW; 358 mib[1] = HW_MEMSIZE; 359 rlen = sizeof(result); 360 if (sysctl(mib, 2, &result, &rlen, NULL, 0) != 0) { 361 throw_internal_error(env, "sysctl failed"); 362 return -1; 363 } 364 return result; 365 #elif defined(_AIX) 366 perfstat_memory_total_t memory_info; 367 if (-1 != perfstat_memory_total(NULL, &memory_info, sizeof(perfstat_memory_total_t), 1)) { 368 return (jlong)(memory_info.real_total * 4L * 1024L); 369 } 370 return -1; 371 #else // solaris / linux 372 jlong num_physical_pages = sysconf(_SC_PHYS_PAGES); 373 return (num_physical_pages * page_size); 374 #endif 375 } 376 377 378 379 JNIEXPORT jlong JNICALL 380 Java_com_sun_management_internal_OperatingSystemImpl_getOpenFileDescriptorCount0 381 (JNIEnv *env, jobject mbean) 382 { 383 #ifdef __APPLE__ 384 // This code is influenced by the darwin lsof source 385 pid_t my_pid; 386 struct proc_bsdinfo bsdinfo; 387 struct proc_fdinfo *fds; 388 int nfiles; 389 kern_return_t kres; 390 int res; 391 size_t fds_size; 392 393 kres = pid_for_task(mach_task_self(), &my_pid); 394 if (kres != KERN_SUCCESS) { 395 throw_internal_error(env, "pid_for_task failed"); 396 return -1; 397 } 398 399 // get the maximum number of file descriptors 400 res = proc_pidinfo(my_pid, PROC_PIDTBSDINFO, 0, &bsdinfo, PROC_PIDTBSDINFO_SIZE); 401 if (res <= 0) { 402 throw_internal_error(env, "proc_pidinfo with PROC_PIDTBSDINFO failed"); 403 return -1; 404 } 405 406 // allocate memory to hold the fd information (we don't acutally use this information 407 // but need it to get the number of open files) 408 fds_size = bsdinfo.pbi_nfiles * sizeof(struct proc_fdinfo); 409 fds = malloc(fds_size); 410 if (fds == NULL) { 411 JNU_ThrowOutOfMemoryError(env, "could not allocate space for file descriptors"); 412 return -1; 413 } 414 415 // get the list of open files - the return value is the number of bytes 416 // proc_pidinfo filled in 417 res = proc_pidinfo(my_pid, PROC_PIDLISTFDS, 0, fds, fds_size); 418 if (res <= 0) { 419 free(fds); 420 throw_internal_error(env, "proc_pidinfo failed for PROC_PIDLISTFDS"); 421 return -1; 422 } 423 nfiles = res / sizeof(struct proc_fdinfo); 424 free(fds); 425 426 return nfiles; 427 #elif defined(_ALLBSD_SOURCE) 428 /* 429 * XXXBSD: there's no way available to do it in FreeBSD, AFAIK. 430 */ 431 // throw_internal_error(env, "Unimplemented in FreeBSD"); 432 return (100); 433 #else /* solaris/linux */ 434 DIR *dirp; 435 struct dirent dbuf; 436 struct dirent* dentp; 437 jlong fds = 0; 438 439 #if defined(_AIX) 440 /* AIX does not understand '/proc/self' - it requires the real process ID */ 441 #define FD_DIR aix_fd_dir 442 char aix_fd_dir[32]; /* the pid has at most 19 digits */ 443 snprintf(aix_fd_dir, 32, "/proc/%d/fd", getpid()); 444 #else 445 #define FD_DIR "/proc/self/fd" 446 #endif 447 448 dirp = opendir(FD_DIR); 449 if (dirp == NULL) { 450 throw_internal_error(env, "Unable to open directory /proc/self/fd"); 451 return -1; 452 } 453 454 // iterate through directory entries, skipping '.' and '..' 455 // each entry represents an open file descriptor. 456 while ((dentp = read_dir(dirp, &dbuf)) != NULL) { 457 if (isdigit(dentp->d_name[0])) { 458 fds++; 459 } 460 } 461 462 closedir(dirp); 463 // subtract by 1 which was the fd open for this implementation 464 return (fds - 1); 465 #endif 466 } 467 468 JNIEXPORT jlong JNICALL 469 Java_com_sun_management_internal_OperatingSystemImpl_getMaxFileDescriptorCount0 470 (JNIEnv *env, jobject mbean) 471 { 472 struct rlimit rlp; 473 474 if (getrlimit(RLIMIT_NOFILE, &rlp) == -1) { 475 throw_internal_error(env, "getrlimit failed"); 476 return -1; 477 } 478 return (jlong) rlp.rlim_cur; 479 }