1 /* 2 * Copyright (c) 2003, 2020, 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 #if defined(_AIX) 78 #define DIR DIR64 79 #define dirent dirent64 80 #define opendir opendir64 81 #define readdir readdir64 82 #define closedir closedir64 83 #endif 84 85 // true = get available swap in bytes 86 // false = get total swap in bytes 87 static jlong get_total_or_available_swap_space_size(JNIEnv* env, jboolean available) { 88 #if defined(__linux__) 89 int ret; 90 FILE *fp; 91 jlong total = 0, avail = 0; 92 93 struct sysinfo si; 94 ret = sysinfo(&si); 95 if (ret != 0) { 96 throw_internal_error(env, "sysinfo failed to get swap size"); 97 } 98 total = (jlong)si.totalswap * si.mem_unit; 99 avail = (jlong)si.freeswap * si.mem_unit; 100 101 return available ? avail : total; 102 #elif defined(__APPLE__) 103 struct xsw_usage vmusage; 104 size_t size = sizeof(vmusage); 105 if (sysctlbyname("vm.swapusage", &vmusage, &size, NULL, 0) != 0) { 106 throw_internal_error(env, "sysctlbyname failed"); 107 } 108 return available ? (jlong)vmusage.xsu_avail : (jlong)vmusage.xsu_total; 109 #else /* _ALLBSD_SOURCE */ 110 /* 111 * XXXBSD: there's no way available to get swap info in 112 * FreeBSD. Usage of libkvm is not an option here 113 */ 114 // throw_internal_error(env, "Unimplemented in FreeBSD"); 115 return (0); 116 #endif 117 } 118 119 JNIEXPORT void JNICALL 120 Java_com_sun_management_internal_OperatingSystemImpl_initialize0 121 (JNIEnv *env, jclass cls) 122 { 123 page_size = sysconf(_SC_PAGESIZE); 124 } 125 126 JNIEXPORT jlong JNICALL 127 Java_com_sun_management_internal_OperatingSystemImpl_getCommittedVirtualMemorySize0 128 (JNIEnv *env, jobject mbean) 129 { 130 #if defined(__linux__) 131 FILE *fp; 132 unsigned long vsize = 0; 133 134 if ((fp = fopen("/proc/self/stat", "r")) == NULL) { 135 throw_internal_error(env, "Unable to open /proc/self/stat"); 136 return -1; 137 } 138 139 // Ignore everything except the vsize entry 140 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) { 141 throw_internal_error(env, "Unable to get virtual memory usage"); 142 fclose(fp); 143 return -1; 144 } 145 146 fclose(fp); 147 return (jlong)vsize; 148 #elif defined(__APPLE__) 149 struct task_basic_info t_info; 150 mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; 151 152 kern_return_t res = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count); 153 if (res != KERN_SUCCESS) { 154 throw_internal_error(env, "task_info failed"); 155 } 156 return t_info.virtual_size; 157 #else /* _ALLBSD_SOURCE */ 158 /* 159 * XXXBSD: there's no way available to do it in FreeBSD, AFAIK. 160 */ 161 // throw_internal_error(env, "Unimplemented in FreeBSD"); 162 return (64 * MB); 163 #endif 164 } 165 166 JNIEXPORT jlong JNICALL 167 Java_com_sun_management_internal_OperatingSystemImpl_getTotalSwapSpaceSize0 168 (JNIEnv *env, jobject mbean) 169 { 170 return get_total_or_available_swap_space_size(env, JNI_FALSE); 171 } 172 173 JNIEXPORT jlong JNICALL 174 Java_com_sun_management_internal_OperatingSystemImpl_getFreeSwapSpaceSize0 175 (JNIEnv *env, jobject mbean) 176 { 177 return get_total_or_available_swap_space_size(env, JNI_TRUE); 178 } 179 180 JNIEXPORT jlong JNICALL 181 Java_com_sun_management_internal_OperatingSystemImpl_getProcessCpuTime0 182 (JNIEnv *env, jobject mbean) 183 { 184 #ifdef __APPLE__ 185 struct rusage usage; 186 if (getrusage(RUSAGE_SELF, &usage) != 0) { 187 throw_internal_error(env, "getrusage failed"); 188 return -1; 189 } 190 jlong microsecs = 191 usage.ru_utime.tv_sec * 1000 * 1000 + usage.ru_utime.tv_usec + 192 usage.ru_stime.tv_sec * 1000 * 1000 + usage.ru_stime.tv_usec; 193 return microsecs * 1000; 194 #else 195 jlong clk_tck, ns_per_clock_tick; 196 jlong cpu_time_ns; 197 struct tms time; 198 199 /* 200 * BSDNOTE: FreeBSD implements _SC_CLK_TCK since FreeBSD 5, so 201 * add a magic to handle it 202 */ 203 #if defined(_SC_CLK_TCK) 204 clk_tck = (jlong) sysconf(_SC_CLK_TCK); 205 #elif defined(__linux__) || defined(_ALLBSD_SOURCE) 206 clk_tck = 100; 207 #endif 208 if (clk_tck == -1) { 209 throw_internal_error(env, 210 "sysconf failed - not able to get clock tick"); 211 return -1; 212 } 213 214 times(&time); 215 ns_per_clock_tick = (jlong) 1000 * 1000 * 1000 / (jlong) clk_tck; 216 cpu_time_ns = ((jlong)time.tms_utime + (jlong) time.tms_stime) * 217 ns_per_clock_tick; 218 return cpu_time_ns; 219 #endif 220 } 221 222 JNIEXPORT jlong JNICALL 223 Java_com_sun_management_internal_OperatingSystemImpl_getFreeMemorySize0 224 (JNIEnv *env, jobject mbean) 225 { 226 #ifdef __APPLE__ 227 mach_msg_type_number_t count; 228 vm_statistics_data_t vm_stats; 229 kern_return_t res; 230 231 count = HOST_VM_INFO_COUNT; 232 res = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vm_stats, &count); 233 if (res != KERN_SUCCESS) { 234 throw_internal_error(env, "host_statistics failed"); 235 return -1; 236 } 237 return (jlong)vm_stats.free_count * page_size; 238 #elif defined(_ALLBSD_SOURCE) 239 /* 240 * XXBSDL no way to do it in FreeBSD 241 */ 242 // throw_internal_error(env, "unimplemented in FreeBSD") 243 return (128 * MB); 244 #elif defined(_AIX) 245 perfstat_memory_total_t memory_info; 246 if (-1 != perfstat_memory_total(NULL, &memory_info, sizeof(perfstat_memory_total_t), 1)) { 247 return (jlong)(memory_info.real_free * 4L * 1024L); 248 } 249 return -1; 250 #else // solaris / linux 251 jlong num_avail_physical_pages = sysconf(_SC_AVPHYS_PAGES); 252 return (num_avail_physical_pages * page_size); 253 #endif 254 } 255 256 JNIEXPORT jlong JNICALL 257 Java_com_sun_management_internal_OperatingSystemImpl_getTotalMemorySize0 258 (JNIEnv *env, jobject mbean) 259 { 260 #ifdef _ALLBSD_SOURCE 261 jlong result = 0; 262 int mib[2]; 263 size_t rlen; 264 265 mib[0] = CTL_HW; 266 mib[1] = HW_MEMSIZE; 267 rlen = sizeof(result); 268 if (sysctl(mib, 2, &result, &rlen, NULL, 0) != 0) { 269 throw_internal_error(env, "sysctl failed"); 270 return -1; 271 } 272 return result; 273 #elif defined(_AIX) 274 perfstat_memory_total_t memory_info; 275 if (-1 != perfstat_memory_total(NULL, &memory_info, sizeof(perfstat_memory_total_t), 1)) { 276 return (jlong)(memory_info.real_total * 4L * 1024L); 277 } 278 return -1; 279 #else // solaris / linux 280 jlong num_physical_pages = sysconf(_SC_PHYS_PAGES); 281 return (num_physical_pages * page_size); 282 #endif 283 } 284 285 286 287 JNIEXPORT jlong JNICALL 288 Java_com_sun_management_internal_OperatingSystemImpl_getOpenFileDescriptorCount0 289 (JNIEnv *env, jobject mbean) 290 { 291 #ifdef __APPLE__ 292 // This code is influenced by the darwin lsof source 293 pid_t my_pid; 294 struct proc_bsdinfo bsdinfo; 295 struct proc_fdinfo *fds; 296 int nfiles; 297 kern_return_t kres; 298 int res; 299 size_t fds_size; 300 301 kres = pid_for_task(mach_task_self(), &my_pid); 302 if (kres != KERN_SUCCESS) { 303 throw_internal_error(env, "pid_for_task failed"); 304 return -1; 305 } 306 307 // get the maximum number of file descriptors 308 res = proc_pidinfo(my_pid, PROC_PIDTBSDINFO, 0, &bsdinfo, PROC_PIDTBSDINFO_SIZE); 309 if (res <= 0) { 310 throw_internal_error(env, "proc_pidinfo with PROC_PIDTBSDINFO failed"); 311 return -1; 312 } 313 314 // allocate memory to hold the fd information (we don't acutally use this information 315 // but need it to get the number of open files) 316 fds_size = bsdinfo.pbi_nfiles * sizeof(struct proc_fdinfo); 317 fds = malloc(fds_size); 318 if (fds == NULL) { 319 JNU_ThrowOutOfMemoryError(env, "could not allocate space for file descriptors"); 320 return -1; 321 } 322 323 // get the list of open files - the return value is the number of bytes 324 // proc_pidinfo filled in 325 res = proc_pidinfo(my_pid, PROC_PIDLISTFDS, 0, fds, fds_size); 326 if (res <= 0) { 327 free(fds); 328 throw_internal_error(env, "proc_pidinfo failed for PROC_PIDLISTFDS"); 329 return -1; 330 } 331 nfiles = res / sizeof(struct proc_fdinfo); 332 free(fds); 333 334 return nfiles; 335 #elif defined(_ALLBSD_SOURCE) 336 /* 337 * XXXBSD: there's no way available to do it in FreeBSD, AFAIK. 338 */ 339 // throw_internal_error(env, "Unimplemented in FreeBSD"); 340 return (100); 341 #else /* solaris/linux */ 342 DIR *dirp; 343 struct dirent* dentp; 344 jlong fds = 0; 345 346 #if defined(_AIX) 347 /* AIX does not understand '/proc/self' - it requires the real process ID */ 348 #define FD_DIR aix_fd_dir 349 char aix_fd_dir[32]; /* the pid has at most 19 digits */ 350 snprintf(aix_fd_dir, 32, "/proc/%d/fd", getpid()); 351 #else 352 #define FD_DIR "/proc/self/fd" 353 #endif 354 355 dirp = opendir(FD_DIR); 356 if (dirp == NULL) { 357 throw_internal_error(env, "Unable to open directory /proc/self/fd"); 358 return -1; 359 } 360 361 // iterate through directory entries, skipping '.' and '..' 362 // each entry represents an open file descriptor. 363 while ((dentp = readdir(dirp)) != NULL) { 364 if (isdigit(dentp->d_name[0])) { 365 fds++; 366 } 367 } 368 369 closedir(dirp); 370 // subtract by 1 which was the fd open for this implementation 371 return (fds - 1); 372 #endif 373 } 374 375 JNIEXPORT jlong JNICALL 376 Java_com_sun_management_internal_OperatingSystemImpl_getMaxFileDescriptorCount0 377 (JNIEnv *env, jobject mbean) 378 { 379 struct rlimit rlp; 380 381 if (getrlimit(RLIMIT_NOFILE, &rlp) == -1) { 382 throw_internal_error(env, "getrlimit failed"); 383 return -1; 384 } 385 return (jlong) rlp.rlim_cur; 386 }