8134540: Much nearly duplicated code for PerfMemory support

Reviewed-by: coleenp, dholmes
This commit is contained in:
Harold Seigel 2021-01-19 13:44:07 +00:00
parent a9519c83b8
commit 82adfb3233
9 changed files with 102 additions and 2625 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2018 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -69,18 +69,6 @@ inline int os::ftruncate(int fd, jlong length) {
return ::ftruncate64(fd, length);
}
// macros for restartable system calls
#define RESTARTABLE(_cmd, _result) do { \
_result = _cmd; \
} while(((int)_result == OS_ERR) && (errno == EINTR))
#define RESTARTABLE_RETURN_INT(_cmd) do { \
int _result; \
RESTARTABLE(_cmd, _result); \
return _result; \
} while(false)
// We don't have NUMA support on Aix, but we need this for compilation.
inline bool os::numa_has_static_binding() { ShouldNotReachHere(); return true; }
inline bool os::numa_has_group_homing() { ShouldNotReachHere(); return false; }
@ -91,10 +79,6 @@ inline size_t os::write(int fd, const void *buf, unsigned int nBytes) {
return res;
}
inline int os::close(int fd) {
return ::close(fd);
}
inline int os::socket_close(int fd) {
return ::close(fd);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -72,18 +72,6 @@ inline int os::ftruncate(int fd, jlong length) {
return ::ftruncate(fd, length);
}
// macros for restartable system calls
#define RESTARTABLE(_cmd, _result) do { \
_result = _cmd; \
} while(((int)_result == OS_ERR) && (errno == EINTR))
#define RESTARTABLE_RETURN_INT(_cmd) do { \
int _result; \
RESTARTABLE(_cmd, _result); \
return _result; \
} while(false)
inline bool os::numa_has_static_binding() { return true; }
inline bool os::numa_has_group_homing() { return false; }
@ -93,10 +81,6 @@ inline size_t os::write(int fd, const void *buf, unsigned int nBytes) {
return res;
}
inline int os::close(int fd) {
return ::close(fd);
}
inline int os::socket_close(int fd) {
return ::close(fd);
}

File diff suppressed because it is too large Load Diff

View File

