perfMemory_solaris.cpp revision 7331:110ec5963eb1
118334Speter/* 290087Sobrien * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. 3169699Skan * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4169699Skan * 518334Speter * This code is free software; you can redistribute it and/or modify it 690087Sobrien * under the terms of the GNU General Public License version 2 only, as 718334Speter * published by the Free Software Foundation. 890087Sobrien * 990087Sobrien * This code is distributed in the hope that it will be useful, but WITHOUT 1090087Sobrien * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1190087Sobrien * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1218334Speter * version 2 for more details (a copy is included in the LICENSE file that 1390087Sobrien * accompanied this code). 1490087Sobrien * 1590087Sobrien * You should have received a copy of the GNU General Public License version 1690087Sobrien * 2 along with this work; if not, write to the Free Software Foundation, 1718334Speter * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1818334Speter * 1990087Sobrien * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20169699Skan * or visit www.oracle.com if you need additional information or have any 21169699Skan * questions. 2218334Speter * 2318334Speter */ 2418334Speter 2518334Speter#include "precompiled.hpp" 2618334Speter#include "classfile/vmSymbols.hpp" 2718334Speter#include "memory/allocation.inline.hpp" 2818334Speter#include "memory/resourceArea.hpp" 2918334Speter#include "oops/oop.inline.hpp" 3018334Speter#include "os_solaris.inline.hpp" 3118334Speter#include "runtime/handles.inline.hpp" 3218334Speter#include "runtime/perfMemory.hpp" 3318334Speter#include "services/memTracker.hpp" 3418334Speter#include "utilities/exceptions.hpp" 3518334Speter 3618334Speter// put OS-includes here 3718334Speter# include <sys/types.h> 3818334Speter# include <sys/mman.h> 3918334Speter# include <errno.h> 4018334Speter# include <stdio.h> 4118334Speter# include <unistd.h> 4218334Speter# include <sys/stat.h> 4318334Speter# include <signal.h> 4418334Speter# include <pwd.h> 4590087Sobrien# include <procfs.h> 4690087Sobrien 4718334Speter 4818334Speterstatic char* backing_store_file_name = NULL; // name of the backing store 4950503Sobrien // file, if successfully created. 50132727Skan 51132727Skan// Standard Memory Implementation Details 5218334Speter 5318334Speter// create the PerfData memory region in standard memory. 5418334Speter// 5590087Sobrienstatic char* create_standard_memory(size_t size) { 5618334Speter 5718334Speter // allocate an aligned chuck of memory 5818334Speter char* mapAddress = os::reserve_memory(size); 5918334Speter 6018334Speter if (mapAddress == NULL) { 6118334Speter return NULL; 6218334Speter } 6318334Speter 6418334Speter // commit memory 6550503Sobrien if (!os::commit_memory(mapAddress, size, !ExecMem)) { 6690087Sobrien if (PrintMiscellaneous && Verbose) { 6750503Sobrien warning("Could not commit PerfData memory\n"); 6850503Sobrien } 6952515Sobrien os::release_memory(mapAddress, size); 7090087Sobrien return NULL; 7190087Sobrien } 7290087Sobrien 7390087Sobrien return mapAddress; 74117404Skan} 75169699Skan 76169699Skan// delete the PerfData memory region 77169699Skan// 78169699Skanstatic void delete_standard_memory(char* addr, size_t size) { 7918334Speter 8018334Speter // there are no persistent external resources to cleanup for standard 8190087Sobrien // memory. since DestroyJavaVM does not support unloading of the JVM, 8290087Sobrien // cleanup of the memory resource is not performed. The memory will be 8318334Speter // reclaimed by the OS upon termination of the process. 8418334Speter // 8550503Sobrien return; 8650503Sobrien} 8750503Sobrien 8850503Sobrien// save the specified memory region to the given file 89132727Skan// 90132727Skan// Note: this function might be called from signal handler (by os::abort()), 91132727Skan// don't allocate heap memory. 92132727Skan// 93169699Skanstatic void save_memory_to_file(char* addr, size_t size) { 94169699Skan 95169699Skan const char* destfile = PerfMemory::get_perfdata_file_path(); 96169699Skan assert(destfile[0] != '\0', "invalid PerfData file path"); 9718334Speter 9818334Speter int result; 9918334Speter 10018334Speter RESTARTABLE(::open(destfile, O_CREAT|O_WRONLY|O_TRUNC, S_IREAD|S_IWRITE), 10118334Speter result);; 10218334Speter if (result == OS_ERR) { 10318334Speter if (PrintMiscellaneous && Verbose) { 10418334Speter warning("Could not create Perfdata save file: %s: %s\n", 10518334Speter destfile, strerror(errno)); 10618334Speter } 10718334Speter } else { 10818334Speter 10918334Speter int fd = result; 11018334Speter 11118334Speter for (size_t remaining = size; remaining > 0;) { 11218334Speter 11350503Sobrien RESTARTABLE(::write(fd, addr, remaining), result); 11450503Sobrien if (result == OS_ERR) { 11550503Sobrien if (PrintMiscellaneous && Verbose) { 11650503Sobrien warning("Could not write Perfdata save file: %s: %s\n", 117132727Skan destfile, strerror(errno)); 118132727Skan } 119132727Skan break; 120132727Skan } 121132727Skan remaining -= (size_t)result; 12218334Speter addr += result; 12390087Sobrien } 12490087Sobrien 12518334Speter result = ::close(fd); 12618334Speter if (PrintMiscellaneous && Verbose) { 12718334Speter if (result == OS_ERR) { 12818334Speter warning("Could not close %s: %s\n", destfile, strerror(errno)); 12918334Speter } 13018334Speter } 13118334Speter } 13218334Speter FREE_C_HEAP_ARRAY(char, destfile, mtInternal); 13318334Speter} 13418334Speter 13518334Speter 13690087Sobrien// Shared Memory Implementation Details 13718334Speter 138169699Skan// Note: the solaris and linux shared memory implementation uses the mmap 139169699Skan// interface with a backing store file to implement named shared memory. 14050503Sobrien// Using the file system as the name space for shared memory allows a 141169699Skan// common name space to be supported across a variety of platforms. It 142169699Skan// also provides a name space that Java applications can deal with through 14318334Speter// simple file apis. 144169699Skan// 14518334Speter// The solaris and linux implementations store the backing store file in 146117404Skan// a user specific temporary directory located in the /tmp file system, 14718334Speter// which is always a local file system and is sometimes a RAM based file 14818334Speter// system. 14950503Sobrien 15018334Speter// return the user specific temporary directory name. 15118334Speter// 15218334Speter// the caller is expected to free the allocated memory. 15318334Speter// 15418334Speterstatic char* get_user_tmp_dir(const char* user) { 15518334Speter 15618334Speter const char* tmpdir = os::get_temp_directory(); 15718334Speter const char* perfdir = PERFDATA_NAME; 15818334Speter size_t nbytes = strlen(tmpdir) + strlen(perfdir) + strlen(user) + 3; 15918334Speter char* dirname = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); 16018334Speter 16118334Speter // construct the path name to user specific tmp directory 16218334Speter snprintf(dirname, nbytes, "%s/%s_%s", tmpdir, perfdir, user); 16318334Speter 16418334Speter return dirname; 16518334Speter} 16618334Speter 16718334Speter// convert the given file name into a process id. if the file 16818334Speter// does not meet the file naming constraints, return 0. 16918334Speter// 17018334Speterstatic pid_t filename_to_pid(const char* filename) { 17118334Speter 17218334Speter // a filename that doesn't begin with a digit is not a 17318334Speter // candidate for conversion. 17418334Speter // 17518334Speter if (!isdigit(*filename)) { 17618334Speter return 0; 17718334Speter } 17818334Speter 17918334Speter // check if file name can be converted to an integer without 18018334Speter // any leftover characters. 18118334Speter // 18218334Speter char* remainder = NULL; 18318334Speter errno = 0; 184132727Skan pid_t pid = (pid_t)strtol(filename, &remainder, 10); 185132727Skan 186132727Skan if (errno != 0) { 187132727Skan return 0; 188132727Skan } 189132727Skan 19018334Speter // check for left over characters. If any, then the filename is 191132727Skan // not a candidate for conversion. 192132727Skan // 19318334Speter if (remainder != NULL && *remainder != '\0') { 19418334Speter return 0; 19518334Speter } 19690087Sobrien 19718334Speter // successful conversion, return the pid 19818334Speter return pid; 19918334Speter} 20018334Speter 20118334Speter 20218334Speter// check if the given path is considered a secure directory for 20318334Speter// the backing store files. Returns true if the directory exists 20418334Speter// and is considered a secure location. Returns false if the path 20518334Speter// is a symbolic link or if an error occurred. 20618334Speter// 20718334Speterstatic bool is_directory_secure(const char* path) { 20818334Speter struct stat statbuf; 20918334Speter int result = 0; 21018334Speter 21118334Speter RESTARTABLE(::lstat(path, &statbuf), result); 21218334Speter if (result == OS_ERR) { 21318334Speter return false; 21418334Speter } 21590087Sobrien 21690087Sobrien // the path exists, now check it's mode 21790087Sobrien if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) { 21890087Sobrien // the path represents a link or some non-directory file type, 21918334Speter // which is not what we expected. declare it insecure. 22050503Sobrien // 221132727Skan return false; 22250503Sobrien } 223132727Skan else { 224132727Skan // we have an existing directory, check if the permissions are safe. 225132727Skan // 226132727Skan if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) { 227132727Skan // the directory is open for writing and could be subjected 228132727Skan // to a symlnk attack. declare it insecure. 229132727Skan // 230132727Skan return false; 231132727Skan } 23250503Sobrien } 233132727Skan return true; 23450503Sobrien} 23550503Sobrien 236132727Skan 23750503Sobrien// return the user name for the given user id 23890087Sobrien// 239132727Skan// the caller is expected to free the allocated memory. 24090087Sobrien// 24190087Sobrienstatic char* get_user_name(uid_t uid) { 242132727Skan 24390087Sobrien struct passwd pwent; 24418334Speter 24518334Speter // determine the max pwbuf size from sysconf, and hardcode 24618334Speter // a default if this not available through sysconf. 24718334Speter // 248132727Skan long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); 24918334Speter if (bufsize == -1) 25018334Speter bufsize = 1024; 25118334Speter 25218334Speter char* pwbuf = NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); 25318334Speter 25418334Speter#ifdef _GNU_SOURCE 25518334Speter struct passwd* p = NULL; 25618334Speter int result = getpwuid_r(uid, &pwent, pwbuf, (size_t)bufsize, &p); 25718334Speter#else // _GNU_SOURCE 25890087Sobrien struct passwd* p = getpwuid_r(uid, &pwent, pwbuf, (int)bufsize); 25918334Speter#endif // _GNU_SOURCE 26090087Sobrien 26190087Sobrien if (p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') { 26290087Sobrien if (PrintMiscellaneous && Verbose) { 263132727Skan if (p == NULL) { 264132727Skan warning("Could not retrieve passwd entry: %s\n", 26590087Sobrien strerror(errno)); 26690087Sobrien } 26718334Speter else { 26890087Sobrien warning("Could not determine user name: %s\n", 26990087Sobrien p->pw_name == NULL ? "pw_name = NULL" : 270132727Skan "pw_name zero length"); 27190087Sobrien } 27218334Speter } 27318334Speter FREE_C_HEAP_ARRAY(char, pwbuf, mtInternal); 27418334Speter return NULL; 27518334Speter } 27618334Speter 27718334Speter char* user_name = NEW_C_HEAP_ARRAY(char, strlen(p->pw_name) + 1, mtInternal); 278132727Skan strcpy(user_name, p->pw_name); 27918334Speter 28018334Speter FREE_C_HEAP_ARRAY(char, pwbuf, mtInternal); 28118334Speter return user_name; 28250503Sobrien} 28318334Speter 28418334Speter// return the name of the user that owns the process identified by vmid. 28518334Speter// 28618334Speter// This method uses a slow directory search algorithm to find the backing 28718334Speter// store file for the specified vmid and returns the user name, as determined 28818334Speter// by the user name suffix of the hsperfdata_<username> directory name. 28918334Speter// 29018334Speter// the caller is expected to free the allocated memory. 291132727Skan// 29218334Speterstatic char* get_user_name_slow(int vmid, TRAPS) { 29318334Speter 29418334Speter // short circuit the directory search if the process doesn't even exist. 29550503Sobrien if (kill(vmid, 0) == OS_ERR) { 29618334Speter if (errno == ESRCH) { 29718334Speter THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), 29818334Speter "Process not found"); 29918334Speter } 30090087Sobrien else /* EPERM */ { 30118334Speter THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno)); 30218334Speter } 30318334Speter } 30418334Speter 30518334Speter // directory search 306132727Skan char* oldest_user = NULL; 30718334Speter time_t oldest_ctime = 0; 30818334Speter 30918334Speter const char* tmpdirname = os::get_temp_directory(); 31018334Speter 31118334Speter DIR* tmpdirp = os::opendir(tmpdirname); 31218334Speter 31318334Speter if (tmpdirp == NULL) { 31418334Speter return NULL; 31518334Speter } 31618334Speter 31718334Speter // for each entry in the directory that matches the pattern hsperfdata_*, 31818334Speter // open the directory and check if the file for the given vmid exists. 31918334Speter // The file with the expected name and the latest creation date is used 32018334Speter // to determine the user name for the process id. 32190087Sobrien // 32218334Speter struct dirent* dentry; 32390087Sobrien char* tdbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(tmpdirname), mtInternal); 32490087Sobrien errno = 0; 32552515Sobrien while ((dentry = os::readdir(tmpdirp, (struct dirent *)tdbuf)) != NULL) { 32652515Sobrien 32752515Sobrien // check if the directory entry is a hsperfdata file 32818334Speter if (strncmp(dentry->d_name, PERFDATA_NAME, strlen(PERFDATA_NAME)) != 0) { 32918334Speter continue; 33018334Speter } 33150503Sobrien 33250503Sobrien char* usrdir_name = NEW_C_HEAP_ARRAY(char, 33350503Sobrien strlen(tmpdirname) + strlen(dentry->d_name) + 2, mtInternal); 33490087Sobrien strcpy(usrdir_name, tmpdirname); 33550503Sobrien strcat(usrdir_name, "/"); 33650503Sobrien strcat(usrdir_name, dentry->d_name); 33750503Sobrien 33850503Sobrien DIR* subdirp = os::opendir(usrdir_name); 33950503Sobrien 34050503Sobrien if (subdirp == NULL) { 34150503Sobrien FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal); 34250503Sobrien continue; 34350503Sobrien } 34450503Sobrien 34550503Sobrien // Since we don't create the backing store files in directories 346260918Spfg // pointed to by symbolic links, we also don't follow them when 347260918Spfg // looking for the files. We check for a symbolic link after the 34850503Sobrien // call to opendir in order to eliminate a small window where the 34950503Sobrien // symlink can be exploited. 350260918Spfg // 35150503Sobrien if (!is_directory_secure(usrdir_name)) { 352260918Spfg FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal); 353260918Spfg os::closedir(subdirp); 35418334Speter continue; 35518334Speter } 35618334Speter 357132727Skan struct dirent* udentry; 35818334Speter char* udbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(usrdir_name), mtInternal); 35950503Sobrien errno = 0; 36050503Sobrien while ((udentry = os::readdir(subdirp, (struct dirent *)udbuf)) != NULL) { 36150503Sobrien 36250503Sobrien if (filename_to_pid(udentry->d_name) == vmid) { 36350503Sobrien struct stat statbuf; 36450503Sobrien int result; 36550503Sobrien 36650503Sobrien char* filename = NEW_C_HEAP_ARRAY(char, 36750503Sobrien strlen(usrdir_name) + strlen(udentry->d_name) + 2, mtInternal); 36852515Sobrien 36950503Sobrien strcpy(filename, usrdir_name); 37090087Sobrien strcat(filename, "/"); 37190087Sobrien strcat(filename, udentry->d_name); 37290087Sobrien 37350503Sobrien // don't follow symbolic links for the file 37450503Sobrien RESTARTABLE(::lstat(filename, &statbuf), result); 37550503Sobrien if (result == OS_ERR) { 37650503Sobrien FREE_C_HEAP_ARRAY(char, filename, mtInternal); 37750503Sobrien continue; 37818334Speter } 37918334Speter 38018334Speter // skip over files that are not regular files. 381169699Skan if (!S_ISREG(statbuf.st_mode)) { 382169699Skan FREE_C_HEAP_ARRAY(char, filename, mtInternal); 383169699Skan continue; 384169699Skan } 385169699Skan 38618334Speter // compare and save filename with latest creation time 38718334Speter if (statbuf.st_size > 0 && statbuf.st_ctime > oldest_ctime) { 38818334Speter 38918334Speter if (statbuf.st_ctime > oldest_ctime) { 39018334Speter char* user = strchr(dentry->d_name, '_') + 1; 39118334Speter 39252515Sobrien if (oldest_user != NULL) FREE_C_HEAP_ARRAY(char, oldest_user, mtInternal); 39318334Speter oldest_user = NEW_C_HEAP_ARRAY(char, strlen(user)+1, mtInternal); 39418334Speter 39518334Speter strcpy(oldest_user, user); 39618334Speter oldest_ctime = statbuf.st_ctime; 39718334Speter } 39818334Speter } 39918334Speter 40018334Speter FREE_C_HEAP_ARRAY(char, filename, mtInternal); 40118334Speter } 40218334Speter } 403169699Skan os::closedir(subdirp); 40418334Speter FREE_C_HEAP_ARRAY(char, udbuf, mtInternal); 40518334Speter FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal); 40618334Speter } 40718334Speter os::closedir(tmpdirp); 408117404Skan FREE_C_HEAP_ARRAY(char, tdbuf, mtInternal); 40918334Speter 41050503Sobrien return(oldest_user); 41150503Sobrien} 41218334Speter 41318334Speter// return the name of the user that owns the JVM indicated by the given vmid. 414169699Skan// 41518334Speterstatic char* get_user_name(int vmid, TRAPS) { 41618334Speter 41718334Speter char psinfo_name[PATH_MAX]; 41818334Speter int result; 41918334Speter 42018334Speter snprintf(psinfo_name, PATH_MAX, "/proc/%d/psinfo", vmid); 42118334Speter 42218334Speter RESTARTABLE(::open(psinfo_name, O_RDONLY), result); 423169699Skan 42418334Speter if (result != OS_ERR) { 42518334Speter int fd = result; 42618334Speter 42718334Speter psinfo_t psinfo; 428169699Skan char* addr = (char*)&psinfo; 42950503Sobrien 43050503Sobrien for (size_t remaining = sizeof(psinfo_t); remaining > 0;) { 43150503Sobrien 43250503Sobrien RESTARTABLE(::read(fd, addr, remaining), result); 43318334Speter if (result == OS_ERR) { 43418334Speter ::close(fd); 43518334Speter THROW_MSG_0(vmSymbols::java_io_IOException(), "Read error"); 43618334Speter } else { 43718334Speter remaining-=result; 43818334Speter addr+=result; 43918334Speter } 44018334Speter } 441169699Skan 442169699Skan ::close(fd); 44318334Speter 44418334Speter // get the user name for the effective user id of the process 445169699Skan char* user_name = get_user_name(psinfo.pr_euid); 446169699Skan 447169699Skan return user_name; 448169699Skan } 449169699Skan 450169699Skan if (result == OS_ERR && errno == EACCES) { 451169699Skan 452169699Skan // In this case, the psinfo file for the process id existed, 453169699Skan // but we didn't have permission to access it. 454169699Skan THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), 455169699Skan strerror(errno)); 456169699Skan } 457169699Skan 458169699Skan // at this point, we don't know if the process id itself doesn't 459169699Skan // exist or if the psinfo file doesn't exit. If the psinfo file 460169699Skan // doesn't exist, then we are running on Solaris 2.5.1 or earlier. 46118334Speter // since the structured procfs and old procfs interfaces can't be 46250503Sobrien // mixed, we attempt to find the file through a directory search. 46350503Sobrien 46450503Sobrien return get_user_name_slow(vmid, CHECK_NULL); 46550503Sobrien} 46650503Sobrien 46750503Sobrien// return the file name of the backing store file for the named 46850503Sobrien// shared memory region for the given user name and vmid. 46990087Sobrien// 47050503Sobrien// the caller is expected to free the allocated memory. 47190087Sobrien// 47250503Sobrienstatic char* get_sharedmem_filename(const char* dirname, int vmid) { 47350503Sobrien 47450503Sobrien // add 2 for the file separator and a NULL terminator. 47590087Sobrien size_t nbytes = strlen(dirname) + UINT_CHARS + 2; 47650503Sobrien 47750503Sobrien char* name = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); 47890087Sobrien snprintf(name, nbytes, "%s/%d", dirname, vmid); 47950503Sobrien 48050503Sobrien return name; 48190087Sobrien} 48250503Sobrien 48390087Sobrien 48450503Sobrien// remove file 48590087Sobrien// 48650503Sobrien// this method removes the file specified by the given path 48750503Sobrien// 48850503Sobrienstatic void remove_file(const char* path) { 48950503Sobrien 49090087Sobrien int result; 49150503Sobrien 49250503Sobrien // if the file is a directory, the following unlink will fail. since 49390087Sobrien // we don't expect to find directories in the user temp directory, we 49450503Sobrien // won't try to handle this situation. even if accidentially or 49550503Sobrien // maliciously planted, the directory's presence won't hurt anything. 49690087Sobrien // 49750503Sobrien RESTARTABLE(::unlink(path), result); 49850503Sobrien if (PrintMiscellaneous && Verbose && result == OS_ERR) { 49950503Sobrien if (errno != ENOENT) { 50050503Sobrien warning("Could not unlink shared memory backing" 50150503Sobrien " store file %s : %s\n", path, strerror(errno)); 50250503Sobrien } 50350503Sobrien } 50490087Sobrien} 50550503Sobrien 50650503Sobrien 50750503Sobrien// remove file 50890087Sobrien// 50950503Sobrien// this method removes the file with the given file name in the 51050503Sobrien// named directory. 51150503Sobrien// 51290087Sobrienstatic void remove_file(const char* dirname, const char* filename) { 51350503Sobrien 51450503Sobrien size_t nbytes = strlen(dirname) + strlen(filename) + 2; 51550503Sobrien char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); 51690087Sobrien 51750503Sobrien strcpy(path, dirname); 51850503Sobrien strcat(path, "/"); 51950503Sobrien strcat(path, filename); 52050503Sobrien 52150503Sobrien remove_file(path); 52250503Sobrien 52350503Sobrien FREE_C_HEAP_ARRAY(char, path, mtInternal); 52450503Sobrien} 52550503Sobrien 52650503Sobrien 52790087Sobrien// cleanup stale shared memory resources 52890087Sobrien// 52990087Sobrien// This method attempts to remove all stale shared memory files in 53090087Sobrien// the named user temporary directory. It scans the named directory 53190087Sobrien// for files matching the pattern ^$[0-9]*$. For each file found, the 53290087Sobrien// process id is extracted from the file name and a test is run to 53390087Sobrien// determine if the process is alive. If the process is not alive, 53490087Sobrien// any stale file resources are removed. 53550503Sobrien// 53690087Sobrienstatic void cleanup_sharedmem_resources(const char* dirname) { 537132727Skan 53850503Sobrien // open the user temp directory 53990087Sobrien DIR* dirp = os::opendir(dirname); 54050503Sobrien 54150503Sobrien if (dirp == NULL) { 54250503Sobrien // directory doesn't exist, so there is nothing to cleanup 54390087Sobrien return; 54450503Sobrien } 54550503Sobrien 54690087Sobrien if (!is_directory_secure(dirname)) { 54750503Sobrien // the directory is not a secure directory 54850503Sobrien os::closedir(dirp); 54950503Sobrien return; 55050503Sobrien } 55150503Sobrien 55250503Sobrien // for each entry in the directory that matches the expected file 55350503Sobrien // name pattern, determine if the file resources are stale and if 55450503Sobrien // so, remove the file resources. Note, instrumented HotSpot processes 55550503Sobrien // for this user may start and/or terminate during this search and 556260918Spfg // remove or create new files in this directory. The behavior of this 557260918Spfg // loop under these conditions is dependent upon the implementation of 55850503Sobrien // opendir/readdir. 55990087Sobrien // 56050503Sobrien struct dirent* entry; 561132727Skan char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal); 56250503Sobrien errno = 0; 563260918Spfg while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) { 564260918Spfg 565260918Spfg pid_t pid = filename_to_pid(entry->d_name); 56650503Sobrien 56750503Sobrien if (pid == 0) { 56850503Sobrien 56950503Sobrien if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { 57050503Sobrien 57150503Sobrien // attempt to remove all unexpected files, except "." and ".." 57250503Sobrien remove_file(dirname, entry->d_name); 57350503Sobrien } 57450503Sobrien 57550503Sobrien errno = 0; 57650503Sobrien continue; 57750503Sobrien } 57850503Sobrien 57950503Sobrien // we now have a file name that converts to a valid integer 58050503Sobrien // that could represent a process id . if this process id 58150503Sobrien // matches the current process id or the process is not running, 58250503Sobrien // then remove the stale file resources. 58350503Sobrien // 58450503Sobrien // process liveness is detected by sending signal number 0 to 58550503Sobrien // the process id (see kill(2)). if kill determines that the 58690087Sobrien // process does not exist, then the file resources are removed. 58750503Sobrien // if kill determines that that we don't have permission to 58850503Sobrien // signal the process, then the file resources are assumed to 58950503Sobrien // be stale and are removed because the resources for such a 59050503Sobrien // process should be in a different user specific directory. 59150503Sobrien // 59250503Sobrien if ((pid == os::current_process_id()) || 59350503Sobrien (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) { 59450503Sobrien 59550503Sobrien remove_file(dirname, entry->d_name); 59690087Sobrien } 59790087Sobrien errno = 0; 598132727Skan } 59950503Sobrien os::closedir(dirp); 60050503Sobrien FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); 60150503Sobrien} 60250503Sobrien 60350503Sobrien// make the user specific temporary directory. Returns true if 60450503Sobrien// the directory exists and is secure upon return. Returns false 60550503Sobrien// if the directory exists but is either a symlink, is otherwise 60650503Sobrien// insecure, or if an error occurred. 60750503Sobrien// 60850503Sobrienstatic bool make_user_tmp_dir(const char* dirname) { 60950503Sobrien 61050503Sobrien // create the directory with 0755 permissions. note that the directory 61190087Sobrien // will be owned by euid::egid, which may not be the same as uid::gid. 61250503Sobrien // 61350503Sobrien if (mkdir(dirname, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) == OS_ERR) { 614260918Spfg if (errno == EEXIST) { 615260918Spfg // The directory already exists and was probably created by another 616260918Spfg // JVM instance. However, this could also be the result of a 61750503Sobrien // deliberate symlink. Verify that the existing directory is safe. 61850503Sobrien // 61950503Sobrien if (!is_directory_secure(dirname)) { 62050503Sobrien // directory is not secure 62150503Sobrien if (PrintMiscellaneous && Verbose) { 62250503Sobrien warning("%s directory is insecure\n", dirname); 62350503Sobrien } 62450503Sobrien return false; 62550503Sobrien } 62650503Sobrien } 62750503Sobrien else { 62850503Sobrien // we encountered some other failure while attempting 62950503Sobrien // to create the directory 63050503Sobrien // 63150503Sobrien if (PrintMiscellaneous && Verbose) { 63250503Sobrien warning("could not create directory %s: %s\n", 63350503Sobrien dirname, strerror(errno)); 63450503Sobrien } 63550503Sobrien return false; 63650503Sobrien } 63790087Sobrien } 63850503Sobrien return true; 639132727Skan} 64050503Sobrien 64190087Sobrien// create the shared memory file resources 64290087Sobrien// 64390087Sobrien// This method creates the shared memory file with the given size 64490087Sobrien// This method also creates the user specific temporary directory, if 64590087Sobrien// it does not yet exist. 64690087Sobrien// 64790087Sobrienstatic int create_sharedmem_resources(const char* dirname, const char* filename, size_t size) { 64890087Sobrien 649169699Skan // make the user temporary directory 65050503Sobrien if (!make_user_tmp_dir(dirname)) { 65150503Sobrien // could not make/find the directory or the found directory 65250503Sobrien // was not secure 65350503Sobrien return -1; 65450503Sobrien } 65550503Sobrien 65650503Sobrien int result; 65790087Sobrien 65890087Sobrien RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result); 65990087Sobrien if (result == OS_ERR) { 66090087Sobrien if (PrintMiscellaneous && Verbose) { 66150503Sobrien warning("could not create file %s: %s\n", filename, strerror(errno)); 66290087Sobrien } 66350503Sobrien return -1; 66450503Sobrien } 66550503Sobrien 66650503Sobrien // save the file descriptor 66750503Sobrien int fd = result; 66890087Sobrien 66950503Sobrien // set the file size 67050503Sobrien RESTARTABLE(::ftruncate(fd, (off_t)size), result); 67150503Sobrien if (result == OS_ERR) { 67250503Sobrien if (PrintMiscellaneous && Verbose) { 67350503Sobrien warning("could not set shared memory file size: %s\n", strerror(errno)); 67450503Sobrien } 675169699Skan ::close(fd); 676169699Skan return -1; 677169699Skan } 678169699Skan 679132727Skan return fd; 68090087Sobrien} 681260918Spfg 682260918Spfg// open the shared memory file for the given user and vmid. returns 683117404Skan// the file descriptor for the open file or -1 if the file could not 68490087Sobrien// be opened. 685260918Spfg// 686260918Spfgstatic int open_sharedmem_file(const char* filename, int oflags, TRAPS) { 68790087Sobrien 68890087Sobrien // open the file 68990087Sobrien int result; 690169699Skan RESTARTABLE(::open(filename, oflags), result); 69190087Sobrien if (result == OS_ERR) { 692117404Skan if (errno == ENOENT) { 69390087Sobrien THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), 694132727Skan "Process not found", OS_ERR); 69590087Sobrien } 69690087Sobrien else if (errno == EACCES) { 697169699Skan THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), 698260918Spfg "Permission denied", OS_ERR); 699260918Spfg } 70090087Sobrien else { 701260918Spfg THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); 702169699Skan } 703132727Skan } 70490087Sobrien 705260918Spfg return result; 706260918Spfg} 707260918Spfg 708260918Spfg// create a named shared memory region. returns the address of the 709260918Spfg// memory region on success or NULL on failure. A return value of 710260918Spfg// NULL will ultimately disable the shared memory feature. 71190087Sobrien// 71290087Sobrien// On Solaris and Linux, the name space for shared memory objects 71390087Sobrien// is the file system name space. 714169699Skan// 71590087Sobrien// A monitoring application attaching to a JVM does not need to know 71690087Sobrien// the file system name of the shared memory object. However, it may 71790087Sobrien// be convenient for applications to discover the existence of newly 71890087Sobrien// created and terminating JVMs by watching the file system name space 71990087Sobrien// for files being created or removed. 72090087Sobrien// 72190087Sobrienstatic char* mmap_create_shared(size_t size) { 72290087Sobrien 72390087Sobrien int result; 72490087Sobrien int fd; 72590087Sobrien char* mapAddress; 72690087Sobrien 72790087Sobrien int vmid = os::current_process_id(); 72890087Sobrien 72990087Sobrien char* user_name = get_user_name(geteuid()); 73090087Sobrien 73190087Sobrien if (user_name == NULL) 73290087Sobrien return NULL; 73390087Sobrien 734117404Skan char* dirname = get_user_tmp_dir(user_name); 735117404Skan char* filename = get_sharedmem_filename(dirname, vmid); 73690087Sobrien 73790087Sobrien // cleanup any stale shared memory files 73890087Sobrien cleanup_sharedmem_resources(dirname); 73990087Sobrien 74090087Sobrien assert(((size > 0) && (size % os::vm_page_size() == 0)), 74190087Sobrien "unexpected PerfMemory region size"); 74290087Sobrien 74390087Sobrien fd = create_sharedmem_resources(dirname, filename, size); 74490087Sobrien 74590087Sobrien FREE_C_HEAP_ARRAY(char, user_name, mtInternal); 746117404Skan FREE_C_HEAP_ARRAY(char, dirname, mtInternal); 74790087Sobrien 748132727Skan if (fd == -1) { 74990087Sobrien FREE_C_HEAP_ARRAY(char, filename, mtInternal); 750117404Skan return NULL; 75190087Sobrien } 75290087Sobrien 75390087Sobrien mapAddress = (char*)::mmap((char*)0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 75490087Sobrien 75590087Sobrien result = ::close(fd); 75690087Sobrien assert(result != OS_ERR, "could not close file"); 75790087Sobrien 75890087Sobrien if (mapAddress == MAP_FAILED) { 759260918Spfg if (PrintMiscellaneous && Verbose) { 760260918Spfg warning("mmap failed - %s\n", strerror(errno)); 761260918Spfg } 76290087Sobrien remove_file(filename); 763169699Skan FREE_C_HEAP_ARRAY(char, filename, mtInternal); 76490087Sobrien return NULL; 765169699Skan } 766169699Skan 767169699Skan // save the file name for use in delete_shared_memory() 768169699Skan backing_store_file_name = filename; 769169699Skan 770169699Skan // clear the shared memory region 771169699Skan (void)::memset((void*) mapAddress, 0, size); 772169699Skan 773169699Skan // it does not go through os api, the operation has to record from here 774169699Skan MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, 775169699Skan size, CURRENT_PC, mtInternal); 776169699Skan 777169699Skan return mapAddress; 778169699Skan} 779169699Skan 780169699Skan// release a named shared memory region 781169699Skan// 782169699Skanstatic void unmap_shared(char* addr, size_t bytes) { 78390087Sobrien os::release_memory(addr, bytes); 78418334Speter} 78518334Speter 78618334Speter// create the PerfData memory region in shared memory. 78750503Sobrien// 78850503Sobrienstatic char* create_shared_memory(size_t size) { 78950503Sobrien 79050503Sobrien // create the shared memory region. 79190087Sobrien return mmap_create_shared(size); 79250503Sobrien} 79350503Sobrien 79450503Sobrien// delete the shared PerfData memory region 79518334Speter// 796132727Skanstatic void delete_shared_memory(char* addr, size_t size) { 79718334Speter 79850503Sobrien // cleanup the persistent shared memory resources. since DestroyJavaVM does 79950503Sobrien // not support unloading of the JVM, unmapping of the memory resource is 80050503Sobrien // not performed. The memory will be reclaimed by the OS upon termination of 80150503Sobrien // the process. The backing store file is deleted from the file system. 80250503Sobrien 80318334Speter assert(!PerfDisableSharedMem, "shouldn't be here"); 80450503Sobrien 80550503Sobrien if (backing_store_file_name != NULL) { 80618334Speter remove_file(backing_store_file_name); 80718334Speter // Don't.. Free heap memory could deadlock os::abort() if it is called 80818334Speter // from signal handler. OS will reclaim the heap memory. 80918334Speter // FREE_C_HEAP_ARRAY(char, backing_store_file_name); 81050503Sobrien backing_store_file_name = NULL; 81118334Speter } 81250503Sobrien} 81318334Speter 814260918Spfg// return the size of the file for the given file descriptor 815260918Spfg// or 0 if it is not a valid size for a shared memory file 816260918Spfg// 81750503Sobrienstatic size_t sharedmem_filesize(int fd, TRAPS) { 81850503Sobrien 819169699Skan struct stat statbuf; 820169699Skan int result; 82150503Sobrien 822169699Skan RESTARTABLE(::fstat(fd, &statbuf), result); 823169699Skan if (result == OS_ERR) { 824260918Spfg if (PrintMiscellaneous && Verbose) { 825260918Spfg warning("fstat failed: %s\n", strerror(errno)); 82650503Sobrien } 82750503Sobrien THROW_MSG_0(vmSymbols::java_io_IOException(), 82850503Sobrien "Could not determine PerfMemory size"); 82950503Sobrien } 83090087Sobrien 83150503Sobrien if ((statbuf.st_size == 0) || 83250503Sobrien ((size_t)statbuf.st_size % os::vm_page_size() != 0)) { 83350503Sobrien THROW_MSG_0(vmSymbols::java_lang_Exception(), 83450503Sobrien "Invalid PerfMemory size"); 83550503Sobrien } 83650503Sobrien 83750503Sobrien return (size_t)statbuf.st_size; 83850503Sobrien} 83990087Sobrien 840169699Skan// attach to a named shared memory region. 841169699Skan// 842169699Skanstatic void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemoryMode mode, char** addr, size_t* sizep, TRAPS) { 84350503Sobrien 84450503Sobrien char* mapAddress; 84550503Sobrien int result; 84690087Sobrien int fd; 847260918Spfg size_t size = 0; 848260918Spfg const char* luser = NULL; 849260918Spfg 85090087Sobrien int mmap_prot; 85190087Sobrien int file_flags; 85290087Sobrien 853260918Spfg ResourceMark rm; 854260918Spfg 855260918Spfg // map the high level access mode to the appropriate permission 85690087Sobrien // constructs for the file and the shared memory mapping. 85790087Sobrien if (mode == PerfMemory::PERF_MODE_RO) { 85850503Sobrien mmap_prot = PROT_READ; 85950503Sobrien file_flags = O_RDONLY; 86050503Sobrien } 86150503Sobrien else if (mode == PerfMemory::PERF_MODE_RW) { 86250503Sobrien#ifdef LATER 86350503Sobrien mmap_prot = PROT_READ | PROT_WRITE; 864169699Skan file_flags = O_RDWR; 86550503Sobrien#else 86650503Sobrien THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 867169699Skan "Unsupported access mode"); 868169699Skan#endif 869169699Skan } 87050503Sobrien else { 87150503Sobrien THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 87250503Sobrien "Illegal access mode"); 87350503Sobrien } 87450503Sobrien 87550503Sobrien if (user == NULL || strlen(user) == 0) { 87650503Sobrien luser = get_user_name(vmid, CHECK); 87750503Sobrien } 87850503Sobrien else { 87950503Sobrien luser = user; 88050503Sobrien } 88150503Sobrien 88250503Sobrien if (luser == NULL) { 883260918Spfg THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 884260918Spfg "Could not map vmid to user Name"); 885260918Spfg } 88650503Sobrien 88750503Sobrien char* dirname = get_user_tmp_dir(luser); 88850503Sobrien 889169699Skan // since we don't follow symbolic links when creating the backing 89050503Sobrien // store file, we don't follow them when attaching either. 89150503Sobrien // 89250503Sobrien if (!is_directory_secure(dirname)) { 89390087Sobrien FREE_C_HEAP_ARRAY(char, dirname, mtInternal); 89450503Sobrien if (luser != user) { 895169699Skan FREE_C_HEAP_ARRAY(char, luser, mtInternal); 89650503Sobrien } 89750503Sobrien THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 89850503Sobrien "Process not found"); 89950503Sobrien } 90050503Sobrien 90150503Sobrien char* filename = get_sharedmem_filename(dirname, vmid); 90250503Sobrien 90350503Sobrien // copy heap memory to resource memory. the open_sharedmem_file 90450503Sobrien // method below need to use the filename, but could throw an 90550503Sobrien // exception. using a resource array prevents the leak that 90650503Sobrien // would otherwise occur. 90750503Sobrien char* rfilename = NEW_RESOURCE_ARRAY(char, strlen(filename) + 1); 90850503Sobrien strcpy(rfilename, filename); 90950503Sobrien 910169699Skan // free the c heap resources that are no longer needed 91152515Sobrien if (luser != user) FREE_C_HEAP_ARRAY(char, luser, mtInternal); 91250503Sobrien FREE_C_HEAP_ARRAY(char, dirname, mtInternal); 91350503Sobrien FREE_C_HEAP_ARRAY(char, filename, mtInternal); 91490087Sobrien 91550503Sobrien // open the shared memory file for the give vmid 916169699Skan fd = open_sharedmem_file(rfilename, file_flags, THREAD); 91750503Sobrien 91850503Sobrien if (fd == OS_ERR) { 91950503Sobrien return; 92050503Sobrien } 92150503Sobrien 92250503Sobrien if (HAS_PENDING_EXCEPTION) { 923169699Skan ::close(fd); 92450503Sobrien return; 92590087Sobrien } 92650503Sobrien 92750503Sobrien if (*sizep == 0) { 92850503Sobrien size = sharedmem_filesize(fd, CHECK); 92950503Sobrien } else { 93050503Sobrien size = *sizep; 93150503Sobrien } 932260918Spfg 933260918Spfg assert(size > 0, "unexpected size <= 0"); 934260918Spfg 93550503Sobrien mapAddress = (char*)::mmap((char*)0, size, mmap_prot, MAP_SHARED, fd, 0); 93650503Sobrien 93750503Sobrien result = ::close(fd); 93850503Sobrien assert(result != OS_ERR, "could not close file"); 93950503Sobrien 94050503Sobrien if (mapAddress == MAP_FAILED) { 94150503Sobrien if (PrintMiscellaneous && Verbose) { 94250503Sobrien warning("mmap failed: %s\n", strerror(errno)); 94350503Sobrien } 94450503Sobrien THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), 94550503Sobrien "Could not map PerfMemory"); 94650503Sobrien } 94750503Sobrien 94850503Sobrien // it does not go through os api, the operation has to record from here 94950503Sobrien MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, 95050503Sobrien size, CURRENT_PC, mtInternal); 95150503Sobrien 95250503Sobrien *addr = mapAddress; 95350503Sobrien *sizep = size; 95450503Sobrien 95550503Sobrien if (PerfTraceMemOps) { 95650503Sobrien tty->print("mapped " SIZE_FORMAT " bytes for vmid %d at " 95750503Sobrien INTPTR_FORMAT "\n", size, vmid, (void*)mapAddress); 95850503Sobrien } 95950503Sobrien} 96050503Sobrien 961169699Skan 96250503Sobrien 96350503Sobrien 96450503Sobrien// create the PerfData memory region 96550503Sobrien// 966169699Skan// This method creates the memory region used to store performance 96750503Sobrien// data for the JVM. The memory may be created in standard or 96850503Sobrien// shared memory. 96950503Sobrien// 97050503Sobrienvoid PerfMemory::create_memory_region(size_t size) { 97150503Sobrien 97250503Sobrien if (PerfDisableSharedMem) { 97350503Sobrien // do not share the memory for the performance data. 97450503Sobrien _start = create_standard_memory(size); 97550503Sobrien } 97650503Sobrien else { 97750503Sobrien _start = create_shared_memory(size); 97850503Sobrien if (_start == NULL) { 97950503Sobrien 98050503Sobrien // creation of the shared memory region failed, attempt 98150503Sobrien // to create a contiguous, non-shared memory region instead. 982260918Spfg // 983260918Spfg if (PrintMiscellaneous && Verbose) { 984260918Spfg warning("Reverting to non-shared PerfMemory region.\n"); 985260918Spfg } 98650503Sobrien PerfDisableSharedMem = true; 987169699Skan _start = create_standard_memory(size); 988169699Skan } 98950503Sobrien } 99050503Sobrien 991169699Skan if (_start != NULL) _capacity = size; 99250503Sobrien 99350503Sobrien} 99450503Sobrien 99550503Sobrien// delete the PerfData memory region 99650503Sobrien// 99750503Sobrien// This method deletes the memory region used to store performance 99850503Sobrien// data for the JVM. The memory region indicated by the <address, size> 99950503Sobrien// tuple will be inaccessible after a call to this method. 100050503Sobrien// 100150503Sobrienvoid PerfMemory::delete_memory_region() { 100250503Sobrien 100318334Speter assert((start() != NULL && capacity() > 0), "verify proper state"); 1004132727Skan 100518334Speter // If user specifies PerfDataSaveFile, it will save the performance data 100618334Speter // to the specified file name no matter whether PerfDataSaveToFile is specified 100718334Speter // or not. In other word, -XX:PerfDataSaveFile=.. overrides flag 100818334Speter // -XX:+PerfDataSaveToFile. 100950503Sobrien if (PerfDataSaveToFile || PerfDataSaveFile != NULL) { 101050503Sobrien save_memory_to_file(start(), capacity()); 101150503Sobrien } 1012169699Skan 101350503Sobrien if (PerfDisableSharedMem) { 1014260918Spfg delete_standard_memory(start(), capacity()); 1015260918Spfg } 1016260918Spfg else { 101750503Sobrien delete_shared_memory(start(), capacity()); 101850503Sobrien } 101950503Sobrien} 102050503Sobrien 102150503Sobrien// attach to the PerfData memory region for another JVM 102250503Sobrien// 102350503Sobrien// This method returns an <address, size> tuple that points to 102450503Sobrien// a memory buffer that is kept reasonably synchronized with 1025117404Skan// the PerfData memory region for the indicated JVM. This 102690087Sobrien// buffer may be kept in synchronization via shared memory 1027169699Skan// or some other mechanism that keeps the buffer updated. 1028169699Skan// 102918334Speter// If the JVM chooses not to support the attachability feature, 103050503Sobrien// this method should throw an UnsupportedOperation exception. 103150503Sobrien// 103218334Speter// This implementation utilizes named shared memory to map 103318334Speter// the indicated process's PerfData memory region into this JVMs 103418334Speter// address space. 103518334Speter// 103618334Spetervoid PerfMemory::attach(const char* user, int vmid, PerfMemoryMode mode, char** addrp, size_t* sizep, TRAPS) { 103718334Speter 1038169699Skan if (vmid == 0 || vmid == os::current_process_id()) { 1039169699Skan *addrp = start(); 104050503Sobrien *sizep = capacity(); 104150503Sobrien return; 104250503Sobrien } 104350503Sobrien 104418334Speter mmap_attach_shared(user, vmid, mode, addrp, sizep, CHECK); 104590087Sobrien} 104618334Speter 104718334Speter// detach from the PerfData memory region of another JVM 104818334Speter// 104918334Speter// This method detaches the PerfData memory region of another 105018334Speter// JVM, specified as an <address, size> tuple of a buffer 105118334Speter// in this process's address space. This method may perform 105218334Speter// arbitrary actions to accomplish the detachment. The memory 105318334Speter// region specified by <address, size> will be inaccessible after 105418334Speter// a call to this method. 105518334Speter// 105618334Speter// If the JVM chooses not to support the attachability feature, 105718334Speter// this method should throw an UnsupportedOperation exception. 105850503Sobrien// 105918334Speter// This implementation utilizes named shared memory to detach 106018334Speter// the indicated process's PerfData memory region from this 106118334Speter// process's address space. 106218334Speter// 106318334Spetervoid PerfMemory::detach(char* addr, size_t bytes, TRAPS) { 106418334Speter 106590087Sobrien assert(addr != 0, "address sanity check"); 106690087Sobrien assert(bytes > 0, "capacity sanity check"); 106718334Speter 106818334Speter if (PerfMemory::contains(addr) || PerfMemory::contains(addr + bytes - 1)) { 106918334Speter // prevent accidental detachment of this process's PerfMemory region 107018334Speter return; 107190087Sobrien } 107218334Speter 107318334Speter unmap_shared(addr, bytes); 107418334Speter} 107518334Speter