< prev index next >
src/os/posix/vm/os_posix.cpp
Print this page
*** 36,45 ****
--- 36,46 ----
#include <sys/resource.h>
#include <sys/utsname.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
+ #include <sys/mman.h>
// Todo: provide a os::get_max_process_id() or similar. Number of processes
// may have been configured, can be read more accurately from proc fs etc.
#ifndef MAX_PID
#define MAX_PID INT_MAX
*** 137,158 ****
void os::wait_for_keypress_at_exit(void) {
// don't do anything on posix platforms
return;
}
// Multiple threads can race in this code, and can remap over each other with MAP_FIXED,
// so on posix, unmap the section at the start and at the end of the chunk that we mapped
// rather than unmapping and remapping the whole chunk to get requested alignment.
! char* os::reserve_memory_aligned(size_t size, size_t alignment) {
assert((alignment & (os::vm_allocation_granularity() - 1)) == 0,
"Alignment must be a multiple of allocation granularity (page size)");
assert((size & (alignment -1)) == 0, "size must be 'alignment' aligned");
size_t extra_size = size + alignment;
assert(extra_size >= size, "overflow, size is too large to allow alignment");
! char* extra_base = os::reserve_memory(extra_size, NULL, alignment);
if (extra_base == NULL) {
return NULL;
}
--- 138,327 ----
void os::wait_for_keypress_at_exit(void) {
// don't do anything on posix platforms
return;
}
+ // Helper function to create a temp file in the given directory.
+ int os::create_file_for_heap(const char* dir, size_t size) {
+
+ const char name_template[] = "/jvmheap.XXXXXX";
+
+ char *fullname = (char*)::malloc(strlen(dir) + sizeof(name_template));
+ if (fullname == NULL) {
+ vm_exit_during_initialization(err_msg("malloc failed"));
+ return -1;
+ }
+ (void)strcpy(fullname, dir);
+ (void)strcat(fullname, name_template);
+
+ sigset_t set, oldset;
+ int ret = sigfillset(&set);
+ assert(ret == 0, "sigfillset error");
+
+ // block all signals while we do the file operation.
+ ret = pthread_sigmask(SIG_BLOCK, &set, &oldset);
+ assert(ret == 0, "pthread_sigmask error");
+
+ // set the file creation mask.
+ mode_t file_mode = S_IRUSR | S_IWUSR;
+
+ // create a new file.
+ int fd = mkstemp(fullname);
+
+ if (fd < 0) {
+ // reset the signal mask.
+ ret = pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+ assert(ret == 0, "pthread_sigmask error");
+ ::free(fullname);
+ return -1;
+ }
+
+ // change file permissions; mkstemp creates file with permissions 0600 (glibc versions after 2.06) or 0666 (2.06 and earlier versions)
+ ret = fchmod(fd, file_mode);
+ assert(ret == 0, "fchmod error");
+
+ // delete the name from the filesystem. When 'fd' is closed, the file (and space) will be deleted.
+ ret = unlink(fullname);
+ assert(ret == 0, "unlink error");
+
+ // reset the signal mask.
+ ret = pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+ assert(ret == 0, "pthread_sigmask error");
+
+ ::free(fullname);
+ return fd;
+ }
+
+ static char* reserve_mmaped_memory(size_t bytes, char* requested_addr) {
+ char * addr;
+ int flags;
+
+ flags = MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS;
+ if (requested_addr != NULL) {
+ assert((uintptr_t)requested_addr % os::Linux::page_size() == 0, "unaligned address");
+ flags |= MAP_FIXED;
+ }
+
+ // Map reserved/uncommitted pages PROT_NONE so we fail early if we
+ // touch an uncommitted page. Otherwise, the read/write might
+ // succeed if we have enough swap space to back the physical page.
+ addr = (char*)::mmap(requested_addr, bytes, PROT_NONE,
+ flags, -1, 0);
+
+ if (addr != MAP_FAILED) {
+ MemTracker::record_virtual_memory_reserve((address)addr, bytes, CALLER_PC);
+ return addr;
+ }
+ return NULL;
+ }
+
+ static int util_posix_fallocate(int fd, off_t offset, off_t len) {
+ #ifdef __APPLE__
+ fstore_t store = { F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, len };
+ // First we try to get a continous chunk of disk space
+ int ret = fcntl(fd, F_PREALLOCATE, &store);
+ if (ret == -1) {
+ // Maybe we are too fragmented, try to allocate non-continuous range
+ store.fst_flags = F_ALLOCATEALL;
+ ret = fcntl(fd, F_PREALLOCATE, &store);
+ if (ret == -1)
+ return -1;
+ }
+ return ftruncate(fd, len);
+ #else
+ return posix_fallocate(fd, offset, len);
+ #endif
+ }
+
+ // Map the given address range to the provided file descriptor.
+ char* os::map_memory_to_dax_file(char* base, size_t size, int fd) {
+ assert(fd != -1, "File descriptor is not valid");
+
+ // allocate space for the file
+ if (util_posix_fallocate(fd, 0, (off_t)size) != 0) {
+ vm_exit_during_initialization(err_msg("Error in mapping Java heap at the given filesystem directory (%s)", os::strerror(errno)));
+ return NULL;
+ }
+
+ int prot = PROT_READ | PROT_WRITE;
+ int flags = MAP_SHARED;
+ if (base != NULL) {
+ flags |= MAP_FIXED;
+ }
+ char* addr = (char*)mmap(base, size, prot, flags, fd, 0);
+
+ if (addr == MAP_FAILED || (base != NULL && addr != base)) {
+ if (addr != MAP_FAILED) {
+ if (!os::release_memory(addr, size)) {
+ warning("Could not release memory on unsuccessful file mapping");
+ }
+ }
+ return NULL;
+ }
+
+ return addr;
+ }
+
+ char* os::replace_existing_mapping_with_dax_file_mapping(char* base, size_t size, int fd) {
+ assert(fd != -1, "File descriptor is not valid");
+ assert(base != NULL, "base cannot be NULL");
+
+ return map_memory_to_dax_file(base, size, fd);
+
+ }
+
+ char* os::attempt_reserve_memory_at(size_t bytes, char* addr, int file_desc) {
+
+ // We would want to use the complex logic in pd_attempt_reserve_memory_at(), especially in Linux.
+ // So we call pd_attempt_reserve_memory_at() to purely reserve mmemory
+ // and then replace the anonymous mapping with file mapping.
+ // Unfortunately for AIX, we need to pass new bool parameter to pd_attempt_reserve_memory_at()
+ // to indicate not to use SHM
+ #if defined(AIX)
+ char* result = pd_attempt_reserve_memory_at(bytes, addr, file_desc == -1 /*can use SHM*/);
+ #else
+ char* result = pd_attempt_reserve_memory_at(bytes, addr);
+ #endif
+ if (result != NULL && file_desc != -1) {
+ if (replace_existing_mapping_with_dax_file_mapping(result, bytes, file_desc) == NULL) {
+ vm_exit_during_initialization(err_msg("Error in mapping Java heap at the given filesystem directory"));
+ }
+ MemTracker::record_virtual_memory_reserve_and_commit((address)result, bytes, CALLER_PC);
+ return result;
+ }
+ if (result != NULL) {
+ MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC);
+ }
+ return result;
+ }
+
// Multiple threads can race in this code, and can remap over each other with MAP_FIXED,
// so on posix, unmap the section at the start and at the end of the chunk that we mapped
// rather than unmapping and remapping the whole chunk to get requested alignment.
! char* os::reserve_memory_aligned(size_t size, size_t alignment, int file_desc) {
assert((alignment & (os::vm_allocation_granularity() - 1)) == 0,
"Alignment must be a multiple of allocation granularity (page size)");
assert((size & (alignment -1)) == 0, "size must be 'alignment' aligned");
size_t extra_size = size + alignment;
assert(extra_size >= size, "overflow, size is too large to allow alignment");
! char* extra_base;
! if (file_desc != -1) {
! // For file mapping, we do not call os:reserve_memory(extra_size, NULL, alignment, file_desc) because
! // we need to deal with shrinking of the file space later when we release extra memory after alignment.
! // We also cannot called os:reserve_memory() with file_desc set to -1 because on aix we might get SHM memory.
! // So here to call a helper function while reserve memory for us. After we have a aligned base,
! // we will replace anonymous mapping with file mapping.
! extra_base = reserve_mmaped_memory(extra_size, NULL);
! if (extra_base != NULL) {
! MemTracker::record_virtual_memory_reserve((address)extra_base, extra_size, CALLER_PC);
! }
! }
! else {
! extra_base = os::reserve_memory(extra_size, NULL, alignment);
! }
if (extra_base == NULL) {
return NULL;
}
*** 175,184 ****
--- 344,360 ----
if (end_offset > 0) {
os::release_memory(extra_base + begin_offset + size, end_offset);
}
+ if (file_desc != -1) {
+ // After we have an aligned address, we can replace anonymopus mapping with file mapping
+ if (replace_existing_mapping_with_dax_file_mapping(aligned_base, size, file_desc) == NULL) {
+ vm_exit_during_initialization(err_msg("Error in mapping Java heap at the given filesystem directory"));
+ }
+ MemTracker::record_virtual_memory_commit((address)aligned_base, size, CALLER_PC);
+ }
return aligned_base;
}
int os::log_vsnprintf(char* buf, size_t len, const char* fmt, va_list args) {
return vsnprintf(buf, len, fmt, args);
< prev index next >