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