aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: // Must be at least Windows 2000 or XP to use IsDebuggerPresent aoqi@0: #define _WIN32_WINNT 0x500 aoqi@0: aoqi@0: // no precompiled headers aoqi@0: #include "classfile/classLoader.hpp" aoqi@0: #include "classfile/systemDictionary.hpp" aoqi@0: #include "classfile/vmSymbols.hpp" aoqi@0: #include "code/icBuffer.hpp" aoqi@0: #include "code/vtableStubs.hpp" aoqi@0: #include "compiler/compileBroker.hpp" aoqi@0: #include "compiler/disassembler.hpp" aoqi@0: #include "interpreter/interpreter.hpp" aoqi@0: #include "jvm_windows.h" aoqi@0: #include "memory/allocation.inline.hpp" aoqi@0: #include "memory/filemap.hpp" aoqi@0: #include "mutex_windows.inline.hpp" aoqi@0: #include "oops/oop.inline.hpp" aoqi@0: #include "os_share_windows.hpp" aoqi@0: #include "prims/jniFastGetField.hpp" aoqi@0: #include "prims/jvm.h" aoqi@0: #include "prims/jvm_misc.hpp" aoqi@0: #include "runtime/arguments.hpp" aoqi@0: #include "runtime/extendedPC.hpp" aoqi@0: #include "runtime/globals.hpp" aoqi@0: #include "runtime/interfaceSupport.hpp" aoqi@0: #include "runtime/java.hpp" aoqi@0: #include "runtime/javaCalls.hpp" aoqi@0: #include "runtime/mutexLocker.hpp" aoqi@0: #include "runtime/objectMonitor.hpp" aoqi@0: #include "runtime/osThread.hpp" aoqi@0: #include "runtime/perfMemory.hpp" aoqi@0: #include "runtime/sharedRuntime.hpp" aoqi@0: #include "runtime/statSampler.hpp" aoqi@0: #include "runtime/stubRoutines.hpp" aoqi@0: #include "runtime/thread.inline.hpp" aoqi@0: #include "runtime/threadCritical.hpp" aoqi@0: #include "runtime/timer.hpp" aoqi@0: #include "services/attachListener.hpp" aoqi@0: #include "services/memTracker.hpp" aoqi@0: #include "services/runtimeService.hpp" aoqi@0: #include "utilities/decoder.hpp" aoqi@0: #include "utilities/defaultStream.hpp" aoqi@0: #include "utilities/events.hpp" aoqi@0: #include "utilities/growableArray.hpp" aoqi@0: #include "utilities/vmError.hpp" aoqi@0: aoqi@0: #ifdef _DEBUG aoqi@0: #include aoqi@0: #endif aoqi@0: aoqi@0: aoqi@0: #include aoqi@0: #include aoqi@0: #include aoqi@0: #include aoqi@0: #include aoqi@0: #include aoqi@0: aoqi@0: #include aoqi@0: #include aoqi@0: #include aoqi@0: #include aoqi@0: #include aoqi@0: #include aoqi@0: #include // For _beginthreadex(), _endthreadex() aoqi@0: #include // For os::dll_address_to_function_name aoqi@0: /* for enumerating dll libraries */ aoqi@0: #include aoqi@0: aoqi@0: // for timer info max values which include all bits aoqi@0: #define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) aoqi@0: aoqi@0: // For DLL loading/load error detection aoqi@0: // Values of PE COFF aoqi@0: #define IMAGE_FILE_PTR_TO_SIGNATURE 0x3c aoqi@0: #define IMAGE_FILE_SIGNATURE_LENGTH 4 aoqi@0: aoqi@0: static HANDLE main_process; aoqi@0: static HANDLE main_thread; aoqi@0: static int main_thread_id; aoqi@0: aoqi@0: static FILETIME process_creation_time; aoqi@0: static FILETIME process_exit_time; aoqi@0: static FILETIME process_user_time; aoqi@0: static FILETIME process_kernel_time; aoqi@0: aoqi@0: #ifdef _M_IA64 aoqi@0: #define __CPU__ ia64 aoqi@0: #elif _M_AMD64 aoqi@0: #define __CPU__ amd64 aoqi@0: #else aoqi@0: #define __CPU__ i486 aoqi@0: #endif aoqi@0: aoqi@0: // save DLL module handle, used by GetModuleFileName aoqi@0: aoqi@0: HINSTANCE vm_lib_handle; aoqi@0: aoqi@0: BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) { aoqi@0: switch (reason) { aoqi@0: case DLL_PROCESS_ATTACH: aoqi@0: vm_lib_handle = hinst; aoqi@0: if(ForceTimeHighResolution) aoqi@0: timeBeginPeriod(1L); aoqi@0: break; aoqi@0: case DLL_PROCESS_DETACH: aoqi@0: if(ForceTimeHighResolution) aoqi@0: timeEndPeriod(1L); aoqi@0: break; aoqi@0: default: aoqi@0: break; aoqi@0: } aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: static inline double fileTimeAsDouble(FILETIME* time) { aoqi@0: const double high = (double) ((unsigned int) ~0); aoqi@0: const double split = 10000000.0; aoqi@0: double result = (time->dwLowDateTime / split) + aoqi@0: time->dwHighDateTime * (high/split); aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: // Implementation of os aoqi@0: aoqi@0: bool os::getenv(const char* name, char* buffer, int len) { aoqi@0: int result = GetEnvironmentVariable(name, buffer, len); aoqi@0: return result > 0 && result < len; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // No setuid programs under Windows. aoqi@0: bool os::have_special_privileges() { aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // This method is a periodic task to check for misbehaving JNI applications aoqi@0: // under CheckJNI, we can add any periodic checks here. aoqi@0: // For Windows at the moment does nothing aoqi@0: void os::run_periodic_checks() { aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: #ifndef _WIN64 aoqi@0: // previous UnhandledExceptionFilter, if there is one aoqi@0: static LPTOP_LEVEL_EXCEPTION_FILTER prev_uef_handler = NULL; aoqi@0: aoqi@0: LONG WINAPI Handle_FLT_Exception(struct _EXCEPTION_POINTERS* exceptionInfo); aoqi@0: #endif aoqi@0: void os::init_system_properties_values() { aoqi@0: /* sysclasspath, java_home, dll_dir */ aoqi@0: { aoqi@0: char *home_path; aoqi@0: char *dll_path; aoqi@0: char *pslash; aoqi@0: char *bin = "\\bin"; aoqi@0: char home_dir[MAX_PATH]; aoqi@0: aoqi@0: if (!getenv("_ALT_JAVA_HOME_DIR", home_dir, MAX_PATH)) { aoqi@0: os::jvm_path(home_dir, sizeof(home_dir)); aoqi@0: // Found the full path to jvm.dll. aoqi@0: // Now cut the path to /jre if we can. aoqi@0: *(strrchr(home_dir, '\\')) = '\0'; /* get rid of \jvm.dll */ aoqi@0: pslash = strrchr(home_dir, '\\'); aoqi@0: if (pslash != NULL) { aoqi@0: *pslash = '\0'; /* get rid of \{client|server} */ aoqi@0: pslash = strrchr(home_dir, '\\'); aoqi@0: if (pslash != NULL) aoqi@0: *pslash = '\0'; /* get rid of \bin */ aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: home_path = NEW_C_HEAP_ARRAY(char, strlen(home_dir) + 1, mtInternal); aoqi@0: if (home_path == NULL) aoqi@0: return; aoqi@0: strcpy(home_path, home_dir); aoqi@0: Arguments::set_java_home(home_path); aoqi@0: aoqi@0: dll_path = NEW_C_HEAP_ARRAY(char, strlen(home_dir) + strlen(bin) + 1, mtInternal); aoqi@0: if (dll_path == NULL) aoqi@0: return; aoqi@0: strcpy(dll_path, home_dir); aoqi@0: strcat(dll_path, bin); aoqi@0: Arguments::set_dll_dir(dll_path); aoqi@0: aoqi@0: if (!set_boot_path('\\', ';')) aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: /* library_path */ aoqi@0: #define EXT_DIR "\\lib\\ext" aoqi@0: #define BIN_DIR "\\bin" aoqi@0: #define PACKAGE_DIR "\\Sun\\Java" aoqi@0: { aoqi@0: /* Win32 library search order (See the documentation for LoadLibrary): aoqi@0: * aoqi@0: * 1. The directory from which application is loaded. aoqi@0: * 2. The system wide Java Extensions directory (Java only) aoqi@0: * 3. System directory (GetSystemDirectory) aoqi@0: * 4. Windows directory (GetWindowsDirectory) aoqi@0: * 5. The PATH environment variable aoqi@0: * 6. The current directory aoqi@0: */ aoqi@0: aoqi@0: char *library_path; aoqi@0: char tmp[MAX_PATH]; aoqi@0: char *path_str = ::getenv("PATH"); aoqi@0: aoqi@0: library_path = NEW_C_HEAP_ARRAY(char, MAX_PATH * 5 + sizeof(PACKAGE_DIR) + aoqi@0: sizeof(BIN_DIR) + (path_str ? strlen(path_str) : 0) + 10, mtInternal); aoqi@0: aoqi@0: library_path[0] = '\0'; aoqi@0: aoqi@0: GetModuleFileName(NULL, tmp, sizeof(tmp)); aoqi@0: *(strrchr(tmp, '\\')) = '\0'; aoqi@0: strcat(library_path, tmp); aoqi@0: aoqi@0: GetWindowsDirectory(tmp, sizeof(tmp)); aoqi@0: strcat(library_path, ";"); aoqi@0: strcat(library_path, tmp); aoqi@0: strcat(library_path, PACKAGE_DIR BIN_DIR); aoqi@0: aoqi@0: GetSystemDirectory(tmp, sizeof(tmp)); aoqi@0: strcat(library_path, ";"); aoqi@0: strcat(library_path, tmp); aoqi@0: aoqi@0: GetWindowsDirectory(tmp, sizeof(tmp)); aoqi@0: strcat(library_path, ";"); aoqi@0: strcat(library_path, tmp); aoqi@0: aoqi@0: if (path_str) { aoqi@0: strcat(library_path, ";"); aoqi@0: strcat(library_path, path_str); aoqi@0: } aoqi@0: aoqi@0: strcat(library_path, ";."); aoqi@0: aoqi@0: Arguments::set_library_path(library_path); aoqi@0: FREE_C_HEAP_ARRAY(char, library_path, mtInternal); aoqi@0: } aoqi@0: aoqi@0: /* Default extensions directory */ aoqi@0: { aoqi@0: char path[MAX_PATH]; aoqi@0: char buf[2 * MAX_PATH + 2 * sizeof(EXT_DIR) + sizeof(PACKAGE_DIR) + 1]; aoqi@0: GetWindowsDirectory(path, MAX_PATH); aoqi@0: sprintf(buf, "%s%s;%s%s%s", Arguments::get_java_home(), EXT_DIR, aoqi@0: path, PACKAGE_DIR, EXT_DIR); aoqi@0: Arguments::set_ext_dirs(buf); aoqi@0: } aoqi@0: #undef EXT_DIR aoqi@0: #undef BIN_DIR aoqi@0: #undef PACKAGE_DIR aoqi@0: aoqi@0: /* Default endorsed standards directory. */ aoqi@0: { aoqi@0: #define ENDORSED_DIR "\\lib\\endorsed" aoqi@0: size_t len = strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR); aoqi@0: char * buf = NEW_C_HEAP_ARRAY(char, len, mtInternal); aoqi@0: sprintf(buf, "%s%s", Arguments::get_java_home(), ENDORSED_DIR); aoqi@0: Arguments::set_endorsed_dirs(buf); aoqi@0: #undef ENDORSED_DIR aoqi@0: } aoqi@0: aoqi@0: #ifndef _WIN64 aoqi@0: // set our UnhandledExceptionFilter and save any previous one aoqi@0: prev_uef_handler = SetUnhandledExceptionFilter(Handle_FLT_Exception); aoqi@0: #endif aoqi@0: aoqi@0: // Done aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: void os::breakpoint() { aoqi@0: DebugBreak(); aoqi@0: } aoqi@0: aoqi@0: // Invoked from the BREAKPOINT Macro aoqi@0: extern "C" void breakpoint() { aoqi@0: os::breakpoint(); aoqi@0: } aoqi@0: aoqi@0: /* aoqi@0: * RtlCaptureStackBackTrace Windows API may not exist prior to Windows XP. aoqi@0: * So far, this method is only used by Native Memory Tracking, which is aoqi@0: * only supported on Windows XP or later. aoqi@0: */ aoqi@0: address os::get_caller_pc(int n) { aoqi@0: #ifdef _NMT_NOINLINE_ aoqi@0: n ++; aoqi@0: #endif aoqi@0: address pc; aoqi@0: if (os::Kernel32Dll::RtlCaptureStackBackTrace(n + 1, 1, (PVOID*)&pc, NULL) == 1) { aoqi@0: return pc; aoqi@0: } aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // os::current_stack_base() aoqi@0: // aoqi@0: // Returns the base of the stack, which is the stack's aoqi@0: // starting address. This function must be called aoqi@0: // while running on the stack of the thread being queried. aoqi@0: aoqi@0: address os::current_stack_base() { aoqi@0: MEMORY_BASIC_INFORMATION minfo; aoqi@0: address stack_bottom; aoqi@0: size_t stack_size; aoqi@0: aoqi@0: VirtualQuery(&minfo, &minfo, sizeof(minfo)); aoqi@0: stack_bottom = (address)minfo.AllocationBase; aoqi@0: stack_size = minfo.RegionSize; aoqi@0: aoqi@0: // Add up the sizes of all the regions with the same aoqi@0: // AllocationBase. aoqi@0: while( 1 ) aoqi@0: { aoqi@0: VirtualQuery(stack_bottom+stack_size, &minfo, sizeof(minfo)); aoqi@0: if ( stack_bottom == (address)minfo.AllocationBase ) aoqi@0: stack_size += minfo.RegionSize; aoqi@0: else aoqi@0: break; aoqi@0: } aoqi@0: aoqi@0: #ifdef _M_IA64 aoqi@0: // IA64 has memory and register stacks aoqi@0: // aoqi@0: // This is the stack layout you get on NT/IA64 if you specify 1MB stack limit aoqi@0: // at thread creation (1MB backing store growing upwards, 1MB memory stack aoqi@0: // growing downwards, 2MB summed up) aoqi@0: // aoqi@0: // ... aoqi@0: // ------- top of stack (high address) ----- aoqi@0: // | aoqi@0: // | 1MB aoqi@0: // | Backing Store (Register Stack) aoqi@0: // | aoqi@0: // | / \ aoqi@0: // | | aoqi@0: // | | aoqi@0: // | | aoqi@0: // ------------------------ stack base ----- aoqi@0: // | 1MB aoqi@0: // | Memory Stack aoqi@0: // | aoqi@0: // | | aoqi@0: // | | aoqi@0: // | | aoqi@0: // | \ / aoqi@0: // | aoqi@0: // ----- bottom of stack (low address) ----- aoqi@0: // ... aoqi@0: aoqi@0: stack_size = stack_size / 2; aoqi@0: #endif aoqi@0: return stack_bottom + stack_size; aoqi@0: } aoqi@0: aoqi@0: size_t os::current_stack_size() { aoqi@0: size_t sz; aoqi@0: MEMORY_BASIC_INFORMATION minfo; aoqi@0: VirtualQuery(&minfo, &minfo, sizeof(minfo)); aoqi@0: sz = (size_t)os::current_stack_base() - (size_t)minfo.AllocationBase; aoqi@0: return sz; aoqi@0: } aoqi@0: aoqi@0: struct tm* os::localtime_pd(const time_t* clock, struct tm* res) { aoqi@0: const struct tm* time_struct_ptr = localtime(clock); aoqi@0: if (time_struct_ptr != NULL) { aoqi@0: *res = *time_struct_ptr; aoqi@0: return res; aoqi@0: } aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo); aoqi@0: aoqi@0: // Thread start routine for all new Java threads aoqi@0: static unsigned __stdcall java_start(Thread* thread) { aoqi@0: // Try to randomize the cache line index of hot stack frames. aoqi@0: // This helps when threads of the same stack traces evict each other's aoqi@0: // cache lines. The threads can be either from the same JVM instance, or aoqi@0: // from different JVM instances. The benefit is especially true for aoqi@0: // processors with hyperthreading technology. aoqi@0: static int counter = 0; aoqi@0: int pid = os::current_process_id(); aoqi@0: _alloca(((pid ^ counter++) & 7) * 128); aoqi@0: aoqi@0: OSThread* osthr = thread->osthread(); aoqi@0: assert(osthr->get_state() == RUNNABLE, "invalid os thread state"); aoqi@0: aoqi@0: if (UseNUMA) { aoqi@0: int lgrp_id = os::numa_get_group_id(); aoqi@0: if (lgrp_id != -1) { aoqi@0: thread->set_lgrp_id(lgrp_id); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // Install a win32 structured exception handler around every thread created aoqi@0: // by VM, so VM can genrate error dump when an exception occurred in non- aoqi@0: // Java thread (e.g. VM thread). aoqi@0: __try { aoqi@0: thread->run(); aoqi@0: } __except(topLevelExceptionFilter( aoqi@0: (_EXCEPTION_POINTERS*)_exception_info())) { aoqi@0: // Nothing to do. aoqi@0: } aoqi@0: aoqi@0: // One less thread is executing aoqi@0: // When the VMThread gets here, the main thread may have already exited aoqi@0: // which frees the CodeHeap containing the Atomic::add code aoqi@0: if (thread != VMThread::vm_thread() && VMThread::vm_thread() != NULL) { aoqi@0: Atomic::dec_ptr((intptr_t*)&os::win32::_os_thread_count); aoqi@0: } aoqi@0: aoqi@0: return 0; aoqi@0: } aoqi@0: aoqi@0: static OSThread* create_os_thread(Thread* thread, HANDLE thread_handle, int thread_id) { aoqi@0: // Allocate the OSThread object aoqi@0: OSThread* osthread = new OSThread(NULL, NULL); aoqi@0: if (osthread == NULL) return NULL; aoqi@0: aoqi@0: // Initialize support for Java interrupts aoqi@0: HANDLE interrupt_event = CreateEvent(NULL, true, false, NULL); aoqi@0: if (interrupt_event == NULL) { aoqi@0: delete osthread; aoqi@0: return NULL; aoqi@0: } aoqi@0: osthread->set_interrupt_event(interrupt_event); aoqi@0: aoqi@0: // Store info on the Win32 thread into the OSThread aoqi@0: osthread->set_thread_handle(thread_handle); aoqi@0: osthread->set_thread_id(thread_id); aoqi@0: aoqi@0: if (UseNUMA) { aoqi@0: int lgrp_id = os::numa_get_group_id(); aoqi@0: if (lgrp_id != -1) { aoqi@0: thread->set_lgrp_id(lgrp_id); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Initial thread state is INITIALIZED, not SUSPENDED aoqi@0: osthread->set_state(INITIALIZED); aoqi@0: aoqi@0: return osthread; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: bool os::create_attached_thread(JavaThread* thread) { aoqi@0: #ifdef ASSERT aoqi@0: thread->verify_not_published(); aoqi@0: #endif aoqi@0: HANDLE thread_h; aoqi@0: if (!DuplicateHandle(main_process, GetCurrentThread(), GetCurrentProcess(), aoqi@0: &thread_h, THREAD_ALL_ACCESS, false, 0)) { aoqi@0: fatal("DuplicateHandle failed\n"); aoqi@0: } aoqi@0: OSThread* osthread = create_os_thread(thread, thread_h, aoqi@0: (int)current_thread_id()); aoqi@0: if (osthread == NULL) { aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: // Initial thread state is RUNNABLE aoqi@0: osthread->set_state(RUNNABLE); aoqi@0: aoqi@0: thread->set_osthread(osthread); aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: bool os::create_main_thread(JavaThread* thread) { aoqi@0: #ifdef ASSERT aoqi@0: thread->verify_not_published(); aoqi@0: #endif aoqi@0: if (_starting_thread == NULL) { aoqi@0: _starting_thread = create_os_thread(thread, main_thread, main_thread_id); aoqi@0: if (_starting_thread == NULL) { aoqi@0: return false; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // The primordial thread is runnable from the start) aoqi@0: _starting_thread->set_state(RUNNABLE); aoqi@0: aoqi@0: thread->set_osthread(_starting_thread); aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: // Allocate and initialize a new OSThread aoqi@0: bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { aoqi@0: unsigned thread_id; aoqi@0: aoqi@0: // Allocate the OSThread object aoqi@0: OSThread* osthread = new OSThread(NULL, NULL); aoqi@0: if (osthread == NULL) { aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: // Initialize support for Java interrupts aoqi@0: HANDLE interrupt_event = CreateEvent(NULL, true, false, NULL); aoqi@0: if (interrupt_event == NULL) { aoqi@0: delete osthread; aoqi@0: return NULL; aoqi@0: } aoqi@0: osthread->set_interrupt_event(interrupt_event); aoqi@0: osthread->set_interrupted(false); aoqi@0: aoqi@0: thread->set_osthread(osthread); aoqi@0: aoqi@0: if (stack_size == 0) { aoqi@0: switch (thr_type) { aoqi@0: case os::java_thread: aoqi@0: // Java threads use ThreadStackSize which default value can be changed with the flag -Xss aoqi@0: if (JavaThread::stack_size_at_create() > 0) aoqi@0: stack_size = JavaThread::stack_size_at_create(); aoqi@0: break; aoqi@0: case os::compiler_thread: aoqi@0: if (CompilerThreadStackSize > 0) { aoqi@0: stack_size = (size_t)(CompilerThreadStackSize * K); aoqi@0: break; aoqi@0: } // else fall through: aoqi@0: // use VMThreadStackSize if CompilerThreadStackSize is not defined aoqi@0: case os::vm_thread: aoqi@0: case os::pgc_thread: aoqi@0: case os::cgc_thread: aoqi@0: case os::watcher_thread: aoqi@0: if (VMThreadStackSize > 0) stack_size = (size_t)(VMThreadStackSize * K); aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Create the Win32 thread aoqi@0: // aoqi@0: // Contrary to what MSDN document says, "stack_size" in _beginthreadex() aoqi@0: // does not specify stack size. Instead, it specifies the size of aoqi@0: // initially committed space. The stack size is determined by aoqi@0: // PE header in the executable. If the committed "stack_size" is larger aoqi@0: // than default value in the PE header, the stack is rounded up to the aoqi@0: // nearest multiple of 1MB. For example if the launcher has default aoqi@0: // stack size of 320k, specifying any size less than 320k does not aoqi@0: // affect the actual stack size at all, it only affects the initial aoqi@0: // commitment. On the other hand, specifying 'stack_size' larger than aoqi@0: // default value may cause significant increase in memory usage, because aoqi@0: // not only the stack space will be rounded up to MB, but also the aoqi@0: // entire space is committed upfront. aoqi@0: // aoqi@0: // Finally Windows XP added a new flag 'STACK_SIZE_PARAM_IS_A_RESERVATION' aoqi@0: // for CreateThread() that can treat 'stack_size' as stack size. However we aoqi@0: // are not supposed to call CreateThread() directly according to MSDN aoqi@0: // document because JVM uses C runtime library. The good news is that the aoqi@0: // flag appears to work with _beginthredex() as well. aoqi@0: aoqi@0: #ifndef STACK_SIZE_PARAM_IS_A_RESERVATION aoqi@0: #define STACK_SIZE_PARAM_IS_A_RESERVATION (0x10000) aoqi@0: #endif aoqi@0: aoqi@0: HANDLE thread_handle = aoqi@0: (HANDLE)_beginthreadex(NULL, aoqi@0: (unsigned)stack_size, aoqi@0: (unsigned (__stdcall *)(void*)) java_start, aoqi@0: thread, aoqi@0: CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, aoqi@0: &thread_id); aoqi@0: if (thread_handle == NULL) { aoqi@0: // perhaps STACK_SIZE_PARAM_IS_A_RESERVATION is not supported, try again aoqi@0: // without the flag. aoqi@0: thread_handle = aoqi@0: (HANDLE)_beginthreadex(NULL, aoqi@0: (unsigned)stack_size, aoqi@0: (unsigned (__stdcall *)(void*)) java_start, aoqi@0: thread, aoqi@0: CREATE_SUSPENDED, aoqi@0: &thread_id); aoqi@0: } aoqi@0: if (thread_handle == NULL) { aoqi@0: // Need to clean up stuff we've allocated so far aoqi@0: CloseHandle(osthread->interrupt_event()); aoqi@0: thread->set_osthread(NULL); aoqi@0: delete osthread; aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: Atomic::inc_ptr((intptr_t*)&os::win32::_os_thread_count); aoqi@0: aoqi@0: // Store info on the Win32 thread into the OSThread aoqi@0: osthread->set_thread_handle(thread_handle); aoqi@0: osthread->set_thread_id(thread_id); aoqi@0: aoqi@0: // Initial thread state is INITIALIZED, not SUSPENDED aoqi@0: osthread->set_state(INITIALIZED); aoqi@0: aoqi@0: // The thread is returned suspended (in state INITIALIZED), and is started higher up in the call chain aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // Free Win32 resources related to the OSThread aoqi@0: void os::free_thread(OSThread* osthread) { aoqi@0: assert(osthread != NULL, "osthread not set"); aoqi@0: CloseHandle(osthread->thread_handle()); aoqi@0: CloseHandle(osthread->interrupt_event()); aoqi@0: delete osthread; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: static int has_performance_count = 0; aoqi@0: static jlong first_filetime; aoqi@0: static jlong initial_performance_count; aoqi@0: static jlong performance_frequency; aoqi@0: aoqi@0: aoqi@0: jlong as_long(LARGE_INTEGER x) { aoqi@0: jlong result = 0; // initialization to avoid warning aoqi@0: set_high(&result, x.HighPart); aoqi@0: set_low(&result, x.LowPart); aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: jlong os::elapsed_counter() { aoqi@0: LARGE_INTEGER count; aoqi@0: if (has_performance_count) { aoqi@0: QueryPerformanceCounter(&count); aoqi@0: return as_long(count) - initial_performance_count; aoqi@0: } else { aoqi@0: FILETIME wt; aoqi@0: GetSystemTimeAsFileTime(&wt); aoqi@0: return (jlong_from(wt.dwHighDateTime, wt.dwLowDateTime) - first_filetime); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: jlong os::elapsed_frequency() { aoqi@0: if (has_performance_count) { aoqi@0: return performance_frequency; aoqi@0: } else { aoqi@0: // the FILETIME time is the number of 100-nanosecond intervals since January 1,1601. aoqi@0: return 10000000; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: julong os::available_memory() { aoqi@0: return win32::available_memory(); aoqi@0: } aoqi@0: aoqi@0: julong os::win32::available_memory() { aoqi@0: // Use GlobalMemoryStatusEx() because GlobalMemoryStatus() may return incorrect aoqi@0: // value if total memory is larger than 4GB aoqi@0: MEMORYSTATUSEX ms; aoqi@0: ms.dwLength = sizeof(ms); aoqi@0: GlobalMemoryStatusEx(&ms); aoqi@0: aoqi@0: return (julong)ms.ullAvailPhys; aoqi@0: } aoqi@0: aoqi@0: julong os::physical_memory() { aoqi@0: return win32::physical_memory(); aoqi@0: } aoqi@0: aoqi@0: bool os::has_allocatable_memory_limit(julong* limit) { aoqi@0: MEMORYSTATUSEX ms; aoqi@0: ms.dwLength = sizeof(ms); aoqi@0: GlobalMemoryStatusEx(&ms); aoqi@0: #ifdef _LP64 aoqi@0: *limit = (julong)ms.ullAvailVirtual; aoqi@0: return true; aoqi@0: #else aoqi@0: // Limit to 1400m because of the 2gb address space wall aoqi@0: *limit = MIN2((julong)1400*M, (julong)ms.ullAvailVirtual); aoqi@0: return true; aoqi@0: #endif aoqi@0: } aoqi@0: aoqi@0: // VC6 lacks DWORD_PTR aoqi@0: #if _MSC_VER < 1300 aoqi@0: typedef UINT_PTR DWORD_PTR; aoqi@0: #endif aoqi@0: aoqi@0: int os::active_processor_count() { aoqi@0: DWORD_PTR lpProcessAffinityMask = 0; aoqi@0: DWORD_PTR lpSystemAffinityMask = 0; aoqi@0: int proc_count = processor_count(); aoqi@0: if (proc_count <= sizeof(UINT_PTR) * BitsPerByte && aoqi@0: GetProcessAffinityMask(GetCurrentProcess(), &lpProcessAffinityMask, &lpSystemAffinityMask)) { aoqi@0: // Nof active processors is number of bits in process affinity mask aoqi@0: int bitcount = 0; aoqi@0: while (lpProcessAffinityMask != 0) { aoqi@0: lpProcessAffinityMask = lpProcessAffinityMask & (lpProcessAffinityMask-1); aoqi@0: bitcount++; aoqi@0: } aoqi@0: return bitcount; aoqi@0: } else { aoqi@0: return proc_count; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void os::set_native_thread_name(const char *name) { aoqi@0: // Not yet implemented. aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: bool os::distribute_processes(uint length, uint* distribution) { aoqi@0: // Not yet implemented. aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: bool os::bind_to_processor(uint processor_id) { aoqi@0: // Not yet implemented. aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: static void initialize_performance_counter() { aoqi@0: LARGE_INTEGER count; aoqi@0: if (QueryPerformanceFrequency(&count)) { aoqi@0: has_performance_count = 1; aoqi@0: performance_frequency = as_long(count); aoqi@0: QueryPerformanceCounter(&count); aoqi@0: initial_performance_count = as_long(count); aoqi@0: } else { aoqi@0: has_performance_count = 0; aoqi@0: FILETIME wt; aoqi@0: GetSystemTimeAsFileTime(&wt); aoqi@0: first_filetime = jlong_from(wt.dwHighDateTime, wt.dwLowDateTime); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: double os::elapsedTime() { aoqi@0: return (double) elapsed_counter() / (double) elapsed_frequency(); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // Windows format: aoqi@0: // The FILETIME structure is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601. aoqi@0: // Java format: aoqi@0: // Java standards require the number of milliseconds since 1/1/1970 aoqi@0: aoqi@0: // Constant offset - calculated using offset() aoqi@0: static jlong _offset = 116444736000000000; aoqi@0: // Fake time counter for reproducible results when debugging aoqi@0: static jlong fake_time = 0; aoqi@0: aoqi@0: #ifdef ASSERT aoqi@0: // Just to be safe, recalculate the offset in debug mode aoqi@0: static jlong _calculated_offset = 0; aoqi@0: static int _has_calculated_offset = 0; aoqi@0: aoqi@0: jlong offset() { aoqi@0: if (_has_calculated_offset) return _calculated_offset; aoqi@0: SYSTEMTIME java_origin; aoqi@0: java_origin.wYear = 1970; aoqi@0: java_origin.wMonth = 1; aoqi@0: java_origin.wDayOfWeek = 0; // ignored aoqi@0: java_origin.wDay = 1; aoqi@0: java_origin.wHour = 0; aoqi@0: java_origin.wMinute = 0; aoqi@0: java_origin.wSecond = 0; aoqi@0: java_origin.wMilliseconds = 0; aoqi@0: FILETIME jot; aoqi@0: if (!SystemTimeToFileTime(&java_origin, &jot)) { aoqi@0: fatal(err_msg("Error = %d\nWindows error", GetLastError())); aoqi@0: } aoqi@0: _calculated_offset = jlong_from(jot.dwHighDateTime, jot.dwLowDateTime); aoqi@0: _has_calculated_offset = 1; aoqi@0: assert(_calculated_offset == _offset, "Calculated and constant time offsets must be equal"); aoqi@0: return _calculated_offset; aoqi@0: } aoqi@0: #else aoqi@0: jlong offset() { aoqi@0: return _offset; aoqi@0: } aoqi@0: #endif aoqi@0: aoqi@0: jlong windows_to_java_time(FILETIME wt) { aoqi@0: jlong a = jlong_from(wt.dwHighDateTime, wt.dwLowDateTime); aoqi@0: return (a - offset()) / 10000; aoqi@0: } aoqi@0: aoqi@0: FILETIME java_to_windows_time(jlong l) { aoqi@0: jlong a = (l * 10000) + offset(); aoqi@0: FILETIME result; aoqi@0: result.dwHighDateTime = high(a); aoqi@0: result.dwLowDateTime = low(a); aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: bool os::supports_vtime() { return true; } aoqi@0: bool os::enable_vtime() { return false; } aoqi@0: bool os::vtime_enabled() { return false; } aoqi@0: aoqi@0: double os::elapsedVTime() { aoqi@0: FILETIME created; aoqi@0: FILETIME exited; aoqi@0: FILETIME kernel; aoqi@0: FILETIME user; aoqi@0: if (GetThreadTimes(GetCurrentThread(), &created, &exited, &kernel, &user) != 0) { aoqi@0: // the resolution of windows_to_java_time() should be sufficient (ms) aoqi@0: return (double) (windows_to_java_time(kernel) + windows_to_java_time(user)) / MILLIUNITS; aoqi@0: } else { aoqi@0: return elapsedTime(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: jlong os::javaTimeMillis() { aoqi@0: if (UseFakeTimers) { aoqi@0: return fake_time++; aoqi@0: } else { aoqi@0: FILETIME wt; aoqi@0: GetSystemTimeAsFileTime(&wt); aoqi@0: return windows_to_java_time(wt); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: jlong os::javaTimeNanos() { aoqi@0: if (!has_performance_count) { aoqi@0: return javaTimeMillis() * NANOSECS_PER_MILLISEC; // the best we can do. aoqi@0: } else { aoqi@0: LARGE_INTEGER current_count; aoqi@0: QueryPerformanceCounter(¤t_count); aoqi@0: double current = as_long(current_count); aoqi@0: double freq = performance_frequency; aoqi@0: jlong time = (jlong)((current/freq) * NANOSECS_PER_SEC); aoqi@0: return time; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) { aoqi@0: if (!has_performance_count) { aoqi@0: // javaTimeMillis() doesn't have much percision, aoqi@0: // but it is not going to wrap -- so all 64 bits aoqi@0: info_ptr->max_value = ALL_64_BITS; aoqi@0: aoqi@0: // this is a wall clock timer, so may skip aoqi@0: info_ptr->may_skip_backward = true; aoqi@0: info_ptr->may_skip_forward = true; aoqi@0: } else { aoqi@0: jlong freq = performance_frequency; aoqi@0: if (freq < NANOSECS_PER_SEC) { aoqi@0: // the performance counter is 64 bits and we will aoqi@0: // be multiplying it -- so no wrap in 64 bits aoqi@0: info_ptr->max_value = ALL_64_BITS; aoqi@0: } else if (freq > NANOSECS_PER_SEC) { aoqi@0: // use the max value the counter can reach to aoqi@0: // determine the max value which could be returned aoqi@0: julong max_counter = (julong)ALL_64_BITS; aoqi@0: info_ptr->max_value = (jlong)(max_counter / (freq / NANOSECS_PER_SEC)); aoqi@0: } else { aoqi@0: // the performance counter is 64 bits and we will aoqi@0: // be using it directly -- so no wrap in 64 bits aoqi@0: info_ptr->max_value = ALL_64_BITS; aoqi@0: } aoqi@0: aoqi@0: // using a counter, so no skipping aoqi@0: info_ptr->may_skip_backward = false; aoqi@0: info_ptr->may_skip_forward = false; aoqi@0: } aoqi@0: info_ptr->kind = JVMTI_TIMER_ELAPSED; // elapsed not CPU time aoqi@0: } aoqi@0: aoqi@0: char* os::local_time_string(char *buf, size_t buflen) { aoqi@0: SYSTEMTIME st; aoqi@0: GetLocalTime(&st); aoqi@0: jio_snprintf(buf, buflen, "%d-%02d-%02d %02d:%02d:%02d", aoqi@0: st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); aoqi@0: return buf; aoqi@0: } aoqi@0: aoqi@0: bool os::getTimesSecs(double* process_real_time, aoqi@0: double* process_user_time, aoqi@0: double* process_system_time) { aoqi@0: HANDLE h_process = GetCurrentProcess(); aoqi@0: FILETIME create_time, exit_time, kernel_time, user_time; aoqi@0: BOOL result = GetProcessTimes(h_process, aoqi@0: &create_time, aoqi@0: &exit_time, aoqi@0: &kernel_time, aoqi@0: &user_time); aoqi@0: if (result != 0) { aoqi@0: FILETIME wt; aoqi@0: GetSystemTimeAsFileTime(&wt); aoqi@0: jlong rtc_millis = windows_to_java_time(wt); aoqi@0: jlong user_millis = windows_to_java_time(user_time); aoqi@0: jlong system_millis = windows_to_java_time(kernel_time); aoqi@0: *process_real_time = ((double) rtc_millis) / ((double) MILLIUNITS); aoqi@0: *process_user_time = ((double) user_millis) / ((double) MILLIUNITS); aoqi@0: *process_system_time = ((double) system_millis) / ((double) MILLIUNITS); aoqi@0: return true; aoqi@0: } else { aoqi@0: return false; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void os::shutdown() { aoqi@0: aoqi@0: // allow PerfMemory to attempt cleanup of any persistent resources aoqi@0: perfMemory_exit(); aoqi@0: aoqi@0: // flush buffered output, finish log files aoqi@0: ostream_abort(); aoqi@0: aoqi@0: // Check for abort hook aoqi@0: abort_hook_t abort_hook = Arguments::abort_hook(); aoqi@0: if (abort_hook != NULL) { aoqi@0: abort_hook(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: static BOOL (WINAPI *_MiniDumpWriteDump) ( HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION, aoqi@0: PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION); aoqi@0: aoqi@0: void os::check_or_create_dump(void* exceptionRecord, void* contextRecord, char* buffer, size_t bufferSize) { aoqi@0: HINSTANCE dbghelp; aoqi@0: EXCEPTION_POINTERS ep; aoqi@0: MINIDUMP_EXCEPTION_INFORMATION mei; aoqi@0: MINIDUMP_EXCEPTION_INFORMATION* pmei; aoqi@0: aoqi@0: HANDLE hProcess = GetCurrentProcess(); aoqi@0: DWORD processId = GetCurrentProcessId(); aoqi@0: HANDLE dumpFile; aoqi@0: MINIDUMP_TYPE dumpType; aoqi@0: static const char* cwd; aoqi@0: aoqi@0: // Default is to always create dump for debug builds, on product builds only dump on server versions of Windows. aoqi@0: #ifndef ASSERT aoqi@0: // If running on a client version of Windows and user has not explicitly enabled dumping aoqi@0: if (!os::win32::is_windows_server() && !CreateMinidumpOnCrash) { aoqi@0: VMError::report_coredump_status("Minidumps are not enabled by default on client versions of Windows", false); aoqi@0: return; aoqi@0: // If running on a server version of Windows and user has explictly disabled dumping aoqi@0: } else if (os::win32::is_windows_server() && !FLAG_IS_DEFAULT(CreateMinidumpOnCrash) && !CreateMinidumpOnCrash) { aoqi@0: VMError::report_coredump_status("Minidump has been disabled from the command line", false); aoqi@0: return; aoqi@0: } aoqi@0: #else aoqi@0: if (!FLAG_IS_DEFAULT(CreateMinidumpOnCrash) && !CreateMinidumpOnCrash) { aoqi@0: VMError::report_coredump_status("Minidump has been disabled from the command line", false); aoqi@0: return; aoqi@0: } aoqi@0: #endif aoqi@0: aoqi@0: dbghelp = os::win32::load_Windows_dll("DBGHELP.DLL", NULL, 0); aoqi@0: aoqi@0: if (dbghelp == NULL) { aoqi@0: VMError::report_coredump_status("Failed to load dbghelp.dll", false); aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: _MiniDumpWriteDump = CAST_TO_FN_PTR( aoqi@0: BOOL(WINAPI *)( HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION, aoqi@0: PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION), aoqi@0: GetProcAddress(dbghelp, "MiniDumpWriteDump")); aoqi@0: aoqi@0: if (_MiniDumpWriteDump == NULL) { aoqi@0: VMError::report_coredump_status("Failed to find MiniDumpWriteDump() in module dbghelp.dll", false); aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: dumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithHandleData); aoqi@0: aoqi@0: // Older versions of dbghelp.h doesn't contain all the dumptypes we want, dbghelp.h with aoqi@0: // API_VERSION_NUMBER 11 or higher contains the ones we want though aoqi@0: #if API_VERSION_NUMBER >= 11 aoqi@0: dumpType = (MINIDUMP_TYPE)(dumpType | MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo | aoqi@0: MiniDumpWithUnloadedModules); aoqi@0: #endif aoqi@0: aoqi@0: cwd = get_current_directory(NULL, 0); aoqi@0: jio_snprintf(buffer, bufferSize, "%s\\hs_err_pid%u.mdmp",cwd, current_process_id()); aoqi@0: dumpFile = CreateFile(buffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); aoqi@0: aoqi@0: if (dumpFile == INVALID_HANDLE_VALUE) { aoqi@0: VMError::report_coredump_status("Failed to create file for dumping", false); aoqi@0: return; aoqi@0: } aoqi@0: if (exceptionRecord != NULL && contextRecord != NULL) { aoqi@0: ep.ContextRecord = (PCONTEXT) contextRecord; aoqi@0: ep.ExceptionRecord = (PEXCEPTION_RECORD) exceptionRecord; aoqi@0: aoqi@0: mei.ThreadId = GetCurrentThreadId(); aoqi@0: mei.ExceptionPointers = &ep; aoqi@0: pmei = &mei; aoqi@0: } else { aoqi@0: pmei = NULL; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // Older versions of dbghelp.dll (the one shipped with Win2003 for example) may not support all aoqi@0: // the dump types we really want. If first call fails, lets fall back to just use MiniDumpWithFullMemory then. aoqi@0: if (_MiniDumpWriteDump(hProcess, processId, dumpFile, dumpType, pmei, NULL, NULL) == false && aoqi@0: _MiniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, pmei, NULL, NULL) == false) { aoqi@0: DWORD error = GetLastError(); aoqi@0: LPTSTR msgbuf = NULL; aoqi@0: aoqi@0: if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | aoqi@0: FORMAT_MESSAGE_FROM_SYSTEM | aoqi@0: FORMAT_MESSAGE_IGNORE_INSERTS, aoqi@0: NULL, error, 0, (LPTSTR)&msgbuf, 0, NULL) != 0) { aoqi@0: aoqi@0: jio_snprintf(buffer, bufferSize, "Call to MiniDumpWriteDump() failed (Error 0x%x: %s)", error, msgbuf); aoqi@0: LocalFree(msgbuf); aoqi@0: } else { aoqi@0: // Call to FormatMessage failed, just include the result from GetLastError aoqi@0: jio_snprintf(buffer, bufferSize, "Call to MiniDumpWriteDump() failed (Error 0x%x)", error); aoqi@0: } aoqi@0: VMError::report_coredump_status(buffer, false); aoqi@0: } else { aoqi@0: VMError::report_coredump_status(buffer, true); aoqi@0: } aoqi@0: aoqi@0: CloseHandle(dumpFile); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: aoqi@0: void os::abort(bool dump_core) aoqi@0: { aoqi@0: os::shutdown(); aoqi@0: // no core dump on Windows aoqi@0: ::exit(1); aoqi@0: } aoqi@0: aoqi@0: // Die immediately, no exit hook, no abort hook, no cleanup. aoqi@0: void os::die() { aoqi@0: _exit(-1); aoqi@0: } aoqi@0: aoqi@0: // Directory routines copied from src/win32/native/java/io/dirent_md.c aoqi@0: // * dirent_md.c 1.15 00/02/02 aoqi@0: // aoqi@0: // The declarations for DIR and struct dirent are in jvm_win32.h. aoqi@0: aoqi@0: /* Caller must have already run dirname through JVM_NativePath, which removes aoqi@0: duplicate slashes and converts all instances of '/' into '\\'. */ aoqi@0: aoqi@0: DIR * aoqi@0: os::opendir(const char *dirname) aoqi@0: { aoqi@0: assert(dirname != NULL, "just checking"); // hotspot change aoqi@0: DIR *dirp = (DIR *)malloc(sizeof(DIR), mtInternal); aoqi@0: DWORD fattr; // hotspot change aoqi@0: char alt_dirname[4] = { 0, 0, 0, 0 }; aoqi@0: aoqi@0: if (dirp == 0) { aoqi@0: errno = ENOMEM; aoqi@0: return 0; aoqi@0: } aoqi@0: aoqi@0: /* aoqi@0: * Win32 accepts "\" in its POSIX stat(), but refuses to treat it aoqi@0: * as a directory in FindFirstFile(). We detect this case here and aoqi@0: * prepend the current drive name. aoqi@0: */ aoqi@0: if (dirname[1] == '\0' && dirname[0] == '\\') { aoqi@0: alt_dirname[0] = _getdrive() + 'A' - 1; aoqi@0: alt_dirname[1] = ':'; aoqi@0: alt_dirname[2] = '\\'; aoqi@0: alt_dirname[3] = '\0'; aoqi@0: dirname = alt_dirname; aoqi@0: } aoqi@0: aoqi@0: dirp->path = (char *)malloc(strlen(dirname) + 5, mtInternal); aoqi@0: if (dirp->path == 0) { aoqi@0: free(dirp, mtInternal); aoqi@0: errno = ENOMEM; aoqi@0: return 0; aoqi@0: } aoqi@0: strcpy(dirp->path, dirname); aoqi@0: aoqi@0: fattr = GetFileAttributes(dirp->path); aoqi@0: if (fattr == 0xffffffff) { aoqi@0: free(dirp->path, mtInternal); aoqi@0: free(dirp, mtInternal); aoqi@0: errno = ENOENT; aoqi@0: return 0; aoqi@0: } else if ((fattr & FILE_ATTRIBUTE_DIRECTORY) == 0) { aoqi@0: free(dirp->path, mtInternal); aoqi@0: free(dirp, mtInternal); aoqi@0: errno = ENOTDIR; aoqi@0: return 0; aoqi@0: } aoqi@0: aoqi@0: /* Append "*.*", or possibly "\\*.*", to path */ aoqi@0: if (dirp->path[1] == ':' aoqi@0: && (dirp->path[2] == '\0' aoqi@0: || (dirp->path[2] == '\\' && dirp->path[3] == '\0'))) { aoqi@0: /* No '\\' needed for cases like "Z:" or "Z:\" */ aoqi@0: strcat(dirp->path, "*.*"); aoqi@0: } else { aoqi@0: strcat(dirp->path, "\\*.*"); aoqi@0: } aoqi@0: aoqi@0: dirp->handle = FindFirstFile(dirp->path, &dirp->find_data); aoqi@0: if (dirp->handle == INVALID_HANDLE_VALUE) { aoqi@0: if (GetLastError() != ERROR_FILE_NOT_FOUND) { aoqi@0: free(dirp->path, mtInternal); aoqi@0: free(dirp, mtInternal); aoqi@0: errno = EACCES; aoqi@0: return 0; aoqi@0: } aoqi@0: } aoqi@0: return dirp; aoqi@0: } aoqi@0: aoqi@0: /* parameter dbuf unused on Windows */ aoqi@0: aoqi@0: struct dirent * aoqi@0: os::readdir(DIR *dirp, dirent *dbuf) aoqi@0: { aoqi@0: assert(dirp != NULL, "just checking"); // hotspot change aoqi@0: if (dirp->handle == INVALID_HANDLE_VALUE) { aoqi@0: return 0; aoqi@0: } aoqi@0: aoqi@0: strcpy(dirp->dirent.d_name, dirp->find_data.cFileName); aoqi@0: aoqi@0: if (!FindNextFile(dirp->handle, &dirp->find_data)) { aoqi@0: if (GetLastError() == ERROR_INVALID_HANDLE) { aoqi@0: errno = EBADF; aoqi@0: return 0; aoqi@0: } aoqi@0: FindClose(dirp->handle); aoqi@0: dirp->handle = INVALID_HANDLE_VALUE; aoqi@0: } aoqi@0: aoqi@0: return &dirp->dirent; aoqi@0: } aoqi@0: aoqi@0: int aoqi@0: os::closedir(DIR *dirp) aoqi@0: { aoqi@0: assert(dirp != NULL, "just checking"); // hotspot change aoqi@0: if (dirp->handle != INVALID_HANDLE_VALUE) { aoqi@0: if (!FindClose(dirp->handle)) { aoqi@0: errno = EBADF; aoqi@0: return -1; aoqi@0: } aoqi@0: dirp->handle = INVALID_HANDLE_VALUE; aoqi@0: } aoqi@0: free(dirp->path, mtInternal); aoqi@0: free(dirp, mtInternal); aoqi@0: return 0; aoqi@0: } aoqi@0: aoqi@0: // This must be hard coded because it's the system's temporary aoqi@0: // directory not the java application's temp directory, ala java.io.tmpdir. aoqi@0: const char* os::get_temp_directory() { aoqi@0: static char path_buf[MAX_PATH]; aoqi@0: if (GetTempPath(MAX_PATH, path_buf)>0) aoqi@0: return path_buf; aoqi@0: else{ aoqi@0: path_buf[0]='\0'; aoqi@0: return path_buf; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: static bool file_exists(const char* filename) { aoqi@0: if (filename == NULL || strlen(filename) == 0) { aoqi@0: return false; aoqi@0: } aoqi@0: return GetFileAttributes(filename) != INVALID_FILE_ATTRIBUTES; aoqi@0: } aoqi@0: aoqi@0: bool os::dll_build_name(char *buffer, size_t buflen, aoqi@0: const char* pname, const char* fname) { aoqi@0: bool retval = false; aoqi@0: const size_t pnamelen = pname ? strlen(pname) : 0; aoqi@0: const char c = (pnamelen > 0) ? pname[pnamelen-1] : 0; aoqi@0: aoqi@0: // Return error on buffer overflow. aoqi@0: if (pnamelen + strlen(fname) + 10 > buflen) { aoqi@0: return retval; aoqi@0: } aoqi@0: aoqi@0: if (pnamelen == 0) { aoqi@0: jio_snprintf(buffer, buflen, "%s.dll", fname); aoqi@0: retval = true; aoqi@0: } else if (c == ':' || c == '\\') { aoqi@0: jio_snprintf(buffer, buflen, "%s%s.dll", pname, fname); aoqi@0: retval = true; aoqi@0: } else if (strchr(pname, *os::path_separator()) != NULL) { aoqi@0: int n; aoqi@0: char** pelements = split_path(pname, &n); aoqi@0: if (pelements == NULL) { aoqi@0: return false; aoqi@0: } aoqi@0: for (int i = 0 ; i < n ; i++) { aoqi@0: char* path = pelements[i]; aoqi@0: // Really shouldn't be NULL, but check can't hurt aoqi@0: size_t plen = (path == NULL) ? 0 : strlen(path); aoqi@0: if (plen == 0) { aoqi@0: continue; // skip the empty path values aoqi@0: } aoqi@0: const char lastchar = path[plen - 1]; aoqi@0: if (lastchar == ':' || lastchar == '\\') { aoqi@0: jio_snprintf(buffer, buflen, "%s%s.dll", path, fname); aoqi@0: } else { aoqi@0: jio_snprintf(buffer, buflen, "%s\\%s.dll", path, fname); aoqi@0: } aoqi@0: if (file_exists(buffer)) { aoqi@0: retval = true; aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: // release the storage aoqi@0: for (int i = 0 ; i < n ; i++) { aoqi@0: if (pelements[i] != NULL) { aoqi@0: FREE_C_HEAP_ARRAY(char, pelements[i], mtInternal); aoqi@0: } aoqi@0: } aoqi@0: if (pelements != NULL) { aoqi@0: FREE_C_HEAP_ARRAY(char*, pelements, mtInternal); aoqi@0: } aoqi@0: } else { aoqi@0: jio_snprintf(buffer, buflen, "%s\\%s.dll", pname, fname); aoqi@0: retval = true; aoqi@0: } aoqi@0: return retval; aoqi@0: } aoqi@0: aoqi@0: // Needs to be in os specific directory because windows requires another aoqi@0: // header file aoqi@0: const char* os::get_current_directory(char *buf, size_t buflen) { aoqi@0: int n = static_cast(buflen); aoqi@0: if (buflen > INT_MAX) n = INT_MAX; aoqi@0: return _getcwd(buf, n); aoqi@0: } aoqi@0: aoqi@0: //----------------------------------------------------------- aoqi@0: // Helper functions for fatal error handler aoqi@0: #ifdef _WIN64 aoqi@0: // Helper routine which returns true if address in aoqi@0: // within the NTDLL address space. aoqi@0: // aoqi@0: static bool _addr_in_ntdll( address addr ) aoqi@0: { aoqi@0: HMODULE hmod; aoqi@0: MODULEINFO minfo; aoqi@0: aoqi@0: hmod = GetModuleHandle("NTDLL.DLL"); aoqi@0: if ( hmod == NULL ) return false; aoqi@0: if ( !os::PSApiDll::GetModuleInformation( GetCurrentProcess(), hmod, aoqi@0: &minfo, sizeof(MODULEINFO)) ) aoqi@0: return false; aoqi@0: aoqi@0: if ( (addr >= minfo.lpBaseOfDll) && aoqi@0: (addr < (address)((uintptr_t)minfo.lpBaseOfDll + (uintptr_t)minfo.SizeOfImage))) aoqi@0: return true; aoqi@0: else aoqi@0: return false; aoqi@0: } aoqi@0: #endif aoqi@0: aoqi@0: aoqi@0: // Enumerate all modules for a given process ID aoqi@0: // aoqi@0: // Notice that Windows 95/98/Me and Windows NT/2000/XP have aoqi@0: // different API for doing this. We use PSAPI.DLL on NT based aoqi@0: // Windows and ToolHelp on 95/98/Me. aoqi@0: aoqi@0: // Callback function that is called by enumerate_modules() on aoqi@0: // every DLL module. aoqi@0: // Input parameters: aoqi@0: // int pid, aoqi@0: // char* module_file_name, aoqi@0: // address module_base_addr, aoqi@0: // unsigned module_size, aoqi@0: // void* param aoqi@0: typedef int (*EnumModulesCallbackFunc)(int, char *, address, unsigned, void *); aoqi@0: aoqi@0: // enumerate_modules for Windows NT, using PSAPI aoqi@0: static int _enumerate_modules_winnt( int pid, EnumModulesCallbackFunc func, void * param) aoqi@0: { aoqi@0: HANDLE hProcess ; aoqi@0: aoqi@0: # define MAX_NUM_MODULES 128 aoqi@0: HMODULE modules[MAX_NUM_MODULES]; aoqi@0: static char filename[ MAX_PATH ]; aoqi@0: int result = 0; aoqi@0: aoqi@0: if (!os::PSApiDll::PSApiAvailable()) { aoqi@0: return 0; aoqi@0: } aoqi@0: aoqi@0: hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, aoqi@0: FALSE, pid ) ; aoqi@0: if (hProcess == NULL) return 0; aoqi@0: aoqi@0: DWORD size_needed; aoqi@0: if (!os::PSApiDll::EnumProcessModules(hProcess, modules, aoqi@0: sizeof(modules), &size_needed)) { aoqi@0: CloseHandle( hProcess ); aoqi@0: return 0; aoqi@0: } aoqi@0: aoqi@0: // number of modules that are currently loaded aoqi@0: int num_modules = size_needed / sizeof(HMODULE); aoqi@0: aoqi@0: for (int i = 0; i < MIN2(num_modules, MAX_NUM_MODULES); i++) { aoqi@0: // Get Full pathname: aoqi@0: if(!os::PSApiDll::GetModuleFileNameEx(hProcess, modules[i], aoqi@0: filename, sizeof(filename))) { aoqi@0: filename[0] = '\0'; aoqi@0: } aoqi@0: aoqi@0: MODULEINFO modinfo; aoqi@0: if (!os::PSApiDll::GetModuleInformation(hProcess, modules[i], aoqi@0: &modinfo, sizeof(modinfo))) { aoqi@0: modinfo.lpBaseOfDll = NULL; aoqi@0: modinfo.SizeOfImage = 0; aoqi@0: } aoqi@0: aoqi@0: // Invoke callback function aoqi@0: result = func(pid, filename, (address)modinfo.lpBaseOfDll, aoqi@0: modinfo.SizeOfImage, param); aoqi@0: if (result) break; aoqi@0: } aoqi@0: aoqi@0: CloseHandle( hProcess ) ; aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // enumerate_modules for Windows 95/98/ME, using TOOLHELP aoqi@0: static int _enumerate_modules_windows( int pid, EnumModulesCallbackFunc func, void *param) aoqi@0: { aoqi@0: HANDLE hSnapShot ; aoqi@0: static MODULEENTRY32 modentry ; aoqi@0: int result = 0; aoqi@0: aoqi@0: if (!os::Kernel32Dll::HelpToolsAvailable()) { aoqi@0: return 0; aoqi@0: } aoqi@0: aoqi@0: // Get a handle to a Toolhelp snapshot of the system aoqi@0: hSnapShot = os::Kernel32Dll::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid ) ; aoqi@0: if( hSnapShot == INVALID_HANDLE_VALUE ) { aoqi@0: return FALSE ; aoqi@0: } aoqi@0: aoqi@0: // iterate through all modules aoqi@0: modentry.dwSize = sizeof(MODULEENTRY32) ; aoqi@0: bool not_done = os::Kernel32Dll::Module32First( hSnapShot, &modentry ) != 0; aoqi@0: aoqi@0: while( not_done ) { aoqi@0: // invoke the callback aoqi@0: result=func(pid, modentry.szExePath, (address)modentry.modBaseAddr, aoqi@0: modentry.modBaseSize, param); aoqi@0: if (result) break; aoqi@0: aoqi@0: modentry.dwSize = sizeof(MODULEENTRY32) ; aoqi@0: not_done = os::Kernel32Dll::Module32Next( hSnapShot, &modentry ) != 0; aoqi@0: } aoqi@0: aoqi@0: CloseHandle(hSnapShot); aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: int enumerate_modules( int pid, EnumModulesCallbackFunc func, void * param ) aoqi@0: { aoqi@0: // Get current process ID if caller doesn't provide it. aoqi@0: if (!pid) pid = os::current_process_id(); aoqi@0: aoqi@0: if (os::win32::is_nt()) return _enumerate_modules_winnt (pid, func, param); aoqi@0: else return _enumerate_modules_windows(pid, func, param); aoqi@0: } aoqi@0: aoqi@0: struct _modinfo { aoqi@0: address addr; aoqi@0: char* full_path; // point to a char buffer aoqi@0: int buflen; // size of the buffer aoqi@0: address base_addr; aoqi@0: }; aoqi@0: aoqi@0: static int _locate_module_by_addr(int pid, char * mod_fname, address base_addr, aoqi@0: unsigned size, void * param) { aoqi@0: struct _modinfo *pmod = (struct _modinfo *)param; aoqi@0: if (!pmod) return -1; aoqi@0: aoqi@0: if (base_addr <= pmod->addr && aoqi@0: base_addr+size > pmod->addr) { aoqi@0: // if a buffer is provided, copy path name to the buffer aoqi@0: if (pmod->full_path) { aoqi@0: jio_snprintf(pmod->full_path, pmod->buflen, "%s", mod_fname); aoqi@0: } aoqi@0: pmod->base_addr = base_addr; aoqi@0: return 1; aoqi@0: } aoqi@0: return 0; aoqi@0: } aoqi@0: aoqi@0: bool os::dll_address_to_library_name(address addr, char* buf, aoqi@0: int buflen, int* offset) { aoqi@0: // buf is not optional, but offset is optional aoqi@0: assert(buf != NULL, "sanity check"); aoqi@0: aoqi@0: // NOTE: the reason we don't use SymGetModuleInfo() is it doesn't always aoqi@0: // return the full path to the DLL file, sometimes it returns path aoqi@0: // to the corresponding PDB file (debug info); sometimes it only aoqi@0: // returns partial path, which makes life painful. aoqi@0: aoqi@0: struct _modinfo mi; aoqi@0: mi.addr = addr; aoqi@0: mi.full_path = buf; aoqi@0: mi.buflen = buflen; aoqi@0: int pid = os::current_process_id(); aoqi@0: if (enumerate_modules(pid, _locate_module_by_addr, (void *)&mi)) { aoqi@0: // buf already contains path name aoqi@0: if (offset) *offset = addr - mi.base_addr; aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: buf[0] = '\0'; aoqi@0: if (offset) *offset = -1; aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: bool os::dll_address_to_function_name(address addr, char *buf, aoqi@0: int buflen, int *offset) { aoqi@0: // buf is not optional, but offset is optional aoqi@0: assert(buf != NULL, "sanity check"); aoqi@0: aoqi@0: if (Decoder::decode(addr, buf, buflen, offset)) { aoqi@0: return true; aoqi@0: } aoqi@0: if (offset != NULL) *offset = -1; aoqi@0: buf[0] = '\0'; aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: // save the start and end address of jvm.dll into param[0] and param[1] aoqi@0: static int _locate_jvm_dll(int pid, char* mod_fname, address base_addr, aoqi@0: unsigned size, void * param) { aoqi@0: if (!param) return -1; aoqi@0: aoqi@0: if (base_addr <= (address)_locate_jvm_dll && aoqi@0: base_addr+size > (address)_locate_jvm_dll) { aoqi@0: ((address*)param)[0] = base_addr; aoqi@0: ((address*)param)[1] = base_addr + size; aoqi@0: return 1; aoqi@0: } aoqi@0: return 0; aoqi@0: } aoqi@0: aoqi@0: address vm_lib_location[2]; // start and end address of jvm.dll aoqi@0: aoqi@0: // check if addr is inside jvm.dll aoqi@0: bool os::address_is_in_vm(address addr) { aoqi@0: if (!vm_lib_location[0] || !vm_lib_location[1]) { aoqi@0: int pid = os::current_process_id(); aoqi@0: if (!enumerate_modules(pid, _locate_jvm_dll, (void *)vm_lib_location)) { aoqi@0: assert(false, "Can't find jvm module."); aoqi@0: return false; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: return (vm_lib_location[0] <= addr) && (addr < vm_lib_location[1]); aoqi@0: } aoqi@0: aoqi@0: // print module info; param is outputStream* aoqi@0: static int _print_module(int pid, char* fname, address base, aoqi@0: unsigned size, void* param) { aoqi@0: if (!param) return -1; aoqi@0: aoqi@0: outputStream* st = (outputStream*)param; aoqi@0: aoqi@0: address end_addr = base + size; aoqi@0: st->print(PTR_FORMAT " - " PTR_FORMAT " \t%s\n", base, end_addr, fname); aoqi@0: return 0; aoqi@0: } aoqi@0: aoqi@0: // Loads .dll/.so and aoqi@0: // in case of error it checks if .dll/.so was built for the aoqi@0: // same architecture as Hotspot is running on aoqi@0: void * os::dll_load(const char *name, char *ebuf, int ebuflen) aoqi@0: { aoqi@0: void * result = LoadLibrary(name); aoqi@0: if (result != NULL) aoqi@0: { aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: DWORD errcode = GetLastError(); aoqi@0: if (errcode == ERROR_MOD_NOT_FOUND) { aoqi@0: strncpy(ebuf, "Can't find dependent libraries", ebuflen-1); aoqi@0: ebuf[ebuflen-1]='\0'; aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: // Parsing dll below aoqi@0: // If we can read dll-info and find that dll was built aoqi@0: // for an architecture other than Hotspot is running in aoqi@0: // - then print to buffer "DLL was built for a different architecture" aoqi@0: // else call os::lasterror to obtain system error message aoqi@0: aoqi@0: // Read system error message into ebuf aoqi@0: // It may or may not be overwritten below (in the for loop and just above) aoqi@0: lasterror(ebuf, (size_t) ebuflen); aoqi@0: ebuf[ebuflen-1]='\0'; aoqi@0: int file_descriptor=::open(name, O_RDONLY | O_BINARY, 0); aoqi@0: if (file_descriptor<0) aoqi@0: { aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: uint32_t signature_offset; aoqi@0: uint16_t lib_arch=0; aoqi@0: bool failed_to_get_lib_arch= aoqi@0: ( aoqi@0: //Go to position 3c in the dll aoqi@0: (os::seek_to_file_offset(file_descriptor,IMAGE_FILE_PTR_TO_SIGNATURE)<0) aoqi@0: || aoqi@0: // Read loacation of signature aoqi@0: (sizeof(signature_offset)!= aoqi@0: (os::read(file_descriptor, (void*)&signature_offset,sizeof(signature_offset)))) aoqi@0: || aoqi@0: //Go to COFF File Header in dll aoqi@0: //that is located after"signature" (4 bytes long) aoqi@0: (os::seek_to_file_offset(file_descriptor, aoqi@0: signature_offset+IMAGE_FILE_SIGNATURE_LENGTH)<0) aoqi@0: || aoqi@0: //Read field that contains code of architecture aoqi@0: // that dll was build for aoqi@0: (sizeof(lib_arch)!= aoqi@0: (os::read(file_descriptor, (void*)&lib_arch,sizeof(lib_arch)))) aoqi@0: ); aoqi@0: aoqi@0: ::close(file_descriptor); aoqi@0: if (failed_to_get_lib_arch) aoqi@0: { aoqi@0: // file i/o error - report os::lasterror(...) msg aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: typedef struct aoqi@0: { aoqi@0: uint16_t arch_code; aoqi@0: char* arch_name; aoqi@0: } arch_t; aoqi@0: aoqi@0: static const arch_t arch_array[]={ aoqi@0: {IMAGE_FILE_MACHINE_I386, (char*)"IA 32"}, aoqi@0: {IMAGE_FILE_MACHINE_AMD64, (char*)"AMD 64"}, aoqi@0: {IMAGE_FILE_MACHINE_IA64, (char*)"IA 64"} aoqi@0: }; aoqi@0: #if (defined _M_IA64) aoqi@0: static const uint16_t running_arch=IMAGE_FILE_MACHINE_IA64; aoqi@0: #elif (defined _M_AMD64) aoqi@0: static const uint16_t running_arch=IMAGE_FILE_MACHINE_AMD64; aoqi@0: #elif (defined _M_IX86) aoqi@0: static const uint16_t running_arch=IMAGE_FILE_MACHINE_I386; aoqi@0: #else aoqi@0: #error Method os::dll_load requires that one of following \ aoqi@0: is defined :_M_IA64,_M_AMD64 or _M_IX86 aoqi@0: #endif aoqi@0: aoqi@0: aoqi@0: // Obtain a string for printf operation aoqi@0: // lib_arch_str shall contain string what platform this .dll was built for aoqi@0: // running_arch_str shall string contain what platform Hotspot was built for aoqi@0: char *running_arch_str=NULL,*lib_arch_str=NULL; aoqi@0: for (unsigned int i=0;iprint_cr("Dynamic libraries:"); aoqi@0: enumerate_modules(pid, _print_module, (void *)st); aoqi@0: } aoqi@0: aoqi@0: void os::print_os_info_brief(outputStream* st) { aoqi@0: os::print_os_info(st); aoqi@0: } aoqi@0: aoqi@0: void os::print_os_info(outputStream* st) { aoqi@0: st->print("OS:"); aoqi@0: aoqi@0: os::win32::print_windows_version(st); aoqi@0: } aoqi@0: aoqi@0: void os::win32::print_windows_version(outputStream* st) { aoqi@0: OSVERSIONINFOEX osvi; aoqi@0: SYSTEM_INFO si; aoqi@0: aoqi@0: ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); aoqi@0: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); aoqi@0: aoqi@0: if (!GetVersionEx((OSVERSIONINFO *)&osvi)) { aoqi@0: st->print_cr("N/A"); aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: int os_vers = osvi.dwMajorVersion * 1000 + osvi.dwMinorVersion; aoqi@0: aoqi@0: ZeroMemory(&si, sizeof(SYSTEM_INFO)); aoqi@0: if (os_vers >= 5002) { aoqi@0: // Retrieve SYSTEM_INFO from GetNativeSystemInfo call so that we could aoqi@0: // find out whether we are running on 64 bit processor or not. aoqi@0: if (os::Kernel32Dll::GetNativeSystemInfoAvailable()) { aoqi@0: os::Kernel32Dll::GetNativeSystemInfo(&si); aoqi@0: } else { aoqi@0: GetSystemInfo(&si); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) { aoqi@0: switch (os_vers) { aoqi@0: case 3051: st->print(" Windows NT 3.51"); break; aoqi@0: case 4000: st->print(" Windows NT 4.0"); break; aoqi@0: case 5000: st->print(" Windows 2000"); break; aoqi@0: case 5001: st->print(" Windows XP"); break; aoqi@0: case 5002: aoqi@0: if (osvi.wProductType == VER_NT_WORKSTATION && aoqi@0: si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { aoqi@0: st->print(" Windows XP x64 Edition"); aoqi@0: } else { aoqi@0: st->print(" Windows Server 2003 family"); aoqi@0: } aoqi@0: break; aoqi@0: aoqi@0: case 6000: aoqi@0: if (osvi.wProductType == VER_NT_WORKSTATION) { aoqi@0: st->print(" Windows Vista"); aoqi@0: } else { aoqi@0: st->print(" Windows Server 2008"); aoqi@0: } aoqi@0: break; aoqi@0: aoqi@0: case 6001: aoqi@0: if (osvi.wProductType == VER_NT_WORKSTATION) { aoqi@0: st->print(" Windows 7"); aoqi@0: } else { aoqi@0: st->print(" Windows Server 2008 R2"); aoqi@0: } aoqi@0: break; aoqi@0: aoqi@0: case 6002: aoqi@0: if (osvi.wProductType == VER_NT_WORKSTATION) { aoqi@0: st->print(" Windows 8"); aoqi@0: } else { aoqi@0: st->print(" Windows Server 2012"); aoqi@0: } aoqi@0: break; aoqi@0: aoqi@0: case 6003: aoqi@0: if (osvi.wProductType == VER_NT_WORKSTATION) { aoqi@0: st->print(" Windows 8.1"); aoqi@0: } else { aoqi@0: st->print(" Windows Server 2012 R2"); aoqi@0: } aoqi@0: break; aoqi@0: aoqi@0: default: // future os aoqi@0: // Unrecognized windows, print out its major and minor versions aoqi@0: st->print(" Windows NT %d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion); aoqi@0: } aoqi@0: } else { aoqi@0: switch (os_vers) { aoqi@0: case 4000: st->print(" Windows 95"); break; aoqi@0: case 4010: st->print(" Windows 98"); break; aoqi@0: case 4090: st->print(" Windows Me"); break; aoqi@0: default: // future windows, print out its major and minor versions aoqi@0: st->print(" Windows %d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if (os_vers >= 6000 && si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { aoqi@0: st->print(" , 64 bit"); aoqi@0: } aoqi@0: aoqi@0: st->print(" Build %d", osvi.dwBuildNumber); aoqi@0: st->print(" %s", osvi.szCSDVersion); // service pack aoqi@0: st->cr(); aoqi@0: } aoqi@0: aoqi@0: void os::pd_print_cpu_info(outputStream* st) { aoqi@0: // Nothing to do for now. aoqi@0: } aoqi@0: aoqi@0: void os::print_memory_info(outputStream* st) { aoqi@0: st->print("Memory:"); aoqi@0: st->print(" %dk page", os::vm_page_size()>>10); aoqi@0: aoqi@0: // Use GlobalMemoryStatusEx() because GlobalMemoryStatus() may return incorrect aoqi@0: // value if total memory is larger than 4GB aoqi@0: MEMORYSTATUSEX ms; aoqi@0: ms.dwLength = sizeof(ms); aoqi@0: GlobalMemoryStatusEx(&ms); aoqi@0: aoqi@0: st->print(", physical %uk", os::physical_memory() >> 10); aoqi@0: st->print("(%uk free)", os::available_memory() >> 10); aoqi@0: aoqi@0: st->print(", swap %uk", ms.ullTotalPageFile >> 10); aoqi@0: st->print("(%uk free)", ms.ullAvailPageFile >> 10); aoqi@0: st->cr(); aoqi@0: } aoqi@0: aoqi@0: void os::print_siginfo(outputStream *st, void *siginfo) { aoqi@0: EXCEPTION_RECORD* er = (EXCEPTION_RECORD*)siginfo; aoqi@0: st->print("siginfo:"); aoqi@0: st->print(" ExceptionCode=0x%x", er->ExceptionCode); aoqi@0: aoqi@0: if (er->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && aoqi@0: er->NumberParameters >= 2) { aoqi@0: switch (er->ExceptionInformation[0]) { aoqi@0: case 0: st->print(", reading address"); break; aoqi@0: case 1: st->print(", writing address"); break; aoqi@0: default: st->print(", ExceptionInformation=" INTPTR_FORMAT, aoqi@0: er->ExceptionInformation[0]); aoqi@0: } aoqi@0: st->print(" " INTPTR_FORMAT, er->ExceptionInformation[1]); aoqi@0: } else if (er->ExceptionCode == EXCEPTION_IN_PAGE_ERROR && aoqi@0: er->NumberParameters >= 2 && UseSharedSpaces) { aoqi@0: FileMapInfo* mapinfo = FileMapInfo::current_info(); aoqi@0: if (mapinfo->is_in_shared_space((void*)er->ExceptionInformation[1])) { aoqi@0: st->print("\n\nError accessing class data sharing archive." \ aoqi@0: " Mapped file inaccessible during execution, " \ aoqi@0: " possible disk/network problem."); aoqi@0: } aoqi@0: } else { aoqi@0: int num = er->NumberParameters; aoqi@0: if (num > 0) { aoqi@0: st->print(", ExceptionInformation="); aoqi@0: for (int i = 0; i < num; i++) { aoqi@0: st->print(INTPTR_FORMAT " ", er->ExceptionInformation[i]); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: st->cr(); aoqi@0: } aoqi@0: aoqi@0: void os::print_signal_handlers(outputStream* st, char* buf, size_t buflen) { aoqi@0: // do nothing aoqi@0: } aoqi@0: aoqi@0: static char saved_jvm_path[MAX_PATH] = {0}; aoqi@0: aoqi@0: // Find the full path to the current module, jvm.dll aoqi@0: void os::jvm_path(char *buf, jint buflen) { aoqi@0: // Error checking. aoqi@0: if (buflen < MAX_PATH) { aoqi@0: assert(false, "must use a large-enough buffer"); aoqi@0: buf[0] = '\0'; aoqi@0: return; aoqi@0: } aoqi@0: // Lazy resolve the path to current module. aoqi@0: if (saved_jvm_path[0] != 0) { aoqi@0: strcpy(buf, saved_jvm_path); aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: buf[0] = '\0'; aoqi@0: if (Arguments::created_by_gamma_launcher()) { aoqi@0: // Support for the gamma launcher. Check for an aoqi@0: // JAVA_HOME environment variable aoqi@0: // and fix up the path so it looks like aoqi@0: // libjvm.so is installed there (append a fake suffix aoqi@0: // hotspot/libjvm.so). aoqi@0: char* java_home_var = ::getenv("JAVA_HOME"); aoqi@0: if (java_home_var != NULL && java_home_var[0] != 0 && aoqi@0: strlen(java_home_var) < (size_t)buflen) { aoqi@0: aoqi@0: strncpy(buf, java_home_var, buflen); aoqi@0: aoqi@0: // determine if this is a legacy image or modules image aoqi@0: // modules image doesn't have "jre" subdirectory aoqi@0: size_t len = strlen(buf); aoqi@0: char* jrebin_p = buf + len; aoqi@0: jio_snprintf(jrebin_p, buflen-len, "\\jre\\bin\\"); aoqi@0: if (0 != _access(buf, 0)) { aoqi@0: jio_snprintf(jrebin_p, buflen-len, "\\bin\\"); aoqi@0: } aoqi@0: len = strlen(buf); aoqi@0: jio_snprintf(buf + len, buflen-len, "hotspot\\jvm.dll"); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if(buf[0] == '\0') { aoqi@0: GetModuleFileName(vm_lib_handle, buf, buflen); aoqi@0: } aoqi@0: strncpy(saved_jvm_path, buf, MAX_PATH); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void os::print_jni_name_prefix_on(outputStream* st, int args_size) { aoqi@0: #ifndef _WIN64 aoqi@0: st->print("_"); aoqi@0: #endif aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void os::print_jni_name_suffix_on(outputStream* st, int args_size) { aoqi@0: #ifndef _WIN64 aoqi@0: st->print("@%d", args_size * sizeof(int)); aoqi@0: #endif aoqi@0: } aoqi@0: aoqi@0: // This method is a copy of JDK's sysGetLastErrorString aoqi@0: // from src/windows/hpi/src/system_md.c aoqi@0: aoqi@0: size_t os::lasterror(char* buf, size_t len) { aoqi@0: DWORD errval; aoqi@0: aoqi@0: if ((errval = GetLastError()) != 0) { aoqi@0: // DOS error aoqi@0: size_t n = (size_t)FormatMessage( aoqi@0: FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, aoqi@0: NULL, aoqi@0: errval, aoqi@0: 0, aoqi@0: buf, aoqi@0: (DWORD)len, aoqi@0: NULL); aoqi@0: if (n > 3) { aoqi@0: // Drop final '.', CR, LF aoqi@0: if (buf[n - 1] == '\n') n--; aoqi@0: if (buf[n - 1] == '\r') n--; aoqi@0: if (buf[n - 1] == '.') n--; aoqi@0: buf[n] = '\0'; aoqi@0: } aoqi@0: return n; aoqi@0: } aoqi@0: aoqi@0: if (errno != 0) { aoqi@0: // C runtime error that has no corresponding DOS error code aoqi@0: const char* s = strerror(errno); aoqi@0: size_t n = strlen(s); aoqi@0: if (n >= len) n = len - 1; aoqi@0: strncpy(buf, s, n); aoqi@0: buf[n] = '\0'; aoqi@0: return n; aoqi@0: } aoqi@0: aoqi@0: return 0; aoqi@0: } aoqi@0: aoqi@0: int os::get_last_error() { aoqi@0: DWORD error = GetLastError(); aoqi@0: if (error == 0) aoqi@0: error = errno; aoqi@0: return (int)error; aoqi@0: } aoqi@0: aoqi@0: // sun.misc.Signal aoqi@0: // NOTE that this is a workaround for an apparent kernel bug where if aoqi@0: // a signal handler for SIGBREAK is installed then that signal handler aoqi@0: // takes priority over the console control handler for CTRL_CLOSE_EVENT. aoqi@0: // See bug 4416763. aoqi@0: static void (*sigbreakHandler)(int) = NULL; aoqi@0: aoqi@0: static void UserHandler(int sig, void *siginfo, void *context) { aoqi@0: os::signal_notify(sig); aoqi@0: // We need to reinstate the signal handler each time... aoqi@0: os::signal(sig, (void*)UserHandler); aoqi@0: } aoqi@0: aoqi@0: void* os::user_handler() { aoqi@0: return (void*) UserHandler; aoqi@0: } aoqi@0: aoqi@0: void* os::signal(int signal_number, void* handler) { aoqi@0: if ((signal_number == SIGBREAK) && (!ReduceSignalUsage)) { aoqi@0: void (*oldHandler)(int) = sigbreakHandler; aoqi@0: sigbreakHandler = (void (*)(int)) handler; aoqi@0: return (void*) oldHandler; aoqi@0: } else { aoqi@0: return (void*)::signal(signal_number, (void (*)(int))handler); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void os::signal_raise(int signal_number) { aoqi@0: raise(signal_number); aoqi@0: } aoqi@0: aoqi@0: // The Win32 C runtime library maps all console control events other than ^C aoqi@0: // into SIGBREAK, which makes it impossible to distinguish ^BREAK from close, aoqi@0: // logoff, and shutdown events. We therefore install our own console handler aoqi@0: // that raises SIGTERM for the latter cases. aoqi@0: // aoqi@0: static BOOL WINAPI consoleHandler(DWORD event) { aoqi@0: switch(event) { aoqi@0: case CTRL_C_EVENT: aoqi@0: if (is_error_reported()) { aoqi@0: // Ctrl-C is pressed during error reporting, likely because the error aoqi@0: // handler fails to abort. Let VM die immediately. aoqi@0: os::die(); aoqi@0: } aoqi@0: aoqi@0: os::signal_raise(SIGINT); aoqi@0: return TRUE; aoqi@0: break; aoqi@0: case CTRL_BREAK_EVENT: aoqi@0: if (sigbreakHandler != NULL) { aoqi@0: (*sigbreakHandler)(SIGBREAK); aoqi@0: } aoqi@0: return TRUE; aoqi@0: break; aoqi@0: case CTRL_LOGOFF_EVENT: { aoqi@0: // Don't terminate JVM if it is running in a non-interactive session, aoqi@0: // such as a service process. aoqi@0: USEROBJECTFLAGS flags; aoqi@0: HANDLE handle = GetProcessWindowStation(); aoqi@0: if (handle != NULL && aoqi@0: GetUserObjectInformation(handle, UOI_FLAGS, &flags, aoqi@0: sizeof( USEROBJECTFLAGS), NULL)) { aoqi@0: // If it is a non-interactive session, let next handler to deal aoqi@0: // with it. aoqi@0: if ((flags.dwFlags & WSF_VISIBLE) == 0) { aoqi@0: return FALSE; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: case CTRL_CLOSE_EVENT: aoqi@0: case CTRL_SHUTDOWN_EVENT: aoqi@0: os::signal_raise(SIGTERM); aoqi@0: return TRUE; aoqi@0: break; aoqi@0: default: aoqi@0: break; aoqi@0: } aoqi@0: return FALSE; aoqi@0: } aoqi@0: aoqi@0: /* aoqi@0: * The following code is moved from os.cpp for making this aoqi@0: * code platform specific, which it is by its very nature. aoqi@0: */ aoqi@0: aoqi@0: // Return maximum OS signal used + 1 for internal use only aoqi@0: // Used as exit signal for signal_thread aoqi@0: int os::sigexitnum_pd(){ aoqi@0: return NSIG; aoqi@0: } aoqi@0: aoqi@0: // a counter for each possible signal value, including signal_thread exit signal aoqi@0: static volatile jint pending_signals[NSIG+1] = { 0 }; aoqi@0: static HANDLE sig_sem = NULL; aoqi@0: aoqi@0: void os::signal_init_pd() { aoqi@0: // Initialize signal structures aoqi@0: memset((void*)pending_signals, 0, sizeof(pending_signals)); aoqi@0: aoqi@0: sig_sem = ::CreateSemaphore(NULL, 0, NSIG+1, NULL); aoqi@0: aoqi@0: // Programs embedding the VM do not want it to attempt to receive aoqi@0: // events like CTRL_LOGOFF_EVENT, which are used to implement the aoqi@0: // shutdown hooks mechanism introduced in 1.3. For example, when aoqi@0: // the VM is run as part of a Windows NT service (i.e., a servlet aoqi@0: // engine in a web server), the correct behavior is for any console aoqi@0: // control handler to return FALSE, not TRUE, because the OS's aoqi@0: // "final" handler for such events allows the process to continue if aoqi@0: // it is a service (while terminating it if it is not a service). aoqi@0: // To make this behavior uniform and the mechanism simpler, we aoqi@0: // completely disable the VM's usage of these console events if -Xrs aoqi@0: // (=ReduceSignalUsage) is specified. This means, for example, that aoqi@0: // the CTRL-BREAK thread dump mechanism is also disabled in this aoqi@0: // case. See bugs 4323062, 4345157, and related bugs. aoqi@0: aoqi@0: if (!ReduceSignalUsage) { aoqi@0: // Add a CTRL-C handler aoqi@0: SetConsoleCtrlHandler(consoleHandler, TRUE); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void os::signal_notify(int signal_number) { aoqi@0: BOOL ret; aoqi@0: if (sig_sem != NULL) { aoqi@0: Atomic::inc(&pending_signals[signal_number]); aoqi@0: ret = ::ReleaseSemaphore(sig_sem, 1, NULL); aoqi@0: assert(ret != 0, "ReleaseSemaphore() failed"); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: static int check_pending_signals(bool wait_for_signal) { aoqi@0: DWORD ret; aoqi@0: while (true) { aoqi@0: for (int i = 0; i < NSIG + 1; i++) { aoqi@0: jint n = pending_signals[i]; aoqi@0: if (n > 0 && n == Atomic::cmpxchg(n - 1, &pending_signals[i], n)) { aoqi@0: return i; aoqi@0: } aoqi@0: } aoqi@0: if (!wait_for_signal) { aoqi@0: return -1; aoqi@0: } aoqi@0: aoqi@0: JavaThread *thread = JavaThread::current(); aoqi@0: aoqi@0: ThreadBlockInVM tbivm(thread); aoqi@0: aoqi@0: bool threadIsSuspended; aoqi@0: do { aoqi@0: thread->set_suspend_equivalent(); aoqi@0: // cleared by handle_special_suspend_equivalent_condition() or java_suspend_self() aoqi@0: ret = ::WaitForSingleObject(sig_sem, INFINITE); aoqi@0: assert(ret == WAIT_OBJECT_0, "WaitForSingleObject() failed"); aoqi@0: aoqi@0: // were we externally suspended while we were waiting? aoqi@0: threadIsSuspended = thread->handle_special_suspend_equivalent_condition(); aoqi@0: if (threadIsSuspended) { aoqi@0: // aoqi@0: // The semaphore has been incremented, but while we were waiting aoqi@0: // another thread suspended us. We don't want to continue running aoqi@0: // while suspended because that would surprise the thread that aoqi@0: // suspended us. aoqi@0: // aoqi@0: ret = ::ReleaseSemaphore(sig_sem, 1, NULL); aoqi@0: assert(ret != 0, "ReleaseSemaphore() failed"); aoqi@0: aoqi@0: thread->java_suspend_self(); aoqi@0: } aoqi@0: } while (threadIsSuspended); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: int os::signal_lookup() { aoqi@0: return check_pending_signals(false); aoqi@0: } aoqi@0: aoqi@0: int os::signal_wait() { aoqi@0: return check_pending_signals(true); aoqi@0: } aoqi@0: aoqi@0: // Implicit OS exception handling aoqi@0: aoqi@0: LONG Handle_Exception(struct _EXCEPTION_POINTERS* exceptionInfo, address handler) { aoqi@0: JavaThread* thread = JavaThread::current(); aoqi@0: // Save pc in thread aoqi@0: #ifdef _M_IA64 aoqi@0: // Do not blow up if no thread info available. aoqi@0: if (thread) { aoqi@0: // Saving PRECISE pc (with slot information) in thread. aoqi@0: uint64_t precise_pc = (uint64_t) exceptionInfo->ExceptionRecord->ExceptionAddress; aoqi@0: // Convert precise PC into "Unix" format aoqi@0: precise_pc = (precise_pc & 0xFFFFFFFFFFFFFFF0) | ((precise_pc & 0xF) >> 2); aoqi@0: thread->set_saved_exception_pc((address)precise_pc); aoqi@0: } aoqi@0: // Set pc to handler aoqi@0: exceptionInfo->ContextRecord->StIIP = (DWORD64)handler; aoqi@0: // Clear out psr.ri (= Restart Instruction) in order to continue aoqi@0: // at the beginning of the target bundle. aoqi@0: exceptionInfo->ContextRecord->StIPSR &= 0xFFFFF9FFFFFFFFFF; aoqi@0: assert(((DWORD64)handler & 0xF) == 0, "Target address must point to the beginning of a bundle!"); aoqi@0: #elif _M_AMD64 aoqi@0: // Do not blow up if no thread info available. aoqi@0: if (thread) { aoqi@0: thread->set_saved_exception_pc((address)(DWORD_PTR)exceptionInfo->ContextRecord->Rip); aoqi@0: } aoqi@0: // Set pc to handler aoqi@0: exceptionInfo->ContextRecord->Rip = (DWORD64)handler; aoqi@0: #else aoqi@0: // Do not blow up if no thread info available. aoqi@0: if (thread) { aoqi@0: thread->set_saved_exception_pc((address)(DWORD_PTR)exceptionInfo->ContextRecord->Eip); aoqi@0: } aoqi@0: // Set pc to handler aoqi@0: exceptionInfo->ContextRecord->Eip = (DWORD)(DWORD_PTR)handler; aoqi@0: #endif aoqi@0: aoqi@0: // Continue the execution aoqi@0: return EXCEPTION_CONTINUE_EXECUTION; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // Used for PostMortemDump aoqi@0: extern "C" void safepoints(); aoqi@0: extern "C" void find(int x); aoqi@0: extern "C" void events(); aoqi@0: aoqi@0: // According to Windows API documentation, an illegal instruction sequence should generate aoqi@0: // the 0xC000001C exception code. However, real world experience shows that occasionnaly aoqi@0: // the execution of an illegal instruction can generate the exception code 0xC000001E. This aoqi@0: // seems to be an undocumented feature of Win NT 4.0 (and probably other Windows systems). aoqi@0: aoqi@0: #define EXCEPTION_ILLEGAL_INSTRUCTION_2 0xC000001E aoqi@0: aoqi@0: // From "Execution Protection in the Windows Operating System" draft 0.35 aoqi@0: // Once a system header becomes available, the "real" define should be aoqi@0: // included or copied here. aoqi@0: #define EXCEPTION_INFO_EXEC_VIOLATION 0x08 aoqi@0: aoqi@0: // Handle NAT Bit consumption on IA64. aoqi@0: #ifdef _M_IA64 aoqi@0: #define EXCEPTION_REG_NAT_CONSUMPTION STATUS_REG_NAT_CONSUMPTION aoqi@0: #endif aoqi@0: aoqi@0: // Windows Vista/2008 heap corruption check aoqi@0: #define EXCEPTION_HEAP_CORRUPTION 0xC0000374 aoqi@0: aoqi@0: #define def_excpt(val) #val, val aoqi@0: aoqi@0: struct siglabel { aoqi@0: char *name; aoqi@0: int number; aoqi@0: }; aoqi@0: aoqi@0: // All Visual C++ exceptions thrown from code generated by the Microsoft Visual aoqi@0: // C++ compiler contain this error code. Because this is a compiler-generated aoqi@0: // error, the code is not listed in the Win32 API header files. aoqi@0: // The code is actually a cryptic mnemonic device, with the initial "E" aoqi@0: // standing for "exception" and the final 3 bytes (0x6D7363) representing the aoqi@0: // ASCII values of "msc". aoqi@0: aoqi@0: #define EXCEPTION_UNCAUGHT_CXX_EXCEPTION 0xE06D7363 aoqi@0: aoqi@0: aoqi@0: struct siglabel exceptlabels[] = { aoqi@0: def_excpt(EXCEPTION_ACCESS_VIOLATION), aoqi@0: def_excpt(EXCEPTION_DATATYPE_MISALIGNMENT), aoqi@0: def_excpt(EXCEPTION_BREAKPOINT), aoqi@0: def_excpt(EXCEPTION_SINGLE_STEP), aoqi@0: def_excpt(EXCEPTION_ARRAY_BOUNDS_EXCEEDED), aoqi@0: def_excpt(EXCEPTION_FLT_DENORMAL_OPERAND), aoqi@0: def_excpt(EXCEPTION_FLT_DIVIDE_BY_ZERO), aoqi@0: def_excpt(EXCEPTION_FLT_INEXACT_RESULT), aoqi@0: def_excpt(EXCEPTION_FLT_INVALID_OPERATION), aoqi@0: def_excpt(EXCEPTION_FLT_OVERFLOW), aoqi@0: def_excpt(EXCEPTION_FLT_STACK_CHECK), aoqi@0: def_excpt(EXCEPTION_FLT_UNDERFLOW), aoqi@0: def_excpt(EXCEPTION_INT_DIVIDE_BY_ZERO), aoqi@0: def_excpt(EXCEPTION_INT_OVERFLOW), aoqi@0: def_excpt(EXCEPTION_PRIV_INSTRUCTION), aoqi@0: def_excpt(EXCEPTION_IN_PAGE_ERROR), aoqi@0: def_excpt(EXCEPTION_ILLEGAL_INSTRUCTION), aoqi@0: def_excpt(EXCEPTION_ILLEGAL_INSTRUCTION_2), aoqi@0: def_excpt(EXCEPTION_NONCONTINUABLE_EXCEPTION), aoqi@0: def_excpt(EXCEPTION_STACK_OVERFLOW), aoqi@0: def_excpt(EXCEPTION_INVALID_DISPOSITION), aoqi@0: def_excpt(EXCEPTION_GUARD_PAGE), aoqi@0: def_excpt(EXCEPTION_INVALID_HANDLE), aoqi@0: def_excpt(EXCEPTION_UNCAUGHT_CXX_EXCEPTION), aoqi@0: def_excpt(EXCEPTION_HEAP_CORRUPTION), aoqi@0: #ifdef _M_IA64 aoqi@0: def_excpt(EXCEPTION_REG_NAT_CONSUMPTION), aoqi@0: #endif aoqi@0: NULL, 0 aoqi@0: }; aoqi@0: aoqi@0: const char* os::exception_name(int exception_code, char *buf, size_t size) { aoqi@0: for (int i = 0; exceptlabels[i].name != NULL; i++) { aoqi@0: if (exceptlabels[i].number == exception_code) { aoqi@0: jio_snprintf(buf, size, "%s", exceptlabels[i].name); aoqi@0: return buf; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: //----------------------------------------------------------------------------- aoqi@0: LONG Handle_IDiv_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) { aoqi@0: // handle exception caused by idiv; should only happen for -MinInt/-1 aoqi@0: // (division by zero is handled explicitly) aoqi@0: #ifdef _M_IA64 aoqi@0: assert(0, "Fix Handle_IDiv_Exception"); aoqi@0: #elif _M_AMD64 aoqi@0: PCONTEXT ctx = exceptionInfo->ContextRecord; aoqi@0: address pc = (address)ctx->Rip; aoqi@0: assert(pc[0] == 0xF7, "not an idiv opcode"); aoqi@0: assert((pc[1] & ~0x7) == 0xF8, "cannot handle non-register operands"); aoqi@0: assert(ctx->Rax == min_jint, "unexpected idiv exception"); aoqi@0: // set correct result values and continue after idiv instruction aoqi@0: ctx->Rip = (DWORD)pc + 2; // idiv reg, reg is 2 bytes aoqi@0: ctx->Rax = (DWORD)min_jint; // result aoqi@0: ctx->Rdx = (DWORD)0; // remainder aoqi@0: // Continue the execution aoqi@0: #else aoqi@0: PCONTEXT ctx = exceptionInfo->ContextRecord; aoqi@0: address pc = (address)ctx->Eip; aoqi@0: assert(pc[0] == 0xF7, "not an idiv opcode"); aoqi@0: assert((pc[1] & ~0x7) == 0xF8, "cannot handle non-register operands"); aoqi@0: assert(ctx->Eax == min_jint, "unexpected idiv exception"); aoqi@0: // set correct result values and continue after idiv instruction aoqi@0: ctx->Eip = (DWORD)pc + 2; // idiv reg, reg is 2 bytes aoqi@0: ctx->Eax = (DWORD)min_jint; // result aoqi@0: ctx->Edx = (DWORD)0; // remainder aoqi@0: // Continue the execution aoqi@0: #endif aoqi@0: return EXCEPTION_CONTINUE_EXECUTION; aoqi@0: } aoqi@0: aoqi@0: #ifndef _WIN64 aoqi@0: //----------------------------------------------------------------------------- aoqi@0: LONG WINAPI Handle_FLT_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) { aoqi@0: // handle exception caused by native method modifying control word aoqi@0: PCONTEXT ctx = exceptionInfo->ContextRecord; aoqi@0: DWORD exception_code = exceptionInfo->ExceptionRecord->ExceptionCode; aoqi@0: aoqi@0: switch (exception_code) { aoqi@0: case EXCEPTION_FLT_DENORMAL_OPERAND: aoqi@0: case EXCEPTION_FLT_DIVIDE_BY_ZERO: aoqi@0: case EXCEPTION_FLT_INEXACT_RESULT: aoqi@0: case EXCEPTION_FLT_INVALID_OPERATION: aoqi@0: case EXCEPTION_FLT_OVERFLOW: aoqi@0: case EXCEPTION_FLT_STACK_CHECK: aoqi@0: case EXCEPTION_FLT_UNDERFLOW: aoqi@0: jint fp_control_word = (* (jint*) StubRoutines::addr_fpu_cntrl_wrd_std()); aoqi@0: if (fp_control_word != ctx->FloatSave.ControlWord) { aoqi@0: // Restore FPCW and mask out FLT exceptions aoqi@0: ctx->FloatSave.ControlWord = fp_control_word | 0xffffffc0; aoqi@0: // Mask out pending FLT exceptions aoqi@0: ctx->FloatSave.StatusWord &= 0xffffff00; aoqi@0: return EXCEPTION_CONTINUE_EXECUTION; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if (prev_uef_handler != NULL) { aoqi@0: // We didn't handle this exception so pass it to the previous aoqi@0: // UnhandledExceptionFilter. aoqi@0: return (prev_uef_handler)(exceptionInfo); aoqi@0: } aoqi@0: aoqi@0: return EXCEPTION_CONTINUE_SEARCH; aoqi@0: } aoqi@0: #else //_WIN64 aoqi@0: /* aoqi@0: On Windows, the mxcsr control bits are non-volatile across calls aoqi@0: See also CR 6192333 aoqi@0: If EXCEPTION_FLT_* happened after some native method modified aoqi@0: mxcsr - it is not a jvm fault. aoqi@0: However should we decide to restore of mxcsr after a faulty aoqi@0: native method we can uncomment following code aoqi@0: jint MxCsr = INITIAL_MXCSR; aoqi@0: // we can't use StubRoutines::addr_mxcsr_std() aoqi@0: // because in Win64 mxcsr is not saved there aoqi@0: if (MxCsr != ctx->MxCsr) { aoqi@0: ctx->MxCsr = MxCsr; aoqi@0: return EXCEPTION_CONTINUE_EXECUTION; aoqi@0: } aoqi@0: aoqi@0: */ aoqi@0: #endif // _WIN64 aoqi@0: aoqi@0: aoqi@0: static inline void report_error(Thread* t, DWORD exception_code, aoqi@0: address addr, void* siginfo, void* context) { aoqi@0: VMError err(t, exception_code, addr, siginfo, context); aoqi@0: err.report_and_die(); aoqi@0: aoqi@0: // If UseOsErrorReporting, this will return here and save the error file aoqi@0: // somewhere where we can find it in the minidump. aoqi@0: } aoqi@0: aoqi@0: //----------------------------------------------------------------------------- aoqi@0: LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { aoqi@0: if (InterceptOSException) return EXCEPTION_CONTINUE_SEARCH; aoqi@0: DWORD exception_code = exceptionInfo->ExceptionRecord->ExceptionCode; aoqi@0: #ifdef _M_IA64 aoqi@0: // On Itanium, we need the "precise pc", which has the slot number coded aoqi@0: // into the least 4 bits: 0000=slot0, 0100=slot1, 1000=slot2 (Windows format). aoqi@0: address pc = (address) exceptionInfo->ExceptionRecord->ExceptionAddress; aoqi@0: // Convert the pc to "Unix format", which has the slot number coded aoqi@0: // into the least 2 bits: 0000=slot0, 0001=slot1, 0010=slot2 aoqi@0: // This is needed for IA64 because "relocation" / "implicit null check" / "poll instruction" aoqi@0: // information is saved in the Unix format. aoqi@0: address pc_unix_format = (address) ((((uint64_t)pc) & 0xFFFFFFFFFFFFFFF0) | ((((uint64_t)pc) & 0xF) >> 2)); aoqi@0: #elif _M_AMD64 aoqi@0: address pc = (address) exceptionInfo->ContextRecord->Rip; aoqi@0: #else aoqi@0: address pc = (address) exceptionInfo->ContextRecord->Eip; aoqi@0: #endif aoqi@0: Thread* t = ThreadLocalStorage::get_thread_slow(); // slow & steady aoqi@0: aoqi@0: // Handle SafeFetch32 and SafeFetchN exceptions. aoqi@0: if (StubRoutines::is_safefetch_fault(pc)) { aoqi@0: return Handle_Exception(exceptionInfo, StubRoutines::continuation_for_safefetch_fault(pc)); aoqi@0: } aoqi@0: aoqi@0: #ifndef _WIN64 aoqi@0: // Execution protection violation - win32 running on AMD64 only aoqi@0: // Handled first to avoid misdiagnosis as a "normal" access violation; aoqi@0: // This is safe to do because we have a new/unique ExceptionInformation aoqi@0: // code for this condition. aoqi@0: if (exception_code == EXCEPTION_ACCESS_VIOLATION) { aoqi@0: PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; aoqi@0: int exception_subcode = (int) exceptionRecord->ExceptionInformation[0]; aoqi@0: address addr = (address) exceptionRecord->ExceptionInformation[1]; aoqi@0: aoqi@0: if (exception_subcode == EXCEPTION_INFO_EXEC_VIOLATION) { aoqi@0: int page_size = os::vm_page_size(); aoqi@0: aoqi@0: // Make sure the pc and the faulting address are sane. aoqi@0: // aoqi@0: // If an instruction spans a page boundary, and the page containing aoqi@0: // the beginning of the instruction is executable but the following aoqi@0: // page is not, the pc and the faulting address might be slightly aoqi@0: // different - we still want to unguard the 2nd page in this case. aoqi@0: // aoqi@0: // 15 bytes seems to be a (very) safe value for max instruction size. aoqi@0: bool pc_is_near_addr = aoqi@0: (pointer_delta((void*) addr, (void*) pc, sizeof(char)) < 15); aoqi@0: bool instr_spans_page_boundary = aoqi@0: (align_size_down((intptr_t) pc ^ (intptr_t) addr, aoqi@0: (intptr_t) page_size) > 0); aoqi@0: aoqi@0: if (pc == addr || (pc_is_near_addr && instr_spans_page_boundary)) { aoqi@0: static volatile address last_addr = aoqi@0: (address) os::non_memory_address_word(); aoqi@0: aoqi@0: // In conservative mode, don't unguard unless the address is in the VM aoqi@0: if (UnguardOnExecutionViolation > 0 && addr != last_addr && aoqi@0: (UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) { aoqi@0: aoqi@0: // Set memory to RWX and retry aoqi@0: address page_start = aoqi@0: (address) align_size_down((intptr_t) addr, (intptr_t) page_size); aoqi@0: bool res = os::protect_memory((char*) page_start, page_size, aoqi@0: os::MEM_PROT_RWX); aoqi@0: aoqi@0: if (PrintMiscellaneous && Verbose) { aoqi@0: char buf[256]; aoqi@0: jio_snprintf(buf, sizeof(buf), "Execution protection violation " aoqi@0: "at " INTPTR_FORMAT aoqi@0: ", unguarding " INTPTR_FORMAT ": %s", addr, aoqi@0: page_start, (res ? "success" : strerror(errno))); aoqi@0: tty->print_raw_cr(buf); aoqi@0: } aoqi@0: aoqi@0: // Set last_addr so if we fault again at the same address, we don't aoqi@0: // end up in an endless loop. aoqi@0: // aoqi@0: // There are two potential complications here. Two threads trapping aoqi@0: // at the same address at the same time could cause one of the aoqi@0: // threads to think it already unguarded, and abort the VM. Likely aoqi@0: // very rare. aoqi@0: // aoqi@0: // The other race involves two threads alternately trapping at aoqi@0: // different addresses and failing to unguard the page, resulting in aoqi@0: // an endless loop. This condition is probably even more unlikely aoqi@0: // than the first. aoqi@0: // aoqi@0: // Although both cases could be avoided by using locks or thread aoqi@0: // local last_addr, these solutions are unnecessary complication: aoqi@0: // this handler is a best-effort safety net, not a complete solution. aoqi@0: // It is disabled by default and should only be used as a workaround aoqi@0: // in case we missed any no-execute-unsafe VM code. aoqi@0: aoqi@0: last_addr = addr; aoqi@0: aoqi@0: return EXCEPTION_CONTINUE_EXECUTION; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Last unguard failed or not unguarding aoqi@0: tty->print_raw_cr("Execution protection violation"); aoqi@0: report_error(t, exception_code, addr, exceptionInfo->ExceptionRecord, aoqi@0: exceptionInfo->ContextRecord); aoqi@0: return EXCEPTION_CONTINUE_SEARCH; aoqi@0: } aoqi@0: } aoqi@0: #endif // _WIN64 aoqi@0: aoqi@0: // Check to see if we caught the safepoint code in the aoqi@0: // process of write protecting the memory serialization page. aoqi@0: // It write enables the page immediately after protecting it aoqi@0: // so just return. aoqi@0: if ( exception_code == EXCEPTION_ACCESS_VIOLATION ) { aoqi@0: JavaThread* thread = (JavaThread*) t; aoqi@0: PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; aoqi@0: address addr = (address) exceptionRecord->ExceptionInformation[1]; aoqi@0: if ( os::is_memory_serialize_page(thread, addr) ) { aoqi@0: // Block current thread until the memory serialize page permission restored. aoqi@0: os::block_on_serialize_page_trap(); aoqi@0: return EXCEPTION_CONTINUE_EXECUTION; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if ((exception_code == EXCEPTION_ACCESS_VIOLATION) && aoqi@0: VM_Version::is_cpuinfo_segv_addr(pc)) { aoqi@0: // Verify that OS save/restore AVX registers. aoqi@0: return Handle_Exception(exceptionInfo, VM_Version::cpuinfo_cont_addr()); aoqi@0: } aoqi@0: aoqi@0: if (t != NULL && t->is_Java_thread()) { aoqi@0: JavaThread* thread = (JavaThread*) t; aoqi@0: bool in_java = thread->thread_state() == _thread_in_Java; aoqi@0: aoqi@0: // Handle potential stack overflows up front. aoqi@0: if (exception_code == EXCEPTION_STACK_OVERFLOW) { aoqi@0: if (os::uses_stack_guard_pages()) { aoqi@0: #ifdef _M_IA64 aoqi@0: // Use guard page for register stack. aoqi@0: PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; aoqi@0: address addr = (address) exceptionRecord->ExceptionInformation[1]; aoqi@0: // Check for a register stack overflow on Itanium aoqi@0: if (thread->addr_inside_register_stack_red_zone(addr)) { aoqi@0: // Fatal red zone violation happens if the Java program aoqi@0: // catches a StackOverflow error and does so much processing aoqi@0: // that it runs beyond the unprotected yellow guard zone. As aoqi@0: // a result, we are out of here. aoqi@0: fatal("ERROR: Unrecoverable stack overflow happened. JVM will exit."); aoqi@0: } else if(thread->addr_inside_register_stack(addr)) { aoqi@0: // Disable the yellow zone which sets the state that aoqi@0: // we've got a stack overflow problem. aoqi@0: if (thread->stack_yellow_zone_enabled()) { aoqi@0: thread->disable_stack_yellow_zone(); aoqi@0: } aoqi@0: // Give us some room to process the exception. aoqi@0: thread->disable_register_stack_guard(); aoqi@0: // Tracing with +Verbose. aoqi@0: if (Verbose) { aoqi@0: tty->print_cr("SOF Compiled Register Stack overflow at " INTPTR_FORMAT " (SIGSEGV)", pc); aoqi@0: tty->print_cr("Register Stack access at " INTPTR_FORMAT, addr); aoqi@0: tty->print_cr("Register Stack base " INTPTR_FORMAT, thread->register_stack_base()); aoqi@0: tty->print_cr("Register Stack [" INTPTR_FORMAT "," INTPTR_FORMAT "]", aoqi@0: thread->register_stack_base(), aoqi@0: thread->register_stack_base() + thread->stack_size()); aoqi@0: } aoqi@0: aoqi@0: // Reguard the permanent register stack red zone just to be sure. aoqi@0: // We saw Windows silently disabling this without telling us. aoqi@0: thread->enable_register_stack_red_zone(); aoqi@0: aoqi@0: return Handle_Exception(exceptionInfo, aoqi@0: SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW)); aoqi@0: } aoqi@0: #endif aoqi@0: if (thread->stack_yellow_zone_enabled()) { aoqi@0: // Yellow zone violation. The o/s has unprotected the first yellow aoqi@0: // zone page for us. Note: must call disable_stack_yellow_zone to aoqi@0: // update the enabled status, even if the zone contains only one page. aoqi@0: thread->disable_stack_yellow_zone(); aoqi@0: // If not in java code, return and hope for the best. aoqi@0: return in_java ? Handle_Exception(exceptionInfo, aoqi@0: SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW)) aoqi@0: : EXCEPTION_CONTINUE_EXECUTION; aoqi@0: } else { aoqi@0: // Fatal red zone violation. aoqi@0: thread->disable_stack_red_zone(); aoqi@0: tty->print_raw_cr("An unrecoverable stack overflow has occurred."); aoqi@0: report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord, aoqi@0: exceptionInfo->ContextRecord); aoqi@0: return EXCEPTION_CONTINUE_SEARCH; aoqi@0: } aoqi@0: } else if (in_java) { aoqi@0: // JVM-managed guard pages cannot be used on win95/98. The o/s provides aoqi@0: // a one-time-only guard page, which it has released to us. The next aoqi@0: // stack overflow on this thread will result in an ACCESS_VIOLATION. aoqi@0: return Handle_Exception(exceptionInfo, aoqi@0: SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW)); aoqi@0: } else { aoqi@0: // Can only return and hope for the best. Further stack growth will aoqi@0: // result in an ACCESS_VIOLATION. aoqi@0: return EXCEPTION_CONTINUE_EXECUTION; aoqi@0: } aoqi@0: } else if (exception_code == EXCEPTION_ACCESS_VIOLATION) { aoqi@0: // Either stack overflow or null pointer exception. aoqi@0: if (in_java) { aoqi@0: PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; aoqi@0: address addr = (address) exceptionRecord->ExceptionInformation[1]; aoqi@0: address stack_end = thread->stack_base() - thread->stack_size(); aoqi@0: if (addr < stack_end && addr >= stack_end - os::vm_page_size()) { aoqi@0: // Stack overflow. aoqi@0: assert(!os::uses_stack_guard_pages(), aoqi@0: "should be caught by red zone code above."); aoqi@0: return Handle_Exception(exceptionInfo, aoqi@0: SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW)); aoqi@0: } aoqi@0: // aoqi@0: // Check for safepoint polling and implicit null aoqi@0: // We only expect null pointers in the stubs (vtable) aoqi@0: // the rest are checked explicitly now. aoqi@0: // aoqi@0: CodeBlob* cb = CodeCache::find_blob(pc); aoqi@0: if (cb != NULL) { aoqi@0: if (os::is_poll_address(addr)) { aoqi@0: address stub = SharedRuntime::get_poll_stub(pc); aoqi@0: return Handle_Exception(exceptionInfo, stub); aoqi@0: } aoqi@0: } aoqi@0: { aoqi@0: #ifdef _WIN64 aoqi@0: // aoqi@0: // If it's a legal stack address map the entire region in aoqi@0: // aoqi@0: PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; aoqi@0: address addr = (address) exceptionRecord->ExceptionInformation[1]; aoqi@0: if (addr > thread->stack_yellow_zone_base() && addr < thread->stack_base() ) { aoqi@0: addr = (address)((uintptr_t)addr & aoqi@0: (~((uintptr_t)os::vm_page_size() - (uintptr_t)1))); aoqi@0: os::commit_memory((char *)addr, thread->stack_base() - addr, aoqi@0: !ExecMem); aoqi@0: return EXCEPTION_CONTINUE_EXECUTION; aoqi@0: } aoqi@0: else aoqi@0: #endif aoqi@0: { aoqi@0: // Null pointer exception. aoqi@0: #ifdef _M_IA64 aoqi@0: // Process implicit null checks in compiled code. Note: Implicit null checks aoqi@0: // can happen even if "ImplicitNullChecks" is disabled, e.g. in vtable stubs. aoqi@0: if (CodeCache::contains((void*) pc_unix_format) && !MacroAssembler::needs_explicit_null_check((intptr_t) addr)) { aoqi@0: CodeBlob *cb = CodeCache::find_blob_unsafe(pc_unix_format); aoqi@0: // Handle implicit null check in UEP method entry aoqi@0: if (cb && (cb->is_frame_complete_at(pc) || aoqi@0: (cb->is_nmethod() && ((nmethod *)cb)->inlinecache_check_contains(pc)))) { aoqi@0: if (Verbose) { aoqi@0: intptr_t *bundle_start = (intptr_t*) ((intptr_t) pc_unix_format & 0xFFFFFFFFFFFFFFF0); aoqi@0: tty->print_cr("trap: null_check at " INTPTR_FORMAT " (SIGSEGV)", pc_unix_format); aoqi@0: tty->print_cr(" to addr " INTPTR_FORMAT, addr); aoqi@0: tty->print_cr(" bundle is " INTPTR_FORMAT " (high), " INTPTR_FORMAT " (low)", aoqi@0: *(bundle_start + 1), *bundle_start); aoqi@0: } aoqi@0: return Handle_Exception(exceptionInfo, aoqi@0: SharedRuntime::continuation_for_implicit_exception(thread, pc_unix_format, SharedRuntime::IMPLICIT_NULL)); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Implicit null checks were processed above. Hence, we should not reach aoqi@0: // here in the usual case => die! aoqi@0: if (Verbose) tty->print_raw_cr("Access violation, possible null pointer exception"); aoqi@0: report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord, aoqi@0: exceptionInfo->ContextRecord); aoqi@0: return EXCEPTION_CONTINUE_SEARCH; aoqi@0: aoqi@0: #else // !IA64 aoqi@0: aoqi@0: // Windows 98 reports faulting addresses incorrectly aoqi@0: if (!MacroAssembler::needs_explicit_null_check((intptr_t)addr) || aoqi@0: !os::win32::is_nt()) { aoqi@0: address stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL); aoqi@0: if (stub != NULL) return Handle_Exception(exceptionInfo, stub); aoqi@0: } aoqi@0: report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord, aoqi@0: exceptionInfo->ContextRecord); aoqi@0: return EXCEPTION_CONTINUE_SEARCH; aoqi@0: #endif aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: #ifdef _WIN64 aoqi@0: // Special care for fast JNI field accessors. aoqi@0: // jni_fast_GetField can trap at certain pc's if a GC kicks aoqi@0: // in and the heap gets shrunk before the field access. aoqi@0: if (exception_code == EXCEPTION_ACCESS_VIOLATION) { aoqi@0: address addr = JNI_FastGetField::find_slowcase_pc(pc); aoqi@0: if (addr != (address)-1) { aoqi@0: return Handle_Exception(exceptionInfo, addr); aoqi@0: } aoqi@0: } aoqi@0: #endif aoqi@0: aoqi@0: // Stack overflow or null pointer exception in native code. aoqi@0: report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord, aoqi@0: exceptionInfo->ContextRecord); aoqi@0: return EXCEPTION_CONTINUE_SEARCH; aoqi@0: } // /EXCEPTION_ACCESS_VIOLATION aoqi@0: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - aoqi@0: #if defined _M_IA64 aoqi@0: else if ((exception_code == EXCEPTION_ILLEGAL_INSTRUCTION || aoqi@0: exception_code == EXCEPTION_ILLEGAL_INSTRUCTION_2)) { aoqi@0: M37 handle_wrong_method_break(0, NativeJump::HANDLE_WRONG_METHOD, PR0); aoqi@0: aoqi@0: // Compiled method patched to be non entrant? Following conditions must apply: aoqi@0: // 1. must be first instruction in bundle aoqi@0: // 2. must be a break instruction with appropriate code aoqi@0: if((((uint64_t) pc & 0x0F) == 0) && aoqi@0: (((IPF_Bundle*) pc)->get_slot0() == handle_wrong_method_break.bits())) { aoqi@0: return Handle_Exception(exceptionInfo, aoqi@0: (address)SharedRuntime::get_handle_wrong_method_stub()); aoqi@0: } aoqi@0: } // /EXCEPTION_ILLEGAL_INSTRUCTION aoqi@0: #endif aoqi@0: aoqi@0: aoqi@0: if (in_java) { aoqi@0: switch (exception_code) { aoqi@0: case EXCEPTION_INT_DIVIDE_BY_ZERO: aoqi@0: return Handle_Exception(exceptionInfo, SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO)); aoqi@0: aoqi@0: case EXCEPTION_INT_OVERFLOW: aoqi@0: return Handle_IDiv_Exception(exceptionInfo); aoqi@0: aoqi@0: } // switch aoqi@0: } aoqi@0: #ifndef _WIN64 aoqi@0: if (((thread->thread_state() == _thread_in_Java) || aoqi@0: (thread->thread_state() == _thread_in_native)) && aoqi@0: exception_code != EXCEPTION_UNCAUGHT_CXX_EXCEPTION) aoqi@0: { aoqi@0: LONG result=Handle_FLT_Exception(exceptionInfo); aoqi@0: if (result==EXCEPTION_CONTINUE_EXECUTION) return result; aoqi@0: } aoqi@0: #endif //_WIN64 aoqi@0: } aoqi@0: aoqi@0: if (exception_code != EXCEPTION_BREAKPOINT) { aoqi@0: report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord, aoqi@0: exceptionInfo->ContextRecord); aoqi@0: } aoqi@0: return EXCEPTION_CONTINUE_SEARCH; aoqi@0: } aoqi@0: aoqi@0: #ifndef _WIN64 aoqi@0: // Special care for fast JNI accessors. aoqi@0: // jni_fast_GetField can trap at certain pc's if a GC kicks in and aoqi@0: // the heap gets shrunk before the field access. aoqi@0: // Need to install our own structured exception handler since native code may aoqi@0: // install its own. aoqi@0: LONG WINAPI fastJNIAccessorExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { aoqi@0: DWORD exception_code = exceptionInfo->ExceptionRecord->ExceptionCode; aoqi@0: if (exception_code == EXCEPTION_ACCESS_VIOLATION) { aoqi@0: address pc = (address) exceptionInfo->ContextRecord->Eip; aoqi@0: address addr = JNI_FastGetField::find_slowcase_pc(pc); aoqi@0: if (addr != (address)-1) { aoqi@0: return Handle_Exception(exceptionInfo, addr); aoqi@0: } aoqi@0: } aoqi@0: return EXCEPTION_CONTINUE_SEARCH; aoqi@0: } aoqi@0: aoqi@0: #define DEFINE_FAST_GETFIELD(Return,Fieldname,Result) \ aoqi@0: Return JNICALL jni_fast_Get##Result##Field_wrapper(JNIEnv *env, jobject obj, jfieldID fieldID) { \ aoqi@0: __try { \ aoqi@0: return (*JNI_FastGetField::jni_fast_Get##Result##Field_fp)(env, obj, fieldID); \ aoqi@0: } __except(fastJNIAccessorExceptionFilter((_EXCEPTION_POINTERS*)_exception_info())) { \ aoqi@0: } \ aoqi@0: return 0; \ aoqi@0: } aoqi@0: aoqi@0: DEFINE_FAST_GETFIELD(jboolean, bool, Boolean) aoqi@0: DEFINE_FAST_GETFIELD(jbyte, byte, Byte) aoqi@0: DEFINE_FAST_GETFIELD(jchar, char, Char) aoqi@0: DEFINE_FAST_GETFIELD(jshort, short, Short) aoqi@0: DEFINE_FAST_GETFIELD(jint, int, Int) aoqi@0: DEFINE_FAST_GETFIELD(jlong, long, Long) aoqi@0: DEFINE_FAST_GETFIELD(jfloat, float, Float) aoqi@0: DEFINE_FAST_GETFIELD(jdouble, double, Double) aoqi@0: aoqi@0: address os::win32::fast_jni_accessor_wrapper(BasicType type) { aoqi@0: switch (type) { aoqi@0: case T_BOOLEAN: return (address)jni_fast_GetBooleanField_wrapper; aoqi@0: case T_BYTE: return (address)jni_fast_GetByteField_wrapper; aoqi@0: case T_CHAR: return (address)jni_fast_GetCharField_wrapper; aoqi@0: case T_SHORT: return (address)jni_fast_GetShortField_wrapper; aoqi@0: case T_INT: return (address)jni_fast_GetIntField_wrapper; aoqi@0: case T_LONG: return (address)jni_fast_GetLongField_wrapper; aoqi@0: case T_FLOAT: return (address)jni_fast_GetFloatField_wrapper; aoqi@0: case T_DOUBLE: return (address)jni_fast_GetDoubleField_wrapper; aoqi@0: default: ShouldNotReachHere(); aoqi@0: } aoqi@0: return (address)-1; aoqi@0: } aoqi@0: #endif aoqi@0: aoqi@0: void os::win32::call_test_func_with_wrapper(void (*funcPtr)(void)) { aoqi@0: // Install a win32 structured exception handler around the test aoqi@0: // function call so the VM can generate an error dump if needed. aoqi@0: __try { aoqi@0: (*funcPtr)(); aoqi@0: } __except(topLevelExceptionFilter( aoqi@0: (_EXCEPTION_POINTERS*)_exception_info())) { aoqi@0: // Nothing to do. aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Virtual Memory aoqi@0: aoqi@0: int os::vm_page_size() { return os::win32::vm_page_size(); } aoqi@0: int os::vm_allocation_granularity() { aoqi@0: return os::win32::vm_allocation_granularity(); aoqi@0: } aoqi@0: aoqi@0: // Windows large page support is available on Windows 2003. In order to use aoqi@0: // large page memory, the administrator must first assign additional privilege aoqi@0: // to the user: aoqi@0: // + select Control Panel -> Administrative Tools -> Local Security Policy aoqi@0: // + select Local Policies -> User Rights Assignment aoqi@0: // + double click "Lock pages in memory", add users and/or groups aoqi@0: // + reboot aoqi@0: // Note the above steps are needed for administrator as well, as administrators aoqi@0: // by default do not have the privilege to lock pages in memory. aoqi@0: // aoqi@0: // Note about Windows 2003: although the API supports committing large page aoqi@0: // memory on a page-by-page basis and VirtualAlloc() returns success under this aoqi@0: // scenario, I found through experiment it only uses large page if the entire aoqi@0: // memory region is reserved and committed in a single VirtualAlloc() call. aoqi@0: // This makes Windows large page support more or less like Solaris ISM, in aoqi@0: // that the entire heap must be committed upfront. This probably will change aoqi@0: // in the future, if so the code below needs to be revisited. aoqi@0: aoqi@0: #ifndef MEM_LARGE_PAGES aoqi@0: #define MEM_LARGE_PAGES 0x20000000 aoqi@0: #endif aoqi@0: aoqi@0: static HANDLE _hProcess; aoqi@0: static HANDLE _hToken; aoqi@0: aoqi@0: // Container for NUMA node list info aoqi@0: class NUMANodeListHolder { aoqi@0: private: aoqi@0: int *_numa_used_node_list; // allocated below aoqi@0: int _numa_used_node_count; aoqi@0: aoqi@0: void free_node_list() { aoqi@0: if (_numa_used_node_list != NULL) { aoqi@0: FREE_C_HEAP_ARRAY(int, _numa_used_node_list, mtInternal); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public: aoqi@0: NUMANodeListHolder() { aoqi@0: _numa_used_node_count = 0; aoqi@0: _numa_used_node_list = NULL; aoqi@0: // do rest of initialization in build routine (after function pointers are set up) aoqi@0: } aoqi@0: aoqi@0: ~NUMANodeListHolder() { aoqi@0: free_node_list(); aoqi@0: } aoqi@0: aoqi@0: bool build() { aoqi@0: DWORD_PTR proc_aff_mask; aoqi@0: DWORD_PTR sys_aff_mask; aoqi@0: if (!GetProcessAffinityMask(GetCurrentProcess(), &proc_aff_mask, &sys_aff_mask)) return false; aoqi@0: ULONG highest_node_number; aoqi@0: if (!os::Kernel32Dll::GetNumaHighestNodeNumber(&highest_node_number)) return false; aoqi@0: free_node_list(); aoqi@0: _numa_used_node_list = NEW_C_HEAP_ARRAY(int, highest_node_number + 1, mtInternal); aoqi@0: for (unsigned int i = 0; i <= highest_node_number; i++) { aoqi@0: ULONGLONG proc_mask_numa_node; aoqi@0: if (!os::Kernel32Dll::GetNumaNodeProcessorMask(i, &proc_mask_numa_node)) return false; aoqi@0: if ((proc_aff_mask & proc_mask_numa_node)!=0) { aoqi@0: _numa_used_node_list[_numa_used_node_count++] = i; aoqi@0: } aoqi@0: } aoqi@0: return (_numa_used_node_count > 1); aoqi@0: } aoqi@0: aoqi@0: int get_count() {return _numa_used_node_count;} aoqi@0: int get_node_list_entry(int n) { aoqi@0: // for indexes out of range, returns -1 aoqi@0: return (n < _numa_used_node_count ? _numa_used_node_list[n] : -1); aoqi@0: } aoqi@0: aoqi@0: } numa_node_list_holder; aoqi@0: aoqi@0: aoqi@0: aoqi@0: static size_t _large_page_size = 0; aoqi@0: aoqi@0: static bool resolve_functions_for_large_page_init() { aoqi@0: return os::Kernel32Dll::GetLargePageMinimumAvailable() && aoqi@0: os::Advapi32Dll::AdvapiAvailable(); aoqi@0: } aoqi@0: aoqi@0: static bool request_lock_memory_privilege() { aoqi@0: _hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, aoqi@0: os::current_process_id()); aoqi@0: aoqi@0: LUID luid; aoqi@0: if (_hProcess != NULL && aoqi@0: os::Advapi32Dll::OpenProcessToken(_hProcess, TOKEN_ADJUST_PRIVILEGES, &_hToken) && aoqi@0: os::Advapi32Dll::LookupPrivilegeValue(NULL, "SeLockMemoryPrivilege", &luid)) { aoqi@0: aoqi@0: TOKEN_PRIVILEGES tp; aoqi@0: tp.PrivilegeCount = 1; aoqi@0: tp.Privileges[0].Luid = luid; aoqi@0: tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; aoqi@0: aoqi@0: // AdjustTokenPrivileges() may return TRUE even when it couldn't change the aoqi@0: // privilege. Check GetLastError() too. See MSDN document. aoqi@0: if (os::Advapi32Dll::AdjustTokenPrivileges(_hToken, false, &tp, sizeof(tp), NULL, NULL) && aoqi@0: (GetLastError() == ERROR_SUCCESS)) { aoqi@0: return true; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: static void cleanup_after_large_page_init() { aoqi@0: if (_hProcess) CloseHandle(_hProcess); aoqi@0: _hProcess = NULL; aoqi@0: if (_hToken) CloseHandle(_hToken); aoqi@0: _hToken = NULL; aoqi@0: } aoqi@0: aoqi@0: static bool numa_interleaving_init() { aoqi@0: bool success = false; aoqi@0: bool use_numa_interleaving_specified = !FLAG_IS_DEFAULT(UseNUMAInterleaving); aoqi@0: aoqi@0: // print a warning if UseNUMAInterleaving flag is specified on command line aoqi@0: bool warn_on_failure = use_numa_interleaving_specified; aoqi@0: # define WARN(msg) if (warn_on_failure) { warning(msg); } aoqi@0: aoqi@0: // NUMAInterleaveGranularity cannot be less than vm_allocation_granularity (or _large_page_size if using large pages) aoqi@0: size_t min_interleave_granularity = UseLargePages ? _large_page_size : os::vm_allocation_granularity(); aoqi@0: NUMAInterleaveGranularity = align_size_up(NUMAInterleaveGranularity, min_interleave_granularity); aoqi@0: aoqi@0: if (os::Kernel32Dll::NumaCallsAvailable()) { aoqi@0: if (numa_node_list_holder.build()) { aoqi@0: if (PrintMiscellaneous && Verbose) { aoqi@0: tty->print("NUMA UsedNodeCount=%d, namely ", numa_node_list_holder.get_count()); aoqi@0: for (int i = 0; i < numa_node_list_holder.get_count(); i++) { aoqi@0: tty->print("%d ", numa_node_list_holder.get_node_list_entry(i)); aoqi@0: } aoqi@0: tty->print("\n"); aoqi@0: } aoqi@0: success = true; aoqi@0: } else { aoqi@0: WARN("Process does not cover multiple NUMA nodes."); aoqi@0: } aoqi@0: } else { aoqi@0: WARN("NUMA Interleaving is not supported by the operating system."); aoqi@0: } aoqi@0: if (!success) { aoqi@0: if (use_numa_interleaving_specified) WARN("...Ignoring UseNUMAInterleaving flag."); aoqi@0: } aoqi@0: return success; aoqi@0: #undef WARN aoqi@0: } aoqi@0: aoqi@0: // this routine is used whenever we need to reserve a contiguous VA range aoqi@0: // but we need to make separate VirtualAlloc calls for each piece of the range aoqi@0: // Reasons for doing this: aoqi@0: // * UseLargePagesIndividualAllocation was set (normally only needed on WS2003 but possible to be set otherwise) aoqi@0: // * UseNUMAInterleaving requires a separate node for each piece aoqi@0: static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, DWORD prot, aoqi@0: bool should_inject_error=false) { aoqi@0: char * p_buf; aoqi@0: // note: at setup time we guaranteed that NUMAInterleaveGranularity was aligned up to a page size aoqi@0: size_t page_size = UseLargePages ? _large_page_size : os::vm_allocation_granularity(); aoqi@0: size_t chunk_size = UseNUMAInterleaving ? NUMAInterleaveGranularity : page_size; aoqi@0: aoqi@0: // first reserve enough address space in advance since we want to be aoqi@0: // able to break a single contiguous virtual address range into multiple aoqi@0: // large page commits but WS2003 does not allow reserving large page space aoqi@0: // so we just use 4K pages for reserve, this gives us a legal contiguous aoqi@0: // address space. then we will deallocate that reservation, and re alloc aoqi@0: // using large pages aoqi@0: const size_t size_of_reserve = bytes + chunk_size; aoqi@0: if (bytes > size_of_reserve) { aoqi@0: // Overflowed. aoqi@0: return NULL; aoqi@0: } aoqi@0: p_buf = (char *) VirtualAlloc(addr, aoqi@0: size_of_reserve, // size of Reserve aoqi@0: MEM_RESERVE, aoqi@0: PAGE_READWRITE); aoqi@0: // If reservation failed, return NULL aoqi@0: if (p_buf == NULL) return NULL; aoqi@0: MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, mtNone, CALLER_PC); aoqi@0: os::release_memory(p_buf, bytes + chunk_size); aoqi@0: aoqi@0: // we still need to round up to a page boundary (in case we are using large pages) aoqi@0: // but not to a chunk boundary (in case InterleavingGranularity doesn't align with page size) aoqi@0: // instead we handle this in the bytes_to_rq computation below aoqi@0: p_buf = (char *) align_size_up((size_t)p_buf, page_size); aoqi@0: aoqi@0: // now go through and allocate one chunk at a time until all bytes are aoqi@0: // allocated aoqi@0: size_t bytes_remaining = bytes; aoqi@0: // An overflow of align_size_up() would have been caught above aoqi@0: // in the calculation of size_of_reserve. aoqi@0: char * next_alloc_addr = p_buf; aoqi@0: HANDLE hProc = GetCurrentProcess(); aoqi@0: aoqi@0: #ifdef ASSERT aoqi@0: // Variable for the failure injection aoqi@0: long ran_num = os::random(); aoqi@0: size_t fail_after = ran_num % bytes; aoqi@0: #endif aoqi@0: aoqi@0: int count=0; aoqi@0: while (bytes_remaining) { aoqi@0: // select bytes_to_rq to get to the next chunk_size boundary aoqi@0: aoqi@0: size_t bytes_to_rq = MIN2(bytes_remaining, chunk_size - ((size_t)next_alloc_addr % chunk_size)); aoqi@0: // Note allocate and commit aoqi@0: char * p_new; aoqi@0: aoqi@0: #ifdef ASSERT aoqi@0: bool inject_error_now = should_inject_error && (bytes_remaining <= fail_after); aoqi@0: #else aoqi@0: const bool inject_error_now = false; aoqi@0: #endif aoqi@0: aoqi@0: if (inject_error_now) { aoqi@0: p_new = NULL; aoqi@0: } else { aoqi@0: if (!UseNUMAInterleaving) { aoqi@0: p_new = (char *) VirtualAlloc(next_alloc_addr, aoqi@0: bytes_to_rq, aoqi@0: flags, aoqi@0: prot); aoqi@0: } else { aoqi@0: // get the next node to use from the used_node_list aoqi@0: assert(numa_node_list_holder.get_count() > 0, "Multiple NUMA nodes expected"); aoqi@0: DWORD node = numa_node_list_holder.get_node_list_entry(count % numa_node_list_holder.get_count()); aoqi@0: p_new = (char *)os::Kernel32Dll::VirtualAllocExNuma(hProc, aoqi@0: next_alloc_addr, aoqi@0: bytes_to_rq, aoqi@0: flags, aoqi@0: prot, aoqi@0: node); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if (p_new == NULL) { aoqi@0: // Free any allocated pages aoqi@0: if (next_alloc_addr > p_buf) { aoqi@0: // Some memory was committed so release it. aoqi@0: size_t bytes_to_release = bytes - bytes_remaining; aoqi@0: // NMT has yet to record any individual blocks, so it aoqi@0: // need to create a dummy 'reserve' record to match aoqi@0: // the release. aoqi@0: MemTracker::record_virtual_memory_reserve((address)p_buf, aoqi@0: bytes_to_release, mtNone, CALLER_PC); aoqi@0: os::release_memory(p_buf, bytes_to_release); aoqi@0: } aoqi@0: #ifdef ASSERT aoqi@0: if (should_inject_error) { aoqi@0: if (TracePageSizes && Verbose) { aoqi@0: tty->print_cr("Reserving pages individually failed."); aoqi@0: } aoqi@0: } aoqi@0: #endif aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: bytes_remaining -= bytes_to_rq; aoqi@0: next_alloc_addr += bytes_to_rq; aoqi@0: count++; aoqi@0: } aoqi@0: // Although the memory is allocated individually, it is returned as one. aoqi@0: // NMT records it as one block. aoqi@0: address pc = CALLER_PC; aoqi@0: if ((flags & MEM_COMMIT) != 0) { aoqi@0: MemTracker::record_virtual_memory_reserve_and_commit((address)p_buf, bytes, mtNone, pc); aoqi@0: } else { aoqi@0: MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, mtNone, pc); aoqi@0: } aoqi@0: aoqi@0: // made it this far, success aoqi@0: return p_buf; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: aoqi@0: void os::large_page_init() { aoqi@0: if (!UseLargePages) return; aoqi@0: aoqi@0: // print a warning if any large page related flag is specified on command line aoqi@0: bool warn_on_failure = !FLAG_IS_DEFAULT(UseLargePages) || aoqi@0: !FLAG_IS_DEFAULT(LargePageSizeInBytes); aoqi@0: bool success = false; aoqi@0: aoqi@0: # define WARN(msg) if (warn_on_failure) { warning(msg); } aoqi@0: if (resolve_functions_for_large_page_init()) { aoqi@0: if (request_lock_memory_privilege()) { aoqi@0: size_t s = os::Kernel32Dll::GetLargePageMinimum(); aoqi@0: if (s) { aoqi@0: #if defined(IA32) || defined(AMD64) aoqi@0: if (s > 4*M || LargePageSizeInBytes > 4*M) { aoqi@0: WARN("JVM cannot use large pages bigger than 4mb."); aoqi@0: } else { aoqi@0: #endif aoqi@0: if (LargePageSizeInBytes && LargePageSizeInBytes % s == 0) { aoqi@0: _large_page_size = LargePageSizeInBytes; aoqi@0: } else { aoqi@0: _large_page_size = s; aoqi@0: } aoqi@0: success = true; aoqi@0: #if defined(IA32) || defined(AMD64) aoqi@0: } aoqi@0: #endif aoqi@0: } else { aoqi@0: WARN("Large page is not supported by the processor."); aoqi@0: } aoqi@0: } else { aoqi@0: WARN("JVM cannot use large page memory because it does not have enough privilege to lock pages in memory."); aoqi@0: } aoqi@0: } else { aoqi@0: WARN("Large page is not supported by the operating system."); aoqi@0: } aoqi@0: #undef WARN aoqi@0: aoqi@0: const size_t default_page_size = (size_t) vm_page_size(); aoqi@0: if (success && _large_page_size > default_page_size) { aoqi@0: _page_sizes[0] = _large_page_size; aoqi@0: _page_sizes[1] = default_page_size; aoqi@0: _page_sizes[2] = 0; aoqi@0: } aoqi@0: aoqi@0: cleanup_after_large_page_init(); aoqi@0: UseLargePages = success; aoqi@0: } aoqi@0: aoqi@0: // On win32, one cannot release just a part of reserved memory, it's an aoqi@0: // all or nothing deal. When we split a reservation, we must break the aoqi@0: // reservation into two reservations. aoqi@0: void os::pd_split_reserved_memory(char *base, size_t size, size_t split, aoqi@0: bool realloc) { aoqi@0: if (size > 0) { aoqi@0: release_memory(base, size); aoqi@0: if (realloc) { aoqi@0: reserve_memory(split, base); aoqi@0: } aoqi@0: if (size != split) { aoqi@0: reserve_memory(size - split, base + split); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Multiple threads can race in this code but it's not possible to unmap small sections of aoqi@0: // virtual space to get requested alignment, like posix-like os's. aoqi@0: // Windows prevents multiple thread from remapping over each other so this loop is thread-safe. aoqi@0: char* os::reserve_memory_aligned(size_t size, size_t alignment) { aoqi@0: assert((alignment & (os::vm_allocation_granularity() - 1)) == 0, aoqi@0: "Alignment must be a multiple of allocation granularity (page size)"); aoqi@0: assert((size & (alignment -1)) == 0, "size must be 'alignment' aligned"); aoqi@0: aoqi@0: size_t extra_size = size + alignment; aoqi@0: assert(extra_size >= size, "overflow, size is too large to allow alignment"); aoqi@0: aoqi@0: char* aligned_base = NULL; aoqi@0: aoqi@0: do { aoqi@0: char* extra_base = os::reserve_memory(extra_size, NULL, alignment); aoqi@0: if (extra_base == NULL) { aoqi@0: return NULL; aoqi@0: } aoqi@0: // Do manual alignment aoqi@0: aligned_base = (char*) align_size_up((uintptr_t) extra_base, alignment); aoqi@0: aoqi@0: os::release_memory(extra_base, extra_size); aoqi@0: aoqi@0: aligned_base = os::reserve_memory(size, aligned_base); aoqi@0: aoqi@0: } while (aligned_base == NULL); aoqi@0: aoqi@0: return aligned_base; aoqi@0: } aoqi@0: aoqi@0: char* os::pd_reserve_memory(size_t bytes, char* addr, size_t alignment_hint) { aoqi@0: assert((size_t)addr % os::vm_allocation_granularity() == 0, aoqi@0: "reserve alignment"); aoqi@0: assert(bytes % os::vm_allocation_granularity() == 0, "reserve block size"); aoqi@0: char* res; aoqi@0: // note that if UseLargePages is on, all the areas that require interleaving aoqi@0: // will go thru reserve_memory_special rather than thru here. aoqi@0: bool use_individual = (UseNUMAInterleaving && !UseLargePages); aoqi@0: if (!use_individual) { aoqi@0: res = (char*)VirtualAlloc(addr, bytes, MEM_RESERVE, PAGE_READWRITE); aoqi@0: } else { aoqi@0: elapsedTimer reserveTimer; aoqi@0: if( Verbose && PrintMiscellaneous ) reserveTimer.start(); aoqi@0: // in numa interleaving, we have to allocate pages individually aoqi@0: // (well really chunks of NUMAInterleaveGranularity size) aoqi@0: res = allocate_pages_individually(bytes, addr, MEM_RESERVE, PAGE_READWRITE); aoqi@0: if (res == NULL) { aoqi@0: warning("NUMA page allocation failed"); aoqi@0: } aoqi@0: if( Verbose && PrintMiscellaneous ) { aoqi@0: reserveTimer.stop(); aoqi@0: tty->print_cr("reserve_memory of %Ix bytes took " JLONG_FORMAT " ms (" JLONG_FORMAT " ticks)", bytes, aoqi@0: reserveTimer.milliseconds(), reserveTimer.ticks()); aoqi@0: } aoqi@0: } aoqi@0: assert(res == NULL || addr == NULL || addr == res, aoqi@0: "Unexpected address from reserve."); aoqi@0: aoqi@0: return res; aoqi@0: } aoqi@0: aoqi@0: // Reserve memory at an arbitrary address, only if that area is aoqi@0: // available (and not reserved for something else). aoqi@0: char* os::pd_attempt_reserve_memory_at(size_t bytes, char* requested_addr) { aoqi@0: // Windows os::reserve_memory() fails of the requested address range is aoqi@0: // not avilable. aoqi@0: return reserve_memory(bytes, requested_addr); aoqi@0: } aoqi@0: aoqi@0: size_t os::large_page_size() { aoqi@0: return _large_page_size; aoqi@0: } aoqi@0: aoqi@0: bool os::can_commit_large_page_memory() { aoqi@0: // Windows only uses large page memory when the entire region is reserved aoqi@0: // and committed in a single VirtualAlloc() call. This may change in the aoqi@0: // future, but with Windows 2003 it's not possible to commit on demand. aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: bool os::can_execute_large_page_memory() { aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: char* os::reserve_memory_special(size_t bytes, size_t alignment, char* addr, bool exec) { aoqi@0: assert(UseLargePages, "only for large pages"); aoqi@0: aoqi@0: if (!is_size_aligned(bytes, os::large_page_size()) || alignment > os::large_page_size()) { aoqi@0: return NULL; // Fallback to small pages. aoqi@0: } aoqi@0: aoqi@0: const DWORD prot = exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; aoqi@0: const DWORD flags = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES; aoqi@0: aoqi@0: // with large pages, there are two cases where we need to use Individual Allocation aoqi@0: // 1) the UseLargePagesIndividualAllocation flag is set (set by default on WS2003) aoqi@0: // 2) NUMA Interleaving is enabled, in which case we use a different node for each page aoqi@0: if (UseLargePagesIndividualAllocation || UseNUMAInterleaving) { aoqi@0: if (TracePageSizes && Verbose) { aoqi@0: tty->print_cr("Reserving large pages individually."); aoqi@0: } aoqi@0: char * p_buf = allocate_pages_individually(bytes, addr, flags, prot, LargePagesIndividualAllocationInjectError); aoqi@0: if (p_buf == NULL) { aoqi@0: // give an appropriate warning message aoqi@0: if (UseNUMAInterleaving) { aoqi@0: warning("NUMA large page allocation failed, UseLargePages flag ignored"); aoqi@0: } aoqi@0: if (UseLargePagesIndividualAllocation) { aoqi@0: warning("Individually allocated large pages failed, " aoqi@0: "use -XX:-UseLargePagesIndividualAllocation to turn off"); aoqi@0: } aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: return p_buf; aoqi@0: aoqi@0: } else { aoqi@0: if (TracePageSizes && Verbose) { aoqi@0: tty->print_cr("Reserving large pages in a single large chunk."); aoqi@0: } aoqi@0: // normal policy just allocate it all at once aoqi@0: DWORD flag = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES; aoqi@0: char * res = (char *)VirtualAlloc(addr, bytes, flag, prot); aoqi@0: if (res != NULL) { aoqi@0: address pc = CALLER_PC; aoqi@0: MemTracker::record_virtual_memory_reserve_and_commit((address)res, bytes, mtNone, pc); aoqi@0: } aoqi@0: aoqi@0: return res; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: bool os::release_memory_special(char* base, size_t bytes) { aoqi@0: assert(base != NULL, "Sanity check"); aoqi@0: return release_memory(base, bytes); aoqi@0: } aoqi@0: aoqi@0: void os::print_statistics() { aoqi@0: } aoqi@0: aoqi@0: static void warn_fail_commit_memory(char* addr, size_t bytes, bool exec) { aoqi@0: int err = os::get_last_error(); aoqi@0: char buf[256]; aoqi@0: size_t buf_len = os::lasterror(buf, sizeof(buf)); aoqi@0: warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT aoqi@0: ", %d) failed; error='%s' (DOS error/errno=%d)", addr, bytes, aoqi@0: exec, buf_len != 0 ? buf : "", err); aoqi@0: } aoqi@0: aoqi@0: bool os::pd_commit_memory(char* addr, size_t bytes, bool exec) { aoqi@0: if (bytes == 0) { aoqi@0: // Don't bother the OS with noops. aoqi@0: return true; aoqi@0: } aoqi@0: assert((size_t) addr % os::vm_page_size() == 0, "commit on page boundaries"); aoqi@0: assert(bytes % os::vm_page_size() == 0, "commit in page-sized chunks"); aoqi@0: // Don't attempt to print anything if the OS call fails. We're aoqi@0: // probably low on resources, so the print itself may cause crashes. aoqi@0: aoqi@0: // unless we have NUMAInterleaving enabled, the range of a commit aoqi@0: // is always within a reserve covered by a single VirtualAlloc aoqi@0: // in that case we can just do a single commit for the requested size aoqi@0: if (!UseNUMAInterleaving) { aoqi@0: if (VirtualAlloc(addr, bytes, MEM_COMMIT, PAGE_READWRITE) == NULL) { aoqi@0: NOT_PRODUCT(warn_fail_commit_memory(addr, bytes, exec);) aoqi@0: return false; aoqi@0: } aoqi@0: if (exec) { aoqi@0: DWORD oldprot; aoqi@0: // Windows doc says to use VirtualProtect to get execute permissions aoqi@0: if (!VirtualProtect(addr, bytes, PAGE_EXECUTE_READWRITE, &oldprot)) { aoqi@0: NOT_PRODUCT(warn_fail_commit_memory(addr, bytes, exec);) aoqi@0: return false; aoqi@0: } aoqi@0: } aoqi@0: return true; aoqi@0: } else { aoqi@0: aoqi@0: // when NUMAInterleaving is enabled, the commit might cover a range that aoqi@0: // came from multiple VirtualAlloc reserves (using allocate_pages_individually). aoqi@0: // VirtualQuery can help us determine that. The RegionSize that VirtualQuery aoqi@0: // returns represents the number of bytes that can be committed in one step. aoqi@0: size_t bytes_remaining = bytes; aoqi@0: char * next_alloc_addr = addr; aoqi@0: while (bytes_remaining > 0) { aoqi@0: MEMORY_BASIC_INFORMATION alloc_info; aoqi@0: VirtualQuery(next_alloc_addr, &alloc_info, sizeof(alloc_info)); aoqi@0: size_t bytes_to_rq = MIN2(bytes_remaining, (size_t)alloc_info.RegionSize); aoqi@0: if (VirtualAlloc(next_alloc_addr, bytes_to_rq, MEM_COMMIT, aoqi@0: PAGE_READWRITE) == NULL) { aoqi@0: NOT_PRODUCT(warn_fail_commit_memory(next_alloc_addr, bytes_to_rq, aoqi@0: exec);) aoqi@0: return false; aoqi@0: } aoqi@0: if (exec) { aoqi@0: DWORD oldprot; aoqi@0: if (!VirtualProtect(next_alloc_addr, bytes_to_rq, aoqi@0: PAGE_EXECUTE_READWRITE, &oldprot)) { aoqi@0: NOT_PRODUCT(warn_fail_commit_memory(next_alloc_addr, bytes_to_rq, aoqi@0: exec);) aoqi@0: return false; aoqi@0: } aoqi@0: } aoqi@0: bytes_remaining -= bytes_to_rq; aoqi@0: next_alloc_addr += bytes_to_rq; aoqi@0: } aoqi@0: } aoqi@0: // if we made it this far, return true aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: bool os::pd_commit_memory(char* addr, size_t size, size_t alignment_hint, aoqi@0: bool exec) { aoqi@0: // alignment_hint is ignored on this OS aoqi@0: return pd_commit_memory(addr, size, exec); aoqi@0: } aoqi@0: aoqi@0: void os::pd_commit_memory_or_exit(char* addr, size_t size, bool exec, aoqi@0: const char* mesg) { aoqi@0: assert(mesg != NULL, "mesg must be specified"); aoqi@0: if (!pd_commit_memory(addr, size, exec)) { aoqi@0: warn_fail_commit_memory(addr, size, exec); aoqi@0: vm_exit_out_of_memory(size, OOM_MMAP_ERROR, mesg); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void os::pd_commit_memory_or_exit(char* addr, size_t size, aoqi@0: size_t alignment_hint, bool exec, aoqi@0: const char* mesg) { aoqi@0: // alignment_hint is ignored on this OS aoqi@0: pd_commit_memory_or_exit(addr, size, exec, mesg); aoqi@0: } aoqi@0: aoqi@0: bool os::pd_uncommit_memory(char* addr, size_t bytes) { aoqi@0: if (bytes == 0) { aoqi@0: // Don't bother the OS with noops. aoqi@0: return true; aoqi@0: } aoqi@0: assert((size_t) addr % os::vm_page_size() == 0, "uncommit on page boundaries"); aoqi@0: assert(bytes % os::vm_page_size() == 0, "uncommit in page-sized chunks"); aoqi@0: return (VirtualFree(addr, bytes, MEM_DECOMMIT) != 0); aoqi@0: } aoqi@0: aoqi@0: bool os::pd_release_memory(char* addr, size_t bytes) { aoqi@0: return VirtualFree(addr, 0, MEM_RELEASE) != 0; aoqi@0: } aoqi@0: aoqi@0: bool os::pd_create_stack_guard_pages(char* addr, size_t size) { aoqi@0: return os::commit_memory(addr, size, !ExecMem); aoqi@0: } aoqi@0: aoqi@0: bool os::remove_stack_guard_pages(char* addr, size_t size) { aoqi@0: return os::uncommit_memory(addr, size); aoqi@0: } aoqi@0: aoqi@0: // Set protections specified aoqi@0: bool os::protect_memory(char* addr, size_t bytes, ProtType prot, aoqi@0: bool is_committed) { aoqi@0: unsigned int p = 0; aoqi@0: switch (prot) { aoqi@0: case MEM_PROT_NONE: p = PAGE_NOACCESS; break; aoqi@0: case MEM_PROT_READ: p = PAGE_READONLY; break; aoqi@0: case MEM_PROT_RW: p = PAGE_READWRITE; break; aoqi@0: case MEM_PROT_RWX: p = PAGE_EXECUTE_READWRITE; break; aoqi@0: default: aoqi@0: ShouldNotReachHere(); aoqi@0: } aoqi@0: aoqi@0: DWORD old_status; aoqi@0: aoqi@0: // Strange enough, but on Win32 one can change protection only for committed aoqi@0: // memory, not a big deal anyway, as bytes less or equal than 64K aoqi@0: if (!is_committed) { aoqi@0: commit_memory_or_exit(addr, bytes, prot == MEM_PROT_RWX, aoqi@0: "cannot commit protection page"); aoqi@0: } aoqi@0: // One cannot use os::guard_memory() here, as on Win32 guard page aoqi@0: // have different (one-shot) semantics, from MSDN on PAGE_GUARD: aoqi@0: // aoqi@0: // Pages in the region become guard pages. Any attempt to access a guard page aoqi@0: // causes the system to raise a STATUS_GUARD_PAGE exception and turn off aoqi@0: // the guard page status. Guard pages thus act as a one-time access alarm. aoqi@0: return VirtualProtect(addr, bytes, p, &old_status) != 0; aoqi@0: } aoqi@0: aoqi@0: bool os::guard_memory(char* addr, size_t bytes) { aoqi@0: DWORD old_status; aoqi@0: return VirtualProtect(addr, bytes, PAGE_READWRITE | PAGE_GUARD, &old_status) != 0; aoqi@0: } aoqi@0: aoqi@0: bool os::unguard_memory(char* addr, size_t bytes) { aoqi@0: DWORD old_status; aoqi@0: return VirtualProtect(addr, bytes, PAGE_READWRITE, &old_status) != 0; aoqi@0: } aoqi@0: aoqi@0: void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { } aoqi@0: void os::pd_free_memory(char *addr, size_t bytes, size_t alignment_hint) { } aoqi@0: void os::numa_make_global(char *addr, size_t bytes) { } aoqi@0: void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { } aoqi@0: bool os::numa_topology_changed() { return false; } aoqi@0: size_t os::numa_get_groups_num() { return MAX2(numa_node_list_holder.get_count(), 1); } aoqi@0: int os::numa_get_group_id() { return 0; } aoqi@0: size_t os::numa_get_leaf_groups(int *ids, size_t size) { aoqi@0: if (numa_node_list_holder.get_count() == 0 && size > 0) { aoqi@0: // Provide an answer for UMA systems aoqi@0: ids[0] = 0; aoqi@0: return 1; aoqi@0: } else { aoqi@0: // check for size bigger than actual groups_num aoqi@0: size = MIN2(size, numa_get_groups_num()); aoqi@0: for (int i = 0; i < (int)size; i++) { aoqi@0: ids[i] = numa_node_list_holder.get_node_list_entry(i); aoqi@0: } aoqi@0: return size; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: bool os::get_page_info(char *start, page_info* info) { aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: char *os::scan_pages(char *start, char* end, page_info* page_expected, page_info* page_found) { aoqi@0: return end; aoqi@0: } aoqi@0: aoqi@0: char* os::non_memory_address_word() { aoqi@0: // Must never look like an address returned by reserve_memory, aoqi@0: // even in its subfields (as defined by the CPU immediate fields, aoqi@0: // if the CPU splits constants across multiple instructions). aoqi@0: return (char*)-1; aoqi@0: } aoqi@0: aoqi@0: #define MAX_ERROR_COUNT 100 aoqi@0: #define SYS_THREAD_ERROR 0xffffffffUL aoqi@0: aoqi@0: void os::pd_start_thread(Thread* thread) { aoqi@0: DWORD ret = ResumeThread(thread->osthread()->thread_handle()); aoqi@0: // Returns previous suspend state: aoqi@0: // 0: Thread was not suspended aoqi@0: // 1: Thread is running now aoqi@0: // >1: Thread is still suspended. aoqi@0: assert(ret != SYS_THREAD_ERROR, "StartThread failed"); // should propagate back aoqi@0: } aoqi@0: aoqi@0: class HighResolutionInterval : public CHeapObj { aoqi@0: // The default timer resolution seems to be 10 milliseconds. aoqi@0: // (Where is this written down?) aoqi@0: // If someone wants to sleep for only a fraction of the default, aoqi@0: // then we set the timer resolution down to 1 millisecond for aoqi@0: // the duration of their interval. aoqi@0: // We carefully set the resolution back, since otherwise we aoqi@0: // seem to incur an overhead (3%?) that we don't need. aoqi@0: // CONSIDER: if ms is small, say 3, then we should run with a high resolution time. aoqi@0: // Buf if ms is large, say 500, or 503, we should avoid the call to timeBeginPeriod(). aoqi@0: // Alternatively, we could compute the relative error (503/500 = .6%) and only use aoqi@0: // timeBeginPeriod() if the relative error exceeded some threshold. aoqi@0: // timeBeginPeriod() has been linked to problems with clock drift on win32 systems and aoqi@0: // to decreased efficiency related to increased timer "tick" rates. We want to minimize aoqi@0: // (a) calls to timeBeginPeriod() and timeEndPeriod() and (b) time spent with high aoqi@0: // resolution timers running. aoqi@0: private: aoqi@0: jlong resolution; aoqi@0: public: aoqi@0: HighResolutionInterval(jlong ms) { aoqi@0: resolution = ms % 10L; aoqi@0: if (resolution != 0) { aoqi@0: MMRESULT result = timeBeginPeriod(1L); aoqi@0: } aoqi@0: } aoqi@0: ~HighResolutionInterval() { aoqi@0: if (resolution != 0) { aoqi@0: MMRESULT result = timeEndPeriod(1L); aoqi@0: } aoqi@0: resolution = 0L; aoqi@0: } aoqi@0: }; aoqi@0: aoqi@0: int os::sleep(Thread* thread, jlong ms, bool interruptable) { aoqi@0: jlong limit = (jlong) MAXDWORD; aoqi@0: aoqi@0: while(ms > limit) { aoqi@0: int res; aoqi@0: if ((res = sleep(thread, limit, interruptable)) != OS_TIMEOUT) aoqi@0: return res; aoqi@0: ms -= limit; aoqi@0: } aoqi@0: aoqi@0: assert(thread == Thread::current(), "thread consistency check"); aoqi@0: OSThread* osthread = thread->osthread(); aoqi@0: OSThreadWaitState osts(osthread, false /* not Object.wait() */); aoqi@0: int result; aoqi@0: if (interruptable) { aoqi@0: assert(thread->is_Java_thread(), "must be java thread"); aoqi@0: JavaThread *jt = (JavaThread *) thread; aoqi@0: ThreadBlockInVM tbivm(jt); aoqi@0: aoqi@0: jt->set_suspend_equivalent(); aoqi@0: // cleared by handle_special_suspend_equivalent_condition() or aoqi@0: // java_suspend_self() via check_and_wait_while_suspended() aoqi@0: aoqi@0: HANDLE events[1]; aoqi@0: events[0] = osthread->interrupt_event(); aoqi@0: HighResolutionInterval *phri=NULL; aoqi@0: if(!ForceTimeHighResolution) aoqi@0: phri = new HighResolutionInterval( ms ); aoqi@0: if (WaitForMultipleObjects(1, events, FALSE, (DWORD)ms) == WAIT_TIMEOUT) { aoqi@0: result = OS_TIMEOUT; aoqi@0: } else { aoqi@0: ResetEvent(osthread->interrupt_event()); aoqi@0: osthread->set_interrupted(false); aoqi@0: result = OS_INTRPT; aoqi@0: } aoqi@0: delete phri; //if it is NULL, harmless aoqi@0: aoqi@0: // were we externally suspended while we were waiting? aoqi@0: jt->check_and_wait_while_suspended(); aoqi@0: } else { aoqi@0: assert(!thread->is_Java_thread(), "must not be java thread"); aoqi@0: Sleep((long) ms); aoqi@0: result = OS_TIMEOUT; aoqi@0: } aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: // aoqi@0: // Short sleep, direct OS call. aoqi@0: // aoqi@0: // ms = 0, means allow others (if any) to run. aoqi@0: // aoqi@0: void os::naked_short_sleep(jlong ms) { aoqi@0: assert(ms < 1000, "Un-interruptable sleep, short time use only"); aoqi@0: Sleep(ms); aoqi@0: } aoqi@0: aoqi@0: // Sleep forever; naked call to OS-specific sleep; use with CAUTION aoqi@0: void os::infinite_sleep() { aoqi@0: while (true) { // sleep forever ... aoqi@0: Sleep(100000); // ... 100 seconds at a time aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: typedef BOOL (WINAPI * STTSignature)(void) ; aoqi@0: aoqi@0: os::YieldResult os::NakedYield() { aoqi@0: // Use either SwitchToThread() or Sleep(0) aoqi@0: // Consider passing back the return value from SwitchToThread(). aoqi@0: if (os::Kernel32Dll::SwitchToThreadAvailable()) { aoqi@0: return SwitchToThread() ? os::YIELD_SWITCHED : os::YIELD_NONEREADY ; aoqi@0: } else { aoqi@0: Sleep(0); aoqi@0: } aoqi@0: return os::YIELD_UNKNOWN ; aoqi@0: } aoqi@0: aoqi@0: void os::yield() { os::NakedYield(); } aoqi@0: aoqi@0: void os::yield_all(int attempts) { aoqi@0: // Yields to all threads, including threads with lower priorities aoqi@0: Sleep(1); aoqi@0: } aoqi@0: aoqi@0: // Win32 only gives you access to seven real priorities at a time, aoqi@0: // so we compress Java's ten down to seven. It would be better aoqi@0: // if we dynamically adjusted relative priorities. aoqi@0: aoqi@0: int os::java_to_os_priority[CriticalPriority + 1] = { aoqi@0: THREAD_PRIORITY_IDLE, // 0 Entry should never be used aoqi@0: THREAD_PRIORITY_LOWEST, // 1 MinPriority aoqi@0: THREAD_PRIORITY_LOWEST, // 2 aoqi@0: THREAD_PRIORITY_BELOW_NORMAL, // 3 aoqi@0: THREAD_PRIORITY_BELOW_NORMAL, // 4 aoqi@0: THREAD_PRIORITY_NORMAL, // 5 NormPriority aoqi@0: THREAD_PRIORITY_NORMAL, // 6 aoqi@0: THREAD_PRIORITY_ABOVE_NORMAL, // 7 aoqi@0: THREAD_PRIORITY_ABOVE_NORMAL, // 8 aoqi@0: THREAD_PRIORITY_HIGHEST, // 9 NearMaxPriority aoqi@0: THREAD_PRIORITY_HIGHEST, // 10 MaxPriority aoqi@0: THREAD_PRIORITY_HIGHEST // 11 CriticalPriority aoqi@0: }; aoqi@0: aoqi@0: int prio_policy1[CriticalPriority + 1] = { aoqi@0: THREAD_PRIORITY_IDLE, // 0 Entry should never be used aoqi@0: THREAD_PRIORITY_LOWEST, // 1 MinPriority aoqi@0: THREAD_PRIORITY_LOWEST, // 2 aoqi@0: THREAD_PRIORITY_BELOW_NORMAL, // 3 aoqi@0: THREAD_PRIORITY_BELOW_NORMAL, // 4 aoqi@0: THREAD_PRIORITY_NORMAL, // 5 NormPriority aoqi@0: THREAD_PRIORITY_ABOVE_NORMAL, // 6 aoqi@0: THREAD_PRIORITY_ABOVE_NORMAL, // 7 aoqi@0: THREAD_PRIORITY_HIGHEST, // 8 aoqi@0: THREAD_PRIORITY_HIGHEST, // 9 NearMaxPriority aoqi@0: THREAD_PRIORITY_TIME_CRITICAL, // 10 MaxPriority aoqi@0: THREAD_PRIORITY_TIME_CRITICAL // 11 CriticalPriority aoqi@0: }; aoqi@0: aoqi@0: static int prio_init() { aoqi@0: // If ThreadPriorityPolicy is 1, switch tables aoqi@0: if (ThreadPriorityPolicy == 1) { aoqi@0: int i; aoqi@0: for (i = 0; i < CriticalPriority + 1; i++) { aoqi@0: os::java_to_os_priority[i] = prio_policy1[i]; aoqi@0: } aoqi@0: } aoqi@0: if (UseCriticalJavaThreadPriority) { aoqi@0: os::java_to_os_priority[MaxPriority] = os::java_to_os_priority[CriticalPriority] ; aoqi@0: } aoqi@0: return 0; aoqi@0: } aoqi@0: aoqi@0: OSReturn os::set_native_priority(Thread* thread, int priority) { aoqi@0: if (!UseThreadPriorities) return OS_OK; aoqi@0: bool ret = SetThreadPriority(thread->osthread()->thread_handle(), priority) != 0; aoqi@0: return ret ? OS_OK : OS_ERR; aoqi@0: } aoqi@0: aoqi@0: OSReturn os::get_native_priority(const Thread* const thread, int* priority_ptr) { aoqi@0: if ( !UseThreadPriorities ) { aoqi@0: *priority_ptr = java_to_os_priority[NormPriority]; aoqi@0: return OS_OK; aoqi@0: } aoqi@0: int os_prio = GetThreadPriority(thread->osthread()->thread_handle()); aoqi@0: if (os_prio == THREAD_PRIORITY_ERROR_RETURN) { aoqi@0: assert(false, "GetThreadPriority failed"); aoqi@0: return OS_ERR; aoqi@0: } aoqi@0: *priority_ptr = os_prio; aoqi@0: return OS_OK; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // Hint to the underlying OS that a task switch would not be good. aoqi@0: // Void return because it's a hint and can fail. aoqi@0: void os::hint_no_preempt() {} aoqi@0: aoqi@0: void os::interrupt(Thread* thread) { aoqi@0: assert(!thread->is_Java_thread() || Thread::current() == thread || Threads_lock->owned_by_self(), aoqi@0: "possibility of dangling Thread pointer"); aoqi@0: aoqi@0: OSThread* osthread = thread->osthread(); aoqi@0: osthread->set_interrupted(true); aoqi@0: // More than one thread can get here with the same value of osthread, aoqi@0: // resulting in multiple notifications. We do, however, want the store aoqi@0: // to interrupted() to be visible to other threads before we post aoqi@0: // the interrupt event. aoqi@0: OrderAccess::release(); aoqi@0: SetEvent(osthread->interrupt_event()); aoqi@0: // For JSR166: unpark after setting status aoqi@0: if (thread->is_Java_thread()) aoqi@0: ((JavaThread*)thread)->parker()->unpark(); aoqi@0: aoqi@0: ParkEvent * ev = thread->_ParkEvent ; aoqi@0: if (ev != NULL) ev->unpark() ; aoqi@0: aoqi@0: } aoqi@0: aoqi@0: aoqi@0: bool os::is_interrupted(Thread* thread, bool clear_interrupted) { aoqi@0: assert(!thread->is_Java_thread() || Thread::current() == thread || Threads_lock->owned_by_self(), aoqi@0: "possibility of dangling Thread pointer"); aoqi@0: aoqi@0: OSThread* osthread = thread->osthread(); aoqi@0: // There is no synchronization between the setting of the interrupt aoqi@0: // and it being cleared here. It is critical - see 6535709 - that aoqi@0: // we only clear the interrupt state, and reset the interrupt event, aoqi@0: // if we are going to report that we were indeed interrupted - else aoqi@0: // an interrupt can be "lost", leading to spurious wakeups or lost wakeups aoqi@0: // depending on the timing. By checking thread interrupt event to see aoqi@0: // if the thread gets real interrupt thus prevent spurious wakeup. aoqi@0: bool interrupted = osthread->interrupted() && (WaitForSingleObject(osthread->interrupt_event(), 0) == WAIT_OBJECT_0); aoqi@0: if (interrupted && clear_interrupted) { aoqi@0: osthread->set_interrupted(false); aoqi@0: ResetEvent(osthread->interrupt_event()); aoqi@0: } // Otherwise leave the interrupted state alone aoqi@0: aoqi@0: return interrupted; aoqi@0: } aoqi@0: aoqi@0: // Get's a pc (hint) for a running thread. Currently used only for profiling. aoqi@0: ExtendedPC os::get_thread_pc(Thread* thread) { aoqi@0: CONTEXT context; aoqi@0: context.ContextFlags = CONTEXT_CONTROL; aoqi@0: HANDLE handle = thread->osthread()->thread_handle(); aoqi@0: #ifdef _M_IA64 aoqi@0: assert(0, "Fix get_thread_pc"); aoqi@0: return ExtendedPC(NULL); aoqi@0: #else aoqi@0: if (GetThreadContext(handle, &context)) { aoqi@0: #ifdef _M_AMD64 aoqi@0: return ExtendedPC((address) context.Rip); aoqi@0: #else aoqi@0: return ExtendedPC((address) context.Eip); aoqi@0: #endif aoqi@0: } else { aoqi@0: return ExtendedPC(NULL); aoqi@0: } aoqi@0: #endif aoqi@0: } aoqi@0: aoqi@0: // GetCurrentThreadId() returns DWORD aoqi@0: intx os::current_thread_id() { return GetCurrentThreadId(); } aoqi@0: aoqi@0: static int _initial_pid = 0; aoqi@0: aoqi@0: int os::current_process_id() aoqi@0: { aoqi@0: return (_initial_pid ? _initial_pid : _getpid()); aoqi@0: } aoqi@0: aoqi@0: int os::win32::_vm_page_size = 0; aoqi@0: int os::win32::_vm_allocation_granularity = 0; aoqi@0: int os::win32::_processor_type = 0; aoqi@0: // Processor level is not available on non-NT systems, use vm_version instead aoqi@0: int os::win32::_processor_level = 0; aoqi@0: julong os::win32::_physical_memory = 0; aoqi@0: size_t os::win32::_default_stack_size = 0; aoqi@0: aoqi@0: intx os::win32::_os_thread_limit = 0; aoqi@0: volatile intx os::win32::_os_thread_count = 0; aoqi@0: aoqi@0: bool os::win32::_is_nt = false; aoqi@0: bool os::win32::_is_windows_2003 = false; aoqi@0: bool os::win32::_is_windows_server = false; aoqi@0: aoqi@0: void os::win32::initialize_system_info() { aoqi@0: SYSTEM_INFO si; aoqi@0: GetSystemInfo(&si); aoqi@0: _vm_page_size = si.dwPageSize; aoqi@0: _vm_allocation_granularity = si.dwAllocationGranularity; aoqi@0: _processor_type = si.dwProcessorType; aoqi@0: _processor_level = si.wProcessorLevel; aoqi@0: set_processor_count(si.dwNumberOfProcessors); aoqi@0: aoqi@0: MEMORYSTATUSEX ms; aoqi@0: ms.dwLength = sizeof(ms); aoqi@0: aoqi@0: // also returns dwAvailPhys (free physical memory bytes), dwTotalVirtual, dwAvailVirtual, aoqi@0: // dwMemoryLoad (% of memory in use) aoqi@0: GlobalMemoryStatusEx(&ms); aoqi@0: _physical_memory = ms.ullTotalPhys; aoqi@0: aoqi@0: OSVERSIONINFOEX oi; aoqi@0: oi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); aoqi@0: GetVersionEx((OSVERSIONINFO*)&oi); aoqi@0: switch(oi.dwPlatformId) { aoqi@0: case VER_PLATFORM_WIN32_WINDOWS: _is_nt = false; break; aoqi@0: case VER_PLATFORM_WIN32_NT: aoqi@0: _is_nt = true; aoqi@0: { aoqi@0: int os_vers = oi.dwMajorVersion * 1000 + oi.dwMinorVersion; aoqi@0: if (os_vers == 5002) { aoqi@0: _is_windows_2003 = true; aoqi@0: } aoqi@0: if (oi.wProductType == VER_NT_DOMAIN_CONTROLLER || aoqi@0: oi.wProductType == VER_NT_SERVER) { aoqi@0: _is_windows_server = true; aoqi@0: } aoqi@0: } aoqi@0: break; aoqi@0: default: fatal("Unknown platform"); aoqi@0: } aoqi@0: aoqi@0: _default_stack_size = os::current_stack_size(); aoqi@0: assert(_default_stack_size > (size_t) _vm_page_size, "invalid stack size"); aoqi@0: assert((_default_stack_size & (_vm_page_size - 1)) == 0, aoqi@0: "stack size not a multiple of page size"); aoqi@0: aoqi@0: initialize_performance_counter(); aoqi@0: aoqi@0: // Win95/Win98 scheduler bug work-around. The Win95/98 scheduler is aoqi@0: // known to deadlock the system, if the VM issues to thread operations with aoqi@0: // a too high frequency, e.g., such as changing the priorities. aoqi@0: // The 6000 seems to work well - no deadlocks has been notices on the test aoqi@0: // programs that we have seen experience this problem. aoqi@0: if (!os::win32::is_nt()) { aoqi@0: StarvationMonitorInterval = 6000; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: HINSTANCE os::win32::load_Windows_dll(const char* name, char *ebuf, int ebuflen) { aoqi@0: char path[MAX_PATH]; aoqi@0: DWORD size; aoqi@0: DWORD pathLen = (DWORD)sizeof(path); aoqi@0: HINSTANCE result = NULL; aoqi@0: aoqi@0: // only allow library name without path component aoqi@0: assert(strchr(name, '\\') == NULL, "path not allowed"); aoqi@0: assert(strchr(name, ':') == NULL, "path not allowed"); aoqi@0: if (strchr(name, '\\') != NULL || strchr(name, ':') != NULL) { aoqi@0: jio_snprintf(ebuf, ebuflen, aoqi@0: "Invalid parameter while calling os::win32::load_windows_dll(): cannot take path: %s", name); aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: // search system directory aoqi@0: if ((size = GetSystemDirectory(path, pathLen)) > 0) { aoqi@0: strcat(path, "\\"); aoqi@0: strcat(path, name); aoqi@0: if ((result = (HINSTANCE)os::dll_load(path, ebuf, ebuflen)) != NULL) { aoqi@0: return result; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // try Windows directory aoqi@0: if ((size = GetWindowsDirectory(path, pathLen)) > 0) { aoqi@0: strcat(path, "\\"); aoqi@0: strcat(path, name); aoqi@0: if ((result = (HINSTANCE)os::dll_load(path, ebuf, ebuflen)) != NULL) { aoqi@0: return result; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: jio_snprintf(ebuf, ebuflen, aoqi@0: "os::win32::load_windows_dll() cannot load %s from system directories.", name); aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: void os::win32::setmode_streams() { aoqi@0: _setmode(_fileno(stdin), _O_BINARY); aoqi@0: _setmode(_fileno(stdout), _O_BINARY); aoqi@0: _setmode(_fileno(stderr), _O_BINARY); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: bool os::is_debugger_attached() { aoqi@0: return IsDebuggerPresent() ? true : false; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void os::wait_for_keypress_at_exit(void) { aoqi@0: if (PauseAtExit) { aoqi@0: fprintf(stderr, "Press any key to continue...\n"); aoqi@0: fgetc(stdin); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: int os::message_box(const char* title, const char* message) { aoqi@0: int result = MessageBox(NULL, message, title, aoqi@0: MB_YESNO | MB_ICONERROR | MB_SYSTEMMODAL | MB_DEFAULT_DESKTOP_ONLY); aoqi@0: return result == IDYES; aoqi@0: } aoqi@0: aoqi@0: int os::allocate_thread_local_storage() { aoqi@0: return TlsAlloc(); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void os::free_thread_local_storage(int index) { aoqi@0: TlsFree(index); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void os::thread_local_storage_at_put(int index, void* value) { aoqi@0: TlsSetValue(index, value); aoqi@0: assert(thread_local_storage_at(index) == value, "Just checking"); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void* os::thread_local_storage_at(int index) { aoqi@0: return TlsGetValue(index); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: #ifndef PRODUCT aoqi@0: #ifndef _WIN64 aoqi@0: // Helpers to check whether NX protection is enabled aoqi@0: int nx_exception_filter(_EXCEPTION_POINTERS *pex) { aoqi@0: if (pex->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && aoqi@0: pex->ExceptionRecord->NumberParameters > 0 && aoqi@0: pex->ExceptionRecord->ExceptionInformation[0] == aoqi@0: EXCEPTION_INFO_EXEC_VIOLATION) { aoqi@0: return EXCEPTION_EXECUTE_HANDLER; aoqi@0: } aoqi@0: return EXCEPTION_CONTINUE_SEARCH; aoqi@0: } aoqi@0: aoqi@0: void nx_check_protection() { aoqi@0: // If NX is enabled we'll get an exception calling into code on the stack aoqi@0: char code[] = { (char)0xC3 }; // ret aoqi@0: void *code_ptr = (void *)code; aoqi@0: __try { aoqi@0: __asm call code_ptr aoqi@0: } __except(nx_exception_filter((_EXCEPTION_POINTERS*)_exception_info())) { aoqi@0: tty->print_raw_cr("NX protection detected."); aoqi@0: } aoqi@0: } aoqi@0: #endif // _WIN64 aoqi@0: #endif // PRODUCT aoqi@0: aoqi@0: // this is called _before_ the global arguments have been parsed aoqi@0: void os::init(void) { aoqi@0: _initial_pid = _getpid(); aoqi@0: aoqi@0: init_random(1234567); aoqi@0: aoqi@0: win32::initialize_system_info(); aoqi@0: win32::setmode_streams(); aoqi@0: init_page_sizes((size_t) win32::vm_page_size()); aoqi@0: aoqi@0: // For better scalability on MP systems (must be called after initialize_system_info) aoqi@0: #ifndef PRODUCT aoqi@0: if (is_MP()) { aoqi@0: NoYieldsInMicrolock = true; aoqi@0: } aoqi@0: #endif aoqi@0: // This may be overridden later when argument processing is done. aoqi@0: FLAG_SET_ERGO(bool, UseLargePagesIndividualAllocation, aoqi@0: os::win32::is_windows_2003()); aoqi@0: aoqi@0: // Initialize main_process and main_thread aoqi@0: main_process = GetCurrentProcess(); // Remember main_process is a pseudo handle aoqi@0: if (!DuplicateHandle(main_process, GetCurrentThread(), main_process, aoqi@0: &main_thread, THREAD_ALL_ACCESS, false, 0)) { aoqi@0: fatal("DuplicateHandle failed\n"); aoqi@0: } aoqi@0: main_thread_id = (int) GetCurrentThreadId(); aoqi@0: } aoqi@0: aoqi@0: // To install functions for atexit processing aoqi@0: extern "C" { aoqi@0: static void perfMemory_exit_helper() { aoqi@0: perfMemory_exit(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: static jint initSock(); aoqi@0: aoqi@0: // this is called _after_ the global arguments have been parsed aoqi@0: jint os::init_2(void) { aoqi@0: // Allocate a single page and mark it as readable for safepoint polling aoqi@0: address polling_page = (address)VirtualAlloc(NULL, os::vm_page_size(), MEM_RESERVE, PAGE_READONLY); aoqi@0: guarantee( polling_page != NULL, "Reserve Failed for polling page"); aoqi@0: aoqi@0: address return_page = (address)VirtualAlloc(polling_page, os::vm_page_size(), MEM_COMMIT, PAGE_READONLY); aoqi@0: guarantee( return_page != NULL, "Commit Failed for polling page"); aoqi@0: aoqi@0: os::set_polling_page( polling_page ); aoqi@0: aoqi@0: #ifndef PRODUCT aoqi@0: if( Verbose && PrintMiscellaneous ) aoqi@0: tty->print("[SafePoint Polling address: " INTPTR_FORMAT "]\n", (intptr_t)polling_page); aoqi@0: #endif aoqi@0: aoqi@0: if (!UseMembar) { aoqi@0: address mem_serialize_page = (address)VirtualAlloc(NULL, os::vm_page_size(), MEM_RESERVE, PAGE_READWRITE); aoqi@0: guarantee( mem_serialize_page != NULL, "Reserve Failed for memory serialize page"); aoqi@0: aoqi@0: return_page = (address)VirtualAlloc(mem_serialize_page, os::vm_page_size(), MEM_COMMIT, PAGE_READWRITE); aoqi@0: guarantee( return_page != NULL, "Commit Failed for memory serialize page"); aoqi@0: aoqi@0: os::set_memory_serialize_page( mem_serialize_page ); aoqi@0: aoqi@0: #ifndef PRODUCT aoqi@0: if(Verbose && PrintMiscellaneous) aoqi@0: tty->print("[Memory Serialize Page address: " INTPTR_FORMAT "]\n", (intptr_t)mem_serialize_page); aoqi@0: #endif aoqi@0: } aoqi@0: aoqi@0: // Setup Windows Exceptions aoqi@0: aoqi@0: // for debugging float code generation bugs aoqi@0: if (ForceFloatExceptions) { aoqi@0: #ifndef _WIN64 aoqi@0: static long fp_control_word = 0; aoqi@0: __asm { fstcw fp_control_word } aoqi@0: // see Intel PPro Manual, Vol. 2, p 7-16 aoqi@0: const long precision = 0x20; aoqi@0: const long underflow = 0x10; aoqi@0: const long overflow = 0x08; aoqi@0: const long zero_div = 0x04; aoqi@0: const long denorm = 0x02; aoqi@0: const long invalid = 0x01; aoqi@0: fp_control_word |= invalid; aoqi@0: __asm { fldcw fp_control_word } aoqi@0: #endif aoqi@0: } aoqi@0: aoqi@0: // If stack_commit_size is 0, windows will reserve the default size, aoqi@0: // but only commit a small portion of it. aoqi@0: size_t stack_commit_size = round_to(ThreadStackSize*K, os::vm_page_size()); aoqi@0: size_t default_reserve_size = os::win32::default_stack_size(); aoqi@0: size_t actual_reserve_size = stack_commit_size; aoqi@0: if (stack_commit_size < default_reserve_size) { aoqi@0: // If stack_commit_size == 0, we want this too aoqi@0: actual_reserve_size = default_reserve_size; aoqi@0: } aoqi@0: aoqi@0: // Check minimum allowable stack size for thread creation and to initialize aoqi@0: // the java system classes, including StackOverflowError - depends on page aoqi@0: // size. Add a page for compiler2 recursion in main thread. aoqi@0: // Add in 2*BytesPerWord times page size to account for VM stack during aoqi@0: // class initialization depending on 32 or 64 bit VM. aoqi@0: size_t min_stack_allowed = aoqi@0: (size_t)(StackYellowPages+StackRedPages+StackShadowPages+ aoqi@0: 2*BytesPerWord COMPILER2_PRESENT(+1)) * os::vm_page_size(); aoqi@0: if (actual_reserve_size < min_stack_allowed) { aoqi@0: tty->print_cr("\nThe stack size specified is too small, " aoqi@0: "Specify at least %dk", aoqi@0: min_stack_allowed / K); aoqi@0: return JNI_ERR; aoqi@0: } aoqi@0: aoqi@0: JavaThread::set_stack_size_at_create(stack_commit_size); aoqi@0: aoqi@0: // Calculate theoretical max. size of Threads to guard gainst artifical aoqi@0: // out-of-memory situations, where all available address-space has been aoqi@0: // reserved by thread stacks. aoqi@0: assert(actual_reserve_size != 0, "Must have a stack"); aoqi@0: aoqi@0: // Calculate the thread limit when we should start doing Virtual Memory aoqi@0: // banging. Currently when the threads will have used all but 200Mb of space. aoqi@0: // aoqi@0: // TODO: consider performing a similar calculation for commit size instead aoqi@0: // as reserve size, since on a 64-bit platform we'll run into that more aoqi@0: // often than running out of virtual memory space. We can use the aoqi@0: // lower value of the two calculations as the os_thread_limit. aoqi@0: size_t max_address_space = ((size_t)1 << (BitsPerWord - 1)) - (200 * K * K); aoqi@0: win32::_os_thread_limit = (intx)(max_address_space / actual_reserve_size); aoqi@0: aoqi@0: // at exit methods are called in the reverse order of their registration. aoqi@0: // there is no limit to the number of functions registered. atexit does aoqi@0: // not set errno. aoqi@0: aoqi@0: if (PerfAllowAtExitRegistration) { aoqi@0: // only register atexit functions if PerfAllowAtExitRegistration is set. aoqi@0: // atexit functions can be delayed until process exit time, which aoqi@0: // can be problematic for embedded VM situations. Embedded VMs should aoqi@0: // call DestroyJavaVM() to assure that VM resources are released. aoqi@0: aoqi@0: // note: perfMemory_exit_helper atexit function may be removed in aoqi@0: // the future if the appropriate cleanup code can be added to the aoqi@0: // VM_Exit VMOperation's doit method. aoqi@0: if (atexit(perfMemory_exit_helper) != 0) { aoqi@0: warning("os::init_2 atexit(perfMemory_exit_helper) failed"); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: #ifndef _WIN64 aoqi@0: // Print something if NX is enabled (win32 on AMD64) aoqi@0: NOT_PRODUCT(if (PrintMiscellaneous && Verbose) nx_check_protection()); aoqi@0: #endif aoqi@0: aoqi@0: // initialize thread priority policy aoqi@0: prio_init(); aoqi@0: aoqi@0: if (UseNUMA && !ForceNUMA) { aoqi@0: UseNUMA = false; // We don't fully support this yet aoqi@0: } aoqi@0: aoqi@0: if (UseNUMAInterleaving) { aoqi@0: // first check whether this Windows OS supports VirtualAllocExNuma, if not ignore this flag aoqi@0: bool success = numa_interleaving_init(); aoqi@0: if (!success) UseNUMAInterleaving = false; aoqi@0: } aoqi@0: aoqi@0: if (initSock() != JNI_OK) { aoqi@0: return JNI_ERR; aoqi@0: } aoqi@0: aoqi@0: return JNI_OK; aoqi@0: } aoqi@0: aoqi@0: void os::init_3(void) { aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: // Mark the polling page as unreadable aoqi@0: void os::make_polling_page_unreadable(void) { aoqi@0: DWORD old_status; aoqi@0: if( !VirtualProtect((char *)_polling_page, os::vm_page_size(), PAGE_NOACCESS, &old_status) ) aoqi@0: fatal("Could not disable polling page"); aoqi@0: }; aoqi@0: aoqi@0: // Mark the polling page as readable aoqi@0: void os::make_polling_page_readable(void) { aoqi@0: DWORD old_status; aoqi@0: if( !VirtualProtect((char *)_polling_page, os::vm_page_size(), PAGE_READONLY, &old_status) ) aoqi@0: fatal("Could not enable polling page"); aoqi@0: }; aoqi@0: aoqi@0: aoqi@0: int os::stat(const char *path, struct stat *sbuf) { aoqi@0: char pathbuf[MAX_PATH]; aoqi@0: if (strlen(path) > MAX_PATH - 1) { aoqi@0: errno = ENAMETOOLONG; aoqi@0: return -1; aoqi@0: } aoqi@0: os::native_path(strcpy(pathbuf, path)); aoqi@0: int ret = ::stat(pathbuf, sbuf); aoqi@0: if (sbuf != NULL && UseUTCFileTimestamp) { aoqi@0: // Fix for 6539723. st_mtime returned from stat() is dependent on aoqi@0: // the system timezone and so can return different values for the aoqi@0: // same file if/when daylight savings time changes. This adjustment aoqi@0: // makes sure the same timestamp is returned regardless of the TZ. aoqi@0: // aoqi@0: // See: aoqi@0: // http://msdn.microsoft.com/library/ aoqi@0: // default.asp?url=/library/en-us/sysinfo/base/ aoqi@0: // time_zone_information_str.asp aoqi@0: // and aoqi@0: // http://msdn.microsoft.com/library/default.asp?url= aoqi@0: // /library/en-us/sysinfo/base/settimezoneinformation.asp aoqi@0: // aoqi@0: // NOTE: there is a insidious bug here: If the timezone is changed aoqi@0: // after the call to stat() but before 'GetTimeZoneInformation()', then aoqi@0: // the adjustment we do here will be wrong and we'll return the wrong aoqi@0: // value (which will likely end up creating an invalid class data aoqi@0: // archive). Absent a better API for this, or some time zone locking aoqi@0: // mechanism, we'll have to live with this risk. aoqi@0: TIME_ZONE_INFORMATION tz; aoqi@0: DWORD tzid = GetTimeZoneInformation(&tz); aoqi@0: int daylightBias = aoqi@0: (tzid == TIME_ZONE_ID_DAYLIGHT) ? tz.DaylightBias : tz.StandardBias; aoqi@0: sbuf->st_mtime += (tz.Bias + daylightBias) * 60; aoqi@0: } aoqi@0: return ret; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: #define FT2INT64(ft) \ aoqi@0: ((jlong)((jlong)(ft).dwHighDateTime << 32 | (julong)(ft).dwLowDateTime)) aoqi@0: aoqi@0: aoqi@0: // current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool) aoqi@0: // are used by JVM M&M and JVMTI to get user+sys or user CPU time aoqi@0: // of a thread. aoqi@0: // aoqi@0: // current_thread_cpu_time() and thread_cpu_time(Thread*) returns aoqi@0: // the fast estimate available on the platform. aoqi@0: aoqi@0: // current_thread_cpu_time() is not optimized for Windows yet aoqi@0: jlong os::current_thread_cpu_time() { aoqi@0: // return user + sys since the cost is the same aoqi@0: return os::thread_cpu_time(Thread::current(), true /* user+sys */); aoqi@0: } aoqi@0: aoqi@0: jlong os::thread_cpu_time(Thread* thread) { aoqi@0: // consistent with what current_thread_cpu_time() returns. aoqi@0: return os::thread_cpu_time(thread, true /* user+sys */); aoqi@0: } aoqi@0: aoqi@0: jlong os::current_thread_cpu_time(bool user_sys_cpu_time) { aoqi@0: return os::thread_cpu_time(Thread::current(), user_sys_cpu_time); aoqi@0: } aoqi@0: aoqi@0: jlong os::thread_cpu_time(Thread* thread, bool user_sys_cpu_time) { aoqi@0: // This code is copy from clasic VM -> hpi::sysThreadCPUTime aoqi@0: // If this function changes, os::is_thread_cpu_time_supported() should too aoqi@0: if (os::win32::is_nt()) { aoqi@0: FILETIME CreationTime; aoqi@0: FILETIME ExitTime; aoqi@0: FILETIME KernelTime; aoqi@0: FILETIME UserTime; aoqi@0: aoqi@0: if ( GetThreadTimes(thread->osthread()->thread_handle(), aoqi@0: &CreationTime, &ExitTime, &KernelTime, &UserTime) == 0) aoqi@0: return -1; aoqi@0: else aoqi@0: if (user_sys_cpu_time) { aoqi@0: return (FT2INT64(UserTime) + FT2INT64(KernelTime)) * 100; aoqi@0: } else { aoqi@0: return FT2INT64(UserTime) * 100; aoqi@0: } aoqi@0: } else { aoqi@0: return (jlong) timeGetTime() * 1000000; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { aoqi@0: info_ptr->max_value = ALL_64_BITS; // the max value -- all 64 bits aoqi@0: info_ptr->may_skip_backward = false; // GetThreadTimes returns absolute time aoqi@0: info_ptr->may_skip_forward = false; // GetThreadTimes returns absolute time aoqi@0: info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned aoqi@0: } aoqi@0: aoqi@0: void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { aoqi@0: info_ptr->max_value = ALL_64_BITS; // the max value -- all 64 bits aoqi@0: info_ptr->may_skip_backward = false; // GetThreadTimes returns absolute time aoqi@0: info_ptr->may_skip_forward = false; // GetThreadTimes returns absolute time aoqi@0: info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned aoqi@0: } aoqi@0: aoqi@0: bool os::is_thread_cpu_time_supported() { aoqi@0: // see os::thread_cpu_time aoqi@0: if (os::win32::is_nt()) { aoqi@0: FILETIME CreationTime; aoqi@0: FILETIME ExitTime; aoqi@0: FILETIME KernelTime; aoqi@0: FILETIME UserTime; aoqi@0: aoqi@0: if ( GetThreadTimes(GetCurrentThread(), aoqi@0: &CreationTime, &ExitTime, &KernelTime, &UserTime) == 0) aoqi@0: return false; aoqi@0: else aoqi@0: return true; aoqi@0: } else { aoqi@0: return false; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Windows does't provide a loadavg primitive so this is stubbed out for now. aoqi@0: // It does have primitives (PDH API) to get CPU usage and run queue length. aoqi@0: // "\\Processor(_Total)\\% Processor Time", "\\System\\Processor Queue Length" aoqi@0: // If we wanted to implement loadavg on Windows, we have a few options: aoqi@0: // aoqi@0: // a) Query CPU usage and run queue length and "fake" an answer by aoqi@0: // returning the CPU usage if it's under 100%, and the run queue aoqi@0: // length otherwise. It turns out that querying is pretty slow aoqi@0: // on Windows, on the order of 200 microseconds on a fast machine. aoqi@0: // Note that on the Windows the CPU usage value is the % usage aoqi@0: // since the last time the API was called (and the first call aoqi@0: // returns 100%), so we'd have to deal with that as well. aoqi@0: // aoqi@0: // b) Sample the "fake" answer using a sampling thread and store aoqi@0: // the answer in a global variable. The call to loadavg would aoqi@0: // just return the value of the global, avoiding the slow query. aoqi@0: // aoqi@0: // c) Sample a better answer using exponential decay to smooth the aoqi@0: // value. This is basically the algorithm used by UNIX kernels. aoqi@0: // aoqi@0: // Note that sampling thread starvation could affect both (b) and (c). aoqi@0: int os::loadavg(double loadavg[], int nelem) { aoqi@0: return -1; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // DontYieldALot=false by default: dutifully perform all yields as requested by JVM_Yield() aoqi@0: bool os::dont_yield() { aoqi@0: return DontYieldALot; aoqi@0: } aoqi@0: aoqi@0: // This method is a slightly reworked copy of JDK's sysOpen aoqi@0: // from src/windows/hpi/src/sys_api_md.c aoqi@0: aoqi@0: int os::open(const char *path, int oflag, int mode) { aoqi@0: char pathbuf[MAX_PATH]; aoqi@0: aoqi@0: if (strlen(path) > MAX_PATH - 1) { aoqi@0: errno = ENAMETOOLONG; aoqi@0: return -1; aoqi@0: } aoqi@0: os::native_path(strcpy(pathbuf, path)); aoqi@0: return ::open(pathbuf, oflag | O_BINARY | O_NOINHERIT, mode); aoqi@0: } aoqi@0: aoqi@0: FILE* os::open(int fd, const char* mode) { aoqi@0: return ::_fdopen(fd, mode); aoqi@0: } aoqi@0: aoqi@0: // Is a (classpath) directory empty? aoqi@0: bool os::dir_is_empty(const char* path) { aoqi@0: WIN32_FIND_DATA fd; aoqi@0: HANDLE f = FindFirstFile(path, &fd); aoqi@0: if (f == INVALID_HANDLE_VALUE) { aoqi@0: return true; aoqi@0: } aoqi@0: FindClose(f); aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: // create binary file, rewriting existing file if required aoqi@0: int os::create_binary_file(const char* path, bool rewrite_existing) { aoqi@0: int oflags = _O_CREAT | _O_WRONLY | _O_BINARY; aoqi@0: if (!rewrite_existing) { aoqi@0: oflags |= _O_EXCL; aoqi@0: } aoqi@0: return ::open(path, oflags, _S_IREAD | _S_IWRITE); aoqi@0: } aoqi@0: aoqi@0: // return current position of file pointer aoqi@0: jlong os::current_file_offset(int fd) { aoqi@0: return (jlong)::_lseeki64(fd, (__int64)0L, SEEK_CUR); aoqi@0: } aoqi@0: aoqi@0: // move file pointer to the specified offset aoqi@0: jlong os::seek_to_file_offset(int fd, jlong offset) { aoqi@0: return (jlong)::_lseeki64(fd, (__int64)offset, SEEK_SET); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: jlong os::lseek(int fd, jlong offset, int whence) { aoqi@0: return (jlong) ::_lseeki64(fd, offset, whence); aoqi@0: } aoqi@0: aoqi@0: // This method is a slightly reworked copy of JDK's sysNativePath aoqi@0: // from src/windows/hpi/src/path_md.c aoqi@0: aoqi@0: /* Convert a pathname to native format. On win32, this involves forcing all aoqi@0: separators to be '\\' rather than '/' (both are legal inputs, but Win95 aoqi@0: sometimes rejects '/') and removing redundant separators. The input path is aoqi@0: assumed to have been converted into the character encoding used by the local aoqi@0: system. Because this might be a double-byte encoding, care is taken to aoqi@0: treat double-byte lead characters correctly. aoqi@0: aoqi@0: This procedure modifies the given path in place, as the result is never aoqi@0: longer than the original. There is no error return; this operation always aoqi@0: succeeds. */ aoqi@0: char * os::native_path(char *path) { aoqi@0: char *src = path, *dst = path, *end = path; aoqi@0: char *colon = NULL; /* If a drive specifier is found, this will aoqi@0: point to the colon following the drive aoqi@0: letter */ aoqi@0: aoqi@0: /* Assumption: '/', '\\', ':', and drive letters are never lead bytes */ aoqi@0: assert(((!::IsDBCSLeadByte('/')) aoqi@0: && (!::IsDBCSLeadByte('\\')) aoqi@0: && (!::IsDBCSLeadByte(':'))), aoqi@0: "Illegal lead byte"); aoqi@0: aoqi@0: /* Check for leading separators */ aoqi@0: #define isfilesep(c) ((c) == '/' || (c) == '\\') aoqi@0: while (isfilesep(*src)) { aoqi@0: src++; aoqi@0: } aoqi@0: aoqi@0: if (::isalpha(*src) && !::IsDBCSLeadByte(*src) && src[1] == ':') { aoqi@0: /* Remove leading separators if followed by drive specifier. This aoqi@0: hack is necessary to support file URLs containing drive aoqi@0: specifiers (e.g., "file://c:/path"). As a side effect, aoqi@0: "/c:/path" can be used as an alternative to "c:/path". */ aoqi@0: *dst++ = *src++; aoqi@0: colon = dst; aoqi@0: *dst++ = ':'; aoqi@0: src++; aoqi@0: } else { aoqi@0: src = path; aoqi@0: if (isfilesep(src[0]) && isfilesep(src[1])) { aoqi@0: /* UNC pathname: Retain first separator; leave src pointed at aoqi@0: second separator so that further separators will be collapsed aoqi@0: into the second separator. The result will be a pathname aoqi@0: beginning with "\\\\" followed (most likely) by a host name. */ aoqi@0: src = dst = path + 1; aoqi@0: path[0] = '\\'; /* Force first separator to '\\' */ aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: end = dst; aoqi@0: aoqi@0: /* Remove redundant separators from remainder of path, forcing all aoqi@0: separators to be '\\' rather than '/'. Also, single byte space aoqi@0: characters are removed from the end of the path because those aoqi@0: are not legal ending characters on this operating system. aoqi@0: */ aoqi@0: while (*src != '\0') { aoqi@0: if (isfilesep(*src)) { aoqi@0: *dst++ = '\\'; src++; aoqi@0: while (isfilesep(*src)) src++; aoqi@0: if (*src == '\0') { aoqi@0: /* Check for trailing separator */ aoqi@0: end = dst; aoqi@0: if (colon == dst - 2) break; /* "z:\\" */ aoqi@0: if (dst == path + 1) break; /* "\\" */ aoqi@0: if (dst == path + 2 && isfilesep(path[0])) { aoqi@0: /* "\\\\" is not collapsed to "\\" because "\\\\" marks the aoqi@0: beginning of a UNC pathname. Even though it is not, by aoqi@0: itself, a valid UNC pathname, we leave it as is in order aoqi@0: to be consistent with the path canonicalizer as well aoqi@0: as the win32 APIs, which treat this case as an invalid aoqi@0: UNC pathname rather than as an alias for the root aoqi@0: directory of the current drive. */ aoqi@0: break; aoqi@0: } aoqi@0: end = --dst; /* Path does not denote a root directory, so aoqi@0: remove trailing separator */ aoqi@0: break; aoqi@0: } aoqi@0: end = dst; aoqi@0: } else { aoqi@0: if (::IsDBCSLeadByte(*src)) { /* Copy a double-byte character */ aoqi@0: *dst++ = *src++; aoqi@0: if (*src) *dst++ = *src++; aoqi@0: end = dst; aoqi@0: } else { /* Copy a single-byte character */ aoqi@0: char c = *src++; aoqi@0: *dst++ = c; aoqi@0: /* Space is not a legal ending character */ aoqi@0: if (c != ' ') end = dst; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: *end = '\0'; aoqi@0: aoqi@0: /* For "z:", add "." to work around a bug in the C runtime library */ aoqi@0: if (colon == dst - 1) { aoqi@0: path[2] = '.'; aoqi@0: path[3] = '\0'; aoqi@0: } aoqi@0: aoqi@0: return path; aoqi@0: } aoqi@0: aoqi@0: // This code is a copy of JDK's sysSetLength aoqi@0: // from src/windows/hpi/src/sys_api_md.c aoqi@0: aoqi@0: int os::ftruncate(int fd, jlong length) { aoqi@0: HANDLE h = (HANDLE)::_get_osfhandle(fd); aoqi@0: long high = (long)(length >> 32); aoqi@0: DWORD ret; aoqi@0: aoqi@0: if (h == (HANDLE)(-1)) { aoqi@0: return -1; aoqi@0: } aoqi@0: aoqi@0: ret = ::SetFilePointer(h, (long)(length), &high, FILE_BEGIN); aoqi@0: if ((ret == 0xFFFFFFFF) && (::GetLastError() != NO_ERROR)) { aoqi@0: return -1; aoqi@0: } aoqi@0: aoqi@0: if (::SetEndOfFile(h) == FALSE) { aoqi@0: return -1; aoqi@0: } aoqi@0: aoqi@0: return 0; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // This code is a copy of JDK's sysSync aoqi@0: // from src/windows/hpi/src/sys_api_md.c aoqi@0: // except for the legacy workaround for a bug in Win 98 aoqi@0: aoqi@0: int os::fsync(int fd) { aoqi@0: HANDLE handle = (HANDLE)::_get_osfhandle(fd); aoqi@0: aoqi@0: if ( (!::FlushFileBuffers(handle)) && aoqi@0: (GetLastError() != ERROR_ACCESS_DENIED) ) { aoqi@0: /* from winerror.h */ aoqi@0: return -1; aoqi@0: } aoqi@0: return 0; aoqi@0: } aoqi@0: aoqi@0: static int nonSeekAvailable(int, long *); aoqi@0: static int stdinAvailable(int, long *); aoqi@0: aoqi@0: #define S_ISCHR(mode) (((mode) & _S_IFCHR) == _S_IFCHR) aoqi@0: #define S_ISFIFO(mode) (((mode) & _S_IFIFO) == _S_IFIFO) aoqi@0: aoqi@0: // This code is a copy of JDK's sysAvailable aoqi@0: // from src/windows/hpi/src/sys_api_md.c aoqi@0: aoqi@0: int os::available(int fd, jlong *bytes) { aoqi@0: jlong cur, end; aoqi@0: struct _stati64 stbuf64; aoqi@0: aoqi@0: if (::_fstati64(fd, &stbuf64) >= 0) { aoqi@0: int mode = stbuf64.st_mode; aoqi@0: if (S_ISCHR(mode) || S_ISFIFO(mode)) { aoqi@0: int ret; aoqi@0: long lpbytes; aoqi@0: if (fd == 0) { aoqi@0: ret = stdinAvailable(fd, &lpbytes); aoqi@0: } else { aoqi@0: ret = nonSeekAvailable(fd, &lpbytes); aoqi@0: } aoqi@0: (*bytes) = (jlong)(lpbytes); aoqi@0: return ret; aoqi@0: } aoqi@0: if ((cur = ::_lseeki64(fd, 0L, SEEK_CUR)) == -1) { aoqi@0: return FALSE; aoqi@0: } else if ((end = ::_lseeki64(fd, 0L, SEEK_END)) == -1) { aoqi@0: return FALSE; aoqi@0: } else if (::_lseeki64(fd, cur, SEEK_SET) == -1) { aoqi@0: return FALSE; aoqi@0: } aoqi@0: *bytes = end - cur; aoqi@0: return TRUE; aoqi@0: } else { aoqi@0: return FALSE; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // This code is a copy of JDK's nonSeekAvailable aoqi@0: // from src/windows/hpi/src/sys_api_md.c aoqi@0: aoqi@0: static int nonSeekAvailable(int fd, long *pbytes) { aoqi@0: /* This is used for available on non-seekable devices aoqi@0: * (like both named and anonymous pipes, such as pipes aoqi@0: * connected to an exec'd process). aoqi@0: * Standard Input is a special case. aoqi@0: * aoqi@0: */ aoqi@0: HANDLE han; aoqi@0: aoqi@0: if ((han = (HANDLE) ::_get_osfhandle(fd)) == (HANDLE)(-1)) { aoqi@0: return FALSE; aoqi@0: } aoqi@0: aoqi@0: if (! ::PeekNamedPipe(han, NULL, 0, NULL, (LPDWORD)pbytes, NULL)) { aoqi@0: /* PeekNamedPipe fails when at EOF. In that case we aoqi@0: * simply make *pbytes = 0 which is consistent with the aoqi@0: * behavior we get on Solaris when an fd is at EOF. aoqi@0: * The only alternative is to raise an Exception, aoqi@0: * which isn't really warranted. aoqi@0: */ aoqi@0: if (::GetLastError() != ERROR_BROKEN_PIPE) { aoqi@0: return FALSE; aoqi@0: } aoqi@0: *pbytes = 0; aoqi@0: } aoqi@0: return TRUE; aoqi@0: } aoqi@0: aoqi@0: #define MAX_INPUT_EVENTS 2000 aoqi@0: aoqi@0: // This code is a copy of JDK's stdinAvailable aoqi@0: // from src/windows/hpi/src/sys_api_md.c aoqi@0: aoqi@0: static int stdinAvailable(int fd, long *pbytes) { aoqi@0: HANDLE han; aoqi@0: DWORD numEventsRead = 0; /* Number of events read from buffer */ aoqi@0: DWORD numEvents = 0; /* Number of events in buffer */ aoqi@0: DWORD i = 0; /* Loop index */ aoqi@0: DWORD curLength = 0; /* Position marker */ aoqi@0: DWORD actualLength = 0; /* Number of bytes readable */ aoqi@0: BOOL error = FALSE; /* Error holder */ aoqi@0: INPUT_RECORD *lpBuffer; /* Pointer to records of input events */ aoqi@0: aoqi@0: if ((han = ::GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) { aoqi@0: return FALSE; aoqi@0: } aoqi@0: aoqi@0: /* Construct an array of input records in the console buffer */ aoqi@0: error = ::GetNumberOfConsoleInputEvents(han, &numEvents); aoqi@0: if (error == 0) { aoqi@0: return nonSeekAvailable(fd, pbytes); aoqi@0: } aoqi@0: aoqi@0: /* lpBuffer must fit into 64K or else PeekConsoleInput fails */ aoqi@0: if (numEvents > MAX_INPUT_EVENTS) { aoqi@0: numEvents = MAX_INPUT_EVENTS; aoqi@0: } aoqi@0: aoqi@0: lpBuffer = (INPUT_RECORD *)os::malloc(numEvents * sizeof(INPUT_RECORD), mtInternal); aoqi@0: if (lpBuffer == NULL) { aoqi@0: return FALSE; aoqi@0: } aoqi@0: aoqi@0: error = ::PeekConsoleInput(han, lpBuffer, numEvents, &numEventsRead); aoqi@0: if (error == 0) { aoqi@0: os::free(lpBuffer, mtInternal); aoqi@0: return FALSE; aoqi@0: } aoqi@0: aoqi@0: /* Examine input records for the number of bytes available */ aoqi@0: for(i=0; ibKeyDown == TRUE) { aoqi@0: CHAR *keyPressed = (CHAR *) &(keyRecord->uChar); aoqi@0: curLength++; aoqi@0: if (*keyPressed == '\r') { aoqi@0: actualLength = curLength; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if(lpBuffer != NULL) { aoqi@0: os::free(lpBuffer, mtInternal); aoqi@0: } aoqi@0: aoqi@0: *pbytes = (long) actualLength; aoqi@0: return TRUE; aoqi@0: } aoqi@0: aoqi@0: // Map a block of memory. aoqi@0: char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset, aoqi@0: char *addr, size_t bytes, bool read_only, aoqi@0: bool allow_exec) { aoqi@0: HANDLE hFile; aoqi@0: char* base; aoqi@0: aoqi@0: hFile = CreateFile(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, aoqi@0: OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); aoqi@0: if (hFile == NULL) { aoqi@0: if (PrintMiscellaneous && Verbose) { aoqi@0: DWORD err = GetLastError(); aoqi@0: tty->print_cr("CreateFile() failed: GetLastError->%ld.", err); aoqi@0: } aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: if (allow_exec) { aoqi@0: // CreateFileMapping/MapViewOfFileEx can't map executable memory aoqi@0: // unless it comes from a PE image (which the shared archive is not.) aoqi@0: // Even VirtualProtect refuses to give execute access to mapped memory aoqi@0: // that was not previously executable. aoqi@0: // aoqi@0: // Instead, stick the executable region in anonymous memory. Yuck. aoqi@0: // Penalty is that ~4 pages will not be shareable - in the future aoqi@0: // we might consider DLLizing the shared archive with a proper PE aoqi@0: // header so that mapping executable + sharing is possible. aoqi@0: aoqi@0: base = (char*) VirtualAlloc(addr, bytes, MEM_COMMIT | MEM_RESERVE, aoqi@0: PAGE_READWRITE); aoqi@0: if (base == NULL) { aoqi@0: if (PrintMiscellaneous && Verbose) { aoqi@0: DWORD err = GetLastError(); aoqi@0: tty->print_cr("VirtualAlloc() failed: GetLastError->%ld.", err); aoqi@0: } aoqi@0: CloseHandle(hFile); aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: DWORD bytes_read; aoqi@0: OVERLAPPED overlapped; aoqi@0: overlapped.Offset = (DWORD)file_offset; aoqi@0: overlapped.OffsetHigh = 0; aoqi@0: overlapped.hEvent = NULL; aoqi@0: // ReadFile guarantees that if the return value is true, the requested aoqi@0: // number of bytes were read before returning. aoqi@0: bool res = ReadFile(hFile, base, (DWORD)bytes, &bytes_read, &overlapped) != 0; aoqi@0: if (!res) { aoqi@0: if (PrintMiscellaneous && Verbose) { aoqi@0: DWORD err = GetLastError(); aoqi@0: tty->print_cr("ReadFile() failed: GetLastError->%ld.", err); aoqi@0: } aoqi@0: release_memory(base, bytes); aoqi@0: CloseHandle(hFile); aoqi@0: return NULL; aoqi@0: } aoqi@0: } else { aoqi@0: HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_WRITECOPY, 0, 0, aoqi@0: NULL /*file_name*/); aoqi@0: if (hMap == NULL) { aoqi@0: if (PrintMiscellaneous && Verbose) { aoqi@0: DWORD err = GetLastError(); aoqi@0: tty->print_cr("CreateFileMapping() failed: GetLastError->%ld.", err); aoqi@0: } aoqi@0: CloseHandle(hFile); aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: DWORD access = read_only ? FILE_MAP_READ : FILE_MAP_COPY; aoqi@0: base = (char*)MapViewOfFileEx(hMap, access, 0, (DWORD)file_offset, aoqi@0: (DWORD)bytes, addr); aoqi@0: if (base == NULL) { aoqi@0: if (PrintMiscellaneous && Verbose) { aoqi@0: DWORD err = GetLastError(); aoqi@0: tty->print_cr("MapViewOfFileEx() failed: GetLastError->%ld.", err); aoqi@0: } aoqi@0: CloseHandle(hMap); aoqi@0: CloseHandle(hFile); aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: if (CloseHandle(hMap) == 0) { aoqi@0: if (PrintMiscellaneous && Verbose) { aoqi@0: DWORD err = GetLastError(); aoqi@0: tty->print_cr("CloseHandle(hMap) failed: GetLastError->%ld.", err); aoqi@0: } aoqi@0: CloseHandle(hFile); aoqi@0: return base; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if (allow_exec) { aoqi@0: DWORD old_protect; aoqi@0: DWORD exec_access = read_only ? PAGE_EXECUTE_READ : PAGE_EXECUTE_READWRITE; aoqi@0: bool res = VirtualProtect(base, bytes, exec_access, &old_protect) != 0; aoqi@0: aoqi@0: if (!res) { aoqi@0: if (PrintMiscellaneous && Verbose) { aoqi@0: DWORD err = GetLastError(); aoqi@0: tty->print_cr("VirtualProtect() failed: GetLastError->%ld.", err); aoqi@0: } aoqi@0: // Don't consider this a hard error, on IA32 even if the aoqi@0: // VirtualProtect fails, we should still be able to execute aoqi@0: CloseHandle(hFile); aoqi@0: return base; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if (CloseHandle(hFile) == 0) { aoqi@0: if (PrintMiscellaneous && Verbose) { aoqi@0: DWORD err = GetLastError(); aoqi@0: tty->print_cr("CloseHandle(hFile) failed: GetLastError->%ld.", err); aoqi@0: } aoqi@0: return base; aoqi@0: } aoqi@0: aoqi@0: return base; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // Remap a block of memory. aoqi@0: char* os::pd_remap_memory(int fd, const char* file_name, size_t file_offset, aoqi@0: char *addr, size_t bytes, bool read_only, aoqi@0: bool allow_exec) { aoqi@0: // This OS does not allow existing memory maps to be remapped so we aoqi@0: // have to unmap the memory before we remap it. aoqi@0: if (!os::unmap_memory(addr, bytes)) { aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: // There is a very small theoretical window between the unmap_memory() aoqi@0: // call above and the map_memory() call below where a thread in native aoqi@0: // code may be able to access an address that is no longer mapped. aoqi@0: aoqi@0: return os::map_memory(fd, file_name, file_offset, addr, bytes, aoqi@0: read_only, allow_exec); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // Unmap a block of memory. aoqi@0: // Returns true=success, otherwise false. aoqi@0: aoqi@0: bool os::pd_unmap_memory(char* addr, size_t bytes) { aoqi@0: BOOL result = UnmapViewOfFile(addr); aoqi@0: if (result == 0) { aoqi@0: if (PrintMiscellaneous && Verbose) { aoqi@0: DWORD err = GetLastError(); aoqi@0: tty->print_cr("UnmapViewOfFile() failed: GetLastError->%ld.", err); aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: void os::pause() { aoqi@0: char filename[MAX_PATH]; aoqi@0: if (PauseAtStartupFile && PauseAtStartupFile[0]) { aoqi@0: jio_snprintf(filename, MAX_PATH, PauseAtStartupFile); aoqi@0: } else { aoqi@0: jio_snprintf(filename, MAX_PATH, "./vm.paused.%d", current_process_id()); aoqi@0: } aoqi@0: aoqi@0: int fd = ::open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); aoqi@0: if (fd != -1) { aoqi@0: struct stat buf; aoqi@0: ::close(fd); aoqi@0: while (::stat(filename, &buf) == 0) { aoqi@0: Sleep(100); aoqi@0: } aoqi@0: } else { aoqi@0: jio_fprintf(stderr, aoqi@0: "Could not open pause file '%s', continuing immediately.\n", filename); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() { aoqi@0: assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread"); aoqi@0: } aoqi@0: aoqi@0: /* aoqi@0: * See the caveats for this class in os_windows.hpp aoqi@0: * Protects the callback call so that raised OS EXCEPTIONS causes a jump back aoqi@0: * into this method and returns false. If no OS EXCEPTION was raised, returns aoqi@0: * true. aoqi@0: * The callback is supposed to provide the method that should be protected. aoqi@0: */ aoqi@0: bool os::WatcherThreadCrashProtection::call(os::CrashProtectionCallback& cb) { aoqi@0: assert(Thread::current()->is_Watcher_thread(), "Only for WatcherThread"); aoqi@0: assert(!WatcherThread::watcher_thread()->has_crash_protection(), aoqi@0: "crash_protection already set?"); aoqi@0: aoqi@0: bool success = true; aoqi@0: __try { aoqi@0: WatcherThread::watcher_thread()->set_crash_protection(this); aoqi@0: cb.call(); aoqi@0: } __except(EXCEPTION_EXECUTE_HANDLER) { aoqi@0: // only for protection, nothing to do aoqi@0: success = false; aoqi@0: } aoqi@0: WatcherThread::watcher_thread()->set_crash_protection(NULL); aoqi@0: return success; aoqi@0: } aoqi@0: aoqi@0: // An Event wraps a win32 "CreateEvent" kernel handle. aoqi@0: // aoqi@0: // We have a number of choices regarding "CreateEvent" win32 handle leakage: aoqi@0: // aoqi@0: // 1: When a thread dies return the Event to the EventFreeList, clear the ParkHandle aoqi@0: // field, and call CloseHandle() on the win32 event handle. Unpark() would aoqi@0: // need to be modified to tolerate finding a NULL (invalid) win32 event handle. aoqi@0: // In addition, an unpark() operation might fetch the handle field, but the aoqi@0: // event could recycle between the fetch and the SetEvent() operation. aoqi@0: // SetEvent() would either fail because the handle was invalid, or inadvertently work, aoqi@0: // as the win32 handle value had been recycled. In an ideal world calling SetEvent() aoqi@0: // on an stale but recycled handle would be harmless, but in practice this might aoqi@0: // confuse other non-Sun code, so it's not a viable approach. aoqi@0: // aoqi@0: // 2: Once a win32 event handle is associated with an Event, it remains associated aoqi@0: // with the Event. The event handle is never closed. This could be construed aoqi@0: // as handle leakage, but only up to the maximum # of threads that have been extant aoqi@0: // at any one time. This shouldn't be an issue, as windows platforms typically aoqi@0: // permit a process to have hundreds of thousands of open handles. aoqi@0: // aoqi@0: // 3: Same as (1), but periodically, at stop-the-world time, rundown the EventFreeList aoqi@0: // and release unused handles. aoqi@0: // aoqi@0: // 4: Add a CRITICAL_SECTION to the Event to protect LD+SetEvent from LD;ST(null);CloseHandle. aoqi@0: // It's not clear, however, that we wouldn't be trading one type of leak for another. aoqi@0: // aoqi@0: // 5. Use an RCU-like mechanism (Read-Copy Update). aoqi@0: // Or perhaps something similar to Maged Michael's "Hazard pointers". aoqi@0: // aoqi@0: // We use (2). aoqi@0: // aoqi@0: // TODO-FIXME: aoqi@0: // 1. Reconcile Doug's JSR166 j.u.c park-unpark with the objectmonitor implementation. aoqi@0: // 2. Consider wrapping the WaitForSingleObject(Ex) calls in SEH try/finally blocks aoqi@0: // to recover from (or at least detect) the dreaded Windows 841176 bug. aoqi@0: // 3. Collapse the interrupt_event, the JSR166 parker event, and the objectmonitor ParkEvent aoqi@0: // into a single win32 CreateEvent() handle. aoqi@0: // aoqi@0: // _Event transitions in park() aoqi@0: // -1 => -1 : illegal aoqi@0: // 1 => 0 : pass - return immediately aoqi@0: // 0 => -1 : block aoqi@0: // aoqi@0: // _Event serves as a restricted-range semaphore : aoqi@0: // -1 : thread is blocked aoqi@0: // 0 : neutral - thread is running or ready aoqi@0: // 1 : signaled - thread is running or ready aoqi@0: // aoqi@0: // Another possible encoding of _Event would be aoqi@0: // with explicit "PARKED" and "SIGNALED" bits. aoqi@0: aoqi@0: int os::PlatformEvent::park (jlong Millis) { aoqi@0: guarantee (_ParkHandle != NULL , "Invariant") ; aoqi@0: guarantee (Millis > 0 , "Invariant") ; aoqi@0: int v ; aoqi@0: aoqi@0: // CONSIDER: defer assigning a CreateEvent() handle to the Event until aoqi@0: // the initial park() operation. aoqi@0: aoqi@0: for (;;) { aoqi@0: v = _Event ; aoqi@0: if (Atomic::cmpxchg (v-1, &_Event, v) == v) break ; aoqi@0: } aoqi@0: guarantee ((v == 0) || (v == 1), "invariant") ; aoqi@0: if (v != 0) return OS_OK ; aoqi@0: aoqi@0: // Do this the hard way by blocking ... aoqi@0: // TODO: consider a brief spin here, gated on the success of recent aoqi@0: // spin attempts by this thread. aoqi@0: // aoqi@0: // We decompose long timeouts into series of shorter timed waits. aoqi@0: // Evidently large timo values passed in WaitForSingleObject() are problematic on some aoqi@0: // versions of Windows. See EventWait() for details. This may be superstition. Or not. aoqi@0: // We trust the WAIT_TIMEOUT indication and don't track the elapsed wait time aoqi@0: // with os::javaTimeNanos(). Furthermore, we assume that spurious returns from aoqi@0: // ::WaitForSingleObject() caused by latent ::setEvent() operations will tend aoqi@0: // to happen early in the wait interval. Specifically, after a spurious wakeup (rv == aoqi@0: // WAIT_OBJECT_0 but _Event is still < 0) we don't bother to recompute Millis to compensate aoqi@0: // for the already waited time. This policy does not admit any new outcomes. aoqi@0: // In the future, however, we might want to track the accumulated wait time and aoqi@0: // adjust Millis accordingly if we encounter a spurious wakeup. aoqi@0: aoqi@0: const int MAXTIMEOUT = 0x10000000 ; aoqi@0: DWORD rv = WAIT_TIMEOUT ; aoqi@0: while (_Event < 0 && Millis > 0) { aoqi@0: DWORD prd = Millis ; // set prd = MAX (Millis, MAXTIMEOUT) aoqi@0: if (Millis > MAXTIMEOUT) { aoqi@0: prd = MAXTIMEOUT ; aoqi@0: } aoqi@0: rv = ::WaitForSingleObject (_ParkHandle, prd) ; aoqi@0: assert (rv == WAIT_OBJECT_0 || rv == WAIT_TIMEOUT, "WaitForSingleObject failed") ; aoqi@0: if (rv == WAIT_TIMEOUT) { aoqi@0: Millis -= prd ; aoqi@0: } aoqi@0: } aoqi@0: v = _Event ; aoqi@0: _Event = 0 ; aoqi@0: // see comment at end of os::PlatformEvent::park() below: aoqi@0: OrderAccess::fence() ; aoqi@0: // If we encounter a nearly simultanous timeout expiry and unpark() aoqi@0: // we return OS_OK indicating we awoke via unpark(). aoqi@0: // Implementor's license -- returning OS_TIMEOUT would be equally valid, however. aoqi@0: return (v >= 0) ? OS_OK : OS_TIMEOUT ; aoqi@0: } aoqi@0: aoqi@0: void os::PlatformEvent::park () { aoqi@0: guarantee (_ParkHandle != NULL, "Invariant") ; aoqi@0: // Invariant: Only the thread associated with the Event/PlatformEvent aoqi@0: // may call park(). aoqi@0: int v ; aoqi@0: for (;;) { aoqi@0: v = _Event ; aoqi@0: if (Atomic::cmpxchg (v-1, &_Event, v) == v) break ; aoqi@0: } aoqi@0: guarantee ((v == 0) || (v == 1), "invariant") ; aoqi@0: if (v != 0) return ; aoqi@0: aoqi@0: // Do this the hard way by blocking ... aoqi@0: // TODO: consider a brief spin here, gated on the success of recent aoqi@0: // spin attempts by this thread. aoqi@0: while (_Event < 0) { aoqi@0: DWORD rv = ::WaitForSingleObject (_ParkHandle, INFINITE) ; aoqi@0: assert (rv == WAIT_OBJECT_0, "WaitForSingleObject failed") ; aoqi@0: } aoqi@0: aoqi@0: // Usually we'll find _Event == 0 at this point, but as aoqi@0: // an optional optimization we clear it, just in case can aoqi@0: // multiple unpark() operations drove _Event up to 1. aoqi@0: _Event = 0 ; aoqi@0: OrderAccess::fence() ; aoqi@0: guarantee (_Event >= 0, "invariant") ; aoqi@0: } aoqi@0: aoqi@0: void os::PlatformEvent::unpark() { aoqi@0: guarantee (_ParkHandle != NULL, "Invariant") ; aoqi@0: aoqi@0: // Transitions for _Event: aoqi@0: // 0 :=> 1 aoqi@0: // 1 :=> 1 aoqi@0: // -1 :=> either 0 or 1; must signal target thread aoqi@0: // That is, we can safely transition _Event from -1 to either aoqi@0: // 0 or 1. Forcing 1 is slightly more efficient for back-to-back aoqi@0: // unpark() calls. aoqi@0: // See also: "Semaphores in Plan 9" by Mullender & Cox aoqi@0: // aoqi@0: // Note: Forcing a transition from "-1" to "1" on an unpark() means aoqi@0: // that it will take two back-to-back park() calls for the owning aoqi@0: // thread to block. This has the benefit of forcing a spurious return aoqi@0: // from the first park() call after an unpark() call which will help aoqi@0: // shake out uses of park() and unpark() without condition variables. aoqi@0: aoqi@0: if (Atomic::xchg(1, &_Event) >= 0) return; aoqi@0: aoqi@0: ::SetEvent(_ParkHandle); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // JSR166 aoqi@0: // ------------------------------------------------------- aoqi@0: aoqi@0: /* aoqi@0: * The Windows implementation of Park is very straightforward: Basic aoqi@0: * operations on Win32 Events turn out to have the right semantics to aoqi@0: * use them directly. We opportunistically resuse the event inherited aoqi@0: * from Monitor. aoqi@0: */ aoqi@0: aoqi@0: aoqi@0: void Parker::park(bool isAbsolute, jlong time) { aoqi@0: guarantee (_ParkEvent != NULL, "invariant") ; aoqi@0: // First, demultiplex/decode time arguments aoqi@0: if (time < 0) { // don't wait aoqi@0: return; aoqi@0: } aoqi@0: else if (time == 0 && !isAbsolute) { aoqi@0: time = INFINITE; aoqi@0: } aoqi@0: else if (isAbsolute) { aoqi@0: time -= os::javaTimeMillis(); // convert to relative time aoqi@0: if (time <= 0) // already elapsed aoqi@0: return; aoqi@0: } aoqi@0: else { // relative aoqi@0: time /= 1000000; // Must coarsen from nanos to millis aoqi@0: if (time == 0) // Wait for the minimal time unit if zero aoqi@0: time = 1; aoqi@0: } aoqi@0: aoqi@0: JavaThread* thread = (JavaThread*)(Thread::current()); aoqi@0: assert(thread->is_Java_thread(), "Must be JavaThread"); aoqi@0: JavaThread *jt = (JavaThread *)thread; aoqi@0: aoqi@0: // Don't wait if interrupted or already triggered aoqi@0: if (Thread::is_interrupted(thread, false) || aoqi@0: WaitForSingleObject(_ParkEvent, 0) == WAIT_OBJECT_0) { aoqi@0: ResetEvent(_ParkEvent); aoqi@0: return; aoqi@0: } aoqi@0: else { aoqi@0: ThreadBlockInVM tbivm(jt); aoqi@0: OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */); aoqi@0: jt->set_suspend_equivalent(); aoqi@0: aoqi@0: WaitForSingleObject(_ParkEvent, time); aoqi@0: ResetEvent(_ParkEvent); aoqi@0: aoqi@0: // If externally suspended while waiting, re-suspend aoqi@0: if (jt->handle_special_suspend_equivalent_condition()) { aoqi@0: jt->java_suspend_self(); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void Parker::unpark() { aoqi@0: guarantee (_ParkEvent != NULL, "invariant") ; aoqi@0: SetEvent(_ParkEvent); aoqi@0: } aoqi@0: aoqi@0: // Run the specified command in a separate process. Return its exit value, aoqi@0: // or -1 on failure (e.g. can't create a new process). aoqi@0: int os::fork_and_exec(char* cmd) { aoqi@0: STARTUPINFO si; aoqi@0: PROCESS_INFORMATION pi; aoqi@0: aoqi@0: memset(&si, 0, sizeof(si)); aoqi@0: si.cb = sizeof(si); aoqi@0: memset(&pi, 0, sizeof(pi)); aoqi@0: BOOL rslt = CreateProcess(NULL, // executable name - use command line aoqi@0: cmd, // command line aoqi@0: NULL, // process security attribute aoqi@0: NULL, // thread security attribute aoqi@0: TRUE, // inherits system handles aoqi@0: 0, // no creation flags aoqi@0: NULL, // use parent's environment block aoqi@0: NULL, // use parent's starting directory aoqi@0: &si, // (in) startup information aoqi@0: &pi); // (out) process information aoqi@0: aoqi@0: if (rslt) { aoqi@0: // Wait until child process exits. aoqi@0: WaitForSingleObject(pi.hProcess, INFINITE); aoqi@0: aoqi@0: DWORD exit_code; aoqi@0: GetExitCodeProcess(pi.hProcess, &exit_code); aoqi@0: aoqi@0: // Close process and thread handles. aoqi@0: CloseHandle(pi.hProcess); aoqi@0: CloseHandle(pi.hThread); aoqi@0: aoqi@0: return (int)exit_code; aoqi@0: } else { aoqi@0: return -1; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: //-------------------------------------------------------------------------------------------------- aoqi@0: // Non-product code aoqi@0: aoqi@0: static int mallocDebugIntervalCounter = 0; aoqi@0: static int mallocDebugCounter = 0; aoqi@0: bool os::check_heap(bool force) { aoqi@0: if (++mallocDebugCounter < MallocVerifyStart && !force) return true; aoqi@0: if (++mallocDebugIntervalCounter >= MallocVerifyInterval || force) { aoqi@0: // Note: HeapValidate executes two hardware breakpoints when it finds something aoqi@0: // wrong; at these points, eax contains the address of the offending block (I think). aoqi@0: // To get to the exlicit error message(s) below, just continue twice. aoqi@0: HANDLE heap = GetProcessHeap(); aoqi@0: { HeapLock(heap); aoqi@0: PROCESS_HEAP_ENTRY phe; aoqi@0: phe.lpData = NULL; aoqi@0: while (HeapWalk(heap, &phe) != 0) { aoqi@0: if ((phe.wFlags & PROCESS_HEAP_ENTRY_BUSY) && aoqi@0: !HeapValidate(heap, 0, phe.lpData)) { aoqi@0: tty->print_cr("C heap has been corrupted (time: %d allocations)", mallocDebugCounter); aoqi@0: tty->print_cr("corrupted block near address %#x, length %d", phe.lpData, phe.cbData); aoqi@0: fatal("corrupted C heap"); aoqi@0: } aoqi@0: } aoqi@0: DWORD err = GetLastError(); aoqi@0: if (err != ERROR_NO_MORE_ITEMS && err != ERROR_CALL_NOT_IMPLEMENTED) { aoqi@0: fatal(err_msg("heap walk aborted with error %d", err)); aoqi@0: } aoqi@0: HeapUnlock(heap); aoqi@0: } aoqi@0: mallocDebugIntervalCounter = 0; aoqi@0: } aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: bool os::find(address addr, outputStream* st) { aoqi@0: // Nothing yet aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: LONG WINAPI os::win32::serialize_fault_filter(struct _EXCEPTION_POINTERS* e) { aoqi@0: DWORD exception_code = e->ExceptionRecord->ExceptionCode; aoqi@0: aoqi@0: if ( exception_code == EXCEPTION_ACCESS_VIOLATION ) { aoqi@0: JavaThread* thread = (JavaThread*)ThreadLocalStorage::get_thread_slow(); aoqi@0: PEXCEPTION_RECORD exceptionRecord = e->ExceptionRecord; aoqi@0: address addr = (address) exceptionRecord->ExceptionInformation[1]; aoqi@0: aoqi@0: if (os::is_memory_serialize_page(thread, addr)) aoqi@0: return EXCEPTION_CONTINUE_EXECUTION; aoqi@0: } aoqi@0: aoqi@0: return EXCEPTION_CONTINUE_SEARCH; aoqi@0: } aoqi@0: aoqi@0: // We don't build a headless jre for Windows aoqi@0: bool os::is_headless_jre() { return false; } aoqi@0: aoqi@0: static jint initSock() { aoqi@0: WSADATA wsadata; aoqi@0: aoqi@0: if (!os::WinSock2Dll::WinSock2Available()) { aoqi@0: jio_fprintf(stderr, "Could not load Winsock (error: %d)\n", aoqi@0: ::GetLastError()); aoqi@0: return JNI_ERR; aoqi@0: } aoqi@0: aoqi@0: if (os::WinSock2Dll::WSAStartup(MAKEWORD(2,2), &wsadata) != 0) { aoqi@0: jio_fprintf(stderr, "Could not initialize Winsock (error: %d)\n", aoqi@0: ::GetLastError()); aoqi@0: return JNI_ERR; aoqi@0: } aoqi@0: return JNI_OK; aoqi@0: } aoqi@0: aoqi@0: struct hostent* os::get_host_by_name(char* name) { aoqi@0: return (struct hostent*)os::WinSock2Dll::gethostbyname(name); aoqi@0: } aoqi@0: aoqi@0: int os::socket_close(int fd) { aoqi@0: return ::closesocket(fd); aoqi@0: } aoqi@0: aoqi@0: int os::socket_available(int fd, jint *pbytes) { aoqi@0: int ret = ::ioctlsocket(fd, FIONREAD, (u_long*)pbytes); aoqi@0: return (ret < 0) ? 0 : 1; aoqi@0: } aoqi@0: aoqi@0: int os::socket(int domain, int type, int protocol) { aoqi@0: return ::socket(domain, type, protocol); aoqi@0: } aoqi@0: aoqi@0: int os::listen(int fd, int count) { aoqi@0: return ::listen(fd, count); aoqi@0: } aoqi@0: aoqi@0: int os::connect(int fd, struct sockaddr* him, socklen_t len) { aoqi@0: return ::connect(fd, him, len); aoqi@0: } aoqi@0: aoqi@0: int os::accept(int fd, struct sockaddr* him, socklen_t* len) { aoqi@0: return ::accept(fd, him, len); aoqi@0: } aoqi@0: aoqi@0: int os::sendto(int fd, char* buf, size_t len, uint flags, aoqi@0: struct sockaddr* to, socklen_t tolen) { aoqi@0: aoqi@0: return ::sendto(fd, buf, (int)len, flags, to, tolen); aoqi@0: } aoqi@0: aoqi@0: int os::recvfrom(int fd, char *buf, size_t nBytes, uint flags, aoqi@0: sockaddr* from, socklen_t* fromlen) { aoqi@0: aoqi@0: return ::recvfrom(fd, buf, (int)nBytes, flags, from, fromlen); aoqi@0: } aoqi@0: aoqi@0: int os::recv(int fd, char* buf, size_t nBytes, uint flags) { aoqi@0: return ::recv(fd, buf, (int)nBytes, flags); aoqi@0: } aoqi@0: aoqi@0: int os::send(int fd, char* buf, size_t nBytes, uint flags) { aoqi@0: return ::send(fd, buf, (int)nBytes, flags); aoqi@0: } aoqi@0: aoqi@0: int os::raw_send(int fd, char* buf, size_t nBytes, uint flags) { aoqi@0: return ::send(fd, buf, (int)nBytes, flags); aoqi@0: } aoqi@0: aoqi@0: int os::timeout(int fd, long timeout) { aoqi@0: fd_set tbl; aoqi@0: struct timeval t; aoqi@0: aoqi@0: t.tv_sec = timeout / 1000; aoqi@0: t.tv_usec = (timeout % 1000) * 1000; aoqi@0: aoqi@0: tbl.fd_count = 1; aoqi@0: tbl.fd_array[0] = fd; aoqi@0: aoqi@0: return ::select(1, &tbl, 0, 0, &t); aoqi@0: } aoqi@0: aoqi@0: int os::get_host_name(char* name, int namelen) { aoqi@0: return ::gethostname(name, namelen); aoqi@0: } aoqi@0: aoqi@0: int os::socket_shutdown(int fd, int howto) { aoqi@0: return ::shutdown(fd, howto); aoqi@0: } aoqi@0: aoqi@0: int os::bind(int fd, struct sockaddr* him, socklen_t len) { aoqi@0: return ::bind(fd, him, len); aoqi@0: } aoqi@0: aoqi@0: int os::get_sock_name(int fd, struct sockaddr* him, socklen_t* len) { aoqi@0: return ::getsockname(fd, him, len); aoqi@0: } aoqi@0: aoqi@0: int os::get_sock_opt(int fd, int level, int optname, aoqi@0: char* optval, socklen_t* optlen) { aoqi@0: return ::getsockopt(fd, level, optname, optval, optlen); aoqi@0: } aoqi@0: aoqi@0: int os::set_sock_opt(int fd, int level, int optname, aoqi@0: const char* optval, socklen_t optlen) { aoqi@0: return ::setsockopt(fd, level, optname, optval, optlen); aoqi@0: } aoqi@0: aoqi@0: // WINDOWS CONTEXT Flags for THREAD_SAMPLING aoqi@0: #if defined(IA32) aoqi@0: # define sampling_context_flags (CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS) aoqi@0: #elif defined (AMD64) aoqi@0: # define sampling_context_flags (CONTEXT_FULL | CONTEXT_FLOATING_POINT) aoqi@0: #endif aoqi@0: aoqi@0: // returns true if thread could be suspended, aoqi@0: // false otherwise aoqi@0: static bool do_suspend(HANDLE* h) { aoqi@0: if (h != NULL) { aoqi@0: if (SuspendThread(*h) != ~0) { aoqi@0: return true; aoqi@0: } aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: // resume the thread aoqi@0: // calling resume on an active thread is a no-op aoqi@0: static void do_resume(HANDLE* h) { aoqi@0: if (h != NULL) { aoqi@0: ResumeThread(*h); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // retrieve a suspend/resume context capable handle aoqi@0: // from the tid. Caller validates handle return value. aoqi@0: void get_thread_handle_for_extended_context(HANDLE* h, OSThread::thread_id_t tid) { aoqi@0: if (h != NULL) { aoqi@0: *h = OpenThread(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, FALSE, tid); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // aoqi@0: // Thread sampling implementation aoqi@0: // aoqi@0: void os::SuspendedThreadTask::internal_do_task() { aoqi@0: CONTEXT ctxt; aoqi@0: HANDLE h = NULL; aoqi@0: aoqi@0: // get context capable handle for thread aoqi@0: get_thread_handle_for_extended_context(&h, _thread->osthread()->thread_id()); aoqi@0: aoqi@0: // sanity aoqi@0: if (h == NULL || h == INVALID_HANDLE_VALUE) { aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: // suspend the thread aoqi@0: if (do_suspend(&h)) { aoqi@0: ctxt.ContextFlags = sampling_context_flags; aoqi@0: // get thread context aoqi@0: GetThreadContext(h, &ctxt); aoqi@0: SuspendedThreadTaskContext context(_thread, &ctxt); aoqi@0: // pass context to Thread Sampling impl aoqi@0: do_task(context); aoqi@0: // resume thread aoqi@0: do_resume(&h); aoqi@0: } aoqi@0: aoqi@0: // close handle aoqi@0: CloseHandle(h); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // Kernel32 API aoqi@0: typedef SIZE_T (WINAPI* GetLargePageMinimum_Fn)(void); aoqi@0: typedef LPVOID (WINAPI *VirtualAllocExNuma_Fn) (HANDLE, LPVOID, SIZE_T, DWORD, DWORD, DWORD); aoqi@0: typedef BOOL (WINAPI *GetNumaHighestNodeNumber_Fn) (PULONG); aoqi@0: typedef BOOL (WINAPI *GetNumaNodeProcessorMask_Fn) (UCHAR, PULONGLONG); aoqi@0: typedef USHORT (WINAPI* RtlCaptureStackBackTrace_Fn)(ULONG, ULONG, PVOID*, PULONG); aoqi@0: aoqi@0: GetLargePageMinimum_Fn os::Kernel32Dll::_GetLargePageMinimum = NULL; aoqi@0: VirtualAllocExNuma_Fn os::Kernel32Dll::_VirtualAllocExNuma = NULL; aoqi@0: GetNumaHighestNodeNumber_Fn os::Kernel32Dll::_GetNumaHighestNodeNumber = NULL; aoqi@0: GetNumaNodeProcessorMask_Fn os::Kernel32Dll::_GetNumaNodeProcessorMask = NULL; aoqi@0: RtlCaptureStackBackTrace_Fn os::Kernel32Dll::_RtlCaptureStackBackTrace = NULL; aoqi@0: aoqi@0: aoqi@0: BOOL os::Kernel32Dll::initialized = FALSE; aoqi@0: SIZE_T os::Kernel32Dll::GetLargePageMinimum() { aoqi@0: assert(initialized && _GetLargePageMinimum != NULL, aoqi@0: "GetLargePageMinimumAvailable() not yet called"); aoqi@0: return _GetLargePageMinimum(); aoqi@0: } aoqi@0: aoqi@0: BOOL os::Kernel32Dll::GetLargePageMinimumAvailable() { aoqi@0: if (!initialized) { aoqi@0: initialize(); aoqi@0: } aoqi@0: return _GetLargePageMinimum != NULL; aoqi@0: } aoqi@0: aoqi@0: BOOL os::Kernel32Dll::NumaCallsAvailable() { aoqi@0: if (!initialized) { aoqi@0: initialize(); aoqi@0: } aoqi@0: return _VirtualAllocExNuma != NULL; aoqi@0: } aoqi@0: aoqi@0: LPVOID os::Kernel32Dll::VirtualAllocExNuma(HANDLE hProc, LPVOID addr, SIZE_T bytes, DWORD flags, DWORD prot, DWORD node) { aoqi@0: assert(initialized && _VirtualAllocExNuma != NULL, aoqi@0: "NUMACallsAvailable() not yet called"); aoqi@0: aoqi@0: return _VirtualAllocExNuma(hProc, addr, bytes, flags, prot, node); aoqi@0: } aoqi@0: aoqi@0: BOOL os::Kernel32Dll::GetNumaHighestNodeNumber(PULONG ptr_highest_node_number) { aoqi@0: assert(initialized && _GetNumaHighestNodeNumber != NULL, aoqi@0: "NUMACallsAvailable() not yet called"); aoqi@0: aoqi@0: return _GetNumaHighestNodeNumber(ptr_highest_node_number); aoqi@0: } aoqi@0: aoqi@0: BOOL os::Kernel32Dll::GetNumaNodeProcessorMask(UCHAR node, PULONGLONG proc_mask) { aoqi@0: assert(initialized && _GetNumaNodeProcessorMask != NULL, aoqi@0: "NUMACallsAvailable() not yet called"); aoqi@0: aoqi@0: return _GetNumaNodeProcessorMask(node, proc_mask); aoqi@0: } aoqi@0: aoqi@0: USHORT os::Kernel32Dll::RtlCaptureStackBackTrace(ULONG FrameToSkip, aoqi@0: ULONG FrameToCapture, PVOID* BackTrace, PULONG BackTraceHash) { aoqi@0: if (!initialized) { aoqi@0: initialize(); aoqi@0: } aoqi@0: aoqi@0: if (_RtlCaptureStackBackTrace != NULL) { aoqi@0: return _RtlCaptureStackBackTrace(FrameToSkip, FrameToCapture, aoqi@0: BackTrace, BackTraceHash); aoqi@0: } else { aoqi@0: return 0; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void os::Kernel32Dll::initializeCommon() { aoqi@0: if (!initialized) { aoqi@0: HMODULE handle = ::GetModuleHandle("Kernel32.dll"); aoqi@0: assert(handle != NULL, "Just check"); aoqi@0: _GetLargePageMinimum = (GetLargePageMinimum_Fn)::GetProcAddress(handle, "GetLargePageMinimum"); aoqi@0: _VirtualAllocExNuma = (VirtualAllocExNuma_Fn)::GetProcAddress(handle, "VirtualAllocExNuma"); aoqi@0: _GetNumaHighestNodeNumber = (GetNumaHighestNodeNumber_Fn)::GetProcAddress(handle, "GetNumaHighestNodeNumber"); aoqi@0: _GetNumaNodeProcessorMask = (GetNumaNodeProcessorMask_Fn)::GetProcAddress(handle, "GetNumaNodeProcessorMask"); aoqi@0: _RtlCaptureStackBackTrace = (RtlCaptureStackBackTrace_Fn)::GetProcAddress(handle, "RtlCaptureStackBackTrace"); aoqi@0: initialized = TRUE; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: aoqi@0: #ifndef JDK6_OR_EARLIER aoqi@0: aoqi@0: void os::Kernel32Dll::initialize() { aoqi@0: initializeCommon(); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // Kernel32 API aoqi@0: inline BOOL os::Kernel32Dll::SwitchToThread() { aoqi@0: return ::SwitchToThread(); aoqi@0: } aoqi@0: aoqi@0: inline BOOL os::Kernel32Dll::SwitchToThreadAvailable() { aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: // Help tools aoqi@0: inline BOOL os::Kernel32Dll::HelpToolsAvailable() { aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: inline HANDLE os::Kernel32Dll::CreateToolhelp32Snapshot(DWORD dwFlags,DWORD th32ProcessId) { aoqi@0: return ::CreateToolhelp32Snapshot(dwFlags, th32ProcessId); aoqi@0: } aoqi@0: aoqi@0: inline BOOL os::Kernel32Dll::Module32First(HANDLE hSnapshot,LPMODULEENTRY32 lpme) { aoqi@0: return ::Module32First(hSnapshot, lpme); aoqi@0: } aoqi@0: aoqi@0: inline BOOL os::Kernel32Dll::Module32Next(HANDLE hSnapshot,LPMODULEENTRY32 lpme) { aoqi@0: return ::Module32Next(hSnapshot, lpme); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: inline BOOL os::Kernel32Dll::GetNativeSystemInfoAvailable() { aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: inline void os::Kernel32Dll::GetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo) { aoqi@0: ::GetNativeSystemInfo(lpSystemInfo); aoqi@0: } aoqi@0: aoqi@0: // PSAPI API aoqi@0: inline BOOL os::PSApiDll::EnumProcessModules(HANDLE hProcess, HMODULE *lpModule, DWORD cb, LPDWORD lpcbNeeded) { aoqi@0: return ::EnumProcessModules(hProcess, lpModule, cb, lpcbNeeded); aoqi@0: } aoqi@0: aoqi@0: inline DWORD os::PSApiDll::GetModuleFileNameEx(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize) { aoqi@0: return ::GetModuleFileNameEx(hProcess, hModule, lpFilename, nSize); aoqi@0: } aoqi@0: aoqi@0: inline BOOL os::PSApiDll::GetModuleInformation(HANDLE hProcess, HMODULE hModule, LPMODULEINFO lpmodinfo, DWORD cb) { aoqi@0: return ::GetModuleInformation(hProcess, hModule, lpmodinfo, cb); aoqi@0: } aoqi@0: aoqi@0: inline BOOL os::PSApiDll::PSApiAvailable() { aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // WinSock2 API aoqi@0: inline BOOL os::WinSock2Dll::WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData) { aoqi@0: return ::WSAStartup(wVersionRequested, lpWSAData); aoqi@0: } aoqi@0: aoqi@0: inline struct hostent* os::WinSock2Dll::gethostbyname(const char *name) { aoqi@0: return ::gethostbyname(name); aoqi@0: } aoqi@0: aoqi@0: inline BOOL os::WinSock2Dll::WinSock2Available() { aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: // Advapi API aoqi@0: inline BOOL os::Advapi32Dll::AdjustTokenPrivileges(HANDLE TokenHandle, aoqi@0: BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, DWORD BufferLength, aoqi@0: PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength) { aoqi@0: return ::AdjustTokenPrivileges(TokenHandle, DisableAllPrivileges, NewState, aoqi@0: BufferLength, PreviousState, ReturnLength); aoqi@0: } aoqi@0: aoqi@0: inline BOOL os::Advapi32Dll::OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, aoqi@0: PHANDLE TokenHandle) { aoqi@0: return ::OpenProcessToken(ProcessHandle, DesiredAccess, TokenHandle); aoqi@0: } aoqi@0: aoqi@0: inline BOOL os::Advapi32Dll::LookupPrivilegeValue(LPCTSTR lpSystemName, LPCTSTR lpName, PLUID lpLuid) { aoqi@0: return ::LookupPrivilegeValue(lpSystemName, lpName, lpLuid); aoqi@0: } aoqi@0: aoqi@0: inline BOOL os::Advapi32Dll::AdvapiAvailable() { aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: void* os::get_default_process_handle() { aoqi@0: return (void*)GetModuleHandle(NULL); aoqi@0: } aoqi@0: aoqi@0: // Builds a platform dependent Agent_OnLoad_ function name aoqi@0: // which is used to find statically linked in agents. aoqi@0: // Additionally for windows, takes into account __stdcall names. aoqi@0: // Parameters: aoqi@0: // sym_name: Symbol in library we are looking for aoqi@0: // lib_name: Name of library to look in, NULL for shared libs. aoqi@0: // is_absolute_path == true if lib_name is absolute path to agent aoqi@0: // such as "C:/a/b/L.dll" aoqi@0: // == false if only the base name of the library is passed in aoqi@0: // such as "L" aoqi@0: char* os::build_agent_function_name(const char *sym_name, const char *lib_name, aoqi@0: bool is_absolute_path) { aoqi@0: char *agent_entry_name; aoqi@0: size_t len; aoqi@0: size_t name_len; aoqi@0: size_t prefix_len = strlen(JNI_LIB_PREFIX); aoqi@0: size_t suffix_len = strlen(JNI_LIB_SUFFIX); aoqi@0: const char *start; aoqi@0: aoqi@0: if (lib_name != NULL) { aoqi@0: len = name_len = strlen(lib_name); aoqi@0: if (is_absolute_path) { aoqi@0: // Need to strip path, prefix and suffix aoqi@0: if ((start = strrchr(lib_name, *os::file_separator())) != NULL) { aoqi@0: lib_name = ++start; aoqi@0: } else { aoqi@0: // Need to check for drive prefix aoqi@0: if ((start = strchr(lib_name, ':')) != NULL) { aoqi@0: lib_name = ++start; aoqi@0: } aoqi@0: } aoqi@0: if (len <= (prefix_len + suffix_len)) { aoqi@0: return NULL; aoqi@0: } aoqi@0: lib_name += prefix_len; aoqi@0: name_len = strlen(lib_name) - suffix_len; aoqi@0: } aoqi@0: } aoqi@0: len = (lib_name != NULL ? name_len : 0) + strlen(sym_name) + 2; aoqi@0: agent_entry_name = NEW_C_HEAP_ARRAY_RETURN_NULL(char, len, mtThread); aoqi@0: if (agent_entry_name == NULL) { aoqi@0: return NULL; aoqi@0: } aoqi@0: if (lib_name != NULL) { aoqi@0: const char *p = strrchr(sym_name, '@'); aoqi@0: if (p != NULL && p != sym_name) { aoqi@0: // sym_name == _Agent_OnLoad@XX aoqi@0: strncpy(agent_entry_name, sym_name, (p - sym_name)); aoqi@0: agent_entry_name[(p-sym_name)] = '\0'; aoqi@0: // agent_entry_name == _Agent_OnLoad aoqi@0: strcat(agent_entry_name, "_"); aoqi@0: strncat(agent_entry_name, lib_name, name_len); aoqi@0: strcat(agent_entry_name, p); aoqi@0: // agent_entry_name == _Agent_OnLoad_lib_name@XX aoqi@0: } else { aoqi@0: strcpy(agent_entry_name, sym_name); aoqi@0: strcat(agent_entry_name, "_"); aoqi@0: strncat(agent_entry_name, lib_name, name_len); aoqi@0: } aoqi@0: } else { aoqi@0: strcpy(agent_entry_name, sym_name); aoqi@0: } aoqi@0: return agent_entry_name; aoqi@0: } aoqi@0: aoqi@0: #else aoqi@0: // Kernel32 API aoqi@0: typedef BOOL (WINAPI* SwitchToThread_Fn)(void); aoqi@0: typedef HANDLE (WINAPI* CreateToolhelp32Snapshot_Fn)(DWORD,DWORD); aoqi@0: typedef BOOL (WINAPI* Module32First_Fn)(HANDLE,LPMODULEENTRY32); aoqi@0: typedef BOOL (WINAPI* Module32Next_Fn)(HANDLE,LPMODULEENTRY32); aoqi@0: typedef void (WINAPI* GetNativeSystemInfo_Fn)(LPSYSTEM_INFO); aoqi@0: aoqi@0: SwitchToThread_Fn os::Kernel32Dll::_SwitchToThread = NULL; aoqi@0: CreateToolhelp32Snapshot_Fn os::Kernel32Dll::_CreateToolhelp32Snapshot = NULL; aoqi@0: Module32First_Fn os::Kernel32Dll::_Module32First = NULL; aoqi@0: Module32Next_Fn os::Kernel32Dll::_Module32Next = NULL; aoqi@0: GetNativeSystemInfo_Fn os::Kernel32Dll::_GetNativeSystemInfo = NULL; aoqi@0: aoqi@0: void os::Kernel32Dll::initialize() { aoqi@0: if (!initialized) { aoqi@0: HMODULE handle = ::GetModuleHandle("Kernel32.dll"); aoqi@0: assert(handle != NULL, "Just check"); aoqi@0: aoqi@0: _SwitchToThread = (SwitchToThread_Fn)::GetProcAddress(handle, "SwitchToThread"); aoqi@0: _CreateToolhelp32Snapshot = (CreateToolhelp32Snapshot_Fn) aoqi@0: ::GetProcAddress(handle, "CreateToolhelp32Snapshot"); aoqi@0: _Module32First = (Module32First_Fn)::GetProcAddress(handle, "Module32First"); aoqi@0: _Module32Next = (Module32Next_Fn)::GetProcAddress(handle, "Module32Next"); aoqi@0: _GetNativeSystemInfo = (GetNativeSystemInfo_Fn)::GetProcAddress(handle, "GetNativeSystemInfo"); aoqi@0: initializeCommon(); // resolve the functions that always need resolving aoqi@0: aoqi@0: initialized = TRUE; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: BOOL os::Kernel32Dll::SwitchToThread() { aoqi@0: assert(initialized && _SwitchToThread != NULL, aoqi@0: "SwitchToThreadAvailable() not yet called"); aoqi@0: return _SwitchToThread(); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: BOOL os::Kernel32Dll::SwitchToThreadAvailable() { aoqi@0: if (!initialized) { aoqi@0: initialize(); aoqi@0: } aoqi@0: return _SwitchToThread != NULL; aoqi@0: } aoqi@0: aoqi@0: // Help tools aoqi@0: BOOL os::Kernel32Dll::HelpToolsAvailable() { aoqi@0: if (!initialized) { aoqi@0: initialize(); aoqi@0: } aoqi@0: return _CreateToolhelp32Snapshot != NULL && aoqi@0: _Module32First != NULL && aoqi@0: _Module32Next != NULL; aoqi@0: } aoqi@0: aoqi@0: HANDLE os::Kernel32Dll::CreateToolhelp32Snapshot(DWORD dwFlags,DWORD th32ProcessId) { aoqi@0: assert(initialized && _CreateToolhelp32Snapshot != NULL, aoqi@0: "HelpToolsAvailable() not yet called"); aoqi@0: aoqi@0: return _CreateToolhelp32Snapshot(dwFlags, th32ProcessId); aoqi@0: } aoqi@0: aoqi@0: BOOL os::Kernel32Dll::Module32First(HANDLE hSnapshot,LPMODULEENTRY32 lpme) { aoqi@0: assert(initialized && _Module32First != NULL, aoqi@0: "HelpToolsAvailable() not yet called"); aoqi@0: aoqi@0: return _Module32First(hSnapshot, lpme); aoqi@0: } aoqi@0: aoqi@0: inline BOOL os::Kernel32Dll::Module32Next(HANDLE hSnapshot,LPMODULEENTRY32 lpme) { aoqi@0: assert(initialized && _Module32Next != NULL, aoqi@0: "HelpToolsAvailable() not yet called"); aoqi@0: aoqi@0: return _Module32Next(hSnapshot, lpme); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: BOOL os::Kernel32Dll::GetNativeSystemInfoAvailable() { aoqi@0: if (!initialized) { aoqi@0: initialize(); aoqi@0: } aoqi@0: return _GetNativeSystemInfo != NULL; aoqi@0: } aoqi@0: aoqi@0: void os::Kernel32Dll::GetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo) { aoqi@0: assert(initialized && _GetNativeSystemInfo != NULL, aoqi@0: "GetNativeSystemInfoAvailable() not yet called"); aoqi@0: aoqi@0: _GetNativeSystemInfo(lpSystemInfo); aoqi@0: } aoqi@0: aoqi@0: // PSAPI API aoqi@0: aoqi@0: aoqi@0: typedef BOOL (WINAPI *EnumProcessModules_Fn)(HANDLE, HMODULE *, DWORD, LPDWORD); aoqi@0: typedef BOOL (WINAPI *GetModuleFileNameEx_Fn)(HANDLE, HMODULE, LPTSTR, DWORD);; aoqi@0: typedef BOOL (WINAPI *GetModuleInformation_Fn)(HANDLE, HMODULE, LPMODULEINFO, DWORD); aoqi@0: aoqi@0: EnumProcessModules_Fn os::PSApiDll::_EnumProcessModules = NULL; aoqi@0: GetModuleFileNameEx_Fn os::PSApiDll::_GetModuleFileNameEx = NULL; aoqi@0: GetModuleInformation_Fn os::PSApiDll::_GetModuleInformation = NULL; aoqi@0: BOOL os::PSApiDll::initialized = FALSE; aoqi@0: aoqi@0: void os::PSApiDll::initialize() { aoqi@0: if (!initialized) { aoqi@0: HMODULE handle = os::win32::load_Windows_dll("PSAPI.DLL", NULL, 0); aoqi@0: if (handle != NULL) { aoqi@0: _EnumProcessModules = (EnumProcessModules_Fn)::GetProcAddress(handle, aoqi@0: "EnumProcessModules"); aoqi@0: _GetModuleFileNameEx = (GetModuleFileNameEx_Fn)::GetProcAddress(handle, aoqi@0: "GetModuleFileNameExA"); aoqi@0: _GetModuleInformation = (GetModuleInformation_Fn)::GetProcAddress(handle, aoqi@0: "GetModuleInformation"); aoqi@0: } aoqi@0: initialized = TRUE; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: aoqi@0: BOOL os::PSApiDll::EnumProcessModules(HANDLE hProcess, HMODULE *lpModule, DWORD cb, LPDWORD lpcbNeeded) { aoqi@0: assert(initialized && _EnumProcessModules != NULL, aoqi@0: "PSApiAvailable() not yet called"); aoqi@0: return _EnumProcessModules(hProcess, lpModule, cb, lpcbNeeded); aoqi@0: } aoqi@0: aoqi@0: DWORD os::PSApiDll::GetModuleFileNameEx(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize) { aoqi@0: assert(initialized && _GetModuleFileNameEx != NULL, aoqi@0: "PSApiAvailable() not yet called"); aoqi@0: return _GetModuleFileNameEx(hProcess, hModule, lpFilename, nSize); aoqi@0: } aoqi@0: aoqi@0: BOOL os::PSApiDll::GetModuleInformation(HANDLE hProcess, HMODULE hModule, LPMODULEINFO lpmodinfo, DWORD cb) { aoqi@0: assert(initialized && _GetModuleInformation != NULL, aoqi@0: "PSApiAvailable() not yet called"); aoqi@0: return _GetModuleInformation(hProcess, hModule, lpmodinfo, cb); aoqi@0: } aoqi@0: aoqi@0: BOOL os::PSApiDll::PSApiAvailable() { aoqi@0: if (!initialized) { aoqi@0: initialize(); aoqi@0: } aoqi@0: return _EnumProcessModules != NULL && aoqi@0: _GetModuleFileNameEx != NULL && aoqi@0: _GetModuleInformation != NULL; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // WinSock2 API aoqi@0: typedef int (PASCAL FAR* WSAStartup_Fn)(WORD, LPWSADATA); aoqi@0: typedef struct hostent *(PASCAL FAR *gethostbyname_Fn)(...); aoqi@0: aoqi@0: WSAStartup_Fn os::WinSock2Dll::_WSAStartup = NULL; aoqi@0: gethostbyname_Fn os::WinSock2Dll::_gethostbyname = NULL; aoqi@0: BOOL os::WinSock2Dll::initialized = FALSE; aoqi@0: aoqi@0: void os::WinSock2Dll::initialize() { aoqi@0: if (!initialized) { aoqi@0: HMODULE handle = os::win32::load_Windows_dll("ws2_32.dll", NULL, 0); aoqi@0: if (handle != NULL) { aoqi@0: _WSAStartup = (WSAStartup_Fn)::GetProcAddress(handle, "WSAStartup"); aoqi@0: _gethostbyname = (gethostbyname_Fn)::GetProcAddress(handle, "gethostbyname"); aoqi@0: } aoqi@0: initialized = TRUE; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: BOOL os::WinSock2Dll::WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData) { aoqi@0: assert(initialized && _WSAStartup != NULL, aoqi@0: "WinSock2Available() not yet called"); aoqi@0: return _WSAStartup(wVersionRequested, lpWSAData); aoqi@0: } aoqi@0: aoqi@0: struct hostent* os::WinSock2Dll::gethostbyname(const char *name) { aoqi@0: assert(initialized && _gethostbyname != NULL, aoqi@0: "WinSock2Available() not yet called"); aoqi@0: return _gethostbyname(name); aoqi@0: } aoqi@0: aoqi@0: BOOL os::WinSock2Dll::WinSock2Available() { aoqi@0: if (!initialized) { aoqi@0: initialize(); aoqi@0: } aoqi@0: return _WSAStartup != NULL && aoqi@0: _gethostbyname != NULL; aoqi@0: } aoqi@0: aoqi@0: typedef BOOL (WINAPI *AdjustTokenPrivileges_Fn)(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD); aoqi@0: typedef BOOL (WINAPI *OpenProcessToken_Fn)(HANDLE, DWORD, PHANDLE); aoqi@0: typedef BOOL (WINAPI *LookupPrivilegeValue_Fn)(LPCTSTR, LPCTSTR, PLUID); aoqi@0: aoqi@0: AdjustTokenPrivileges_Fn os::Advapi32Dll::_AdjustTokenPrivileges = NULL; aoqi@0: OpenProcessToken_Fn os::Advapi32Dll::_OpenProcessToken = NULL; aoqi@0: LookupPrivilegeValue_Fn os::Advapi32Dll::_LookupPrivilegeValue = NULL; aoqi@0: BOOL os::Advapi32Dll::initialized = FALSE; aoqi@0: aoqi@0: void os::Advapi32Dll::initialize() { aoqi@0: if (!initialized) { aoqi@0: HMODULE handle = os::win32::load_Windows_dll("advapi32.dll", NULL, 0); aoqi@0: if (handle != NULL) { aoqi@0: _AdjustTokenPrivileges = (AdjustTokenPrivileges_Fn)::GetProcAddress(handle, aoqi@0: "AdjustTokenPrivileges"); aoqi@0: _OpenProcessToken = (OpenProcessToken_Fn)::GetProcAddress(handle, aoqi@0: "OpenProcessToken"); aoqi@0: _LookupPrivilegeValue = (LookupPrivilegeValue_Fn)::GetProcAddress(handle, aoqi@0: "LookupPrivilegeValueA"); aoqi@0: } aoqi@0: initialized = TRUE; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: BOOL os::Advapi32Dll::AdjustTokenPrivileges(HANDLE TokenHandle, aoqi@0: BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, DWORD BufferLength, aoqi@0: PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength) { aoqi@0: assert(initialized && _AdjustTokenPrivileges != NULL, aoqi@0: "AdvapiAvailable() not yet called"); aoqi@0: return _AdjustTokenPrivileges(TokenHandle, DisableAllPrivileges, NewState, aoqi@0: BufferLength, PreviousState, ReturnLength); aoqi@0: } aoqi@0: aoqi@0: BOOL os::Advapi32Dll::OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, aoqi@0: PHANDLE TokenHandle) { aoqi@0: assert(initialized && _OpenProcessToken != NULL, aoqi@0: "AdvapiAvailable() not yet called"); aoqi@0: return _OpenProcessToken(ProcessHandle, DesiredAccess, TokenHandle); aoqi@0: } aoqi@0: aoqi@0: BOOL os::Advapi32Dll::LookupPrivilegeValue(LPCTSTR lpSystemName, LPCTSTR lpName, PLUID lpLuid) { aoqi@0: assert(initialized && _LookupPrivilegeValue != NULL, aoqi@0: "AdvapiAvailable() not yet called"); aoqi@0: return _LookupPrivilegeValue(lpSystemName, lpName, lpLuid); aoqi@0: } aoqi@0: aoqi@0: BOOL os::Advapi32Dll::AdvapiAvailable() { aoqi@0: if (!initialized) { aoqi@0: initialize(); aoqi@0: } aoqi@0: return _AdjustTokenPrivileges != NULL && aoqi@0: _OpenProcessToken != NULL && aoqi@0: _LookupPrivilegeValue != NULL; aoqi@0: } aoqi@0: aoqi@0: #endif aoqi@0: aoqi@0: #ifndef PRODUCT aoqi@0: aoqi@0: // test the code path in reserve_memory_special() that tries to allocate memory in a single aoqi@0: // contiguous memory block at a particular address. aoqi@0: // The test first tries to find a good approximate address to allocate at by using the same aoqi@0: // method to allocate some memory at any address. The test then tries to allocate memory in aoqi@0: // the vicinity (not directly after it to avoid possible by-chance use of that location) aoqi@0: // This is of course only some dodgy assumption, there is no guarantee that the vicinity of aoqi@0: // the previously allocated memory is available for allocation. The only actual failure aoqi@0: // that is reported is when the test tries to allocate at a particular location but gets a aoqi@0: // different valid one. A NULL return value at this point is not considered an error but may aoqi@0: // be legitimate. aoqi@0: // If -XX:+VerboseInternalVMTests is enabled, print some explanatory messages. aoqi@0: void TestReserveMemorySpecial_test() { aoqi@0: if (!UseLargePages) { aoqi@0: if (VerboseInternalVMTests) { aoqi@0: gclog_or_tty->print("Skipping test because large pages are disabled"); aoqi@0: } aoqi@0: return; aoqi@0: } aoqi@0: // save current value of globals aoqi@0: bool old_use_large_pages_individual_allocation = UseLargePagesIndividualAllocation; aoqi@0: bool old_use_numa_interleaving = UseNUMAInterleaving; aoqi@0: aoqi@0: // set globals to make sure we hit the correct code path aoqi@0: UseLargePagesIndividualAllocation = UseNUMAInterleaving = false; aoqi@0: aoqi@0: // do an allocation at an address selected by the OS to get a good one. aoqi@0: const size_t large_allocation_size = os::large_page_size() * 4; aoqi@0: char* result = os::reserve_memory_special(large_allocation_size, os::large_page_size(), NULL, false); aoqi@0: if (result == NULL) { aoqi@0: if (VerboseInternalVMTests) { aoqi@0: gclog_or_tty->print("Failed to allocate control block with size "SIZE_FORMAT". Skipping remainder of test.", aoqi@0: large_allocation_size); aoqi@0: } aoqi@0: } else { aoqi@0: os::release_memory_special(result, large_allocation_size); aoqi@0: aoqi@0: // allocate another page within the recently allocated memory area which seems to be a good location. At least aoqi@0: // we managed to get it once. aoqi@0: const size_t expected_allocation_size = os::large_page_size(); aoqi@0: char* expected_location = result + os::large_page_size(); aoqi@0: char* actual_location = os::reserve_memory_special(expected_allocation_size, os::large_page_size(), expected_location, false); aoqi@0: if (actual_location == NULL) { aoqi@0: if (VerboseInternalVMTests) { aoqi@0: gclog_or_tty->print("Failed to allocate any memory at "PTR_FORMAT" size "SIZE_FORMAT". Skipping remainder of test.", aoqi@0: expected_location, large_allocation_size); aoqi@0: } aoqi@0: } else { aoqi@0: // release memory aoqi@0: os::release_memory_special(actual_location, expected_allocation_size); aoqi@0: // only now check, after releasing any memory to avoid any leaks. aoqi@0: assert(actual_location == expected_location, aoqi@0: err_msg("Failed to allocate memory at requested location "PTR_FORMAT" of size "SIZE_FORMAT", is "PTR_FORMAT" instead", aoqi@0: expected_location, expected_allocation_size, actual_location)); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // restore globals aoqi@0: UseLargePagesIndividualAllocation = old_use_large_pages_individual_allocation; aoqi@0: UseNUMAInterleaving = old_use_numa_interleaving; aoqi@0: } aoqi@0: #endif // PRODUCT aoqi@0: