hotspot/src/os/windows/vm/os_windows.cpp
Print this page
rev 611 : Merge
@@ -1,10 +1,7 @@
-#ifdef USE_PRAGMA_IDENT_SRC
-#pragma ident "@(#)os_windows.cpp 1.535 07/11/15 10:56:43 JVM"
-#endif
/*
- * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
@@ -328,10 +325,18 @@
VirtualQuery(&minfo, &minfo, sizeof(minfo));
sz = (size_t)os::current_stack_base() - (size_t)minfo.AllocationBase;
return sz;
}
+struct tm* os::localtime_pd(const time_t* clock, struct tm* res) {
+ const struct tm* time_struct_ptr = localtime(clock);
+ if (time_struct_ptr != NULL) {
+ *res = *time_struct_ptr;
+ return res;
+ }
+ return NULL;
+}
LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo);
// Thread start routine for all new Java threads
static unsigned __stdcall java_start(Thread* thread) {
@@ -738,24 +743,28 @@
result.dwHighDateTime = high(a);
result.dwLowDateTime = low(a);
return result;
}
-jlong os::timeofday() {
- FILETIME wt;
- GetSystemTimeAsFileTime(&wt);
- return windows_to_java_time(wt);
-}
+// For now, we say that Windows does not support vtime. I have no idea
+// whether it can actually be made to (DLD, 9/13/05).
+bool os::supports_vtime() { return false; }
+bool os::enable_vtime() { return false; }
+bool os::vtime_enabled() { return false; }
+double os::elapsedVTime() {
+ // better than nothing, but not much
+ return elapsedTime();
+}
-// Must return millis since Jan 1 1970 for JVM_CurrentTimeMillis
-// _use_global_time is only set if CacheTimeMillis is true
jlong os::javaTimeMillis() {
if (UseFakeTimers) {
return fake_time++;
} else {
- return (_use_global_time ? read_global_time() : timeofday());
+ FILETIME wt;
+ GetSystemTimeAsFileTime(&wt);
+ return windows_to_java_time(wt);
}
}
#define NANOS_PER_SEC CONST64(1000000000)
#define NANOS_PER_MILLISEC 1000000
@@ -993,10 +1002,67 @@
path_buf[0]='\0';
return path_buf;
}
}
+static bool file_exists(const char* filename) {
+ if (filename == NULL || strlen(filename) == 0) {
+ return false;
+ }
+ return GetFileAttributes(filename) != INVALID_FILE_ATTRIBUTES;
+}
+
+void os::dll_build_name(char *buffer, size_t buflen,
+ const char* pname, const char* fname) {
+ // Copied from libhpi
+ const size_t pnamelen = pname ? strlen(pname) : 0;
+ const char c = (pnamelen > 0) ? pname[pnamelen-1] : 0;
+
+ // Quietly truncates on buffer overflow. Should be an error.
+ if (pnamelen + strlen(fname) + 10 > buflen) {
+ *buffer = '\0';
+ return;
+ }
+
+ if (pnamelen == 0) {
+ jio_snprintf(buffer, buflen, "%s.dll", fname);
+ } else if (c == ':' || c == '\\') {
+ jio_snprintf(buffer, buflen, "%s%s.dll", pname, fname);
+ } else if (strchr(pname, *os::path_separator()) != NULL) {
+ int n;
+ char** pelements = split_path(pname, &n);
+ for (int i = 0 ; i < n ; i++) {
+ char* path = pelements[i];
+ // Really shouldn't be NULL, but check can't hurt
+ size_t plen = (path == NULL) ? 0 : strlen(path);
+ if (plen == 0) {
+ continue; // skip the empty path values
+ }
+ const char lastchar = path[plen - 1];
+ if (lastchar == ':' || lastchar == '\\') {
+ jio_snprintf(buffer, buflen, "%s%s.dll", path, fname);
+ } else {
+ jio_snprintf(buffer, buflen, "%s\\%s.dll", path, fname);
+ }
+ if (file_exists(buffer)) {
+ break;
+ }
+ }
+ // release the storage
+ for (int i = 0 ; i < n ; i++) {
+ if (pelements[i] != NULL) {
+ FREE_C_HEAP_ARRAY(char, pelements[i]);
+ }
+ }
+ if (pelements != NULL) {
+ FREE_C_HEAP_ARRAY(char*, pelements);
+ }
+ } else {
+ jio_snprintf(buffer, buflen, "%s\\%s.dll", pname, fname);
+ }
+}
+
// Needs to be in os specific directory because windows requires another
// header file <direct.h>
const char* os::get_current_directory(char *buf, int buflen) {
return _getcwd(buf, buflen);
}
@@ -1256,10 +1322,14 @@
if (offset) *offset = -1;
if (buf) buf[0] = '\0';
return false;
}
+void* os::dll_lookup(void* handle, const char* name) {
+ return GetProcAddress((HMODULE)handle, name);
+}
+
// save the start and end address of jvm.dll into param[0] and param[1]
static int _locate_jvm_dll(int pid, char* mod_fname, address base_addr,
unsigned size, void * param) {
if (!param) return -1;
@@ -1429,10 +1499,14 @@
int pid = os::current_process_id();
st->print_cr("Dynamic libraries:");
enumerate_modules(pid, _print_module, (void *)st);
}
+// function pointer to Windows API "GetNativeSystemInfo".
+typedef void (WINAPI *GetNativeSystemInfo_func_type)(LPSYSTEM_INFO);
+static GetNativeSystemInfo_func_type _GetNativeSystemInfo;
+
void os::print_os_info(outputStream* st) {
st->print("OS:");
OSVERSIONINFOEX osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
@@ -1442,19 +1516,60 @@
st->print_cr("N/A");
return;
}
int os_vers = osvi.dwMajorVersion * 1000 + osvi.dwMinorVersion;
-
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
switch (os_vers) {
case 3051: st->print(" Windows NT 3.51"); break;
case 4000: st->print(" Windows NT 4.0"); break;
case 5000: st->print(" Windows 2000"); break;
case 5001: st->print(" Windows XP"); break;
- case 5002: st->print(" Windows Server 2003 family"); break;
- case 6000: st->print(" Windows Vista"); break;
+ case 5002:
+ case 6000:
+ case 6001: {
+ // Retrieve SYSTEM_INFO from GetNativeSystemInfo call so that we could
+ // find out whether we are running on 64 bit processor or not.
+ SYSTEM_INFO si;
+ ZeroMemory(&si, sizeof(SYSTEM_INFO));
+ // Check to see if _GetNativeSystemInfo has been initialized.
+ if (_GetNativeSystemInfo == NULL) {
+ HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32.dll"));
+ _GetNativeSystemInfo =
+ CAST_TO_FN_PTR(GetNativeSystemInfo_func_type,
+ GetProcAddress(hKernel32,
+ "GetNativeSystemInfo"));
+ if (_GetNativeSystemInfo == NULL)
+ GetSystemInfo(&si);
+ } else {
+ _GetNativeSystemInfo(&si);
+ }
+ if (os_vers == 5002) {
+ if (osvi.wProductType == VER_NT_WORKSTATION &&
+ si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
+ st->print(" Windows XP x64 Edition");
+ else
+ st->print(" Windows Server 2003 family");
+ } else if (os_vers == 6000) {
+ if (osvi.wProductType == VER_NT_WORKSTATION)
+ st->print(" Windows Vista");
+ else
+ st->print(" Windows Server 2008");
+ if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
+ st->print(" , 64 bit");
+ } else { // os_vers == 6001
+ if (osvi.wProductType == VER_NT_WORKSTATION) {
+ st->print(" Windows 7");
+ } else {
+ // Unrecognized windows, print out its major and minor versions
+ st->print(" Windows NT %d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion);
+ }
+ if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
+ st->print(" , 64 bit");
+ }
+ break;
+ }
default: // future windows, print out its major and minor versions
st->print(" Windows NT %d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion);
}
} else {
switch (os_vers) {
@@ -1463,11 +1578,10 @@
case 4090: st->print(" Windows Me"); break;
default: // future windows, print out its major and minor versions
st->print(" Windows %d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion);
}
}
-
st->print(" Build %d", osvi.dwBuildNumber);
st->print(" %s", osvi.szCSDVersion); // service pack
st->cr();
}
@@ -1957,14 +2071,15 @@
// In conservative mode, don't unguard unless the address is in the VM
if (UnguardOnExecutionViolation > 0 && addr != last_addr &&
(UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) {
- // Unguard and retry
+ // Set memory to RWX and retry
address page_start =
(address) align_size_down((intptr_t) addr, (intptr_t) page_size);
- bool res = os::unguard_memory((char*) page_start, page_size);
+ bool res = os::protect_memory((char*) page_start, page_size,
+ os::MEM_PROT_RWX);
if (PrintMiscellaneous && Verbose) {
char buf[256];
jio_snprintf(buf, sizeof(buf), "Execution protection violation "
"at " INTPTR_FORMAT
@@ -2154,19 +2269,14 @@
//
// Check for implicit null
// We only expect null pointers in the stubs (vtable)
// the rest are checked explicitly now.
//
- CodeBlob* cb = CodeCache::find_blob(pc);
- if (cb != NULL) {
- if (VtableStubs::stub_containing(pc) != NULL) {
if (((uintptr_t)addr) < os::vm_page_size() ) {
// an access to the first page of VM--assume it is a null pointer
- return Handle_Exception(exceptionInfo,
- SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL));
- }
- }
+ address stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
+ if (stub != NULL) return Handle_Exception(exceptionInfo, stub);
}
}
} // in_java
// IA64 doesn't use implicit null checking yet. So we shouldn't
@@ -2178,12 +2288,12 @@
#else /* !IA64 */
// Windows 98 reports faulting addresses incorrectly
if (!MacroAssembler::needs_explicit_null_check((intptr_t)addr) ||
!os::win32::is_nt()) {
- return Handle_Exception(exceptionInfo,
- SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL));
+ address stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
+ if (stub != NULL) return Handle_Exception(exceptionInfo, stub);
}
report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord,
exceptionInfo->ContextRecord);
return EXCEPTION_CONTINUE_SEARCH;
#endif
@@ -2524,14 +2634,113 @@
// and committed in a single VirtualAlloc() call. This may change in the
// future, but with Windows 2003 it's not possible to commit on demand.
return false;
}
+bool os::can_execute_large_page_memory() {
+ return true;
+}
+
char* os::reserve_memory_special(size_t bytes) {
+
+ if (UseLargePagesIndividualAllocation) {
+ if (TracePageSizes && Verbose) {
+ tty->print_cr("Reserving large pages individually.");
+ }
+ char * p_buf;
+ // first reserve enough address space in advance since we want to be
+ // able to break a single contiguous virtual address range into multiple
+ // large page commits but WS2003 does not allow reserving large page space
+ // so we just use 4K pages for reserve, this gives us a legal contiguous
+ // address space. then we will deallocate that reservation, and re alloc
+ // using large pages
+ const size_t size_of_reserve = bytes + _large_page_size;
+ if (bytes > size_of_reserve) {
+ // Overflowed.
+ warning("Individually allocated large pages failed, "
+ "use -XX:-UseLargePagesIndividualAllocation to turn off");
+ return NULL;
+ }
+ p_buf = (char *) VirtualAlloc(NULL,
+ size_of_reserve, // size of Reserve
+ MEM_RESERVE,
+ PAGE_EXECUTE_READWRITE);
+ // If reservation failed, return NULL
+ if (p_buf == NULL) return NULL;
+
+ release_memory(p_buf, bytes + _large_page_size);
+ // round up to page boundary. If the size_of_reserve did not
+ // overflow and the reservation did not fail, this align up
+ // should not overflow.
+ p_buf = (char *) align_size_up((size_t)p_buf, _large_page_size);
+
+ // now go through and allocate one page at a time until all bytes are
+ // allocated
+ size_t bytes_remaining = align_size_up(bytes, _large_page_size);
+ // An overflow of align_size_up() would have been caught above
+ // in the calculation of size_of_reserve.
+ char * next_alloc_addr = p_buf;
+
+#ifdef ASSERT
+ // Variable for the failure injection
+ long ran_num = os::random();
+ size_t fail_after = ran_num % bytes;
+#endif
+
+ while (bytes_remaining) {
+ size_t bytes_to_rq = MIN2(bytes_remaining, _large_page_size);
+ // Note allocate and commit
+ char * p_new;
+
+#ifdef ASSERT
+ bool inject_error = LargePagesIndividualAllocationInjectError &&
+ (bytes_remaining <= fail_after);
+#else
+ const bool inject_error = false;
+#endif
+
+ if (inject_error) {
+ p_new = NULL;
+ } else {
+ p_new = (char *) VirtualAlloc(next_alloc_addr,
+ bytes_to_rq,
+ MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES,
+ PAGE_EXECUTE_READWRITE);
+ }
+
+ if (p_new == NULL) {
+ // Free any allocated pages
+ if (next_alloc_addr > p_buf) {
+ // Some memory was committed so release it.
+ size_t bytes_to_release = bytes - bytes_remaining;
+ release_memory(p_buf, bytes_to_release);
+ }
+#ifdef ASSERT
+ if (UseLargePagesIndividualAllocation &&
+ LargePagesIndividualAllocationInjectError) {
+ if (TracePageSizes && Verbose) {
+ tty->print_cr("Reserving large pages individually failed.");
+ }
+ }
+#endif
+ return NULL;
+ }
+ bytes_remaining -= bytes_to_rq;
+ next_alloc_addr += bytes_to_rq;
+ }
+
+ return p_buf;
+
+ } else {
+ // normal policy just allocate it all at once
DWORD flag = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
- char * res = (char *)VirtualAlloc(NULL, bytes, flag, PAGE_READWRITE);
+ char * res = (char *)VirtualAlloc(NULL,
+ bytes,
+ flag,
+ PAGE_EXECUTE_READWRITE);
return res;
+ }
}
bool os::release_memory_special(char* base, size_t bytes) {
return release_memory(base, bytes);
}
@@ -2567,29 +2776,53 @@
bool os::release_memory(char* addr, size_t bytes) {
return VirtualFree(addr, 0, MEM_RELEASE) != 0;
}
-bool os::protect_memory(char* addr, size_t bytes) {
+// Set protections specified
+bool os::protect_memory(char* addr, size_t bytes, ProtType prot,
+ bool is_committed) {
+ unsigned int p = 0;
+ switch (prot) {
+ case MEM_PROT_NONE: p = PAGE_NOACCESS; break;
+ case MEM_PROT_READ: p = PAGE_READONLY; break;
+ case MEM_PROT_RW: p = PAGE_READWRITE; break;
+ case MEM_PROT_RWX: p = PAGE_EXECUTE_READWRITE; break;
+ default:
+ ShouldNotReachHere();
+ }
+
DWORD old_status;
- return VirtualProtect(addr, bytes, PAGE_READONLY, &old_status) != 0;
+
+ // Strange enough, but on Win32 one can change protection only for committed
+ // memory, not a big deal anyway, as bytes less or equal than 64K
+ if (!is_committed && !commit_memory(addr, bytes)) {
+ fatal("cannot commit protection page");
+ }
+ // One cannot use os::guard_memory() here, as on Win32 guard page
+ // have different (one-shot) semantics, from MSDN on PAGE_GUARD:
+ //
+ // Pages in the region become guard pages. Any attempt to access a guard page
+ // causes the system to raise a STATUS_GUARD_PAGE exception and turn off
+ // the guard page status. Guard pages thus act as a one-time access alarm.
+ return VirtualProtect(addr, bytes, p, &old_status) != 0;
}
bool os::guard_memory(char* addr, size_t bytes) {
DWORD old_status;
- return VirtualProtect(addr, bytes, PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_status) != 0;
+ return VirtualProtect(addr, bytes, PAGE_READWRITE | PAGE_GUARD, &old_status) != 0;
}
bool os::unguard_memory(char* addr, size_t bytes) {
DWORD old_status;
- return VirtualProtect(addr, bytes, PAGE_EXECUTE_READWRITE, &old_status) != 0;
+ return VirtualProtect(addr, bytes, PAGE_READWRITE, &old_status) != 0;
}
void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) { }
void os::free_memory(char *addr, size_t bytes) { }
void os::numa_make_global(char *addr, size_t bytes) { }
-void os::numa_make_local(char *addr, size_t bytes) { }
+void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { }
bool os::numa_topology_changed() { return false; }
size_t os::numa_get_groups_num() { return 1; }
int os::numa_get_group_id() { return 0; }
size_t os::numa_get_leaf_groups(int *ids, size_t size) {
if (size > 0) {
@@ -2891,10 +3124,11 @@
intx os::win32::_os_thread_limit = 0;
volatile intx os::win32::_os_thread_count = 0;
bool os::win32::_is_nt = false;
+bool os::win32::_is_windows_2003 = false;
void os::win32::initialize_system_info() {
SYSTEM_INFO si;
GetSystemInfo(&si);
@@ -2913,11 +3147,19 @@
OSVERSIONINFO oi;
oi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&oi);
switch(oi.dwPlatformId) {
case VER_PLATFORM_WIN32_WINDOWS: _is_nt = false; break;
- case VER_PLATFORM_WIN32_NT: _is_nt = true; break;
+ case VER_PLATFORM_WIN32_NT:
+ _is_nt = true;
+ {
+ int os_vers = oi.dwMajorVersion * 1000 + oi.dwMinorVersion;
+ if (os_vers == 5002) {
+ _is_windows_2003 = true;
+ }
+ }
+ break;
default: fatal("Unknown platform");
}
_default_stack_size = os::current_stack_size();
assert(_default_stack_size > (size_t) _vm_page_size, "invalid stack size");
@@ -3011,10 +3253,14 @@
#ifndef PRODUCT
if (is_MP()) {
NoYieldsInMicrolock = true;
}
#endif
+ // This may be overridden later when argument processing is done.
+ FLAG_SET_ERGO(bool, UseLargePagesIndividualAllocation,
+ os::win32::is_windows_2003());
+
// Initialize main_process and main_thread
main_process = GetCurrentProcess(); // Remember main_process is a pseudo handle
if (!DuplicateHandle(main_process, GetCurrentThread(), main_process,
&main_thread, THREAD_ALL_ACCESS, false, 0)) {
fatal("DuplicateHandle failed\n");
@@ -3120,11 +3366,11 @@
//
// TODO: consider performing a similar calculation for commit size instead
// as reserve size, since on a 64-bit platform we'll run into that more
// often than running out of virtual memory space. We can use the
// lower value of the two calculations as the os_thread_limit.
- size_t max_address_space = ((size_t)1 << (BitsPerOop - 1)) - (200 * K * K);
+ size_t max_address_space = ((size_t)1 << (BitsPerWord - 1)) - (200 * K * K);
win32::_os_thread_limit = (intx)(max_address_space / actual_reserve_size);
// at exit methods are called in the reverse order of their registration.
// there is no limit to the number of functions registered. atexit does
// not set errno.
@@ -3153,10 +3399,14 @@
#endif
// initialize thread priority policy
prio_init();
+ if (UseNUMA && !ForceNUMA) {
+ UseNUMA = false; // Currently unsupported.
+ }
+
return JNI_OK;
}
// Mark the polling page as unreadable