/* * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
// API level must be at least Windows Vista or Server 2008 to use InitOnceExecuteOnce
// No setuid programs under Windows. bool os::have_special_privileges() { returnfalse;
}
// This method is a periodic task to check for misbehaving JNI applications // under CheckJNI, we can add any periodic checks here. // For Windows at the moment does nothing void os::run_periodic_checks(outputStream* st) { return;
}
// previous UnhandledExceptionFilter, if there is one static LPTOP_LEVEL_EXCEPTION_FILTER prev_uef_handler = NULL;
LONG WINAPI Handle_FLT_Exception(struct _EXCEPTION_POINTERS* exceptionInfo);
if (alt_home_dir != NULL) {
strncpy(home_dir, alt_home_dir, MAX_PATH + 1);
home_dir[MAX_PATH] = '\0';
} else {
os::jvm_path(home_dir, sizeof(home_dir)); // Found the full path to jvm.dll. // Now cut the path to <java_home>/jre if we can.
*(strrchr(home_dir, '\\')) = '\0'; // get rid of \jvm.dll
pslash = strrchr(home_dir, '\\'); if (pslash != NULL) {
*pslash = '\0'; // get rid of \{client|server}
pslash = strrchr(home_dir, '\\'); if (pslash != NULL) {
*pslash = '\0'; // get rid of \bin
}
}
}
if (!set_boot_path('\\', ';')) {
vm_exit_during_initialization("Failed setting boot class path.", NULL);
}
}
// library_path #define EXT_DIR "\\lib\\ext" #define BIN_DIR "\\bin" #define PACKAGE_DIR "\\Sun\\Java"
{ // Win32 library search order (See the documentation for LoadLibrary): // // 1. The directory from which application is loaded. // 2. The system wide Java Extensions directory (Java only) // 3. System directory (GetSystemDirectory) // 4. Windows directory (GetWindowsDirectory) // 5. The PATH environment variable // 6. The current directory
#ifndef _WIN64 // set our UnhandledExceptionFilter and save any previous one
prev_uef_handler = SetUnhandledExceptionFilter(Handle_FLT_Exception); #endif
// Done return;
}
void os::breakpoint() {
DebugBreak();
}
// Invoked from the BREAKPOINT Macro extern"C"void breakpoint() {
os::breakpoint();
}
// RtlCaptureStackBackTrace Windows API may not exist prior to Windows XP. // So far, this method is only used by Native Memory Tracking, which is // only supported on Windows XP or later. // int os::get_native_stack(address* stack, int frames, int toSkip) { int captured = RtlCaptureStackBackTrace(toSkip + 1, frames, (PVOID*)stack, NULL); for (int index = captured; index < frames; index ++) {
stack[index] = NULL;
} return captured;
}
// os::current_stack_base() // // Returns the base of the stack, which is the stack's // starting address. This function must be called // while running on the stack of the thread being queried.
// Add up the sizes of all the regions with the same // AllocationBase. while (1) {
VirtualQuery(stack_bottom+stack_size, &minfo, sizeof(minfo)); if (stack_bottom == (address)minfo.AllocationBase) {
stack_size += minfo.RegionSize;
} else { break;
}
} return stack_bottom + stack_size;
}
if (committed_start == NULL) {
assert(committed_size == 0, "Sanity"); returnfalse;
} else {
assert(committed_start >= start_addr && committed_start < top, "Out of range"); // current region may go beyond the limit, trim to the limit
committed_size = MIN2(committed_size, size_t(top - committed_start)); returntrue;
}
}
#ifdef USE_VECTORED_EXCEPTION_HANDLING // Any exception is caught by the Vectored Exception Handler, so VM can // generate error dump when an exception occurred in non-Java thread // (e.g. VM thread).
thread->call_run(); #else // Install a win32 structured exception handler around every thread created // by VM, so VM can generate error dump when an exception occurred in non- // Java thread (e.g. VM thread).
__try {
thread->call_run();
} __except(topLevelExceptionFilter(
(_EXCEPTION_POINTERS*)_exception_info())) { // Nothing to do.
} #endif
// Note: at this point the thread object may already have deleted itself. // Do not dereference it from here on out.
// Thread must not return from exit_process_or_thread(), but if it does, // let it proceed to exit normally return (unsigned)os::win32::exit_process_or_thread(os::win32::EPT_THREAD, res);
}
static OSThread* create_os_thread(Thread* thread, HANDLE thread_handle, int thread_id) { // Allocate the OSThread object
OSThread* osthread = new OSThread(); if (osthread == NULL) return NULL;
// Initialize the JDK library's interrupt event. // This should really be done when OSThread is constructed, // but there is no way for a constructor to report failure to // allocate the event.
HANDLE interrupt_event = CreateEvent(NULL, true, false, NULL); if (interrupt_event == NULL) { delete osthread; return NULL;
}
osthread->set_interrupt_event(interrupt_event);
// Store info on the Win32 thread into the OSThread
osthread->set_thread_handle(thread_handle);
osthread->set_thread_id(thread_id);
if (UseNUMA) { int lgrp_id = os::numa_get_group_id(); if (lgrp_id != -1) {
thread->set_lgrp_id(lgrp_id);
}
}
// Initial thread state is INITIALIZED, not SUSPENDED
osthread->set_state(INITIALIZED);
// Helper function to trace _beginthreadex attributes, // similar to os::Posix::describe_pthread_attr() staticchar* describe_beginthreadex_attributes(char* buf, size_t buflen,
size_t stacksize, unsigned initflag) {
stringStream ss(buf, buflen); if (stacksize == 0) {
ss.print("stacksize: default, ");
} else {
ss.print("stacksize: " SIZE_FORMAT "k, ", stacksize / K);
}
ss.print("flags: "); #define PRINT_FLAG(f) if (initflag & f) ss.print( #f" "); #define ALL(X) \
X(CREATE_SUSPENDED) \
X(STACK_SIZE_PARAM_IS_A_RESERVATION)
ALL(PRINT_FLAG) #undef ALL #undef PRINT_FLAG return buf;
}
// Allocate and initialize a new OSThread bool os::create_thread(Thread* thread, ThreadType thr_type,
size_t stack_size) { unsigned thread_id;
// Allocate the OSThread object
OSThread* osthread = new OSThread(); if (osthread == NULL) { returnfalse;
}
// Initial state is ALLOCATED but not INITIALIZED
osthread->set_state(ALLOCATED);
// Initialize the JDK library's interrupt event. // This should really be done when OSThread is constructed, // but there is no way for a constructor to report failure to // allocate the event.
HANDLE interrupt_event = CreateEvent(NULL, true, false, NULL); if (interrupt_event == NULL) { delete osthread; returnfalse;
}
osthread->set_interrupt_event(interrupt_event); // We don't call set_interrupted(false) as it will trip the assert in there // as we are not operating on the current thread. We don't need to call it // because the initial state is already correct.
thread->set_osthread(osthread);
if (stack_size == 0) { switch (thr_type) { case os::java_thread: // Java threads use ThreadStackSize which default value can be changed with the flag -Xss if (JavaThread::stack_size_at_create() > 0) {
stack_size = JavaThread::stack_size_at_create();
} break; case os::compiler_thread: if (CompilerThreadStackSize > 0) {
stack_size = (size_t)(CompilerThreadStackSize * K); break;
} // else fall through: // use VMThreadStackSize if CompilerThreadStackSize is not defined case os::vm_thread: case os::gc_thread: case os::asynclog_thread: case os::watcher_thread: if (VMThreadStackSize > 0) stack_size = (size_t)(VMThreadStackSize * K); break;
}
}
// Create the Win32 thread // // Contrary to what MSDN document says, "stack_size" in _beginthreadex() // does not specify stack size. Instead, it specifies the size of // initially committed space. The stack size is determined by // PE header in the executable. If the committed "stack_size" is larger // than default value in the PE header, the stack is rounded up to the // nearest multiple of 1MB. For example if the launcher has default // stack size of 320k, specifying any size less than 320k does not // affect the actual stack size at all, it only affects the initial // commitment. On the other hand, specifying 'stack_size' larger than // default value may cause significant increase in memory usage, because // not only the stack space will be rounded up to MB, but also the // entire space is committed upfront. // // Finally Windows XP added a new flag 'STACK_SIZE_PARAM_IS_A_RESERVATION' // for CreateThread() that can treat 'stack_size' as stack size. However we // are not supposed to call CreateThread() directly according to MSDN // document because JVM uses C runtime library. The good news is that the // flag appears to work with _beginthredex() as well.
ResourceMark rm; char buf[64]; if (thread_handle != NULL) {
log_info(os, thread)("Thread \"%s\" started (tid: %u, attributes: %s)",
thread->name(), thread_id,
describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag));
} else {
log_warning(os, thread)("Failed to start thread \"%s\" - _beginthreadex failed (%s) for attributes: %s.",
thread->name(), os::errno_name(errno), describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag)); // Log some OS information which might explain why creating the thread failed.
log_info(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads());
LogStream st(Log(os, thread)::info());
os::print_memory_info(&st);
}
if (thread_handle == NULL) { // Need to clean up stuff we've allocated so far
thread->set_osthread(NULL); delete osthread; returnfalse;
}
// Store info on the Win32 thread into the OSThread
osthread->set_thread_handle(thread_handle);
osthread->set_thread_id(thread_id);
// Thread state now is INITIALIZED, not SUSPENDED
osthread->set_state(INITIALIZED);
// The thread is returned suspended (in state INITIALIZED), and is started higher up in the call chain returntrue;
}
// Free Win32 resources related to the OSThread void os::free_thread(OSThread* osthread) {
assert(osthread != NULL, "osthread not set");
// We are told to free resources of the argument thread, // but we can only really operate on the current thread.
assert(Thread::current()->osthread() == osthread, "os::free_thread but not current thread");
julong os::win32::available_memory() { // Use GlobalMemoryStatusEx() because GlobalMemoryStatus() may return incorrect // value if total memory is larger than 4GB
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(ms);
GlobalMemoryStatusEx(&ms);
bool os::has_allocatable_memory_limit(size_t* limit) {
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(ms);
GlobalMemoryStatusEx(&ms); #ifdef _LP64
*limit = (size_t)ms.ullAvailVirtual; returntrue; #else // Limit to 1400m because of the 2gb address space wall
*limit = MIN2((size_t)1400*M, (size_t)ms.ullAvailVirtual); returntrue; #endif
}
int os::active_processor_count() { // User has overridden the number of active processors if (ActiveProcessorCount > 0) {
log_trace(os)("active_processor_count: " "active processor count set by user : %d",
ActiveProcessorCount); return ActiveProcessorCount;
}
DWORD_PTR lpProcessAffinityMask = 0;
DWORD_PTR lpSystemAffinityMask = 0; int proc_count = processor_count(); if (proc_count <= sizeof(UINT_PTR) * BitsPerByte &&
GetProcessAffinityMask(GetCurrentProcess(), &lpProcessAffinityMask, &lpSystemAffinityMask)) { // Nof active processors is number of bits in process affinity mask int bitcount = 0; while (lpProcessAffinityMask != 0) {
lpProcessAffinityMask = lpProcessAffinityMask & (lpProcessAffinityMask-1);
bitcount++;
} return bitcount;
} else { return proc_count;
}
}
if (_SetThreadDescription != NULL) { // SetThreadDescription takes a PCWSTR but we have conversion routines that produce // LPWSTR. The only difference is that PCWSTR is a pointer to const WCHAR.
LPWSTR unicode_name;
errno_t err = convert_to_unicode(name, &unicode_name); if (err == ERROR_SUCCESS) {
HANDLE current = GetCurrentThread();
HRESULT hr = _SetThreadDescription(current, unicode_name); if (FAILED(hr)) {
log_debug(os, thread)("set_native_thread_name: SetThreadDescription failed - falling back to debugger method");
FREE_C_HEAP_ARRAY(WCHAR, unicode_name);
} else {
log_trace(os, thread)("set_native_thread_name: SetThreadDescription succeeded - new name: %s", name);
#ifdef ASSERT // For verification purposes in a debug build we read the thread name back and check it.
PWSTR thread_name;
HRESULT hr2 = _GetThreadDescription(current, &thread_name); if (FAILED(hr2)) {
log_debug(os, thread)("set_native_thread_name: GetThreadDescription failed!");
} else { int res = CompareStringW(LOCALE_USER_DEFAULT,
0, // no special comparison rules
unicode_name,
-1, // null-terminated
thread_name,
-1 // null-terminated
);
assert(res == CSTR_EQUAL, "Name strings were not the same - set: %ls, but read: %ls", unicode_name, thread_name);
LocalFree(thread_name);
} #endif
FREE_C_HEAP_ARRAY(WCHAR, unicode_name); return;
}
} else {
log_debug(os, thread)("set_native_thread_name: convert_to_unicode failed - falling back to debugger method");
}
}
// See: http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx // // Note that unfortunately this only works if the process // is already attached to a debugger; debugger must observe // the exception below to show the correct name.
// If there is no debugger attached skip raising the exception if (!IsDebuggerPresent()) {
log_debug(os, thread)("set_native_thread_name: no debugger present so unable to set thread name"); return;
}
const DWORD MS_VC_EXCEPTION = 0x406D1388; struct {
DWORD dwType; // must be 0x1000
LPCSTR szName; // pointer to name (in user addr space)
DWORD dwThreadID; // thread ID (-1=caller thread)
DWORD dwFlags; // reserved for future use, must be zero
} info;
// Windows format: // The FILETIME structure is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601. // Java format: // Java standards require the number of milliseconds since 1/1/1970
// Constant offset - calculated using offset() static jlong _offset = 116444736000000000; // Fake time counter for reproducible results when debugging static jlong fake_time = 0;
#ifdef ASSERT // Just to be safe, recalculate the offset in debug mode static jlong _calculated_offset = 0; staticint _has_calculated_offset = 0;
jlong windows_to_java_time(FILETIME wt) {
jlong a = jlong_from(wt.dwHighDateTime, wt.dwLowDateTime); return (a - offset()) / 10000;
}
// Returns time ticks in (10th of micro seconds)
jlong windows_to_time_ticks(FILETIME wt) {
jlong a = jlong_from(wt.dwHighDateTime, wt.dwLowDateTime); return (a - offset());
}
void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) {
jlong freq = performance_frequency; if (freq < NANOSECS_PER_SEC) { // the performance counter is 64 bits and we will // be multiplying it -- so no wrap in 64 bits
info_ptr->max_value = ALL_64_BITS;
} elseif (freq > NANOSECS_PER_SEC) { // use the max value the counter can reach to // determine the max value which could be returned
julong max_counter = (julong)ALL_64_BITS;
info_ptr->max_value = (jlong)(max_counter / (freq / NANOSECS_PER_SEC));
} else { // the performance counter is 64 bits and we will // be using it directly -- so no wrap in 64 bits
info_ptr->max_value = ALL_64_BITS;
}
// using a counter, so no skipping
info_ptr->may_skip_backward = false;
info_ptr->may_skip_forward = false;
info_ptr->kind = JVMTI_TIMER_ELAPSED; // elapsed not CPU time
}
// Check for abort hook
abort_hook_t abort_hook = Arguments::abort_hook(); if (abort_hook != NULL) {
abort_hook();
}
}
static HANDLE dumpFile = NULL;
// Check if dump file can be created. void os::check_dump_limit(char* buffer, size_t buffsz) { bool status = true; if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) {
jio_snprintf(buffer, buffsz, "CreateCoredumpOnCrash is disabled from command line");
status = false;
}
#ifndef ASSERT if (!os::win32::is_windows_server() && FLAG_IS_DEFAULT(CreateCoredumpOnCrash)) {
jio_snprintf(buffer, buffsz, "Minidumps are not enabled by default on client versions of Windows");
status = false;
} #endif
if (status) { constchar* cwd = get_current_directory(NULL, 0); int pid = current_process_id(); if (cwd != NULL) {
jio_snprintf(buffer, buffsz, "%s\\hs_err_pid%u.mdmp", cwd, pid);
} else {
jio_snprintf(buffer, buffsz, ".\\hs_err_pid%u.mdmp", pid);
}
// Older versions of dbghelp.dll (the one shipped with Win2003 for example) may not support all // the dump types we really want. If first call fails, lets fall back to just use MiniDumpWithFullMemory then. if (!WindowsDbgHelp::miniDumpWriteDump(hProcess, processId, dumpFile, dumpType, pmei, NULL, NULL) &&
!WindowsDbgHelp::miniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, pmei, NULL, NULL)) {
jio_fprintf(stderr, "Call to MiniDumpWriteDump() failed (Error 0x%x)\n", GetLastError());
}
CloseHandle(dumpFile);
win32::exit_process_or_thread(win32::EPT_PROCESS, 1);
}
// Die immediately, no exit hook, no abort hook, no cleanup. void os::die() {
win32::exit_process_or_thread(win32::EPT_PROCESS_DIE, -1);
}
// Directory routines copied from src/win32/native/java/io/dirent_md.c // * dirent_md.c 1.15 00/02/02 // // The declarations for DIR and struct dirent are in jvm_win32.h.
// Caller must have already run dirname through JVM_NativePath, which removes // duplicate slashes and converts all instances of '/' into '\\'.
// Win32 accepts "\" in its POSIX stat(), but refuses to treat it // as a directory in FindFirstFile(). We detect this case here and // prepend the current drive name. // if (dirname[1] == '\0' && dirname[0] == '\\') {
alt_dirname[0] = _getdrive() + 'A' - 1;
alt_dirname[1] = ':';
alt_dirname[2] = '\\';
alt_dirname[3] = '\0';
dirname = alt_dirname;
}
// This must be hard coded because it's the system's temporary // directory not the java application's temp directory, ala java.io.tmpdir. constchar* os::get_temp_directory() { staticchar path_buf[MAX_PATH]; if (GetTempPath(MAX_PATH, path_buf) > 0) { return path_buf;
} else {
path_buf[0] = '\0'; return path_buf;
}
}
// Needs to be in os specific directory because windows requires another // header file <direct.h> constchar* os::get_current_directory(char *buf, size_t buflen) { int n = static_cast<int>(buflen); if (buflen > INT_MAX) n = INT_MAX; return _getcwd(buf, n);
}
//----------------------------------------------------------- // Helper functions for fatal error handler #ifdef _WIN64 // Helper routine which returns true if address in // within the NTDLL address space. // staticbool _addr_in_ntdll(address addr) {
HMODULE hmod;
MODULEINFO minfo;
hmod = GetModuleHandle("NTDLL.DLL"); if (hmod == NULL) returnfalse; if (!GetModuleInformation(GetCurrentProcess(), hmod,
&minfo, sizeof(MODULEINFO))) { returnfalse;
}
if (base_addr <= pmod->addr &&
top_address > pmod->addr) { // if a buffer is provided, copy path name to the buffer if (pmod->full_path) {
jio_snprintf(pmod->full_path, pmod->buflen, "%s", mod_fname);
}
pmod->base_addr = base_addr; return 1;
} return 0;
}
bool os::dll_address_to_library_name(address addr, char* buf, int buflen, int* offset) { // buf is not optional, but offset is optional
assert(buf != NULL, "sanity check");
// NOTE: the reason we don't use SymGetModuleInfo() is it doesn't always // return the full path to the DLL file, sometimes it returns path // to the corresponding PDB file (debug info); sometimes it only // returns partial path, which makes life painful.
buf[0] = '\0'; if (offset) *offset = -1; returnfalse;
}
bool os::dll_address_to_function_name(address addr, char *buf, int buflen, int *offset, bool demangle) { // buf is not optional, but offset is optional
assert(buf != NULL, "sanity check");
// save the start and end address of jvm.dll into param[0] and param[1] staticint _locate_jvm_dll(constchar* mod_fname, address base_addr,
address top_address, void * param) { if (!param) return -1;
// Loads .dll/.so and // in case of error it checks if .dll/.so was built for the // same architecture as Hotspot is running on void * os::dll_load(constchar *name, char *ebuf, int ebuflen) {
log_info(os)("attempting shared library load of %s", name);
void * result = LoadLibrary(name); if (result != NULL) {
Events::log_dll_message(NULL, "Loaded shared library %s", name); // Recalculate pdb search path if a DLL was loaded successfully.
SymbolEngine::recalc_search_path();
log_info(os)("shared library load of %s was successful", name); return result;
}
DWORD errcode = GetLastError(); // Read system error message into ebuf // It may or may not be overwritten below (in the for loop and just above)
lasterror(ebuf, (size_t) ebuflen);
ebuf[ebuflen - 1] = '\0';
Events::log_dll_message(NULL, "Loading shared library %s failed, error code %lu", name, errcode);
log_info(os)("shared library load of %s failed, error code %lu", name, errcode);
// Parsing dll below // If we can read dll-info and find that dll was built // for an architecture other than Hotspot is running in // - then print to buffer "DLL was built for a different architecture" // else call os::lasterror to obtain system error message int fd = ::open(name, O_RDONLY | O_BINARY, 0); if (fd < 0) { return NULL;
}
uint32_t signature_offset;
uint16_t lib_arch = 0; bool failed_to_get_lib_arch =
( // Go to position 3c in the dll
(os::seek_to_file_offset(fd, IMAGE_FILE_PTR_TO_SIGNATURE) < 0)
|| // Read location of signature
(sizeof(signature_offset) !=
(::read(fd, (void*)&signature_offset, sizeof(signature_offset))))
|| // Go to COFF File Header in dll // that is located after "signature" (4 bytes long)
(os::seek_to_file_offset(fd,
signature_offset + IMAGE_FILE_SIGNATURE_LENGTH) < 0)
|| // Read field that contains code of architecture // that dll was built for
(sizeof(lib_arch) != (::read(fd, (void*)&lib_arch, sizeof(lib_arch))))
);
staticconst arch_t arch_array[] = {
{IMAGE_FILE_MACHINE_I386, (char*)"IA 32"},
{IMAGE_FILE_MACHINE_AMD64, (char*)"AMD 64"},
{IMAGE_FILE_MACHINE_ARM64, (char*)"ARM 64"}
}; #if (defined _M_ARM64) staticconst uint16_t running_arch = IMAGE_FILE_MACHINE_ARM64; #elif (defined _M_AMD64) staticconst uint16_t running_arch = IMAGE_FILE_MACHINE_AMD64; #elif (defined _M_IX86) staticconst uint16_t running_arch = IMAGE_FILE_MACHINE_I386; #else #error Method os::dll_load requires that one of following \
is defined :_M_AMD64 or _M_IX86 or _M_ARM64 #endif
// Obtain a string for printf operation // lib_arch_str shall contain string what platform this .dll was built for // running_arch_str shall string contain what platform Hotspot was built for char *running_arch_str = NULL, *lib_arch_str = NULL; for (unsignedint i = 0; i < ARRAY_SIZE(arch_array); i++) { if (lib_arch == arch_array[i].arch_code) {
lib_arch_str = arch_array[i].arch_name;
} if (running_arch == arch_array[i].arch_code) {
running_arch_str = arch_array[i].arch_name;
}
}
assert(running_arch_str, "Didn't find running architecture code in arch_array");
// If the architecture is right // but some other error took place - report os::lasterror(...) msg if (lib_arch == running_arch) { return NULL;
}
if (lib_arch_str != NULL) {
::_snprintf(ebuf, ebuflen - 1, "Can't load %s-bit .dll on a %s-bit platform",
lib_arch_str, running_arch_str);
} else { // don't know what architecture this dll was build for
::_snprintf(ebuf, ebuflen - 1, "Can't load this .dll (machine code=0x%x) on a %s-bit platform",
lib_arch, running_arch_str);
}
// number of modules that are currently loaded int num_modules = size_needed / sizeof(HMODULE);
for (int i = 0; i < MIN2(num_modules, MAX_NUM_MODULES); i++) { // Get Full pathname: if (!GetModuleFileNameEx(hProcess, modules[i], filename, sizeof(filename))) {
filename[0] = '\0';
}
void os::get_summary_os_info(char* buf, size_t buflen) {
stringStream sst(buf, buflen);
os::win32::print_windows_version(&sst); // chop off newline character char* nl = strchr(buf, '\n'); if (nl != NULL) *nl = '\0';
}
int os::vsnprintf(char* buf, size_t len, constchar* fmt, va_list args) { // Starting with Visual Studio 2015, vsnprint is C99 compliant.
ALLOW_C_FUNCTION(::vsnprintf, int result = ::vsnprintf(buf, len, fmt, args);) // If an encoding error occurred (result < 0) then it's not clear // whether the buffer is NUL terminated, so ensure it is. if ((result < 0) && (len > 0)) {
buf[len - 1] = '\0';
} return result;
}
staticinline time_t get_mtime(constchar* filename) { struct stat st; int ret = os::stat(filename, &st);
assert(ret == 0, "failed to stat() file '%s': %s", filename, os::strerror(errno)); return st.st_mtime;
}
// Get the full path to \Windows\System32\kernel32.dll and use that for // determining what version of Windows we're running on.
len = MAX_PATH - (UINT)strlen("\\kernel32.dll") - 1;
ret = GetSystemDirectory(kernel32_path, len); if (ret == 0 || ret > len) {
st->print_cr("Call to GetSystemDirectory failed"); return;
}
strncat(kernel32_path, "\\kernel32.dll", MAX_PATH - ret);
DWORD version_size = GetFileVersionInfoSize(kernel32_path, NULL); if (version_size == 0) {
st->print_cr("Call to GetFileVersionInfoSize failed"); return;
}
LPTSTR version_info = (LPTSTR)os::malloc(version_size, mtInternal); if (version_info == NULL) {
st->print_cr("Failed to allocate version_info"); return;
}
if (!GetFileVersionInfo(kernel32_path, NULL, version_size, version_info)) {
os::free(version_info);
st->print_cr("Call to GetFileVersionInfo failed"); return;
}
if (!VerQueryValue(version_info, TEXT("\\"), (LPVOID*)&file_info, &len)) {
os::free(version_info);
st->print_cr("Call to VerQueryValue failed"); return;
}
int major_version = HIWORD(file_info->dwProductVersionMS); int minor_version = LOWORD(file_info->dwProductVersionMS); int build_number = HIWORD(file_info->dwProductVersionLS); int build_minor = LOWORD(file_info->dwProductVersionLS); int os_vers = major_version * 1000 + minor_version;
os::free(version_info);
st->print(" Windows "); switch (os_vers) {
case 6000: if (is_workstation) {
st->print("Vista");
} else {
st->print("Server 2008");
} break;
case 6001: if (is_workstation) {
st->print("7");
} else {
st->print("Server 2008 R2");
} break;
case 6002: if (is_workstation) {
st->print("8");
} else {
st->print("Server 2012");
} break;
case 6003: if (is_workstation) {
st->print("8.1");
} else {
st->print("Server 2012 R2");
} break;
case 10000: if (is_workstation) { if (build_number >= 22000) {
st->print("11");
} else {
st->print("10");
}
} else { // distinguish Windows Server by build number // - 2016 GA 10/2016 build: 14393 // - 2019 GA 11/2018 build: 17763 // - 2022 GA 08/2021 build: 20348 if (build_number > 20347) {
st->print("Server 2022");
} elseif (build_number > 17762) {
st->print("Server 2019");
} else {
st->print("Server 2016");
}
} break;
default: // Unrecognized windows, print out its major and minor versions
st->print("%d.%d", major_version, minor_version); break;
}
// Retrieve SYSTEM_INFO from GetNativeSystemInfo call so that we could // find out whether we are running on 64 bit processor or not
SYSTEM_INFO si;
ZeroMemory(&si, sizeof(SYSTEM_INFO));
GetNativeSystemInfo(&si); if ((si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) ||
(si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64)) {
st->print(" , 64 bit");
}
// Use GlobalMemoryStatusEx() because GlobalMemoryStatus() may return incorrect // value if total memory is larger than 4GB
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(ms); int r1 = GlobalMemoryStatusEx(&ms);
// on 32bit Total/AvailVirtual are interesting (show us how close we get to 2-4 GB per process borders) #ifdefined(_M_IX86)
st->print(", user-mode portion of virtual address-space " INT64_FORMAT "M ",
(int64_t) ms.ullTotalVirtual >> 20);
st->print("(" INT64_FORMAT "M free)", (int64_t) ms.ullAvailVirtual >> 20); #endif
} else {
st->print(", GlobalMemoryStatusEx did not succeed so we miss some memory values.");
}
// extended memory statistics for a process
PROCESS_MEMORY_COUNTERS_EX pmex;
ZeroMemory(&pmex, sizeof(PROCESS_MEMORY_COUNTERS_EX));
pmex.cb = sizeof(pmex); int r2 = GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*) &pmex, sizeof(pmex));
if (r2 != 0) {
st->print("\ncurrent process WorkingSet (physical memory assigned to process): " INT64_FORMAT "M, ",
(int64_t) pmex.WorkingSetSize >> 20);
st->print("peak: " INT64_FORMAT "M\n", (int64_t) pmex.PeakWorkingSetSize >> 20);
st->print("current process commit charge (\"private bytes\"): " INT64_FORMAT "M, ",
(int64_t) pmex.PrivateUsage >> 20);
st->print("peak: " INT64_FORMAT "M", (int64_t) pmex.PeakPagefileUsage >> 20);
} else {
st->print("\nGetProcessMemoryInfo did not succeed so we miss some memory values.");
}
st->cr();
}
bool os::signal_sent_by_kill(constvoid* siginfo) { // TODO: Is this possible? returnfalse;
}
// Find the full path to the current module, jvm.dll void os::jvm_path(char *buf, jint buflen) { // Error checking. if (buflen < MAX_PATH) {
assert(false, "must use a large-enough buffer");
buf[0] = '\0'; return;
} // Lazy resolve the path to current module. if (saved_jvm_path[0] != 0) {
strcpy(buf, saved_jvm_path); return;
}
buf[0] = '\0'; if (Arguments::sun_java_launcher_is_altjvm()) { // Support for the java launcher's '-XXaltjvm=<path>' option. Check // for a JAVA_HOME environment variable and fix up the path so it // looks like jvm.dll is installed there (append a fake suffix // hotspot/jvm.dll). char* java_home_var = ::getenv("JAVA_HOME"); if (java_home_var != NULL && java_home_var[0] != 0 &&
strlen(java_home_var) < (size_t)buflen) {
strncpy(buf, java_home_var, buflen);
// determine if this is a legacy image or modules image // modules image doesn't have "jre" subdirectory
size_t len = strlen(buf); char* jrebin_p = buf + len;
jio_snprintf(jrebin_p, buflen-len, "\\jre\\bin\\"); if (0 != _access(buf, 0)) {
jio_snprintf(jrebin_p, buflen-len, "\\bin\\");
}
len = strlen(buf);
--> --------------------
--> maximum size reached
--> --------------------
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.