@ -4349,6 +4349,37 @@ jlong os::Linux::fast_thread_cpu_time(clockid_t clockid) {
return (tp.tv_sec * NANOSECS_PER_SEC) + tp.tv_nsec;
}
// Determine if the vmid is the parent pid for a child in a PID namespace.
// Return the namespace pid if so, otherwise -1.
int os::Linux::get_namespace_pid(int vmid) {
char fname[24];
int retpid = -1;
snprintf(fname, sizeof(fname), "/proc/%d/status", vmid);
FILE *fp = fopen(fname, "r");
if (fp) {
int pid, nspid;
int ret;
while (!feof(fp) && !ferror(fp)) {
ret = fscanf(fp, "NSpid: %d %d", &pid, &nspid);
if (ret == 1) {
break;
}
if (ret == 2) {
retpid = nspid;
break;
}
for (;;) {
int ch = fgetc(fp);
if (ch == EOF || ch == (int)'\n') break;
}
}
fclose(fp);
}
return retpid;
}
extern void report_error(char* file_name, int line_no, char* title,
char* format, ...);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -169,6 +169,10 @@ class Linux {
static jlong fast_thread_cpu_time(clockid_t clockid);
// Determine if the vmid is the parent pid for a child in a PID namespace.
// Return the namespace pid if so, otherwise -1.
static int get_namespace_pid(int vmid);
// Stack repair handling
// none present

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -64,18 +64,6 @@ inline int os::ftruncate(int fd, jlong length) {
return ::ftruncate64(fd, length);
}
// macros for restartable system calls
#define RESTARTABLE(_cmd, _result) do { \
_result = _cmd; \
} while(((int)_result == OS_ERR) && (errno == EINTR))
#define RESTARTABLE_RETURN_INT(_cmd) do { \
int _result; \
RESTARTABLE(_cmd, _result); \
return _result; \
} while(false)
inline bool os::numa_has_static_binding() { return true; }
inline bool os::numa_has_group_homing() { return false; }
@ -85,10 +73,6 @@ inline size_t os::write(int fd, const void *buf, unsigned int nBytes) {
return res;
}
inline int os::close(int fd) {
return ::close(fd);
}
inline int os::socket_close(int fd) {
return ::close(fd);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,25 @@
#include "runtime/os.hpp"
#include <unistd.h>
// macros for restartable system calls
#define RESTARTABLE(_cmd, _result) do { \
_result = _cmd; \
} while(((int)_result == OS_ERR) && (errno == EINTR))
#define RESTARTABLE_RETURN_INT(_cmd) do { \
int _result; \
RESTARTABLE(_cmd, _result); \
return _result; \
} while(false)
inline int os::close(int fd) {
return ::close(fd);
}
#ifdef SUPPORTS_CLOCK_MONOTONIC
// Exported clock functionality

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2020 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,7 +29,7 @@
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp"
#include "os_linux.inline.hpp"
#include "os_posix.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/os.hpp"
#include "runtime/perfMemory.hpp"
@ -92,8 +93,8 @@ static void delete_standard_memory(char* addr, size_t size) {
//
static void save_memory_to_file(char* addr, size_t size) {
const char* destfile = PerfMemory::get_perfdata_file_path();
assert(destfile[0] != '\0', "invalid PerfData file path");
const char* destfile = PerfMemory::get_perfdata_file_path();
assert(destfile[0] != '\0', "invalid PerfData file path");
int result;
@ -135,38 +136,32 @@ static void save_memory_to_file(char* addr, size_t size) {
// Shared Memory Implementation Details
// Note: the solaris and linux shared memory implementation uses the mmap
// Note: the Posix shared memory implementation uses the mmap
// interface with a backing store file to implement named shared memory.
// Using the file system as the name space for shared memory allows a
// common name space to be supported across a variety of platforms. It
// also provides a name space that Java applications can deal with through
// simple file apis.
//
// The solaris and linux implementations store the backing store file in
// a user specific temporary directory located in the /tmp file system,
// which is always a local file system and is sometimes a RAM based file
// system.
// return the user specific temporary directory name.
//
// If containerized process, get dirname of
// /proc/{vmid}/root/tmp/{PERFDATA_NAME_user}
// otherwise /tmp/{PERFDATA_NAME_user}
//
// the caller is expected to free the allocated memory.
//
#define TMP_BUFFER_LEN (4+22)
static char* get_user_tmp_dir(const char* user, int vmid, int nspid) {
char buffer[TMP_BUFFER_LEN];
char* tmpdir = (char *)os::get_temp_directory();
#if defined(LINUX)
// On linux, if containerized process, get dirname of
// /proc/{vmid}/root/tmp/{PERFDATA_NAME_user}
// otherwise /tmp/{PERFDATA_NAME_user}
char buffer[TMP_BUFFER_LEN];
assert(strlen(tmpdir) == 4, "No longer using /tmp - update buffer size");
if (nspid != -1) {
jio_snprintf(buffer, TMP_BUFFER_LEN, "/proc/%d/root%s", vmid, tmpdir);
tmpdir = buffer;
}
#endif
const char* perfdir = PERFDATA_NAME;
size_t nbytes = strlen(tmpdir) + strlen(perfdir) + strlen(user) + 3;
char* dirname = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
@ -319,6 +314,7 @@ static DIR *open_directory_secure(const char* dirname) {
DIR *dirp = NULL;
RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result);
if (result == OS_ERR) {
// Directory doesn't exist or is a symlink, so there is nothing to cleanup.
if (PrintMiscellaneous && Verbose) {
if (errno == ELOOP) {
warning("directory %s is a symlink and is not secure\n", dirname);
@ -346,7 +342,7 @@ static DIR *open_directory_secure(const char* dirname) {
}
// Check to make sure fd and dirp are referencing the same file system object.
if (!is_same_fsobject(fd, dirfd(dirp))) {
if (!is_same_fsobject(fd, AIX_ONLY(dirp->dd_fd) NOT_AIX(dirfd(dirp)))) {
// The directory is not secure.
os::close(fd);
os::closedir(dirp);
@ -378,7 +374,7 @@ static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) {
// Directory doesn't exist or is insecure, so there is nothing to cleanup.
return dirp;
}
int fd = dirfd(dirp);
int fd = AIX_ONLY(dirp->dd_fd) NOT_AIX(dirfd(dirp));
// Open a fd to the cwd and save it off.
int result;
@ -457,16 +453,14 @@ static char* get_user_name(uid_t uid) {
struct passwd pwent;
// determine the max pwbuf size from sysconf, and hardcode
// Determine the max pwbuf size from sysconf, and hardcode
// a default if this not available through sysconf.
//
long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
if (bufsize == -1)
bufsize = 1024;
char* pwbuf = NEW_C_HEAP_ARRAY(char, bufsize, mtInternal);
// POSIX interface to getpwuid_r is used on LINUX
struct passwd* p;
int result = getpwuid_r(uid, &pwent, pwbuf, (size_t)bufsize, &p);
@ -515,8 +509,6 @@ static char* get_user_name(uid_t uid) {
//
// the caller is expected to free the allocated memory.
//
// If nspid != -1, look in /proc/{vmid}/root/tmp for directories
// containing nspid, otherwise just look for vmid in /tmp
//
static char* get_user_name_slow(int vmid, int nspid, TRAPS) {
@ -534,18 +526,24 @@ static char* get_user_name_slow(int vmid, int nspid, TRAPS) {
// directory search
char* oldest_user = NULL;
time_t oldest_ctime = 0;
char buffer[MAXPATHLEN + 1];
int searchpid;
char* tmpdirname = (char *)os::get_temp_directory();
#if defined(LINUX)
assert(strlen(tmpdirname) == 4, "No longer using /tmp - update buffer size");
// On Linux, if nspid != -1, look in /proc/{vmid}/root/tmp for directories
// containing nspid, otherwise just look for vmid in /tmp.
if (nspid == -1) {
searchpid = vmid;
} else {
char buffer[MAXPATHLEN + 1];
jio_snprintf(buffer, MAXPATHLEN, "/proc/%d/root%s", vmid, tmpdirname);
tmpdirname = buffer;
searchpid = nspid;
}
#else
searchpid = vmid;
#endif
// open the temp directory
DIR* tmpdirp = os::opendir(tmpdirname);
@ -556,7 +554,7 @@ static char* get_user_name_slow(int vmid, int nspid, TRAPS) {
}
// for each entry in the directory that matches the pattern hsperfdata_*,
// open the directory and check if the file for the given vmid or nspid exists.
// open the directory and check if the file for the given vmid (or nspid) exists.
// The file with the expected name and the latest creation date is used
// to determine the user name for the process id.
//
@ -570,7 +568,8 @@ static char* get_user_name_slow(int vmid, int nspid, TRAPS) {
}
char* usrdir_name = NEW_C_HEAP_ARRAY(char,
strlen(tmpdirname) + strlen(dentry->d_name) + 2, mtInternal);
strlen(tmpdirname) + strlen(dentry->d_name) + 2,
mtInternal);
strcpy(usrdir_name, tmpdirname);
strcat(usrdir_name, "/");
strcat(usrdir_name, dentry->d_name);
@ -604,7 +603,8 @@ static char* get_user_name_slow(int vmid, int nspid, TRAPS) {
int result;
char* filename = NEW_C_HEAP_ARRAY(char,
strlen(usrdir_name) + strlen(udentry->d_name) + 2, mtInternal);
strlen(usrdir_name) + strlen(udentry->d_name) + 2,
mtInternal);
strcpy(filename, usrdir_name);
strcat(filename, "/");
@ -648,43 +648,12 @@ static char* get_user_name_slow(int vmid, int nspid, TRAPS) {
return(oldest_user);
}
// Determine if the vmid is the parent pid
// for a child in a PID namespace.
// return the namespace pid if so, otherwise -1
static int get_namespace_pid(int vmid) {
char fname[24];
int retpid = -1;
snprintf(fname, sizeof(fname), "/proc/%d/status", vmid);
FILE *fp = fopen(fname, "r");
if (fp) {
int pid, nspid;
int ret;
while (!feof(fp) && !ferror(fp)) {
ret = fscanf(fp, "NSpid: %d %d", &pid, &nspid);
if (ret == 1) {
break;
}
if (ret == 2) {
retpid = nspid;
break;
}
for (;;) {
int ch = fgetc(fp);
if (ch == EOF || ch == (int)'\n') break;
}
}
fclose(fp);
}
return retpid;
}
// return the name of the user that owns the JVM indicated by the given vmid.
//
static char* get_user_name(int vmid, int *nspid, TRAPS) {
char *result = get_user_name_slow(vmid, *nspid, THREAD);
#if defined(LINUX)
// If we are examining a container process without PID namespaces enabled
// we need to use /proc/{pid}/root/tmp to find hsperfdata files.
if (result == NULL) {
@ -692,6 +661,7 @@ static char* get_user_name(int vmid, int *nspid, TRAPS) {
// Enable nspid logic going forward
if (result != NULL) *nspid = vmid;
}
#endif
return result;
}
@ -702,7 +672,7 @@ static char* get_user_name(int vmid, int *nspid, TRAPS) {
//
static char* get_sharedmem_filename(const char* dirname, int vmid, int nspid) {
int pid = (nspid == -1) ? vmid : nspid;
int pid = LINUX_ONLY((nspid == -1) ? vmid : nspid) NOT_LINUX(vmid);
// add 2 for the file separator and a null terminator.
size_t nbytes = strlen(dirname) + UINT_CHARS + 2;
@ -749,7 +719,7 @@ static void remove_file(const char* path) {
static void cleanup_sharedmem_resources(const char* dirname) {
int saved_cwd_fd;
// open the directory
// open the directory and set the current working directory to it
DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd);
if (dirp == NULL) {
// directory doesn't exist or is insecure, so there is nothing to cleanup
@ -919,7 +889,6 @@ static int create_sharedmem_resources(const char* dirname, const char* filename,
// Verify that we have enough disk space for this file.
// We'll get random SIGBUS crashes on memory accesses if
// we don't.
for (size_t seekpos = 0; seekpos < size; seekpos += os::vm_page_size()) {
int zero_int = 0;
result = (int)os::seek_to_file_offset(fd, (jlong)(seekpos));
@ -979,8 +948,7 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) {
// memory region on success or NULL on failure. A return value of
// NULL will ultimately disable the shared memory feature.
//
// On Linux, the name space for shared memory objects
// is the file system name space.
// The name space for shared memory objects is the file system name space.
//
// A monitoring application attaching to a JVM does not need to know
// the file system name of the shared memory object. However, it may
@ -1057,7 +1025,15 @@ static char* mmap_create_shared(size_t size) {
// release a named shared memory region
//
static void unmap_shared(char* addr, size_t bytes) {
#if defined(_AIX)
// Do not rely on os::reserve_memory/os::release_memory to use mmap.
// Use os::reserve_memory/os::release_memory for PerfDisableSharedMem=1, mmap/munmap for PerfDisableSharedMem=0
if (::munmap(addr, bytes) == -1) {
warning("perfmemory: munmap failed (%d)\n", errno);
}
#else
os::release_memory(addr, bytes);
#endif
}
// create the PerfData memory region in shared memory.
@ -1149,8 +1125,8 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor
"Illegal access mode");
}
// determine if vmid is for a containerized process
int nspid = get_namespace_pid(vmid);
// for linux, determine if vmid is for a containerized process
int nspid = LINUX_ONLY(os::Linux::get_namespace_pid(vmid)) NOT_LINUX(-1);
if (user == NULL || strlen(user) == 0) {
luser = get_user_name(vmid, &nspid, CHECK);