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